summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOndřej Surý <ondrej@sury.org>2011-01-17 12:40:45 +0100
committerOndřej Surý <ondrej@sury.org>2011-01-17 12:40:45 +0100
commit3e45412327a2654a77944249962b3652e6142299 (patch)
treebc3bf69452afa055423cbe0c5cfa8ca357df6ccf
parentc533680039762cacbc37db8dc7eed074c3e497be (diff)
downloadgolang-3e45412327a2654a77944249962b3652e6142299.tar.gz
Imported Upstream version 2011.01.12upstream/2011.01.12
-rw-r--r--.hgignore45
-rw-r--r--AUTHORS40
-rw-r--r--CONTRIBUTORS54
-rw-r--r--LICENSE69
-rw-r--r--PATENTS22
-rw-r--r--README20
-rw-r--r--doc/ExpressivenessOfGo.pdfbin0 -> 859406 bytes
-rw-r--r--doc/Makefile4
-rw-r--r--doc/all.css197
-rw-r--r--doc/button_background.pngbin0 -> 126 bytes
-rw-r--r--doc/code.html48
-rw-r--r--doc/codelab/wiki/Makefile15
-rw-r--r--doc/codelab/wiki/final-noclosure.go34
-rw-r--r--doc/codelab/wiki/final-noerror.go8
-rw-r--r--doc/codelab/wiki/final-parsetemplate.go32
-rw-r--r--doc/codelab/wiki/final-template.go16
-rw-r--r--doc/codelab/wiki/final.go30
-rw-r--r--doc/codelab/wiki/http-sample.go4
-rw-r--r--doc/codelab/wiki/index.html147
-rw-r--r--doc/codelab/wiki/notemplate.go8
-rw-r--r--doc/codelab/wiki/part2.go4
-rw-r--r--doc/codelab/wiki/srcextract.go2
-rw-r--r--doc/codelab/wiki/wiki.html35
-rw-r--r--doc/codereview_with_mq.html6
-rw-r--r--doc/codewalk/urlpoll.go6
-rw-r--r--doc/community.html53
-rw-r--r--doc/contrib.html45
-rw-r--r--doc/contribute.html12
-rw-r--r--doc/devel/release.html1143
-rw-r--r--doc/devel/roadmap.html51
-rw-r--r--doc/docs.html195
-rw-r--r--doc/effective_go.html161
-rw-r--r--doc/frontpage.css140
-rw-r--r--doc/gccgo_install.html42
-rw-r--r--doc/go_faq.html894
-rw-r--r--doc/go_for_cpp_programmers.html4
-rw-r--r--doc/go_lang_faq.html491
-rw-r--r--doc/go_learning.html141
-rw-r--r--doc/go_mem.html35
-rw-r--r--doc/go_programming_faq.html307
-rw-r--r--doc/go_spec.html497
-rw-r--r--doc/go_tutorial.html109
-rw-r--r--doc/go_tutorial.txt77
-rw-r--r--doc/godocs.js23
-rw-r--r--doc/ie.css1
-rw-r--r--doc/install.html392
-rw-r--r--doc/logo.pngbin0 -> 1938 bytes
-rw-r--r--doc/play_overlay.pngbin0 -> 1703 bytes
-rw-r--r--doc/playground.html27
-rw-r--r--doc/progs/cat.go6
-rw-r--r--doc/progs/cat_rot13.go12
-rw-r--r--doc/progs/file.go8
-rw-r--r--doc/progs/helloworld3.go4
-rwxr-xr-xdoc/progs/run12
-rw-r--r--doc/progs/sortmain.go2
-rw-r--r--doc/progs/sum.go4
-rw-r--r--doc/root.html210
-rw-r--r--doc/style.css282
-rw-r--r--doc/talks/gofrontend-gcc-summit-2010.pdfbin0 -> 125185 bytes
-rw-r--r--doc/talks/io2010/balance.go8
-rw-r--r--doc/video-001.pngbin0 -> 29228 bytes
-rw-r--r--doc/video-002.pngbin0 -> 22027 bytes
-rw-r--r--doc/video-003.pngbin0 -> 11189 bytes
-rw-r--r--doc/video-004.pngbin0 -> 22713 bytes
-rw-r--r--doc/video-snap.jpgbin3269 -> 0 bytes
-rw-r--r--include/libc.h8
-rw-r--r--include/u.h5
-rw-r--r--lib/codereview/codereview.py2605
-rw-r--r--lib/godoc/godoc.html178
-rw-r--r--lib/godoc/package.html38
-rw-r--r--lib/godoc/package.txt20
-rw-r--r--lib/godoc/search.html49
-rw-r--r--lib/godoc/search.txt24
-rw-r--r--lib/godoc/source.html23
-rwxr-xr-xmisc/arm/a23
-rw-r--r--misc/bash/go2
-rwxr-xr-xmisc/bbedit/Go.plist11
-rw-r--r--misc/cgo/gmp/Makefile2
-rw-r--r--misc/cgo/life/Makefile20
-rw-r--r--misc/cgo/life/c-life.c2
-rw-r--r--misc/cgo/life/golden.out17
-rw-r--r--misc/cgo/life/life.go2
-rw-r--r--misc/cgo/life/life.h1
-rw-r--r--misc/cgo/life/main.go2
-rwxr-xr-xmisc/cgo/life/test.bash11
-rw-r--r--misc/cgo/stdio/Makefile11
-rw-r--r--misc/cgo/stdio/align.go78
-rw-r--r--misc/cgo/stdio/chain.go4
-rw-r--r--misc/cgo/stdio/fib.go2
-rw-r--r--misc/cgo/stdio/file.go28
-rw-r--r--misc/cgo/stdio/hello.go23
-rwxr-xr-xmisc/cgo/stdio/test.bash5
-rw-r--r--misc/cgo/stdio/test.go144
-rw-r--r--misc/cgo/stdio/test1.go29
-rw-r--r--misc/dashboard/README14
-rw-r--r--misc/dashboard/buildcontrol.py41
-rw-r--r--misc/dashboard/buildcron.sh4
-rw-r--r--misc/dashboard/builder.sh25
-rw-r--r--misc/dashboard/builder/Makefile (renamed from src/pkg/once/Makefile)11
-rw-r--r--misc/dashboard/builder/doc.go54
-rw-r--r--misc/dashboard/builder/exec.go65
-rw-r--r--misc/dashboard/builder/hg.go54
-rw-r--r--misc/dashboard/builder/http.go70
-rw-r--r--misc/dashboard/builder/main.go340
-rw-r--r--misc/dashboard/godashboard/package.py184
-rw-r--r--misc/dashboard/godashboard/project-edit.html10
-rw-r--r--misc/dashboard/godashboard/project-notify.txt2
-rw-r--r--misc/dashboard/godashboard/toutf8.py14
-rwxr-xr-xmisc/dashboard/googlecode_upload.py248
-rw-r--r--misc/emacs/go-mode.el6
-rw-r--r--misc/fraise/go.plist93
-rw-r--r--misc/fraise/readme.txt16
-rw-r--r--misc/goplay/Makefile13
-rw-r--r--misc/goplay/README1
-rw-r--r--misc/goplay/doc.go25
-rw-r--r--misc/goplay/goplay.go314
-rw-r--r--misc/kate/go.xml2
-rw-r--r--misc/vim/syntax/go.vim10
-rw-r--r--misc/zsh/go14
-rw-r--r--pkg/~place-holder~4
-rw-r--r--src/Make.38611
-rw-r--r--src/Make.amd6411
-rw-r--r--src/Make.arm11
-rw-r--r--src/Make.ccmd44
-rw-r--r--src/Make.clib34
-rw-r--r--src/Make.cmd15
-rw-r--r--src/Make.common23
-rw-r--r--src/Make.conf22
-rw-r--r--src/Make.inc146
-rw-r--r--src/Make.pkg100
-rwxr-xr-xsrc/all-arm.bash30
-rwxr-xr-xsrc/all-nacl.bash48
-rwxr-xr-xsrc/all.bash10
-rwxr-xr-xsrc/clean.bash19
-rw-r--r--src/cmd/5a/Makefile25
-rw-r--r--src/cmd/5a/a.h5
-rw-r--r--src/cmd/5a/a.y8
-rw-r--r--src/cmd/5a/lex.c10
-rw-r--r--src/cmd/5c/Makefile21
-rw-r--r--src/cmd/5c/list.c16
-rw-r--r--src/cmd/5c/mul.c4
-rw-r--r--src/cmd/5c/peep.c2
-rw-r--r--src/cmd/5c/reg.c10
-rw-r--r--src/cmd/5c/swt.c42
-rw-r--r--src/cmd/5c/txt.c61
-rw-r--r--src/cmd/5g/Makefile25
-rw-r--r--src/cmd/5g/cgen.c232
-rw-r--r--src/cmd/5g/cgen64.c6
-rw-r--r--src/cmd/5g/galign.c1
-rw-r--r--src/cmd/5g/gg.h6
-rw-r--r--src/cmd/5g/ggen.c87
-rw-r--r--src/cmd/5g/gobj.c6
-rw-r--r--src/cmd/5g/gsubr.c221
-rw-r--r--src/cmd/5g/list.c34
-rw-r--r--src/cmd/5g/opt.h2
-rw-r--r--src/cmd/5g/peep.c1511
-rw-r--r--src/cmd/5g/reg.c1329
-rw-r--r--src/cmd/5l/5.out.h8
-rw-r--r--src/cmd/5l/Makefile24
-rw-r--r--src/cmd/5l/asm.c1310
-rw-r--r--src/cmd/5l/doc.go4
-rw-r--r--src/cmd/5l/l.h143
-rw-r--r--src/cmd/5l/list.c146
-rw-r--r--src/cmd/5l/noop.c1371
-rw-r--r--src/cmd/5l/obj.c475
-rw-r--r--src/cmd/5l/optab.c63
-rw-r--r--src/cmd/5l/pass.c803
-rw-r--r--src/cmd/5l/prof.c214
-rw-r--r--src/cmd/5l/softfloat.c113
-rw-r--r--src/cmd/5l/span.c671
-rw-r--r--src/cmd/5l/thumb.c78
-rw-r--r--src/cmd/6a/Makefile23
-rw-r--r--src/cmd/6a/a.h9
-rw-r--r--src/cmd/6a/a.y14
-rw-r--r--src/cmd/6a/lex.c10
-rw-r--r--src/cmd/6c/Makefile21
-rw-r--r--src/cmd/6c/cgen.c10
-rw-r--r--src/cmd/6c/div.c4
-rw-r--r--src/cmd/6c/list.c15
-rw-r--r--src/cmd/6c/mul.c2
-rw-r--r--src/cmd/6c/peep.c2
-rw-r--r--src/cmd/6c/reg.c12
-rw-r--r--src/cmd/6c/sgen.c4
-rw-r--r--src/cmd/6c/swt.c29
-rw-r--r--src/cmd/6c/txt.c23
-rw-r--r--src/cmd/6g/Makefile21
-rw-r--r--src/cmd/6g/cgen.c257
-rw-r--r--src/cmd/6g/galign.c1
-rw-r--r--src/cmd/6g/gg.h2
-rw-r--r--src/cmd/6g/ggen.c85
-rw-r--r--src/cmd/6g/gobj.c4
-rw-r--r--src/cmd/6g/gsubr.c149
-rw-r--r--src/cmd/6g/list.c18
-rw-r--r--src/cmd/6g/reg.c20
-rw-r--r--src/cmd/6l/6.out.h6
-rw-r--r--src/cmd/6l/Makefile26
-rw-r--r--src/cmd/6l/asm.c1389
-rw-r--r--src/cmd/6l/doc.go4
-rw-r--r--src/cmd/6l/l.h140
-rw-r--r--src/cmd/6l/list.c73
-rw-r--r--src/cmd/6l/obj.c549
-rw-r--r--src/cmd/6l/optab.c6
-rw-r--r--src/cmd/6l/pass.c1112
-rw-r--r--src/cmd/6l/prof.c171
-rw-r--r--src/cmd/6l/span.c1282
-rw-r--r--src/cmd/8a/Makefile23
-rw-r--r--src/cmd/8a/a.h9
-rw-r--r--src/cmd/8a/a.y8
-rw-r--r--src/cmd/8a/lex.c10
-rw-r--r--src/cmd/8c/Makefile21
-rw-r--r--src/cmd/8c/cgen64.c4
-rw-r--r--src/cmd/8c/div.c4
-rw-r--r--src/cmd/8c/list.c30
-rw-r--r--src/cmd/8c/mul.c2
-rw-r--r--src/cmd/8c/reg.c10
-rw-r--r--src/cmd/8c/swt.c38
-rw-r--r--src/cmd/8c/txt.c11
-rw-r--r--src/cmd/8g/Makefile21
-rw-r--r--src/cmd/8g/cgen.c69
-rw-r--r--src/cmd/8g/galign.c1
-rw-r--r--src/cmd/8g/ggen.c116
-rw-r--r--src/cmd/8g/gobj.c4
-rw-r--r--src/cmd/8g/gsubr.c14
-rw-r--r--src/cmd/8g/list.c14
-rw-r--r--src/cmd/8g/reg.c22
-rw-r--r--src/cmd/8l/8.out.h8
-rw-r--r--src/cmd/8l/Makefile29
-rw-r--r--src/cmd/8l/asm.c1328
-rw-r--r--src/cmd/8l/doc.go4
-rw-r--r--src/cmd/8l/l.h136
-rw-r--r--src/cmd/8l/list.c87
-rw-r--r--src/cmd/8l/obj.c505
-rw-r--r--src/cmd/8l/optab.c4
-rw-r--r--src/cmd/8l/pass.c1058
-rw-r--r--src/cmd/8l/prof.c173
-rw-r--r--src/cmd/8l/span.c1183
-rw-r--r--src/cmd/cc/Makefile21
-rw-r--r--src/cmd/cc/acid.c12
-rw-r--r--src/cmd/cc/cc.h3
-rw-r--r--src/cmd/cc/com.c6
-rw-r--r--src/cmd/cc/dcl.c39
-rw-r--r--src/cmd/cc/dpchk.c13
-rw-r--r--src/cmd/cc/lex.c10
-rw-r--r--src/cmd/cc/macbody2
-rw-r--r--src/cmd/cc/pgen.c8
-rw-r--r--src/cmd/cc/pickle.c10
-rw-r--r--src/cmd/cc/pswt.c4
-rw-r--r--src/cmd/cc/sub.c8
-rw-r--r--src/cmd/cgo/Makefile2
-rw-r--r--src/cmd/cgo/ast.go465
-rw-r--r--src/cmd/cgo/doc.go25
-rw-r--r--src/cmd/cgo/gcc.go543
-rw-r--r--src/cmd/cgo/main.go256
-rw-r--r--src/cmd/cgo/out.go524
-rw-r--r--src/cmd/cgo/util.go51
-rw-r--r--src/cmd/clean.bash4
-rw-r--r--src/cmd/cov/Makefile22
-rw-r--r--src/cmd/cov/main.c2
-rw-r--r--src/cmd/ebnflint/Makefile4
-rw-r--r--src/cmd/ebnflint/ebnflint.go6
-rw-r--r--src/cmd/gc/Makefile23
-rw-r--r--src/cmd/gc/align.c76
-rw-r--r--src/cmd/gc/builtin.c.boot18
-rw-r--r--src/cmd/gc/closure.c2
-rw-r--r--src/cmd/gc/const.c22
-rw-r--r--src/cmd/gc/dcl.c20
-rw-r--r--src/cmd/gc/doc.go9
-rw-r--r--src/cmd/gc/export.c3
-rw-r--r--src/cmd/gc/gen.c20
-rw-r--r--src/cmd/gc/go.errors9
-rw-r--r--src/cmd/gc/go.h48
-rw-r--r--src/cmd/gc/go.y174
-rw-r--r--src/cmd/gc/lex.c203
-rwxr-xr-xsrc/cmd/gc/mkbuiltin8
-rw-r--r--src/cmd/gc/mparith1.c42
-rw-r--r--src/cmd/gc/mparith2.c8
-rw-r--r--src/cmd/gc/mparith3.c30
-rw-r--r--src/cmd/gc/obj.c107
-rw-r--r--src/cmd/gc/print.c61
-rw-r--r--src/cmd/gc/range.c17
-rw-r--r--src/cmd/gc/reflect.c116
-rw-r--r--src/cmd/gc/runtime.go22
-rw-r--r--src/cmd/gc/select.c13
-rw-r--r--src/cmd/gc/sinit.c62
-rw-r--r--src/cmd/gc/subr.c177
-rw-r--r--src/cmd/gc/typecheck.c490
-rw-r--r--src/cmd/gc/unsafe.c20
-rw-r--r--src/cmd/gc/walk.c405
-rw-r--r--src/cmd/godefs/Makefile14
-rw-r--r--src/cmd/godefs/main.c10
-rw-r--r--src/cmd/godefs/stabs.c13
-rw-r--r--src/cmd/godoc/Makefile5
-rw-r--r--src/cmd/godoc/codewalk.go51
-rw-r--r--src/cmd/godoc/dirtrees.go341
-rw-r--r--src/cmd/godoc/doc.go17
-rw-r--r--src/cmd/godoc/format.go342
-rw-r--r--src/cmd/godoc/godoc.go1031
-rw-r--r--src/cmd/godoc/index.go295
-rw-r--r--src/cmd/godoc/main.go80
-rw-r--r--src/cmd/godoc/mapping.go94
-rwxr-xr-xsrc/cmd/godoc/snippet.go53
-rw-r--r--src/cmd/godoc/spec.go37
-rw-r--r--src/cmd/godoc/utils.go109
-rw-r--r--src/cmd/gofmt/Makefile6
-rw-r--r--src/cmd/gofmt/doc.go4
-rw-r--r--src/cmd/gofmt/gofmt.go25
-rw-r--r--src/cmd/gofmt/rewrite.go61
-rw-r--r--src/cmd/gofmt/simplify.go67
-rwxr-xr-xsrc/cmd/gofmt/test.sh5
-rw-r--r--src/cmd/gofmt/testdata/composites.golden104
-rw-r--r--src/cmd/gofmt/testdata/composites.input104
-rwxr-xr-xsrc/cmd/gofmt/testdata/test.sh65
-rw-r--r--src/cmd/goinstall/Makefile2
-rw-r--r--src/cmd/goinstall/doc.go41
-rw-r--r--src/cmd/goinstall/download.go57
-rw-r--r--src/cmd/goinstall/main.go91
-rw-r--r--src/cmd/goinstall/make.go80
-rw-r--r--src/cmd/goinstall/parse.go77
-rw-r--r--src/cmd/gomake/doc.go36
-rw-r--r--src/cmd/gopack/Makefile13
-rw-r--r--src/cmd/gopack/ar.c33
-rw-r--r--src/cmd/gopack/doc.go2
-rw-r--r--src/cmd/gotest/Makefile16
-rwxr-xr-xsrc/cmd/gotest/gotest73
-rwxr-xr-xsrc/cmd/gotest/gotry167
-rw-r--r--src/cmd/govet/Makefile11
-rw-r--r--src/cmd/govet/doc.go38
-rw-r--r--src/cmd/govet/govet.go325
-rw-r--r--src/cmd/goyacc/Makefile2
-rw-r--r--src/cmd/goyacc/goyacc.go41
-rw-r--r--src/cmd/goyacc/units.y8
-rw-r--r--src/cmd/hgpatch/Makefile2
-rw-r--r--src/cmd/hgpatch/main.go12
-rw-r--r--src/cmd/ld/data.c914
-rw-r--r--src/cmd/ld/dwarf.c2547
-rw-r--r--src/cmd/ld/dwarf.h29
-rw-r--r--src/cmd/ld/dwarf_defs.h503
-rw-r--r--src/cmd/ld/elf.c124
-rw-r--r--src/cmd/ld/elf.h8
-rw-r--r--src/cmd/ld/go.c182
-rw-r--r--src/cmd/ld/ldelf.c816
-rw-r--r--src/cmd/ld/ldmacho.c794
-rw-r--r--src/cmd/ld/lib.c546
-rw-r--r--src/cmd/ld/lib.h97
-rw-r--r--src/cmd/ld/macho.c394
-rw-r--r--src/cmd/ld/macho.h19
-rw-r--r--src/cmd/ld/pe.c307
-rw-r--r--src/cmd/ld/pe.h14
-rw-r--r--src/cmd/ld/symtab.c259
-rwxr-xr-xsrc/cmd/make.bash10
-rw-r--r--src/cmd/nm/Makefile18
-rw-r--r--src/cmd/nm/nm.c17
-rw-r--r--src/cmd/prof/Makefile24
-rwxr-xr-xsrc/cmd/prof/gopprof41
-rw-r--r--src/cmd/prof/main.c37
-rw-r--r--src/env.bash62
-rw-r--r--src/lib9/Makefile36
-rw-r--r--src/lib9/dirfwstat.c2
-rw-r--r--src/lib9/dirstat.c2
-rw-r--r--src/lib9/time.c4
-rw-r--r--src/lib9/utf/Makefile16
-rw-r--r--src/lib9/utf/mkrunetype.c19
-rw-r--r--src/lib9/utf/runetype.c27
-rw-r--r--src/lib9/utf/runetypebody-5.2.0.c1541
-rw-r--r--src/libbio/Makefile20
-rw-r--r--src/libbio/bprint.c70
-rw-r--r--src/libbio/bseek.c2
-rwxr-xr-xsrc/libcgo/Makefile42
-rw-r--r--src/libcgo/darwin_amd64.c78
-rw-r--r--src/libcgo/freebsd_amd64.c74
-rw-r--r--src/libcgo/nacl_386.c1
-rwxr-xr-xsrc/libcgo/windows_386.c45
-rw-r--r--src/libmach/5obj.c3
-rw-r--r--src/libmach/8db.c51
-rw-r--r--src/libmach/Makefile22
-rw-r--r--src/libmach/darwin.c11
-rw-r--r--src/libmach/executable.c62
-rw-r--r--src/libmach/linux.c58
-rw-r--r--src/libmach/windows.c59
-rwxr-xr-xsrc/make.bash65
-rw-r--r--src/pkg/Makefile91
-rw-r--r--src/pkg/archive/tar/Makefile2
-rw-r--r--src/pkg/archive/tar/reader_test.go2
-rw-r--r--src/pkg/archive/tar/writer.go4
-rw-r--r--src/pkg/archive/tar/writer_test.go2
-rw-r--r--src/pkg/archive/zip/Makefile12
-rw-r--r--src/pkg/archive/zip/reader.go278
-rw-r--r--src/pkg/archive/zip/reader_test.go180
-rw-r--r--src/pkg/archive/zip/struct.go33
-rw-r--r--src/pkg/archive/zip/testdata/gophercolor16x16.pngbin0 -> 785 bytes
-rw-r--r--src/pkg/archive/zip/testdata/r.zipbin0 -> 440 bytes
-rw-r--r--src/pkg/archive/zip/testdata/readme.notzipbin0 -> 1905 bytes
-rw-r--r--src/pkg/archive/zip/testdata/readme.zipbin0 -> 1885 bytes
-rw-r--r--src/pkg/archive/zip/testdata/test.zipbin0 -> 1170 bytes
-rw-r--r--src/pkg/asn1/Makefile2
-rw-r--r--src/pkg/asn1/asn1.go194
-rw-r--r--src/pkg/asn1/asn1_test.go193
-rw-r--r--src/pkg/asn1/common.go5
-rw-r--r--src/pkg/asn1/marshal.go40
-rw-r--r--src/pkg/asn1/marshal_test.go55
-rw-r--r--src/pkg/big/Makefile2
-rw-r--r--src/pkg/big/arith.go228
-rw-r--r--src/pkg/big/arith_arm.s289
-rw-r--r--src/pkg/big/arith_test.go197
-rwxr-xr-xsrc/pkg/big/int.go69
-rwxr-xr-xsrc/pkg/big/int_test.go453
-rwxr-xr-xsrc/pkg/big/nat.go24
-rwxr-xr-xsrc/pkg/big/nat_test.go162
-rw-r--r--src/pkg/big/rat.go136
-rw-r--r--src/pkg/big/rat_test.go219
-rw-r--r--src/pkg/bufio/Makefile2
-rw-r--r--src/pkg/bufio/bufio.go174
-rw-r--r--src/pkg/bufio/bufio_test.go223
-rw-r--r--src/pkg/bytes/Makefile2
-rw-r--r--src/pkg/bytes/asm_amd64.s93
-rw-r--r--src/pkg/bytes/buffer.go78
-rw-r--r--src/pkg/bytes/buffer_test.go61
-rw-r--r--src/pkg/bytes/bytes.go287
-rw-r--r--src/pkg/bytes/bytes_test.go625
-rw-r--r--src/pkg/cmath/Makefile2
-rw-r--r--src/pkg/cmath/cmath_test.go110
-rw-r--r--src/pkg/compress/flate/Makefile2
-rw-r--r--src/pkg/compress/flate/deflate.go148
-rw-r--r--src/pkg/compress/flate/deflate_test.go139
-rw-r--r--src/pkg/compress/flate/huffman_code.go1
-rw-r--r--src/pkg/compress/flate/inflate.go31
-rw-r--r--src/pkg/compress/gzip/Makefile2
-rw-r--r--src/pkg/compress/gzip/gunzip_test.go18
-rw-r--r--src/pkg/compress/zlib/Makefile2
-rw-r--r--src/pkg/compress/zlib/reader_test.go12
-rw-r--r--src/pkg/container/heap/Makefile2
-rw-r--r--src/pkg/container/list/Makefile2
-rw-r--r--src/pkg/container/list/list.go70
-rw-r--r--src/pkg/container/list/list_test.go24
-rw-r--r--src/pkg/container/ring/Makefile2
-rw-r--r--src/pkg/container/vector/Makefile8
-rw-r--r--src/pkg/container/vector/intvector.go21
-rw-r--r--src/pkg/container/vector/intvector_test.go101
-rw-r--r--src/pkg/container/vector/numbers_test.go2
-rw-r--r--src/pkg/container/vector/stringvector.go21
-rw-r--r--src/pkg/container/vector/stringvector_test.go101
-rw-r--r--src/pkg/container/vector/vector.go21
-rw-r--r--src/pkg/container/vector/vector_test.go101
-rw-r--r--src/pkg/crypto/aes/Makefile2
-rw-r--r--src/pkg/crypto/aes/aes_test.go22
-rw-r--r--src/pkg/crypto/aes/block.go4
-rw-r--r--src/pkg/crypto/aes/cipher.go4
-rw-r--r--src/pkg/crypto/aes/const.go16
-rw-r--r--src/pkg/crypto/block/Makefile2
-rw-r--r--src/pkg/crypto/block/cbc.go8
-rw-r--r--src/pkg/crypto/block/cfb.go10
-rw-r--r--src/pkg/crypto/block/cfb_aes_test.go18
-rw-r--r--src/pkg/crypto/block/cipher.go13
-rw-r--r--src/pkg/crypto/block/cmac.go2
-rw-r--r--src/pkg/crypto/block/cmac_aes_test.go24
-rw-r--r--src/pkg/crypto/block/ctr.go4
-rw-r--r--src/pkg/crypto/block/eax.go8
-rw-r--r--src/pkg/crypto/block/eax_aes_test.go20
-rw-r--r--src/pkg/crypto/block/ecb.go10
-rw-r--r--src/pkg/crypto/block/ecb_aes_test.go8
-rw-r--r--src/pkg/crypto/block/ecb_test.go4
-rw-r--r--src/pkg/crypto/block/ofb.go2
-rw-r--r--src/pkg/crypto/block/ofb_aes_test.go6
-rw-r--r--src/pkg/crypto/blowfish/Makefile2
-rw-r--r--src/pkg/crypto/blowfish/blowfish_test.go72
-rw-r--r--src/pkg/crypto/blowfish/cipher.go4
-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/Makefile16
-rw-r--r--src/pkg/crypto/cipher/cbc.go78
-rw-r--r--src/pkg/crypto/cipher/cbc_aes_test.go (renamed from src/pkg/crypto/block/cbc_aes_test.go)41
-rw-r--r--src/pkg/crypto/cipher/cfb.go64
-rw-r--r--src/pkg/crypto/cipher/cfb_test.go35
-rw-r--r--src/pkg/crypto/cipher/cipher.go63
-rw-r--r--src/pkg/crypto/cipher/common_test.go28
-rw-r--r--src/pkg/crypto/cipher/ctr.go51
-rw-r--r--src/pkg/crypto/cipher/ctr_aes_test.go (renamed from src/pkg/crypto/block/ctr_aes_test.go)47
-rw-r--r--src/pkg/crypto/cipher/io.go57
-rw-r--r--src/pkg/crypto/cipher/ocfb.go112
-rw-r--r--src/pkg/crypto/cipher/ocfb_test.go39
-rw-r--r--src/pkg/crypto/elliptic/Makefile11
-rw-r--r--src/pkg/crypto/elliptic/elliptic.go376
-rw-r--r--src/pkg/crypto/elliptic/elliptic_test.go331
-rw-r--r--src/pkg/crypto/hmac/Makefile2
-rw-r--r--src/pkg/crypto/hmac/hmac.go44
-rw-r--r--src/pkg/crypto/hmac/hmac_test.go127
-rw-r--r--src/pkg/crypto/md4/Makefile2
-rw-r--r--src/pkg/crypto/md4/md4.go5
-rw-r--r--src/pkg/crypto/md4/md4_test.go62
-rw-r--r--src/pkg/crypto/md5/Makefile2
-rw-r--r--src/pkg/crypto/md5/md5.go5
-rw-r--r--src/pkg/crypto/md5/md5_test.go62
-rw-r--r--src/pkg/crypto/ocsp/Makefile (renamed from src/pkg/exp/iterable/Makefile)7
-rw-r--r--src/pkg/crypto/ocsp/ocsp.go203
-rw-r--r--src/pkg/crypto/ocsp/ocsp_test.go97
-rw-r--r--src/pkg/crypto/openpgp/armor/Makefile (renamed from src/pkg/exp/nacl/av/Makefile)11
-rw-r--r--src/pkg/crypto/openpgp/armor/armor.go220
-rw-r--r--src/pkg/crypto/openpgp/armor/armor_test.go97
-rw-r--r--src/pkg/crypto/openpgp/armor/encode.go162
-rw-r--r--src/pkg/crypto/openpgp/error/Makefile11
-rw-r--r--src/pkg/crypto/openpgp/error/error.go46
-rw-r--r--src/pkg/crypto/rand/Makefile16
-rw-r--r--src/pkg/crypto/rand/rand.go113
-rw-r--r--src/pkg/crypto/rand/rand_unix.go125
-rwxr-xr-xsrc/pkg/crypto/rand/rand_windows.go43
-rw-r--r--src/pkg/crypto/rc4/Makefile2
-rw-r--r--src/pkg/crypto/rc4/rc4.go10
-rw-r--r--src/pkg/crypto/rc4/rc4_test.go12
-rw-r--r--src/pkg/crypto/ripemd160/Makefile2
-rw-r--r--src/pkg/crypto/ripemd160/ripemd160.go5
-rw-r--r--src/pkg/crypto/ripemd160/ripemd160_test.go16
-rw-r--r--src/pkg/crypto/rsa/Makefile2
-rw-r--r--src/pkg/crypto/rsa/pkcs1v15.go20
-rw-r--r--src/pkg/crypto/rsa/pkcs1v15_test.go36
-rw-r--r--src/pkg/crypto/rsa/rsa_test.go30
-rw-r--r--src/pkg/crypto/sha1/Makefile2
-rw-r--r--src/pkg/crypto/sha1/sha1.go5
-rw-r--r--src/pkg/crypto/sha1/sha1_test.go62
-rw-r--r--src/pkg/crypto/sha256/Makefile2
-rw-r--r--src/pkg/crypto/sha256/sha256.go5
-rw-r--r--src/pkg/crypto/sha256/sha256_test.go124
-rw-r--r--src/pkg/crypto/sha512/Makefile2
-rw-r--r--src/pkg/crypto/sha512/sha512.go5
-rw-r--r--src/pkg/crypto/sha512/sha512_test.go124
-rw-r--r--src/pkg/crypto/subtle/Makefile2
-rw-r--r--src/pkg/crypto/subtle/constant_time_test.go16
-rw-r--r--src/pkg/crypto/tls/Makefile4
-rw-r--r--src/pkg/crypto/tls/ca_set.go50
-rw-r--r--src/pkg/crypto/tls/cipher_suites.go102
-rw-r--r--src/pkg/crypto/tls/common.go176
-rw-r--r--src/pkg/crypto/tls/conn.go232
-rw-r--r--src/pkg/crypto/tls/conn_test.go52
-rw-r--r--src/pkg/crypto/tls/generate_cert.go70
-rw-r--r--src/pkg/crypto/tls/handshake_client.go215
-rw-r--r--src/pkg/crypto/tls/handshake_client_test.go211
-rw-r--r--src/pkg/crypto/tls/handshake_messages.go367
-rw-r--r--src/pkg/crypto/tls/handshake_messages_test.go37
-rw-r--r--src/pkg/crypto/tls/handshake_server.go189
-rw-r--r--src/pkg/crypto/tls/handshake_server_test.go443
-rw-r--r--src/pkg/crypto/tls/key_agreement.go246
-rw-r--r--src/pkg/crypto/tls/parse-gnutls-cli-debug-log.py55
-rw-r--r--src/pkg/crypto/tls/prf.go39
-rw-r--r--src/pkg/crypto/tls/prf_test.go18
-rw-r--r--src/pkg/crypto/tls/tls.go108
-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/Makefile2
-rw-r--r--src/pkg/crypto/x509/x509.go222
-rw-r--r--src/pkg/crypto/x509/x509_test.go43
-rw-r--r--src/pkg/crypto/xtea/Makefile2
-rw-r--r--src/pkg/crypto/xtea/block.go4
-rw-r--r--src/pkg/crypto/xtea/cipher.go4
-rw-r--r--src/pkg/crypto/xtea/xtea_test.go28
-rw-r--r--src/pkg/debug/dwarf/Makefile2
-rw-r--r--src/pkg/debug/dwarf/type.go26
-rw-r--r--src/pkg/debug/elf/Makefile2
-rw-r--r--src/pkg/debug/elf/elf.go917
-rw-r--r--src/pkg/debug/elf/elf_test.go44
-rw-r--r--src/pkg/debug/elf/file.go161
-rw-r--r--src/pkg/debug/elf/file_test.go150
-rw-r--r--src/pkg/debug/gosym/Makefile2
-rw-r--r--src/pkg/debug/gosym/pclinetest.s35
-rw-r--r--src/pkg/debug/gosym/pclntab_test.go2
-rw-r--r--src/pkg/debug/macho/Makefile2
-rw-r--r--src/pkg/debug/macho/file.go167
-rw-r--r--src/pkg/debug/macho/file_test.go6
-rw-r--r--src/pkg/debug/macho/macho.go90
-rw-r--r--src/pkg/debug/pe/Makefile (renamed from src/pkg/exp/nacl/srpc/Makefile)11
-rw-r--r--src/pkg/debug/pe/file.go231
-rw-r--r--src/pkg/debug/pe/file_test.go99
-rw-r--r--src/pkg/debug/pe/pe.go51
-rw-r--r--src/pkg/debug/pe/testdata/gcc-386-mingw-execbin0 -> 29941 bytes
-rw-r--r--src/pkg/debug/pe/testdata/gcc-386-mingw-objbin0 -> 2372 bytes
-rw-r--r--src/pkg/debug/pe/testdata/hello.c8
-rw-r--r--src/pkg/debug/proc/Makefile2
-rw-r--r--src/pkg/debug/proc/proc_linux.go29
-rw-r--r--src/pkg/debug/proc/proc_nacl.go20
-rw-r--r--src/pkg/debug/proc/regs_linux_386.go24
-rw-r--r--src/pkg/debug/proc/regs_linux_amd64.go2
-rwxr-xr-xsrc/pkg/deps.bash7
-rw-r--r--src/pkg/ebnf/Makefile2
-rw-r--r--src/pkg/ebnf/ebnf.go91
-rw-r--r--src/pkg/ebnf/ebnf_test.go8
-rw-r--r--src/pkg/ebnf/parser.go68
-rw-r--r--src/pkg/encoding/ascii85/Makefile2
-rw-r--r--src/pkg/encoding/ascii85/ascii85_test.go8
-rw-r--r--src/pkg/encoding/base64/Makefile2
-rw-r--r--src/pkg/encoding/base64/base64_test.go50
-rw-r--r--src/pkg/encoding/binary/Makefile2
-rw-r--r--src/pkg/encoding/binary/binary.go59
-rw-r--r--src/pkg/encoding/binary/binary_test.go82
-rw-r--r--src/pkg/encoding/git85/Makefile2
-rw-r--r--src/pkg/encoding/git85/git_test.go8
-rw-r--r--src/pkg/encoding/hex/Makefile2
-rw-r--r--src/pkg/encoding/hex/hex.go2
-rw-r--r--src/pkg/encoding/hex/hex_test.go112
-rw-r--r--src/pkg/encoding/line/Makefile11
-rw-r--r--src/pkg/encoding/line/line.go95
-rw-r--r--src/pkg/encoding/line/line_test.go89
-rw-r--r--src/pkg/encoding/pem/Makefile2
-rw-r--r--src/pkg/encoding/pem/pem.go13
-rw-r--r--src/pkg/encoding/pem/pem_test.go28
-rw-r--r--src/pkg/exec/Makefile16
-rw-r--r--src/pkg/exec/exec.go46
-rw-r--r--src/pkg/exec/exec_test.go46
-rw-r--r--src/pkg/exec/lp_unix.go45
-rw-r--r--src/pkg/exec/lp_windows.go66
-rw-r--r--src/pkg/exp/4s/4s.go79
-rw-r--r--src/pkg/exp/4s/4s.html26
-rw-r--r--src/pkg/exp/4s/5s.go9
-rw-r--r--src/pkg/exp/4s/5s.html26
-rw-r--r--src/pkg/exp/4s/Makefile20
-rw-r--r--src/pkg/exp/4s/data.go142
-rw-r--r--src/pkg/exp/4s/xs.go742
-rw-r--r--src/pkg/exp/bignum/Makefile14
-rw-r--r--src/pkg/exp/bignum/arith.go121
-rw-r--r--src/pkg/exp/bignum/arith_amd64.s41
-rw-r--r--src/pkg/exp/bignum/bignum.go1024
-rw-r--r--src/pkg/exp/bignum/bignum_test.go681
-rw-r--r--src/pkg/exp/bignum/integer.go520
-rw-r--r--src/pkg/exp/bignum/nrdiv_test.go188
-rw-r--r--src/pkg/exp/bignum/rational.go205
-rw-r--r--src/pkg/exp/datafmt/Makefile2
-rw-r--r--src/pkg/exp/datafmt/datafmt.go8
-rw-r--r--src/pkg/exp/datafmt/datafmt_test.go10
-rw-r--r--src/pkg/exp/datafmt/parser.go38
-rw-r--r--src/pkg/exp/draw/Makefile4
-rw-r--r--src/pkg/exp/draw/arith.go155
-rw-r--r--src/pkg/exp/draw/color.go105
-rw-r--r--src/pkg/exp/draw/draw.go207
-rw-r--r--src/pkg/exp/draw/draw_test.go129
-rw-r--r--src/pkg/exp/draw/event.go66
-rw-r--r--src/pkg/exp/draw/x11/Makefile2
-rw-r--r--src/pkg/exp/draw/x11/conn.go170
-rw-r--r--src/pkg/exp/eval/Makefile16
-rw-r--r--src/pkg/exp/eval/bridge.go12
-rw-r--r--src/pkg/exp/eval/compiler.go14
-rw-r--r--src/pkg/exp/eval/eval_test.go49
-rw-r--r--src/pkg/exp/eval/expr.go206
-rwxr-xr-x[-rw-r--r--]src/pkg/exp/eval/expr1.go198
-rw-r--r--src/pkg/exp/eval/expr_test.go91
-rw-r--r--src/pkg/exp/eval/func.go15
-rw-r--r--src/pkg/exp/eval/gen.go126
-rw-r--r--src/pkg/exp/eval/main.go12
-rw-r--r--src/pkg/exp/eval/scope.go40
-rw-r--r--src/pkg/exp/eval/stmt.go101
-rwxr-xr-xsrc/pkg/exp/eval/test.bash6
-rw-r--r--src/pkg/exp/eval/type.go85
-rw-r--r--src/pkg/exp/eval/typec.go54
-rw-r--r--src/pkg/exp/eval/util.go39
-rw-r--r--src/pkg/exp/eval/value.go18
-rw-r--r--src/pkg/exp/eval/world.go33
-rw-r--r--src/pkg/exp/iterable/array.go59
-rw-r--r--src/pkg/exp/iterable/iterable.go344
-rw-r--r--src/pkg/exp/iterable/iterable_test.go387
-rw-r--r--src/pkg/exp/nacl/README36
-rw-r--r--src/pkg/exp/nacl/av/av.go299
-rw-r--r--src/pkg/exp/nacl/av/event.go472
-rw-r--r--src/pkg/exp/nacl/av/image.go85
-rw-r--r--src/pkg/exp/nacl/srpc/client.go210
-rw-r--r--src/pkg/exp/nacl/srpc/msg.go526
-rw-r--r--src/pkg/exp/nacl/srpc/server.go201
-rw-r--r--src/pkg/exp/ogle/Makefile6
-rw-r--r--src/pkg/exp/ogle/cmd.go12
-rw-r--r--src/pkg/exp/ogle/process.go14
-rw-r--r--src/pkg/exp/ogle/rtype.go4
-rw-r--r--src/pkg/exp/ogle/vars.go4
-rw-r--r--src/pkg/exp/spacewar/Makefile18
-rw-r--r--src/pkg/exp/spacewar/code.go7556
-rw-r--r--src/pkg/exp/spacewar/pdp1.go389
-rw-r--r--src/pkg/exp/spacewar/spacewar.go196
-rw-r--r--src/pkg/exp/spacewar/spacewar.html21
-rw-r--r--src/pkg/expvar/Makefile2
-rw-r--r--src/pkg/expvar/expvar.go26
-rw-r--r--src/pkg/expvar/expvar_test.go24
-rw-r--r--src/pkg/flag/Makefile2
-rw-r--r--src/pkg/flag/export_test.go32
-rw-r--r--src/pkg/flag/flag.go114
-rw-r--r--src/pkg/flag/flag_test.go24
-rw-r--r--src/pkg/fmt/Makefile3
-rw-r--r--src/pkg/fmt/doc.go163
-rw-r--r--src/pkg/fmt/fmt_test.go612
-rw-r--r--src/pkg/fmt/format.go11
-rw-r--r--src/pkg/fmt/print.go384
-rw-r--r--src/pkg/fmt/scan.go138
-rw-r--r--src/pkg/fmt/scan_test.go422
-rw-r--r--src/pkg/go/ast/Makefile3
-rw-r--r--src/pkg/go/ast/ast.go562
-rw-r--r--src/pkg/go/ast/filter.go41
-rw-r--r--src/pkg/go/ast/print.go217
-rw-r--r--src/pkg/go/ast/scope.go259
-rw-r--r--src/pkg/go/ast/walk.go301
-rw-r--r--src/pkg/go/doc/Makefile2
-rw-r--r--src/pkg/go/doc/comment.go25
-rw-r--r--src/pkg/go/doc/doc.go74
-rw-r--r--src/pkg/go/parser/Makefile2
-rw-r--r--src/pkg/go/parser/interface.go80
-rw-r--r--src/pkg/go/parser/parser.go769
-rw-r--r--src/pkg/go/parser/parser_test.go37
-rw-r--r--src/pkg/go/printer/Makefile2
-rw-r--r--src/pkg/go/printer/nodes.go257
-rw-r--r--src/pkg/go/printer/printer.go241
-rw-r--r--src/pkg/go/printer/printer_test.go24
-rw-r--r--src/pkg/go/printer/testdata/comments.golden32
-rw-r--r--src/pkg/go/printer/testdata/comments.input34
-rw-r--r--src/pkg/go/printer/testdata/declarations.golden115
-rw-r--r--src/pkg/go/printer/testdata/declarations.input83
-rw-r--r--src/pkg/go/printer/testdata/expressions.golden77
-rw-r--r--src/pkg/go/printer/testdata/expressions.input74
-rw-r--r--src/pkg/go/printer/testdata/expressions.raw77
-rw-r--r--src/pkg/go/printer/testdata/statements.golden81
-rw-r--r--src/pkg/go/printer/testdata/statements.input70
-rw-r--r--src/pkg/go/scanner/Makefile2
-rw-r--r--src/pkg/go/scanner/scanner.go336
-rw-r--r--src/pkg/go/scanner/scanner_test.go496
-rw-r--r--src/pkg/go/token/Makefile3
-rw-r--r--src/pkg/go/token/position.go409
-rw-r--r--src/pkg/go/token/position_test.go158
-rw-r--r--src/pkg/go/token/token.go41
-rw-r--r--src/pkg/go/typechecker/Makefile13
-rw-r--r--src/pkg/go/typechecker/scope.go119
-rw-r--r--src/pkg/go/typechecker/testdata/test0.go94
-rw-r--r--src/pkg/go/typechecker/testdata/test1.go13
-rw-r--r--src/pkg/go/typechecker/testdata/test3.go38
-rw-r--r--src/pkg/go/typechecker/testdata/test4.go11
-rw-r--r--src/pkg/go/typechecker/typechecker.go484
-rw-r--r--src/pkg/go/typechecker/typechecker_test.go167
-rw-r--r--src/pkg/go/typechecker/universe.go38
-rw-r--r--src/pkg/gob/Makefile4
-rw-r--r--src/pkg/gob/codec_test.go772
-rw-r--r--src/pkg/gob/debug.go310
-rw-r--r--src/pkg/gob/decode.go488
-rw-r--r--src/pkg/gob/decoder.go121
-rw-r--r--src/pkg/gob/doc.go307
-rw-r--r--src/pkg/gob/encode.go541
-rw-r--r--src/pkg/gob/encoder.go81
-rw-r--r--src/pkg/gob/encoder_test.go205
-rw-r--r--src/pkg/gob/error.go41
-rw-r--r--src/pkg/gob/type.go265
-rw-r--r--src/pkg/gob/type_test.go12
-rw-r--r--src/pkg/hash/Makefile2
-rw-r--r--src/pkg/hash/adler32/Makefile2
-rw-r--r--src/pkg/hash/adler32/adler32_test.go64
-rw-r--r--src/pkg/hash/crc32/Makefile2
-rw-r--r--src/pkg/hash/crc32/crc32_test.go62
-rw-r--r--src/pkg/hash/crc64/Makefile2
-rw-r--r--src/pkg/hash/crc64/crc64.go2
-rw-r--r--src/pkg/hash/crc64/crc64_test.go62
-rw-r--r--src/pkg/html/Makefile15
-rw-r--r--src/pkg/html/doc.go106
-rw-r--r--src/pkg/html/entity.go2250
-rw-r--r--src/pkg/html/entity_test.go26
-rw-r--r--src/pkg/html/escape.go224
-rw-r--r--src/pkg/html/parse.go666
-rw-r--r--src/pkg/html/parse_test.go158
-rw-r--r--src/pkg/html/token.go398
-rw-r--r--src/pkg/html/token_test.go231
-rw-r--r--src/pkg/http/Makefile2
-rw-r--r--src/pkg/http/client.go70
-rw-r--r--src/pkg/http/fs.go143
-rw-r--r--src/pkg/http/fs_test.go172
-rw-r--r--src/pkg/http/lex_test.go10
-rw-r--r--src/pkg/http/pprof/Makefile2
-rw-r--r--src/pkg/http/pprof/pprof.go26
-rw-r--r--src/pkg/http/readrequest_test.go20
-rw-r--r--src/pkg/http/request.go113
-rw-r--r--src/pkg/http/request_test.go60
-rw-r--r--src/pkg/http/requestwrite_test.go26
-rw-r--r--src/pkg/http/response.go8
-rw-r--r--src/pkg/http/response_test.go46
-rw-r--r--src/pkg/http/responsewrite_test.go19
-rw-r--r--src/pkg/http/serve_test.go135
-rw-r--r--src/pkg/http/server.go542
-rw-r--r--src/pkg/http/status.go6
-rw-r--r--src/pkg/http/testdata/file1
-rw-r--r--src/pkg/http/transfer.go23
-rw-r--r--src/pkg/http/triv.go77
-rw-r--r--src/pkg/http/url.go287
-rw-r--r--src/pkg/http/url_test.go377
-rw-r--r--src/pkg/image/Makefile4
-rw-r--r--src/pkg/image/color.go45
-rw-r--r--src/pkg/image/format.go86
-rw-r--r--src/pkg/image/geom.go223
-rw-r--r--src/pkg/image/image.go482
-rw-r--r--src/pkg/image/jpeg/Makefile4
-rw-r--r--src/pkg/image/jpeg/reader.go33
-rw-r--r--src/pkg/image/names.go71
-rw-r--r--src/pkg/image/png/Makefile2
-rw-r--r--src/pkg/image/png/reader.go248
-rw-r--r--src/pkg/image/png/reader_test.go84
-rw-r--r--src/pkg/image/png/writer.go162
-rw-r--r--src/pkg/image/png/writer_test.go27
-rw-r--r--src/pkg/index/suffixarray/Makefile12
-rw-r--r--src/pkg/index/suffixarray/qsufsort.go164
-rw-r--r--src/pkg/index/suffixarray/suffixarray.go182
-rw-r--r--src/pkg/index/suffixarray/suffixarray_test.go234
-rw-r--r--src/pkg/io/Makefile3
-rw-r--r--src/pkg/io/io.go25
-rw-r--r--src/pkg/io/io_test.go76
-rw-r--r--src/pkg/io/ioutil/Makefile2
-rw-r--r--src/pkg/io/ioutil/ioutil.go2
-rw-r--r--src/pkg/io/ioutil/ioutil_test.go12
-rw-r--r--src/pkg/io/ioutil/tempfile_test.go2
-rw-r--r--src/pkg/io/multi.go60
-rw-r--r--src/pkg/io/multi_test.go88
-rw-r--r--src/pkg/io/pipe.go27
-rw-r--r--src/pkg/io/pipe_test.go12
-rw-r--r--src/pkg/json/Makefile2
-rw-r--r--src/pkg/json/decode.go50
-rw-r--r--src/pkg/json/decode_test.go107
-rw-r--r--src/pkg/json/encode.go99
-rw-r--r--src/pkg/json/scanner.go19
-rw-r--r--src/pkg/json/scanner_test.go22
-rw-r--r--src/pkg/json/stream.go3
-rw-r--r--src/pkg/json/stream_test.go4
-rw-r--r--src/pkg/log/Makefile2
-rw-r--r--src/pkg/log/log.go283
-rw-r--r--src/pkg/log/log_test.go70
-rw-r--r--src/pkg/math/Makefile10
-rw-r--r--src/pkg/math/all_test.go700
-rw-r--r--src/pkg/math/bits.go2
-rw-r--r--src/pkg/math/const.go10
-rw-r--r--src/pkg/math/exp.go129
-rw-r--r--src/pkg/math/exp2.go2
-rw-r--r--src/pkg/math/exp_amd64.s92
-rw-r--r--src/pkg/math/exp_port.go192
-rw-r--r--src/pkg/math/exp_test.go10
-rw-r--r--src/pkg/math/frexp.go4
-rw-r--r--src/pkg/math/hypot_amd64.s50
-rw-r--r--src/pkg/math/log.go8
-rw-r--r--src/pkg/math/log10.go13
-rw-r--r--src/pkg/math/log10_386.s19
-rw-r--r--src/pkg/math/log10_decl.go8
-rw-r--r--src/pkg/math/log_386.s16
-rw-r--r--src/pkg/math/log_amd64.s109
-rw-r--r--src/pkg/math/log_decl.go2
-rw-r--r--src/pkg/math/logb.go4
-rw-r--r--src/pkg/math/modf.go6
-rw-r--r--src/pkg/math/sincos_amd64.s143
-rw-r--r--src/pkg/math/sqrt_port.go4
-rw-r--r--src/pkg/math/tan.go2
-rw-r--r--src/pkg/mime/Makefile4
-rw-r--r--src/pkg/mime/grammar.go36
-rw-r--r--src/pkg/mime/mediatype.go120
-rw-r--r--src/pkg/mime/mediatype_test.go117
-rw-r--r--src/pkg/mime/multipart/Makefile11
-rw-r--r--src/pkg/mime/multipart/multipart.go280
-rw-r--r--src/pkg/mime/multipart/multipart_test.go204
-rw-r--r--src/pkg/mime/type.go42
-rw-r--r--src/pkg/net/Makefile21
-rw-r--r--src/pkg/net/dial.go2
-rw-r--r--src/pkg/net/dialgoogle_test.go2
-rw-r--r--src/pkg/net/dict/Makefile7
-rw-r--r--src/pkg/net/dict/dict.go212
-rw-r--r--src/pkg/net/dnsclient.go63
-rw-r--r--src/pkg/net/dnsmsg.go5
-rw-r--r--src/pkg/net/dnsname_test.go69
-rw-r--r--src/pkg/net/fd.go99
-rw-r--r--src/pkg/net/fd_freebsd.go6
-rw-r--r--src/pkg/net/fd_nacl.go33
-rw-r--r--src/pkg/net/fd_windows.go160
-rw-r--r--src/pkg/net/hosts.go14
-rw-r--r--src/pkg/net/hosts_test.go10
-rw-r--r--src/pkg/net/ip.go5
-rw-r--r--src/pkg/net/ip_test.go56
-rw-r--r--src/pkg/net/iprawsock.go15
-rw-r--r--src/pkg/net/ipsock.go6
-rw-r--r--src/pkg/net/net.go6
-rw-r--r--src/pkg/net/net_test.go16
-rw-r--r--src/pkg/net/parse_test.go5
-rw-r--r--src/pkg/net/port.go5
-rw-r--r--src/pkg/net/port_test.go49
-rw-r--r--src/pkg/net/resolv_windows.go83
-rw-r--r--src/pkg/net/server_test.go9
-rw-r--r--src/pkg/net/sock.go18
-rw-r--r--src/pkg/net/srv_test.go22
-rw-r--r--src/pkg/net/tcpsock.go32
-rw-r--r--src/pkg/net/textproto/Makefile14
-rw-r--r--src/pkg/net/textproto/pipeline.go117
-rw-r--r--src/pkg/net/textproto/reader.go492
-rw-r--r--src/pkg/net/textproto/reader_test.go140
-rw-r--r--src/pkg/net/textproto/textproto.go122
-rw-r--r--src/pkg/net/textproto/writer.go119
-rw-r--r--src/pkg/net/textproto/writer_test.go35
-rw-r--r--src/pkg/net/timeout_test.go5
-rw-r--r--src/pkg/net/udpsock.go12
-rw-r--r--src/pkg/net/unixsock.go38
-rw-r--r--src/pkg/netchan/Makefile2
-rw-r--r--src/pkg/netchan/common.go121
-rw-r--r--src/pkg/netchan/export.go238
-rw-r--r--src/pkg/netchan/import.go128
-rw-r--r--src/pkg/netchan/netchan_test.go329
-rw-r--r--src/pkg/nntp/nntp.go709
-rw-r--r--src/pkg/nntp/nntp_test.go241
-rw-r--r--src/pkg/once/once.go59
-rw-r--r--src/pkg/once/once_test.go30
-rw-r--r--src/pkg/os/Makefile9
-rw-r--r--src/pkg/os/dir_darwin.go12
-rw-r--r--src/pkg/os/dir_freebsd.go12
-rw-r--r--src/pkg/os/dir_linux.go12
-rw-r--r--src/pkg/os/dir_nacl.go77
-rw-r--r--src/pkg/os/env.go119
-rw-r--r--src/pkg/os/env_test.go59
-rw-r--r--[-rwxr-xr-x]src/pkg/os/env_unix.go83
-rw-r--r--[-rwxr-xr-x]src/pkg/os/env_windows.go98
-rw-r--r--src/pkg/os/exec.go23
-rw-r--r--src/pkg/os/file.go45
-rw-r--r--src/pkg/os/file_unix.go10
-rw-r--r--src/pkg/os/file_windows.go39
-rw-r--r--src/pkg/os/inotify/Makefile14
-rw-r--r--src/pkg/os/inotify/inotify_linux.go291
-rw-r--r--src/pkg/os/inotify/inotify_linux_test.go99
-rw-r--r--src/pkg/os/os_test.go420
-rw-r--r--src/pkg/os/path.go8
-rw-r--r--src/pkg/os/path_test.go79
-rw-r--r--src/pkg/os/signal/Makefile2
-rw-r--r--src/pkg/os/stat_nacl.go38
-rw-r--r--src/pkg/os/stat_windows.go10
-rw-r--r--src/pkg/os/sys_nacl.go7
-rw-r--r--src/pkg/os/types.go2
-rw-r--r--src/pkg/patch/Makefile2
-rw-r--r--src/pkg/patch/patch_test.go28
-rw-r--r--src/pkg/path/Makefile16
-rw-r--r--src/pkg/path/match.go74
-rw-r--r--src/pkg/path/match_test.go128
-rw-r--r--src/pkg/path/path.go20
-rw-r--r--src/pkg/path/path_test.go176
-rw-r--r--src/pkg/path/path_unix.go11
-rw-r--r--src/pkg/path/path_windows.go11
-rw-r--r--src/pkg/rand/Makefile2
-rw-r--r--src/pkg/rand/rand_test.go12
-rw-r--r--src/pkg/reflect/Makefile2
-rw-r--r--src/pkg/reflect/all_test.go375
-rw-r--r--src/pkg/reflect/type.go2
-rw-r--r--src/pkg/reflect/value.go95
-rw-r--r--src/pkg/regexp/Makefile2
-rw-r--r--src/pkg/regexp/all_test.go479
-rw-r--r--src/pkg/regexp/find_test.go459
-rw-r--r--src/pkg/regexp/regexp.go950
-rw-r--r--src/pkg/rpc/Makefile2
-rw-r--r--src/pkg/rpc/client.go21
-rw-r--r--src/pkg/rpc/debug.go36
-rw-r--r--src/pkg/rpc/jsonrpc/Makefile2
-rw-r--r--src/pkg/rpc/jsonrpc/all_test.go13
-rw-r--r--src/pkg/rpc/jsonrpc/client.go17
-rw-r--r--src/pkg/rpc/jsonrpc/server.go14
-rw-r--r--src/pkg/rpc/server.go191
-rw-r--r--src/pkg/rpc/server_test.go126
-rw-r--r--src/pkg/runtime/386/asm.s90
-rw-r--r--src/pkg/runtime/386/closure.c17
-rw-r--r--src/pkg/runtime/386/memmove.s3
-rw-r--r--src/pkg/runtime/386/vlop.s4
-rw-r--r--src/pkg/runtime/386/vlrt.c12
-rw-r--r--src/pkg/runtime/Makefile42
-rw-r--r--src/pkg/runtime/amd64/asm.s290
-rw-r--r--src/pkg/runtime/amd64/closure.c12
-rw-r--r--src/pkg/runtime/amd64/memmove.s2
-rw-r--r--src/pkg/runtime/amd64/traceback.c44
-rw-r--r--src/pkg/runtime/arm/asm.s112
-rw-r--r--src/pkg/runtime/arm/cas5.s8
-rw-r--r--src/pkg/runtime/arm/cas6.s2
-rw-r--r--src/pkg/runtime/arm/closure.c14
-rw-r--r--src/pkg/runtime/arm/memmove.s2
-rw-r--r--src/pkg/runtime/arm/memset.s2
-rw-r--r--src/pkg/runtime/arm/softfloat.c784
-rw-r--r--src/pkg/runtime/arm/traceback.c32
-rw-r--r--src/pkg/runtime/arm/vlop.s22
-rw-r--r--src/pkg/runtime/arm/vlrt.c854
-rwxr-xr-xsrc/pkg/runtime/cgo/386.S (renamed from src/libcgo/386.S)8
-rw-r--r--src/pkg/runtime/cgo/Makefile61
-rw-r--r--src/pkg/runtime/cgo/amd64.S (renamed from src/libcgo/amd64.S)16
-rw-r--r--src/pkg/runtime/cgo/arm.S (renamed from src/libcgo/linux_arm.c)0
-rw-r--r--src/pkg/runtime/cgo/callbacks.c73
-rw-r--r--src/pkg/runtime/cgo/cgo.go17
-rw-r--r--src/pkg/runtime/cgo/darwin_386.c (renamed from src/libcgo/darwin_386.c)14
-rw-r--r--src/pkg/runtime/cgo/darwin_amd64.c125
-rw-r--r--src/pkg/runtime/cgo/freebsd.c13
-rw-r--r--src/pkg/runtime/cgo/freebsd_386.c (renamed from src/libcgo/freebsd_386.c)10
-rw-r--r--src/pkg/runtime/cgo/freebsd_amd64.c (renamed from src/libcgo/linux_amd64.c)43
-rw-r--r--src/pkg/runtime/cgo/iscgo.c14
-rw-r--r--src/pkg/runtime/cgo/libcgo.h (renamed from src/libcgo/libcgo.h)8
-rw-r--r--src/pkg/runtime/cgo/linux_386.c68
-rw-r--r--src/pkg/runtime/cgo/linux_amd64.c (renamed from src/libcgo/linux_386.c)17
-rw-r--r--src/pkg/runtime/cgo/linux_arm.c19
-rw-r--r--src/pkg/runtime/cgo/nacl_386.c19
-rw-r--r--src/pkg/runtime/cgo/util.c (renamed from src/libcgo/util.c)17
-rwxr-xr-xsrc/pkg/runtime/cgo/windows_386.c57
-rwxr-xr-xsrc/pkg/runtime/cgo/windows_amd64.c (renamed from src/libcgo/windows_amd64.c)32
-rw-r--r--src/pkg/runtime/cgocall.c54
-rw-r--r--src/pkg/runtime/cgocall.h8
-rw-r--r--src/pkg/runtime/chan.c294
-rw-r--r--src/pkg/runtime/chan_defs.go56
-rw-r--r--src/pkg/runtime/complex.c26
-rw-r--r--src/pkg/runtime/darwin/386/defs.h1
-rw-r--r--src/pkg/runtime/darwin/386/rt0.s2
-rw-r--r--src/pkg/runtime/darwin/386/signal.c105
-rw-r--r--src/pkg/runtime/darwin/386/sys.s85
-rw-r--r--src/pkg/runtime/darwin/amd64/defs.h1
-rw-r--r--src/pkg/runtime/darwin/amd64/rt0.s2
-rw-r--r--src/pkg/runtime/darwin/amd64/signal.c120
-rw-r--r--src/pkg/runtime/darwin/amd64/sys.s122
-rw-r--r--src/pkg/runtime/darwin/defs.c1
-rw-r--r--src/pkg/runtime/darwin/mem.c25
-rw-r--r--src/pkg/runtime/darwin/os.h34
-rw-r--r--src/pkg/runtime/darwin/runtime_defs.go23
-rw-r--r--src/pkg/runtime/darwin/signals.h2
-rw-r--r--src/pkg/runtime/darwin/thread.c187
-rw-r--r--src/pkg/runtime/debug.go23
-rw-r--r--src/pkg/runtime/error.go4
-rw-r--r--src/pkg/runtime/export_test.go17
-rw-r--r--src/pkg/runtime/extern.go59
-rw-r--r--src/pkg/runtime/float.c52
-rw-r--r--src/pkg/runtime/freebsd/386/defs.h1
-rw-r--r--src/pkg/runtime/freebsd/386/rt0.s2
-rw-r--r--src/pkg/runtime/freebsd/386/signal.c104
-rw-r--r--src/pkg/runtime/freebsd/386/sys.s70
-rw-r--r--src/pkg/runtime/freebsd/amd64/defs.h1
-rw-r--r--src/pkg/runtime/freebsd/amd64/rt0.s2
-rw-r--r--src/pkg/runtime/freebsd/amd64/signal.c120
-rw-r--r--src/pkg/runtime/freebsd/amd64/sys.s81
-rw-r--r--src/pkg/runtime/freebsd/defs.c1
-rw-r--r--src/pkg/runtime/freebsd/mem.c25
-rw-r--r--src/pkg/runtime/freebsd/os.h8
-rw-r--r--src/pkg/runtime/freebsd/runtime_defs.go14
-rw-r--r--src/pkg/runtime/freebsd/signals.h2
-rw-r--r--src/pkg/runtime/freebsd/thread.c88
-rw-r--r--src/pkg/runtime/goc2c.c6
-rw-r--r--src/pkg/runtime/hashmap.c241
-rw-r--r--src/pkg/runtime/hashmap.h27
-rw-r--r--src/pkg/runtime/hashmap_defs.go51
-rw-r--r--src/pkg/runtime/iface.c192
-rw-r--r--src/pkg/runtime/iface_defs.go18
-rw-r--r--src/pkg/runtime/linux/386/defs.h1
-rw-r--r--src/pkg/runtime/linux/386/rt0.s10
-rw-r--r--src/pkg/runtime/linux/386/signal.c108
-rw-r--r--src/pkg/runtime/linux/386/sys.s55
-rw-r--r--src/pkg/runtime/linux/amd64/defs.h1
-rw-r--r--src/pkg/runtime/linux/amd64/rt0.s2
-rw-r--r--src/pkg/runtime/linux/amd64/signal.c124
-rw-r--r--src/pkg/runtime/linux/amd64/sys.s96
-rw-r--r--src/pkg/runtime/linux/arm/defs.h27
-rw-r--r--src/pkg/runtime/linux/arm/rt0.s2
-rw-r--r--src/pkg/runtime/linux/arm/signal.c118
-rw-r--r--src/pkg/runtime/linux/arm/sys.s47
-rw-r--r--src/pkg/runtime/linux/defs.c1
-rw-r--r--src/pkg/runtime/linux/defs2.c1
-rw-r--r--src/pkg/runtime/linux/defs_arm.c29
-rw-r--r--src/pkg/runtime/linux/mem.c27
-rw-r--r--src/pkg/runtime/linux/os.h10
-rw-r--r--src/pkg/runtime/linux/runtime_defs.go14
-rw-r--r--src/pkg/runtime/linux/signals.h2
-rw-r--r--src/pkg/runtime/linux/thread.c90
-rw-r--r--src/pkg/runtime/malloc.goc165
-rw-r--r--src/pkg/runtime/malloc.h88
-rw-r--r--src/pkg/runtime/malloc_defs.go130
-rw-r--r--src/pkg/runtime/mcache.c25
-rw-r--r--src/pkg/runtime/mcentral.c66
-rw-r--r--src/pkg/runtime/mfinal.c48
-rw-r--r--src/pkg/runtime/mfixalloc.c8
-rw-r--r--src/pkg/runtime/mgc0.c227
-rw-r--r--src/pkg/runtime/mheap.c122
-rw-r--r--src/pkg/runtime/mheapmap32.c16
-rw-r--r--src/pkg/runtime/mheapmap32.h10
-rw-r--r--src/pkg/runtime/mheapmap32_defs.go23
-rw-r--r--src/pkg/runtime/mheapmap64.c16
-rw-r--r--src/pkg/runtime/mheapmap64.h10
-rw-r--r--src/pkg/runtime/mheapmap64_defs.go31
-rwxr-xr-xsrc/pkg/runtime/mkasmh.sh46
-rw-r--r--src/pkg/runtime/mkversion.c6
-rw-r--r--src/pkg/runtime/mprof.goc30
-rw-r--r--src/pkg/runtime/msize.c82
-rw-r--r--src/pkg/runtime/nacl/386/closure.c247
-rw-r--r--src/pkg/runtime/nacl/386/defs.h17
-rw-r--r--src/pkg/runtime/nacl/386/rt0.s8
-rw-r--r--src/pkg/runtime/nacl/386/signal.c14
-rw-r--r--src/pkg/runtime/nacl/386/sys.s138
-rw-r--r--src/pkg/runtime/nacl/defs.c27
-rw-r--r--src/pkg/runtime/nacl/mem.c28
-rw-r--r--src/pkg/runtime/nacl/os.h9
-rw-r--r--src/pkg/runtime/nacl/signals.h0
-rw-r--r--src/pkg/runtime/nacl/thread.c164
-rw-r--r--src/pkg/runtime/plan9/386/defs.h1
-rw-r--r--src/pkg/runtime/plan9/386/rt0.s32
-rw-r--r--src/pkg/runtime/plan9/386/signal.c16
-rw-r--r--src/pkg/runtime/plan9/386/sys.s76
-rw-r--r--src/pkg/runtime/plan9/mem.c49
-rw-r--r--src/pkg/runtime/plan9/os.h27
-rw-r--r--src/pkg/runtime/plan9/runtime_defs.go23
-rw-r--r--src/pkg/runtime/plan9/signals.h1
-rw-r--r--src/pkg/runtime/plan9/thread.c140
-rw-r--r--src/pkg/runtime/pprof/Makefile2
-rw-r--r--src/pkg/runtime/print.c140
-rw-r--r--src/pkg/runtime/proc.c545
-rw-r--r--src/pkg/runtime/reflect.goc28
-rw-r--r--src/pkg/runtime/rune.c7
-rw-r--r--src/pkg/runtime/runtime-gdb.py398
-rw-r--r--src/pkg/runtime/runtime.c286
-rw-r--r--src/pkg/runtime/runtime.h378
-rw-r--r--src/pkg/runtime/runtime1.goc2
-rw-r--r--src/pkg/runtime/runtime_defs.go200
-rw-r--r--src/pkg/runtime/sema.goc36
-rw-r--r--src/pkg/runtime/sigqueue.goc24
-rw-r--r--src/pkg/runtime/slice.c308
-rw-r--r--src/pkg/runtime/softfloat64.go498
-rw-r--r--src/pkg/runtime/softfloat64_test.go198
-rw-r--r--src/pkg/runtime/string.goc136
-rw-r--r--src/pkg/runtime/symtab.c72
-rw-r--r--src/pkg/runtime/tiny/386/rt0.s8
-rw-r--r--src/pkg/runtime/tiny/386/signal.c8
-rw-r--r--src/pkg/runtime/tiny/386/sys.s18
-rwxr-xr-xsrc/pkg/runtime/tiny/README32
-rw-r--r--src/pkg/runtime/tiny/mem.c31
-rw-r--r--src/pkg/runtime/tiny/runtime_defs.go14
-rw-r--r--src/pkg/runtime/tiny/thread.c44
-rw-r--r--src/pkg/runtime/type.go6
-rw-r--r--src/pkg/runtime/windows/386/rt0.s2
-rw-r--r--src/pkg/runtime/windows/386/signal.c9
-rw-r--r--src/pkg/runtime/windows/386/sys.s157
-rw-r--r--src/pkg/runtime/windows/mem.c47
-rw-r--r--src/pkg/runtime/windows/os.h34
-rw-r--r--src/pkg/runtime/windows/runtime_defs.go22
-rw-r--r--src/pkg/runtime/windows/syscall.goc54
-rw-r--r--src/pkg/runtime/windows/thread.c268
-rw-r--r--src/pkg/scanner/Makefile2
-rw-r--r--src/pkg/scanner/scanner.go24
-rw-r--r--src/pkg/scanner/scanner_test.go319
-rw-r--r--src/pkg/smtp/Makefile12
-rw-r--r--src/pkg/smtp/auth.go69
-rw-r--r--src/pkg/smtp/smtp.go295
-rw-r--r--src/pkg/smtp/smtp_test.go182
-rw-r--r--src/pkg/sort/Makefile3
-rw-r--r--src/pkg/sort/search.go110
-rw-r--r--src/pkg/sort/search_test.go137
-rw-r--r--src/pkg/sort/sort.go18
-rw-r--r--src/pkg/strconv/Makefile2
-rw-r--r--src/pkg/strconv/atob_test.go26
-rw-r--r--src/pkg/strconv/atof.go44
-rw-r--r--src/pkg/strconv/atof_test.go131
-rw-r--r--src/pkg/strconv/atoi.go2
-rw-r--r--src/pkg/strconv/atoi_test.go204
-rw-r--r--src/pkg/strconv/decimal.go56
-rw-r--r--src/pkg/strconv/decimal_test.go72
-rw-r--r--src/pkg/strconv/fp_test.go2
-rw-r--r--src/pkg/strconv/ftoa.go12
-rw-r--r--src/pkg/strconv/ftoa_test.go178
-rw-r--r--src/pkg/strconv/itoa_test.go116
-rw-r--r--src/pkg/strconv/quote.go13
-rw-r--r--src/pkg/strconv/quote_test.go154
-rw-r--r--src/pkg/strings/Makefile2
-rw-r--r--src/pkg/strings/strings.go158
-rw-r--r--src/pkg/strings/strings_test.go481
-rw-r--r--src/pkg/sync/Makefile3
-rw-r--r--src/pkg/sync/asm_arm5.s2
-rw-r--r--src/pkg/sync/mutex.go7
-rw-r--r--src/pkg/sync/once.go35
-rw-r--r--src/pkg/sync/once_test.go37
-rw-r--r--src/pkg/sync/rwmutex.go2
-rw-r--r--src/pkg/syscall/Makefile10
-rw-r--r--src/pkg/syscall/asm_linux_amd64.s23
-rw-r--r--src/pkg/syscall/asm_linux_arm.s78
-rw-r--r--src/pkg/syscall/asm_nacl_386.s119
-rw-r--r--src/pkg/syscall/exec_unix.go (renamed from src/pkg/syscall/exec.go)0
-rw-r--r--src/pkg/syscall/exec_windows.go203
-rwxr-xr-xsrc/pkg/syscall/mkall.sh18
-rwxr-xr-xsrc/pkg/syscall/mkerrors.sh44
-rwxr-xr-xsrc/pkg/syscall/mkerrors_nacl.sh41
-rwxr-xr-xsrc/pkg/syscall/mkerrors_windows.sh210
-rwxr-xr-xsrc/pkg/syscall/mksyscall.sh41
-rwxr-xr-xsrc/pkg/syscall/mksyscall_windows.sh40
-rwxr-xr-xsrc/pkg/syscall/mksysnum_linux.sh16
-rw-r--r--src/pkg/syscall/mksysnum_nacl.sh29
-rw-r--r--src/pkg/syscall/syscall.go4
-rw-r--r--src/pkg/syscall/syscall_bsd.go19
-rw-r--r--src/pkg/syscall/syscall_darwin.go14
-rw-r--r--src/pkg/syscall/syscall_freebsd.go14
-rw-r--r--src/pkg/syscall/syscall_linux.go157
-rw-r--r--src/pkg/syscall/syscall_linux_386.go37
-rw-r--r--src/pkg/syscall/syscall_linux_amd64.go23
-rw-r--r--src/pkg/syscall/syscall_linux_arm.go71
-rw-r--r--src/pkg/syscall/syscall_nacl.go353
-rw-r--r--src/pkg/syscall/syscall_nacl_386.go19
-rw-r--r--src/pkg/syscall/syscall_windows.go208
-rw-r--r--src/pkg/syscall/types_linux.c17
-rw-r--r--src/pkg/syscall/types_nacl.c123
-rw-r--r--src/pkg/syscall/zerrors_darwin_386.go174
-rw-r--r--src/pkg/syscall/zerrors_darwin_amd64.go170
-rw-r--r--src/pkg/syscall/zerrors_freebsd_386.go1253
-rw-r--r--src/pkg/syscall/zerrors_freebsd_amd64.go150
-rw-r--r--src/pkg/syscall/zerrors_linux_386.go448
-rw-r--r--src/pkg/syscall/zerrors_linux_amd64.go452
-rw-r--r--src/pkg/syscall/zerrors_linux_arm.go133
-rw-r--r--src/pkg/syscall/zerrors_nacl_386.go246
-rw-r--r--src/pkg/syscall/zerrors_windows_386.go404
-rw-r--r--src/pkg/syscall/zsyscall_darwin_386.go297
-rw-r--r--src/pkg/syscall/zsyscall_darwin_amd64.go296
-rw-r--r--src/pkg/syscall/zsyscall_freebsd_386.go294
-rw-r--r--src/pkg/syscall/zsyscall_freebsd_amd64.go295
-rw-r--r--src/pkg/syscall/zsyscall_linux_386.go422
-rw-r--r--src/pkg/syscall/zsyscall_linux_amd64.go470
-rw-r--r--src/pkg/syscall/zsyscall_linux_arm.go480
-rw-r--r--src/pkg/syscall/zsyscall_nacl_386.go229
-rw-r--r--src/pkg/syscall/zsyscall_windows_386.go673
-rw-r--r--src/pkg/syscall/zsysnum_freebsd_386.go3
-rw-r--r--src/pkg/syscall/zsysnum_freebsd_amd64.go3
-rw-r--r--src/pkg/syscall/zsysnum_linux_386.go29
-rw-r--r--src/pkg/syscall/zsysnum_linux_amd64.go17
-rw-r--r--src/pkg/syscall/zsysnum_nacl_386.go61
-rw-r--r--src/pkg/syscall/zsysnum_windows_386.go3
-rw-r--r--src/pkg/syscall/ztypes_linux_386.go72
-rw-r--r--src/pkg/syscall/ztypes_linux_amd64.go86
-rw-r--r--src/pkg/syscall/ztypes_linux_arm.go168
-rw-r--r--src/pkg/syscall/ztypes_nacl.go9
-rw-r--r--src/pkg/syscall/ztypes_nacl_386.go105
-rw-r--r--src/pkg/syscall/ztypes_windows_386.go248
-rw-r--r--src/pkg/syslog/Makefile2
-rw-r--r--src/pkg/syslog/syslog.go2
-rw-r--r--src/pkg/syslog/syslog_test.go2
-rw-r--r--src/pkg/tabwriter/Makefile2
-rw-r--r--src/pkg/tabwriter/tabwriter.go122
-rw-r--r--src/pkg/tabwriter/tabwriter_test.go164
-rw-r--r--src/pkg/template/Makefile2
-rw-r--r--src/pkg/template/format.go22
-rw-r--r--src/pkg/template/template.go178
-rw-r--r--src/pkg/template/template_test.go295
-rw-r--r--src/pkg/testing/Makefile3
-rw-r--r--src/pkg/testing/benchmark.go57
-rw-r--r--src/pkg/testing/iotest/Makefile2
-rw-r--r--src/pkg/testing/iotest/logger.go12
-rw-r--r--src/pkg/testing/quick/Makefile2
-rw-r--r--src/pkg/testing/regexp.go831
-rw-r--r--src/pkg/testing/regexp_test.go307
-rw-r--r--src/pkg/testing/script/Makefile2
-rw-r--r--src/pkg/testing/testing.go30
-rw-r--r--src/pkg/time/Makefile5
-rw-r--r--src/pkg/time/format.go41
-rw-r--r--src/pkg/time/sleep.go135
-rw-r--r--src/pkg/time/sleep_test.go108
-rw-r--r--src/pkg/time/tick.go59
-rw-r--r--src/pkg/time/tick_test.go2
-rw-r--r--src/pkg/time/time_test.go116
-rw-r--r--src/pkg/time/zoneinfo.go243
-rw-r--r--src/pkg/time/zoneinfo_unix.go7
-rw-r--r--src/pkg/time/zoneinfo_windows.go7
-rw-r--r--src/pkg/try/Makefile (renamed from src/pkg/nntp/Makefile)6
-rw-r--r--src/pkg/try/try.go174
-rw-r--r--src/pkg/try/try_test.go60
-rw-r--r--src/pkg/unicode/Makefile2
-rw-r--r--src/pkg/unicode/digit_test.go4
-rw-r--r--src/pkg/unicode/letter_test.go158
-rw-r--r--src/pkg/unicode/maketables.go34
-rw-r--r--src/pkg/unicode/script_test.go320
-rw-r--r--src/pkg/unicode/tables.go6834
-rw-r--r--src/pkg/utf16/Makefile2
-rw-r--r--src/pkg/utf16/utf16_test.go17
-rw-r--r--src/pkg/utf8/Makefile3
-rw-r--r--src/pkg/utf8/string.go211
-rw-r--r--src/pkg/utf8/string_test.go109
-rw-r--r--src/pkg/utf8/utf8.go69
-rw-r--r--src/pkg/utf8/utf8_test.go191
-rw-r--r--src/pkg/websocket/Makefile2
-rw-r--r--src/pkg/websocket/client.go113
-rw-r--r--src/pkg/websocket/server.go75
-rw-r--r--src/pkg/websocket/websocket.go92
-rw-r--r--src/pkg/websocket/websocket_test.go133
-rw-r--r--src/pkg/xml/Makefile2
-rw-r--r--src/pkg/xml/read.go6
-rw-r--r--src/pkg/xml/read_test.go16
-rw-r--r--src/pkg/xml/xml.go638
-rw-r--r--src/pkg/xml/xml_test.go68
-rwxr-xr-xsrc/quietgcc.bash11
-rwxr-xr-xsrc/run.bash75
-rwxr-xr-xsrc/sudo.bash3
-rw-r--r--test/64bit.go302
-rw-r--r--test/append.go227
-rw-r--r--test/arm-pass.txt444
-rw-r--r--test/assign.go48
-rw-r--r--test/assign1.go110
-rw-r--r--test/bench/fannkuch-parallel.go2
-rw-r--r--test/bench/fasta.c4
-rw-r--r--test/bench/fasta.go47
-rw-r--r--test/bench/k-nucleotide-parallel.go2
-rw-r--r--test/bench/pidigits.go8
-rw-r--r--test/bench/regex-dna-parallel.go4
-rw-r--r--test/bench/regex-dna.go2
-rw-r--r--test/bench/timing.log108
-rwxr-xr-xtest/bench/timing.sh42
-rw-r--r--test/bigalg.go86
-rw-r--r--test/blank.go62
-rw-r--r--test/blank1.go4
-rw-r--r--test/chan/fifo.go26
-rw-r--r--test/chan/goroutines.go32
-rw-r--r--test/chan/nonblock.go98
-rw-r--r--test/chan/perm.go68
-rw-r--r--test/chan/powser1.go579
-rw-r--r--test/chan/powser2.go585
-rw-r--r--test/chan/select3.go203
-rw-r--r--test/chan/select4.go25
-rw-r--r--test/char_lit.go7
-rw-r--r--test/char_lit1.go16
-rw-r--r--test/closedchan.go98
-rw-r--r--test/closure.go11
-rw-r--r--test/cmp1.go54
-rw-r--r--test/cmp2.go6
-rw-r--r--test/cmp3.go6
-rw-r--r--test/cmp4.go8
-rw-r--r--test/cmp5.go8
-rw-r--r--test/cmp6.go42
-rw-r--r--test/cmplx.go1
-rw-r--r--test/cmplxdivide.go5
-rw-r--r--test/complit.go44
-rw-r--r--test/compos.go8
-rw-r--r--test/const.go164
-rw-r--r--test/const1.go114
-rw-r--r--test/const2.go2
-rw-r--r--test/const3.go6
-rw-r--r--test/convert3.go4
-rw-r--r--test/convlit.go40
-rw-r--r--test/copy.go61
-rw-r--r--test/ddd.go34
-rw-r--r--test/ddd1.go19
-rw-r--r--test/decl.go30
-rw-r--r--test/declbad.go42
-rw-r--r--test/defer.go2
-rw-r--r--test/env.go17
-rw-r--r--test/eof.go9
-rw-r--r--test/eof1.go (renamed from test/syntax/slice.go)4
-rwxr-xr-xtest/errchk100
-rw-r--r--test/escape.go158
-rw-r--r--test/fixedbugs/bug045.go2
-rw-r--r--test/fixedbugs/bug059.go2
-rw-r--r--test/fixedbugs/bug146.go2
-rw-r--r--test/fixedbugs/bug195.go4
-rw-r--r--test/fixedbugs/bug206.go4
-rw-r--r--test/fixedbugs/bug243.go8
-rw-r--r--test/fixedbugs/bug251.go6
-rw-r--r--test/fixedbugs/bug252.go4
-rw-r--r--test/fixedbugs/bug255.go6
-rw-r--r--test/fixedbugs/bug260.go (renamed from test/bugs/bug260.go)18
-rw-r--r--test/fixedbugs/bug273.go28
-rw-r--r--test/fixedbugs/bug274.go (renamed from test/bugs/bug274.go)0
-rw-r--r--test/fixedbugs/bug278.go8
-rw-r--r--test/fixedbugs/bug284.go70
-rw-r--r--test/fixedbugs/bug286.go (renamed from test/bugs/bug286.go)0
-rw-r--r--test/fixedbugs/bug289.go26
-rw-r--r--test/fixedbugs/bug290.go15
-rw-r--r--test/fixedbugs/bug291.go23
-rw-r--r--test/fixedbugs/bug292.go22
-rw-r--r--test/fixedbugs/bug293.go37
-rw-r--r--test/fixedbugs/bug294.go79
-rw-r--r--test/fixedbugs/bug295.go17
-rw-r--r--test/fixedbugs/bug296.go88
-rw-r--r--test/fixedbugs/bug297.go15
-rw-r--r--test/fixedbugs/bug298.go11
-rw-r--r--test/fixedbugs/bug299.go27
-rw-r--r--test/fixedbugs/bug300.go29
-rw-r--r--test/fixedbugs/bug301.go18
-rw-r--r--test/fixedbugs/bug302.dir/main.go12
-rw-r--r--test/fixedbugs/bug302.dir/p.go1011
-rw-r--r--test/fixedbugs/bug302.go6
-rw-r--r--test/fixedbugs/bug303.go37
-rw-r--r--test/fixedbugs/bug304.go18
-rw-r--r--test/fixedbugs/bug305.go24
-rw-r--r--test/fixedbugs/bug306.dir/p1.go9
-rw-r--r--test/fixedbugs/bug306.dir/p2.go (renamed from src/pkg/debug/proc/regs_nacl_386.go)7
-rw-r--r--test/fixedbugs/bug306.go7
-rw-r--r--test/fixedbugs/bug307.go15
-rw-r--r--test/fixedbugs/bug308.go19
-rw-r--r--test/fixedbugs/bug309.go19
-rw-r--r--test/fixedbugs/bug310.go20
-rw-r--r--test/fixedbugs/bug311.go20
-rw-r--r--test/fixedbugs/bug312.go22
-rw-r--r--test/fixedbugs/bug313.dir/a.go11
-rw-r--r--test/fixedbugs/bug313.dir/b.go11
-rw-r--r--test/fixedbugs/bug313.go19
-rw-r--r--test/fixedbugs/bug314.go31
-rw-r--r--test/fixedbugs/bug315.go18
-rw-r--r--test/fixedbugs/bug316.go17
-rw-r--r--test/fixedbugs/bug317.go16
-rw-r--r--test/float_lit.go224
-rw-r--r--test/floatcmp.go18
-rw-r--r--test/for.go42
-rw-r--r--test/func.go74
-rw-r--r--test/func1.go4
-rw-r--r--test/func2.go24
-rw-r--r--test/func3.go14
-rw-r--r--test/func4.go4
-rw-r--r--test/garbage/Makefile2
-rw-r--r--test/garbage/parser.go8
-rw-r--r--test/gc.go2
-rw-r--r--test/gc1.go4
-rw-r--r--test/golden-arm.out110
-rw-r--r--test/golden.out14
-rwxr-xr-xtest/hashmap.go123
-rw-r--r--test/helloworld.go2
-rw-r--r--test/if.go100
-rw-r--r--test/if1.go4
-rw-r--r--test/import.go8
-rw-r--r--test/import1.go4
-rw-r--r--test/index.go224
-rw-r--r--test/indirect1.go2
-rw-r--r--test/initialize.go12
-rw-r--r--test/initializerr.go10
-rw-r--r--test/initsyscall.go4
-rw-r--r--test/int_lit.go6
-rw-r--r--test/interface/bigdata.go52
-rw-r--r--test/interface/convert1.go18
-rw-r--r--test/interface/convert2.go18
-rw-r--r--test/interface/embed.go63
-rw-r--r--test/interface/embed0.go24
-rw-r--r--test/interface/embed1.go50
-rw-r--r--test/interface/embed2.go70
-rw-r--r--test/interface/explicit.go12
-rw-r--r--test/interface/fail.go12
-rw-r--r--test/interface/fake.go78
-rw-r--r--test/interface/receiver.go4
-rw-r--r--test/interface/returntype.go6
-rw-r--r--test/interface/struct.go152
-rw-r--r--test/iota.go156
-rw-r--r--test/ken/array.go8
-rw-r--r--test/ken/convert.go431
-rw-r--r--test/ken/cplx4.go2
-rw-r--r--test/ken/slicearray.go24
-rw-r--r--test/ken/sliceslice.go20
-rw-r--r--test/literal.go356
-rw-r--r--test/mallocrand.go10
-rw-r--r--test/mallocrep.go3
-rw-r--r--test/map.go412
-rw-r--r--test/method.go24
-rw-r--r--test/method1.go8
-rw-r--r--test/method2.go19
-rw-r--r--test/named1.go2
-rw-r--r--test/nil.go36
-rw-r--r--test/nilptr/arrayindex.go7
-rw-r--r--test/nilptr/arrayindex1.go9
-rw-r--r--test/nilptr/arraytoslice.go11
-rw-r--r--test/nilptr/arraytoslice1.go11
-rw-r--r--test/nilptr/arraytoslice2.go13
-rw-r--r--test/nilptr/slicearray.go9
-rw-r--r--test/nilptr/structfield.go13
-rw-r--r--test/nilptr/structfield1.go13
-rw-r--r--test/nilptr/structfield2.go15
-rw-r--r--test/nilptr/structfieldaddr.go13
-rw-r--r--test/nul1.go6
-rw-r--r--test/parentype.go12
-rw-r--r--test/peano.go13
-rw-r--r--test/printbig.go2
-rw-r--r--test/range.go199
-rw-r--r--test/recover2.go10
-rw-r--r--test/recover3.go17
-rwxr-xr-xtest/run39
-rwxr-xr-xtest/run-arm102
-rw-r--r--test/runtime.go2
-rw-r--r--test/sieve.go20
-rw-r--r--test/sigchld.go5
-rw-r--r--test/sinit.go8
-rw-r--r--test/solitaire.go119
-rw-r--r--test/string_lit.go54
-rw-r--r--test/stringrange.go54
-rw-r--r--test/switch.go158
-rw-r--r--test/switch1.go6
-rw-r--r--test/syntax/chan.go17
-rw-r--r--test/syntax/topexpr.go6
-rw-r--r--test/syntax/vareq.go2
-rw-r--r--test/syntax/vareq1.go2
-rw-r--r--test/test0.go64
-rw-r--r--test/turing.go51
-rw-r--r--test/typeswitch.go78
-rw-r--r--test/undef.go10
-rw-r--r--test/utf.go60
-rw-r--r--test/varerr.go4
-rw-r--r--test/zerodivide.go44
1473 files changed, 96880 insertions, 64769 deletions
diff --git a/.hgignore b/.hgignore
deleted file mode 100644
index c80814058..000000000
--- a/.hgignore
+++ /dev/null
@@ -1,45 +0,0 @@
-syntax:glob
-.DS_Store
-.git
-.gitignore
-*.[568ao]
-*.ao
-*.so
-*.pyc
-._*
-.nfs.*
-[568a].out
-*~
-*.orig
-core
-_obj
-_test
-doc/htmlgen
-src/cmd/6a/6a
-y.tab.[ch]
-src/cmd/?l/enam.c
-src/cmd/gc/builtin.c
-src/cmd/gc/mkbuiltin1
-src/cmd/gc/opnames.h
-src/cmd/gc/y.output
-src/cmd/gc/y1.tab.c
-src/cmd/gc/yerr.h
-src/pkg/Make.deps
-src/pkg/exp/ogle/ogle
-src/pkg/os/signal/unix.go
-src/pkg/runtime/*/asm.h
-src/pkg/runtime/goc2c
-src/pkg/runtime/mkversion
-src/pkg/runtime/runtime.acid.*
-src/pkg/runtime/version.go
-src/pkg/github.com/
-src/pkg/*.googlecode.com/
-test/pass.out
-test/run.out
-test/times.out
-test/garbage/*.out
-
-syntax:regexp
-^pkg/
-^src/cmd/(.*)/6?\1$
-^.*/core.[0-9]*$
diff --git a/AUTHORS b/AUTHORS
index b41da7dc9..03bc7f43d 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -10,6 +10,7 @@
Abhinav Gupta <abhinav.g90@gmail.com>
Adrian O'Grady <elpollouk@gmail.com>
+Albert Strasheim <fullung@gmail.com>
Alex Brainman <alex.brainman@gmail.com>
Amrut Joshi <amrut.joshi@gmail.com>
Andrei Vieru <euvieru@gmail.com>
@@ -17,14 +18,22 @@ Andrew Skiba <skibaa@gmail.com>
Andrey Mirtchovski <mirtchovski@gmail.com>
Andy Davis <andy@bigandian.com>
Anh Hai Trinh <anh.hai.trinh@gmail.com>
+Anschel Schaffer-Cohen <anschelsc@gmail.com>
+Anthony Martin <ality@pbrane.org>
Anthony Starks <ajstarks@gmail.com>
Aron Nopanen <aron.nopanen@gmail.com>
Arvindh Rajesh Tamilmani <art@a-30.net>
Ben Olive <sionide21@gmail.com>
+Benny Siegert <bsiegert@gmail.com>
+Caine Tighe <arctanofyourface@gmail.com>
Charles L. Dorian <cldorian@gmail.com>
+Chris Jones <chris@cjones.org> <chris.jones.yar@gmail.com>
Chris Lennert <calennert@gmail.com>
+Christian Himpel <chressie@googlemail.com>
Christopher Wedgwood <cw@f00f.org>
Conrad Meyer <cemeyer@cs.washington.edu>
+Corey Thomasson <cthom.lists@gmail.com>
+Dan Sinclair <dan.sinclair@gmail.com>
Daniel Fleischman <danielfleischman@gmail.com>
Daniel Theophanes <kardianos@gmail.com>
David G. Andersen <dave.andersen@gmail.com>
@@ -32,33 +41,54 @@ David Titarenco <david.titarenco@gmail.com>
Dean Prichard <dean.prichard@gmail.com>
Devon H. O'Dell <devon.odell@gmail.com>
Eden Li <eden.li@gmail.com>
+Eoghan Sherry <ejsherry@gmail.com>
+Eric Clark <zerohp@gmail.com>
+Eric Eisner <eric.d.eisner@gmail.com>
Evan Shaw <chickencha@gmail.com>
Fazlul Shahriar <fshahriar@gmail.com>
Firmansyah Adiputra <frm.adiputra@gmail.com>
+Florian Uekermann <florian@uekermann-online.de> <f1@uekermann-online.de>
Giles Lean <giles.lean@pobox.com>
Google Inc.
+Graham Miller <graham.miller@gmail.com>
Gustavo Niemeyer <gustavo@niemeyer.net>
+Harley Laue <losinggeneration@gmail.com>
Hector Chu <hectorchu@gmail.com>
Icarus Sparry <golang@icarus.freeuk.com>
Isaac Wagner <ibw@isaacwagner.me>
+James Fysh <james.fysh@gmail.com>
James Meneghello <rawrz0r@gmail.com>
James Toy <nil@opensesame.st>
James Whitehead <jnwhiteh@gmail.com>
Jan H. Hosang <jan.hosang@gmail.com>
Jan Mercl <befelemepeseveze@gmail.com>
+Jim McGrath <jimmc2@gmail.com>
Joe Poirier <jdpoirier@gmail.com>
Jonathan Wills <runningwild@gmail.com>
Josh Goebel <dreamer3@gmail.com>
+Jukka-Pekka Kekkonen <karatepekka@gmail.com>
+Kai Backman <kaib@golang.org>
Kei Son <hey.calmdown@gmail.com>
+Keith Rarick <kr@xph.us>
Ken Friedenbach <kenliz@cruzio.com>
Kevin Ballard <kevin@sb.org>
Kyle Consalus <consalus@gmail.com>
+Kyle Lemons <kyle@kylelemons.net>
+Lorenzo Stoakes <lstoakes@gmail.com>
+Markus Duft <markus.duft@salomon.at>
+Martin Neubauer <m.ne@gmx.net>
+Mathieu Lonjaret <mathieu.lonjaret@gmail.com>
Micah Stetson <micah.stetson@gmail.com>
Michael Elkins <michael.elkins@gmail.com>
Michael Hoisie <hoisie@gmail.com>
+Mikio Hara <mikioh.mikioh@gmail.com>
+Mikkel Krautz <mikkel@krautz.dk> <krautz@gmail.com>
Moriyoshi Koizumi <mozo@mozo.jp>
Môshe van der Sterre <moshevds@gmail.com>
+Nicholas Waples <nwaples@gmail.com>
+Nigel Kerr <nigel.kerr@gmail.com>
Paolo Giarrusso <p.giarrusso@gmail.com>
+Patrick Gavlin <pgavlin@gmail.com>
Petar Maymounkov <petarm@gmail.com>
Peter Froehlich <peter.hans.froehlich@gmail.com>
Peter Mundy <go.peter.90@gmail.com>
@@ -67,14 +97,24 @@ Raif S. Naffah <go@naffah-raif.name>
Risto Jaakko Saarelma <rsaarelm@gmail.com>
Roger Peppe <rogpeppe@gmail.com>
Ross Light <rlight2@gmail.com>
+Ryan Hitchman <hitchmanr@gmail.com>
+Scott Lawrence <bytbox@gmail.com>
+Sebastien Binet <seb.binet@gmail.com>
Sergei Skorobogatov <skorobo@rambler.ru>
Sergey 'SnakE' Gromov <snake.scaly@gmail.com>
Sergio Luis O. B. Correia <sergio@larces.uece.br>
Spring Mc <heresy.mc@gmail.com>
+Stefan Nilsson <snilsson@nada.kth.se>
Stephen Weinberg <stephen@q5comm.com>
Sven Almgren <sven@tras.se>
+Tarmigan Casebolt <tarmigan@gmail.com>
Timo Savola <timo.savola@gmail.com>
Tor Andersson <tor.andersson@gmail.com>
+Vincent Ambo <tazjin@googlemail.com>
Vinu Rajashekhar <vinutheraj@gmail.com>
+Wei Guangjing <vcc.163@gmail.com>
William Josephson <wjosephson@gmail.com>
Yongjian Xu <i3dmaster@gmail.com>
+Yasuhiro Matsumoto <mattn.jp@gmail.com>
+Yuusei Kuwana <kuwana@kumama.org>
+Yuval Pavel Zholkover <paulzhol@gmail.com>
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index caa4fb358..317cb525b 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -23,12 +23,18 @@
# Names should be added to this file like so:
# Name <email address>
+#
+# An entry with two email addresses specifies that the
+# first address should be used in the submit logs and
+# that the second address should be recognized as the
+# same person when interacting with Rietveld.
# Please keep the list sorted.
Abhinav Gupta <abhinav.g90@gmail.com>
Adam Langley <agl@golang.org>
Adrian O'Grady <elpollouk@gmail.com>
+Albert Strasheim <fullung@gmail.com>
Alex Brainman <alex.brainman@gmail.com>
Amrut Joshi <amrut.joshi@gmail.com>
Andrei Vieru <euvieru@gmail.com>
@@ -37,22 +43,32 @@ Andrew Skiba <skibaa@gmail.com>
Andrey Mirtchovski <mirtchovski@gmail.com>
Andy Davis <andy@bigandian.com>
Anh Hai Trinh <anh.hai.trinh@gmail.com>
+Anschel Schaffer-Cohen <anschelsc@gmail.com>
+Anthony Martin <ality@pbrane.org>
Anthony Starks <ajstarks@gmail.com>
Aron Nopanen <aron.nopanen@gmail.com>
Arvindh Rajesh Tamilmani <art@a-30.net>
Austin Clements <aclements@csail.mit.edu>
+Balazs Lecz <leczb@google.com>
Ben Eitzen <eitzenb@golang.org>
Ben Olive <sionide21@gmail.com>
-Bill Neubauer <wcn@golang.org>
-Brad Fitzpatrick <brad@danga.com>
+Benny Siegert <bsiegert@gmail.com>
+Bill Neubauer <wcn@golang.org> <wcn@google.com>
+Brad Fitzpatrick <brad@danga.com> <bradfitz@gmail.com>
Brendan O'Dea <bod@golang.org>
+Caine Tighe <arctanofyourface@gmail.com>
Cary Hull <chull@google.com>
Charles L. Dorian <cldorian@gmail.com>
+Chris Jones <chris@cjones.org> <chris.jones.yar@gmail.com>
Chris Lennert <calennert@gmail.com>
+Christian Himpel <chressie@googlemail.com> <chressie@gmail.com>
Christopher Wedgwood <cw@f00f.org>
Conrad Meyer <cemeyer@cs.washington.edu>
+Corey Thomasson <cthom.lists@gmail.com>
+Dan Sinclair <dan.sinclair@gmail.com>
Daniel Fleischman <danielfleischman@gmail.com>
Daniel Nadasi <dnadasi@google.com>
+Berengar Lehr <Berengar.Lehr@gmx.de>
Daniel Theophanes <kardianos@gmail.com>
David G. Andersen <dave.andersen@gmail.com>
David Symonds <dsymonds@golang.org>
@@ -60,12 +76,18 @@ David Titarenco <david.titarenco@gmail.com>
Dean Prichard <dean.prichard@gmail.com>
Devon H. O'Dell <devon.odell@gmail.com>
Eden Li <eden.li@gmail.com>
+Eoghan Sherry <ejsherry@gmail.com>
+Eric Clark <zerohp@gmail.com>
+Eric Eisner <eric.d.eisner@gmail.com>
Evan Shaw <chickencha@gmail.com>
Fazlul Shahriar <fshahriar@gmail.com>
Firmansyah Adiputra <frm.adiputra@gmail.com>
+Florian Uekermann <florian@uekermann-online.de> <f1@uekermann-online.de>
Fumitoshi Ukai <ukai@google.com>
Giles Lean <giles.lean@pobox.com>
+Graham Miller <graham.miller@gmail.com>
Gustavo Niemeyer <gustavo@niemeyer.net> <n13m3y3r@gmail.com>
+Harley Laue <losinggeneration@gmail.com>
Hector Chu <hectorchu@gmail.com>
Ian Lance Taylor <iant@golang.org>
Icarus Sparry <golang@icarus.freeuk.com>
@@ -73,31 +95,47 @@ Isaac Wagner <ibw@isaacwagner.me>
Ivan Krasin <krasin@golang.org>
Jacob Baskin <jbaskin@google.com>
James Aguilar <jaguilar@google.com>
+James Fysh <james.fysh@gmail.com>
James Meneghello <rawrz0r@gmail.com>
James Toy <nil@opensesame.st>
James Whitehead <jnwhiteh@gmail.com>
+Jamie Gennis <jgennis@google.com>
Jan H. Hosang <jan.hosang@gmail.com>
Jan Mercl <befelemepeseveze@gmail.com>
+Jim McGrath <jimmc2@gmail.com>
Joe Poirier <jdpoirier@gmail.com>
Jonathan Wills <runningwild@gmail.com>
Josh Goebel <dreamer3@gmail.com>
+Jukka-Pekka Kekkonen <karatepekka@gmail.com>
Kai Backman <kaib@golang.org>
Kei Son <hey.calmdown@gmail.com>
+Keith Rarick <kr@xph.us>
Ken Friedenbach <kenliz@cruzio.com>
Ken Thompson <ken@golang.org>
Kevin Ballard <kevin@sb.org>
Kirklin McDonald <kirklin.mcdonald@gmail.com>
Kyle Consalus <consalus@gmail.com>
+Kyle Lemons <kyle@kylelemons.net>
Larry Hosken <lahosken@golang.org>
+Lorenzo Stoakes <lstoakes@gmail.com>
+Luuk van Dijk <lvd@golang.org> <lvd@google.com>
Mark Zavislak <zavislak@google.com>
+Markus Duft <markus.duft@salomon.at>
+Martin Neubauer <m.ne@gmx.net>
+Mathieu Lonjaret <mathieu.lonjaret@gmail.com>
Maxim Ushakov <ushakov@google.com>
Micah Stetson <micah.stetson@gmail.com>
Michael Elkins <michael.elkins@gmail.com>
Michael Hoisie <hoisie@gmail.com>
+Mikio Hara <mikioh.mikioh@gmail.com>
+Mikkel Krautz <mikkel@krautz.dk> <krautz@gmail.com>
Moriyoshi Koizumi <mozo@mozo.jp>
Môshe van der Sterre <moshevds@gmail.com>
+Nicholas Waples <nwaples@gmail.com>
+Nigel Kerr <nigel.kerr@gmail.com>
Nigel Tao <nigeltao@golang.org>
Paolo Giarrusso <p.giarrusso@gmail.com>
+Patrick Gavlin <pgavlin@gmail.com>
Petar Maymounkov <petarm@gmail.com>
Peter Froehlich <peter.hans.froehlich@gmail.com>
Peter McKenzie <petermck@google.com>
@@ -112,21 +150,31 @@ Robert Griesemer <gri@golang.org>
Roger Peppe <rogpeppe@gmail.com>
Ross Light <rlight2@gmail.com>
Russ Cox <rsc@golang.org>
-Sam Thorogood <thorogood@google.com>
+Ryan Hitchman <hitchmanr@gmail.com>
+Sam Thorogood <thorogood@google.com> <sam.thorogood@gmail.com>
Scott Schwartz <scotts@golang.org>
+Scott Lawrence <bytbox@gmail.com>
+Sebastien Binet <seb.binet@gmail.com>
Sergei Skorobogatov <skorobo@rambler.ru>
Sergey 'SnakE' Gromov <snake.scaly@gmail.com>
Sergio Luis O. B. Correia <sergio@larces.uece.br>
Spring Mc <heresy.mc@gmail.com>
+Stefan Nilsson <snilsson@nada.kth.se>
Stephen Ma <stephenm@golang.org>
Stephen Weinberg <stephen@q5comm.com>
Sven Almgren <sven@tras.se>
+Tarmigan Casebolt <tarmigan@gmail.com>
Tom Szymanski <tgs@google.com>
Timo Savola <timo.savola@gmail.com>
Tor Andersson <tor.andersson@gmail.com>
Trevor Strohman <trevor.strohman@gmail.com>
+Vincent Ambo <tazjin@googlemail.com>
Vinu Rajashekhar <vinutheraj@gmail.com>
Vish Subramanian <vish@google.com>
+Wei Guangjing <vcc.163@gmail.com>
William Josephson <wjosephson@gmail.com>
Yongjian Xu <i3dmaster@gmail.com>
+Yasuhiro Matsumoto <mattn.jp@gmail.com>
+Yuusei Kuwana <kuwana@kumama.org>
+Yuval Pavel Zholkover <paulzhol@gmail.com>
Yves Junqueira <yves.junqueira@gmail.com>
diff --git a/LICENSE b/LICENSE
index d77335ff8..6a66aea5e 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,42 +1,27 @@
-// Copyright (c) 2009 The Go Authors. All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// Subject to the terms and conditions of this License, Google hereby
-// grants to You a perpetual, worldwide, non-exclusive, no-charge,
-// royalty-free, irrevocable (except as stated in this section) patent
-// license to make, have made, use, offer to sell, sell, import, and
-// otherwise transfer this implementation of Go, where such license
-// applies only to those patent claims licensable by Google that are
-// necessarily infringed by use of this implementation of Go. If You
-// institute patent litigation against any entity (including a
-// cross-claim or counterclaim in a lawsuit) alleging that this
-// implementation of Go or a Contribution incorporated within this
-// implementation of Go constitutes direct or contributory patent
-// infringement, then any patent licenses granted to You under this
-// License for this implementation of Go shall terminate as of the date
-// such litigation is filed.
+Copyright (c) 2009 The Go Authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/PATENTS b/PATENTS
new file mode 100644
index 000000000..733099041
--- /dev/null
+++ b/PATENTS
@@ -0,0 +1,22 @@
+Additional IP Rights Grant (Patents)
+
+"This implementation" means the copyrightable works distributed by
+Google as part of the Go project.
+
+Google hereby grants to You a perpetual, worldwide, non-exclusive,
+no-charge, royalty-free, irrevocable (except as stated in this section)
+patent license to make, have made, use, offer to sell, sell, import,
+transfer and otherwise run, modify and propagate the contents of this
+implementation of Go, where such license applies only to those patent
+claims, both currently owned or controlled by Google and acquired in
+the future, licensable by Google that are necessarily infringed by this
+implementation of Go. This grant does not include claims that would be
+infringed only as a consequence of further modification of this
+implementation. If you or your agent or exclusive licensee institute or
+order or agree to the institution of patent litigation against any
+entity (including a cross-claim or counterclaim in a lawsuit) alleging
+that this implementation of Go or any code incorporated within this
+implementation of Go constitutes direct or contributory patent
+infringement, or inducement of patent infringement, then any patent
+rights granted to you under this License for this implementation of Go
+shall terminate as of the date such litigation is filed.
diff --git a/README b/README
index e25bbdb8d..8bf9e7b8c 100644
--- a/README
+++ b/README
@@ -9,3 +9,23 @@ and then visiting http://localhost:6060/doc/install.html.
Unless otherwise noted, the Go source files are distributed
under the BSD-style license found in the LICENSE file.
+
+--
+
+Binary Distribution Notes
+
+If you have just untarred a binary Go distribution, you need to set
+the environment variable $GOROOT to the full path of the go
+directory (the one containing this README). You can omit the
+variable if you unpack it into /usr/local/go, or if you rebuild
+from sources by running all.bash (see doc/install.html).
+You should also add the Go binary directory $GOROOT/bin
+to your shell's path.
+
+For example, if you extracted the tar file into $HOME/go, you might
+put the following in your .profile:
+
+ export GOROOT=$HOME/go
+ export PATH=$PATH:$GOROOT/bin
+
+See doc/install.html for more details.
diff --git a/doc/ExpressivenessOfGo.pdf b/doc/ExpressivenessOfGo.pdf
new file mode 100644
index 000000000..f1931d081
--- /dev/null
+++ b/doc/ExpressivenessOfGo.pdf
Binary files differ
diff --git a/doc/Makefile b/doc/Makefile
index 0abb881b1..d992a39f3 100644
--- a/doc/Makefile
+++ b/doc/Makefile
@@ -2,10 +2,10 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include $(GOROOT)/src/Make.$(GOARCH)
+include ../src/Make.inc
TARG=htmlgen
GOFILES=\
htmlgen.go\
-include $(GOROOT)/src/Make.cmd
+include ../src/Make.cmd
diff --git a/doc/all.css b/doc/all.css
new file mode 100644
index 000000000..f70ef1599
--- /dev/null
+++ b/doc/all.css
@@ -0,0 +1,197 @@
+/* General Styles */
+body {
+ font-family: "Bitstream Vera Sans", Verdana, sans-serif;
+ font-size: 81.25%;
+ line-height: 1.23em;
+ padding: 0;
+ margin: 1.23em;
+ background: white;
+ color: black;
+}
+a {
+ color: #04a;
+ text-decoration: none;
+}
+a:visited {
+ color: #04a;
+}
+a:hover {
+ color: #a40;
+ text-decoration: underline;
+}
+a:active {
+ color: #c00;
+}
+code, pre {
+ font-size: 1.2em;
+}
+pre {
+ background: #F0F0F0;
+ padding: 0.5em 1em;
+}
+
+/* Top bar */
+#container {
+ width: 100%;
+ margin: auto;
+}
+#topnav {
+ height: 55px;
+ background: url(/doc/logo.png) no-repeat top left;
+}
+a#logo-box {
+ display: block;
+ height: 55px;
+}
+h1#title {
+ display: none;
+}
+#nav-main {
+ float: right;
+ width: 500px;
+ margin-top: -5px;
+ text-align: center;
+}
+#nav-main ul {
+ padding-left: 0;
+ margin-left: 0;
+ margin-bottom: 0.5em;
+}
+#nav-main li a {
+ display: inline;
+ display: inline-block;
+ padding: .46em .62em .38em .62em;
+}
+#nav-main li a:link,
+#nav-main li a:visited {
+ color: #000;
+}
+#nav-main li {
+ display: inline;
+ display: inline-block;
+ background: #e6e6e6 url(/doc/button_background.png) repeat-x;
+ border: solid 1px #999;
+ margin-left: -1px;
+ text-shadow: #fff 0 1px 0;
+ box-shadow: 0 1px 1px #ccc;
+ -moz-box-shadow: 0 1px 1px #ccc;
+ -webkit-box-shadow: 0 1px 1px #ccc;
+}
+#nav-main li:first-child {
+ -moz-border-top-left-radius: 4px;
+ border-top-left-radius: 4px;
+ -moz-border-bottom-left-radius: 4px;
+ border-bottom-left-radius: 4px;
+}
+#nav-main li:last-child {
+ -moz-border-top-right-radius: 4px;
+ border-top-right-radius: 4px;
+ -moz-border-bottom-right-radius: 4px;
+ border-bottom-right-radius: 4px;
+}
+#nav-main .quickref {
+ color: #444;
+}
+#nav-main .quickref .sep {
+ color: #999;
+}
+#search {
+ width: 100px;
+ margin-left: 0.5em;
+}
+#search.inactive {
+ text-align: center;
+ color: #444;
+}
+
+/* Footer */
+#site-info {
+ position: relative;
+ text-align: center;
+}
+#site-info, #site-info a:link, #site-info a:visited {
+ color: #aaa;
+}
+
+/* Content */
+#content {
+ clear: both;
+ padding: 0;
+ position: relative;
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+ border-top: solid 1px #aaa;
+ border-bottom: solid 1px #aaa;
+}
+.left-column {
+ width: 49%;
+ float: left;
+}
+.right-column {
+ width: 49%;
+ float: right;
+}
+.end-columns {
+ clear: both;
+}
+#content h1 {
+ margin-bottom: -0em;
+ padding: 0;
+}
+#content h2 {
+ border-top: 1px solid #ddd;
+ background: #E2E7F0;
+ padding: 5px;
+ margin: 1.5em 0 0;
+}
+#content .subtitle {
+ margin-top: 1em;
+ display: block;
+}
+.navtop a {
+ font-weight: normal; font-size: 7pt;
+ float: right; color: #999;
+}
+
+/* Content and Code Highlighting */
+pre.ebnf, pre.grammar {
+ background: #FFFFE0;
+}
+span.comment {
+ color: #002090;
+}
+span.highlight {
+ background: #FF9900;
+ font-weight: bold;
+}
+span.highlight-comment {
+ background: #FF9900;
+ font-weight: bold;
+ color: #002090;
+}
+span.selection {
+ background: #FFFF00
+}
+span.selection-comment {
+ color: #002090;
+ background: #FFFF00
+}
+span.selection-highlight {
+ background: #FF9900;
+ font-weight: bold;
+}
+span.selection-highlight-comment {
+ background: #FF9900;
+ font-weight: bold;
+ color: #002090;
+}
+span.alert {
+ color: #D00000;
+}
+#nav table {
+ width: 100%;
+}
+.detail {
+ padding: 0.25em 1em;
+ background: #F4F4F4;
+}
diff --git a/doc/button_background.png b/doc/button_background.png
new file mode 100644
index 000000000..86a3b3086
--- /dev/null
+++ b/doc/button_background.png
Binary files differ
diff --git a/doc/code.html b/doc/code.html
index 14bb6f9fe..55afe09af 100644
--- a/doc/code.html
+++ b/doc/code.html
@@ -64,7 +64,7 @@ is illustrated by <a href="../src/pkg/container/vector/Makefile"><code>src/pkg/c
</p>
<pre>
-include ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=container/vector
GOFILES=\
@@ -80,7 +80,7 @@ Outside the Go source tree (for personal packages), the standard form is
</p>
<pre>
-include $(GOROOT)/src/Make.$(GOARCH)
+include $(GOROOT)/src/Make.inc
TARG=mypackage
GOFILES=\
@@ -99,6 +99,14 @@ This makes it easy for programmers to try Go.
</p>
<p>
+If you have not set <code>$GOROOT</code> in your environment,
+you must run <code>gomake</code> to use this form of makefile.
+<code>Gomake</code> also takes care to invoke GNU Make
+even on systems where it is installed as <code>gmake</code>
+rather than <code>make</code>.
+</p>
+
+<p>
<code>TARG</code> is the target install path for the package,
the string that clients will use to import it.
Inside the Go tree, this string should be the same as the directory
@@ -131,8 +139,8 @@ cd $GOROOT/src/pkg
</pre>
<p>
to update the dependency file <code>Make.deps</code>.
-(This happens automatically each time you run <code>make all</code>
-or <code>make build</code>.)
+(This happens automatically each time you run <code>all.bash</code>
+or <code>make.bash</code>.)
</p>
<p>
@@ -169,6 +177,32 @@ Writing clean, idiomatic Go code is beyond the scope of this document.
that topic.
</p>
+<h2 id="Building_programs">Building programs</h2>
+<p>To build a Go program with gomake, create a Makefile alongside your program's
+source files. It should be similar to the example above, but include
+<code>Make.cmd</code> instead of <code>Make.pkg</code>:
+
+<pre>
+include $(GOROOT)/src/Make.inc
+
+TARG=helloworld
+GOFILES=\
+ helloworld.go\
+
+include $(GOROOT)/src/Make.cmd
+</pre>
+
+<p>Running <code>gomake</code> will compile <code>helloworld.go</code>
+and produce an executable named <code>helloworld</code> in the current
+directory.
+</p>
+
+<p>
+Running <code>gomake install</code> will build <code>helloworld</code> if
+necessary and copy it to the <code>$GOBIN</code> directory
+(<code>$GOROOT/bin/</code> is the default).
+</p>
+
<h2 id="Testing">Testing</h2>
<p>
@@ -259,7 +293,7 @@ Finally, the <code>Makefile</code>:
</p>
<pre>
-include $(GOROOT)/src/Make.$(GOARCH)
+include $(GOROOT)/src/Make.inc
TARG=numbers
GOFILES=\
@@ -269,13 +303,13 @@ include $(GOROOT)/src/Make.pkg
</pre>
<p>
-Running <code>make install</code> will build and install the package to
+Running <code>gomake install</code> will build and install the package to
the <code>$GOROOT/pkg/</code> directory (it can then be used by any
program on the system).
</p>
<p>
-Running <code>make test</code> (or just running the command
+Running <code>gomake test</code> (or just running the command
<code>gotest</code>) will rebuild the package, including the
<code>numbers_test.go</code> file, and then run the <code>TestDouble</code>
function. The output "<code>PASS</code>" indicates that all tests passed
diff --git a/doc/codelab/wiki/Makefile b/doc/codelab/wiki/Makefile
index 76ab5c5bc..e0549fc8e 100644
--- a/doc/codelab/wiki/Makefile
+++ b/doc/codelab/wiki/Makefile
@@ -2,16 +2,11 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../../src/Make.$(GOARCH)
+include ../../../src/Make.inc
all: index.html
-# ugly hack to deal with whitespaces in $GOROOT
-nullstring :=
-space := $(nullstring) # a space at the end
-QUOTED_GOROOT:=$(subst $(space),\ ,$(GOROOT))
-
-include $(QUOTED_GOROOT)/src/Make.common
+include ../../../src/Make.common
CLEANFILES+=index.html srcextract.bin htmlify.bin
@@ -23,7 +18,7 @@ test: final.bin
rm -f final.6 final.bin
%.bin: %.$O
- $(QUOTED_GOBIN)/$(LD) -o $@ $<
-%.$O:
- $(QUOTED_GOBIN)/$(GC) $*.go
+ $(LD) -o $@ $<
+%.$O:
+ $(GC) $*.go
diff --git a/doc/codelab/wiki/final-noclosure.go b/doc/codelab/wiki/final-noclosure.go
index d4ce71560..2f48565ca 100644
--- a/doc/codelab/wiki/final-noclosure.go
+++ b/doc/codelab/wiki/final-noclosure.go
@@ -27,21 +27,21 @@ func loadPage(title string) (*page, os.Error) {
return &page{title: title, body: body}, nil
}
-func viewHandler(c *http.Conn, r *http.Request) {
- title, err := getTitle(c, r)
+func viewHandler(w http.ResponseWriter, r *http.Request) {
+ title, err := getTitle(w, r)
if err != nil {
return
}
p, err := loadPage(title)
if err != nil {
- http.Redirect(c, "/edit/"+title, http.StatusFound)
+ http.Redirect(w, r, "/edit/"+title, http.StatusFound)
return
}
- renderTemplate(c, "view", p)
+ renderTemplate(w, "view", p)
}
-func editHandler(c *http.Conn, r *http.Request) {
- title, err := getTitle(c, r)
+func editHandler(w http.ResponseWriter, r *http.Request) {
+ title, err := getTitle(w, r)
if err != nil {
return
}
@@ -49,11 +49,11 @@ func editHandler(c *http.Conn, r *http.Request) {
if err != nil {
p = &page{title: title}
}
- renderTemplate(c, "edit", p)
+ renderTemplate(w, "edit", p)
}
-func saveHandler(c *http.Conn, r *http.Request) {
- title, err := getTitle(c, r)
+func saveHandler(w http.ResponseWriter, r *http.Request) {
+ title, err := getTitle(w, r)
if err != nil {
return
}
@@ -61,21 +61,21 @@ func saveHandler(c *http.Conn, r *http.Request) {
p := &page{title: title, body: []byte(body)}
err = p.save()
if err != nil {
- http.Error(c, err.String(), http.StatusInternalServerError)
+ http.Error(w, err.String(), http.StatusInternalServerError)
return
}
- http.Redirect(c, "/view/"+title, http.StatusFound)
+ http.Redirect(w, r, "/view/"+title, http.StatusFound)
}
-func renderTemplate(c *http.Conn, tmpl string, p *page) {
+func renderTemplate(w http.ResponseWriter, tmpl string, p *page) {
t, err := template.ParseFile(tmpl+".html", nil)
if err != nil {
- http.Error(c, err.String(), http.StatusInternalServerError)
+ http.Error(w, err.String(), http.StatusInternalServerError)
return
}
- err = t.Execute(p, c)
+ err = t.Execute(p, w)
if err != nil {
- http.Error(c, err.String(), http.StatusInternalServerError)
+ http.Error(w, err.String(), http.StatusInternalServerError)
}
}
@@ -83,10 +83,10 @@ const lenPath = len("/view/")
var titleValidator = regexp.MustCompile("^[a-zA-Z0-9]+$")
-func getTitle(c *http.Conn, r *http.Request) (title string, err os.Error) {
+func getTitle(w http.ResponseWriter, r *http.Request) (title string, err os.Error) {
title = r.URL.Path[lenPath:]
if !titleValidator.MatchString(title) {
- http.NotFound(c, r)
+ http.NotFound(w, r)
err = os.NewError("Invalid Page Title")
}
return
diff --git a/doc/codelab/wiki/final-noerror.go b/doc/codelab/wiki/final-noerror.go
index 3b699452a..cf4852265 100644
--- a/doc/codelab/wiki/final-noerror.go
+++ b/doc/codelab/wiki/final-noerror.go
@@ -28,21 +28,21 @@ func loadPage(title string) (*page, os.Error) {
const lenPath = len("/view/")
-func editHandler(c *http.Conn, r *http.Request) {
+func editHandler(w http.ResponseWriter, r *http.Request) {
title := r.URL.Path[lenPath:]
p, err := loadPage(title)
if err != nil {
p = &page{title: title}
}
t, _ := template.ParseFile("edit.html", nil)
- t.Execute(p, c)
+ t.Execute(p, w)
}
-func viewHandler(c *http.Conn, r *http.Request) {
+func viewHandler(w http.ResponseWriter, r *http.Request) {
title := r.URL.Path[lenPath:]
p, _ := loadPage(title)
t, _ := template.ParseFile("view.html", nil)
- t.Execute(p, c)
+ t.Execute(p, w)
}
func main() {
diff --git a/doc/codelab/wiki/final-parsetemplate.go b/doc/codelab/wiki/final-parsetemplate.go
index 93b956b9d..f02d116b2 100644
--- a/doc/codelab/wiki/final-parsetemplate.go
+++ b/doc/codelab/wiki/final-parsetemplate.go
@@ -27,43 +27,43 @@ func loadPage(title string) (*page, os.Error) {
return &page{title: title, body: body}, nil
}
-func viewHandler(c *http.Conn, r *http.Request, title string) {
+func viewHandler(w http.ResponseWriter, r *http.Request, title string) {
p, err := loadPage(title)
if err != nil {
- http.Redirect(c, "/edit/"+title, http.StatusFound)
+ http.Redirect(w, r, "/edit/"+title, http.StatusFound)
return
}
- renderTemplate(c, "view", p)
+ renderTemplate(w, "view", p)
}
-func editHandler(c *http.Conn, r *http.Request, title string) {
+func editHandler(w http.ResponseWriter, r *http.Request, title string) {
p, err := loadPage(title)
if err != nil {
p = &page{title: title}
}
- renderTemplate(c, "edit", p)
+ renderTemplate(w, "edit", p)
}
-func saveHandler(c *http.Conn, r *http.Request, title string) {
+func saveHandler(w http.ResponseWriter, r *http.Request, title string) {
body := r.FormValue("body")
p := &page{title: title, body: []byte(body)}
err := p.save()
if err != nil {
- http.Error(c, err.String(), http.StatusInternalServerError)
+ http.Error(w, err.String(), http.StatusInternalServerError)
return
}
- http.Redirect(c, "/view/"+title, http.StatusFound)
+ http.Redirect(w, r, "/view/"+title, http.StatusFound)
}
-func renderTemplate(c *http.Conn, tmpl string, p *page) {
+func renderTemplate(w http.ResponseWriter, tmpl string, p *page) {
t, err := template.ParseFile(tmpl+".html", nil)
if err != nil {
- http.Error(c, err.String(), http.StatusInternalServerError)
+ http.Error(w, err.String(), http.StatusInternalServerError)
return
}
- err = t.Execute(p, c)
+ err = t.Execute(p, w)
if err != nil {
- http.Error(c, err.String(), http.StatusInternalServerError)
+ http.Error(w, err.String(), http.StatusInternalServerError)
}
}
@@ -71,14 +71,14 @@ const lenPath = len("/view/")
var titleValidator = regexp.MustCompile("^[a-zA-Z0-9]+$")
-func makeHandler(fn func(*http.Conn, *http.Request, string)) http.HandlerFunc {
- return func(c *http.Conn, r *http.Request) {
+func makeHandler(fn func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
title := r.URL.Path[lenPath:]
if !titleValidator.MatchString(title) {
- http.NotFound(c, r)
+ http.NotFound(w, r)
return
}
- fn(c, r, title)
+ fn(w, r, title)
}
}
diff --git a/doc/codelab/wiki/final-template.go b/doc/codelab/wiki/final-template.go
index 06c9366ad..0bb133d3a 100644
--- a/doc/codelab/wiki/final-template.go
+++ b/doc/codelab/wiki/final-template.go
@@ -28,32 +28,32 @@ func loadPage(title string) (*page, os.Error) {
const lenPath = len("/view/")
-func editHandler(c *http.Conn, r *http.Request) {
+func editHandler(w http.ResponseWriter, r *http.Request) {
title := r.URL.Path[lenPath:]
p, err := loadPage(title)
if err != nil {
p = &page{title: title}
}
- renderTemplate(c, "edit", p)
+ renderTemplate(w, "edit", p)
}
-func viewHandler(c *http.Conn, r *http.Request) {
+func viewHandler(w http.ResponseWriter, r *http.Request) {
title := r.URL.Path[lenPath:]
p, _ := loadPage(title)
- renderTemplate(c, "view", p)
+ renderTemplate(w, "view", p)
}
-func saveHandler(c *http.Conn, r *http.Request) {
+func saveHandler(w http.ResponseWriter, r *http.Request) {
title := r.URL.Path[lenPath:]
body := r.FormValue("body")
p := &page{title: title, body: []byte(body)}
p.save()
- http.Redirect(c, "/view/"+title, http.StatusFound)
+ http.Redirect(w, r, "/view/"+title, http.StatusFound)
}
-func renderTemplate(c *http.Conn, tmpl string, p *page) {
+func renderTemplate(w http.ResponseWriter, tmpl string, p *page) {
t, _ := template.ParseFile(tmpl+".html", nil)
- t.Execute(p, c)
+ t.Execute(p, w)
}
func main() {
diff --git a/doc/codelab/wiki/final.go b/doc/codelab/wiki/final.go
index 0186729c2..0c0206bc0 100644
--- a/doc/codelab/wiki/final.go
+++ b/doc/codelab/wiki/final.go
@@ -27,32 +27,32 @@ func loadPage(title string) (*page, os.Error) {
return &page{title: title, body: body}, nil
}
-func viewHandler(c *http.Conn, r *http.Request, title string) {
+func viewHandler(w http.ResponseWriter, r *http.Request, title string) {
p, err := loadPage(title)
if err != nil {
- http.Redirect(c, "/edit/"+title, http.StatusFound)
+ http.Redirect(w, r, "/edit/"+title, http.StatusFound)
return
}
- renderTemplate(c, "view", p)
+ renderTemplate(w, "view", p)
}
-func editHandler(c *http.Conn, r *http.Request, title string) {
+func editHandler(w http.ResponseWriter, r *http.Request, title string) {
p, err := loadPage(title)
if err != nil {
p = &page{title: title}
}
- renderTemplate(c, "edit", p)
+ renderTemplate(w, "edit", p)
}
-func saveHandler(c *http.Conn, r *http.Request, title string) {
+func saveHandler(w http.ResponseWriter, r *http.Request, title string) {
body := r.FormValue("body")
p := &page{title: title, body: []byte(body)}
err := p.save()
if err != nil {
- http.Error(c, err.String(), http.StatusInternalServerError)
+ http.Error(w, err.String(), http.StatusInternalServerError)
return
}
- http.Redirect(c, "/view/"+title, http.StatusFound)
+ http.Redirect(w, r, "/view/"+title, http.StatusFound)
}
var templates = make(map[string]*template.Template)
@@ -63,10 +63,10 @@ func init() {
}
}
-func renderTemplate(c *http.Conn, tmpl string, p *page) {
- err := templates[tmpl].Execute(p, c)
+func renderTemplate(w http.ResponseWriter, tmpl string, p *page) {
+ err := templates[tmpl].Execute(p, w)
if err != nil {
- http.Error(c, err.String(), http.StatusInternalServerError)
+ http.Error(w, err.String(), http.StatusInternalServerError)
}
}
@@ -74,14 +74,14 @@ const lenPath = len("/view/")
var titleValidator = regexp.MustCompile("^[a-zA-Z0-9]+$")
-func makeHandler(fn func(*http.Conn, *http.Request, string)) http.HandlerFunc {
- return func(c *http.Conn, r *http.Request) {
+func makeHandler(fn func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
title := r.URL.Path[lenPath:]
if !titleValidator.MatchString(title) {
- http.NotFound(c, r)
+ http.NotFound(w, r)
return
}
- fn(c, r, title)
+ fn(w, r, title)
}
}
diff --git a/doc/codelab/wiki/http-sample.go b/doc/codelab/wiki/http-sample.go
index 11d5d7861..33379a1b6 100644
--- a/doc/codelab/wiki/http-sample.go
+++ b/doc/codelab/wiki/http-sample.go
@@ -5,8 +5,8 @@ import (
"http"
)
-func handler(c *http.Conn, r *http.Request) {
- fmt.Fprintf(c, "Hi there, I love %s!", r.URL.Path[1:])
+func handler(w http.ResponseWriter, r *http.Request) {
+ fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])
}
func main() {
diff --git a/doc/codelab/wiki/index.html b/doc/codelab/wiki/index.html
index 107e49f26..c494a3ced 100644
--- a/doc/codelab/wiki/index.html
+++ b/doc/codelab/wiki/index.html
@@ -1,7 +1,4 @@
-<div class="content">
-
-<h1>Writing Web Applications</h1>
-
+<!-- Codelab: Writing Web Applications -->
<h2>Introduction</h2>
<p>
@@ -243,8 +240,8 @@ import (
&#34;http&#34;
)
-func handler(c *http.Conn, r *http.Request) {
- fmt.Fprintf(c, &#34;Hi there, I love %s!&#34;, r.URL.Path[1:])
+func handler(w http.ResponseWriter, r *http.Request) {
+ fmt.Fprintf(w, &#34;Hi there, I love %s!&#34;, r.URL.Path[1:])
}
func main() {
@@ -269,12 +266,12 @@ This function will block until the program is terminated.
<p>
The function <code>handler</code> is of the type <code>http.HandlerFunc</code>.
-It takes an <code>http.Conn</code> and <code>http.Request</code> as its
-arguments.
+It takes an <code>http.ResponseWriter</code> and an <code>http.Request</code> as
+its arguments.
</p>
<p>
-An <code>http.Conn</code> is the server end of an HTTP connection; by writing
+An <code>http.ResponseWriter</code> value assembles the HTTP server's response; by writing
to it, we send data to the HTTP client.
</p>
@@ -317,10 +314,10 @@ Let's create a handler to view a wiki page:
<pre>
const lenPath = len(&#34;/view/&#34;)
-func viewHandler(c *http.Conn, r *http.Request) {
+func viewHandler(w http.ResponseWriter, r *http.Request) {
title := r.URL.Path[lenPath:]
p, _ := loadPage(title)
- fmt.Fprintf(c, &#34;&lt;h1&gt;%s&lt;/h1&gt;&lt;div&gt;%s&lt;/div&gt;&#34;, p.title, p.body)
+ fmt.Fprintf(w, &#34;&lt;h1&gt;%s&lt;/h1&gt;&lt;div&gt;%s&lt;/div&gt;&#34;, p.title, p.body)
}
</pre>
@@ -336,7 +333,7 @@ begin with <code>"/view/"</code>, which is not part of the page title.
<p>
The function then loads the page data, formats the page with a string of simple
-HTML, and writes it to <code>c</code>, the <code>http.Conn</code>.
+HTML, and writes it to <code>w</code>, the <code>http.ResponseWriter</code>.
</p>
<p>
@@ -409,13 +406,13 @@ and displays an HTML form.
</p>
<pre>
-func editHandler(c *http.Conn, r *http.Request) {
+func editHandler(w http.ResponseWriter, r *http.Request) {
title := r.URL.Path[lenPath:]
p, err := loadPage(title)
if err != nil {
p = &amp;page{title: title}
}
- fmt.Fprintf(c, &#34;&lt;h1&gt;Editing %s&lt;/h1&gt;&#34;+
+ fmt.Fprintf(w, &#34;&lt;h1&gt;Editing %s&lt;/h1&gt;&#34;+
&#34;&lt;form action=\&#34;/save/%s\&#34; method=\&#34;POST\&#34;&gt;&#34;+
&#34;&lt;textarea name=\&#34;body\&#34;&gt;%s&lt;/textarea&gt;&lt;br&gt;&#34;+
&#34;&lt;input type=\&#34;submit\&#34; value=\&#34;Save\&#34;&gt;&#34;+
@@ -471,14 +468,14 @@ HTML:
</p>
<pre>
-func editHandler(c *http.Conn, r *http.Request) {
+func editHandler(w http.ResponseWriter, r *http.Request) {
title := r.URL.Path[lenPath:]
p, err := loadPage(title)
if err != nil {
p = &amp;page{title: title}
}
t, _ := template.ParseFile(&#34;edit.html&#34;, nil)
- t.Execute(p, c)
+ t.Execute(p, w)
}
</pre>
@@ -491,7 +488,7 @@ The function <code>template.ParseFile</code> will read the contents of
The method <code>t.Execute</code> replaces all occurrences of
<code>{title}</code> and <code>{body}</code> with the values of
<code>p.title</code> and <code>p.body</code>, and writes the resultant
-HTML to the <code>http.Conn</code>.
+HTML to the <code>http.ResponseWriter</code>.
</p>
<p>
@@ -526,11 +523,11 @@ Modify <code>viewHandler</code> accordingly:
</p>
<pre>
-func viewHandler(c *http.Conn, r *http.Request) {
+func viewHandler(w http.ResponseWriter, r *http.Request) {
title := r.URL.Path[lenPath:]
p, _ := loadPage(title)
t, _ := template.ParseFile(&#34;view.html&#34;, nil)
- t.Execute(p, c)
+ t.Execute(p, w)
}
</pre>
@@ -541,24 +538,24 @@ to its own function:
</p>
<pre>
-func viewHandler(c *http.Conn, r *http.Request) {
+func viewHandler(w http.ResponseWriter, r *http.Request) {
title := r.URL.Path[lenPath:]
p, _ := loadPage(title)
- renderTemplate(c, &#34;view&#34;, p)
+ renderTemplate(w, &#34;view&#34;, p)
}
-func editHandler(c *http.Conn, r *http.Request) {
+func editHandler(w http.ResponseWriter, r *http.Request) {
title := r.URL.Path[lenPath:]
p, err := loadPage(title)
if err != nil {
p = &amp;page{title: title}
}
- renderTemplate(c, &#34;edit&#34;, p)
+ renderTemplate(w, &#34;edit&#34;, p)
}
-func renderTemplate(c *http.Conn, tmpl string, p *page) {
+func renderTemplate(w http.ResponseWriter, tmpl string, p *page) {
t, _ := template.ParseFile(tmpl+&#34;.html&#34;, nil)
- t.Execute(p, c)
+ t.Execute(p, w)
}
</pre>
@@ -576,13 +573,13 @@ redirect the client to the edit page so the content may be created:
</p>
<pre>
-func viewHandler(c *http.Conn, r *http.Request, title string) {
+func viewHandler(w http.ResponseWriter, r *http.Request, title string) {
p, err := loadPage(title)
if err != nil {
- http.Redirect(c, &#34;/edit/&#34;+title, http.StatusFound)
+ http.Redirect(w, r, &#34;/edit/&#34;+title, http.StatusFound)
return
}
- renderTemplate(c, &#34;view&#34;, p)
+ renderTemplate(w, &#34;view&#34;, p)
}
</pre>
@@ -599,12 +596,12 @@ The function <code>saveHandler</code> will handle the form submission.
</p>
<pre>
-func saveHandler(c *http.Conn, r *http.Request) {
+func saveHandler(w http.ResponseWriter, r *http.Request) {
title := r.URL.Path[lenPath:]
body := r.FormValue(&#34;body&#34;)
p := &amp;page{title: title, body: []byte(body)}
p.save()
- http.Redirect(c, &#34;/view/&#34;+title, http.StatusFound)
+ http.Redirect(w, r, &#34;/view/&#34;+title, http.StatusFound)
}
</pre>
@@ -637,15 +634,15 @@ First, let's handle the errors in <code>renderTemplate</code>:
</p>
<pre>
-func renderTemplate(c *http.Conn, tmpl string, p *page) {
+func renderTemplate(w http.ResponseWriter, tmpl string, p *page) {
t, err := template.ParseFile(tmpl+&#34;.html&#34;, nil)
if err != nil {
- http.Error(c, err.String(), http.StatusInternalServerError)
+ http.Error(w, err.String(), http.StatusInternalServerError)
return
}
- err = t.Execute(p, c)
+ err = t.Execute(p, w)
if err != nil {
- http.Error(c, err.String(), http.StatusInternalServerError)
+ http.Error(w, err.String(), http.StatusInternalServerError)
}
}
</pre>
@@ -661,15 +658,15 @@ Now let's fix up <code>saveHandler</code>:
</p>
<pre>
-func saveHandler(c *http.Conn, r *http.Request, title string) {
+func saveHandler(w http.ResponseWriter, r *http.Request, title string) {
body := r.FormValue(&#34;body&#34;)
p := &amp;page{title: title, body: []byte(body)}
err := p.save()
if err != nil {
- http.Error(c, err.String(), http.StatusInternalServerError)
+ http.Error(w, err.String(), http.StatusInternalServerError)
return
}
- http.Redirect(c, &#34;/view/&#34;+title, http.StatusFound)
+ http.Redirect(w, r, &#34;/view/&#34;+title, http.StatusFound)
}
</pre>
@@ -728,10 +725,10 @@ the <code>Execute</code> method on the appropriate <code>Template</code> from
<code>templates</code>:
<pre>
-func renderTemplate(c *http.Conn, tmpl string, p *page) {
- err := templates[tmpl].Execute(p, c)
+func renderTemplate(w http.ResponseWriter, tmpl string, p *page) {
+ err := templates[tmpl].Execute(p, w)
if err != nil {
- http.Error(c, err.String(), http.StatusInternalServerError)
+ http.Error(w, err.String(), http.StatusInternalServerError)
}
}
</pre>
@@ -768,10 +765,10 @@ URL, and tests it against our <code>titleValidator</code> expression:
</p>
<pre>
-func getTitle(c *http.Conn, r *http.Request) (title string, err os.Error) {
+func getTitle(w http.ResponseWriter, r *http.Request) (title string, err os.Error) {
title = r.URL.Path[lenPath:]
if !titleValidator.MatchString(title) {
- http.NotFound(c, r)
+ http.NotFound(w, r)
err = os.NewError(&#34;Invalid Page Title&#34;)
}
return
@@ -790,21 +787,21 @@ Let's put a call to <code>getTitle</code> in each of the handlers:
</p>
<pre>
-func viewHandler(c *http.Conn, r *http.Request) {
- title, err := getTitle(c, r)
+func viewHandler(w http.ResponseWriter, r *http.Request) {
+ title, err := getTitle(w, r)
if err != nil {
return
}
p, err := loadPage(title)
if err != nil {
- http.Redirect(c, &#34;/edit/&#34;+title, http.StatusFound)
+ http.Redirect(w, r, &#34;/edit/&#34;+title, http.StatusFound)
return
}
- renderTemplate(c, &#34;view&#34;, p)
+ renderTemplate(w, &#34;view&#34;, p)
}
-func editHandler(c *http.Conn, r *http.Request) {
- title, err := getTitle(c, r)
+func editHandler(w http.ResponseWriter, r *http.Request) {
+ title, err := getTitle(w, r)
if err != nil {
return
}
@@ -812,11 +809,11 @@ func editHandler(c *http.Conn, r *http.Request) {
if err != nil {
p = &amp;page{title: title}
}
- renderTemplate(c, &#34;edit&#34;, p)
+ renderTemplate(w, &#34;edit&#34;, p)
}
-func saveHandler(c *http.Conn, r *http.Request) {
- title, err := getTitle(c, r)
+func saveHandler(w http.ResponseWriter, r *http.Request) {
+ title, err := getTitle(w, r)
if err != nil {
return
}
@@ -824,10 +821,10 @@ func saveHandler(c *http.Conn, r *http.Request) {
p := &amp;page{title: title, body: []byte(body)}
err = p.save()
if err != nil {
- http.Error(c, err.String(), http.StatusInternalServerError)
+ http.Error(w, err.String(), http.StatusInternalServerError)
return
}
- http.Redirect(c, &#34;/view/&#34;+title, http.StatusFound)
+ http.Redirect(w, r, &#34;/view/&#34;+title, http.StatusFound)
}
</pre>
@@ -848,9 +845,9 @@ a title string:
</p>
<pre>
-func viewHandler(c *http.Conn, r *http.Request, title string)
-func editHandler(c *http.Conn, r *http.Request, title string)
-func saveHandler(c *http.Conn, r *http.Request, title string)
+func viewHandler(w http.ResponseWriter, r *http.Request, title string)
+func editHandler(w http.ResponseWriter, r *http.Request, title string)
+func saveHandler(w http.ResponseWriter, r *http.Request, title string)
</pre>
<p>
@@ -860,8 +857,8 @@ type</i>, and returns a function of type <code>http.HandlerFunc</code>
</p>
<pre>
-func makeHandler(fn func (*http.Conn, *http.Request, string)) http.HandlerFunc {
- return func(c *http.Conn, r *http.Request) {
+func makeHandler(fn func (http.ResponseWriter, *http.Request, string)) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
// Here we will extract the page title from the Request,
// and call the provided handler 'fn'
}
@@ -881,28 +878,28 @@ Now we can take the code from <code>getTitle</code> and use it here
</p>
<pre>
-func makeHandler(fn func(*http.Conn, *http.Request, string)) http.HandlerFunc {
- return func(c *http.Conn, r *http.Request) {
+func makeHandler(fn func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
title := r.URL.Path[lenPath:]
if !titleValidator.MatchString(title) {
- http.NotFound(c, r)
+ http.NotFound(w, r)
return
}
- fn(c, r, title)
+ fn(w, r, title)
}
}
</pre>
<p>
The closure returned by <code>makeHandler</code> is a function that takes
-an <code>http.Conn</code> and <code>http.Request</code> (in other words,
-an <code>http.HandlerFunc</code>).
+an <code>http.ResponseWriter</code> and <code>http.Request</code> (in other
+words, an <code>http.HandlerFunc</code>).
The closure extracts the <code>title</code> from the request path, and
validates it with the <code>titleValidator</code> regexp. If the
<code>title</code> is invalid, an error will be written to the
-<code>Conn</code> using the <code>http.NotFound</code> function.
+<code>ResponseWriter</code> using the <code>http.NotFound</code> function.
If the <code>title</code> is valid, the enclosed handler function
-<code>fn</code> will be called with the <code>Conn</code>,
+<code>fn</code> will be called with the <code>ResponseWriter</code>,
<code>Request</code>, and <code>title</code> as arguments.
</p>
@@ -927,32 +924,32 @@ making them much simpler:
</p>
<pre>
-func viewHandler(c *http.Conn, r *http.Request, title string) {
+func viewHandler(w http.ResponseWriter, r *http.Request, title string) {
p, err := loadPage(title)
if err != nil {
- http.Redirect(c, &#34;/edit/&#34;+title, http.StatusFound)
+ http.Redirect(w, r, &#34;/edit/&#34;+title, http.StatusFound)
return
}
- renderTemplate(c, &#34;view&#34;, p)
+ renderTemplate(w, &#34;view&#34;, p)
}
-func editHandler(c *http.Conn, r *http.Request, title string) {
+func editHandler(w http.ResponseWriter, r *http.Request, title string) {
p, err := loadPage(title)
if err != nil {
p = &amp;page{title: title}
}
- renderTemplate(c, &#34;edit&#34;, p)
+ renderTemplate(w, &#34;edit&#34;, p)
}
-func saveHandler(c *http.Conn, r *http.Request, title string) {
+func saveHandler(w http.ResponseWriter, r *http.Request, title string) {
body := r.FormValue(&#34;body&#34;)
p := &amp;page{title: title, body: []byte(body)}
err := p.save()
if err != nil {
- http.Error(c, err.String(), http.StatusInternalServerError)
+ http.Error(w, err.String(), http.StatusInternalServerError)
return
}
- http.Redirect(c, &#34;/view/&#34;+title, http.StatusFound)
+ http.Redirect(w, r, &#34;/view/&#34;+title, http.StatusFound)
}
</pre>
@@ -996,5 +993,3 @@ Here are some simple tasks you might want to tackle on your own:
(hint: you could use <code>regexp.ReplaceAllFunc</code> to do this)
</li>
</ul>
-
-</div>
diff --git a/doc/codelab/wiki/notemplate.go b/doc/codelab/wiki/notemplate.go
index a61d905e3..c1f952c83 100644
--- a/doc/codelab/wiki/notemplate.go
+++ b/doc/codelab/wiki/notemplate.go
@@ -28,19 +28,19 @@ func loadPage(title string) (*page, os.Error) {
const lenPath = len("/view/")
-func viewHandler(c *http.Conn, r *http.Request) {
+func viewHandler(w http.ResponseWriter, r *http.Request) {
title := r.URL.Path[lenPath:]
p, _ := loadPage(title)
- fmt.Fprintf(c, "<h1>%s</h1><div>%s</div>", p.title, p.body)
+ fmt.Fprintf(w, "<h1>%s</h1><div>%s</div>", p.title, p.body)
}
-func editHandler(c *http.Conn, r *http.Request) {
+func editHandler(w http.ResponseWriter, r *http.Request) {
title := r.URL.Path[lenPath:]
p, err := loadPage(title)
if err != nil {
p = &page{title: title}
}
- fmt.Fprintf(c, "<h1>Editing %s</h1>"+
+ fmt.Fprintf(w, "<h1>Editing %s</h1>"+
"<form action=\"/save/%s\" method=\"POST\">"+
"<textarea name=\"body\">%s</textarea><br>"+
"<input type=\"submit\" value=\"Save\">"+
diff --git a/doc/codelab/wiki/part2.go b/doc/codelab/wiki/part2.go
index c2c29dc3b..8d4454a74 100644
--- a/doc/codelab/wiki/part2.go
+++ b/doc/codelab/wiki/part2.go
@@ -28,10 +28,10 @@ func loadPage(title string) (*page, os.Error) {
const lenPath = len("/view/")
-func viewHandler(c *http.Conn, r *http.Request) {
+func viewHandler(w http.ResponseWriter, r *http.Request) {
title := r.URL.Path[lenPath:]
p, _ := loadPage(title)
- fmt.Fprintf(c, "<h1>%s</h1><div>%s</div>", p.title, p.body)
+ fmt.Fprintf(w, "<h1>%s</h1><div>%s</div>", p.title, p.body)
}
func main() {
diff --git a/doc/codelab/wiki/srcextract.go b/doc/codelab/wiki/srcextract.go
index 607375183..0addc61c4 100644
--- a/doc/codelab/wiki/srcextract.go
+++ b/doc/codelab/wiki/srcextract.go
@@ -25,7 +25,7 @@ func main() {
os.Exit(2)
}
// load file
- file, err := parser.ParseFile(*srcFn, nil, nil, 0)
+ file, err := parser.ParseFile(*srcFn, nil, 0)
if err != nil {
log.Exit(err)
}
diff --git a/doc/codelab/wiki/wiki.html b/doc/codelab/wiki/wiki.html
index c7f44ded4..919385edf 100644
--- a/doc/codelab/wiki/wiki.html
+++ b/doc/codelab/wiki/wiki.html
@@ -1,7 +1,4 @@
-<div class="content">
-
-<h1>Writing Web Applications</h1>
-
+<!-- Codelab: Writing Web Applications -->
<h2>Introduction</h2>
<p>
@@ -233,12 +230,12 @@ This function will block until the program is terminated.
<p>
The function <code>handler</code> is of the type <code>http.HandlerFunc</code>.
-It takes an <code>http.Conn</code> and <code>http.Request</code> as its
-arguments.
+It takes an <code>http.ResponseWriter</code> and an <code>http.Request</code> as
+its arguments.
</p>
<p>
-An <code>http.Conn</code> is the server end of an HTTP connection; by writing
+An <code>http.ResponseWriter</code> value assembles the HTTP server's response; by writing
to it, we send data to the HTTP client.
</p>
@@ -296,7 +293,7 @@ begin with <code>"/view/"</code>, which is not part of the page title.
<p>
The function then loads the page data, formats the page with a string of simple
-HTML, and writes it to <code>c</code>, the <code>http.Conn</code>.
+HTML, and writes it to <code>w</code>, the <code>http.ResponseWriter</code>.
</p>
<p>
@@ -418,7 +415,7 @@ The function <code>template.ParseFile</code> will read the contents of
The method <code>t.Execute</code> replaces all occurrences of
<code>{title}</code> and <code>{body}</code> with the values of
<code>p.title</code> and <code>p.body</code>, and writes the resultant
-HTML to the <code>http.Conn</code>.
+HTML to the <code>http.ResponseWriter</code>.
</p>
<p>
@@ -670,9 +667,9 @@ a title string:
</p>
<pre>
-func viewHandler(c *http.Conn, r *http.Request, title string)
-func editHandler(c *http.Conn, r *http.Request, title string)
-func saveHandler(c *http.Conn, r *http.Request, title string)
+func viewHandler(w http.ResponseWriter, r *http.Request, title string)
+func editHandler(w http.ResponseWriter, r *http.Request, title string)
+func saveHandler(w http.ResponseWriter, r *http.Request, title string)
</pre>
<p>
@@ -682,8 +679,8 @@ type</i>, and returns a function of type <code>http.HandlerFunc</code>
</p>
<pre>
-func makeHandler(fn func (*http.Conn, *http.Request, string)) http.HandlerFunc {
- return func(c *http.Conn, r *http.Request) {
+func makeHandler(fn func (http.ResponseWriter, *http.Request, string)) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
// Here we will extract the page title from the Request,
// and call the provided handler 'fn'
}
@@ -708,14 +705,14 @@ Now we can take the code from <code>getTitle</code> and use it here
<p>
The closure returned by <code>makeHandler</code> is a function that takes
-an <code>http.Conn</code> and <code>http.Request</code> (in other words,
-an <code>http.HandlerFunc</code>).
+an <code>http.ResponseWriter</code> and <code>http.Request</code> (in other
+words, an <code>http.HandlerFunc</code>).
The closure extracts the <code>title</code> from the request path, and
validates it with the <code>titleValidator</code> regexp. If the
<code>title</code> is invalid, an error will be written to the
-<code>Conn</code> using the <code>http.NotFound</code> function.
+<code>ResponseWriter</code> using the <code>http.NotFound</code> function.
If the <code>title</code> is valid, the enclosed handler function
-<code>fn</code> will be called with the <code>Conn</code>,
+<code>fn</code> will be called with the <code>ResponseWriter</code>,
<code>Request</code>, and <code>title</code> as arguments.
</p>
@@ -782,5 +779,3 @@ Here are some simple tasks you might want to tackle on your own:
(hint: you could use <code>regexp.ReplaceAllFunc</code> to do this)
</li>
</ul>
-
-</div>
diff --git a/doc/codereview_with_mq.html b/doc/codereview_with_mq.html
index 7b2e0f3bf..33f415f13 100644
--- a/doc/codereview_with_mq.html
+++ b/doc/codereview_with_mq.html
@@ -36,11 +36,11 @@ prevent that case:
<pre>
[hooks]
# Prevent "hg pull" if MQ patches are applied.
-prechangegroup.mq-no-pull = ! hg qtop > /dev/null 2>&1
+prechangegroup.mq-no-pull = ! hg qtop > /dev/null 2>&amp;1
# Prevent "hg push" if MQ patches are applied.
-preoutgoing.mq-no-push = ! hg qtop > /dev/null 2>&1
+preoutgoing.mq-no-push = ! hg qtop > /dev/null 2>&amp;1
# Prevent "hg update" if MQ patches are applied.
-preupdate.mq-no-update = ! hg qtop > /dev/null 2>&1
+preupdate.mq-no-update = ! hg qtop > /dev/null 2>&amp;1
</pre>
<h2>Making a change</h2>
diff --git a/doc/codewalk/urlpoll.go b/doc/codewalk/urlpoll.go
index 2629f2b68..b51be9502 100644
--- a/doc/codewalk/urlpoll.go
+++ b/doc/codewalk/urlpoll.go
@@ -52,9 +52,9 @@ func StateMonitor(updateInterval int64) chan<- State {
// logState prints a state map.
func logState(s map[string]string) {
- log.Stdout("Current state:")
+ log.Println("Current state:")
for k, v := range s {
- log.Stdoutf(" %s %s", k, v)
+ log.Printf(" %s %s", k, v)
}
}
@@ -69,7 +69,7 @@ type Resource struct {
func (r *Resource) Poll() string {
resp, err := http.Head(r.url)
if err != nil {
- log.Stderr("Error", r.url, err)
+ log.Println("Error", r.url, err)
r.errCount++
return err.String()
}
diff --git a/doc/community.html b/doc/community.html
new file mode 100644
index 000000000..c3b16cacb
--- /dev/null
+++ b/doc/community.html
@@ -0,0 +1,53 @@
+<!-- title Community -->
+
+<div class="left-column">
+
+<h2 id="developer_info">The Go Community</h2>
+
+<h3 id="mailinglist"><a href="http://groups.google.com/group/golang-nuts">Go Nuts Mailing List</a></h3>
+<p>The <a href="http://groups.google.com/group/golang-nuts">golang-nuts</a>
+mailing list is for general Go discussion.</p>
+
+<h3 id=""><a href="http://godashboard.appspot.com/package">Go Packages Dashboard</a></h3>
+<p>A list of the most popular <a href="/cmd/goinstall/">goinstall</a>'d
+Go libraries.</p>
+
+<h3 id=""><a href="http://godashboard.appspot.com/project">Go Project Dashboard</a></h3>
+<p>A list of external Go projects including programs and libraries.</p>
+
+<h3 id="irc"><a href="irc:irc.freenode.net/go-nuts">Go IRC Channel</a></h3>
+<p><b>#go-nuts</b> on <b>irc.freenode.net</b> is the official Go IRC channel.</p>
+
+<h3 id="twitter"><a href="http://twitter.com/go_nuts">@go_nuts at Twitter</a></h3>
+<p>The Go project's official Twitter account.</p>
+
+</div>
+
+<div class="right-column">
+
+<h2 id="blogs">Blogs</h2>
+
+<h3 id="blog_go"><a href="http://blog.golang.org/">The Go Blog</a></h3>
+<p>
+The Go project's official blog, maintained by the core Go developers.
+</p>
+
+<h3 id="blog_rsc"><a href="http://research.swtch.com/search/label/Go">research!rsc</a></h3>
+<p>
+Posts labelled 'Go' by Russ Cox, one of the core Go developers.
+</p>
+
+<h3 id="blog_iant"><a href="http://www.airs.com/blog/archives/category/programming">Airs</a></h3>
+<p>
+Posts labelled 'Programming' by Ian Lance Taylor, one of the core Go developers.
+</p>
+
+<h3 id="blog_adg"><a href="http://nf.id.au/tag/go">nf.id.au</a></h3>
+<p>
+Posts labelled 'Go' by Andrew Gerrand, one of the core Go developers.
+</p>
+
+</div>
+
+<div class="end-columns"></div>
+
diff --git a/doc/contrib.html b/doc/contrib.html
new file mode 100644
index 000000000..121cc45dc
--- /dev/null
+++ b/doc/contrib.html
@@ -0,0 +1,45 @@
+<!-- title Contributing -->
+
+<div class="left-column">
+
+<h2 id="developer_info">Resources for Developers</h2>
+
+<h3 id="issuetracker"><a href="http://code.google.com/p/go/issues">Issue Tracker</a></h3>
+<p>Having an issue with Go? Check the tracker to see if it's a known issue.</p>
+<p>If your issue is not listed, please file a <a
+href="http://code.google.com/p/go/issues/entry">bug report</a>.</p>
+
+<h3 id="build_status"><a href="http://godashboard.appspot.com/">Build Status</a></h3>
+<p>View the status of Go builds across the supported operating
+systems and architectures.</p>
+
+<h3 id="contibute"><a href="contribute.html">Contribution Guidelines</a></h3>
+<p>So, you want to contribute code to the Go project? That's great!</p>
+<p>The first step is to read these contributions guidelines for information on
+design, testing, and our code review process.</p>
+
+</div>
+
+<div class="right-column">
+
+<h2 id="">The Go Project</h2>
+
+<h3 id="roadmap"><a href="devel/roadmap.html">Roadmap</a></h3>
+<p>Features and ideas being developed or discussed by the Go team.</p>
+
+<h3 id="release"><a href="devel/release.html">Release History</a></h3>
+<p>A summarization of the changes between tagged releases of Go.</p>
+
+<h3 id="golang-dev"><a href="http://groups.google.com/group/golang-dev">Developer Mailing List</a></h3>
+<p>The <a href="http://groups.google.com/group/golang-dev">golang-dev</a>
+mailing list is for discussing and reviewing code for the Go project.</p>
+<p>For general discussion of Go programming, see <a
+href="http://groups.google.com/group/golang-nuts">golang-nuts</a>.</p>
+
+<h3 id="golang-checkins"><a href="http://groups.google.com/group/golang-checkins">Checkins Mailing List</a></h3>
+<p>A mailing list that receives a message summarizing each checkin to the Go repository.</p>
+
+</div>
+
+<div class="end-columns"></div>
+
diff --git a/doc/contribute.html b/doc/contribute.html
index 6814274ba..ba70c9600 100644
--- a/doc/contribute.html
+++ b/doc/contribute.html
@@ -1,4 +1,4 @@
-<!-- Contributing to the Go project -->
+<!-- Contribution Guidelines -->
<h2 id="Introduction">Introduction</h2>
@@ -218,9 +218,9 @@ mailing list.
<p>
Replace &ldquo;<code>&lt;enter description here&gt;</code>&rdquo;
with a description of your change.
-The first line of the change description is conventionally
-a one-line summary of the change and is used as the
-subject for code review mail; the rest of the
+The first line of the change description is conventionally a one-line
+summary of the change, prefixed by the primary affected package,
+and is used as the subject for code review mail; the rest of the
description elaborates.
</p>
@@ -245,7 +245,7 @@ Reviewer: golang-dev@googlegroups.com
CC: math-nuts@swtch.com
Description:
- Sin, Cos, Tan: improved precision for very large arguments
+ math: improved Sin, Cos and Tan precision for very large arguments.
See Bimmler and Shaney, ``Extreme sinusoids,'' J. Math 3(14).
Fixes issue 159.
@@ -522,7 +522,7 @@ This rigmarole needs to be done only for your first submission.
<p>Code that you contribute should use the standard copyright header:</p>
<pre>
-// Copyright 2010 The Go Authors. All rights reserved.
+// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
</pre>
diff --git a/doc/devel/release.html b/doc/devel/release.html
index 39c521c1e..ecf125953 100644
--- a/doc/devel/release.html
+++ b/doc/devel/release.html
@@ -5,6 +5,1149 @@
<p>This page summarizes the changes between tagged releases of Go.
For full details, see the <a href="http://code.google.com/p/go/source/list">Mercurial change log</a>.</p>
+<h3 id="2011-01-12">2011-01-12</h3>
+
+<pre>
+The json, gob, and template packages have changed, and code that uses them
+may need to be updated after this release. They will no longer read or write
+unexported struct fields. When marshalling a struct with json or gob the
+unexported fields will be silently ignored. Attempting to unmarshal json or
+gob data into an unexported field will generate an error. Accessing an
+unexported field from a template will cause the Execute function to return
+an error.
+
+Godoc now supports regular expression full text search, and this
+functionality is now available on golang.org.
+
+Other changes:
+* arm: initial cut at arm optimizer.
+* bytes.Buffer: Fix bug in UnreadByte.
+* cgo: export unsafe.Pointer as void*, fix enum const conflict,
+ output alignment fix (thanks Gustavo Niemeyer).
+* crypto/block: mark as deprecated.
+* crypto/openpgp: add error and armor.
+* crypto: add twofish package (thanks Berengar Lehr).
+* doc/spec: remove Maxalign from spec.
+* encoding/line: new package for reading lines from an io.Reader.
+* go/ast: correct end position for Index and TypeAssert expressions.
+* gob: make (en|dec)code(Ui|I)nt methods rather than functions.
+* godefs: better handling of enums.
+* gofmt: don't attempt certain illegal rewrites,
+ rewriter matches apply to expressions only.
+* goinstall: preliminary support for cgo packages (thanks Gustavo Niemeyer).
+* hg: add cgo/_cgo_* to .hgignore.
+* http: fix text displayed in Redirect.
+* ld: fix exported dynamic symbols on Mach-O,
+ permit a Mach-O symbol to be exported in the dynamic symbol table.
+* log: add methods for exit and panic.
+* net: use closesocket api instead of CloseHandle on Windows (thanks Alex Brainman).
+* netchan: make fields exported for gob change.
+* os: add Sync to *File, wraps syscall.Fsync.
+* runtime/cgo: Add callbacks to support SWIG.
+* runtime: Restore scheduler stack position if cgo callback panics.
+* suffixarray: faster creation algorithm (thanks Eric Eisner).
+* syscall: fix mksysnum_linux.sh (thanks Anthony Martin).
+* time.NewTicker: panic for intervals <= 0.
+* time: add AfterFunc to call a function after a duration (thanks Roger Peppe),
+ fix tick accuracy when using multiple Tickers (thanks Eoghan Sherry).</pre>
+
+<h3 id="2011-01-06">2011-01-06</h3>
+
+<pre>
+This release includes several fixes and changes:
+
+* build: Make.pkg: use installed runtime.h for cgo.
+* cgo: disallow use of C.errno.
+* crypto/cipher: fix OCFB,
+ make NewCBCEncrypter return BlockMode.
+* doc: 6l: fix documentation of -L flag,
+ add golanguage.ru to foreign-language doc list,
+ effective go: explain the effect of repanicking better,
+ update Effective Go for template API change,
+ update contribution guidelines to prefix the change description.
+* encoding/binary: reject types with implementation-dependent sizes (thanks Patrick Gavlin).
+* exp/evalsimple fix handling of slices like s[:2] (thanks Sebastien Binet).
+* fmt: made format string handling more efficient,
+ normalize processing of format string.
+* gc: return constant floats for parts of complex constants (thanks Anthony Martin),
+ rewrite complex /= to l = l / r (thanks Patrick Gavlin),
+ fix &^=.
+* go/ast: provide complete node text range info.
+* gob: generate a better error message in one confusing place.
+* godoc: fix godoc -src (thanks Icarus Sparry).
+* goinstall: add -clean flag (thanks Kyle Lemons),
+ add checkout concept (thanks Caine Tighe),
+ fix -u for bzr (thanks Gustavo Niemeyer).
+* http: permit empty Reason-Phrase in response Status-Line.
+* io: fix Copyn EOF handling.
+* net: fix close of Listener (thanks Michael Hoisie).
+* regexp: fix performance bug, make anchored searches fail fast,
+ fix prefix bug.
+* runtime/cgo: fix stackguard on FreeBSD/amd64 (thanks Anthony Martin).
+* strconv: atof: added 'E' as valid token for exponent (thanks Stefan Nilsson),
+ update ftoa comment for 'E' and 'G'.
+* strings: fix description of FieldsFunc (thanks Roger Peppe).
+* syscall: correct Linux Splice definition,
+ make Access second argument consistently uint32.
+</pre>
+
+<h3 id="2010-12-22">2010-12-22</h3>
+
+<pre>
+A small release this week. The most significant change is that some
+outstanding cgo issues were resolved.
+
+* cgo: handle references to symbols in shared libraries.
+* crypto/elliptic: add serialisation and key pair generation.
+* crypto/hmac: add HMAC-SHA256 (thanks Anthony Martin).
+* crypto/tls: add ECDHE support ("Elliptic Curve Diffie Hellman Ephemeral"),
+ add support code for generating handshake scripts for testing.
+* darwin, freebsd: ignore write failure (during print, panic).
+* exp/draw: remove Border function.
+* expvar: quote StringFunc output, same as String output.
+* hash/crc64: fix typo in Sum.
+* ld: allow relocations pointing at ELF .bss symbols, ignore stab symbols.
+* misc/cgo/life: fix, add to build.
+* regexp: add HasMeta, HasOperator, and String methods to Regexp.
+* suffixarray: implemented FindAllIndex regexp search.
+* test/bench: update numbers for regex-dna after speedup to regexp.
+* time: explain the formats a little better.
+</pre>
+
+<h3 id="2010-12-15">2010-12-15</h3>
+
+<pre>
+Package crypto/cipher has been started, to replace crypto/block.
+As part of the changes, rc4.Cipher’s XORKeyStream method signature has changed from
+ XORKeyStream(buf []byte)
+to
+ XORKeyStream(dst, src []byte)
+to implement the cipher.Stream interface. If you use crypto/block, you’ll need
+to switch to crypto/cipher once it is complete.
+
+Package smtp’s StartTLS now takes a *tls.Config argument.
+
+Package reflect’s ArrayCopy has been renamed to Copy. There are new functions
+Append and AppendSlice.
+
+The print/println bootstrapping functions now write to standard error.
+To write to standard output, use fmt.Print[ln].
+
+A new tool, govet, has been added to the Go distribution. Govet is a static
+checker for Go programs. At the moment, and for the forseeable future,
+it only checks arguments to print calls.
+
+The cgo tool for writing Go bindings for C code has changed so that it no
+longer uses stub .so files (like cgo_stdio.so). Cgo-based packages using the
+standard Makefiles should build without any changes. Any alternate build
+mechanisms will need to be updated.
+
+The C and Go compilers (6g, 6c, 8g, 8c, 5g, 5c) now align structs according to
+the maximum alignment of the fields they contain; previously they aligned
+structs to word boundaries. This may break non-cgo-based code that attempts to
+mix C and Go.
+
+NaCl support has been removed. The recent linker changes broke NaCl support
+a month ago, and there are no known users of it.
+If necessary, the NaCl code can be recovered from the repository history.
+
+* 5g/8g, 8l, ld, prof: fix output of 32-bit values (thanks Eoghan Sherry).
+* [68]l and runtime: GDB support for interfaces and goroutines.
+* 6l, 8l: support for linking ELF and Mach-O .o files.
+* all: simplify two-variable ranges with unused second variable (thanks Ryan Hitchman).
+* arm: updated soft float support.
+* codereview: keep quiet when not in use (thanks Eoghan Sherry).
+* compress/flate: implement Flush, equivalent to zlib's Z_SYNC_FLUSH.
+* crypto/tls: use rand.Reader in cert generation example (thanks Anthony Martin).
+* dashboard: fix project tag filter.
+* debug/elf, debug/macho: add ImportedLibraries, ImportedSymbols.
+* doc/go_mem: goroutine exit is not special.
+* event.go: another print glitch from gocheck.
+* gc: bug fixes,
+ syntax error for incomplete chan type (thanks Ryan Hitchman).
+* go/ast: fix ast.Walk.
+* gob: document the byte count used in the encoding of values,
+ fix bug sending zero-length top-level slices and maps,
+ Register should use the original type, not the indirected one.
+* godashboard: support submitting projects with non-ascii names (thanks Ryan Hitchman)
+* godefs: guard against structs with pad fields
+* godoc: added textual search, to enable use -fulltext flag.
+* gofmt: simplify "x, _ = range y" to "x = range y".
+* gopack: allow ELF/Mach-O objects in .a files without clearing allobj.
+* go/token,scanner: fix comments so godoc aligns properly.
+* govet: on error continue to the next file (thanks Christopher Wedgwood).
+* html: improved parsing.
+* http: ServeFile handles Range header for partial requests.
+* json: check for invalid UTF-8.
+* ld: allow .o files with no symbols,
+ reading of ELF object files,
+ reading of Mach-O object files.
+* math: change float64 bias constant from 1022 to 1023 (thanks Eoghan Sherry),
+ rename the MinFloat constant to SmallestNonzeroFloat.
+* nm: silently ignore .o files in .a files.
+* os: fix test of RemoveAll.
+* os/inotify: new package (thanks Balazs Lecz).
+* os: make MkdirAll work with symlinks (thanks Ryan Hitchman).
+* regexp: speed up by about 30%; also simplify code for brackets.
+* runtime/linux/386: set FPU to 64-bit precision.
+* runtime: remove paranoid mapping at 0.
+* suffixarray: add Bytes function.
+* syscall: add network interface constants for linux/386, linux/amd64 (thanks Mikio Hara).
+* syscall/windows: restrict access rights param of OpenProcess(),
+ remove \r and \n from error messages (thanks Alex Brainman).
+* test/bench: fixes to timing.sh (thanks Anthony Martin).
+* time: fix bug in Ticker: shutdown using channel rather than memory.
+* token/position: provide FileSet.File, provide files iterator.
+* xml: disallow invalid Unicode code points (thanks Nigel Kerr).
+</pre>
+
+<h3 id="2010-12-08">2010-12-08</h3>
+
+<pre>
+This release includes some package changes. If you use the crypto/tls or
+go/parser packages your code may require changes.
+
+The crypto/tls package's Dial function now takes an additional *Config
+argument. Most uses will pass nil to get the same default behavior as before.
+See the documentation for details:
+ http://golang.org/pkg/crypto/tls/#Config
+ http://golang.org/pkg/crypto/tls/#Dial
+
+The go/parser package's ParseFile function now takes a *token.FileSet as its
+first argument. This is a pointer to a data structure used to store
+position information. If you don't care about position information you
+can pass "token.NewFileSet()". See the documentation for details:
+ http://golang.org/pkg/go/parser/#ParseFile
+
+This release also splits the patent grant text out of the LICENSE file into a
+separate PATENTS file and changes it to be more like the WebM grant.
+These clarifications were made at the request of the Fedora project.
+
+Other changes:
+* [68]l: generate debug info for builtin structured types, prettyprinting in gdb.
+* 8l: add dynimport to import table in Windows PE (thanks Wei Guangjing).
+* 8l, runtime: fix Plan 9 386 build (thanks Yuval Pavel Zholkover).
+* all: fix broken calls to Printf etc.
+* bufio: make Reader.Read implement io.Reader semantics (thanks Roger Peppe).
+* build: allow archiver to be specified by HOST_AR (thanks Albert Strasheim).
+* bytes: add Buffer.UnreadRune, Buffer.UnreadByte (thanks Roger Peppe).
+* crypto/tls: fix build of certificate generation example (thanks Christian Himpel).
+* doc/install: describe GOHOSTOS and GOHOSTARCH.
+* errchk: accept multiple source files (thanks Eoghan Sherry).
+* exec.LookPath: return os.PathError instad of os.ENOENT (thanks Michael Hoisie)..
+* flag: fix format error in boolean error report,
+ handle multiple calls to flag.Parse.
+* fmt: add %U format for standard Unicode representation of code point values.
+* gc: fix method offsets of anonymous interfaces (thanks Eoghan Sherry),
+ skip undefined symbols in import . (thanks Eoghan Sherry).
+* go/scanner: remove Tokenize - was only used in tests
+* gobuilder: add buildroot command-line flag (thanks Devon H. O'Dell).
+* html: unescape numeric entities (thanks Ryan Hitchman).
+* http: Add EncodeQuery, helper for constructing query strings.
+* ld: fix dwarf decoding of 64-bit reflect values (thanks Eoghan Sherry).
+* math: improve accuracy of Exp2 (thanks Eoghan Sherry).
+* runtime: add Goroutines (thanks Keith Rarick).
+* sync: small naming fix for armv5 (thanks Dean Prichard).
+* syscall, net: Add Recvmsg and Sendmsg on Linux (thanks Albert Strasheim).
+* time: make After use fewer goroutines and host processes (thanks Roger Peppe).
+</pre>
+
+<h3 id="2010-12-02">2010-12-02</h3>
+
+<pre>
+Several package changes in this release may require you to update your code if
+you use the bytes, template, or utf8 packages. In all cases, any outdated code
+will fail to compile rather than behave erroneously.
+
+The bytes package has changed. Its Add and AddByte functions have been removed,
+as their functionality is provided by the recently-introduced built-in function
+“append”. Any code that uses them will need to be changed:
+s = bytes.Add(s, b) -> s = append(s, b...)
+s = bytes.AddByte(b, c) -> s = append(s, b)
+s = bytes.Add(nil, c) -> append([]byte(nil), c)
+
+The template package has changed. Your code will need to be updated if it calls
+the HTMLFormatter or StringFormatter functions, or implements its own formatter
+functions. The function signature for formatter types has changed to:
+ func(wr io.Writer, formatter string, data ...interface{})
+to allow multiple arguments to the formatter. No templates will need updating.
+See the change for examples:
+ http://code.google.com/p/go/source/detail?r=2c2be793120e
+
+The template change permits the implementation of multi-word variable
+instantiation for formatters. Before one could say
+ {field}
+or
+ {field|formatter}
+Now one can also say
+ {field1 field2 field3}
+or
+ {field1 field2 field3|formatter}
+and the fields are passed as successive arguments to the formatter,
+by analogy to fmt.Print.
+
+The utf8 package has changed. The order of EncodeRune’s arguments has been
+reversed to satisfy the convention of “destination first”.
+Any code that uses EncodeRune will need to be updated.
+
+Other changes:
+* [68]l: correct dwarf location for globals and ranges for arrays.
+* big: fix (*Rat) SetFrac64(a, b) when b < 0 (thanks Eoghan Sherry).
+* compress/flate: fix typo in comment (thanks Mathieu Lonjaret).
+* crypto/elliptic: use a Jacobian transform for better performance.
+* doc/code.html: fix reference to "gomake build" (thanks Anschel Schaffer-Cohen).
+* doc/roadmap: update gdb status.
+* doc/spec: fixed some omissions and type errors.
+* doc: some typo fixes (thanks Peter Mundy).
+* exp/eval: build fix for parser.ParseFile API change (thanks Anschel Schaffer-Cohen).
+* fmt: Scan accepts Inf and NaN,
+ allow "% X" as well as "% x".
+* go/printer: preserve newlines in func parameter lists (thanks Jamie Gennis).
+* http: consume request body before next request.
+* log: ensure writes are atomic (thanks Roger Peppe).
+* path: Windows support for Split (thanks Benny Siegert).
+* runtime: fix SysFree to really free memory on Windows (thanks Alex Brainman),
+ parallel definitions in Go for all C structs.
+* sort: avoid overflow in pivot calculation,
+ reduced stack depth to lg(n) in quickSort (thanks Stefan Nilsson).
+* strconv: Atof on Infs and NaNs.
+</pre>
+
+<h3 id="2010-11-23">2010-11-23</h3>
+
+<pre>
+This release includes a backwards-incompatible package change to the
+sort.Search function (introduced in the last release).
+See the change for details and examples of how you might change your code:
+ http://code.google.com/p/go/source/detail?r=102866c369
+
+* build: automatically #define _64BIT in 6c.
+* cgo: print required space after parameter name in wrapper function.
+* crypto/cipher: new package to replace crypto/block (thanks Adam Langley).
+* crypto/elliptic: new package, implements elliptic curves over prime fields (thanks Adam Langley).
+* crypto/x509: policy OID support and fixes (thanks Adam Langley).
+* doc: add link to codewalks,
+ fix recover() documentation (thanks Anschel Schaffer-Cohen),
+ explain how to write Makefiles for commands.
+* exec: enable more tests on windows (thanks Alex Brainman).
+* gc: adjustable hash code in typecheck of composite literals
+ (thanks to vskrap, Andrey Mirtchovski, and Eoghan Sherry).
+* gc: better error message for bad type in channel send (thanks Anthony Martin).
+* godoc: bug fix in relativePath,
+ compute search index for all file systems under godoc's observation,
+ use correct time stamp to indicate accuracy of search result.
+* index/suffixarray: use sort.Search.
+* net: add ReadFrom and WriteTo windows version (thanks Wei Guangjing).
+* reflect: remove unnecessary casts in Get methods.
+* rpc: add RegisterName to allow override of default type name.
+* runtime: free memory allocated by windows CommandLineToArgv (thanks Alex Brainman).
+* sort: simplify Search (thanks Roger Peppe).
+* strings: add LastIndexAny (thanks Benny Siegert).
+</pre>
+
+<h3 id="2010-11-10">2010-11-10</h3>
+
+<pre>
+The birthday release includes a new Search capability inside the sort package.
+It takes an unusual but very general and easy-to-use approach to searching
+arbitrary indexable sorted data. See the documentation for details:
+ http://golang.org/pkg/sort/#Search
+
+The ARM port now uses the hardware floating point unit (VFP). It still has a
+few bugs, mostly around conversions between unsigned integer and floating-point
+values, but it's stabilizing.
+
+In addition, there have been many smaller fixes and updates:
+
+* 6l: generate dwarf variable names with disambiguating suffix.
+* container/list: make Remove return Value of removed element.
+ makes it easier to remove first or last item.
+* crypto: add cast5 (default PGP cipher),
+ switch block cipher methods to be destination first.
+* crypto/tls: use pool building for certificate checking
+* go/ast: change embedded token.Position fields to named fields
+ (preparation for a different position representation)
+* net: provide public access to file descriptors (thanks Keith Rarick)
+* os: add Expand function to evaluate environment variables.
+* path: add Glob (thanks Benny Siegert)
+* runtime: memequal optimization (thanks Graham Miller)
+ prefix all external symbols with "runtime·" to avoid
+ conflicts linking with external C libraries.
+</pre>
+
+<h3 id="2010-11-02">2010-11-02</h3>
+
+<pre>
+This release includes a language change: the new built-in function, append.
+Append makes growing slices much simpler. See the spec for details:
+ http://golang.org/doc/go_spec.html#Appending_and_copying_slices
+
+Other changes:
+* 8l: pe generation fixes (thanks Alex Brainman).
+* doc: Effective Go: append and a few words about "..." args.
+* build: fiddle with make variables.
+* codereview: fix sync and download in Python 2.7 (thanks Fazlul Shahriar).
+* debug/pe, cgo: add windows support (thanks Wei Guangjing <vcc.163@gmail.com>).
+* go/ast: add Inspect function for easy AST inspection w/o a visitor.
+* go/printer: do not remove parens around composite literals starting with
+ a type name in control clauses.
+* go/scanner: bug fixes, revisions, and more tests.
+* gob: several fixes and documentation updates.
+* godoc: bug fix (bug introduced with revision 3ee58453e961).
+* gotest: print empty benchmark list in a way that gofmt will leave alone.
+* http server: correctly respond with 304 NotModified (thanks Michael Hoisie).
+* kate: update list of builtins (thanks Evan Shaw).
+* libutf: update to Unicode 5.2.0 to match pkg/unicode (thanks Anthony Martin).
+* misc/bbedit: update list of builtins (thanks Anthony Starks).
+* misc/vim: update list of builtins.
+* mkrunetype: install a Makefile and tweak it slightly so it can be built.
+* netchan: fix locking bug.
+* pidigits: minor improvements (thanks Evan Shaw).
+* rpc: fix client deadlock bug.
+* src: use append where appropriate (often instead of vector).
+* strings: add Contains helper function (thanks Brad Fitzpatrick).
+* syscall: SIO constants for Linux (thanks Albert Strasheim),
+ Stat(path) on windows (thanks Alex Brainman).
+* test/ken/convert.go: add conversion torture test.
+* testing: add Benchmark (thanks Roger Peppe).
+</pre>
+
+<h3 id="2010-10-27">2010-10-27</h3>
+
+<pre>
+*** This release changes the encoding used by package gob.
+ If you store gobs on disk, see below. ***
+
+The ARM port (5g) now passes all tests. The optimizer is not yet enabled, and
+floating point arithmetic is performed entirely in software. Work is underway
+to address both of these deficiencies.
+
+The syntax for arrays, slices, and maps of composite literals has been
+simplified. Within a composite literal of array, slice, or map type, elements
+that are themselves composite literals may elide the type if it is identical to
+the outer literal’s element type. For example, these expressions:
+ [][]int{[]int{1, 2, 3}, []int{4, 5}}
+ map[string]Point{“x”: Point{1.5, -3.5}, “y”: Point{0, 0}}
+can be simplified to:
+ [][]int{{1, 2, 3}, {4, 5}}
+ map[string]Point{“x”: {1.5, -3.5}, “y”: {0, 0}}
+Gofmt can make these simplifications mechanically when invoked with the
+new -s flag.
+
+The built-in copy function can now copy bytes from a string value to a []byte.
+Code like this (for []byte b and string s):
+ for i := 0; i < len(s); i++ {
+ b[i] = s[i]
+ }
+can be rewritten as:
+ copy(b, s)
+
+The gob package can now encode and decode interface values containing types
+registered ahead of time with the new Register function. These changes required
+a backwards-incompatible change to the wire format. Data written with the old
+version of the package will not be readable with the new one, and vice versa.
+(Steps were made in this change to make sure this doesn’t happen again.)
+We don’t know of anyone using gobs to create permanent data, but if you do this
+and need help converting, please let us know, and do not update to this release
+yet. We will help you convert your data.
+
+Other changes:
+* 5g, 6g, 8g: generate code for string index instead of calling function.
+* 5l, 6l, 8l: introduce sub-symbols.
+* 6l/8l: global and local variables and type info.
+* Make.inc: delete unnecessary -fno-inline flag to quietgcc.
+* arm: precise float64 software floating point, bug fixes.
+* big: arm assembly, faster software mulWW, divWW.
+* build: only print "You need to add foo to PATH" when needed.
+* container/list: fix Remove bug and use pointer to self as identifier.
+* doc: show page title in browser title bar,
+ update roadmap.
+* encoding/binary: give LittleEndian, BigEndian specific types.
+* go/parser: consume auto-inserted semi when calling ParseExpr().
+* gobuilder: pass GOHOSTOS and GOHOSTARCH to build,
+ write build and benchmarking logs to disk.
+* goinstall: display helpful message when encountering a cgo package,
+ fix test for multiple package names (thanks Fazlul Shahriar).
+* gotest: generate correct gofmt-formatted _testmain.go.
+* image/png: speed up paletted encoding ~25% (thanks Brad Fitzpatrick).
+* misc: update python scripts to specify python2 as python3 is now "python".
+* net: fix comment on Dial to mention unix/unixgram.
+* rpc: expose Server type to allow multiple RPC Server instances.
+* runtime: print unknown types in panic.
+* spec: append built-in (not yet implemented).
+* src: gofmt -s -w src misc.
+ update code to use copy-from-string.
+* test/bench: update numbers.
+* websocket: fix short Read.
+</pre>
+
+<h3 id="2010-10-20">2010-10-20</h3>
+
+<pre>
+This release removes the log package's deprecated functions.
+Code that has not been updated to use the new interface will break.
+See the previous release notes for details:
+ http://golang.org/doc/devel/release.html#2010-10-13
+
+Also included are major improvements to the linker. It is now faster,
+uses less memory, and more parallelizable (but not yet parallel).
+
+The nntp package has been removed from the standard library.
+Its new home is the nntp-go project at Google Code:
+ http://code.google.com/p/nntp-go
+You can install it with goinstall:
+ goinstall nntp-go.googlecode.com/hg/nntp
+And import it in your code like so:
+ import "nntp-go.googlecode.com/hg/nntp"
+
+Other changes:
+* 6g: avoid too-large immediate constants.
+* 8l, runtime: initial support for Plan 9 (thanks Yuval Pavel Zholkover).
+* 6l, 8l: more improvements on exporting debug information (DWARF).
+* arm: code gen fixes. Most tests now pass, except for floating point code.
+* big: add random number generation (thanks Florian Uekermann).
+* gc: keep track of real actual type of identifiers,
+ report that shift must be unsigned integer,
+ select receive with implicit conversion.
+* goplay: fix to run under windows (thanks Yasuhiro Matsumoto).
+* http: do not close connection after sending HTTP/1.0 request.
+* netchan: add new method Hangup to terminate transmission on a channel.
+* os: change TestForkExec so it can run on windows (thanks Yasuhiro Matsumoto).
+* runtime: don't let select split stack.
+* syscall/arm: correct 64-bit system call arguments.
+</pre>
+
+<h3 id="2010-10-13">2010-10-13</h3>
+
+<pre>
+This release includes changes to the log package, the removal of exp/iterable,
+two new tools (gotry and goplay), one small language change, and many other
+changes and fixes. If you use the log or iterable packages, you need to make
+changes to your code.
+
+The log package has changed. Loggers now have only one output, and output to
+standard error by default. The names have also changed, although the old names
+are still supported. They will be deleted in the next release, though, so it
+would be good to update now if you can. For most purposes all you need to do
+is make these substitutions:
+ log.Stderr -> log.Println or log.Print
+ log.Stderrf -> log.Printf
+ log.Crash -> log.Panicln or log.Panic
+ log.Crashf -> log.Panicf
+ log.Exit -> log.Exitln or log.Exit
+ log.Exitf -> log.Exitf (no change)
+Calls to log.New() must drop the second argument.
+Also, custom loggers with exit or panic properties will need to be reworked.
+For full details, see the change description:
+ http://code.google.com/p/go/source/detail?r=d8a3c7563d
+
+The language change is that uses of pointers to interface values no longer
+automatically dereference the pointer. A pointer to an interface value is more
+often a beginner’s bug than correct code.
+
+The package exp/iterable has been removed. It was an interesting experiment,
+but it encourages writing inefficient code and has outlived its utility.
+
+The new tools:
+* gotry: an exercise in reflection and an unusual tool. Run 'gotry' for details.
+* goplay: a stand-alone version of the Go Playground. See misc/goplay.
+
+Other changes:
+* 6l: Mach-O fixes, and fix to work with OS X nm/otool (thanks Jim McGrath).
+* [568]a: correct line numbers for statements.
+* arm: code generation and runtime fixes,
+ adjust recover for new reflect.call,
+ enable 6 more tests after net fix.
+* big: fix panic and round correctly in Rat.FloatString (thanks Anthony Martin).
+* build: Make.cmd: remove $(OFILES) (thanks Eric Clark),
+ Make.pkg: remove .so before installing new one,
+ add GOHOSTOS and GOHOSTARCH environment variables.
+* crypto/tls: better error messages for certificate issues,
+ make SetReadTimeout work.
+* doc: add Sydney University video,
+ add The Expressiveness of Go talk.
+* exp/draw/x11: support X11 vendors other than "The X.Org Foundation".
+* expvar: add (*Int).Set (thanks Sam Thorogood).
+* fmt: add Errorf helper function,
+ allow %d on []byte.
+* gc: O(1) string comparison when lengths differ,
+ various bug fixes.
+* http: return the correct error if a header line is too long.
+* image: add image.Tiled type, the Go equivalent of Plan 9's repl bit.
+* ld: be less picky about bad line number info.
+* misc/cgo/life: fix for new slice rules (thanks Graham Miller).
+* net: allow _ in DNS names.
+* netchan: export before import when testing, and
+ zero out request to ensure correct gob decoding. (thanks Roger Peppe).
+* os: make tests work on windows (thanks Alex Brainman).
+* runtime: bug fix: serialize mcache allocation,
+ correct iteration of large map values,
+ faster strequal, memequal (thanks Graham Miller),
+ fix argument dump in traceback,
+ fix tiny build.
+* smtp: new package (thanks Evan Shaw).
+* syscall: add sockaddr_ll support for linux/386, linux/amd64 (thanks Mikio Hara),
+ add ucred structure for SCM_CREDENTIALS over UNIX sockets. (thanks Albert Strasheim).
+* syscall: implement WaitStatus and Wait4() for windows (thanks Wei Guangjing).
+* time: add After.
+* websocket: enable tests on windows (thanks Alex Brainman).
+</pre>
+
+<h3 id="2010-09-29">2010-09-29</h3>
+
+<pre>
+This release includes some minor language changes and some significant package
+changes. You may need to change your code if you use ...T parameters or the
+http package.
+
+The semantics and syntax of forwarding ...T parameters have changed.
+ func message(f string, s ...interface{}) { fmt.Printf(f, s) }
+Here, s has type []interface{} and contains the parameters passed to message.
+Before this language change, the compiler recognized when a function call
+passed a ... parameter to another ... parameter of the same type, and just
+passed it as though it was a list of arguments. But this meant that you
+couldn't control whether to pass the slice as a single argument and you
+couldn't pass a regular slice as a ... parameter, which can be handy. This
+change gives you that control at the cost of a few characters in the call.
+If you want the promotion to ..., append ... to the argument:
+ func message(f string, s ...interface{}) { fmt.Printf(f, s...) }
+Without the ..., s would be passed to Printf as a single argument of type
+[]interface{}. The bad news is you might need to fix up some of your code,
+but the compiler will detect the situation and warn you.
+
+Also, the http.Handler and http.HandlerFunc types have changed. Where http
+handler functions previously accepted an *http.Conn, they now take an interface
+type http.ResponseWriter. ResponseWriter implements the same methods as *Conn,
+so in most cases the only change required will be changing the type signature
+of your handler function's first parameter. See:
+ http://golang.org/pkg/http/#Handler
+
+The utf8 package has a new type, String, that provides efficient indexing
+into utf8 strings by rune (previously an expensive conversion to []int
+was required). See:
+ http://golang.org/pkg/utf8/#String
+
+The compiler will now automatically insert a semicolon at the end of a file if
+one is not found. This effect of this is that Go source files are no longer
+required to have a trailing newline.
+
+Other changes:
+* 6prof: more accurate usage message.
+* archive/zip: new package for reading Zip files.
+* arm: fix code generation, 10 more package tests pass.
+* asn1: make interface consistent with json.
+* bufio.UnreadRune: fix bug at EOF.
+* build: clear custom variables like GREP_OPTIONS,
+ silence warnings generated by ubuntu gcc,
+ use full path when compiling libraries.
+* bytes, strings: change lastIndexFunc to use DecodeLastRune (thanks Roger Peppe).
+* doc: add to and consolidate non-english doc references,
+ consolidate FAQs into a single file, go_faq.html,
+ updates for new http interface.
+* fmt/Printf: document and tweak error messages produced for bad formats.
+* gc: allow select case expr = <-c,
+ eliminate duplicates in method table,
+ fix reflect table method receiver,
+ improve error message for x \= 0.
+* go/scanner: treat EOF like a newline for purposes of semicolon insertion.
+* gofmt: stability improvements.
+* gotest: leave _testmain.go for "make clean" to clean up.
+* http: correct escaping of different parts of URL,
+ support HTTP/1.0 Keep-Alive.
+* json: do not write to unexported fields.
+* libcgo: don't build for NaCl,
+ set g, m in thread local storage for windows 386 (thanks Wei Guangjing).
+* math: Fix off-by-one error in Ilogb and Logb. (thanks Charles L. Dorian).
+* misc/dashboard/builder: remove build files after benchmarking.
+* nacl: update instructions for new SDK.
+* net: enable v4-over-v6 on ip sockets,
+ fix crash in DialIP.
+* os: check for valid arguments in windows Readdir (thanks Peter Mundy).
+* runtime: add mmap of null page just in case,
+ correct stats in SysFree,
+ fix unwindstack crash.
+* syscall: add IPPROTO_IPV6 and IPV6_V6ONLY const to fix nacl and windows build,
+ add inotify on Linux (thanks Balazs Lecz),
+ fix socketpair in syscall_bsd,
+ fix windows value of IPV6_V6ONLY (thanks Alex Brainman),
+ implement windows version of Utimes (thanks Alex Brainman),
+ make mkall.sh work for nacl.
+* test: Add test that causes incorrect error from gccgo.
+* utf8: add DecodeLastRune and DecodeLastRuneInString (thanks Roger Peppe).
+* xml: Allow entities inside CDATA tags (thanks Dan Sinclair).
+</pre>
+
+<h3 id="2010-09-22">2010-09-22</h3>
+
+<pre>
+This release includes new package functionality, and many bug fixes and changes.
+It also improves support for the arm and nacl platforms.
+
+* 5l: avoid fixed buffers in list.
+* 6l, 8l: clean up ELF code, fix NaCl.
+* 6l/8l: emit DWARF frame info.
+* Make.inc: make GOOS detection work on windows (thanks Alex Brainman).
+* build: fixes for native arn build,
+ make all.bash run on Ubuntu ARM.
+* cgo: bug fixes,
+ show preamble gcc errors (thanks Eric Clark).
+* crypto/x509, crypto/tls: improve root matching and observe CA flag.
+* crypto: Fix certificate validation.
+* doc: variable-width layout.
+* env.bash: fix building in directory with spaces in the path (thanks Alex Brainman).
+* exp/4s, exp/nacl/av: sync to recent exp/draw changes.
+* exp/draw/x11: mouse location is a signed integer.
+* exp/nacl/av: update color to max out at 1<<16-1 instead of 1<<32-1.
+* fmt: support '*' for width or precision (thanks Anthony Martin).
+* gc: improvements to static initialization,
+ make sure path names are canonical.
+* gob: make robust when decoding a struct with non-struct data.
+* gobuilder: add -cmd for user-specified build command,
+ add -rev= flag to build specific revision and exit,
+ fix bug that caused old revisions to be rebuilt.
+* godoc: change default filter file name to "",
+ don't use quadratic algorithm to filter paths,
+ show "Last update" info for directory listings.
+* http: new redirect test,
+ URLEscape now escapes all reserved characters as per the RFC.
+* nacl: fix zero-length writes.
+* net/dict: parse response correctly (thanks Fazlul Shahriar).
+* netchan: add a cross-connect test,
+ handle closing of channels,
+ provide a method (Importer.Errors()) to recover protocol errors.
+* os: make Open() O_APPEND flag work on windows (thanks Alex Brainman),
+ make RemoveAll() work on windows (thanks Alex Brainman).
+* pkg/Makefile: disable netchan test to fix windows build (thanks Alex Brainman).
+* regexp: delete Iter methods.
+* runtime: better panic for send to nil channel.
+* strings: fix minor bug in LastIndexFunc (thanks Roger Peppe).
+* suffixarray: a package for creating suffixarray-based indexes.
+* syscall: Use vsyscall for syscall.Gettimeofday and .Time on linux amd64.
+* test: fix NaCl build.
+* windows: fix netchan test by using 127.0.0.1.
+</pre>
+
+<h3 id="2010-09-15">2010-09-15</h3>
+
+<pre>
+This release includes a language change: the lower bound of a subslice may
+now be omitted, in which case the value will default to 0.
+For example, s[0:10] may now be written as s[:10], and s[0:] as s[:].
+
+The release also includes important bug fixes for the ARM architecture,
+as well as the following fixes and changes:
+
+* 5g: register allocation bugs
+* 6c, 8c: show line numbers in -S output
+* 6g, 6l, 8g, 8l: move read-only data to text segment
+* 6l, 8l: make etext accurate; introduce rodata, erodata.
+* arm: fix build bugs.
+ make libcgo build during OS X cross-compile
+ remove reference to deleted file syntax/slice.go
+ use the correct stat syscalls
+ work around reg allocator bug in 5g
+* bufio: add UnreadRune.
+* build: avoid bad environment interactions
+ fix build for tiny
+ generate, clean .exe files on Windows (thanks Joe Poirier)
+ test for _WIN32, not _MINGW32 (thanks Joe Poirier)
+ work with GNU Make 3.82 (thanks Jukka-Pekka Kekkonen)
+* cgo: add typedef for uintptr in generated headers
+ silence warning for C call returning const pointer
+* codereview: convert email address to lower case before checking CONTRIBUTORS
+* crypto/tls: don't return an error from Close()
+* doc/tutorial: update for slice changes.
+* exec: separate LookPath implementations for unix/windows (thanks Joe Poirier)
+* exp/draw/x11: allow clean shutdown when the user closes the window.
+* exp/draw: clip destination rectangle to the image bounds.
+ fast path for drawing overlapping image.RGBAs.
+ fix double-counting of pt.Min for the src and mask points.
+ reintroduce the MouseEvent.Nsec timestamp.
+ rename Context to Window, and add a Close method.
+* exp/debug: preliminary support for 'copy' function (thanks Sebastien Binet)
+* fmt.Fscan: use UnreadRune to preserve data across calls.
+* gc: better printing of named constants, func literals in errors
+ many bug fixes
+ fix line number printing with //line directives
+ fix symbol table generation on windows (thanks Alex Brainman)
+ implement comparison rule from spec change 33abb649cb63
+ implement new slice spec (thanks Scott Lawrence)
+ make string x + y + z + ... + w efficient
+ more accurate line numbers for ATEXT
+ remove &[10]int -> []int conversion
+* go-mode.el: fix highlighting for 'chan' type (thanks Scott Lawrence)
+* godoc: better support for directory trees for user-supplied paths
+ use correct delay time (bug fix)
+* gofmt, go/printer: update internal estimated position correctly
+* goinstall: warn when package name starts with http:// (thanks Scott Lawrence)
+* http: check https certificate against host name
+ do not cache CanonicalHeaderKey (thanks Jukka-Pekka Kekkonen)
+* image: change a ColorImage's minimum point from (0, 0) to (-1e9, -1e9).
+ introduce Intersect and Union rectangle methods.
+* ld: handle quoted spaces in package path (thanks Dan Sinclair)
+* libcgo: fix NaCl build.
+* libmach: fix build on arm host
+ fix new thread race with Linux
+* math: make portable Tan(Pi/2) return NaN
+* misc/dashboard/builder: gobuilder, a continuous build client
+* net: disable tests for functions not available on windows (thanks Alex Brainman)
+* netchan: make -1 unlimited, as advertised.
+* os, exec: rename argv0 to name
+* path: add IsAbs (thanks Ivan Krasin)
+* runtime: fix bug in tracebacks
+ fix crash trace on amd64
+ fix windows build (thanks Alex Brainman)
+ use manual stack for garbage collection
+* spec: add examples for slices with omitted index expressions.
+ allow omission of low slice bound (thanks Scott Lawrence)
+* syscall: fix windows Gettimeofday (thanks Alex Brainman)
+* test(arm): disable zerodivide.go because compilation fails.
+* test(windows): disable tests that cause the build to fail (thanks Joe Poirier)
+* test/garbage/parser: sync with recent parser changes
+* test: Add test for //line
+ Make gccgo believe that the variables can change.
+ Recognize gccgo error messages.
+ Reduce race conditions in chan/nonblock.go.
+ Run garbage collector before testing malloc numbers.
+* websocket: Add support for secure WebSockets (thanks Jukka-Pekka Kekkonen)
+* windows: disable unimplemented tests (thanks Joe Poirier)
+</pre>
+
+<h3 id="2010-09-06">2010-09-06</h3>
+
+<pre>
+This release includes the syntactic modernization of more than 100 files in /test,
+and these additions, changes, and fixes:
+* 6l/8l: emit DWARF in macho.
+* 8g: use FCHS, not FMUL, for minus float.
+* 8l: emit DWARF in ELF,
+ suppress emitting DWARF in Windows PE (thanks Alex Brainman).
+* big: added RatString, some simplifications.
+* build: create bin and pkg directories as needed; drop from hg,
+ delete Make.386 Make.amd64 Make.arm (obsoleted by Make.inc),
+ fix cgo with -j2,
+ let pkg/Makefile coordinate building of Go commands,
+ never use quietgcc in Make.pkg,
+ remove more references to GOBIN and GOROOT (thanks Christian Himpel).
+* codereview: Fix uploading for Mercurial 1.6.3 (thanks Evan Shaw),
+ consistent indent, cut dead code,
+ fix hang on standard hg commands,
+ print status when tasks take longer than 30 seconds,
+ really disable codereview when not available,
+ upload files in parallel (5x improvement on large CLs).
+* crypto/hmac: make Sum idempotent (thanks Jukka-Pekka Kekkonen).
+* doc: add links to more German docs,
+ add round-robin flag to io2010 balance example,
+ fix a bug in the example in Constants subsection (thanks James Fysh),
+ various changes for validating HTML (thanks Scott Lawrence).
+* fmt: delete erroneous sentence about return value for Sprint*.
+* gc: appease bison version running on FreeBSD builder,
+ fix spurious syntax error.
+* go/doc: use correct escaper for URL.
+* go/printer: align ImportPaths in ImportDecls (thanks Scott Lawrence).
+* go/typechecker: 2nd step towards augmenting AST with full type information.
+* gofmt: permit omission of first index in slice expression.
+* goinstall: added -a flag to mean "all remote packages" (thanks Scott Lawrence),
+ assume go binaries are in path (following new convention),
+ use https for Google Code checkouts.
+* gotest: allow make test of cgo packages (without make install).
+* http: add Date to server, Last-Modified and If-Modified-Since to file server,
+ add PostForm function to post url-encoded key/value data,
+ obscure passwords in return value of URL.String (thanks Scott Lawrence).
+* image: introduce Config type and DecodeConfig function.
+* libcgo: update Makefile to use Make.inc.
+* list: update comment to state that the zero value is ready to use.
+* math: amd64 version of Sincos (thanks Charles L. Dorian).
+* misc/bash: add *.go completion for gofmt (thanks Scott Lawrence).
+* misc/emacs: make _ a word symbol (thanks Scott Lawrence).
+* misc: add zsh completion (using compctl),
+ syntax highlighting for Fraise.app (OS X) (thanks Vincent Ambo).
+* net/textproto: Handle multi-line responses (thanks Evan Shaw).
+* net: add LookupMX (thanks Corey Thomasson).
+* netchan: Fix race condition in test,
+ rather than 0, make -1 mean infinite (a la strings.Split et al),
+ use acknowledgements on export send.
+ new methods Sync and Drain for clean teardown.
+* regexp: interpret all Go characer escapes \a \b \f \n \r \t \v.
+* rpc: fix bug that caused private methods to attempt to be registered.
+* runtime: Correct commonType.kind values to match compiler,
+ add GOOS, GOARCH; fix FuncLine,
+ special case copy, equal for one-word interface values (thanks Kyle Consalus).
+* scanner: fix incorrect reporting of error in Next (thanks Kyle Consalus).
+* spec: clarify that arrays must be addressable to be sliceable.
+* template: fix space handling around actions.
+* test/solitaire: an exercise in backtracking and string conversions.
+* test: Recognize gccgo error messages and other fixes.
+* time: do not crash in String on nil Time.
+* tutorial: regenerate HTML to pick up change to progs/file.go.
+* websocket: fix missing Sec-WebSocket-Protocol on server response (thanks Jukka-Pekka Kekkonen).
+</pre>
+
+<h3 id="2010-08-25">2010-08-25</h3>
+
+<pre>
+This release includes changes to the build system that will likely require you
+to make changes to your environment variables and Makefiles.
+
+All environment variables are now optional:
+ - $GOOS and $GOARCH are now optional; their values should now be inferred
+ automatically by the build system,
+ - $GOROOT is now optional, but if you choose not to set it you must run
+ 'gomake' instead of 'make' or 'gmake' when developing Go programs
+ using the conventional Makefiles,
+ - $GOBIN remains optional and now defaults to $GOROOT/bin;
+ if you wish to use this new default, make sure it is in your $PATH
+ and that you have removed the existing binaries from $HOME/bin.
+
+As a result of these changes, the Go Makefiles have changed. If your Makefiles
+inherit from the Go Makefiles, you must change this line:
+ include ../../Make.$(GOARCH)
+to this:
+ include ../../Make.inc
+
+This release also removes the deprecated functions in regexp and the
+once package. Any code that still uses them will break.
+See the notes from the last release for details:
+ http://golang.org/doc/devel/release.html#2010-08-11
+
+Other changes:
+* 6g: better registerization for slices, strings, interface values
+* 6l: line number information in DWARF format
+* build: $GOBIN defaults to $GOROOT/bin,
+ no required environment variables
+* cgo: add C.GoStringN (thanks Eric Clark).
+* codereview: fix issues with leading tabs in CL descriptions,
+ do not send "Abandoned" mail if the CL has not been mailed.
+* crypto/ocsp: add missing Makefile.
+* crypto/tls: client certificate support (thanks Mikkel Krautz).
+* doc: update gccgo information for recent changes.
+ fix errors in Effective Go.
+* fmt/print: give %p priority, analogous to %T,
+ honor Formatter in Print, Println.
+* gc: fix parenthesization check.
+* go/ast: facility for printing AST nodes,
+ first step towards augmenting AST with full type information.
+* go/printer: do not modify tabwriter.Escape'd text.
+* gofmt: do not modify multi-line string literals,
+ print AST nodes by setting -ast flag.
+* http: fix typo in http.Request documentation (thanks Scott Lawrence)
+ parse query string always, not just in GET
+* image/png: support 16-bit color.
+* io: ReadAtLeast now errors if min > len(buf).
+* jsonrpc: use `error: null` for success, not `error: ""`.
+* libmach: implement register fetch for 32-bit x86 kernel.
+* net: make IPv6 String method standards-compliant (thanks Mikio Hara).
+* os: FileInfo.Permission() now returns uint32 (thanks Scott Lawrence),
+ implement env using native Windows API (thanks Alex Brainman).
+* reflect: allow PtrValue.PointTo(nil).
+* runtime: correct line numbers for .goc files,
+ fix another stack split bug,
+ fix freebsd/386 mmap.
+* syscall: regenerate syscall/z* files for linux/386, linux/amd64, linux/arm.
+* tabwriter: Introduce a new flag StripEscape.
+* template: fix handling of space around actions,
+ vars preceded by white space parse correctly (thanks Roger Peppe).
+* test: add test case that crashes gccgo.
+* time: parse no longer requires minutes for time zone (thanks Jan H. Hosang)
+* yacc: fix bounds check in error recovery.
+</pre>
+
+<h3 id="2010-08-11">2010-08-11</h3>
+
+<pre>
+This release introduces some package changes. You may need to change your
+code if you use the once, regexp, image, or exp/draw packages.
+
+The type Once has been added to the sync package. The new sync.Once will
+supersede the functionality provided by the once package. We intend to remove
+the once package after this release. See:
+ http://golang.org/pkg/sync/#Once
+All instances of once in the standard library have been replaced with
+sync.Once. Reviewing these changes may help you modify your existing code.
+The relevant changeset:
+ http://code.google.com/p/go/source/detail?r=fa2c43595119
+
+A new set of methods has been added to the regular expression package, regexp.
+These provide a uniformly named approach to discovering the matches of an
+expression within a piece of text; see the package documentation for details:
+ http://golang.org/pkg/regexp/
+These new methods will, in a later release, replace the old methods for
+matching substrings. The following methods are deprecated:
+ Execute (use FindSubmatchIndex)
+ ExecuteString (use FindStringSubmatchIndex)
+ MatchStrings(use FindStringSubmatch)
+ MatchSlices (use FindSubmatch)
+ AllMatches (use FindAll; note that n<0 means 'all matches'; was n<=0)
+ AllMatchesString (use FindAllString; note that n<0 means 'all matches'; was n<=0)
+(Plus there are ten new methods you didn't know you wanted.)
+Please update your code to use the new routines before the next release.
+
+An image.Image now has a Bounds rectangle, where previously it ranged
+from (0, 0) to (Width, Height). Loops that previously looked like:
+ for y := 0; y < img.Height(); y++ {
+ for x := 0; x < img.Width(); x++ {
+ // Do something with img.At(x, y)
+ }
+ }
+should instead be:
+ b := img.Bounds()
+ for y := b.Min.Y; y < b.Max.Y; y++ {
+ for x := b.Min.X; x < b.Max.X; x++ {
+ // Do something with img.At(x, y)
+ }
+ }
+The Point and Rectangle types have also moved from exp/draw to image.
+
+Other changes:
+* arm: bugfixes and syscall (thanks Kai Backman).
+* asn1: fix incorrect encoding of signed integers (thanks Nicholas Waples).
+* big: fixes to bitwise functions (thanks Evan Shaw).
+* bytes: add IndexRune, FieldsFunc and To*Special (thanks Christian Himpel).
+* encoding/binary: add complex (thanks Roger Peppe).
+* exp/iterable: add UintArray (thanks Anschel Schaffer-Cohen).
+* godoc: report Status 404 if a pkg or file is not found.
+* gofmt: better reporting for unexpected semicolon errors.
+* html: new package, an HTML tokenizer.
+* image: change image representation from slice-of-slices to linear buffer,
+ introduce Decode and RegisterFormat,
+ introduce Transparent and Opaque,
+ replace Width and Height by Bounds, add the Point and Rect types.
+* libbio: fix Bprint to address 6g issues with large data structures.
+* math: fix amd64 Hypot (thanks Charles L. Dorian).
+* net/textproto: new package, with example net/dict.
+* os: fix ForkExec() handling of envv == nil (thanks Alex Brainman).
+* png: grayscale support (thanks Mathieu Lonjaret).
+* regexp: document that backslashes are the escape character.
+* rpc: catch errors from ReadResponseBody.
+* runtime: memory free fix (thanks Alex Brainman).
+* template: add ParseFile method to template.Template.
+* test/peano: use directly recursive type def.
+</pre>
+
+<h3 id="2010-08-04">2010-08-04</h3>
+
+<pre>
+This release includes a change to os.Open (and co.). The file permission
+argument has been changed to a uint32. Your code may require changes - a simple
+conversion operation at most.
+
+Other changes:
+* amd64: use segment memory for thread-local storage.
+* arm: add gdb support to android launcher script,
+ bugfixes (stack clobbering, indices),
+ disable another flaky test,
+ remove old qemu dependency from gotest.
+* bufio: introduce Peek.
+* bytes: added test case for explode with blank string (thanks Scott Lawrence).
+* cgo: correct multiple return value function invocations (thanks Christian Himpel).
+* crypto/x509: unwrap Subject Key Identifier (thanks Adam Langley).
+* gc: index bounds tests and other fixes.
+* gofmt/go/parser: strengthen syntax checks.
+* goinstall: check for error from exec.*Cmd.Wait() (thanks Alex Brainman).
+* image/png: use image-specific methods for checking opacity.
+* image: introduce Gray and Gray16 types,
+ remove the named colors except for Black and White.
+* json: object members must have a value (thanks Anthony Martin).
+* misc/vim: highlight misspelled words only in comments (thanks Christian Himpel).
+* os: Null device (thanks Peter Mundy).
+* runtime: do not fall through in SIGBUS/SIGSEGV.
+* strings: fix Split("", "", -1) (thanks Scott Lawrence).
+* syscall: make go errors not clash with windows errors (thanks Alex Brainman).
+* test/run: diff old new,
+* websocket: correct challenge response (thanks Tarmigan Casebolt),
+ fix bug involving spaces in header keys (thanks Bill Neubauer).
+</pre>
+
+<h3 id="2010-07-29">2010-07-29</h3>
+
+<pre>
+* 5g: more soft float support and several bugfixes.
+* asn1: Enumerated, Flag and GeneralizedTime support.
+* build: clean.bash to check that GOOS and GOARCH are set.
+* bytes: add IndexFunc and LastIndexFunc (thanks Fazlul Shahriar),
+ add Title.
+* cgo: If CC is set in environment, use it rather than "gcc",
+ use new command line syntax: -- separates cgo flags from gcc flags.
+* codereview: avoid crash if no config,
+ don't run gofmt with an empty file list,
+ make 'hg submit' work with Mercurial 1.6.
+* crypto/ocsp: add package to parse OCSP responses.
+* crypto/tls: add client-side SNI support and PeerCertificates.
+* exp/bignum: delete package - functionality subsumed by package big.
+* fmt.Print: fix bug in placement of spaces introduced when ...T went in.
+* fmt.Scanf: handle trailing spaces.
+* gc: fix smaller-than-pointer-sized receivers in interfaces,
+ floating point precision/normalization fixes,
+ graceful exit on seg fault,
+ import dot shadowing bug,
+ many fixes including better handling of invalid input,
+ print error detail about failure to open import.
+* gccgo_install.html: add description of the port to RTEMS (thanks Vinu Rajashekhar).
+* gobs: fix bug in singleton arrays.
+* godoc: display synopses for all packages that have some kind of documentation..
+* gofmt: fix some linebreak issues.
+* http: add https client support (thanks Fazlul Shahriar),
+ write body when content length unknown (thanks James Whitehead).
+* io: MultiReader and MultiWriter (thanks Brad Fitzpatrick),
+ fix another race condition in Pipes.
+* ld: many fixes including better handling of invalid input.
+* libmach: correct handling of .5 files with D_REGREG addresses.
+* linux/386: use Xen-friendly ELF TLS instruction sequence.
+* mime: add AddExtensionType (thanks Yuusei Kuwana).
+* misc/vim: syntax file recognizes constants like 1e9 (thanks Petar Maymounkov).
+* net: TCPConn.SetNoDelay, back by popular demand.
+* net(windows): fix crashing Read/Write when passed empty slice on (thanks Alex Brainman),
+ implement LookupHost/Port/SRV (thanks Wei Guangjing),
+ properly handle EOF in (*netFD).Read() (thanks Alex Brainman).
+* runtime: fix bug introduced in revision 4a01b8d28570 (thanks Alex Brainman),
+ rename cgo2c, *.cgo to goc2c, *.goc (thanks Peter Mundy).
+* scanner: better comment.
+* strings: add Title.
+* syscall: add ForkExec, Syscall12 on Windows (thanks Daniel Theophanes),
+ improve windows errno handling (thanks Alex Brainman).
+* syscall(windows): fix FormatMessage (thanks Peter Mundy),
+ implement Pipe() (thanks Wei Guangjing).
+* time: fix parsing of minutes in time zones.
+* utf16(windows): fix cyclic dependency when testing (thanks Peter Mundy).
+</pre>
+
+<h3 id="2010-07-14">2010-07-14</h3>
+
+<pre>
+This release includes a package change. In container/vector, the Iter method
+has been removed from the Vector, IntVector, and StringVector types. Also, the
+Data method has been renamed to Copy to better express its actual behavior.
+Now that Vector is just a slice, any for loops ranging over v.Iter() or
+v.Data() can be changed to range over v instead.
+
+Other changes:
+* big: Improvements to Rat.SetString (thanks Evan Shaw),
+ add sign, abs, Rat.IsInt.
+* cgo: various bug fixes.
+* codereview: Fix for Mercurial >= 1.6 (thanks Evan Shaw).
+* crypto/rand: add Windows implementation (thanks Peter Mundy).
+* crypto/tls: make HTTPS servers easier,
+ add client OCSP stapling support.
+* exp/eval: converted from bignum to big (thanks Evan Shaw).
+* gc: implement new len spec, range bug fix, optimization.
+* go/parser: require that '...' parameters are followed by a type.
+* http: fix ParseURL to handle //relative_path properly.
+* io: fix SectionReader Seek to seek backwards (thanks Peter Mundy).
+* json: Add HTMLEscape (thanks Micah Stetson).
+* ld: bug fixes.
+* math: amd64 version of log (thanks Charles L. Dorian).
+* mime/multipart: new package to parse multipart MIME messages
+ and HTTP multipart/form-data support.
+* os: use TempFile with default TempDir for test files (thanks Peter Mundy).
+* runtime/tiny: add docs for additional VMs, fix build (thanks Markus Duft).
+* runtime: better error for send/recv on nil channel.
+* spec: clarification of channel close(),
+ lock down some details about channels and select,
+ restrict when len(x) is constant,
+ specify len/cap for nil slices, maps, and channels.
+* windows: append .exe to binary names (thanks Joe Poirier).
+</pre>
+
<h3 id="2010-07-01">2010-07-01</h3>
<pre>
diff --git a/doc/devel/roadmap.html b/doc/devel/roadmap.html
index eace183f7..021ed6478 100644
--- a/doc/devel/roadmap.html
+++ b/doc/devel/roadmap.html
@@ -2,6 +2,7 @@
<h2 id="Roadmap">Go Roadmap</h2>
+<p>
This page lists features and ideas being developed or discussed by the
Go team. This list will be updated as work continues.
@@ -26,6 +27,9 @@ Variant types. A way to define a type as being the union of some set
of types.
<li>
Generics. An active topic of discussion.
+<li>
+Methods for operators, to allow a type to use arithmetic notation for
+expressions.
</ul>
<h3 id="Implementation_roadmap">
@@ -38,14 +42,10 @@ with a cycle detector running in a separate core.
<li>
Debugger.
<li>
-Native Client (NaCl) support.
-<li>
App Engine support.
<li>
Improved CGO including some mechanism for calling back from C to Go.
<li>
-SWIG support.
-<li>
Improved implementation documentation.
</ul>
@@ -56,28 +56,55 @@ Gc compiler roadmap</h4>
<li>
Implement goto restrictions.
<li>
-Safe compilation mode: generate code that is guaranteed not to obtain
-an invalid memory address other than via <code>import "unsafe"</code>.
-<li>
-Generate ELF debug info.
-<li>
Improved optimization.
<li>
5g: Better floating point support.
+<li>
+Use escape analysis to keep more data on stack.
</ul>
-<h4 id = "Gccgo_roadmap">
+<h4 id="Gccgo_roadmap">
Gccgo compiler roadmap</h4>
<ul>
<li>
Implement goto restrictions.
<li>
-Implement garbage collection.
-<li>
Use goroutines rather than threads.
<li>
Separate gcc interface from frontend proper.
<li>
Use escape analysis to keep more data on stack.
</ul>
+
+<h3 id="done">Done</h3>
+
+<ul>
+<li>
+gc: Generate DWARF debug info.
+<li>
+gc: Provide gdb support for runtime facilities.
+<li>
+Safe compilation mode: generate code that is guaranteed not to obtain an invalid memory address other than via <code>import "unsafe"</code>.
+<li>
+Gccgo: garbage collection.
+<li>
+SWIG support.
+<li>
+Simpler semicolon rules.
+<li>
+A more general definition of <code>...</code> in parameter lists.
+<li>
+Explicit conversions from <code>string</code>
+to <code>[]byte</code> and <code>[]int</code>.
+<li>
+A function that will be run by the garbage collector when an item is freed
+(runtime.SetFinalizer).
+<li>
+Public continuous build and benchmark infrastructure (gobuilder).
+<li>
+Package manager (goinstall).
+<li>
+A means of recovering from a panic (recover).
+</ul>
+
diff --git a/doc/docs.html b/doc/docs.html
new file mode 100644
index 000000000..e8152bb35
--- /dev/null
+++ b/doc/docs.html
@@ -0,0 +1,195 @@
+<!-- title Documentation -->
+
+<div class="left-column">
+
+<h2 id="learning">Learning Go</h2>
+
+<p>
+If you're new to Go, we recommend you work through the
+<a href="go_tutorial.html">tutorial</a>. The
+<a href="go_spec.html">language specification</a> has all the details should
+you want to explore.
+</p>
+<p>
+Once you've learned a little about the language,
+<a href="effective_go.html">Effective Go</a> will help you learn the style and
+idioms of programming in Go.
+</p>
+
+<h3 id="orig_tutorial"><a href="go_tutorial.html">A Tutorial for the Go Programming Language</a></h3>
+<p>
+The first tutorial. An introductory text that touches upon several core
+concepts: syntax, types, allocation, constants, I/O, sorting, printing,
+goroutines, and channels.
+</p>
+
+<h3 id="effective_go"><a href="effective_go.html">Effective Go</a></h3>
+<p>
+A document that gives tips for writing clear, idiomatic Go code.
+A must read for any new Go programmer. It augments the tutorial and
+the language specification, both of which should be read first.
+</p>
+
+<h3 id="go_faq"><a href="go_faq.html">Frequently Asked Questions (FAQ)</a></h3>
+<p>
+Answers to common questions about Go.
+</p>
+
+<h3 id="code"><a href="code.html">How to write Go code</a></h3>
+<p>
+How to write a new package and how to test code.
+</p>
+
+<h3 id="codelab_wiki"><a href="codelab/wiki/">Codelab: Writing Web Applications</a></h3>
+<p>
+This codelab takes the reader through the creation of a simple wiki web
+application. It touches on structs, methods, file I/O, http, regular expressions,
+and closures.
+</p>
+
+<h3 id="codewalks"><a href="codewalk/">Codewalks</a></h3>
+<p>
+Guided tours of Go programs.
+</p>
+
+<h3 id="go_for_cpp_programmers"><a href="go_for_cpp_programmers.html">Go for C++ Programmers</a></h3>
+<p>
+An introduction to Go for C++ programmers.
+</p>
+
+<h2 id="tutorials_nonenglish">Non-English Documentation</h2>
+
+<h3 id="docs_cn">Chinese &mdash; 中文</h3>
+
+<ul>
+<li><a href="http://code.google.com/p/golang-china/">golang-china</a> - a broad range of Go documentation.</li>
+<li><a href="http://code.google.com/p/ac-me/downloads/detail?name=fango.pdf">Effective Go and Tutorial</a></li>
+</ul>
+
+<h3 id="docs_de">German &mdash; Deutsch</h3>
+
+<ul>
+<li><a href="http://bitloeffel.de/DOC/golang/go_tutorial_de.html">Eine Anleitung zum Programmieren in Go</a> - the Go Tutorial.</li>
+<li><a href="http://bitloeffel.de/DOC/golang/effective_go_de.html">Wirkungsvoll Go programmieren</a> - Effective Go.</li>
+<li><a href="http://bitloeffel.de/DOC/golang/code_de.html">Wie man Go-Kode schreibt</a> - How to Write Go Code.</li>
+</ul>
+
+<h3 id="docs_jp">Japanese &mdash; 日本語</h3>
+<ul>
+<li><a href="http://golang.jp/">golang.jp</a> - Go documentation and news.
+</ul>
+
+<h3 id="docs_ru">Russian &mdash; Русский</h3>
+<ul>
+<li><a href="http://golanguage.ru/">golanguage.ru</a> - Go documentation.
+</ul>
+
+</div>
+
+
+<div class="right-column">
+
+<h2 id="References">References</h2>
+
+<p>Keep these under your pillow.</p>
+
+<h3 id="pkg"><a href="/pkg/">Package Documentation</a></h3>
+<p>
+The built-in documentation for the Go standard library.
+</p>
+
+<h3 id="cmd"><a href="/cmd/">Command Documentation</a></h3>
+<p>
+The built-in documentation for the Go tools.
+</p>
+
+<h3 id="spec"><a href="go_spec.html">Language Specification</a></h3>
+<p>
+The official Go Language specification.
+</p>
+
+<h3 id="go_mem"><a href="go_mem.html">The Go Memory Model</a></h3>
+<p>
+A document that specifies the conditions under which reads of a variable in
+one goroutine can be guaranteed to observe values produced by writes to the
+same variable in a different goroutine.
+</p>
+
+<h2 id="videos_talks">Videos and Talks</h2>
+
+<h3 id="go_programming"><a href="http://www.youtube.com/watch?v=jgVhBThJdXc">Go Programming</a></h3>
+<p>
+A presentation delivered by Rob Pike and Russ Cox at Google I/O 2010. It
+illustrates how programming in Go differs from other languages through a set of
+examples demonstrating features particular to Go. These include concurrency,
+embedded types, methods on any type, and program construction using interfaces.
+</p>
+
+<h3 id="practical_go_programming"><a href="http://osdc.blip.tv/file/4432146/">Practical Go Programming</a></h3>
+<p>
+This talk presents the development of a complete web application in Go.
+It looks at design, storage, concurrency, and scaling issues in detail, using
+the simple example of an URL shortening service.
+See the <a href="http://wh3rd.net/practical-go/">presentation slides</a>.
+</p>
+
+<h3 id="techtalk"><a href="http://www.youtube.com/watch?v=rKnDgT73v8s">The Go Tech Talk</a></h3>
+<p>
+An hour-long talk delivered by Rob Pike at Google in October 2009.
+The language's first public introduction. (See the <a href="talks/go_talk-20091030.pdf">slides in PDF format</a>.) The language has changed since it was made,
+but it's still a good introduction.
+</p>
+
+<h3 id="gocoding_channel"><a href="http://www.youtube.com/gocoding">gocoding YouTube Channel</a></h3>
+<p>
+A YouTube channel that includes screencasts and other Go-related videos:
+</p>
+<ul>
+<li><a href="http://www.youtube.com/gocoding#p/u/0/jDWBJOXs_iI">Screencast: Writing Go Packages</a> - writing, building, and distributing Go packages.</li>
+<li><a href="http://www.youtube.com/watch?v=3brH0zOqm0w">Screencast: Testing Go Packages</a> - writing unit tests and benchmarking Go packages.</li>
+</ul>
+
+<h3 id="jaoo_go"><a href="/doc/ExpressivenessOfGo.pdf">The Expressiveness Of Go</a></h3>
+<p>
+A discussion of the qualities that make Go an expressive and comprehensible
+language. The talk was presented by Rob Pike at JAOO 2010.
+The recording of the event was lost due to a hardware error.
+</p>
+
+<h3 id="oscon_go"><a href="http://www.oscon.com/oscon2010/public/schedule/detail/14760">Another Go at Language Design</a></h3>
+<p>
+A tour, with some background, of the major features of Go, intended for
+an audience new to the language. The talk was presented at OSCON 2010.
+See the <a href="http://assets.en.oreilly.com/1/event/45/Another%20Go%20at%20Language%20Design%20Presentation.pdf">presentation slides</a>.
+</p>
+<p>
+This talk was also delivered at Sydney University in September 2010. A video
+of the lecture is available
+<a href="http://sydney.edu.au/engineering/it/videos/seminar_pike">here</a>.
+</p>
+
+<h3 id="emerging_go"><a href="http://www.oscon.com/oscon2010/public/schedule/detail/15464">Go Emerging Languages Conference Talk</a></h3>
+<p>
+Rob Pike's Emerging Languages Conference presentation delivered in July 2010. See the <a href="http://assets.en.oreilly.com/1/event/45/Go%20Presentation.pdf">presentation slides</a>. Abstract:
+</p>
+<p><i>
+Go’s approach to concurrency differs from that of many languages, even those
+(such as Erlang) that make concurrency central, yet it has deep roots. The path
+from Hoare’s 1978 paper to Go provides insight into how and why Go works as it
+does.
+</i></p>
+
+<h3 id="emerging_go"><a href="talks/gofrontend-gcc-summit-2010.pdf">The Go frontend for GCC</a></h3>
+<p>
+A description of the Go language frontend for gcc.
+Ian Lance Taylor's paper delivered at the GCC Summit 2010.
+</p>
+
+<h3 id="promo_video"><a href="http://www.youtube.com/watch?v=wwoWei-GAPo">The Go Promo Video</a></h3>
+<p>
+A short promotional video featuring Russ Cox demonstrating Go's fast compiler.
+</p>
+
+</div>
+
+<div class="end-columns"></div>
diff --git a/doc/effective_go.html b/doc/effective_go.html
index 41a7b8af9..26e317b5d 100644
--- a/doc/effective_go.html
+++ b/doc/effective_go.html
@@ -207,7 +207,7 @@ have a doc comment.
</p>
<p>
-Doc comments work best as complete English sentences, which allow
+Doc comments work best as complete sentences, which allow
a wide variety of automated presentations.
The first sentence should be a one-sentence summary that
starts with the name being declared.
@@ -463,7 +463,7 @@ statement, it's common to see one used to set up a local variable.
<pre>
if err := file.Chmod(0664); err != nil {
- log.Stderr(err)
+ log.Print(err)
return err
}
</pre>
@@ -794,7 +794,7 @@ func Contents(filename string) (string, os.Error) {
buf := make([]byte, 100)
for {
n, err := f.Read(buf[0:])
- result = bytes.Add(result, buf[0:n])
+ result = append(result, buf[0:n]...) // append is discussed later.
if err != nil {
if err == os.EOF {
break
@@ -815,7 +815,7 @@ which is much clearer than placing it at the end of the function.
</p>
<p>
-The arguments to the deferred function (which includes the receiver if
+The arguments to the deferred function (which include the receiver if
the function is a method) are evaluated when the <i>defer</i>
executes, not when the <i>call</i> executes. Besides avoiding worries
about variables changing values as the function executes, this means
@@ -1218,6 +1218,11 @@ func Append(slice, data[]byte) []byte {
We must return the slice afterwards because, although <code>Append</code>
can modify the elements of <code>slice</code>, the slice itself (the run-time data
structure holding the pointer, length, and capacity) is passed by value.
+<p>
+The idea of appending to a slice is so useful it's captured by the
+<code>append</code> built-in function. To understand that function's
+design, though, we need a little more information, so we'll return
+to it later.
</p>
@@ -1288,7 +1293,7 @@ func offset(tz string) int {
if seconds, ok := timeZone[tz]; ok {
return seconds
}
- log.Stderr("unknown time zone", tz)
+ log.Println("unknown time zone", tz)
return 0
}
</pre>
@@ -1326,13 +1331,15 @@ You don't need to provide a format string. For each of <code>Printf</code>,
<code>Fprintf</code> and <code>Sprintf</code> there is another pair
of functions, for instance <code>Print</code> and <code>Println</code>.
These functions do not take a format string but instead generate a default
-format for each argument. The <code>ln</code> version also inserts a blank
-between arguments if neither is a string and appends a newline to the output.
+format for each argument. The <code>Println</code> versions also insert a blank
+between arguments and append a newline to the output while
+the <code>Print</code> versions add blanks only if the operand on neither side is a string.
In this example each line produces the same output.
</p>
<pre>
fmt.Printf("Hello %d\n", 23)
fmt.Fprint(os.Stdout, "Hello ", 23, "\n")
+fmt.Println("Hello", 23)
fmt.Println(fmt.Sprint("Hello ", 23))
</pre>
<p>
@@ -1453,16 +1460,20 @@ Within the function <code>Printf</code>, <code>v</code> acts like a variable of
<code>[]interface{}</code> but if it is passed to another variadic function, it acts like
a regular list of arguments.
Here is the implementation of the
-function <code>log.Stderr</code> we used above. It passes its arguments directly to
+function <code>log.Println</code> we used above. It passes its arguments directly to
<code>fmt.Sprintln</code> for the actual formatting.
</p>
<pre>
-// Stderr is a helper function for easy logging to stderr. It is analogous to Fprintln(os.Stderr).
-func Stderr(v ...interface{}) {
- stderr.Output(2, fmt.Sprintln(v)) // Output takes parameters (int, string)
+// Println prints to the standard logger in the manner of fmt.Println.
+func Println(v ...interface{}) {
+ std.Output(2, fmt.Sprintln(v...)) // Output takes parameters (int, string)
}
</pre>
<p>
+We write <code>...</code> after <code>v</code> in the nested call to <code>Sprintln</code> to tell the
+compiler to treat <code>v</code> as a list of arguments; otherwise it would just pass
+<code>v</code> as a single slice argument.
+<p>
There's even more to printing than we've covered here. See the <code>godoc</code> documentation
for package <code>fmt</code> for the details.
</p>
@@ -1482,6 +1493,47 @@ func Min(a ...int) int {
}
</pre>
+<h3 id="append">Append</h3>
+<p>
+Now we have the missing piece we needed to explain the design of
+the <code>append</code> built-in function. The signature of <code>append</code>
+is different from our custom <code>Append</code> function above.
+Schematically, it's like this:
+<pre>
+func append(slice []<i>T</i>, elements...T) []<i>T</i>
+</pre>
+where <i>T</i> is a placeholder for any given type. You can't
+actually write a function in Go where the type <code>T</code>
+is determined by the caller.
+That's why <code>append</code> is built in: it needs support from the
+compiler.
+<p>
+What <code>append</code> does is append the elements to the end of
+the slice and return the result. The result needs to be returned
+because, as with our hand-written <code>Append</code>, the underlying
+array may change. This simple example
+<pre>
+x := []int{1,2,3}
+x = append(x, 4, 5, 6)
+fmt.Println(x)
+</pre>
+prints <code>[1 2 3 4 5 6]</code>. So <code>append</code> works a
+little like <code>Printf</code>, collecting an arbitrary number of
+arguments.
+<p>
+But what if we wanted to do what our <code>Append</code> does and
+append a slice to a slice? Easy: use <code>...</code> at the call
+site, just as we did in the call to <code>Output</code> above. This
+snippet produces identical output to the one above.
+<pre>
+x := []int{1,2,3}
+y := []int{4,5,6}
+x = append(x, y...)
+fmt.Println(x)
+</pre>
+Without that <code>...</code>, it wouldn't compile because the types
+would be wrong; <code>y</code> is not of type <code>int</code>.
+
<h2 id="initialization">Initialization</h2>
<p>
@@ -1537,26 +1589,29 @@ automatically for printing, even as part of a general type.
func (b ByteSize) String() string {
switch {
case b &gt;= YB:
- return fmt.Sprintf("%.2fYB", b/YB)
+ return fmt.Sprintf("%.2fYB", float64(b/YB))
case b &gt;= ZB:
- return fmt.Sprintf("%.2fZB", b/ZB)
+ return fmt.Sprintf("%.2fZB", float64(b/ZB))
case b &gt;= EB:
- return fmt.Sprintf("%.2fEB", b/EB)
+ return fmt.Sprintf("%.2fEB", float64(b/EB))
case b &gt;= PB:
- return fmt.Sprintf("%.2fPB", b/PB)
+ return fmt.Sprintf("%.2fPB", float64(b/PB))
case b &gt;= TB:
- return fmt.Sprintf("%.2fTB", b/TB)
+ return fmt.Sprintf("%.2fTB", float64(b/TB))
case b &gt;= GB:
- return fmt.Sprintf("%.2fGB", b/GB)
+ return fmt.Sprintf("%.2fGB", float64(b/GB))
case b &gt;= MB:
- return fmt.Sprintf("%.2fMB", b/MB)
+ return fmt.Sprintf("%.2fMB", float64(b/MB))
case b &gt;= KB:
- return fmt.Sprintf("%.2fKB", b/KB)
+ return fmt.Sprintf("%.2fKB", float64(b/KB))
}
- return fmt.Sprintf("%.2fB", b)
+ return fmt.Sprintf("%.2fB", float64(b))
}
</pre>
<p>
+(The <code>float64</code> conversions prevent <code>Sprintf</code>
+from recurring back through the <code>String</code> method for
+<code>ByteSize</code>.)
The expression <code>YB</code> prints as <code>1.00YB</code>,
while <code>ByteSize(1e13)</code> prints as <code>9.09TB</code>.
</p>
@@ -1849,10 +1904,18 @@ that implements <code>Handler</code> can serve HTTP requests.
</p>
<pre>
type Handler interface {
- ServeHTTP(*Conn, *Request)
+ ServeHTTP(ResponseWriter, *Request)
}
</pre>
<p>
+<code>ResponseWriter</code> is itself an interface that provides access
+to the methods needed to return the response to the client.
+Those methods include the standard <code>Write</code> method, so an
+<code>http.ResponseWriter</code> can be used wherever an <code>io.Writer</code>
+can be used.
+<code>Request</code> is a struct containing a parsed representation
+of the request from the client.
+<p>
For brevity, let's ignore POSTs and assume HTTP requests are always
GETs; that simplification does not affect the way the handlers are
set up. Here's a trivial but complete implementation of a handler to
@@ -1865,13 +1928,14 @@ type Counter struct {
n int
}
-func (ctr *Counter) ServeHTTP(c *http.Conn, req *http.Request) {
+func (ctr *Counter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
ctr.n++
- fmt.Fprintf(c, "counter = %d\n", ctr.n)
+ fmt.Fprintf(w, "counter = %d\n", ctr.n)
}
</pre>
<p>
-(Keeping with our theme, note how <code>Fprintf</code> can print to an HTTP connection.)
+(Keeping with our theme, note how <code>Fprintf</code> can print to an
+<code>http.ResponseWriter</code>.)
For reference, here's how to attach such a server to a node on the URL tree.
<pre>
import "http"
@@ -1887,9 +1951,9 @@ But why make <code>Counter</code> a struct? An integer is all that's needed.
// Simpler counter server.
type Counter int
-func (ctr *Counter) ServeHTTP(c *http.Conn, req *http.Request) {
+func (ctr *Counter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
*ctr++
- fmt.Fprintf(c, "counter = %d\n", *ctr)
+ fmt.Fprintf(w, "counter = %d\n", *ctr)
}
</pre>
<p>
@@ -1901,9 +1965,9 @@ has been visited? Tie a channel to the web page.
// (Probably want the channel to be buffered.)
type Chan chan *http.Request
-func (ch Chan) ServeHTTP(c *http.Conn, req *http.Request) {
+func (ch Chan) ServeHTTP(w http.ResponseWriter, req *http.Request) {
ch &lt;- req
- fmt.Fprint(c, "notification sent")
+ fmt.Fprint(w, "notification sent")
}
</pre>
<p>
@@ -1930,11 +1994,11 @@ The <code>http</code> package contains this code:
// ordinary functions as HTTP handlers. If f is a function
// with the appropriate signature, HandlerFunc(f) is a
// Handler object that calls f.
-type HandlerFunc func(*Conn, *Request)
+type HandlerFunc func(ResponseWriter, *Request)
// ServeHTTP calls f(c, req).
-func (f HandlerFunc) ServeHTTP(c *Conn, req *Request) {
- f(c, req)
+func (f HandlerFunc) ServeHTTP(w ResponseWriter, req *Request) {
+ f(w, req)
}
</pre>
<p>
@@ -1950,9 +2014,9 @@ to have the right signature.
</p>
<pre>
// Argument server.
-func ArgServer(c *http.Conn, req *http.Request) {
+func ArgServer(w http.ResponseWriter, req *http.Request) {
for i, s := range os.Args {
- fmt.Fprintln(c, s)
+ fmt.Fprintln(w, s)
}
}
</pre>
@@ -2014,7 +2078,7 @@ two methods explicitly, but it's easier and more evocative
to embed the two interfaces to form the new one, like this:
</p>
<pre>
-// ReadWrite is the interface that groups the basic Read and Write methods.
+// ReadWriter is the interface that combines the Reader and Writer interfaces.
type ReadWriter interface {
Reader
Writer
@@ -2119,7 +2183,7 @@ func NewJob(command string, logger *log.Logger) *Job {
or with a composite literal,
</p>
<pre>
-job := &amp;Job{command, log.New(os.Stderr, nil, "Job: ", log.Ldate)}
+job := &amp;Job{command, log.New(os.Stderr, "Job: ", log.Ldate)}
</pre>
<p>
If we need to refer to an embedded field directly, the type name of the field,
@@ -2603,7 +2667,7 @@ func CubeRoot(x float64) float64 {
}
}
// A million iterations has not converged; something is wrong.
- panic(fmt.Sprintf("CubeRoot(%g) did not converge", x)
+ panic(fmt.Sprintf("CubeRoot(%g) did not converge", x))
}
</pre>
@@ -2654,14 +2718,14 @@ inside a server without killing the other executing goroutines.
<pre>
func server(workChan <-chan *Work) {
for work := range workChan {
- safelyDo(work)
+ go safelyDo(work)
}
}
func safelyDo(work *Work) {
defer func() {
if err := recover(); err != nil {
- log.Stderr("work failed:", err)
+ log.Println("work failed:", err)
}
}()
do(work)
@@ -2728,7 +2792,7 @@ user-triggered errors.
</p>
<p>
-With this error handling in place, the <code>error</code> method
+With error handling in place, the <code>error</code> method
makes it easy to report parse errors without worrying about unwinding
the parse stack by hand.
</p>
@@ -2740,6 +2804,17 @@ Useful though this pattern is, it should be used only within a package.
to its client. That is a good rule to follow.
</p>
+<p>
+By the way, this re-panic idiom changes the panic value if an actual
+error occurs. However, both the original and new failures will be
+presented in the crash report, so the root cause of the problem will
+still be visible. Thus this simple re-panic approach is usually
+sufficient&mdash;it's a crash after all&mdash;but if you want to
+display only the original value, you can write a little more code to
+filter unexpected problems and re-panic with the original error.
+That's left as an exercise for the reader.
+</p>
+
<h2 id="web_server">A web server</h2>
@@ -2789,12 +2864,12 @@ func main() {
}
}
-func QR(c *http.Conn, req *http.Request) {
- templ.Execute(req.FormValue("s"), c)
+func QR(w http.ResponseWriter, req *http.Request) {
+ templ.Execute(req.FormValue("s"), w)
}
-func UrlHtmlFormatter(w io.Writer, v interface{}, fmt string) {
- template.HTMLEscape(w, []byte(http.URLEscape(v.(string))))
+func UrlHtmlFormatter(w io.Writer, fmt string, v ...interface{}) {
+ template.HTMLEscape(w, []byte(http.URLEscape(v[0].(string))))
}
diff --git a/doc/frontpage.css b/doc/frontpage.css
new file mode 100644
index 000000000..bcdca6401
--- /dev/null
+++ b/doc/frontpage.css
@@ -0,0 +1,140 @@
+/* Overloads to all.css */
+#container { width: 76em }
+.left-column { width: 48%; }
+.right-column { width: 48%; }
+
+/* Frontpage styles */
+#content-introductory code {
+ font-family: "Bitstream Vera Sans Mono", "Andale Mono", monospace;
+}
+#content-introductory input, select, textarea {
+ font-family: "Bitstream Vera Sans", Verdana, sans-serif;
+ font-size: 1em;
+}
+span.keyword {
+ font-family: Cambria, Georgia, Times, "Times New Roman", serif;
+ font-size: 1.15em;
+ font-style: italic;
+}
+#content h3, #content h2 {
+ margin: 0;
+ font-size: 1em;
+ background: none;
+ border: none;
+ padding: 0;
+}
+#content .more {
+ color: #999;
+ font-weight: normal;
+}
+#frontpage h2#branding-tagline {
+ font-weight: normal;
+ font-style: italic;
+}
+#resources {
+ position: relative;
+ margin-top: 1em;
+}
+#resources h3 {
+ margin-top: 0;
+ margin-bottom: -.5em;
+ font-size: 1em;
+ font-weight: normal;
+}
+#resources-users {
+ float: left;
+ width: 48%;
+}
+#resources-contributors {
+ float: right;
+ width: 50%;
+}
+#resources ul {
+ padding-left: 2em;
+}
+#resources li {
+ margin-bottom: 0.5em;
+}
+#content-rotating {
+ height: 200px;
+}
+#content-videos {
+ float: left;
+ width: 170px;
+}
+#content-videos .thumbnail {
+ width: 150px;
+ height: 103px;
+ background-repeat: no-repeat;
+ border: none;
+}
+#content-videos .thumbnail._001 {
+ background: url(/doc/video-001.png);
+}
+#content-videos .thumbnail._002 {
+ background: url(/doc/video-002.png);
+}
+#content-videos .thumbnail._003 {
+ background: url(/doc/video-003.png);
+}
+#content-videos .thumbnail._004 {
+ background: url(/doc/video-004.png);
+}
+#content-videos a.video {
+ display: inline-block;
+ width: 150px;
+ margin-right: .30em;
+ margin-top: 1.2em;
+}
+#content-videos a.video .caption {
+ display: block;
+ text-align: center;
+}
+#content-videos a.video .caption.title {
+ margin-top: .31em;
+ font-weight: bold;
+}
+#content-blog ul {
+ margin-top: 1em;
+ margin-left: 0;
+ padding-left: 0;
+}
+#content-blog li {
+ list-style: none;
+ margin-bottom: 1em;
+}
+#content-blog li a {
+ color: #999;
+ text-decoration: none;
+}
+#content-blog .date {
+ color: #999;
+ font-size: 0.8em;
+ display: inline-block;
+ margin-left: 0.5em;
+}
+#content-blog li a:link .title {
+ color: #04a;
+}
+#content-blog li a:visited .title {
+ color: #04a;
+}
+#content-blog li a:hover .title {
+ color: #a40;
+ text-decoration: underline;
+}
+#content-blog li a:active .title {
+ color: #c00;
+}
+.navtop {
+ display: none !important;
+}
+.how {
+ float: right;
+ font-size: 75%;
+}
+.unsupported {
+ font-weight: bold;
+ color: red;
+}
+
diff --git a/doc/gccgo_install.html b/doc/gccgo_install.html
index 3ffd6a645..393e57963 100644
--- a/doc/gccgo_install.html
+++ b/doc/gccgo_install.html
@@ -224,12 +224,9 @@ gccgo -o main main.o mypackage.o # Explicitly links with mypackage.o
<p>
Some Go features are not yet implemented in <code>gccgo</code>. As of
-2009-11-06, the following are not implemented:
+2010-08-23, the following are not implemented:
<ul>
-<li>Garbage collection is not implemented. There is no way to free memory.
- Thus long running programs are not supported.
-
<li>goroutines are implemented as NPTL threads. If you can not use
the gold linker as described above, they are created with a fixed
stack size, and the number of goroutines that may be created at
@@ -263,14 +260,13 @@ Pointers in Go are pointers in C. A Go <code>struct</code> is the same as C
<code>struct</code> with the same fields and types.
<p>
-The Go <code>string</code> type is a pointer to a structure.
-The current definition is
-(this is <b style="color: red;">expected to change</b>):
+The Go <code>string</code> type is currently defined as a two-element
+structure (this is <b style="color: red;">subject to change</b>):
<pre>
struct __go_string {
- size_t __length;
- unsigned char __data[];
+ const unsigned char *__data;
+ int __length;
};
</pre>
@@ -310,9 +306,10 @@ when the functions have equivalent types.
<p>
Go <code>interface</code>, <code>channel</code>, and <code>map</code>
-types have no corresponding C type (they roughly correspond to pointers
-to structs in C, but the structs are deliberately undocumented). C
-<code>enum</code> types correspond to some Go type, but precisely
+types have no corresponding C type (<code>interface</code> is a
+two-element struct and <code>channel</code> and <code>map</code> are
+pointers to structs in C, but the structs are deliberately undocumented). C
+<code>enum</code> types correspond to some integer type, but precisely
which one is difficult to predict in general; use a cast. C <code>union</code>
types have no corresponding Go type. C <code>struct</code> types containing
bitfields have no corresponding Go type. C++ <code>class</code> types have
@@ -359,12 +356,15 @@ i := c_open(&amp;name[0], os.O_RDONLY, 0);
<p>
The name of Go functions accessed from C is subject to change. At present
the name of a Go function that does not have a receiver is
-<code>package.Functionname</code>. To call it from C you must set the
-name using a <code>gcc</code> extension similar to the <code>gccgo</code>
+<code>prefix.package.Functionname</code>. The prefix is set by
+the <code>-fgo-prefix</code> option used when the package is compiled;
+if the option is not used, the default is simply <code>go</code>.
+To call the function from C you must set the name using
+a <code>gcc</code> extension similar to the <code>gccgo</code>
extension.
<pre>
-extern int go_function(int) __asm__ ("mypackage.Function");
+extern int go_function(int) __asm__ ("myprefix.mypackage.Function");
</pre>
<h3 id="Automatic_generation_of_Go_declarations_from_C_source_code">
@@ -395,3 +395,15 @@ grep '#GO' foo.s | grep -v INVALID | grep -v unknowndefine | grep -v undef > foo
This procedure is full of unstated caveats and restrictions and we make no
guarantee that it will not change in the future. It is more useful as a
starting point for real Go code than as a regular procedure.
+
+<h2 id="RTEMS_Port">RTEMS Port</h2>
+<p>
+The <code>gccgo</code> compiler has been ported to <a href="http://www.rtems.com/">
+<code>RTEMS</code></a>. <code>RTEMS</code> is a real-time executive
+that provides a high performance environment for embedded applications
+on a range of processors and embedded hardware. The current <code>gccgo</code>
+port is for x86. The goal is to extend the port to most of the
+<a href="http://www.rtems.org/wiki/index.php/SupportedCPUs">
+architectures supported by <code>RTEMS</code></a>. For more information on the port,
+as well as instructions on how to install it, please see this
+<a href="http://www.rtems.com/wiki/index.php/GCCGoRTEMS"><code>RTEMS</code> Wiki page</a>.
diff --git a/doc/go_faq.html b/doc/go_faq.html
index 4f11baa80..1c7b85ef8 100644
--- a/doc/go_faq.html
+++ b/doc/go_faq.html
@@ -56,6 +56,21 @@ What is the origin of the name?</h3>
<p>
&ldquo;Ogle&rdquo; would be a good name for a Go debugger.
+<h3 id="Whats_the_origin_of_the_mascot">
+What's the origin of the mascot?</h3>
+
+<p>
+The mascot and logo were designed by
+<a href="http://reneefrench.blogspot.com">Renée French</a>, who also designed
+<a href="http://plan9.bell-labs.com/plan9/glenda.html">Glenda</a>,
+the Plan 9 bunny.
+The gopher is derived from one she used for an <a href="http://wfmu.org/">WFMU</a>
+T-shirt design some years ago.
+The logo and mascot are covered by the
+<a href="http://creativecommons.org/licenses/by/3.0/">Creative Commons Attribution 3.0</a>
+license.
+</p>
+
<h3 id="What_kind_of_a_name_is_6g">
What kind of a name is 6g?</h3>
@@ -69,42 +84,102 @@ http://plan9.bell-labs.com/sys/doc/compiler.html</a>
<code>6</code> is the architecture letter for amd64 (or x86-64, if you prefer), while
<code>g</code> stands for Go.
-<h3 id="Why_not_just_write_some_libraries_for_Cpp_to_do_communication">
-Why not just write some libraries for C++ to do communication?</h3>
+<h3 id="history">
+What is the history of the project?</h3>
+<p>
+Robert Griesemer, Rob Pike and Ken Thompson started sketching the
+goals for a new language on the white board on September 21, 2007.
+Within a few days the goals had settled into a plan to do something
+and a fair idea of what it would be. Design continued part-time in
+parallel with unrelated work. By January 2008, Ken had started work
+on a compiler with which to explore ideas; it generated C code as its
+output. By mid-year the language had become a full-time project and
+had settled enough to attempt a production compiler. In May 2008,
+Ian Taylor independently started on a GCC front end for Go using the
+draft specification. Russ Cox joined in late 2008 and helped move the language
+and libraries from prototype to reality.
+</p>
-<p>We considered doing that, but too many of the problems&mdash;lack of
-garbage collection, long dependency chains, nested include files,
-lack of concurrency awareness&mdash;are rooted in the design of
-the C and C++ languages themselves.
-We felt a viable solution required a more complete approach.
+<p>
+Many others have contributed ideas, discussions, and code.
+</p>
-<h3 id="Why_doesnt_Go_run_on_Windows">
-Why doesn't Go run on Windows yet?</h3>
+<h3 id="creating_a_new_language">
+Why are you creating a new language?</h3>
<p>
-We understand that a significant fraction of computers in the world
-run Windows and it would be great if those computers could run Go
-programs. A group of volunteers has made significant progress toward
-porting Go to <a href="http://www.mingw.org/">MinGW</a>.
-You can follow their progress at the Go Wiki's
-<a href="http://code.google.com/p/go/wiki/WindowsPort">WindowsPort</a> page.
+Go was born out of frustration with existing languages and
+environments for systems programming. Programming had become too
+difficult and the choice of languages was partly to blame. One had to
+choose either efficient compilation, efficient execution, or ease of
+programming; all three were not available in the same mainstream
+language. Programmers who could were choosing ease over
+safety and efficiency by moving to dynamically typed languages such as
+Python and JavaScript rather than C++ or, to a lesser extent, Java.
+</p>
+<p>
+Go is an attempt to combine the ease of programming of an interpreted,
+dynamically typed
+language with the efficiency and safety of a statically typed, compiled language.
+It also aims to be modern, with support for networked and multicore
+computing. Finally, it is intended to be <i>fast</i>: it should take
+at most a few seconds to build a large executable on a single computer.
+To meet these goals required addressing a number of
+linguistic issues: an expressive but lightweight type system;
+concurrency and garbage collection; rigid dependency specification;
+and so on. These cannot be addressed well by libraries or tools; a new
+language was called for.
</p>
-<h3 id="Whats_the_origin_of_the_mascot">
-What's the origin of the mascot?</h3>
+<h3 id="ancestors">
+What are Go's ancestors?</h3>
<p>
-The mascot and logo were designed by
-<a href="http://reneefrench.blogspot.com">Renée French</a>, who also designed
-<a href="http://plan9.bell-labs.com/plan9/glenda.html">Glenda</a>,
-the Plan 9 bunny.
-The gopher is derived from one she used for an <a href="http://wfmu.org/">WFMU</a>
-T-shirt design some years ago.
-The logo and mascot are covered by the
-<a href="http://creativecommons.org/licenses/by/3.0/">Creative Commons Attribution 3.0</a>
-license.
+Go is mostly in the C family (basic syntax),
+with significant input from the Pascal/Modula/Oberon
+family (declarations, packages),
+plus some ideas from languages
+inspired by Tony Hoare's CSP,
+such as Newsqueak and Limbo (concurrency).
+However, it is a new language across the board.
+In every respect the language was designed by thinking
+about what programmers do and how to make programming, at least the
+kind of programming we do, more effective, which means more fun.
+</p>
+
+
+<h3 id="principles">
+What are the guiding principles in the design?</h3>
+<p>
+Programming today involves too much bookkeeping, repetition, and
+clerical work. As Dick Gabriel says, &ldquo;Old programs read
+like quiet conversations between a well-spoken research worker and a
+well-studied mechanical colleague, not as a debate with a compiler.
+Who'd have guessed sophistication bought such noise?&rdquo;
+The sophistication is worthwhile&mdash;no one wants to go back to
+the old languages&mdash;but can it be more quietly achieved?
+</p>
+<p>
+Go attempts to reduce the amount of typing in both senses of the word.
+Throughout its design, we have tried to reduce clutter and
+complexity. There are no forward declarations and no header files;
+everything is declared exactly once. Initialization is expressive,
+automatic, and easy to use. Syntax is clean and light on keywords.
+Stuttering (<code>foo.Foo* myFoo = new(foo.Foo)</code>) is reduced by
+simple type derivation using the <code>:=</code>
+declare-and-initialize construct. And perhaps most radically, there
+is no type hierarchy: types just <i>are</i>, they don't have to
+announce their relationships. These simplifications allow Go to be
+expressive yet comprehensible without sacrificing, well, sophistication.
+</p>
+<p>
+Another important principle is to keep the concepts orthogonal.
+Methods can be implemented for any type; structures represent data while
+interfaces represent abstraction; and so on. Orthogonality makes it
+easier to understand what happens when things combine.
</p>
+
<h2 id="Usage">Usage</h2>
<h3 id="Who_should_use_the_language">
@@ -116,37 +191,31 @@ if they enjoy it. Not every programmer
will, but we hope enough will find satisfaction in the approach it
offers to justify further development.
-<h3 id="Is_Google_using_go_internally"> Is Google using Go
-internally?</h3>
+<h3 id="Is_Google_using_go_internally"> Is Google using Go internally?</h3>
-<p> The Go project was conceived to make it easier to write the kind
-of servers and other software Google uses internally, but the
-implementation isn't quite mature enough yet for large-scale
-production use. While we continue development we are also doing
-experiments with the language as a candidate server environment. It's
-getting there. For instance, the server behind <a
-href="http://golang.org">http://golang.org</a> is a Go program; in
-fact it's just the <a href="/cmd/godoc"><code>godoc</code></a> document server running in a
-production configuration.
+<p>Yes. There are now several Go programs deployed in
+production inside Google. For instance, the server behind
+<a href="http://golang.org">http://golang.org</a> is a Go program;
+in fact it's just the <a href="/cmd/godoc"><code>godoc</code></a>
+document server running in a production configuration.
<h3 id="Do_Go_programs_link_with_Cpp_programs">
Do Go programs link with C/C++ programs?</h3>
<p>
-There are two Go compiler implementations, <code>6g</code> and friends, generically called
-<code>gc</code>, and <code>gccgo</code>.
+There are two Go compiler implementations, <code>6g</code> and friends,
+generically called <code>gc</code>, and <code>gccgo</code>.
<code>Gc</code> uses a different calling convention and linker and can
therefore only be linked with C programs using the same convention.
-There is such a C compiler but no C++ compiler. <code>Gccgo</code> is a
-GCC front-end that can, with care, be linked with GCC-compiled
-C or C++ programs. However, because Go is garbage-collected it will be
-unwise to do so, at least naively.
+There is such a C compiler but no C++ compiler.
+<code>Gccgo</code> is a GCC front-end that can, with care, be linked with
+GCC-compiled C or C++ programs.
<p>
-There is a &ldquo;foreign function interface&rdquo; to allow safe calling of C-written
-libraries from Go code. We expect to use SWIG to extend this capability
-to C++ libraries. There is no safe way to call Go code from C or C++ yet.
+The <a href="/cmd/cgo/">cgo</a> program provides the mechanism for a
+&ldquo;foreign function interface&rdquo; to allow safe calling of
+C libraries from Go code. SWIG extends this capability to C++ libraries.
<h3 id="Does_Go_support_Google_protocol_buffers">
Does Go support Google's protocol buffers?</h3>
@@ -170,7 +239,35 @@ you will need to abide by the guidelines at
<h2 id="Design">Design</h2>
-<h3 id="Why_doesnt_Go_have_feature_X">Why doesn't Go have feature X?</h3>
+<h3 id="unicode_identifiers">
+What's up with Unicode identifiers?</h3>
+
+<p>
+It was important to us to extend the space of identifiers from the
+confines of ASCII. Go's rule&mdash;identifier characters must be
+letters or digits as defined by Unicode&mdash;is simple to understand
+and to implement but has restrictions. Combining characters are
+excluded by design, for instance.
+Until there
+is an agreed external definition of what an identifier might be,
+plus a definition of canonicalization of identifiers that guarantees
+no ambiguity, it seemed better to keep combining characters out of
+the mix. Thus we have a simple rule that can be expanded later
+without breaking programs, one that avoids bugs that would surely arise
+from a rule that admits ambiguous identifiers.
+</p>
+
+<p>
+On a related note, since an exported identifier must begin with an
+upper-case letter, identifiers created from &ldquo;letters&rdquo;
+in some languages can, by definition, not be exported. For now the
+only solution is to use something like <code>X日本語</code>, which
+is clearly unsatisfactory; we are considering other options. The
+case-for-visibility rule is unlikely to change however; it's one
+of our favorite features of Go.
+</p>
+
+<h3 id="Why_doesnt_Go_have_feature_X">Why does Go not have feature X?</h3>
<p>
Every language contains novel features and omits someone's favorite
@@ -186,15 +283,145 @@ If it bothers you that Go is missing feature <var>X</var>,
please forgive us and investigate the features that Go does have. You might find that
they compensate in interesting ways for the lack of <var>X</var>.
-<h3 id="Why_is_the_syntax_so_different_from_Cpp">
-Why is the syntax so different from C++?</h3>
+<h3 id="generics">
+Why does Go not have generic types?</h3>
+<p>
+Generics may well be added at some point. We don't feel an urgency for
+them, although we understand some programmers do.
+</p>
+<p>
+Generics are convenient but they come at a cost in
+complexity in the type system and run-time. We haven't yet found a
+design that gives value proportionate to the complexity, although we
+continue to think about it. Meanwhile, Go's built-in maps and slices,
+plus the ability to use the empty interface to construct containers
+(with explicit unboxing) mean in many cases it is possible to write
+code that does what generics would enable, if less smoothly.
+</p>
+<p>
+This remains an open issue.
+</p>
+<h3 id="exceptions">
+Why does Go not have exceptions?</h3>
<p>
-This and other language design questions are answered in
-the separate <a href="go_lang_faq.html">language design FAQ</a>.
+We believe that coupling exceptions to a control
+structure, as in the <code>try-catch-finally</code> idiom, results in
+convoluted code. It also tends to encourage programmers to label
+too many ordinary errors, such as failing to open a file, as
+exceptional.
+</p>
+<p>
+Go takes a different approach. Instead of exceptions, it has a couple
+of built-in functions to signal and recover from truly exceptional
+conditions. The recovery mechanism is executed only as part of a
+function's state being torn down after an error, which is sufficient
+to handle catastrophe but requires no extra control structures and,
+when used well, can result in clean error-handling code.
+</p>
+<p>
+See the <a href="http://blog.golang.org/2010/08/defer-panic-and-recover.html">Defer, Panic, and Recover</a> article for details.
+</p>
-<h2 id="Object_Oriented_Programming">
-Object-Oriented Programming</h2>
+
+<h3 id="assertions">
+Why does Go not have assertions?</h3>
+
+<p>
+Go doesn't provide assertions. They are undeniably convenient, but our
+experience has been that programmers use them as a crutch to avoid thinking
+about proper error handling and reporting. Proper error handling means that
+servers continue operation after non-fatal errors instead of crashing.
+Proper error reporting means that errors are direct and to the point,
+saving the programmer from interpreting a large crash trace. Precise
+errors are particularly important when the programmer seeing the errors is
+not familiar with the code.
+
+<p>
+The same arguments apply to the use of <code>assert()</code> in test programs. Proper
+error handling means letting other tests run after one has failed, so
+that the person debugging the failure gets a complete picture of what is
+wrong. It is more useful for a test to report that
+<code>isPrime</code> gives the wrong answer for 2, 3, 5, and 7 (or for
+2, 4, 8, and 16) than to report that <code>isPrime</code> gives the wrong
+answer for 2 and therefore no more tests were run. The programmer who
+triggers the test failure may not be familiar with the code that fails.
+Time invested writing a good error message now pays off later when the
+test breaks.
+
+<p>
+In testing, if the amount of extra code required to write
+good errors seems repetitive and overwhelming, it might work better as a
+table-driven test instead.
+Go has excellent support for data structure literals.
+
+<p>
+We understand that this is a point of contention. There are many things in
+the Go language and libraries that differ from modern practices, simply
+because we feel it's sometimes worth trying a different approach.
+
+<h3 id="csp">
+Why build concurrency on the ideas of CSP?</h3>
+<p>
+Concurrency and multi-threaded programming have a reputation
+for difficulty. We believe the problem is due partly to complex
+designs such as pthreads and partly to overemphasis on low-level details
+such as mutexes, condition variables, and even memory barriers.
+Higher-level interfaces enable much simpler code, even if there are still
+mutexes and such under the covers.
+</p>
+<p>
+One of the most successful models for providing high-level linguistic support
+for concurrency comes from Hoare's Communicating Sequential Processes, or CSP.
+Occam and Erlang are two well known languages that stem from CSP.
+Go's concurrency primitives derive from a different part of the family tree
+whose main contribution is the powerful notion of channels as first class objects.
+</p>
+
+<h3 id="goroutines">
+Why goroutines instead of threads?</h3>
+<p>
+Goroutines are part of making concurrency easy to use. The idea, which has
+been around for a while, is to multiplex independently executing
+functions&mdash;coroutines, really&mdash;onto a set of threads.
+When a coroutine blocks, such as by calling a blocking system call,
+the run-time automatically moves other coroutines on the same operating
+system thread to a different, runnable thread so they won't be blocked.
+The programmer sees none of this, which is the point.
+The result, which we call goroutines, can be very cheap: unless they spend a lot of time
+in long-running system calls, they cost little more than the memory
+for the stack.
+</p>
+<p>
+To make the stacks small, Go's run-time uses segmented stacks. A newly
+minted goroutine is given a few kilobytes, which is almost always enough.
+When it isn't, the run-time allocates (and frees) extension segments automatically.
+The overhead averages about three cheap instructions per function call.
+It is practical to create hundreds of thousands of goroutines in the same
+address space. If goroutines were just threads, system resources would
+run out at a much smaller number.
+</p>
+
+<h3 id="atomic_maps">
+Why are map operations not defined to be atomic?</h3>
+
+<p>
+After long discussion it was decided that the typical use of maps did not require
+safe access from multiple threads, and in those cases where it did, the map was
+probably part of some larger data structure or computation that was already
+synchronized. Therefore requiring that all map operations grab a mutex would slow
+down most programs and add safety to few. This was not an easy decision,
+however, since it means uncontrolled map access can crash the program.
+</p>
+
+<p>
+The language does not preclude atomic map updates. When required, such
+as when hosting an untrusted program, the implementation could interlock
+map access.
+</p>
+
+
+<h2 id="types">Types</h2>
<h3 id="Is_Go_an_object-oriented_language">
Is Go an object-oriented language?</h3>
@@ -220,6 +447,130 @@ How do I get dynamic dispatch of methods?</h3>
The only way to have dynamically dispatched methods is through an
interface. Methods on structs or other types are always resolved statically.
+<h3 id="inheritance">
+Why is there no type inheritance?</h3>
+<p>
+Object-oriented programming, at least in the best-known languages,
+involves too much discussion of the relationships between types,
+relationships that often could be derived automatically. Go takes a
+different approach.
+</p>
+<p>
+Rather than requiring the programmer to declare ahead of time that two
+types are related, in Go a type automatically satisfies any interface
+that specifies a subset of its methods. Besides reducing the
+bookkeeping, this approach has real advantages. Types can satisfy
+many interfaces at once, without the complexities of traditional
+multiple inheritance.
+Interfaces can be very lightweight&mdash;having one or even zero methods
+in an interface can express useful concepts.
+Interfaces can be added after the fact if a new idea comes along
+or for testing&mdash;without annotating the original types.
+Because there are no explicit relationships between types
+and interfaces, there is no type hierarchy to manage or discuss.
+</p>
+<p>
+It's possible to use these ideas to construct something analogous to
+type-safe Unix pipes. For instance, see how <code>fmt.Fprintf</code>
+enables formatted printing to any output, not just a file, or how the
+<code>bufio</code> package can be completely separate from file I/O,
+or how the <code>crypto</code> packages stitch together block and
+stream ciphers. All these ideas stem from a single interface
+(<code>io.Writer</code>) representing a single method
+(<code>Write</code>). And that's only scratching the surface.
+</p>
+<p>
+It takes some getting used to but this implicit style of type
+dependency is one of the most exciting things about Go.
+</p>
+
+<h3 id="methods_on_basics">
+Why is <code>len</code> a function and not a method?</h3>
+<p>
+We debated this issue but decided
+implementing <code>len</code> and friends as functions was fine in practice and
+didn't complicate questions about the interface (in the Go type sense)
+of basic types.
+</p>
+
+<h3 id="overloading">
+Why does Go not support overloading of methods and operators?</h3>
+<p>
+Method dispatch is simplified if it doesn't need to do type matching as well.
+Experience with other languages told us that having a variety of
+methods with the same name but different signatures was occasionally useful
+but that it could also be confusing and fragile in practice. Matching only by name
+and requiring consistency in the types was a major simplifying decision
+in Go's type system.
+</p>
+<p>
+Regarding operator overloading, it seems more a convenience than an absolute
+requirement. Again, things are simpler without it.
+</p>
+
+
+<h2 id="values">Values</h2>
+
+<h3 id="conversions">
+Why does Go not provide implicit numeric conversions?</h3>
+<p>
+The convenience of automatic conversion between numeric types in C is
+outweighed by the confusion it causes. When is an expression unsigned?
+How big is the value? Does it overflow? Is the result portable, independent
+of the machine on which it executes?
+It also complicates the compiler; &ldquo;the usual arithmetic conversions&rdquo;
+are not easy to implement and inconsistent across architectures.
+For reasons of portability, we decided to make things clear and straightforward
+at the cost of some explicit conversions in the code.
+The definition of constants in Go&mdash;arbitrary precision values free
+of signedness and size annotations&mdash;ameliorates matters considerably,
+though.
+</p>
+<p>
+A related detail is that, unlike in C, <code>int</code> and <code>int64</code>
+are distinct types even if <code>int</code> is a 64-bit type. The <code>int</code>
+type is generic; if you care about how many bits an integer holds, Go
+encourages you to be explicit.
+</p>
+
+<h3 id="builtin_maps">
+Why are maps built in?</h3>
+<p>
+The same reason strings are: they are such a powerful and important data
+structure that providing one excellent implementation with syntactic support
+makes programming more pleasant. We believe that Go's implementation of maps
+is strong enough that it will serve for the vast majority of uses.
+If a specific application can benefit from a custom implementation, it's possible
+to write one but it will not be as convenient syntactically; this seems a reasonable tradeoff.
+</p>
+
+
+<h3 id="map_keys">
+Why don't maps allow structs and arrays as keys?</h3>
+<p>
+Map lookup requires an equality operator, which structs and arrays do not implement.
+They don't implement equality because equality is not well defined on such types;
+there are multiple considerations involving shallow vs. deep comparison, pointer vs.
+value comparison, how to deal with recursive structures, and so on.
+We may revisit this issue&mdash;and implementing equality for structs and arrays
+will not invalidate any existing programs&mdash;but without a clear idea of what
+equality of structs and arrays should mean, it was simpler to leave it out for now.
+</p>
+
+<h3 id="references">
+Why are maps, slices, and channels references while arrays are values?</h3>
+<p>
+There's a lot of history on that topic. Early on, maps and channels
+were syntactically pointers and it was impossible to declare or use a
+non-pointer instance. Also, we struggled with how arrays should work.
+Eventually we decided that the strict separation of pointers and
+values made the language harder to use. Introducing reference types,
+including slices to handle the reference form of arrays, resolved
+these issues. Reference types add some regrettable complexity to the
+language but they have a large effect on usability: Go became a more
+productive, comfortable language when they were introduced.
+</p>
+
<h2 id="Writing_Code">Writing Code</h2>
@@ -259,41 +610,284 @@ See the document
<a href="contribute.html">Contributing to the Go project</a>
for more information about how to proceed.
-<h3 id="Where_is_assert">
-Where is assert?</h3>
+
+<h2 id="Pointers">Pointers and Allocation</h2>
+
+<h3 id="pass_by_value">
+When are function parameters passed by value?</h3>
<p>
-Go doesn't provide assertions. They are undeniably convenient, but our
-experience has been that programmers use them as a crutch to avoid thinking
-about proper error handling and reporting. Proper error handling means that
-servers continue operation after non-fatal errors instead of crashing.
-Proper error reporting means that errors are direct and to the point,
-saving the programmer from interpreting a large crash trace. Precise
-errors are particularly important when the programmer seeing the errors is
-not familiar with the code.
+Everything in Go is passed by value. A function always gets a copy of the
+thing being passed, as if there were an assignment statement assigning the
+value to the parameter. For instance, copying a pointer value makes a copy of
+the pointer, not the data it points to.
+</p>
<p>
-The same arguments apply to the use of <code>assert()</code> in test programs. Proper
-error handling means letting other tests run after one has failed, so
-that the person debugging the failure gets a complete picture of what is
-wrong. It is more useful for a test to report that
-<code>isPrime</code> gives the wrong answer for 2, 3, 5, and 7 (or for
-2, 4, 8, and 16) than to report that <code>isPrime</code> gives the wrong
-answer for 2 and therefore no more tests were run. The programmer who
-triggers the test failure may not be familiar with the code that fails.
-Time invested writing a good error message now pays off later when the
-test breaks.
+Map and slice values behave like pointers; they are descriptors that
+contain pointers to the underlying map or slice data. Copying a map or
+slice value doesn't copy the data it points to. Copying an interface value
+makes a copy of the thing stored in the interface value. If the interface
+value holds a struct, copying the interface value makes a copy of the
+struct. If the interface value holds a pointer, copying the interface value
+makes a copy of the pointer, but again not the data it points to.
+</p>
+
+<h3 id="methods_on_values_or_pointers">
+Should I define methods on values or pointers?</h3>
+
+<pre>
+func (s *MyStruct) someMethod() { } // method on pointer
+func (s MyStruct) someMethod() { } // method on value
+</pre>
<p>
-In testing, if the amount of extra code required to write
-good errors seems repetitive and overwhelming, it might work better as a
-table-driven test instead.
-Go has excellent support for data structure literals.
+When defining a method on a type, the receiver (<code>s</code> in the above
+example) behaves exactly is if it were an argument to the method. Define the
+method on a pointer type if you need the method to modify the data the receiver
+points to. Otherwise, it is often cleaner to define the method on a value type.
+</p>
+
+<h3 id="new_and_make">
+What's the difference between new and make?</h3>
<p>
-We understand that this is a point of contention. There are many things in
-the Go language and libraries that differ from modern practices, simply
-because we feel it's sometimes worth trying a different approach.
+In short: <code>new</code> allocates memory, <code>make</code> initializes
+the slice, map, and channel types.
+</p>
+
+<p>
+See the <a href="/doc/effective_go.html#allocation_new">relevant section
+of Effective Go</a> for more details.
+</p>
+
+<h3 id="q_int_sizes">
+Why is <code>int</code> 32 bits on 64 bit machines?</h3>
+
+<p>
+The size of <code>int</code> and <code>float</code> is implementation-specific.
+The 64 bit Go compilers (both 6g and gccgo) use a 32 bit representation for
+both <code>int</code> and <code>float</code>. Code that relies on a particular
+size of value should use an explicitly sized type, like <code>int64</code> or
+<code>float64</code>.
+</p>
+
+<h2 id="Concurrency">Concurrency</h2>
+
+<h3 id="What_operations_are_atomic_What_about_mutexes">
+What operations are atomic? What about mutexes?</h3>
+
+<p>
+We haven't fully defined it all yet, but some details about atomicity are
+available in the <a href="go_mem.html">Go Memory Model specification</a>.
+</p>
+
+<p>
+Regarding mutexes, the <a href="/pkg/sync">sync</a>
+package implements them, but we hope Go programming style will
+encourage people to try higher-level techniques. In particular, consider
+structuring your program so that only one goroutine at a time is ever
+responsible for a particular piece of data.
+</p>
+
+<p>
+Do not communicate by sharing memory. Instead, share memory by communicating.
+</p>
+
+<p>
+See the <a href="/doc/codewalk/sharemem/">Share Memory By Communicating</a> code walk and its <a href="http://blog.golang.org/2010/07/share-memory-by-communicating.html">associated article</a> for a detailed discussion of this concept.
+</p>
+
+<h3 id="Why_no_multi_CPU">
+Why doesn't my multi-goroutine program use multiple CPUs?</h3>
+
+<p>
+Under the gc compilers you must set <code>GOMAXPROCS</code> to allow the
+runtime to utilise more than one OS thread. Under <code>gccgo</code> an OS
+thread will be created for each goroutine, and <code>GOMAXPROCS</code> is
+effectively equal to the number of running goroutines.
+</p>
+
+<p>
+Programs that perform concurrent computation should benefit from an increase in
+<code>GOMAXPROCS</code>. (See the <a
+href="http://golang.org/pkg/runtime/#GOMAXPROCS">runtime package
+documentation</a>.)
+</p>
+
+<h3 id="Why_GOMAXPROCS">
+Why does using <code>GOMAXPROCS</code> &gt; 1 sometimes make my program
+slower?</h3>
+
+<p>
+(This is specific to the gc compilers. See above.)
+</p>
+
+<p>
+It depends on the nature of your program.
+Programs that contain several goroutines that spend a lot of time
+communicating on channels will experience performance degradation when using
+multiple OS threads. This is because of the significant context-switching
+penalty involved in sending data between threads.
+</p>
+
+<p>
+The Go runtime's scheduler is not as good as it needs to be. In future, it
+should recognise such cases and optimize its use of OS threads. For now,
+<code>GOMAXPROCS</code> should be set on a per-application basis.
+</p>
+
+
+<h2 id="Functions_methods">Functions and Methods</h2>
+
+<h3 id="different_method_sets">
+Why do T and *T have different method sets?</h3>
+
+<p>
+From the <a href="http://golang.org/doc/go_spec.html#Types">Go Spec</a>:
+</p>
+
+<blockquote>
+The method set of any other named type <code>T</code> consists of all methods
+with receiver type <code>T</code>. The method set of the corresponding pointer
+type <code>*T</code> is the set of all methods with receiver <code>*T</code> or
+<code>T</code> (that is, it also contains the method set of <code>T</code>).
+</blockquote>
+
+<p>
+If an interface value contains a pointer <code>*T</code>,
+a method call can obtain a value by dereferencing the pointer,
+but if an interface value contains a value <code>T</code>,
+there is no useful way for a method call to obtain a pointer.
+</p>
+
+<p>
+If not for this restriction, this code:
+</p>
+
+<pre>
+var buf bytes.Buffer
+io.Copy(buf, os.Stdin)
+</pre>
+
+<p>
+would copy standard input into a <i>copy</i> of <code>buf</code>,
+not into <code>buf</code> itself.
+This is almost never the desired behavior.
+</p>
+
+<h3 id="closures_and_goroutines">
+Why am I confused by the way my closures behave as goroutines?</h3>
+
+<p>
+Some confusion may arise when using closures with concurrency.
+Consider the following program:
+</p>
+
+<pre>
+func main() {
+ done := make(chan bool)
+
+ values = []string{ "a", "b", "c" }
+ for _, v := range values {
+ go func() {
+ fmt.Println(v)
+ done &lt;- true
+ }()
+ }
+
+ // wait for all goroutines to complete before exiting
+ for i := range values {
+ &lt;-done
+ }
+}
+</pre>
+
+<p>
+One might mistakenly expect to see <code>a, b, c</code> as the output.
+What you'll probably see instead is <code>c, c, c</code>. This is because
+each closure shares the same variable <code>v</code>. Each closure prints the
+value of <code>v</code> at the time <code>fmt.Println</code> is executed,
+rather than the value of <code>v</code> when the goroutine was launched.
+</p>
+
+<p>
+To bind the value of <code>v</code> to each closure as they are launched, one
+could modify the inner loop to read:
+</p>
+
+<pre>
+ for _, v := range values {
+ go func(<b>u</b>) {
+ fmt.Println(<b>u</b>)
+ done &lt;- true
+ }(<b>v</b>)
+ }
+</pre>
+
+<p>
+In this example, the value of <code>v</code> is passed as an argument to the
+anonymous function. That value is then accessible inside the function as
+the variable <code>u</code>.
+</p>
+
+<h2 id="Control_flow">Control flow</h2>
+
+<h3 id="Does_Go_have_a_ternary_form">
+Does Go have the <code>?:</code> operator?</h3>
+
+<p>
+There is no ternary form in Go. You may use the following to achieve the same
+result:
+</p>
+
+<pre>
+if expr {
+ n = trueVal
+} else {
+ n = falseVal
+}
+</pre>
+
+<h2 id="Packages_Testing">Packages and Testing</h2>
+
+<h3 id="How_do_I_create_a_multifile_package">
+How do I create a multifile package?</h3>
+
+<p>
+Put all the source files for the package in a directory by themselves.
+Source files can refer to items from different files at will; there is
+no need for forward declarations or a header file.
+</p>
+
+<p>
+Other than being split into multiple files, the package will compile and test
+just like a single-file package.
+</p>
+
+<h3 id="How_do_I_write_a_unit_test">
+How do I write a unit test?</h3>
+
+<p>
+Create a new file ending in <code>_test.go</code> in the same directory
+as your package sources. Inside that file, <code>import "testing"</code>
+and write functions of the form
+</p>
+
+<pre>
+func TestFoo(t *testing.T) {
+ ...
+}
+</pre>
+
+<p>
+Run <code>gotest</code> in that directory.
+That script finds the <code>Test</code> functions,
+builds a test binary, and runs it.
+</p>
+
+<p>See the <a href="/doc/code.html">How to Write Go Code</a> document for more details.</p>
+
<h2 id="Implementation">Implementation</h2>
@@ -368,3 +962,143 @@ isn't fast enough yet (even if it were, taking care not to generate unnecessary
garbage can have a huge effect).
</p>
+
+<h2 id="change_from_c">Changes from C</h2>
+
+<h3 id="different_syntax">
+Why is the syntax so different from C?</h3>
+<p>
+Other than declaration syntax, the differences are not major and stem
+from two desires. First, the syntax should feel light, without too
+many mandatory keywords, repetition, or arcana. Second, the language
+has been designed to be easy to analyze
+and can be parsed without a symbol table. This makes it much easier
+to build tools such as debuggers, dependency analyzers, automated
+documentation extractors, IDE plug-ins, and so on. C and its
+descendants are notoriously difficult in this regard.
+</p>
+
+<h3 id="declarations_backwards">
+Why are declarations backwards?</h3>
+<p>
+They're only backwards if you're used to C. In C, the notion is that a
+variable is declared like an expression denoting its type, which is a
+nice idea, but the type and expression grammars don't mix very well and
+the results can be confusing; consider function pointers. Go mostly
+separates expression and type syntax and that simplifies things (using
+prefix <code>*</code> for pointers is an exception that proves the rule). In C,
+the declaration
+</p>
+<pre>
+ int* a, b;
+</pre>
+<p>
+declares <code>a</code> to be a pointer but not <code>b</code>; in Go
+</p>
+<pre>
+ var a, b *int;
+</pre>
+<p>
+declares both to be pointers. This is clearer and more regular.
+Also, the <code>:=</code> short declaration form argues that a full variable
+declaration should present the same order as <code>:=</code> so
+</p>
+<pre>
+ var a uint64 = 1;
+</pre>
+has the same effect as
+<pre>
+ a := uint64(1);
+</pre>
+<p>
+Parsing is also simplified by having a distinct grammar for types that
+is not just the expression grammar; keywords such as <code>func</code>
+and <code>chan</code> keep things clear.
+</p>
+
+<p>
+See the <a href="http://blog.golang.org/2010/07/gos-declaration-syntax.html">Go's Declaration Syntax</a> article for more details.
+</p>
+
+<h3 id="no_pointer_arithmetic">
+Why is there no pointer arithmetic?</h3>
+<p>
+Safety. Without pointer arithmetic it's possible to create a
+language that can never derive an illegal address that succeeds
+incorrectly. Compiler and hardware technology have advanced to the
+point where a loop using array indices can be as efficient as a loop
+using pointer arithmetic. Also, the lack of pointer arithmetic can
+simplify the implementation of the garbage collector.
+</p>
+
+<h3 id="inc_dec">
+Why are <code>++</code> and <code>--</code> statements and not expressions? And why postfix, not prefix?</h3>
+<p>
+Without pointer arithmetic, the convenience value of pre- and postfix
+increment operators drops. By removing them from the expression
+hierarchy altogether, expression syntax is simplified and the messy
+issues around order of evaluation of <code>++</code> and <code>--</code>
+(consider <code>f(i++)</code> and <code>p[i] = q[++i]</code>)
+are eliminated as well. The simplification is
+significant. As for postfix vs. prefix, either would work fine but
+the postfix version is more traditional; insistence on prefix arose
+with the STL, a library for a language whose name contains, ironically, a
+postfix increment.
+</p>
+
+<h3 id="semicolons">
+Why are there braces but no semicolons? And why can't I put the opening
+brace on the next line?</h3>
+<p>
+Go uses brace brackets for statement grouping, a syntax familiar to
+programmers who have worked with any language in the C family.
+Semicolons, however, are for parsers, not for people, and we wanted to
+eliminate them as much as possible. To achieve this goal, Go borrows
+a trick from BCPL: the semicolons that separate statements are in the
+formal grammar but are injected automatically, without lookahead, by
+the lexer at the end of any line that could be the end of a statement.
+This works very well in practice but has the effect that it forces a
+brace style. For instance, the opening brace of a function cannot
+appear on a line by itself.
+</p>
+<p>
+Some have argued that the lexer should do lookahead to permit the
+brace to live on the next line. We disagree. Since Go code is meant
+to be formatted automatically by
+<a href="http://golang.org/cmd/gofmt/"><code>gofmt</code></a>,
+<i>some</i> style must be chosen. That style may differ from what
+you've used in C or Java, but Go is a new language and
+<code>gofmt</code>'s style is as good as any other. More
+important&mdash;much more important&mdash;the advantages of a single,
+programmatically mandated format for all Go programs greatly outweigh
+any perceived disadvantages of the particular style.
+Note too that Go's style means that an interactive implementation of
+Go can use the standard syntax one line at a time without special rules.
+</p>
+
+<h3 id="garbage_collection">
+Why do garbage collection? Won't it be too expensive?</h3>
+<p>
+One of the biggest sources of bookkeeping in systems programs is
+memory management. We feel it's critical to eliminate that
+programmer overhead, and advances in garbage collection
+technology in the last few years give us confidence that we can
+implement it with low enough overhead and no significant
+latency. (The current implementation is a plain mark-and-sweep
+collector but a replacement is in the works.)
+</p>
+<p>
+Another point is that a large part of the difficulty of concurrent
+and multi-threaded programming is memory management;
+as objects get passed among threads it becomes cumbersome
+to guarantee they become freed safely.
+Automatic garbage collection makes concurrent code far easier to write.
+Of course, implementing garbage collection in a concurrent environment is
+itself a challenge, but meeting it once rather than in every
+program helps everyone.
+</p>
+<p>
+Finally, concurrency aside, garbage collection makes interfaces
+simpler because they don't need to specify how memory is managed across them.
+</p>
+
diff --git a/doc/go_for_cpp_programmers.html b/doc/go_for_cpp_programmers.html
index a2291715c..fae2ec44e 100644
--- a/doc/go_for_cpp_programmers.html
+++ b/doc/go_for_cpp_programmers.html
@@ -198,7 +198,7 @@ the <code>else</code>, causing a syntax error.
Since semicolons do end statements, you may continue using them as in
C++. However, that is not the recommended style. Idiomatic Go code
omits unnecessary semicolons, which in practice is all of them other
-than the initial <for> loop clause and cases where you want several
+than the initial <code>for</code> loop clause and cases where you want several
short statements on a single line.
<p>
@@ -668,7 +668,7 @@ func manager(ch chan cmd) {
var val int = 0
for {
c := &lt;- ch
- if c.get { c.val = val ch &lt;- c }
+ if c.get { c.val = val; ch &lt;- c }
else { val = c.val }
}
}
diff --git a/doc/go_lang_faq.html b/doc/go_lang_faq.html
deleted file mode 100644
index b8deb1534..000000000
--- a/doc/go_lang_faq.html
+++ /dev/null
@@ -1,491 +0,0 @@
-<!-- Language Design FAQ -->
-
-<h2 id="origins">Origins</h2>
-
-<h3 id="history">
-What is the history of the project?</h3>
-<p>
-Robert Griesemer, Rob Pike and Ken Thompson started sketching the
-goals for a new language on the white board on September 21, 2007.
-Within a few days the goals had settled into a plan to do something
-and a fair idea of what it would be. Design continued part-time in
-parallel with unrelated work. By January 2008, Ken had started work
-on a compiler with which to explore ideas; it generated C code as its
-output. By mid-year the language had become a full-time project and
-had settled enough to attempt a production compiler. In May 2008,
-Ian Taylor independently started on a GCC front end for Go using the
-draft specification. Russ Cox joined in late 2008 and helped move the language
-and libraries from prototype to reality.
-</p>
-
-<p>
-Many others have contributed ideas, discussions, and code.
-</p>
-
-<h3 id="creating_a_new_language">
-Why are you creating a new language?</h3>
-<p>
-Go was born out of frustration with existing languages and
-environments for systems programming. Programming had become too
-difficult and the choice of languages was partly to blame. One had to
-choose either efficient compilation, efficient execution, or ease of
-programming; all three were not available in the same mainstream
-language. Programmers who could were choosing ease over
-safety and efficiency by moving to dynamically typed languages such as
-Python and JavaScript rather than C++ or, to a lesser extent, Java.
-</p>
-<p>
-Go is an attempt to combine the ease of programming of an interpreted,
-dynamically typed
-language with the efficiency and safety of a statically typed, compiled language.
-It also aims to be modern, with support for networked and multicore
-computing. Finally, it is intended to be <i>fast</i>: it should take
-at most a few seconds to build a large executable on a single computer.
-To meet these goals required addressing a number of
-linguistic issues: an expressive but lightweight type system;
-concurrency and garbage collection; rigid dependency specification;
-and so on. These cannot be addressed well by libraries or tools; a new
-language was called for.
-</p>
-
-
-<h3 id="ancestors">
-What are Go's ancestors?</h3>
-<p>
-Go is mostly in the C family (basic syntax),
-with significant input from the Pascal/Modula/Oberon
-family (declarations, packages),
-plus some ideas from languages
-inspired by Tony Hoare's CSP,
-such as Newsqueak and Limbo (concurrency).
-However, it is a new language across the board.
-In every respect the language was designed by thinking
-about what programmers do and how to make programming, at least the
-kind of programming we do, more effective, which means more fun.
-</p>
-
-<h3 id="principles">
-What are the guiding principles in the design?</h3>
-<p>
-Programming today involves too much bookkeeping, repetition, and
-clerical work. As Dick Gabriel says, &ldquo;Old programs read
-like quiet conversations between a well-spoken research worker and a
-well-studied mechanical colleague, not as a debate with a compiler.
-Who'd have guessed sophistication bought such noise?&rdquo;
-The sophistication is worthwhile&mdash;no one wants to go back to
-the old languages&mdash;but can it be more quietly achieved?
-</p>
-<p>
-Go attempts to reduce the amount of typing in both senses of the word.
-Throughout its design, we have tried to reduce clutter and
-complexity. There are no forward declarations and no header files;
-everything is declared exactly once. Initialization is expressive,
-automatic, and easy to use. Syntax is clean and light on keywords.
-Stuttering (<code>foo.Foo* myFoo = new(foo.Foo)</code>) is reduced by
-simple type derivation using the <code>:=</code>
-declare-and-initialize construct. And perhaps most radically, there
-is no type hierarchy: types just <i>are</i>, they don't have to
-announce their relationships. These simplifications allow Go to be
-expressive yet comprehensible without sacrificing, well, sophistication.
-</p>
-<p>
-Another important principle is to keep the concepts orthogonal.
-Methods can be implemented for any type; structures represent data while
-interfaces represent abstraction; and so on. Orthogonality makes it
-easier to understand what happens when things combine.
-</p>
-
-
-<h2 id="change_from_c">Changes from C</h2>
-
-<h3 id="different_syntax">
-Why is the syntax so different from C?</h3>
-<p>
-Other than declaration syntax, the differences are not major and stem
-from two desires. First, the syntax should feel light, without too
-many mandatory keywords, repetition, or arcana. Second, the language
-has been designed to be easy to analyze
-and can be parsed without a symbol table. This makes it much easier
-to build tools such as debuggers, dependency analyzers, automated
-documentation extractors, IDE plug-ins, and so on. C and its
-descendants are notoriously difficult in this regard.
-</p>
-
-<h3 id="declarations_backwards">
-Why are declarations backwards?</h3>
-<p>
-They're only backwards if you're used to C. In C, the notion is that a
-variable is declared like an expression denoting its type, which is a
-nice idea, but the type and expression grammars don't mix very well and
-the results can be confusing; consider function pointers. Go mostly
-separates expression and type syntax and that simplifies things (using
-prefix <code>*</code> for pointers is an exception that proves the rule). In C,
-the declaration
-</p>
-<pre>
- int* a, b;
-</pre>
-<p>
-declares <code>a</code> to be a pointer but not <code>b</code>; in Go
-</p>
-<pre>
- var a, b *int;
-</pre>
-<p>
-declares both to be pointers. This is clearer and more regular.
-Also, the <code>:=</code> short declaration form argues that a full variable
-declaration should present the same order as <code>:=</code> so
-</p>
-<pre>
- var a uint64 = 1;
-</pre>
-has the same effect as
-<pre>
- a := uint64(1);
-</pre>
-<p>
-Parsing is also simplified by having a distinct grammar for types that
-is not just the expression grammar; keywords such as <code>func</code>
-and <code>chan</code> keep things clear.
-</p>
-
-<h3 id="no_pointer_arithmetic">
-Why is there no pointer arithmetic?</h3>
-<p>
-Safety. Without pointer arithmetic it's possible to create a
-language that can never derive an illegal address that succeeds
-incorrectly. Compiler and hardware technology have advanced to the
-point where a loop using array indices can be as efficient as a loop
-using pointer arithmetic. Also, the lack of pointer arithmetic can
-simplify the implementation of the garbage collector.
-</p>
-
-<h3 id="inc_dec">
-Why are <code>++</code> and <code>--</code> statements and not expressions? And why postfix, not prefix?</h3>
-<p>
-Without pointer arithmetic, the convenience value of pre- and postfix
-increment operators drops. By removing them from the expression
-hierarchy altogether, expression syntax is simplified and the messy
-issues around order of evaluation of <code>++</code> and <code>--</code>
-(consider <code>f(i++)</code> and <code>p[i] = q[++i]</code>)
-are eliminated as well. The simplification is
-significant. As for postfix vs. prefix, either would work fine but
-the postfix version is more traditional; insistence on prefix arose
-with the STL, a library for a language whose name contains, ironically, a
-postfix increment.
-</p>
-
-<h3 id="semicolons">
-Why are there braces but no semicolons? And why can't I put the opening
-brace on the next line?</h3>
-<p>
-Go uses brace brackets for statement grouping, a syntax familiar to
-programmers who have worked with any language in the C family.
-Semicolons, however, are for parsers, not for people, and we wanted to
-eliminate them as much as possible. To achieve this goal, Go borrows
-a trick from BCPL: the semicolons that separate statements are in the
-formal grammar but are injected automatically, without lookahead, by
-the lexer at the end of any line that could be the end of a statement.
-This works very well in practice but has the effect that it forces a
-brace style. For instance, the opening brace of a function cannot
-appear on a line by itself.
-</p>
-<p>
-Some have argued that the lexer should do lookahead to permit the
-brace to live on the next line. We disagree. Since Go code is meant
-to be formatted automatically by
-<a href="http://golang.org/cmd/gofmt/"><code>gofmt</code></a>,
-<i>some</i> style must be chosen. That style may differ from what
-you've used in C or Java, but Go is a new language and
-<code>gofmt</code>'s style is as good as any other. More
-important&mdash;much more important&mdash;the advantages of a single,
-programmatically mandated format for all Go programs greatly outweigh
-any perceived disadvantages of the particular style.
-Note too that Go's style means that an interactive implementation of
-Go can use the standard syntax one line at a time without special rules.
-</p>
-
-<h3 id="garbage_collection">
-Why do garbage collection? Won't it be too expensive?</h3>
-<p>
-One of the biggest sources of bookkeeping in systems programs is
-memory management. We feel it's critical to eliminate that
-programmer overhead, and advances in garbage collection
-technology in the last few years give us confidence that we can
-implement it with low enough overhead and no significant
-latency. (The current implementation is a plain mark-and-sweep
-collector but a replacement is in the works.)
-</p>
-<p>
-Another point is that a large part of the difficulty of concurrent
-and multi-threaded programming is memory management;
-as objects get passed among threads it becomes cumbersome
-to guarantee they become freed safely.
-Automatic garbage collection makes concurrent code far easier to write.
-Of course, implementing garbage collection in a concurrent environment is
-itself a challenge, but meeting it once rather than in every
-program helps everyone.
-</p>
-<p>
-Finally, concurrency aside, garbage collection makes interfaces
-simpler because they don't need to specify how memory is managed across them.
-</p>
-
-<h2 id="unicode_identifiers">What's up with Unicode identifiers?</h2>
-
-<p>
-It was important to us to extend the space of identifiers from the
-confines of ASCII. Go's rule&mdash;identifier characters must be
-letters or digits as defined by Unicode&mdash;is simple to understand
-and to implement but has restrictions. Combining characters are
-excluded by design, for instance.
-Until there
-is an agreed external definition of what an identifier might be,
-plus a definition of canonicalization of identifiers that guarantees
-no ambiguity, it seemed better to keep combining characters out of
-the mix. Thus we have a simple rule that can be expanded later
-without breaking programs, one that avoids bugs that would surely arise
-from a rule that admits ambiguous identifiers.
-</p>
-
-<p>
-On a related note, since an exported identifier must begin with an
-upper-case letter, identifiers created from &ldquo;letters&rdquo;
-in some languages can, by definition, not be exported. For now the
-only solution is to use something like <code>X日本語</code>, which
-is clearly unsatisfactory; we are considering other options. The
-case-for-visibility rule is unlikely to change however; it's one
-of our favorite features of Go.
-</p>
-
-<h2 id="absent_features">Absent features</h2>
-
-<h3 id="generics">
-Why does Go not have generic types?</h3>
-<p>
-Generics may well be added at some point. We don't feel an urgency for
-them, although we understand some programmers do.
-</p>
-<p>
-Generics are convenient but they come at a cost in
-complexity in the type system and run-time. We haven't yet found a
-design that gives value proportionate to the complexity, although we
-continue to think about it. Meanwhile, Go's built-in maps and slices,
-plus the ability to use the empty interface to construct containers
-(with explicit unboxing) mean in many cases it is possible to write
-code that does what generics would enable, if less smoothly.
-</p>
-<p>
-This remains an open issue.
-</p>
-
-<h3 id="exceptions">
-Why does Go not have exceptions?</h3>
-<p>
-We believe that coupling exceptions to a control
-structure, as in the <code>try-catch-finally</code> idiom, results in
-convoluted code. It also tends to encourage programmers to label
-too many ordinary errors, such as failing to open a file, as
-exceptional.
-</p>
-<p>
-Go takes a different approach. Instead of exceptions, it has a couple
-of built-in functions to signal and recover from truly exceptional
-conditions. The recovery mechanism is executed only as part of a
-function's state being torn down after an error, which is sufficient
-to handle catastrophe but requires no extra control structures and,
-when used well, can result in clean error-handling code.
-</p>
-
-<h3 id="assertions">
-Why does Go not have assertions?</h3>
-<p>
-This is answered in the general <a href="go_faq.html#Where_is_assert">FAQ</a>.
-</p>
-
-<h2 id="types">Types</h2>
-
-<h3 id="inheritance">
-Why is there no type inheritance?</h3>
-<p>
-Object-oriented programming, at least in the best-known languages,
-involves too much discussion of the relationships between types,
-relationships that often could be derived automatically. Go takes a
-different approach.
-</p>
-<p>
-Rather than requiring the programmer to declare ahead of time that two
-types are related, in Go a type automatically satisfies any interface
-that specifies a subset of its methods. Besides reducing the
-bookkeeping, this approach has real advantages. Types can satisfy
-many interfaces at once, without the complexities of traditional
-multiple inheritance.
-Interfaces can be very lightweight&mdash;having one or even zero methods
-in an interface can express useful concepts.
-Interfaces can be added after the fact if a new idea comes along
-or for testing&mdash;without annotating the original types.
-Because there are no explicit relationships between types
-and interfaces, there is no type hierarchy to manage or discuss.
-</p>
-<p>
-It's possible to use these ideas to construct something analogous to
-type-safe Unix pipes. For instance, see how <code>fmt.Fprintf</code>
-enables formatted printing to any output, not just a file, or how the
-<code>bufio</code> package can be completely separate from file I/O,
-or how the <code>crypto</code> packages stitch together block and
-stream ciphers. All these ideas stem from a single interface
-(<code>io.Writer</code>) representing a single method
-(<code>Write</code>). And that's only scratching the surface.
-</p>
-<p>
-It takes some getting used to but this implicit style of type
-dependency is one of the most exciting things about Go.
-</p>
-
-<h3 id="methods_on_basics">
-Why is <code>len</code> a function and not a method?</h3>
-<p>
-We debated this issue but decided
-implementing <code>len</code> and friends as functions was fine in practice and
-didn't complicate questions about the interface (in the Go type sense)
-of basic types.
-</p>
-
-<h3 id="overloading">
-Why does Go not support overloading of methods and operators?</h3>
-<p>
-Method dispatch is simplified if it doesn't need to do type matching as well.
-Experience with other languages told us that having a variety of
-methods with the same name but different signatures was occasionally useful
-but that it could also be confusing and fragile in practice. Matching only by name
-and requiring consistency in the types was a major simplifying decision
-in Go's type system.
-</p>
-<p>
-Regarding operator overloading, it seems more a convenience than an absolute
-requirement. Again, things are simpler without it.
-</p>
-
-<h2 id="values">Values</h2>
-
-<h3 id="conversions">
-Why does Go not provide implicit numeric conversions?</h3>
-<p>
-The convenience of automatic conversion between numeric types in C is
-outweighed by the confusion it causes. When is an expression unsigned?
-How big is the value? Does it overflow? Is the result portable, independent
-of the machine on which it executes?
-It also complicates the compiler; &ldquo;the usual arithmetic conversions&rdquo;
-are not easy to implement and inconsistent across architectures.
-For reasons of portability, we decided to make things clear and straightforward
-at the cost of some explicit conversions in the code.
-The definition of constants in Go&mdash;arbitrary precision values free
-of signedness and size annotations&mdash;ameliorates matters considerably,
-though.
-</p>
-<p>
-A related detail is that, unlike in C, <code>int</code> and <code>int64</code>
-are distinct types even if <code>int</code> is a 64-bit type. The <code>int</code>
-type is generic; if you care about how many bits an integer holds, Go
-encourages you to be explicit.
-</p>
-
-<h3 id="builtin_maps">
-Why are maps built in?</h3>
-<p>
-The same reason strings are: they are such a powerful and important data
-structure that providing one excellent implementation with syntactic support
-makes programming more pleasant. We believe that Go's implementation of maps
-is strong enough that it will serve for the vast majority of uses.
-If a specific application can benefit from a custom implementation, it's possible
-to write one but it will not be as convenient syntactically; this seems a reasonable tradeoff.
-</p>
-
-
-<h3 id="map_keys">
-Why don't maps allow structs and arrays as keys?</h3>
-<p>
-Map lookup requires an equality operator, which structs and arrays do not implement.
-They don't implement equality because equality is not well defined on such types;
-there are multiple considerations involving shallow vs. deep comparison, pointer vs.
-value comparison, how to deal with recursive structures, and so on.
-We may revisit this issue&mdash;and implementing equality for structs and arrays
-will not invalidate any existing programs&mdash;but without a clear idea of what
-equality of structs and arrays should mean, it was simpler to leave it out for now.
-</p>
-
-<h3 id="references">
-Why are maps, slices, and channels references while arrays are values?</h3>
-<p>
-There's a lot of history on that topic. Early on, maps and channels
-were syntactically pointers and it was impossible to declare or use a
-non-pointer instance. Also, we struggled with how arrays should work.
-Eventually we decided that the strict separation of pointers and
-values made the language harder to use. Introducing reference types,
-including slices to handle the reference form of arrays, resolved
-these issues. Reference types add some regrettable complexity to the
-language but they have a large effect on usability: Go became a more
-productive, comfortable language when they were introduced.
-</p>
-
-<h2 id="concurrency">Concurrency</h2>
-
-<h3 id="csp">
-Why build concurrency on the ideas of CSP?</h3>
-<p>
-Concurrency and multi-threaded programming have a reputation
-for difficulty. We believe the problem is due partly to complex
-designs such as pthreads and partly to overemphasis on low-level details
-such as mutexes, condition variables, and even memory barriers.
-Higher-level interfaces enable much simpler code, even if there are still
-mutexes and such under the covers.
-</p>
-<p>
-One of the most successful models for providing high-level linguistic support
-for concurrency comes from Hoare's Communicating Sequential Processes, or CSP.
-Occam and Erlang are two well known languages that stem from CSP.
-Go's concurrency primitives derive from a different part of the family tree
-whose main contribution is the powerful notion of channels as first class objects.
-</p>
-
-<h3 id="goroutines">
-Why goroutines instead of threads?</h3>
-<p>
-Goroutines are part of making concurrency easy to use. The idea, which has
-been around for a while, is to multiplex independently executing
-functions&mdash;coroutines, really&mdash;onto a set of threads.
-When a coroutine blocks, such as by calling a blocking system call,
-the run-time automatically moves other coroutines on the same operating
-system thread to a different, runnable thread so they won't be blocked.
-The programmer sees none of this, which is the point.
-The result, which we call goroutines, can be very cheap: unless they spend a lot of time
-in long-running system calls, they cost little more than the memory
-for the stack.
-</p>
-<p>
-To make the stacks small, Go's run-time uses segmented stacks. A newly
-minted goroutine is given a few kilobytes, which is almost always enough.
-When it isn't, the run-time allocates (and frees) extension segments automatically.
-The overhead averages about three cheap instructions per function call.
-It is practical to create hundreds of thousands of goroutines in the same
-address space. If goroutines were just threads, system resources would
-run out at a much smaller number.
-</p>
-
-<h3 id="atomic_maps">
-Why are map operations not defined to be atomic?</h3>
-
-<p>
-After long discussion it was decided that the typical use of maps did not require
-safe access from multiple threads, and in those cases where it did, the map was
-probably part of some larger data structure or computation that was already
-synchronized. Therefore requiring that all map operations grab a mutex would slow
-down most programs and add safety to few. This was not an easy decision,
-however, since it means uncontrolled map access can crash the program.
-</p>
-
-<p>
-The language does not preclude atomic map updates. When required, such
-as when hosting an untrusted program, the implementation could interlock
-map access.
-</p>
diff --git a/doc/go_learning.html b/doc/go_learning.html
deleted file mode 100644
index 072d047f0..000000000
--- a/doc/go_learning.html
+++ /dev/null
@@ -1,141 +0,0 @@
-<!-- title Go Resources -->
-<!-- subtitle Go documents and learning materials -->
-
-<h2 id="about">Recommendations</h2>
-<p>
-If you're new to Go, we recommend following the
-<a href="go_tutorial.html">tutorial</a> while consulting the
-<a href="go_spec.html">language spec</a>.
-Then read <a href="effective_go.html">Effective Go</a>, as it addresses many
-common beginner questions.
-</p>
-
-<h2 id="reference">Reference Materials</h2>
-<p>Keep these under your pillow.</p>
-
-<h3 id="pkg"><a href="/pkg/">Package Documentation</a></h3>
-<p>
-The built-in documentation for the Go standard library.
-</p>
-
-<h3 id="pkg"><a href="/cmd/">Command Documentation</a></h3>
-<p>
-The built-in documentation for the Go tools.
-</p>
-
-<h3 id="spec"><a href="go_spec.html">Language Specification</a></h3>
-<p>
-The official Go Language specification.
-</p>
-
-<h3 id="go_mem"><a href="go_mem.html">The Go Memory Model</a></h3>
-<p>
-A document that specifies the conditions under which reads of a variable in
-one goroutine can be guaranteed to observe values produced by writes to the
-same variable in a different goroutine.
-</p>
-
-<h2 id="tutorials">Tutorials</h2>
-
-<h3 id="orig_tutorial"><a href="go_tutorial.html">A Tutorial for the Go Programming Language</a></h3>
-<p>
-The first tutorial. An introductory text that touches upon several core
-concepts: syntax, types, allocation, constants, I/O, sorting, printing,
-goroutines, and channels.
-</p>
-
-<h3 id="effective_go"><a href="effective_go.html">Effective Go</a></h3>
-<p>
-A document that gives tips for writing clear, idiomatic Go code.
-A must read for any new Go programmer. It augments the tutorial and
-the language spec, both of which should be read first.
-</p>
-
-<h3 id="codelab_wiki"><a href="codelab/wiki/">Codelab: Writing Web Applications</a></h3>
-<p>
-This codelab takes the reader through the creation of a simple wiki web
-application. It touches on structs, methods, file I/O, http, regular expressions,
-and closures.
-</p>
-
-<h3 id="go_for_cpp_programmers"><a href="go_for_cpp_programmers.html">Go for C++ Programmers</a></h3>
-<p>
-An introduction to Go for C++ programmers.
-</p>
-
-<h3 id="code"><a href="code.html">How to write Go code</a></h3>
-<p>
-How to write a new package and how to test code.
-</p>
-
-<h2 id="faqs">Frequently Asked Questions</h2>
-
-<h3 id="go_faq"><a href="go_faq.html">Go FAQ</a></h3>
-<p>
-Answers to common questions about Go.
-</p>
-
-<h3 id="go_lang_faq"><a href="go_lang_faq.html">Language Design FAQ</a></h3>
-<p>
-Answers to common questions about the design decisions behind Go.
-</p>
-
-<h3 id="go_programming_faq"><a href="go_programming_faq.html">Programming FAQ</a></h3>
-<p>
-Answers to common questions about programming with Go.
-</p>
-
-<h2 id="faqs">Development</h2>
-
-<h3 id="contibute"><a href="contribute.html">Contributing to the Go project</a></h3>
-<p>
-How to contribute changes to the Go project.
-</p>
-
-<h3 id="roadmap"><a href="devel/roadmap.html">Roadmap</a></h3>
-<p>
-Features and ideas being developed or discussed by the Go team.
-</p>
-
-<h3 id="release"><a href="devel/release.html">Release History</a></h3>
-<p>
-A summarization of the changes between tagged releases of Go.
-</p>
-
-<h2 id="videos">Videos</h2>
-
-<h3 id="techtalk"><a href="http://www.youtube.com/watch?v=rKnDgT73v8s">The Go Tech Talk</a></h3>
-<p>
-An hour-long talk delivered by Rob Pike at Google in October 2009.
-The language's first public introduction. (See the <a href="talks/go_talk-20091030.pdf">slides in PDF format</a>.) The language has changed since it was made,
-but it's still a good introduction.
-</p>
-
-
-<h3 id="gocoding_channel"><a href="http://www.youtube.com/gocoding">gocoding YouTube Channel</a></h3>
-<p>
-A YouTube channel that includes screencasts and other Go-related videos:
-</p>
-<ul>
-<li><a href="http://www.youtube.com/gocoding#p/u/0/jDWBJOXs_iI">Screencast: Writing Go Packages</a> - writing, building, and distributing Go packages.</li>
-</ul>
-
-<h3 id="promo_video"><a href="http://www.youtube.com/watch?v=wwoWei-GAPo">The Go Promo Video</a></h3>
-<p>
-A short promotional video featuring Russ Cox demonstrating Go's fast compiler.
-</p>
-
-<h2 id="blogs">Blog Posts</h2>
-<p>
-Articles about Go from external blogs.
-</p>
-
-<h3 id="blog_rsc"><a href="http://research.swtch.com/search/label/Go">Go articles at research!rsc</a></h3>
-<p>
-Posts labelled 'Go' by Russ Cox, one of the core Go developers.
-</p>
-
-<h3 id="blog_iant"><a href="http://www.airs.com/blog/archives/category/programming">Programming articles at Airs</a></h3>
-<p>
-Posts labelled 'Programming' by Ian Lance Taylor, one of the core Go developers.
-</p>
diff --git a/doc/go_mem.html b/doc/go_mem.html
index 33bce5f7a..da45a07d7 100644
--- a/doc/go_mem.html
+++ b/doc/go_mem.html
@@ -143,6 +143,35 @@ calling <code>hello</code> will print <code>"hello, world"</code>
at some point in the future (perhaps after <code>hello</code> has returned).
</p>
+<h3>Goroutine destruction</h3>
+
+<p>
+The exit of a goroutine is not guaranteed to happen before
+any event in the program. For example, in this program:
+</p>
+
+<pre>
+var a string
+
+func hello() {
+ go func() { a = "hello" }()
+ print(a)
+}
+</pre>
+
+<p>
+the assignment to <code>a</code> is not followed by
+any synchronization event, so it is not guaranteed to be
+observed by any other goroutine.
+In fact, an aggressive compiler might delete the entire <code>go</code> statement.
+</p>
+
+<p>
+If the effects of a goroutine must be observed by another goroutine,
+use a synchronization mechanism such as a lock or channel
+communication to establish a relative ordering.
+</p>
+
<h3>Channel communication</h3>
<p>
@@ -276,8 +305,9 @@ before the <i>n</i>+1'th call to <code>l.Lock</code>.
<h3>Once</h3>
<p>
-The <code>once</code> package provides a safe mechanism for
-initialization in the presence of multiple goroutines.
+The <code>sync</code> package provides a safe mechanism for
+initialization in the presence of multiple goroutines
+through the use of the <code>Once</code> type.
Multiple threads can execute <code>once.Do(f)</code> for a particular <code>f</code>,
but only one will run <code>f()</code>, and the other calls block
until <code>f()</code> has returned.
@@ -293,6 +323,7 @@ In this program:
<pre>
var a string
+var once sync.Once
func setup() {
a = "hello, world"
diff --git a/doc/go_programming_faq.html b/doc/go_programming_faq.html
deleted file mode 100644
index 3c4f0e1ba..000000000
--- a/doc/go_programming_faq.html
+++ /dev/null
@@ -1,307 +0,0 @@
-<!-- Programming FAQ -->
-
-<h2 id="Pointers">Pointers and Allocation</h2>
-
-<h3 id="pass_by_value">
-When are function paramters passed by value?</h3>
-
-<p>
-Everything in Go is passed by value. A function always gets a copy of the
-thing being passed, as if there were an assignment statement assigning the
-value to the parameter. For instance, copying a pointer value makes a copy of
-the pointer, not the data it points to.
-</p>
-
-<p>
-Map and slice values behave like pointers; they are descriptors that
-contain pointers to the underlying map or slice data. Copying a map or
-slice value doesn't copy the data it points to. Copying an interface value
-makes a copy of the thing stored in the interface value. If the interface
-value holds a struct, copying the interface value makes a copy of the
-struct. If the interface value holds a pointer, copying the interface value
-makes a copy of the pointer, but again not the data it points to.
-</p>
-
-<h3 id="methods_on_values_or_pointers">
-Should I define methods on values or pointers?</h3>
-
-<pre>
-func (s *MyStruct) someMethod() { } // method on pointer
-func (s MyStruct) someMethod() { } // method on value
-</pre>
-
-<p>
-When defining a method on a type, the receiver (<code>s</code> in the above
-example) behaves exactly is if it were an argument to the method. Define the
-method on a pointer type if you need the method to modify the data the receiver
-points to. Otherwise, it is often cleaner to define the method on a value type.
-</p>
-
-<h3 id="new_and_make">
-What's the difference between new and make?</h3>
-
-<p>
-In short: <code>new</code> allocates memory, <code>make</code> initializes
-the slice, map, and channel types.
-</p>
-
-<p>
-See the <a href="/doc/effective_go.html#allocation_new">relevant section
-of Effective Go</a> for more details.
-</p>
-
-<h3 id="64bit_machine_32bit_int">
-Why is <code>int</code> 32 bits on 64 bit machines?</h3>
-
-<p>
-The size of <code>int</code> and <code>float</code> is implementation-specific.
-The 64 bit Go compilers (both 6g and gccgo) use a 32 bit representation for
-both <code>int</code> and <code>float</code>. Code that relies on a particular
-size of value should use an explicitly sized type, like <code>int64</code> or
-<code>float64</code>.
-</p>
-
-<h2 id="Concurrent_programming">Concurrent programming</h2>
-
-<h3 id="What_operations_are_atomic_What_about_mutexes">
-What operations are atomic? What about mutexes?</h3>
-
-<p>
-We haven't fully defined it all yet, but some details about atomicity are
-available in the <a href="go_mem.html">Go Memory Model specification</a>.
-Also, some concurrency questions are answered in more detail in the <a
-href="go_lang_faq.html">language design FAQ</a>.
-</p>
-
-<p>
-Regarding mutexes, the <a href="/pkg/sync">sync</a>
-package implements them, but we hope Go programming style will
-encourage people to try higher-level techniques. In particular, consider
-structuring your program so that only one goroutine at a time is ever
-responsible for a particular piece of data.
-</p>
-
-<p>
-Do not communicate by sharing memory. Instead, share memory by communicating.
-</p>
-
-<h3 id="Why_no_multi_CPU">
-Why doesn't my multi-goroutine program use multiple CPUs?</h3>
-
-<p>
-Under the gc compilers you must set <code>GOMAXPROCS</code> to allow the
-runtime to utilise more than one OS thread. Under <code>gccgo</code> an OS
-thread will be created for each goroutine, and <code>GOMAXPROCS</code> is
-effectively equal to the number of running goroutines.
-</p>
-
-<p>
-Programs that perform concurrent computation should benefit from an increase in
-<code>GOMAXPROCS</code>. (See the <a
-href="http://golang.org/pkg/runtime/#GOMAXPROCS">runtime package
-documentation</a>.)
-</p>
-
-<h3 id="Why_GOMAXPROCS">
-Why does using <code>GOMAXPROCS</code> &gt; 1 sometimes make my program
-slower?</h3>
-
-<p>
-(This is specific to the gc compilers. See above.)
-</p>
-
-<p>
-It depends on the nature of your program.
-Programs that contain several goroutines that spend a lot of time
-communicating on channels will experience performance degradation when using
-multiple OS threads. This is because of the significant context-switching
-penalty involved in sending data between threads.
-</p>
-
-<p>
-The Go runtime's scheduler is not as good as it needs to be. In future, it
-should recognise such cases and optimize its use of OS threads. For now,
-<code>GOMAXPROCS</code> should be set on a per-application basis.
-</p>
-
-
-<h2 id="Functions_methods">Functions and Methods</h2>
-
-<h3 id="different_method_sets">
-Why do T and *T have different method sets?</h3>
-
-<p>
-From the <a href="http://golang.org/doc/go_spec.html#Types">Go Spec</a>:
-</p>
-
-<blockquote>
-The method set of any other named type <code>T</code> consists of all methods
-with receiver type <code>T</code>. The method set of the corresponding pointer
-type <code>*T</code> is the set of all methods with receiver <code>*T</code> or
-<code>T</code> (that is, it also contains the method set of <code>T</code>).
-</blockquote>
-
-<p>
-If an interface value contains a pointer <code>*T</code>,
-a method call can obtain a value by dereferencing the pointer,
-but if an interface value contains a value <code>T</code>,
-there is no useful way for a method call to obtain a pointer.
-</p>
-
-<p>
-If not for this restriction, this code:
-</p>
-
-<pre>
-var buf bytes.Buffer
-io.Copy(buf, os.Stdin)
-</pre>
-
-<p>
-would copy standard input into a <i>copy</i> of <code>buf</code>,
-not into <code>buf</code> itself.
-This is almost never the desired behavior.
-</p>
-
-<h3 id="closures_and_goroutines">
-Why am I confused by the way my closures behave as goroutines?</h3>
-
-<p>
-Some confusion may arise when using closures with concurrency.
-Consider the following program:
-</p>
-
-<pre>
-func main() {
- done := make(chan bool)
-
- values = []string{ "a", "b", "c" }
- for _, v := range values {
- go func() {
- fmt.Println(v)
- done &lt;- true
- }()
- }
-
- // wait for all goroutines to complete before exiting
- for i := range values {
- &lt;-done
- }
-}
-</pre>
-
-<p>
-One might mistakenly expect to see <code>a, b, c</code> as the output.
-What you'll probably see instead is <code>c, c, c</code>. This is because
-each closure shares the same variable <code>v</code>. Each closure prints the
-value of <code>v</code> at the time <code>fmt.Println</code> is executed,
-rather than the value of <code>v</code> when the goroutine was launched.
-</p>
-
-<p>
-To bind the value of <code>v</code> to each closure as they are launched, one
-could modify the inner loop to read:
-</p>
-
-<pre>
- for _, v := range values {
- go func(<b>u</b>) {
- fmt.Println(<b>u</b>)
- done &lt;- true
- }(<b>v</b>)
- }
-</pre>
-
-<p>
-In this example, the value of <code>v</code> is passed as an argument to the
-anonymous function. That value is then accessible inside the function as
-the variable <code>u</code>.
-</p>
-
-<h2 id="Control_flow">Control flow</h2>
-
-<h3 id="Does_Go_have_a_ternary_form">
-Does Go have the <code>?:</code> operator?</h3>
-
-<p>
-There is no ternary form in Go. You may use the following to achieve the same
-result:
-</p>
-
-<pre>
-if expr {
- n = trueVal
-} else {
- n = falseVal
-}
-</pre>
-
-<h2 id="Packages_Testing">Packages and Testing</h2>
-
-<h3 id="How_do_I_create_a_multifile_package">
-How do I create a multifile package?</h3>
-
-<p>
-Put all the source files for the package in a directory by themselves.
-Source files can refer to items from different files at will; there is
-no need for forward declarations or a header file.
-</p>
-
-<p>
-Other than being split into multiple files, the package will compile and test
-just like a single-file package.
-</p>
-
-<h3 id="How_do_I_write_a_unit_test">
-How do I write a unit test?</h3>
-
-<p>
-Create a new file ending in <code>_test.go</code> in the same directory
-as your package sources. Inside that file, <code>import "testing"</code>
-and write functions of the form
-</p>
-
-<pre>
-func TestFoo(t *testing.T) {
- ...
-}
-</pre>
-
-<p>
-Run <code>gotest</code> in that directory.
-That script finds the <code>Test</code> functions,
-builds a test binary, and runs it.
-</p>
-
-
-<h2 id="Data_structures">Data Structures</h2>
-
-<h3 id="nested_array_verbose"
->Why does the syntax for nested array literals seem overly verbose?</h3>
-
-<p>
-In Go, you must specify a 2-dimensional array literal like this:
-</p>
-
-<pre>
-var intArray = [4][4]int{
- [4]int{1, 2, 3, 4},
- [4]int{2, 4, 8, 16},
- [4]int{3, 9, 27, 81},
- [4]int{4, 16, 64, 256},
-}
-</pre>
-
-<p>
-It seems that the <code>[4]int</code> could be inferred, but in general it's
-hard to get this sort of thing right.
-</p>
-
-<p>
-Some of Go's designers had worked on other languages that derived types
-automatically in such expressions, but the special cases that arise can
-be messy, especially when interfaces, nil, constant conversions, and
-such are involved. It seemed better to require the full type
-information. That way there will be no surprises.
-</p>
-
diff --git a/doc/go_spec.html b/doc/go_spec.html
index f296c2a38..e1c7e90e2 100644
--- a/doc/go_spec.html
+++ b/doc/go_spec.html
@@ -1,5 +1,5 @@
<!-- title The Go Programming Language Specification -->
-<!-- subtitle Version of June 7, 2010 -->
+<!-- subtitle Version of January 7, 2011 -->
<!--
TODO
@@ -14,7 +14,6 @@ TODO
[ ] should string(1<<s) and float(1<<s) be valid?
[ ] should probably write something about evaluation order of statements even
though obvious
-[ ] specify iteration direction for range clause
[ ] review language on implicit dereferencing
[ ] clarify what it means for two functions to be "the same" when comparing them
-->
@@ -139,7 +138,7 @@ There are two forms of comments:
<ol>
<li>
<i>Line comments</i> start with the character sequence <code>//</code>
-and continue through the next newline. A line comment acts like a newline.
+and stop at the end of the line. A line comment acts like a newline.
</li>
<li>
<i>General comments</i> start with the character sequence <code>/*</code>
@@ -163,7 +162,7 @@ and delimiters</i>, and <i>literals</i>. <i>White space</i>, formed from
spaces (U+0020), horizontal tabs (U+0009),
carriage returns (U+000D), and newlines (U+000A),
is ignored except as it separates tokens
-that would otherwise combine into a single token. Also, a newline
+that would otherwise combine into a single token. Also, a newline or end of file
may trigger the insertion of a <a href="#Semicolons">semicolon</a>.
While breaking the input into tokens,
the next token is the longest sequence of characters that form a
@@ -527,9 +526,10 @@ A constant value is represented by an
<a href="#String_literals">string</a> literal,
an identifier denoting a constant,
a <a href="#Constant_expressions">constant expression</a>, or
-the result value of some built-in functions such as <code>unsafe.Sizeof</code>
-and <code>cap</code> or <code>len</code> applied to an array,
-<code>len</code> applied to a string constant,
+the result value of some built-in functions such as
+<code>unsafe.Sizeof</code> applied to any value,
+<code>cap</code> or <code>len</code> applied to
+<a href="#Length_and_capacity">some expressions</a>,
<code>real</code> and <code>imag</code> applied to a complex constant
and <code>cmplx</code> applied to numeric constants.
The boolean truth values are represented by the predeclared constants
@@ -590,13 +590,13 @@ for floating-point values, both the mantissa and exponent must be twice as large
<p>
A type determines the set of values and operations specific to values of that
type. A type may be specified by a (possibly qualified) <i>type name</i>
-(§<a href="#Qualified_identifier">Qualified identifier</a>, §<a href="#Type_declarations">Type declarations</a>) or a <i>type literal</i>,
+(§<a href="#Qualified_identifiers">Qualified identifier</a>, §<a href="#Type_declarations">Type declarations</a>) or a <i>type literal</i>,
which composes a new type from previously declared types.
</p>
<pre class="ebnf">
Type = TypeName | TypeLit | "(" Type ")" .
-TypeName = QualifiedIdent.
+TypeName = QualifiedIdent .
TypeLit = ArrayType | StructType | PointerType | FunctionType | InterfaceType |
SliceType | MapType | ChannelType .
</pre>
@@ -754,8 +754,8 @@ ElementType = Type .
The length is part of the array's type and must be a
<a href="#Constant_expressions">constant expression</a> that evaluates to a non-negative
integer value. The length of array <code>a</code> can be discovered
-using the built-in function <code>len(a)</code>, which is a
-compile-time constant. The elements can be indexed by integer
+using the built-in function <a href="#Length_and_capacity"><code>len(a)</code></a>.
+The elements can be indexed by integer
indices 0 through the <code>len(a)-1</code> (§<a href="#Indexes">Indexes</a>).
Array types are always one-dimensional but may be composed to form
multi-dimensional types.
@@ -785,7 +785,7 @@ SliceType = "[" "]" ElementType .
<p>
Like arrays, slices are indexable and have a length. The length of a
slice <code>s</code> can be discovered by the built-in function
-<code>len(s)</code>; unlike with arrays it may change during
+<a href="#Length_and_capacity"><code>len(s)</code></a>; unlike with arrays it may change during
execution. The elements can be addressed by integer indices 0
through <code>len(s)-1</code> (§<a href="#Indexes">Indexes</a>). The slice index of a
given element may be less than the index of the same element in the
@@ -804,18 +804,14 @@ the length of the slice and the length of the array beyond the slice;
a slice of length up to that capacity can be created by `slicing' a new
one from the original slice (§<a href="#Slices">Slices</a>).
The capacity of a slice <code>a</code> can be discovered using the
-built-in function <code>cap(a)</code> and the relationship between
-<code>len()</code> and <code>cap()</code> is:
+built-in function <a href="#Length_and_capacity"><code>cap(a)</code></a>.
</p>
-<pre>
-0 <= len(a) <= cap(a)
-</pre>
-
<p>
-The length and capacity of a <code>nil</code> slice
-are 0. A new, initialized slice value for a given element type <code>T</code> is
-made using the built-in function <code>make</code>, which takes a slice type
+A new, initialized slice value for a given element type <code>T</code> is
+made using the built-in function
+<a href="#Making_slices_maps_and_channels"><code>make</code></a>,
+which takes a slice type
and parameters specifying the length and optionally the capacity:
</p>
@@ -883,9 +879,10 @@ struct {
</pre>
<p>
-A field declared with a type but no explicit field name is an <i>anonymous field</i>.
+A field declared with a type but no explicit field name is an <i>anonymous field</i>
+(colloquially called an embedded field).
Such a field type must be specified as
-a type name <code>T</code> or as a pointer to a type name <code>*T</code>,
+a type name <code>T</code> or as a pointer to a non-interface type name <code>*T</code>,
and <code>T</code> itself may not be
a pointer type. The unqualified type name acts as the field name.
</p>
@@ -959,7 +956,7 @@ struct {
<p>
A pointer type denotes the set of all pointers to variables of a given
type, called the <i>base type</i> of the pointer.
-The value of an unitialized pointer is <code>nil</code>.
+The value of an uninitialized pointer is <code>nil</code>.
</p>
<pre class="ebnf">
@@ -976,7 +973,7 @@ BaseType = Type .
<p>
A function type denotes the set of all functions with the same parameter
-and result types. The value of an unitialized variable of function type
+and result types. The value of an uninitialized variable of function type
is <code>nil</code>.
</p>
@@ -995,15 +992,14 @@ must either all be present or all be absent. If present, each name
stands for one item (parameter or result) of the specified type; if absent, each
type stands for one item of that type. Parameter and result
lists are always parenthesized except that if there is exactly
-one unnamed result it may written as an unparenthesized type.
+one unnamed result it may be written as an unparenthesized type.
</p>
-<p>
-If the function's last parameter has a type prefixed with <code>...</code>,
-the function may be invoked with zero or more arguments for that parameter,
-each of which must be <a href="#Assignability">assignable</a>
-to the type that follows the <code>...</code>.
-Such a function is called <i>variadic</i>.
+<p>
+The final parameter in a function signature may have
+a type prefixed with <code>...</code>.
+A function with such a parameter is called <i>variadic</i> and
+may be invoked with zero or more arguments for that parameter.
</p>
<pre>
@@ -1026,7 +1022,7 @@ An interface type specifies a <a href="#Types">method set</a> called its <i>inte
A variable of interface type can store a value of any type with a method set
that is any superset of the interface. Such a type is said to
<i>implement the interface</i>.
-The value of an unitialized variable of interface type is <code>nil</code>.
+The value of an uninitialized variable of interface type is <code>nil</code>.
</p>
<pre class="ebnf">
@@ -1155,16 +1151,16 @@ map [string] interface {}
</pre>
<p>
-The number of elements is called the length and is never negative.
-The length of a map <code>m</code> can be discovered using the
-built-in function <code>len(m)</code> and may change during execution.
-Values may be added and removed
+The number of map elements is called its length.
+For a map <code>m</code>, it can be discovered using the
+built-in function <a href="#Length_and_capacity"><code>len(m)</code></a>
+and may change during execution. Values may be added and removed
during execution using special forms of <a href="#Assignments">assignment</a>.
</p>
<p>
A new, empty map value is made using the built-in
-function <code>make</code>, which takes the map type and an optional
-capacity hint as arguments:
+function <a href="#Making_slices_maps_and_channels"><code>make</code></a>,
+which takes the map type and an optional capacity hint as arguments:
</p>
<pre>
@@ -1331,9 +1327,9 @@ A value <code>x</code> is <i>assignable</i> to a variable of type <code>T</code>
<code>x</code>'s type is identical to <code>T</code>.
</li>
<li>
-<code>x</code>'s type <code>V</code> or <code>T</code> have identical
-<a href="#Types">underlying types</a> and <code>V</code> or <code>T</code>
-is not a named type.
+<code>x</code>'s type <code>V</code> and <code>T</code> have identical
+<a href="#Types">underlying types</a> and at least one of <code>V</code>
+or <code>T</code> is not a named type.
</li>
<li>
<code>T</code> is an interface type and
@@ -1342,7 +1338,7 @@ is not a named type.
<li>
<code>x</code> is a bidirectional channel value, <code>T</code> is a channel type,
<code>x</code>'s type <code>V</code> and <code>T</code> have identical element types,
-and <code>V</code> or <code>T</code> is not a named type.
+and at least one of <code>V</code> or <code>T</code> is not a named type.
</li>
<li>
<code>x</code> is the predeclared identifier <code>nil</code> and <code>T</code>
@@ -1496,8 +1492,8 @@ Zero value:
nil
Functions:
- cap close closed cmplx copy imag len make
- new panic print println real
+ append cap close closed cmplx copy imag len
+ make new panic print println real recover
</pre>
@@ -1665,7 +1661,7 @@ TypeSpec = identifier Type .
type IntArray [16]int
type (
- Point struct { x, y float }
+ Point struct { x, y float64 }
Polar Point
)
@@ -1835,7 +1831,7 @@ A function declaration binds an identifier to a function (§<a href="#Function_t
<pre class="ebnf">
FunctionDecl = "func" identifier Signature [ Body ] .
-Body = Block.
+Body = Block .
</pre>
<p>
@@ -1882,13 +1878,13 @@ Given type <code>Point</code>, the declarations
</p>
<pre>
-func (p *Point) Length() float {
- return Math.sqrt(p.x * p.x + p.y * p.y)
+func (p *Point) Length() float64 {
+ return math.Sqrt(p.x * p.x + p.y * p.y)
}
-func (p *Point) Scale(factor float) {
- p.x = p.x * factor
- p.y = p.y * factor
+func (p *Point) Scale(factor float64) {
+ p.x *= factor
+ p.y *= factor
}
</pre>
@@ -1910,7 +1906,7 @@ argument. For instance, the method <code>Scale</code> has type
</p>
<pre>
-(p *Point, factor float)
+func(p *Point, factor float64)
</pre>
<p>
@@ -1975,15 +1971,16 @@ a single expression or a key-value pair.
</p>
<pre class="ebnf">
-CompositeLit = LiteralType "{" [ ElementList [ "," ] ] "}" .
+CompositeLit = LiteralType LiteralValue .
LiteralType = StructType | ArrayType | "[" "..." "]" ElementType |
- SliceType | MapType | TypeName | "(" LiteralType ")" .
+ SliceType | MapType | TypeName .
+LiteralValue = "{" [ ElementList [ "," ] ] "}" .
ElementList = Element { "," Element } .
Element = [ Key ":" ] Value .
Key = FieldName | ElementIndex .
FieldName = identifier .
ElementIndex = Expression .
-Value = Expression .
+Value = Expression | LiteralValue .
</pre>
<p>
@@ -2028,8 +2025,8 @@ For struct literals the following rules apply:
Given the declarations
</p>
<pre>
-type Point struct { x, y, z float }
-type Line struct { p, q Point }
+type Point3D struct { x, y, z float64 }
+type Line struct { p, q Point3D }
</pre>
<p>
@@ -2037,8 +2034,8 @@ one may write
</p>
<pre>
-origin := Point{} // zero value for Point
-line := Line{origin, Point{y: -4, z: 12.3}} // zero value for line.q.x
+origin := Point3D{} // zero value for Point3D
+line := Line{origin, Point3D{y: -4, z: 12.3}} // zero value for line.q.x
</pre>
<p>
@@ -2061,7 +2058,7 @@ Taking the address of a composite literal (§<a href="#Address_operators">Addres
generates a unique pointer to an instance of the literal's value.
</p>
<pre>
-var pointer *Point = &amp;Point{y: 1000}
+var pointer *Point3D = &amp;Point3D{y: 1000}
</pre>
<p>
@@ -2098,11 +2095,23 @@ and is a shortcut for a slice operation applied to an array literal:
</pre>
<p>
+Within a composite literal of array, slice, or map type <code>T</code>,
+elements that are themselves composite literals may elide the respective
+literal type if it is identical to the element type of <code>T</code>.
+</p>
+
+<pre>
+[...]Point{{1.5, -3.5}, {0, 0}} // same as [...]Point{Point{1.5, -3.5}, Point{0, 0}}
+[][]int{{1, 2, 3}, {4, 5}} // same as [][]int{[]int{1, 2, 3}, []int{4, 5}}
+</pre>
+
+<p>
A parsing ambiguity arises when a composite literal using the
-TypeName form of the LiteralType appears in the condition of an
+TypeName form of the LiteralType appears between the
+<a href="#Keywords">keyword</a> and the opening brace of the block of an
"if", "for", or "switch" statement, because the braces surrounding
the expressions in the literal are confused with those introducing
-a block of statements. To resolve the ambiguity in this rare case,
+the block of statements. To resolve the ambiguity in this rare case,
the composite literal must appear within
parentheses.
</p>
@@ -2185,9 +2194,10 @@ PrimaryExpr =
Selector = "." identifier .
Index = "[" Expression "]" .
-Slice = "[" Expression ":" [ Expression ] "]" .
+Slice = "[" [ Expression ] ":" [ Expression ] "]" .
TypeAssertion = "." "(" Type ")" .
-Call = "(" [ ExpressionList [ "," ] ] ")" .
+Call = "(" [ ArgumentList [ "," ] ] ")" .
+ArgumentList = ExpressionList [ "..." ] .
</pre>
@@ -2200,7 +2210,7 @@ Point{1, 2}
m["foo"]
s[i : j + 1]
obj.color
-Math.sin
+math.Sin
f.p[i].x()
</pre>
@@ -2217,8 +2227,7 @@ x.f
<p>
denotes the field or method <code>f</code> of the value denoted by <code>x</code>
-(or of <code>*x</code> if
-<code>x</code> is of pointer type). The identifier <code>f</code>
+(or sometimes <code>*x</code>; see below). The identifier <code>f</code>
is called the (field or method)
<i>selector</i>; it must not be the <a href="#Blank_identifier">blank identifier</a>.
The type of the expression is the type of <code>f</code>.
@@ -2261,16 +2270,13 @@ In all other cases, <code>x.f</code> is illegal.
</li>
</ol>
<p>
-Selectors automatically dereference pointers.
-If <code>x</code> is of pointer type, <code>x.y</code>
-is shorthand for <code>(*x).y</code>; if <code>y</code>
-is also of pointer type, <code>x.y.z</code> is shorthand
+Selectors automatically dereference pointers to structs.
+If <code>x</code> is a pointer to a struct, <code>x.y</code>
+is shorthand for <code>(*x).y</code>; if the field <code>y</code>
+is also a pointer to a struct, <code>x.y.z</code> is shorthand
for <code>(*(*x).y).z</code>, and so on.
-If <code>*x</code> is of pointer type, dereferencing
-must be explicit;
-only one level of automatic dereferencing is provided.
-For an <code>x</code> of type <code>T</code> containing an
-anonymous field declared as <code>*A</code>,
+If <code>x</code> contains an anonymous field of type <code>*A</code>,
+where <code>A</code> is also a struct type,
<code>x.f</code> is a shortcut for <code>(*x.A).f</code>.
</p>
<p>
@@ -2428,14 +2434,14 @@ For a string, array, or slice <code>a</code>, the primary expression
</p>
<pre>
-a[lo : hi]
+a[low : high]
</pre>
<p>
-constructs a substring or slice. The index expressions <code>lo</code> and
-<code>hi</code> select which elements appear in the result. The result has
+constructs a substring or slice. The index expressions <code>low</code> and
+<code>high</code> select which elements appear in the result. The result has
indexes starting at 0 and length equal to
-<code>hi</code>&nbsp;-&nbsp;<code>lo</code>.
+<code>high</code>&nbsp;-&nbsp;<code>low</code>.
After slicing the array <code>a</code>
</p>
@@ -2455,19 +2461,28 @@ s[2] == 4
</pre>
<p>
-For convenience, the <code>hi</code> expression may be omitted; the notation
-<code>a[lo :]</code> is shorthand for <code>a[lo : len(a)]</code>.
-For arrays or strings, the indexes
-<code>lo</code> and <code>hi</code> must satisfy
-0 &lt;= <code>lo</code> &lt;= <code>hi</code> &lt;= length;
-for slices, the upper bound is the capacity rather than the length.
+For convenience, any of the index expressions may be omitted. A missing <code>low</code>
+index defaults to zero; a missing <code>high</code> index defaults to the length of the
+sliced operand:
+</p>
+
+<pre>
+a[2:] // same a[2 : len(a)]
+a[:3] // same as a[0 : 3]
+a[:] // same as a[0 : len(a)]
+</pre>
+
+<p>
+For arrays or strings, the indexes <code>low</code> and <code>high</code> must
+satisfy 0 &lt;= <code>low</code> &lt;= <code>high</code> &lt;= length; for
+slices, the upper bound is the capacity rather than the length.
</p>
<p>
If the sliced operand is a string or slice, the result of the slice operation
is a string or slice of the same type.
-If the sliced operand is an array, the result of the slice operation is a slice
-with the same element type as the array.
+If the sliced operand is an array, it must be <a href="#Address_operators">addressable</a>
+and the result of the slice operation is a slice with the same element type as the array.
</p>
@@ -2605,9 +2620,9 @@ then within the function the argument is equivalent to a parameter of type
<code>[]T</code>. At each call of <code>f</code>, the argument
passed to the final parameter is
a new slice of type <code>[]T</code> whose successive elements are
-the actual arguments. The length of the slice is therefore the
-number of arguments bound to the final parameter and
-may differ for each call site.
+the actual arguments, which all must be <a href="#Assignability">assignable</a>
+to the type <code>T</code>. The length of the slice is therefore the number of
+arguments bound to the final parameter and may differ for each call site.
</p>
<p>
@@ -2619,20 +2634,31 @@ Greeting("hello:", "Joe", "Anna", "Eileen")
</pre>
<p>
-Within <code>Greeting</code>, <code>who</code> will have value
-<code>[]string{"Joe", "Anna", "Eileen")</code>
+within <code>Greeting</code>, <code>who</code> will have the value
+<code>[]string{"Joe", "Anna", "Eileen"}</code>
</p>
+<p>
+If the final argument is assignable to a slice type <code>[]T</code>, it may be
+passed unchanged as the value for a <code>...T</code> parameter if the argument
+is followed by <code>...</code>. In this case no new slice is created.
+</p>
<p>
-As a special case, if a function passes its own <code>...</code> parameter
-as the <code>...</code> argument in a call to another function with
-a <code>...</code> parameter of <a href="#Type_identity">identical type</a>,
-the parameter is passed directly. In short, a formal <code>...</code>
-parameter is passed unchanged as an actual <code>...</code> parameter provided the
-types match.
+Given the slice <code>s</code> and call
</p>
+<pre>
+s := []string{"James", "Jasmine"}
+Greeting("goodbye:", s...)
+</pre>
+
+<p>
+within <code>Greeting</code>, <code>who</code> will have the same value as <code>s</code>
+with the same underlying array.
+</p>
+
+
<h3 id="Operators">Operators</h3>
<p>
@@ -2903,7 +2929,7 @@ and string values. The result of a comparison is defined as follows:
String values are compared byte-wise (lexically).
</li>
<li>
- Boolean values are are equal if they are either both
+ Boolean values are equal if they are either both
<code>true</code> or both <code>false</code>.
</li>
<li>
@@ -3065,6 +3091,12 @@ to <code>false</code> and <code>x</code> is set to the
zero value for its type (§<a href="#The_zero_value">The zero value</a>).
</p>
+<p>
+Except in a communications clause of a <a href="#Select_statements">select statement</a>,
+sending or receiving from a <code>nil</code> channel causes a
+<a href="#Run_time_panics">run-time panic</a>.
+</p>
+
<!---
<p>
<span class="alert">TODO: Probably in a separate section, communication semantics
@@ -3548,8 +3580,8 @@ f(x+y)
<p>
The "++" and "--" statements increment or decrement their operands
by the untyped <a href="#Constants">constant</a> <code>1</code>.
-As with an assignment, the operand must be a variable, pointer indirection,
-field selector or index expression.
+As with an assignment, the operand must be <a href="#Address_operators">addressable</a>
+or a map index expression.
</p>
<pre class="ebnf">
@@ -3567,6 +3599,7 @@ x++ x += 1
x-- x -= 1
</pre>
+
<h3 id="Assignments">Assignments</h3>
<pre class="ebnf">
@@ -3925,59 +3958,81 @@ for { S() } is the same as for true { S() }
<p>
A "for" statement with a "range" clause
iterates through all entries of an array, slice, string or map,
-or values received on a channel.
-For each entry it first assigns the current index or key to an iteration
-variable - or the current (index, element) or (key, value) pair to a pair
-of iteration variables - and then executes the block.
+or values received on a channel. For each entry it assigns <i>iteration values</i>
+to corresponding <i>iteration variables</i> and then executes the block.
</p>
<pre class="ebnf">
-RangeClause = ExpressionList ( "=" | ":=" ) "range" Expression .
-</pre>
-
-<p>
-The type of the right-hand expression in the "range" clause must be an
-array, slice, string or map, or a pointer to an array;
-or it may be a channel.
-Except for channels,
-the identifier list must contain one or two expressions
-(as in assignments, these must be a
-variable, pointer indirection, field selector, or index expression)
-denoting the
-iteration variables. On each iteration,
-the first variable is set to the string, array or slice index or
-map key, and the second variable, if present, is set to the corresponding
-string or array element or map value.
-The types of the array or slice index (always <code>int</code>)
-and element, or of the map key and value respectively,
-must be <a href="#Assignability">assignable</a> to
-the type of the iteration variables. The expression on the right hand
-side is evaluated once before beginning the loop. At each iteration
-of the loop, the values produced by the range clause are assigned to
-the left hand side as in an <a href="#Assignments">assignment
-statement</a>. Function calls on the left hand side will be evaluated
-exactly once per iteration.
-</p>
-<p>
-For a value of a string type, the "range" clause iterates over the Unicode code points
-in the string. On successive iterations, the index variable will be the
-index of the first byte of successive UTF-8-encoded code points in the string, and
-the second variable, of type <code>int</code>, will be the value of
+RangeClause = Expression [ "," Expression ] ( "=" | ":=" ) "range" Expression .
+</pre>
+
+<p>
+The expression on the right in the "range" clause is called the <i>range expression</i>,
+which may be an array, pointer to an array, slice, string, map, or channel.
+As with an assignment, the operands on the left must be
+<a href="#Address_operators">addressable</a> or map index expressions; they
+denote the iteration variables. If the range expression is a channel, only
+one iteration variable is permitted, otherwise there may be one or two.
+</p>
+
+<p>
+The range expression is evaluated once before beginning the loop.
+Function calls on the left are evaluated once per iteration.
+For each iteration, iteration values are produced as follows:
+</p>
+
+<pre class="grammar">
+Range expression 1st value 2nd value (if 2nd variable is present)
+
+array or slice a [n]E, *[n]E, or []E index i int a[i] E
+string s string type index i int see below int
+map m map[K]V key k K m[k] V
+channel c chan E element e E
+</pre>
+
+<ol>
+<li>
+For an array or slice value, the index iteration values are produced in
+increasing order, starting at element index 0.
+</li>
+
+<li>
+For a string value, the "range" clause iterates over the Unicode code points
+in the string starting at byte index 0. On successive iterations, the index value will be the
+index of the first byte of successive UTF-8-encoded code points in the string,
+and the second value, of type <code>int</code>, will be the value of
the corresponding code point. If the iteration encounters an invalid
-UTF-8 sequence, the second variable will be <code>0xFFFD</code>,
+UTF-8 sequence, the second value will be <code>0xFFFD</code>,
the Unicode replacement character, and the next iteration will advance
a single byte in the string.
-</p>
+</li>
+
+<li>
+The iteration order over maps is not specified.
+If map entries that have not yet been reached are deleted during iteration,
+the corresponding iteration values will not be produced. If map entries are
+inserted during iteration, the behavior is implementation-dependent, but the
+iteration values for each entry will be produced at most once.
+</li>
+
+<li>
+For channels, the iteration values produced are the successive values sent on
+the channel until the channel is closed; it does not produce the zero value sent
+before the channel is closed
+(§<a href="#Close_and_closed"><code>close</code> and <code>closed</code></a>).
+</li>
+</ol
+
<p>
-For channels, the identifier list must contain one identifier.
-The iteration receives values sent on the channel until the channel is closed;
-it does not process the zero value sent before the channel is closed.
+The iteration values are assigned to the respective
+iteration variables as in an <a href="#Assignments">assignment statement</a>.
</p>
+
<p>
-The iteration variables may be declared by the "range" clause (":="), in which
-case their scope ends at the end of the "for" statement (§<a href="#Declarations_and">Declarations and</a>
-scope rules). In this case their types are set to
-<code>int</code> and the array element type, or the map key and value types, respectively.
+The iteration variables may be declared by the "range" clause (<code>:=</code>).
+In this case their types are set to the types of the respective iteration values
+and their <a href="#Declarations_and_scope">scope</a> ends at the end of the "for"
+statement; they are re-used in each iteration.
If the iteration variables are declared outside the "for" statement,
after execution their values will be those of the last iteration.
</p>
@@ -4002,11 +4057,6 @@ for key, val = range m {
// val == map[key]
</pre>
-<p>
-If map entries that have not yet been processed are deleted during iteration,
-they will not be processed. If map entries are inserted during iteration, the
-behavior is implementation-dependent, but each entry will be processed at most once.
-</p>
<h3 id="Go_statements">Go statements</h3>
@@ -4050,18 +4100,22 @@ RecvExpr = [ Expression ( "=" | ":=" ) ] "&lt;-" Expression .
<p>
For all the send and receive expressions in the "select"
-statement, the channel expressions are evaluated, along with
-any expressions that appear on the right hand side of send expressions,
-in top-to-bottom order.
-If any of the resulting operations can proceed, one is
-chosen and the corresponding communication and statements are
-evaluated. Otherwise, if there is a default case, that executes;
-if not, the statement blocks until one of the communications can
-complete. The channels and send expressions are not re-evaluated.
-A channel pointer may be <code>nil</code>,
+statement, the channel expressions are evaluated in top-to-bottom order, along with
+any expressions that appear on the right hand side of send expressions.
+A channel may be <code>nil</code>,
which is equivalent to that case not
being present in the select statement
except, if a send, its expression is still evaluated.
+If any of the resulting operations can proceed, one of those is
+chosen and the corresponding communication and statements are
+evaluated. Otherwise, if there is a default case, that executes;
+if there is no default case, the statement blocks until one of the communications can
+complete.
+If there are no cases with non-<code>nil</code> channels,
+the statement blocks forever.
+Even if the statement blocks,
+the channel and send expressions are evaluated only once,
+upon entering the select statement.
</p>
<p>
Since all the channels and send expressions are evaluated, any side
@@ -4069,7 +4123,7 @@ effects in that evaluation will occur for all the communications
in the "select" statement.
</p>
<p>
-If multiple cases can proceed, a uniform fair choice is made to decide
+If multiple cases can proceed, a pseudo-random fair choice is made to decide
which single communication will execute.
<p>
The receive case may declare a new variable using a
@@ -4094,6 +4148,8 @@ for { // send random sequence of bits to c
case c &lt;- 1:
}
}
+
+select { } // block forever
</pre>
@@ -4150,7 +4206,7 @@ func complex_f2() (re float, im float) {
}
</pre>
</li>
- <li>The expression list may be empty if the functions's result
+ <li>The expression list may be empty if the function's result
type specifies names for its result parameters (§<a href="#Function_Types">Function Types</a>).
The result parameters act as ordinary local variables
and the function may assign values to them as necessary.
@@ -4331,21 +4387,24 @@ they cannot be used as function values.
</p>
<pre class="ebnf">
-BuiltinCall = identifier "(" [ BuiltinArgs ] ")" .
+BuiltinCall = identifier "(" [ BuiltinArgs [ "," ] ] ")" .
BuiltinArgs = Type [ "," ExpressionList ] | ExpressionList .
</pre>
<h3 id="Close_and_closed">Close and closed</h3>
<p>
-For a channel <code>c</code>, the predefined function <code>close(c)</code>
-marks the channel as unable to accept more
-values through a send operation. After any previously
+For a channel <code>c</code>, the built-in function <code>close(c)</code>
+marks the channel as unable to accept more values through a send operation;
+values sent to a closed channel are ignored.
+After calling <code>close</code>, and after any previously
sent values have been received, receive operations will return
-the zero value for the channel's type. After at least one such zero value has been
+the zero value for the channel's type without blocking.
+After at least one such zero value has been
received, <code>closed(c)</code> returns true.
</p>
+
<h3 id="Length_and_capacity">Length and capacity</h3>
<p>
@@ -4358,12 +4417,12 @@ The implementation guarantees that the result always fits into an <code>int</cod
Call Argument type Result
len(s) string type string length in bytes
- [n]T, *[n]T array length (== constant n)
+ [n]T, *[n]T array length (== n)
[]T slice length
map[K]T map length (number of defined keys)
chan T number of elements queued in channel buffer
-cap(s) [n]T, *[n]T array length (== constant n)
+cap(s) [n]T, *[n]T array length (== n)
[]T slice capacity
chan T channel buffer capacity
</pre>
@@ -4378,6 +4437,24 @@ At any time the following relationship holds:
0 <= len(s) <= cap(s)
</pre>
+<p>
+The length and capacity of a <code>nil</code> slice, map, or channel are 0.
+</p>
+
+<p>
+The expression
+<code>len(s)</code> is a
+<a href="#Constants">constant</a> if <code>s</code> is a string constant.
+The expressions
+<code>len(s)</code> and
+<code>cap(s)</code> are
+constants if <code>s</code> is an (optionally parenthesized)
+identifier or
+<a href="#Qualified_identifiers">qualified identifier</a>
+denoting an array or pointer to array.
+Otherwise invocations of <code>len</code> and <code>cap</code> are not
+constant.
+</p>
<h3 id="Allocation">Allocation</h3>
@@ -4450,20 +4527,53 @@ m := make(map[string] int, 100) // map with initial space for 100 elements
</pre>
-<h3 id="Copying_slices">Copying slices</h3>
+<h3 id="Appending_and_copying_slices">Appending to and copying slices</h3>
+
+<p>
+Two built-in functions assist in common slice operations.
+</p>
+
+<p>
+The function <code>append</code> appends zero or more values <code>x</code>
+to a slice <code>s</code> and returns the resulting slice, with the same type
+as s. Each value must be <a href="#Assignability">assignable</a> to the slice's
+element type.
+</p>
+
+<pre class="grammar">
+append(s S, x ...T) S // S is assignable to []T
+</pre>
<p>
-The built-in function <code>copy</code> copies slice elements from
+If the capacity of <code>s</code> is not large enough to fit the additional
+values, <code>append</code> allocates a new, sufficiently large slice that fits
+both the existing slice elements and the additional values. Thus, the returned
+slice may refer to a different underlying array.
+</p>
+
+<pre>
+s0 := []int{0, 0}
+s1 := append(s0, 2) // append a single element s1 == []int{0, 0, 2}
+s2 := append(s1, 3, 5, 7) // append multiple elements s2 == []int{0, 0, 2, 3, 5, 7}
+s3 := append(s2, s0...) // append a slice s3 == []int{0, 0, 2, 3, 5, 7, 0, 0}
+</pre>
+
+<p>
+The function <code>copy</code> copies slice elements from
a source <code>src</code> to a destination <code>dst</code> and returns the
number of elements copied. Source and destination may overlap.
Both arguments must have <a href="#Type_identity">identical</a> element type <code>T</code> and must be
-<a href="#Assignability">assignable</a> to a slice
-of type <code>[]T</code>. The number of arguments copied is the minimum of
+<a href="#Assignability">assignable</a> to a slice of type <code>[]T</code>.
+The number of arguments copied is the minimum of
<code>len(src)</code> and <code>len(dst)</code>.
+As a special case, <code>copy</code> also accepts a destination argument assignable
+to type <code>[]byte</code> with a source argument of a string type.
+This form copies the bytes from the string into the byte slice.
</p>
<pre class="grammar">
copy(dst, src []T) int
+copy(dst []byte, src string) int
</pre>
<p>
@@ -4473,8 +4583,10 @@ Examples:
<pre>
var a = [...]int{0, 1, 2, 3, 4, 5, 6, 7}
var s = make([]int, 6)
-n1 := copy(s, a[0:]) // n1 == 6, s == []int{0, 1, 2, 3, 4, 5}
-n2 := copy(s, s[2:]) // n2 == 4, s == []int{2, 3, 4, 5, 4, 5}
+var b = make([]byte, 5)
+n1 := copy(s, a[0:]) // n1 == 6, s == []int{0, 1, 2, 3, 4, 5}
+n2 := copy(s, s[2:]) // n2 == 4, s == []int{2, 3, 4, 5, 4, 5}
+n3 := copy(b, "Hello, World!") // n3 == 5, b == []byte("Hello")
</pre>
<h3 id="Complex_numbers">Assembling and disassembling complex numbers</h3>
@@ -4533,10 +4645,10 @@ func recover() interface{}
</pre>
<p>
-<font color=red>TODO: Most of this text could move to the respective
+<span class="alert">TODO: Most of this text could move to the respective
comments in <code>runtime.go</code> once the functions are implemented.
They are here, at least for now, for reference and discussion.
-</font>
+</span>
</p>
<p>
@@ -4630,8 +4742,9 @@ func IsPrintable(s string) (ok bool) {
}
// Panicking has stopped; execution will resume normally in caller.
// The return value will be true normally, false if a panic occurred.
- }
+ }()
panicIfNotPrintable(s) // will panic if validations fails.
+ return
}
</pre>
@@ -5086,27 +5199,24 @@ For the numeric types (§<a href="#Numeric_types">Numeric types</a>), the follow
</p>
<pre class="grammar">
-type size in bytes
+type size in bytes
-byte, uint8, int8 1
-uint16, int16 2
-uint32, int32, float32 4
-uint64, int64, float64 8
+byte, uint8, int8 1
+uint16, int16 2
+uint32, int32, float32 4
+uint64, int64, float64, complex64 8
+complex128 16
</pre>
<p>
The following minimal alignment properties are guaranteed:
</p>
<ol>
-<li>For a variable <code>x</code> of any type: <code>1 <= unsafe.Alignof(x) <= unsafe.Maxalign</code>.
-</li>
-
-<li>For a variable <code>x</code> of numeric type: <code>unsafe.Alignof(x)</code> is the smaller
- of <code>unsafe.Sizeof(x)</code> and <code>unsafe.Maxalign</code>, but at least 1.
+<li>For a variable <code>x</code> of any type: <code>unsafe.Alignof(x)</code> is at least 1.
</li>
<li>For a variable <code>x</code> of struct type: <code>unsafe.Alignof(x)</code> is the largest of
- all the values <code>unsafe.Alignof(x.f)</code> for each field <code>f</code> of x, but at least 1.
+ all the values <code>unsafe.Alignof(x.f)</code> for each field <code>f</code> of <code>x</code>, but at least 1.
</li>
<li>For a variable <code>x</code> of array type: <code>unsafe.Alignof(x)</code> is the same as
@@ -5117,10 +5227,7 @@ The following minimal alignment properties are guaranteed:
<h2 id="Implementation_differences"><span class="alert">Implementation differences - TODO</span></h2>
<ul>
<li><span class="alert">Implementation does not honor the restriction on goto statements and targets (no intervening declarations).</span></li>
- <li><span class="alert">Method expressions are partially implemented.</span></li>
+ <li><span class="alert">Gccgo: The <code>append</code> built-in function is not yet implemented.</span></li>
+ <li><span class="alert">Gccgo: Method expressions are partially implemented.</span></li>
<li><span class="alert">Gccgo: allows only one init() function per source file.</span></li>
- <li><span class="alert">Gccgo: Deferred functions cannot access the surrounding function's result parameters.</span></li>
- <li><span class="alert">Gccgo: Function results are not addressable.</span></li>
- <li><span class="alert">Gccgo: Recover is not implemented.</span></li>
- <li><span class="alert">Gccgo: The implemented version of panic differs from its specification.</span></li>
</ul>
diff --git a/doc/go_tutorial.html b/doc/go_tutorial.html
index 7eb09b5b4..11e9b4ad7 100644
--- a/doc/go_tutorial.html
+++ b/doc/go_tutorial.html
@@ -286,14 +286,15 @@ In Go, since arrays are values, it's meaningful (and useful) to talk
about pointers to arrays.
<p>
The size of the array is part of its type; however, one can declare
-a <i>slice</i> variable, to which one can assign a pointer to
-any array
-with the same element type or&mdash;much more commonly&mdash;a <i>slice
-expression</i> of the form <code>a[low : high]</code>, representing
-the subarray indexed by <code>low</code> through <code>high-1</code>.
-Slices look a lot like arrays but have
+a <i>slice</i> variable to hold a reference to any array, of any size,
+with the same element type.
+A <i>slice
+expression</i> has the form <code>a[low : high]</code>, representing
+the internal array indexed from <code>low</code> through <code>high-1</code>; the resulting
+slice is indexed from <code>0</code> through <code>high-low-1</code>.
+In short, slices look a lot like arrays but with
no explicit size (<code>[]</code> vs. <code>[10]</code>) and they reference a segment of
-an underlying, often anonymous, regular array. Multiple slices
+an underlying, usually anonymous, regular array. Multiple slices
can share data if they represent pieces of the same array;
multiple arrays can never share data.
<p>
@@ -302,17 +303,28 @@ regular arrays; they're more flexible, have reference semantics,
and are efficient. What they lack is the precise control of storage
layout of a regular array; if you want to have a hundred elements
of an array stored within your structure, you should use a regular
-array.
+array. To create one, use a compound value <i>constructor</i>&mdash;an
+expression formed
+from a type followed by a brace-bounded expression like this:
+<p>
+<pre>
+ [3]int{1,2,3}
+</pre>
+<p>
+In this case the constructor builds an array of 3 <code>ints</code>.
<p>
When passing an array to a function, you almost always want
to declare the formal parameter to be a slice. When you call
-the function, take the address of the array and Go will
-create (efficiently) a slice reference and pass that.
+the function, slice the array to create
+(efficiently) a slice reference and pass that.
+By default, the lower and upper bounds of a slice match the
+ends of the existing object, so the concise notation <code>[:]</code>
+will slice the whole array.
<p>
Using slices one can write this function (from <code>sum.go</code>):
<p>
<pre> <!-- progs/sum.go /sum/ /^}/ -->
-09 func sum(a []int) int { // returns an int
+09 func sum(a []int) int { // returns an int
10 s := 0
11 for i := 0; i &lt; len(a); i++ {
12 s += a[i]
@@ -321,32 +333,27 @@ Using slices one can write this function (from <code>sum.go</code>):
15 }
</pre>
<p>
-and invoke it like this:
-<p>
-<pre> <!-- progs/sum.go /1,2,3/ -->
-19 s := sum(&amp;[3]int{1,2,3}) // a slice of the array is passed to sum
-</pre>
-<p>
Note how the return type (<code>int</code>) is defined for <code>sum()</code> by stating it
after the parameter list.
-The expression <code>[3]int{1,2,3}</code>&mdash;a type followed by a
-brace-bounded
-expression&mdash;is a constructor for a value, in this case an array
-of 3 <code>ints</code>.
-Putting an <code>&amp;</code>
-in front gives us the address of a unique instance of the value. We pass the
-pointer to <code>sum()</code> by (implicitly) promoting it to a slice.
+<p>
+To call the function, we slice the array. This intricate call (we'll show
+a simpler way in a moment) constructs
+an array and slices it:
+<p>
+<pre>
+ s := sum([3]int{1,2,3}[:])
+</pre>
<p>
If you are creating a regular array but want the compiler to count the
elements for you, use <code>...</code> as the array size:
<p>
<pre>
- s := sum(&amp;[...]int{1,2,3})
+ s := sum([...]int{1,2,3}[:])
</pre>
<p>
-In practice, though, unless you're meticulous about storage layout within a
-data structure, a slice itself&mdash;using empty brackets and no
-<code>&amp;</code>&mdash;is all you need:
+That's fussier than necessary, though.
+In practice, unless you're meticulous about storage layout within a
+data structure, a slice itself&mdash;using empty brackets with no size&mdash;is all you need:
<p>
<pre>
s := sum([]int{1,2,3})
@@ -470,8 +477,8 @@ sort of open/close/read/write interface. Here's the start of <code>file.go</cod
10 )
<p>
12 type File struct {
-13 fd int // file descriptor number
-14 name string // file name at Open time
+13 fd int // file descriptor number
+14 name string // file name at Open time
15 }
</pre>
<p>
@@ -524,7 +531,7 @@ object. We could write
return n
</pre>
<p>
-but for simple structures like <code>File</code> it's easier to return the address of a nonce
+but for simple structures like <code>File</code> it's easier to return the address of a
composite literal, as is done here on line 21.
<p>
We can use the factory to construct some familiar, exported variables of type <code>*File</code>:
@@ -541,7 +548,7 @@ The <code>newFile</code> function was not exported because it's internal. The pr
exported factory to use is <code>Open</code>:
<p>
<pre> <!-- progs/file.go /func.Open/ /^}/ -->
-30 func Open(name string, mode int, perm int) (file *File, err os.Error) {
+30 func Open(name string, mode int, perm uint32) (file *File, err os.Error) {
31 r, e := syscall.Open(name, mode, perm)
32 if e != 0 {
33 err = os.Errno(e)
@@ -581,7 +588,7 @@ each of which declares a receiver variable <code>file</code>.
40 return os.EINVAL
41 }
42 e := syscall.Close(file.fd)
-43 file.fd = -1 // so it can't be closed again
+43 file.fd = -1 // so it can't be closed again
44 if e != 0 {
45 return os.Errno(e)
46 }
@@ -642,24 +649,30 @@ We can now use our new package:
13 func main() {
14 hello := []byte(&quot;hello, world\n&quot;)
15 file.Stdout.Write(hello)
-16 file, err := file.Open(&quot;/does/not/exist&quot;, 0, 0)
-17 if file == nil {
+16 f, err := file.Open(&quot;/does/not/exist&quot;, 0, 0)
+17 if f == nil {
18 fmt.Printf(&quot;can't open file; err=%s\n&quot;, err.String())
19 os.Exit(1)
20 }
21 }
</pre>
<p>
-The ''<code>./</code>'' in the import of ''<code>./file</code>'' tells the compiler to use our own package rather than
+The ''<code>./</code>'' in the import of ''<code>./file</code>'' tells the compiler
+to use our own package rather than
something from the directory of installed packages.
+(Also, ''<code>file.go</code>'' must be compiled before we can import the
+package.)
<p>
-Finally we can run the program:
+Now we can compile and run the program:
<p>
<pre>
- % helloworld3
+ $ 6g file.go # compile file package
+ $ 6g helloworld3.go # compile main package
+ $ 6l -o helloworld3 helloworld3.6 # link - no need to mention "file"
+ $ helloworld3
hello, world
can't open file; err=No such file or directory
- %
+ $
</pre>
<p>
<h2>Rotting cats</h2>
@@ -681,11 +694,11 @@ Building on the <code>file</code> package, here's a simple version of the Unix u
15 const NBUF = 512
16 var buf [NBUF]byte
17 for {
-18 switch nr, er := f.Read(&amp;buf); true {
+18 switch nr, er := f.Read(buf[:]); true {
19 case nr &lt; 0:
20 fmt.Fprintf(os.Stderr, &quot;cat: error reading from %s: %s\n&quot;, f.String(), er.String())
21 os.Exit(1)
-22 case nr == 0: // EOF
+22 case nr == 0: // EOF
23 return
24 case nr &gt; 0:
25 if nw, ew := file.Stdout.Write(buf[0:nr]); nw != nr {
@@ -696,7 +709,7 @@ Building on the <code>file</code> package, here's a simple version of the Unix u
30 }
<p>
32 func main() {
-33 flag.Parse() // Scans the arg list and sets up flags
+33 flag.Parse() // Scans the arg list and sets up flags
34 if flag.NArg() == 0 {
35 cat(file.Stdin)
36 }
@@ -757,7 +770,7 @@ we have a second implementation of the <code>reader</code> interface.
<p>
<pre> <!-- progs/cat_rot13.go /type.rotate13/ /end.of.rotate13/ -->
31 type rotate13 struct {
-32 source reader
+32 source reader
33 }
<p>
35 func newRotate13(source reader) *rotate13 {
@@ -797,11 +810,11 @@ and use it from within a mostly unchanged <code>cat()</code> function:
57 r = newRotate13(r)
58 }
59 for {
-60 switch nr, er := r.Read(&amp;buf); {
+60 switch nr, er := r.Read(buf[:]); {
61 case nr &lt; 0:
62 fmt.Fprintf(os.Stderr, &quot;cat: error reading from %s: %s\n&quot;, r.String(), er.String())
63 os.Exit(1)
-64 case nr == 0: // EOF
+64 case nr == 0: // EOF
65 return
66 case nr &gt; 0:
67 nw, ew := file.Stdout.Write(buf[0:nr])
@@ -823,11 +836,11 @@ even though under the covers it holds a pointer to a <code>struct</code>.
Here it is in action:
<p>
<pre>
- % echo abcdefghijklmnopqrstuvwxyz | ./cat
+ $ echo abcdefghijklmnopqrstuvwxyz | ./cat
abcdefghijklmnopqrstuvwxyz
- % echo abcdefghijklmnopqrstuvwxyz | ./cat --rot13
+ $ echo abcdefghijklmnopqrstuvwxyz | ./cat --rot13
nopqrstuvwxyzabcdefghijklm
- %
+ $
</pre>
<p>
Fans of dependency injection may take cheer from how easily interfaces
diff --git a/doc/go_tutorial.txt b/doc/go_tutorial.txt
index 6ab6094c0..9c08bd278 100644
--- a/doc/go_tutorial.txt
+++ b/doc/go_tutorial.txt
@@ -227,14 +227,15 @@ In Go, since arrays are values, it's meaningful (and useful) to talk
about pointers to arrays.
The size of the array is part of its type; however, one can declare
-a <i>slice</i> variable, to which one can assign a pointer to
-any array
-with the same element type or&mdash;much more commonly&mdash;a <i>slice
-expression</i> of the form "a[low : high]", representing
-the subarray indexed by "low" through "high-1".
-Slices look a lot like arrays but have
+a <i>slice</i> variable to hold a reference to any array, of any size,
+with the same element type.
+A <i>slice
+expression</i> has the form "a[low : high]", representing
+the internal array indexed from "low" through "high-1"; the resulting
+slice is indexed from "0" through "high-low-1".
+In short, slices look a lot like arrays but with
no explicit size ("[]" vs. "[10]") and they reference a segment of
-an underlying, often anonymous, regular array. Multiple slices
+an underlying, usually anonymous, regular array. Multiple slices
can share data if they represent pieces of the same array;
multiple arrays can never share data.
@@ -243,39 +244,43 @@ regular arrays; they're more flexible, have reference semantics,
and are efficient. What they lack is the precise control of storage
layout of a regular array; if you want to have a hundred elements
of an array stored within your structure, you should use a regular
-array.
+array. To create one, use a compound value <i>constructor</i>&mdash;an
+expression formed
+from a type followed by a brace-bounded expression like this:
+
+ [3]int{1,2,3}
+
+In this case the constructor builds an array of 3 "ints".
When passing an array to a function, you almost always want
to declare the formal parameter to be a slice. When you call
-the function, take the address of the array and Go will
-create (efficiently) a slice reference and pass that.
+the function, slice the array to create
+(efficiently) a slice reference and pass that.
+By default, the lower and upper bounds of a slice match the
+ends of the existing object, so the concise notation "[:]"
+will slice the whole array.
Using slices one can write this function (from "sum.go"):
--PROG progs/sum.go /sum/ /^}/
-and invoke it like this:
-
---PROG progs/sum.go /1,2,3/
-
Note how the return type ("int") is defined for "sum()" by stating it
after the parameter list.
-The expression "[3]int{1,2,3}"&mdash;a type followed by a
-brace-bounded
-expression&mdash;is a constructor for a value, in this case an array
-of 3 "ints".
-Putting an "&amp;"
-in front gives us the address of a unique instance of the value. We pass the
-pointer to "sum()" by (implicitly) promoting it to a slice.
+
+To call the function, we slice the array. This intricate call (we'll show
+a simpler way in a moment) constructs
+an array and slices it:
+
+ s := sum([3]int{1,2,3}[:])
If you are creating a regular array but want the compiler to count the
elements for you, use "..." as the array size:
- s := sum(&amp;[...]int{1,2,3})
+ s := sum([...]int{1,2,3}[:])
-In practice, though, unless you're meticulous about storage layout within a
-data structure, a slice itself&mdash;using empty brackets and no
-"&amp;"&mdash;is all you need:
+That's fussier than necessary, though.
+In practice, unless you're meticulous about storage layout within a
+data structure, a slice itself&mdash;using empty brackets with no size&mdash;is all you need:
s := sum([]int{1,2,3})
@@ -415,7 +420,7 @@ object. We could write
n.name = name
return n
-but for simple structures like "File" it's easier to return the address of a nonce
+but for simple structures like "File" it's easier to return the address of a
composite literal, as is done here on line 21.
We can use the factory to construct some familiar, exported variables of type "*File":
@@ -471,15 +476,21 @@ We can now use our new package:
--PROG progs/helloworld3.go /package/ END
-The ''"./"'' in the import of ''"./file"'' tells the compiler to use our own package rather than
+The ''"./"'' in the import of ''"./file"'' tells the compiler
+to use our own package rather than
something from the directory of installed packages.
+(Also, ''"file.go"'' must be compiled before we can import the
+package.)
-Finally we can run the program:
+Now we can compile and run the program:
- % helloworld3
+ $ 6g file.go # compile file package
+ $ 6g helloworld3.go # compile main package
+ $ 6l -o helloworld3 helloworld3.6 # link - no need to mention "file"
+ $ helloworld3
hello, world
can't open file; err=No such file or directory
- %
+ $
Rotting cats
----
@@ -549,11 +560,11 @@ even though under the covers it holds a pointer to a "struct".
Here it is in action:
<pre>
- % echo abcdefghijklmnopqrstuvwxyz | ./cat
+ $ echo abcdefghijklmnopqrstuvwxyz | ./cat
abcdefghijklmnopqrstuvwxyz
- % echo abcdefghijklmnopqrstuvwxyz | ./cat --rot13
+ $ echo abcdefghijklmnopqrstuvwxyz | ./cat --rot13
nopqrstuvwxyzabcdefghijklm
- %
+ $
</pre>
Fans of dependency injection may take cheer from how easily interfaces
diff --git a/doc/godocs.js b/doc/godocs.js
index b2fc1b357..8b451547d 100644
--- a/doc/godocs.js
+++ b/doc/godocs.js
@@ -11,17 +11,32 @@
/* We want to do some stuff on page load (after the HTML is rendered).
So listen for that:
*/
-if (window.addEventListener){
- window.addEventListener('load', godocs_onload, false);
-} else if (window.attachEvent){
- window.attachEvent('onload', godocs_onload);
+function bindEvent(el, e, fn) {
+ if (el.addEventListener){
+ el.addEventListener(e, fn, false);
+ } else if (el.attachEvent){
+ el.attachEvent('on'+e, fn);
+ }
}
+bindEvent(window, 'load', godocs_onload);
function godocs_onload() {
+ godocs_bindSearchEvents();
godocs_generateTOC();
godocs_addTopLinks();
}
+function godocs_bindSearchEvents() {
+ var search = document.getElementById('search');
+ function clearInactive() {
+ if (search.className == "inactive") {
+ search.value = "";
+ search.className = "";
+ }
+ }
+ bindEvent(search, 'focus', clearInactive);
+}
+
/* Generates a table of contents: looks for h2 and h3 elements and generates
* links. "Decorates" the element with id=="nav" with this table of contents.
*/
diff --git a/doc/ie.css b/doc/ie.css
new file mode 100644
index 000000000..bb89d54be
--- /dev/null
+++ b/doc/ie.css
@@ -0,0 +1 @@
+#nav-main li { display: inline; }
diff --git a/doc/install.html b/doc/install.html
index 2c1ff2157..92b099fe8 100644
--- a/doc/install.html
+++ b/doc/install.html
@@ -1,6 +1,6 @@
-<!-- Installing Go -->
+<!-- Getting Started -->
-<h2>Introduction</h2>
+<h2 id="introduction">Introduction</h2>
<p>Go is an open source project, distributed under a
<a href="/LICENSE">BSD-style license</a>.
@@ -8,6 +8,8 @@ This document explains how to check out the sources,
build them on your own machine, and run them.
</p>
+<div class="detail">
+
<p>
There are two distinct ways to experiment with Go.
This document focuses on the <code>gc</code> Go
@@ -17,117 +19,6 @@ compiler using the GCC back end, see
<a href="gccgo_install.html">Setting up and using gccgo</a>.
</p>
-<h2>Environment variables</h2>
-
-<p>
-The Go compilation environment depends on three environment variables plus one optional variable:
-</p>
-
-<dl>
-<dt>
- <code>$GOROOT</code>
-</dt>
-<dd>The root of the Go tree. Typically this is <code>$HOME/go</code>
- but it can be any directory.
-</dd>
-
-<dt>
-<code>$GOOS</code> and <code>$GOARCH</code>
-</dt>
-<dd>
- The name of the target operating system and compilation architecture.
- Choices for <code>$GOOS</code> are <code>linux</code>,
- <code>freebsd</code>,
- <code>darwin</code> (Mac OS X 10.5 or 10.6),
- and <code>nacl</code> (Native Client, an incomplete port).
- Choices for <code>$GOARCH</code> are <code>amd64</code> (64-bit x86, the most mature port),
- <code>386</code> (32-bit x86), and
- <code>arm</code> (32-bit ARM, an incomplete port).
- The valid combinations of <code>$GOOS</code> and <code>$GOARCH</code> are:
- <p>
- <table cellpadding="0">
- <tr>
- <th width="50"><th align="left" width="100"><code>$GOOS</code></th> <th align="left" width="100"><code>$GOARCH</code></th>
- </tr>
- <tr>
- <td></td><td><code>darwin</code></td> <td><code>386</code></td>
- </tr>
- <tr>
- <td></td><td><code>darwin</code></td> <td><code>amd64</code></td>
- </tr>
- <tr>
- <td></td><td><code>freebsd</code></td> <td><code>386</code></td>
- </tr>
- <tr>
- <td></td><td><code>freebsd</code></td> <td><code>amd64</code></td>
- </tr>
- <tr>
- <td></td><td><code>linux</code></td> <td><code>386</code></td>
- </tr>
- <tr>
- <td></td><td><code>linux</code></td> <td><code>amd64</code></td>
- </tr>
- <tr>
- <td></td><td><code>linux</code></td> <td><code>arm</code></td>
- </tr>
- <tr>
- <td></td><td><code>nacl</code></td> <td><code>386</code></td>
- </tr>
- </table>
- <p>
-</dd>
-
-<dt>
-<code>$GOBIN</code> (optional)
-</dt>
-<dd>
- The location where binaries will be installed.
- The default is <code>$HOME/bin</code>.
- After installing, you will want to arrange to add this
- directory to your <code>$PATH</code>, so you can use the tools.
-</dd>
-
-<dt>
-<code>$GOARM</code> (optional, arm, default=6)
-</dt>
-<dd>
- The ARM architecture version the runtime libraries should target.
- ARMv6 cores have more efficient synchronization primitives. Setting
- <code>$GOARM</code> to 5 will compile the runtime libraries using
- just SWP instructions that work on older architectures as well.
- Running v6 code on an older core will cause an illegal instruction trap.
-</dd>
-</dl>
-
-<p>
-Note that <code>$GOARCH</code> and <code>$GOOS</code> identify the
-<em>target</em> environment, not the environment you are running on.
-In effect, you are always cross-compiling.
-</p>
-
-<p>
-Set these variables in your shell profile (<code>$HOME/.bashrc</code>,
-<code>$HOME/.profile</code>, or equivalent). The settings might look
-something like this:
-</p>
-
-<pre>
-export GOROOT=$HOME/go
-export GOARCH=amd64
-export GOOS=linux
-</pre>
-
-<p>
-Double-check them by listing your environment. (You will need to launch
-a new shell or terminal window for the changes to take effect.)
-</p>
-
-<pre>
-$ env | grep '^GO'
-</pre>
-
-<h2>Ports</h2>
-
<p>
The Go compilers support three instruction sets.
There are important differences in the quality of the compilers for the different
@@ -147,17 +38,19 @@ architectures.
<code>386</code> (a.k.a. <code>x86</code> or <code>x86-32</code>); <code>8g,8l,8c,8a</code>
</dt>
<dd>
- Comparable to the <code>amd64</code> port. Not as well soaked but
- should be nearly as solid.
-
+ Comparable to the <code>amd64</code> port.
</dd>
<dt>
<code>arm</code> (a.k.a. <code>ARM</code>); <code>5g,5l,5c,5a</code>
</dt>
<dd>
- It's got a couple of outstanding bugs but is improving.
- Tested against QEMU and an android phone.
- Only supports Linux binaries.
+ Incomplete.
+ It only supports Linux binaries, the optimizer is not enabled,
+ and floating point is performed entirely in software.
+ However, all tests pass.
+ Work on the optimizer and use of the VFP hardware
+ floating point unit is underway.
+ Tested against a Nexus One.
</dd>
</dl>
@@ -169,74 +62,106 @@ support for segmented stacks, and a strong goroutine implementation.
</p>
<p>
-See the separate <a href="gccgo_install.html"><code>gccgo</code> document</a>
-for details about that compiler and environment.
+The compilers can target the FreeBSD, Linux,
+and OS X (a.k.a. Darwin) operating systems.
+(A port to Microsoft Windows is in progress but incomplete. See the
+<a href="http://code.google.com/p/go/wiki/WindowsPort">Windows Port</a>
+page for details.)
+The full set of supported combinations is listed in the discussion of
+<a href="#environment">environment variables</a> below.
</p>
-<h2>Install C tools, if needed</h2>
+</div>
-<p>The Go tool chain is written in C. To build it, you need
-to have GCC, the standard C libraries, the parser generator Bison,
-<tt>make</tt>, <tt>awk</tt>, and the text editor <tt>ed</tt> installed. On OS X, they can be
-installed as part of
-<a href="http://developer.apple.com/TOOLS/Xcode/">Xcode</a>. On Linux, use
+<h2 id="ctools">Install C tools, if needed</h2>
+
+<p>The Go tool chain is written in C.
+To build it, you need these programs installed:
+<ul>
+<li>GCC,
+<li>the standard C libraries,
+<li>the parser generator Bison,
+<li><tt>make</tt>,
+<li><tt>awk</tt>, and
+<li>the text editor <tt>ed</tt>.
+</ul>
</p>
-<pre>
-$ sudo apt-get install bison gcc libc6-dev ed gawk make
-</pre>
+<p>On OS X, they can be
+installed as part of
+<a href="http://developer.apple.com/TOOLS/Xcode/">Xcode</a>.
+</p>
-<p>
-(or the equivalent on your Linux distribution).
+<p>On Ubuntu/Debian, use <code>sudo apt-get install bison ed gawk gcc libc6-dev make</code>.
</p>
-<h2>Fetch the repository</h2>
+<h2 id="mercurial">Install Mercurial, if needed</h2>
<p>
-If you do not have Mercurial installed (you do not have an <code>hg</code> command),
-this command:
+To perform the next step you must have Mercurial installed. (Check that you have an <code>hg</code> command.) This suffices to install Mercurial on most systems:
</p>
-
<pre>
-$ sudo easy_install mercurial
+sudo easy_install mercurial
</pre>
+(On Ubuntu/Debian, you might try <code>apt-get install python-setuptools
+python-dev build-essential</code> first. The Mercurial in your distribution's
+package repository will most likely be old and broken.)
+</p>
+<p>
+If that fails, try installing manually from the <a href="http://mercurial.selenic.com/wiki/Download">Mercurial Download</a> page.</p>
+</p>
-<p>works on most systems.
-(On Ubuntu/Debian, you might try <code>apt-get install python-setuptools python-dev build-essential gcc</code> first.)
-If that fails, visit the <a href="http://mercurial.selenic.com/wiki/Download">Mercurial Download</a> page.</p>
+<h2 id="fetch">Fetch the repository</h2>
-<p>Make sure the <code>$GOROOT</code> directory does not exist or is empty.
+<p>
+<p>Go will install to a directory named <code>go</code>.
+Change to the directory that will be its parent
+and make sure the <code>go</code> directory does not exist.
Then check out the repository:</p>
<pre>
-$ hg clone -r release https://go.googlecode.com/hg/ $GOROOT
+$ hg clone -r release https://go.googlecode.com/hg/ go
</pre>
-<h2>Install Go</h2>
+<h2 id="install">Install Go</h2>
<p>
To build the Go distribution, run
</p>
<pre>
-$ cd $GOROOT/src
+$ cd go/src
$ ./all.bash
</pre>
<p>
-If all goes well, it will finish by printing
+If all goes well, it will finish by printing output like:
</p>
<pre>
--- cd ../test
N known bugs; 0 unexpected bugs
+
+---
+Installed Go for linux/amd64 in /home/you/go.
+Installed commands in /home/you/go/bin.
+*** You need to add /home/you/go/bin to your $PATH. ***
+The compiler is 6g.
</pre>
<p>
-where <var>N</var> is a number that varies from release to release.
+where <var>N</var> is a number that varies from release to release
+and the details on the last few lines will reflect the operating system,
+architecture, and root directory used during the install.
</p>
-<h2>Writing programs</h2>
+<div class="detail">
+
+<p>For more information about ways to control the build,
+see the discussion of <a href="#environment">environment variables</a> below.</p>
+</div>
+
+<h2 id="writing">Writing programs</h2>
<p>
Given a file <code>file.go</code>, compile it using
@@ -299,34 +224,57 @@ command line.
The linker learns about them by reading <code>hello.6</code>.
</p>
+<div class="detail">
<p>
To build more complicated programs, you will probably
want to use a
<code>Makefile</code>.
There are examples in places like
-<code>$GOROOT/src/cmd/godoc/Makefile</code>
-and <code>$GOROOT/src/pkg/*/Makefile</code>.
+<code>go/src/cmd/godoc/Makefile</code>
+and <code>go/src/pkg/*/Makefile</code>.
The
<a href="contribute.html">document</a>
about contributing to the Go project
gives more detail about
the process of building and testing Go programs.
</p>
+</div>
-<h2>Keeping up with releases</h2>
+<h2 id="next">What's next</h2>
+
+<p>
+Start by reading the <a href="go_tutorial.html">Go Tutorial</a>.
+</p>
+
+<p>
+Build a web application by following the <a href="codelab/wiki/">Wiki
+Codelab</a>.
+</p>
+
+<p>
+Read <a href="effective_go.html">Effective Go</a> to learn about writing
+idiomatic Go code.
+</p>
+
+<p>
+For the full story, consult Go's extensive
+<a href="docs.html">documentation</a>.
+</p>
+
+<h2 id="releases">Keeping up with releases</h2>
<p>New releases are announced on the <a href="http://groups.google.com/group/golang-nuts">Go Nuts</a> mailing list.
To update an existing tree to the latest release, you can run:
</p>
<pre>
-$ cd $GOROOT/src
+$ cd go/src
$ hg pull
$ hg update release
$ ./all.bash
</pre>
-<h2>Community resources</h2>
+<h2 id="community">Community resources</h2>
<p>
For real-time help, there may be users or developers on
@@ -348,4 +296,144 @@ there is another mailing list, <a href="http://groups.google.com/group/golang-ch
that receives a message summarizing each checkin to the Go repository.
</p>
+<h2 id="environment">Environment variables</h2>
+
+<p>
+The Go compilation environment can be customized by environment variables.
+None are required by the build, but you may wish to set them
+to override the defaults.
+</p>
+
+<dl>
+<dt>
+ <code>$GOROOT</code>
+</dt>
+<dd>
+ The root of the Go tree, often <code>$HOME/go</code>.
+ This defaults to the parent of the directory where <code>all.bash</code> is run.
+ If you choose not to set <code>$GOROOT</code>, you must
+ run <code>gomake</code> instead of <code>make</code> or <code>gmake</code>
+ when developing Go programs using the conventional makefiles.
+</dd>
+
+<dt>
+ <code>$GOROOT_FINAL</code>
+</dt>
+<dd>
+ The value assumed by installed binaries and scripts when
+ <code>$GOROOT</code> is not set.
+ It defaults to the value used for <code>$GOROOT</code>.
+ If you want to build the Go tree in one location
+ but move it elsewhere after the build, set
+ <code>$GOROOT_FINAL</code> to the eventual location.
+</dd>
+
+<dt>
+<code>$GOOS</code> and <code>$GOARCH</code>
+</dt>
+<dd>
+ The name of the target operating system and compilation architecture.
+ These default to the values of <code>$GOHOSTOS</code> and
+ <code>$GOHOSTARCH</code> respectively (described below).
+ <p>
+ Choices for <code>$GOOS</code> are <code>linux</code>,
+ <code>freebsd</code>,
+ <code>darwin</code> (Mac OS X 10.5 or 10.6),
+ and <code>windows</code> (Windows, an incomplete port).
+ Choices for <code>$GOARCH</code> are <code>amd64</code> (64-bit x86, the most mature port),
+ <code>386</code> (32-bit x86), and
+ <code>arm</code> (32-bit ARM, an incomplete port).
+ The valid combinations of <code>$GOOS</code> and <code>$GOARCH</code> are:
+ <table cellpadding="0">
+ <tr>
+ <th width="50"><th align="left" width="100"><code>$GOOS</code></th> <th align="left" width="100"><code>$GOARCH</code></th> <th align="left"></th>
+ </tr>
+ <tr>
+ <td></td><td><code>darwin</code></td> <td><code>386</code></td>
+ </tr>
+ <tr>
+ <td></td><td><code>darwin</code></td> <td><code>amd64</code></td>
+ </tr>
+ <tr>
+ <td></td><td><code>freebsd</code></td> <td><code>386</code></td>
+ </tr>
+ <tr>
+ <td></td><td><code>freebsd</code></td> <td><code>amd64</code></td>
+ </tr>
+ <tr>
+ <td></td><td><code>linux</code></td> <td><code>386</code></td>
+ </tr>
+ <tr>
+ <td></td><td><code>linux</code></td> <td><code>amd64</code></td>
+ </tr>
+ <tr>
+ <td></td><td><code>linux</code></td> <td><code>arm</code></td> <td><i>incomplete</i></td>
+ </tr>
+ <tr>
+ <td></td><td><code>windows</code></td> <td><code>386</code></td> <td><i>incomplete</i></td>
+ </tr>
+ </table>
+</dd>
+
+<dt>
+<code>$GOHOSTOS</code> and <code>$GOHOSTARCH</code>
+</dt>
+<dd>
+ The name of the host operating system and compilation architecture.
+ These default to the local system's operating system and
+ architecture.
+
+ <p>
+ Valid choices are the same as for <code>$GOOS</code> and
+ <code>$GOARCH</code>, listed above.
+ The specified values must be compatible with the local system.
+ For example, you should not set <code>$GOHOSTARCH</code> to
+ <code>arm</code> on an x86 system.
+</dd>
+
+<dt>
+<code>$GOBIN</code>
+</dt>
+<dd>
+ The location where binaries will be installed.
+ The default is <code>$GOROOT/bin</code>.
+ After installing, you will want to arrange to add this
+ directory to your <code>$PATH</code>, so you can use the tools.
+</dd>
+
+<dt>
+<code>$GOARM</code> (arm, default=6)
+</dt>
+<dd>
+ The ARM architecture version the runtime libraries should target.
+ ARMv6 cores have more efficient synchronization primitives. Setting
+ <code>$GOARM</code> to 5 will compile the runtime libraries using
+ just SWP instructions that work on older architectures as well.
+ Running v6 code on an older core will cause an illegal instruction trap.
+</dd>
+</dl>
+
+<p>
+Note that <code>$GOARCH</code> and <code>$GOOS</code> identify the
+<em>target</em> environment, not the environment you are running on.
+In effect, you are always cross-compiling.
+By architecture, we mean the kind of binaries
+that the target environment can run:
+an x86-64 system running a 32-bit-only operating system
+must set <code>GOARCH</code> to <code>386</code>,
+not <code>amd64</code>.
+</p>
+
+<p>
+If you choose to override the defaults,
+set these variables in your shell profile (<code>$HOME/.bashrc</code>,
+<code>$HOME/.profile</code>, or equivalent). The settings might look
+something like this:
+</p>
+
+<pre>
+export GOROOT=$HOME/go
+export GOARCH=386
+export GOOS=linux
+</pre>
diff --git a/doc/logo.png b/doc/logo.png
new file mode 100644
index 000000000..076ce398e
--- /dev/null
+++ b/doc/logo.png
Binary files differ
diff --git a/doc/play_overlay.png b/doc/play_overlay.png
new file mode 100644
index 000000000..20ef7f399
--- /dev/null
+++ b/doc/play_overlay.png
Binary files differ
diff --git a/doc/playground.html b/doc/playground.html
new file mode 100644
index 000000000..01d3adc9c
--- /dev/null
+++ b/doc/playground.html
@@ -0,0 +1,27 @@
+<!-- About the Go Playground -->
+
+<div class="left-column">
+<p>
+The Go Playground is a web service that runs on
+<a href="http://golang.org/">golang.org</a>'s servers.
+The service receives a Go program, compiles, links, and runs the program inside
+a sandbox, then returns the output.
+</p>
+
+<p>
+There are limitations to the programs that can be run in the Playground.
+They must be single-threaded (but they may use many goroutines).
+There are also limits on execution time, and CPU and memory usage.
+The Playground can access only a subset of the standard library
+(notably absent are network and file system access).
+Therefore, the only communication a Playground program has to the outside world
+is via standard output.
+</div>
+
+<div class="right-column">
+<script src="http://www.google.com/jsapi" type="text/javascript"></script>
+<div id="playground" class="small"></div>
+<script src="/doc/play/playground.js"></script>
+</div>
+
+<div class="end-columns"></div>
diff --git a/doc/progs/cat.go b/doc/progs/cat.go
index f8d1a54fb..697e5f786 100644
--- a/doc/progs/cat.go
+++ b/doc/progs/cat.go
@@ -15,11 +15,11 @@ func cat(f *file.File) {
const NBUF = 512
var buf [NBUF]byte
for {
- switch nr, er := f.Read(&buf); true {
+ switch nr, er := f.Read(buf[:]); true {
case nr < 0:
fmt.Fprintf(os.Stderr, "cat: error reading from %s: %s\n", f.String(), er.String())
os.Exit(1)
- case nr == 0: // EOF
+ case nr == 0: // EOF
return
case nr > 0:
if nw, ew := file.Stdout.Write(buf[0:nr]); nw != nr {
@@ -30,7 +30,7 @@ func cat(f *file.File) {
}
func main() {
- flag.Parse() // Scans the arg list and sets up flags
+ flag.Parse() // Scans the arg list and sets up flags
if flag.NArg() == 0 {
cat(file.Stdin)
}
diff --git a/doc/progs/cat_rot13.go b/doc/progs/cat_rot13.go
index 42c6195fb..03fc02259 100644
--- a/doc/progs/cat_rot13.go
+++ b/doc/progs/cat_rot13.go
@@ -15,10 +15,10 @@ var rot13Flag = flag.Bool("rot13", false, "rot13 the input")
func rot13(b byte) byte {
if 'a' <= b && b <= 'z' {
- b = 'a' + ((b - 'a') + 13) % 26
+ b = 'a' + ((b-'a')+13)%26
}
if 'A' <= b && b <= 'Z' {
- b = 'A' + ((b - 'A') + 13) % 26
+ b = 'A' + ((b-'A')+13)%26
}
return b
}
@@ -29,7 +29,7 @@ type reader interface {
}
type rotate13 struct {
- source reader
+ source reader
}
func newRotate13(source reader) *rotate13 {
@@ -57,11 +57,11 @@ func cat(r reader) {
r = newRotate13(r)
}
for {
- switch nr, er := r.Read(&buf); {
+ switch nr, er := r.Read(buf[:]); {
case nr < 0:
fmt.Fprintf(os.Stderr, "cat: error reading from %s: %s\n", r.String(), er.String())
os.Exit(1)
- case nr == 0: // EOF
+ case nr == 0: // EOF
return
case nr > 0:
nw, ew := file.Stdout.Write(buf[0:nr])
@@ -73,7 +73,7 @@ func cat(r reader) {
}
func main() {
- flag.Parse() // Scans the arg list and sets up flags
+ flag.Parse() // Scans the arg list and sets up flags
if flag.NArg() == 0 {
cat(file.Stdin)
}
diff --git a/doc/progs/file.go b/doc/progs/file.go
index b2f2c0476..d3fb5ae9e 100644
--- a/doc/progs/file.go
+++ b/doc/progs/file.go
@@ -10,8 +10,8 @@ import (
)
type File struct {
- fd int // file descriptor number
- name string // file name at Open time
+ fd int // file descriptor number
+ name string // file name at Open time
}
func newFile(fd int, name string) *File {
@@ -27,7 +27,7 @@ var (
Stderr = newFile(2, "/dev/stderr")
)
-func Open(name string, mode int, perm int) (file *File, err os.Error) {
+func Open(name string, mode int, perm uint32) (file *File, err os.Error) {
r, e := syscall.Open(name, mode, perm)
if e != 0 {
err = os.Errno(e)
@@ -40,7 +40,7 @@ func (file *File) Close() os.Error {
return os.EINVAL
}
e := syscall.Close(file.fd)
- file.fd = -1 // so it can't be closed again
+ file.fd = -1 // so it can't be closed again
if e != 0 {
return os.Errno(e)
}
diff --git a/doc/progs/helloworld3.go b/doc/progs/helloworld3.go
index e065f02e6..adbcea324 100644
--- a/doc/progs/helloworld3.go
+++ b/doc/progs/helloworld3.go
@@ -13,8 +13,8 @@ import (
func main() {
hello := []byte("hello, world\n")
file.Stdout.Write(hello)
- file, err := file.Open("/does/not/exist", 0, 0)
- if file == nil {
+ f, err := file.Open("/does/not/exist", 0, 0)
+ if f == nil {
fmt.Printf("can't open file; err=%s\n", err.String())
os.Exit(1)
}
diff --git a/doc/progs/run b/doc/progs/run
index 07bc141df..29f1f8152 100755
--- a/doc/progs/run
+++ b/doc/progs/run
@@ -5,9 +5,7 @@
set -e
-GOBIN="${GOBIN:-$HOME/bin}"
-
-. "$GOROOT"/src/Make.$GOARCH
+eval $(gomake --no-print-directory -f ../../src/Make.inc go-env)
if [ -z "$O" ]; then
echo 'missing $O - maybe no Make.$GOARCH?' 1>&2
@@ -34,11 +32,11 @@ for i in \
; do
BASE=$(basename $i .go)
- "$GOBIN"/$GC $i
+ $GC $i
done
function testit {
- "$GOBIN"/$LD $1.$O
+ $LD $1.$O
x=$(echo $(./$O.out $2 2>&1)) # extra echo canonicalizes
if [ "$x" != "$3" ]
then
@@ -47,7 +45,7 @@ function testit {
}
function testitpipe {
- "$GOBIN"/$LD $1.$O
+ $LD $1.$O
x=$(echo $(./$O.out | $2 2>&1)) # extra echo canonicalizes
if [ "$x" != "$3" ]
then
@@ -76,7 +74,7 @@ testitpipe sieve "sed 10q" "2 3 5 7 11 13 17 19 23 29"
testitpipe sieve "sed 10q" "2 3 5 7 11 13 17 19 23 29"
# server hangs; don't run it, just compile it
-"$GOBIN"/$GC server.go
+$GC server.go
testit server1 "" ""
rm -f $O.out *.$O
diff --git a/doc/progs/sortmain.go b/doc/progs/sortmain.go
index 6bd504a5b..a77ae7381 100644
--- a/doc/progs/sortmain.go
+++ b/doc/progs/sortmain.go
@@ -6,7 +6,7 @@ package main
import (
"fmt"
- "sort"
+ "./sort"
)
func ints() {
diff --git a/doc/progs/sum.go b/doc/progs/sum.go
index 74fd5bca3..9caa799fd 100644
--- a/doc/progs/sum.go
+++ b/doc/progs/sum.go
@@ -6,7 +6,7 @@ package main
import "fmt"
-func sum(a []int) int { // returns an int
+func sum(a []int) int { // returns an int
s := 0
for i := 0; i < len(a); i++ {
s += a[i]
@@ -16,6 +16,6 @@ func sum(a []int) int { // returns an int
func main() {
- s := sum(&[3]int{1,2,3}) // a slice of the array is passed to sum
+ s := sum([3]int{1, 2, 3}[:]) // a slice of the array is passed to sum
fmt.Print(s, "\n")
}
diff --git a/doc/root.html b/doc/root.html
index 3a5a49515..f98f9c243 100644
--- a/doc/root.html
+++ b/doc/root.html
@@ -1,131 +1,97 @@
-<!-- The Go Programming Language -->
+<link rel="stylesheet" type="text/css" href="/doc/frontpage.css">
-<script>
- // On the frontpage we hide the header and navigation elements that other
- // pages have.
- document.getElementById('generatedHeader').style.display = 'none';
- document.getElementById('nav').style.display = 'none';
-</script>
-
-<!-- begin blog post widget JS/styles -->
<script src="http://www.google.com/jsapi" type="text/javascript"></script>
<script type="text/javascript">
function loadFeed() {
- var url = "http://blog.golang.org/feeds/posts/default";
- var divId = "blogFeed";
- var feed = new google.feeds.Feed(url);
- feed.setNumEntries(8)
- feed.load(function (result) {
- var container = document.getElementById(divId)
- if (result.error) {
- container.innerHTML = "Error loading feed.";
- return;
- }
- container.innerHTML = "";
- var entries = result.feed.entries;
- for (var i=0; i<entries.length; i++) {
- var a = document.createElement("a");
- a.setAttribute("href", entries[i].link);
- a.appendChild(document.createTextNode(entries[i].title));
- container.appendChild(a);
- }
- });
+ var url = "http://blog.golang.org/feeds/posts/default";
+ var divId = "blogFeed";
+ var feed = new google.feeds.Feed(url);
+ feed.setNumEntries(4)
+ feed.load(function (result) {
+ var container = document.getElementById(divId)
+ if (result.error) {
+ container.innerHTML = "Error loading feed.";
+ return;
+ }
+ container.innerHTML = "";
+ var entries = result.feed.entries;
+ for (var i=0; i<entries.length; i++) {
+ var li = document.createElement("li");
+ var a = document.createElement("a");
+ a.setAttribute("href", entries[i].link);
+ var span_title = document.createElement("span");
+ span_title.appendChild(document.createTextNode(entries[i].title));
+ span_title.className = "title";
+ a.appendChild(span_title);
+ li.appendChild(a);
+ var span_date = document.createElement("span");
+ span_date.appendChild(document.createTextNode(entries[i].publishedDate.substr(0, 11)));
+ span_date.className = "date";
+ a.appendChild(span_date);
+ container.appendChild(li);
+ }
+ });
}
google.load("feeds", "1");
google.setOnLoadCallback(loadFeed);
</script>
-<!-- end blog post widget JS/styles -->
-
-<div id="gettingStarted">
- <h1>Getting started</h1>
-
- <ol>
- <li>
- <span><a href="/doc/install.html">Install Go</a>.</span>
- </li>
-
- <li>
- <span>Read the <a href="/doc/go_tutorial.html">tutorial</a>.</span>
- </li>
-
- <li>
- <span>Learn the <a href="/pkg">libraries</a>.</span>
- </li>
- </ol>
-
- <h1>Slow compiles?<br>Watch this</h1>
- <table width="100%">
- <tr>
- <td align=center width="100%">
- <a href="http://www.youtube.com/watch?v=wwoWei-GAPo"><img src="/doc/video-snap.jpg"></a>
- </td>
- </tr>
- </table>
-</div>
-
-<div id="blog">
- <h1>From the <a href="http://blog.golang.org">Go Blog</a>:</h1>
- <div id="blogFeed">Loading...</div>
-</div>
-
-
-<div id="frontpage">
-
-<table style="padding-top: 1em; padding-bottom: 2em;">
- <tr>
- <td>
- <img style="padding-right: 1em;" src="/doc/go-logo-black.png">
- </td>
- <td>
- <div><span style="font-size: 2em; font-weight: bold;">a systems programming language</span><br><span style="font-size: 1.5em;">expressive, concurrent, garbage-collected</span></div>
- </td>
- </tr>
-</table>
-
-<p style="font-size: 1.5em; font-weight: bold;">Go is &hellip;</p>
-
-<h3>&hellip; simple</h3>
-<pre class="code">
-package main
-
-import "fmt"
-
-func main() {
- fmt.Printf("Hello, 世界\n")
-}</pre>
-
-<h3>&hellip; fast</h3>
-
-<p>
-Go compilers produce fast code fast. Typical builds take a fraction of a second yet the resulting programs run nearly as quickly as comparable C or C++ code.
-</p>
-
-<h3>&hellip; safe</h3>
-
-<p>Go is type safe and memory safe. Go has pointers but no pointer arithmetic.
-For random access, use slices, which know their limits.</p>
-
-<h3>&hellip; concurrent</h3>
-
-<p>
-Go promotes writing systems and servers as sets of lightweight
-communicating processes, called goroutines, with strong support from the language.
-Run thousands of goroutines if you want&mdash;and say good-bye to stack overflows.
-</p>
-
-<h3>&hellip; fun</h3>
-
-<p>
-Go has fast builds, clean syntax, garbage collection,
-methods for any type, and run-time reflection.
-It feels like a dynamic language but has the speed and safety of a static language.
-It's a joy to use.
-</p>
-
-<h3>&hellip; open source</h3>
-
-<p>
-<a href="/doc/install.html">Go for it</a>.
-</p>
-</div>
+ <div id="frontpage">
+ <div class="left-column">
+ <p style="margin-top: 0;">
+ The Go programming language is an open source project to make
+ programmers more productive. Go is expressive, concise, clean,
+ and efficient. Its concurrency mechanisms make it easy to write
+ programs that get the most out of multicore and networked machines,
+ while its novel type system enables flexible and modular program
+ construction. Go compiles quickly to machine code yet has the
+ convenience of garbage collection and the power of run-time reflection.
+ It's a fast, statically typed, compiled language that feels like a
+ dynamically typed, interpreted language.
+ </p>
+ <h2>Check it out!</h2>
+ <p>
+ <div class="how">[<a href="/doc/playground.html">How does this work?</a>]</div>
+ <a href="/doc/install.html">Install Go now</a>, or try it right here in your browser:</p>
+ <div id="playground" class="small"></div>
+ <script src="/doc/play/playground.js"></script>
+ </div>
+ <div class="right-column">
+ <div id="content-rotating">
+ <div id="content-videos">
+ <h2>Go Videos <span class="more">| <a href="/doc/docs.html#videos_talks">More...</a></span></h2>
+ <a class="video" href="http://osdc.blip.tv/file/4432146/"><img src="/doc/play_overlay.png" class="thumbnail _004" /> <span class="caption title">&ldquo;Practical Go Programming&rdquo;</span> <span class="caption description">OSDC Tech Talk</span></a>
+ </div>
+ <h2>Go Blog <span class="more">| <a href="http://blog.golang.org/">More...</a></span></h2>
+ <div id="content-blog">
+ <ul id="blogFeed">
+ </ul>
+ </div>
+ </div>
+ <h2>Quick Links</h2>
+ <div id="resources">
+ <div id="resources-users">
+ <h3>For newcomers:</h3>
+ <ul>
+ <li><a href="/doc/install.html">Getting Started</a></li>
+ <li><a href="/doc/go_tutorial.html">Tutorial</a></li>
+ <li><a href="/doc/effective_go.html">Effective Go</a></li>
+ <li><a href="/doc/go_faq.html">Go FAQ</a></li>
+ <li><a href="/doc/docs.html">Other Documentation</a></li>
+ </ul>
+ </div>
+ <div id="resources-contributors" class="resources">
+ <h3>For developers:</h3>
+ <ul>
+ <li><a href="http://godashboard.appspot.com/package">Package Dashboard</a></li>
+ <li><a href="http://code.google.com/p/go/issues">Issue Tracker</a></li>
+ <li><a href="http://godashboard.appspot.com/">Build Status</a></li>
+ <li><a href="http://code.google.com/p/go/source/browse/">Go Source</a> [<a href="http://code.google.com/p/go/source/list">changes</a>]</li>
+ <li><a href="/pkg/">Package Reference</a></li>
+ <li><a href="/doc/go_spec.html">Language Specification</a></li>
+ </ul>
+ </div>
+ </div>
+ </div>
+ <div class="end-columns"></div>
+ </div>
diff --git a/doc/style.css b/doc/style.css
deleted file mode 100644
index cd57232a7..000000000
--- a/doc/style.css
+++ /dev/null
@@ -1,282 +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.
-*/
-
-/* ------------------------------------------------------------------------- */
-/* Styles meant to help page authors achieve beauty. */
-
-a {
- text-decoration: none;
-}
-
-code, .code {
- font-size: 100%;
- font-family: monospace;
- color: #0f398d;
-}
-
-kbd {
- font-size: 100%;
- font-family: monospace;
- font-weight: bold;
-}
-
-pre.ebnf {
- background-color: #ffffe9;
-}
-
-pre.grammar {
- background-color: #ffffe9;
-}
-
-p.rule {
- font-style: italic;
-}
-
-span.event {
- font-style: italic;
-}
-
-span.alert {
- color: #ff0000;
-}
-
-body {
- font: 13px Helvetica, Arial, sans-serif;
- margin-bottom: 0px;
-}
-
-h1 {
- margin-top: 0;
- padding-top: 0.75em;
- margin-bottom: 0.75em;
-}
-
-h2, h3, h4, h5, h6 {
- font-family: Helvetica, Arial, sans-serif;
- margin-bottom: 0.25em;
-}
-
-h2 {
- background-color: #e5ecf9;
- margin-top: 2em;
- border-top:1px solid #36C;
- padding-left: 0.2em;
-}
-
-pre {
- font-size: 9pt;
- background-color: #f8f8ff;
- margin: 1em 0 0 0;
- padding: .99em;
- line-height: 125%;
- overflow: auto;
- word-wrap: break-word;
-}
-
-li {
- padding-bottom: 0.5em;
-}
-
-li pre {
- margin: 0.5em 0px 1em 0px;
-}
-
-a:link {
- color: #0f398d
-}
-
-a:visited {
- color: #0b2455
-}
-
-a:hover {
- color: #0000ff
-}
-
-/* ------------------------------------------------------------------------- */
-/* Styles used in the boilerplate-ish parts of pages. */
-
-div#content {
- margin-left: 20%;
- padding: 0 1em 2em 1em;
- margin-top: 0px;
- margin-bottom: 0px;
-/*
- border-left: 2px solid #e5ecf9;
- border-right: 2px solid #e5ecf9;
- border-bottom: 2px solid #e5ecf9;
-*/
-}
-
-#topnav {
- margin: 0px;
- padding-top: 0.2em;
- width: 100%;
- white-space: nowrap;
- background-color: #ffffff;
- border-bottom: 2px solid #36C;
- font: bold 150% Helvetica, Arial, sans-serif;
-}
-
-div#linkList {
- margin-top: 1.5em;
- padding-left: 0.5em;
- font: 13px Helvetica, Arial, sans-serif;
- float: left;
- width: 18%;
- background-color: #fffff0;
- border: 2px solid #ba9836;
-}
-
-div#linkList ul {
- padding: 1px;
- list-style-type: none;
-}
-
-div#linkList li {
- margin-left: 1em;
- padding-bottom: 0.2em;
-}
-
-div#linkList li.navhead {
- font-weight: bold;
- margin-left: 0px;
- padding-bottom: 0.25em;
-}
-
-#nav dl {
- margin: 0 0.5em 0 0.5em;
- padding: 0px;
-}
-
-.navtop {
- font-size: xx-small;
- float: right;
-}
-
-#footer {
- margin: 2em 0 0 0;
- text-align: center;
- color: #555;
- font-size: small;
-}
-
-#footer p {
- margin: 0px;
-}
-
-#footer a {
- color: #555;
-}
-
-@media print {
- div#linkList {
- display: none;
- }
- .navtop {
- display: none;
- }
- div#content {
- margin-left: 0px;
- border: none;
- }
-}
-
-
-/* ------------------------------------------------------------------------- */
-/* Styles used by godoc */
-
-table.layout {
- border-width: 0px;
- border-spacing: 0px;
- padding: 0px;
-}
-
-span.comment {
- color: #0000a0;
-}
-
-span.highlight {
- font-weight: bold;
- background-color: #ffffa0;
-}
-
-span.subtitle {
- font-weight: bold;
- font-size: medium;
-}
-
-/* same style as for gettingStarted */
-#menu {
- margin-top: 1.5em;
- margin-left: 1.75em;
- margin-right: 0em;
- float: right;
- background-color: #fffff0;
- padding-left: 1em;
- padding-right: 1em;
- padding-bottom: 0.75em;
- border: 2px solid #ba9836;
-}
-
-/* same color scheme as for gettingStarted */
-#content .popup {
- position: absolute;
- border: 1px solid #ba9836;
- background-color: #fffff0;
- margin-top: 3em;
- padding: 3px;
-}
-
-#content .identifier,
-#content .type {
- color: #008;
-}
-
-/* ------------------------------------------------------------------------- */
-/* Styles for the frontpage */
-
-#gettingStarted, #blog {
- margin-top: 1.5em;
- margin-left: 1.75em;
- margin-right: 0em;
- float: right;
- clear: right;
- background-color: #fffff0;
- padding-left: 1em;
- padding-right: 1em;
- padding-bottom: 0.75em;
- border: 2px solid #ba9836;
- width: 160px;
-}
-
-#blog { margin-bottom: 1.5em; }
-#blog h1 { font-size: 1.2em; }
-#blog #blogFeed a { font-size: 1.1em; display: block; margin-top: 1em; }
-
-#gettingStarted h1 {
- padding-top: 0.3em;
- margin-bottom: 0.2em;
- font-size: 1.5em;
-}
-
-#gettingStarted ol {
- padding-left: 2em;
-}
-
-#gettingStarted a img {
- border: 1px solid blue;
-}
-
-#frontpage {
- width: 100%;
-}
-
-#frontpage h3 {
- margin-left: 3em;
- font-size: 1.5em;
- font-weight: normal;
-}
diff --git a/doc/talks/gofrontend-gcc-summit-2010.pdf b/doc/talks/gofrontend-gcc-summit-2010.pdf
new file mode 100644
index 000000000..157fd7676
--- /dev/null
+++ b/doc/talks/gofrontend-gcc-summit-2010.pdf
Binary files differ
diff --git a/doc/talks/io2010/balance.go b/doc/talks/io2010/balance.go
index 6a0713831..b01f7468c 100644
--- a/doc/talks/io2010/balance.go
+++ b/doc/talks/io2010/balance.go
@@ -6,6 +6,7 @@ package main
import (
"container/heap"
+ "flag"
"fmt"
"rand"
"time"
@@ -14,6 +15,8 @@ import (
const nRequester = 100
const nWorker = 10
+var roundRobin = flag.Bool("r", false, "use round-robin scheduling")
+
// Simulation of some work: just sleep for a while and report how long.
func op() int {
n := rand.Int63n(1e9)
@@ -125,7 +128,7 @@ func (b *Balancer) print() {
}
func (b *Balancer) dispatch(req Request) {
- if false {
+ if *roundRobin {
w := b.pool[b.i]
w.requests <- req
w.pending++
@@ -144,7 +147,7 @@ func (b *Balancer) dispatch(req Request) {
}
func (b *Balancer) completed(w *Worker) {
- if false {
+ if *roundRobin {
w.pending--
return
}
@@ -156,6 +159,7 @@ func (b *Balancer) completed(w *Worker) {
}
func main() {
+ flag.Parse()
work := make(chan Request)
for i := 0; i < nRequester; i++ {
go requester(work)
diff --git a/doc/video-001.png b/doc/video-001.png
new file mode 100644
index 000000000..d3468bbe8
--- /dev/null
+++ b/doc/video-001.png
Binary files differ
diff --git a/doc/video-002.png b/doc/video-002.png
new file mode 100644
index 000000000..4f7c5d184
--- /dev/null
+++ b/doc/video-002.png
Binary files differ
diff --git a/doc/video-003.png b/doc/video-003.png
new file mode 100644
index 000000000..3dff68602
--- /dev/null
+++ b/doc/video-003.png
Binary files differ
diff --git a/doc/video-004.png b/doc/video-004.png
new file mode 100644
index 000000000..92144549a
--- /dev/null
+++ b/doc/video-004.png
Binary files differ
diff --git a/doc/video-snap.jpg b/doc/video-snap.jpg
deleted file mode 100644
index ae66c558e..000000000
--- a/doc/video-snap.jpg
+++ /dev/null
Binary files differ
diff --git a/include/libc.h b/include/libc.h
index ea6fc3b26..1103bcf81 100644
--- a/include/libc.h
+++ b/include/libc.h
@@ -292,9 +292,15 @@ extern char* getgoroot(void);
extern char* getgoversion(void);
#ifdef __MINGW32__
-extern int fork();
+struct timespec {
+ int tv_sec;
+ long tv_nsec;
+};
+extern int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
+extern int fork(void);
extern int pread(int fd, void *buf, int n, int off);
extern int pwrite(int fd, void *buf, int n, int off);
+#define execv(prog, argv) execv(prog, (const char* const*)(argv))
#define execvp(prog, argv) execvp(prog, (const char**)(argv))
#define lseek(fd, n, base) _lseeki64(fd, n, base)
#define mkdir(path, perm) mkdir(path)
diff --git a/include/u.h b/include/u.h
index 6dd55a09c..3cc1f335c 100644
--- a/include/u.h
+++ b/include/u.h
@@ -68,6 +68,7 @@ extern "C" {
#include <stddef.h>
#include <math.h>
#include <ctype.h> /* for tolower */
+#include <signal.h>
/*
* OS-specific crap
@@ -192,6 +193,10 @@ typedef u64int uint64;
#undef _NEEDUINT
#undef _NEEDULONG
+#ifndef SIGBUS
+#define SIGBUS SIGSEGV /* close enough */
+#endif
+
/*
* Funny-named symbols to tip off 9l to autolink.
*/
diff --git a/lib/codereview/codereview.py b/lib/codereview/codereview.py
index 2d0977caa..e8c84abec 100644
--- a/lib/codereview/codereview.py
+++ b/lib/codereview/codereview.py
@@ -1,12 +1,14 @@
-#!/usr/bin/env python
-#
+# coding=utf-8
+# (The line above is necessary so that I can use 世界 in the
+# *comment* below without Python getting all bent out of shape.)
+
# Copyright 2007-2009 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
@@ -54,6 +56,12 @@ except:
from mercurial.version import version as v
hgversion = v.get_version()
+try:
+ from mercurial.discovery import findcommonincoming
+except:
+ def findcommonincoming(repo, remote):
+ return repo.findcommonincoming(remote)
+
oldMessage = """
The code review extension requires Mercurial 1.3 or newer.
@@ -102,6 +110,35 @@ server = "codereview.appspot.com"
server_url_base = None
defaultcc = None
contributors = {}
+missing_codereview = None
+
+#######################################################################
+# RE: UNICODE STRING HANDLING
+#
+# Python distinguishes between the str (string of bytes)
+# and unicode (string of code points) types. Most operations
+# work on either one just fine, but some (like regexp matching)
+# require unicode, and others (like write) require str.
+#
+# As befits the language, Python hides the distinction between
+# unicode and str by converting between them silently, but
+# *only* if all the bytes/code points involved are 7-bit ASCII.
+# This means that if you're not careful, your program works
+# fine on "hello, world" and fails on "hello, 世界". And of course,
+# the obvious way to be careful - use static types - is unavailable.
+# So the only way is trial and error to find where to put explicit
+# conversions.
+#
+# Because more functions do implicit conversion to str (string of bytes)
+# than do implicit conversion to unicode (string of code points),
+# the convention in this module is to represent all text as str,
+# converting to unicode only when calling a unicode-only function
+# and then converting back to str as soon as possible.
+
+def typecheck(s, t):
+ if type(s) != t:
+ raise util.Abort("type check failed: %s has type %s != %s" % (repr(s), type(s), t))
+
#######################################################################
# Change list parsing.
@@ -120,9 +157,9 @@ diff --git a/~rietveld~placeholder~ b/~rietveld~placeholder~
new file mode 100644
"""
-
class CL(object):
def __init__(self, name):
+ typecheck(name, str)
self.name = name
self.desc = ''
self.files = []
@@ -145,6 +182,7 @@ class CL(object):
s += "Files:\n"
for f in cl.files:
s += "\t" + f + "\n"
+ typecheck(s, str)
return s
def EditorText(self):
@@ -169,6 +207,7 @@ class CL(object):
for f in cl.files:
s += "\t" + f + "\n"
s += "\n"
+ typecheck(s, str)
return s
def PendingText(self):
@@ -183,6 +222,7 @@ class CL(object):
s += "\tFiles:\n"
for f in cl.files:
s += "\t\t" + f + "\n"
+ typecheck(s, str)
return s
def Flush(self, ui, repo):
@@ -210,13 +250,15 @@ class CL(object):
s = s[0:55] + "..."
if self.name != "new":
s = "code review %s: %s" % (self.name, s)
+ typecheck(s, str)
return s
def Upload(self, ui, repo, send_mail=False, gofmt=True, gofmt_just_warn=False):
if not self.files:
ui.warn("no files in change list\n")
if ui.configbool("codereview", "force_gofmt", True) and gofmt:
- CheckGofmt(ui, repo, self.files, just_warn=gofmt_just_warn)
+ CheckFormat(ui, repo, self.files, just_warn=gofmt_just_warn)
+ set_status("uploading CL metadata + diffs")
os.chdir(repo.root)
form_fields = [
("content_upload", "1"),
@@ -229,13 +271,11 @@ class CL(object):
("subject", self.Subject()),
]
- # NOTE(rsc): This duplicates too much of RealMain,
- # but RealMain doesn't have the most reusable interface.
if self.name != "new":
form_fields.append(("issue", self.name))
vcs = None
if self.files:
- vcs = GuessVCS(upload_options)
+ vcs = MercurialVCS(upload_options, ui, repo)
data = vcs.GenerateDiff(self.files)
files = vcs.GetBaseFiles(data)
if len(data) > MAX_UPLOAD_SIZE:
@@ -255,6 +295,7 @@ class CL(object):
patchset = lines[1].strip()
patches = [x.split(" ", 1) for x in lines[2:]]
ui.status(msg + "\n")
+ set_status("uploaded CL metadata + diffs")
if not response_body.startswith("Issue created.") and not response_body.startswith("Issue updated."):
raise util.Abort("failed to update issue: " + response_body)
issue = msg[msg.rfind("/")+1:]
@@ -262,12 +303,16 @@ class CL(object):
if not self.url:
self.url = server_url_base + self.name
if not uploaded_diff_file:
+ set_status("uploading patches")
patches = UploadSeparatePatches(issue, rpc, patchset, data, upload_options)
if vcs:
+ set_status("uploading base files")
vcs.UploadBaseFiles(issue, rpc, patches, patchset, upload_options, files)
if send_mail:
+ set_status("sending mail")
MySend("/" + issue + "/mail", payload="")
self.web = True
+ set_status("flushing changes to disk")
self.Flush(ui, repo)
return
@@ -281,14 +326,18 @@ class CL(object):
pmsg += "I'd like you to review this change.\n"
else:
pmsg += "Please take another look.\n"
+ typecheck(pmsg, str)
PostMessage(ui, self.name, pmsg, subject=self.Subject())
self.mailed = True
self.Flush(ui, repo)
def GoodCLName(name):
+ typecheck(name, str)
return re.match("^[0-9]+$", name)
def ParseCL(text, name):
+ typecheck(text, str)
+ typecheck(name, str)
sname = None
lineno = 0
sections = {
@@ -332,6 +381,7 @@ def ParseCL(text, name):
i = line.find('#')
if i >= 0:
line = line[0:i].rstrip()
+ line = line.strip()
if line == '':
continue
cl.files.append(line)
@@ -349,18 +399,22 @@ def ParseCL(text, name):
return cl, 0, ''
def SplitCommaSpace(s):
+ typecheck(s, str)
s = s.strip()
if s == "":
return []
return re.split(", *", s)
def CutDomain(s):
+ typecheck(s, str)
i = s.find('@')
if i >= 0:
s = s[0:i]
return s
def JoinComma(l):
+ for s in l:
+ typecheck(s, str)
return ", ".join(l)
def ExceptionDetail():
@@ -379,6 +433,8 @@ def IsLocalCL(ui, repo, name):
# Load CL from disk and/or the web.
def LoadCL(ui, repo, name, web=True):
+ typecheck(name, str)
+ set_status("loading CL " + name)
if not GoodCLName(name):
return None, "invalid CL name"
dir = CodeReviewDir(ui, repo)
@@ -412,8 +468,40 @@ def LoadCL(ui, repo, name, web=True):
cl.desc = f['description']
cl.url = server_url_base + name
cl.web = True
+ set_status("loaded CL " + name)
return cl, ''
+global_status = None
+
+def set_status(s):
+ # print >>sys.stderr, "\t", time.asctime(), s
+ global global_status
+ global_status = s
+
+class StatusThread(threading.Thread):
+ def __init__(self):
+ threading.Thread.__init__(self)
+ def run(self):
+ # pause a reasonable amount of time before
+ # starting to display status messages, so that
+ # most hg commands won't ever see them.
+ time.sleep(30)
+
+ # now show status every 15 seconds
+ while True:
+ time.sleep(15 - time.time() % 15)
+ s = global_status
+ if s is None:
+ continue
+ if s == "":
+ s = "(unknown status)"
+ print >>sys.stderr, time.asctime(), s
+
+def start_status_thread():
+ t = StatusThread()
+ t.setDaemon(True) # allowed to exit if t is still running
+ t.start()
+
class LoadCLThread(threading.Thread):
def __init__(self, ui, repo, dir, f, web):
threading.Thread.__init__(self)
@@ -467,6 +555,7 @@ def RepoDir(ui, repo):
url = url[5:]
if url.endswith('/'):
url = url[:-1]
+ typecheck(url, str)
return url
# Find (or make) code review directory. On error, ui.warn and return None
@@ -481,10 +570,12 @@ def CodeReviewDir(ui, repo):
except:
ui.warn('cannot mkdir %s: %s\n' % (dir, ExceptionDetail()))
return None
+ typecheck(dir, str)
return dir
# Strip maximal common leading white space prefix from text
def StripCommon(text):
+ typecheck(text, str)
ws = None
for line in text.split('\n'):
line = line.rstrip()
@@ -513,17 +604,22 @@ def StripCommon(text):
t += line + '\n'
while len(t) >= 2 and t[-2:] == '\n\n':
t = t[:-1]
+ typecheck(t, str)
return t
# Indent text with indent.
def Indent(text, indent):
+ typecheck(text, str)
+ typecheck(indent, str)
t = ''
for line in text.split('\n'):
t += indent + line + '\n'
+ typecheck(t, str)
return t
# Return the first line of l
def line1(text):
+ typecheck(text, str)
return text.split('\n')[0]
_change_prolog = """# Change list.
@@ -592,16 +688,21 @@ def getremote(ui, repo, opts):
# delete it in an attempt to "help"
proxy = os.environ.get('http_proxy')
source = hg.parseurl(ui.expandpath("default"), None)[0]
- other = hg.repository(cmdutil.remoteui(repo, opts), source)
+ try:
+ remoteui = hg.remoteui # hg 1.6
+ except:
+ remoteui = cmdutil.remoteui
+ other = hg.repository(remoteui(repo, opts), source)
if proxy is not None:
os.environ['http_proxy'] = proxy
return other
def Incoming(ui, repo, opts):
- _, incoming, _ = repo.findcommonincoming(getremote(ui, repo, opts))
+ _, incoming, _ = findcommonincoming(repo, getremote(ui, repo, opts))
return incoming
def EditCL(ui, repo, cl):
+ set_status(None) # do not show status
s = cl.EditorText()
while True:
s = ui.edit(s, ui.username())
@@ -660,7 +761,7 @@ original_match = None
def ReplacementForCmdutilMatch(repo, pats=[], opts={}, globbed=False, default='relpath'):
taken = []
files = []
- pats = pats or []
+ pats = pats or []
for p in pats:
if p.startswith('@'):
taken.append(p)
@@ -670,7 +771,7 @@ def ReplacementForCmdutilMatch(repo, pats=[], opts={}, globbed=False, default='r
cl, err = LoadCL(repo.ui, repo, clname, web=False)
if err != '':
raise util.Abort("loading CL " + clname + ": " + err)
- if cl.files == None:
+ if not cl.files:
raise util.Abort("no files in CL " + clname)
files = Add(files, cl.files)
pats = Sub(pats, taken) + ['path:'+f for f in files]
@@ -682,14 +783,21 @@ def RelativePath(path, cwd):
return path[n+1:]
return path
+def CheckFormat(ui, repo, files, just_warn=False):
+ set_status("running gofmt")
+ CheckGofmt(ui, repo, files, just_warn)
+ CheckTabfmt(ui, repo, files, just_warn)
+
# Check that gofmt run on the list of files does not change them
-def CheckGofmt(ui, repo, files, just_warn=False):
+def CheckGofmt(ui, repo, files, just_warn):
files = [f for f in files if (f.startswith('src/') or f.startswith('test/bench/')) and f.endswith('.go')]
if not files:
return
cwd = os.getcwd()
files = [RelativePath(repo.root + '/' + f, cwd) for f in files]
files = [f for f in files if os.access(f, 0)]
+ if not files:
+ return
try:
cmd = subprocess.Popen(["gofmt", "-l"] + files, shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True)
cmd.stdin.close()
@@ -698,6 +806,7 @@ def CheckGofmt(ui, repo, files, just_warn=False):
data = cmd.stdout.read()
errors = cmd.stderr.read()
cmd.wait()
+ set_status("done with gofmt")
if len(errors) > 0:
ui.warn("gofmt errors:\n" + errors.rstrip() + "\n")
return
@@ -709,6 +818,32 @@ def CheckGofmt(ui, repo, files, just_warn=False):
raise util.Abort(msg)
return
+# Check that *.[chys] files indent using tabs.
+def CheckTabfmt(ui, repo, files, just_warn):
+ files = [f for f in files if f.startswith('src/') and re.search(r"\.[chys]$", f)]
+ if not files:
+ return
+ cwd = os.getcwd()
+ files = [RelativePath(repo.root + '/' + f, cwd) for f in files]
+ files = [f for f in files if os.access(f, 0)]
+ badfiles = []
+ for f in files:
+ try:
+ for line in open(f, 'r'):
+ if line.startswith(' '):
+ badfiles.append(f)
+ break
+ except:
+ # ignore cannot open file, etc.
+ pass
+ if len(badfiles) > 0:
+ msg = "these files use spaces for indentation (use tabs instead):\n\t" + "\n\t".join(badfiles)
+ if just_warn:
+ ui.warn("warning: " + msg + "\n")
+ else:
+ raise util.Abort(msg)
+ return
+
#######################################################################
# Mercurial commands
@@ -742,6 +877,9 @@ def change(ui, repo, *pats, **opts):
before running hg change -d 123456.
"""
+ if missing_codereview:
+ return missing_codereview
+
dirty = {}
if len(pats) > 0 and GoodCLName(pats[0]):
name = pats[0]
@@ -776,7 +914,7 @@ def change(ui, repo, *pats, **opts):
if opts["delete"]:
if cl.copied_from:
return "original author must delete CL; hg change -D will remove locally"
- PostMessage(ui, cl.name, "*** Abandoned ***")
+ PostMessage(ui, cl.name, "*** Abandoned ***", send_mail=cl.mailed)
EditDesc(cl.name, closed="checked")
cl.Delete(ui, repo)
return
@@ -825,6 +963,9 @@ def code_login(ui, repo, **opts):
Logs in to the code review server, saving a cookie in
a file in your home directory.
"""
+ if missing_codereview:
+ return missing_codereview
+
MySend(None)
def clpatch(ui, repo, clname, **opts):
@@ -837,6 +978,9 @@ def clpatch(ui, repo, clname, **opts):
Submitting an imported patch will keep the original author's
name as the Author: line but add your own name to a Committer: line.
"""
+ if missing_codereview:
+ return missing_codereview
+
cl, patch, err = DownloadCL(ui, repo, clname)
argv = ["hgpatch"]
if opts["no_incoming"]:
@@ -869,6 +1013,9 @@ def download(ui, repo, clname, **opts):
Download prints a description of the given change list
followed by its diff, downloaded from the code review server.
"""
+ if missing_codereview:
+ return missing_codereview
+
cl, patch, err = DownloadCL(ui, repo, clname)
if err != "":
return err
@@ -884,6 +1031,9 @@ def file(ui, repo, clname, pat, *pats, **opts):
The -d option only removes files from the change list.
It does not edit them or remove them from the repository.
"""
+ if missing_codereview:
+ return missing_codereview
+
pats = tuple([pat] + list(pats))
if not GoodCLName(clname):
return "invalid CL name " + clname
@@ -941,6 +1091,9 @@ def gofmt(ui, repo, *pats, **opts):
Applies gofmt to the modified files in the repository that match
the given patterns.
"""
+ if missing_codereview:
+ return missing_codereview
+
files = ChangedExistingFiles(ui, repo, pats, opts)
files = [f for f in files if f.endswith(".go")]
if not files:
@@ -965,6 +1118,9 @@ def mail(ui, repo, *pats, **opts):
Uploads a patch to the code review server and then sends mail
to the reviewer and CC list asking for a review.
"""
+ if missing_codereview:
+ return missing_codereview
+
cl, err = CommandLineCL(ui, repo, pats, opts, defaultcc=defaultcc)
if err != "":
return err
@@ -990,6 +1146,9 @@ def pending(ui, repo, *pats, **opts):
Lists pending changes followed by a list of unassigned but modified files.
"""
+ if missing_codereview:
+ return missing_codereview
+
m = LoadAllCL(ui, repo, web=True)
names = m.keys()
names.sort()
@@ -1007,11 +1166,13 @@ def pending(ui, repo, *pats, **opts):
def reposetup(ui, repo):
global original_match
if original_match is None:
+ start_status_thread()
original_match = cmdutil.match
cmdutil.match = ReplacementForCmdutilMatch
RietveldSetup(ui, repo)
def CheckContributor(ui, repo, user=None):
+ set_status("checking CONTRIBUTORS file")
if not user:
user = ui.config("ui", "username")
if not user:
@@ -1022,9 +1183,10 @@ def CheckContributor(ui, repo, user=None):
return userline
def FindContributor(ui, repo, user, warn=True):
+ user = user.lower()
m = re.match(r".*<(.*)>", user)
if m:
- user = m.group(1).lower()
+ user = m.group(1)
if user not in contributors:
if warn:
@@ -1040,6 +1202,9 @@ def submit(ui, repo, *pats, **opts):
Submits change to remote repository.
Bails out if the local repository is not in sync with the remote one.
"""
+ if missing_codereview:
+ return missing_codereview
+
repo.ui.quiet = True
if not opts["no_incoming"] and Incoming(ui, repo, opts):
return "local repository out of date; must sync before submit"
@@ -1075,7 +1240,7 @@ def submit(ui, repo, *pats, **opts):
# check gofmt for real; allowed upload to warn in order to save CL.
cl.Flush(ui, repo)
- CheckGofmt(ui, repo, cl.files)
+ CheckFormat(ui, repo, cl.files)
about += "%s%s\n" % (server_url_base, cl.name)
@@ -1152,6 +1317,9 @@ def sync(ui, repo, **opts):
Incorporates recent changes from the remote repository
into the local repository.
"""
+ if missing_codereview:
+ return missing_codereview
+
if not opts["local"]:
ui.status = sync_note
ui.note = sync_note
@@ -1226,15 +1394,14 @@ def sync_changes(ui, repo):
ui.warn("CL %s has no files; suggest hg change -d %s\n" % (cl.name, cl.name))
return
-def uisetup(ui):
- if "^commit|ci" in commands.table:
- commands.table["^commit|ci"] = (nocommit, [], "")
-
def upload(ui, repo, name, **opts):
"""upload diffs to the code review server
Uploads the current modifications for a given change to the server.
"""
+ if missing_codereview:
+ return missing_codereview
+
repo.ui.quiet = True
cl, err = LoadCL(ui, repo, name, web=True)
if err != "":
@@ -1281,11 +1448,6 @@ cmdtable = {
[],
"",
),
- "commit|ci": (
- nocommit,
- [],
- "",
- ),
"^download": (
download,
[],
@@ -1383,7 +1545,7 @@ class FormParser(HTMLParser):
self.handle_data("&" + name + ";")
def handle_data(self, data):
if self.curdata is not None:
- self.curdata += data.decode("utf-8").encode("utf-8")
+ self.curdata += data
# XML parser
def XMLGet(ui, path):
@@ -1399,13 +1561,14 @@ def IsRietveldSubmitted(ui, clname, hex):
if feed is None:
return False
for sum in feed.findall("{http://www.w3.org/2005/Atom}entry/{http://www.w3.org/2005/Atom}summary"):
- text = sum.findtext("", None).strip()
+ text = sum.text.strip()
m = re.match('\*\*\* Submitted as [^*]*?([0-9a-f]+) \*\*\*', text)
if m is not None and len(m.group(1)) >= 8 and hex.startswith(m.group(1)):
return True
return False
def DownloadCL(ui, repo, clname):
+ set_status("downloading CL " + clname)
cl, err = LoadCL(ui, repo, clname)
if err != "":
return None, None, "error loading CL %s: %s" % (clname, ExceptionDetail())
@@ -1432,7 +1595,7 @@ def DownloadCL(ui, repo, clname):
# Find author - first entry will be author who created CL.
nick = None
for author in feed.findall("{http://www.w3.org/2005/Atom}entry/{http://www.w3.org/2005/Atom}author/{http://www.w3.org/2005/Atom}name"):
- nick = author.findtext("", None).strip()
+ nick = author.text.strip()
break
if not nick:
return None, None, "CL has no author"
@@ -1460,96 +1623,102 @@ def DownloadCL(ui, repo, clname):
return cl, diffdata, ""
def MySend(request_path, payload=None,
- content_type="application/octet-stream",
- timeout=None, force_auth=True,
- **kwargs):
- """Run MySend1 maybe twice, because Rietveld is unreliable."""
- try:
- return MySend1(request_path, payload, content_type, timeout, force_auth, **kwargs)
- except Exception, e:
- if type(e) == urllib2.HTTPError and e.code == 403: # forbidden, it happens
- raise
- print >>sys.stderr, "Loading "+request_path+": "+ExceptionDetail()+"; trying again in 2 seconds."
- time.sleep(2)
- return MySend1(request_path, payload, content_type, timeout, force_auth, **kwargs)
-
+ content_type="application/octet-stream",
+ timeout=None, force_auth=True,
+ **kwargs):
+ """Run MySend1 maybe twice, because Rietveld is unreliable."""
+ try:
+ return MySend1(request_path, payload, content_type, timeout, force_auth, **kwargs)
+ except Exception, e:
+ if type(e) == urllib2.HTTPError and e.code == 403: # forbidden, it happens
+ raise
+ print >>sys.stderr, "Loading "+request_path+": "+ExceptionDetail()+"; trying again in 2 seconds."
+ time.sleep(2)
+ return MySend1(request_path, payload, content_type, timeout, force_auth, **kwargs)
# Like upload.py Send but only authenticates when the
# redirect is to www.google.com/accounts. This keeps
# unnecessary redirects from happening during testing.
def MySend1(request_path, payload=None,
- content_type="application/octet-stream",
- timeout=None, force_auth=True,
- **kwargs):
- """Sends an RPC and returns the response.
-
- Args:
- request_path: The path to send the request to, eg /api/appversion/create.
- payload: The body of the request, or None to send an empty request.
- content_type: The Content-Type header to use.
- timeout: timeout in seconds; default None i.e. no timeout.
- (Note: for large requests on OS X, the timeout doesn't work right.)
- kwargs: Any keyword arguments are converted into query string parameters.
-
- Returns:
- The response body, as a string.
- """
- # TODO: Don't require authentication. Let the server say
- # whether it is necessary.
- global rpc
- if rpc == None:
- rpc = GetRpcServer(upload_options)
- self = rpc
- if not self.authenticated and force_auth:
- self._Authenticate()
- if request_path is None:
- return
-
- old_timeout = socket.getdefaulttimeout()
- socket.setdefaulttimeout(timeout)
- try:
- tries = 0
- while True:
- tries += 1
- args = dict(kwargs)
- url = "http://%s%s" % (self.host, request_path)
- if args:
- url += "?" + urllib.urlencode(args)
- req = self._CreateRequest(url=url, data=payload)
- req.add_header("Content-Type", content_type)
- try:
- f = self.opener.open(req)
- response = f.read()
- f.close()
- # Translate \r\n into \n, because Rietveld doesn't.
- response = response.replace('\r\n', '\n')
- return response
- except urllib2.HTTPError, e:
- if tries > 3:
- raise
- elif e.code == 401:
- self._Authenticate()
- elif e.code == 302:
- loc = e.info()["location"]
- if not loc.startswith('https://www.google.com/a') or loc.find('/ServiceLogin') < 0:
- return ''
- self._Authenticate()
- else:
- raise
- finally:
- socket.setdefaulttimeout(old_timeout)
+ content_type="application/octet-stream",
+ timeout=None, force_auth=True,
+ **kwargs):
+ """Sends an RPC and returns the response.
+
+ Args:
+ request_path: The path to send the request to, eg /api/appversion/create.
+ payload: The body of the request, or None to send an empty request.
+ content_type: The Content-Type header to use.
+ timeout: timeout in seconds; default None i.e. no timeout.
+ (Note: for large requests on OS X, the timeout doesn't work right.)
+ kwargs: Any keyword arguments are converted into query string parameters.
+
+ Returns:
+ The response body, as a string.
+ """
+ # TODO: Don't require authentication. Let the server say
+ # whether it is necessary.
+ global rpc
+ if rpc == None:
+ rpc = GetRpcServer(upload_options)
+ self = rpc
+ if not self.authenticated and force_auth:
+ self._Authenticate()
+ if request_path is None:
+ return
+
+ old_timeout = socket.getdefaulttimeout()
+ socket.setdefaulttimeout(timeout)
+ try:
+ tries = 0
+ while True:
+ tries += 1
+ args = dict(kwargs)
+ url = "http://%s%s" % (self.host, request_path)
+ if args:
+ url += "?" + urllib.urlencode(args)
+ req = self._CreateRequest(url=url, data=payload)
+ req.add_header("Content-Type", content_type)
+ try:
+ f = self.opener.open(req)
+ response = f.read()
+ f.close()
+ # Translate \r\n into \n, because Rietveld doesn't.
+ response = response.replace('\r\n', '\n')
+ # who knows what urllib will give us
+ if type(response) == unicode:
+ response = response.encode("utf-8")
+ typecheck(response, str)
+ return response
+ except urllib2.HTTPError, e:
+ if tries > 3:
+ raise
+ elif e.code == 401:
+ self._Authenticate()
+ elif e.code == 302:
+ loc = e.info()["location"]
+ if not loc.startswith('https://www.google.com/a') or loc.find('/ServiceLogin') < 0:
+ return ''
+ self._Authenticate()
+ else:
+ raise
+ finally:
+ socket.setdefaulttimeout(old_timeout)
def GetForm(url):
f = FormParser()
- f.feed(MySend(url))
+ f.feed(MySend(url).decode("utf-8")) # f.feed wants unicode
f.close()
+ # convert back to utf-8 to restore sanity
+ m = {}
for k,v in f.map.items():
- f.map[k] = v.replace("\r\n", "\n");
- return f.map
+ m[k.encode("utf-8")] = v.replace("\r\n", "\n").encode("utf-8")
+ return m
# Fetch the settings for the CL, like reviewer and CC list, by
# scraping the Rietveld editing forms.
def GetSettings(issue):
+ set_status("getting issue metadata from web")
# The /issue/edit page has everything but only the
# CL owner is allowed to fetch it (and submit it).
f = None
@@ -1566,6 +1735,7 @@ def GetSettings(issue):
return f
def EditDesc(issue, subject=None, desc=None, reviewers=None, cc=None, closed=None):
+ set_status("uploading change to description")
form_fields = GetForm("/" + issue + "/edit")
if subject is not None:
form_fields['subject'] = subject
@@ -1584,6 +1754,7 @@ def EditDesc(issue, subject=None, desc=None, reviewers=None, cc=None, closed=Non
sys.exit(2)
def PostMessage(ui, issue, message, reviewers=None, cc=None, send_mail=True, subject=None):
+ set_status("uploading message")
form_fields = GetForm("/" + issue + "/publish")
if reviewers is not None:
form_fields['reviewers'] = reviewers
@@ -1610,17 +1781,36 @@ def PostMessage(ui, issue, message, reviewers=None, cc=None, send_mail=True, sub
class opt(object):
pass
+def disabled(*opts, **kwopts):
+ raise util.Abort("commit is disabled when codereview is in use")
+
def RietveldSetup(ui, repo):
global defaultcc, upload_options, rpc, server, server_url_base, force_google_account, verbosity, contributors
+ global missing_codereview
+ repo_config_path = ''
# Read repository-specific options from lib/codereview/codereview.cfg
try:
- f = open(repo.root + '/lib/codereview/codereview.cfg')
+ repo_config_path = repo.root + '/lib/codereview/codereview.cfg'
+ f = open(repo_config_path)
for line in f:
if line.startswith('defaultcc: '):
defaultcc = SplitCommaSpace(line[10:])
except:
- pass
+ # If there are no options, chances are good this is not
+ # a code review repository; stop now before we foul
+ # things up even worse. Might also be that repo doesn't
+ # even have a root. See issue 959.
+ if repo_config_path == '':
+ missing_codereview = 'codereview disabled: repository has no root'
+ else:
+ missing_codereview = 'codereview disabled: cannot open ' + repo_config_path
+ return
+
+ # Should only modify repository with hg submit.
+ # Disable the built-in Mercurial commands that might
+ # trip things up.
+ cmdutil.commit = disabled
try:
f = open(repo.root + '/CONTRIBUTORS', 'r')
@@ -1640,15 +1830,6 @@ def RietveldSetup(ui, repo):
contributors[email.lower()] = (name, email)
for extra in m.group(3).split():
contributors[extra[1:-1].lower()] = (name, email)
-
-
- # TODO(rsc): If the repository config has no codereview section,
- # do not enable the extension. This allows users to
- # put the extension in their global .hgrc but only
- # enable it for some repositories.
- # if not ui.has_section("codereview"):
- # cmdtable = {}
- # return
if not ui.verbose:
verbosity = 0
@@ -1693,11 +1874,7 @@ def RietveldSetup(ui, repo):
rpc = None
#######################################################################
-# We keep a full copy of upload.py here to avoid import path hell.
-# It would be nice if hg added the hg repository root
-# to the default PYTHONPATH.
-
-# Edit .+2,<hget http://codereview.appspot.com/static/upload.py
+# http://codereview.appspot.com/static/upload.py, heavily edited.
#!/usr/bin/env python
#
@@ -1707,7 +1884,7 @@ def RietveldSetup(ui, repo):
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
@@ -1722,9 +1899,9 @@ Usage summary: upload.py [options] [-- diff_options]
Diff options are passed to the diff command of the underlying system.
Supported version control systems:
- Git
- Mercurial
- Subversion
+ Git
+ Mercurial
+ Subversion
It is important for Git/Mercurial users to specify a tree/node/branch to diff
against by using the '--rev' option.
@@ -1748,14 +1925,14 @@ import urlparse
# The md5 module was deprecated in Python 2.5.
try:
- from hashlib import md5
+ from hashlib import md5
except ImportError:
- from md5 import md5
+ from md5 import md5
try:
- import readline
+ import readline
except ImportError:
- pass
+ pass
# The logging verbosity:
# 0: Errors only.
@@ -1767,1463 +1944,827 @@ verbosity = 1
# Max size of patch or base file.
MAX_UPLOAD_SIZE = 900 * 1024
-# Constants for version control names. Used by GuessVCSName.
-VCS_GIT = "Git"
-VCS_MERCURIAL = "Mercurial"
-VCS_SUBVERSION = "Subversion"
-VCS_UNKNOWN = "Unknown"
-
# whitelist for non-binary filetypes which do not start with "text/"
# .mm (Objective-C) shows up as application/x-freemind on my Linux box.
-TEXT_MIMETYPES = ['application/javascript', 'application/x-javascript',
- 'application/x-freemind']
-
-VCS_ABBREVIATIONS = {
- VCS_MERCURIAL.lower(): VCS_MERCURIAL,
- "hg": VCS_MERCURIAL,
- VCS_SUBVERSION.lower(): VCS_SUBVERSION,
- "svn": VCS_SUBVERSION,
- VCS_GIT.lower(): VCS_GIT,
-}
-
+TEXT_MIMETYPES = [
+ 'application/javascript',
+ 'application/x-javascript',
+ 'application/x-freemind'
+]
def GetEmail(prompt):
- """Prompts the user for their email address and returns it.
+ """Prompts the user for their email address and returns it.
- The last used email address is saved to a file and offered up as a suggestion
- to the user. If the user presses enter without typing in anything the last
- used email address is used. If the user enters a new address, it is saved
- for next time we prompt.
+ The last used email address is saved to a file and offered up as a suggestion
+ to the user. If the user presses enter without typing in anything the last
+ used email address is used. If the user enters a new address, it is saved
+ for next time we prompt.
- """
- last_email_file_name = os.path.expanduser("~/.last_codereview_email_address")
- last_email = ""
- if os.path.exists(last_email_file_name):
- try:
- last_email_file = open(last_email_file_name, "r")
- last_email = last_email_file.readline().strip("\n")
- last_email_file.close()
- prompt += " [%s]" % last_email
- except IOError, e:
- pass
- email = raw_input(prompt + ": ").strip()
- if email:
- try:
- last_email_file = open(last_email_file_name, "w")
- last_email_file.write(email)
- last_email_file.close()
- except IOError, e:
- pass
- else:
- email = last_email
- return email
+ """
+ last_email_file_name = os.path.expanduser("~/.last_codereview_email_address")
+ last_email = ""
+ if os.path.exists(last_email_file_name):
+ try:
+ last_email_file = open(last_email_file_name, "r")
+ last_email = last_email_file.readline().strip("\n")
+ last_email_file.close()
+ prompt += " [%s]" % last_email
+ except IOError, e:
+ pass
+ email = raw_input(prompt + ": ").strip()
+ if email:
+ try:
+ last_email_file = open(last_email_file_name, "w")
+ last_email_file.write(email)
+ last_email_file.close()
+ except IOError, e:
+ pass
+ else:
+ email = last_email
+ return email
def StatusUpdate(msg):
- """Print a status message to stdout.
+ """Print a status message to stdout.
- If 'verbosity' is greater than 0, print the message.
+ If 'verbosity' is greater than 0, print the message.
- Args:
- msg: The string to print.
- """
- if verbosity > 0:
- print msg
+ Args:
+ msg: The string to print.
+ """
+ if verbosity > 0:
+ print msg
def ErrorExit(msg):
- """Print an error message to stderr and exit."""
- print >>sys.stderr, msg
- sys.exit(1)
+ """Print an error message to stderr and exit."""
+ print >>sys.stderr, msg
+ sys.exit(1)
class ClientLoginError(urllib2.HTTPError):
- """Raised to indicate there was an error authenticating with ClientLogin."""
+ """Raised to indicate there was an error authenticating with ClientLogin."""
- def __init__(self, url, code, msg, headers, args):
- urllib2.HTTPError.__init__(self, url, code, msg, headers, None)
- self.args = args
- self.reason = args["Error"]
+ def __init__(self, url, code, msg, headers, args):
+ urllib2.HTTPError.__init__(self, url, code, msg, headers, None)
+ self.args = args
+ self.reason = args["Error"]
class AbstractRpcServer(object):
- """Provides a common interface for a simple RPC server."""
-
- def __init__(self, host, auth_function, host_override=None, extra_headers={},
- save_cookies=False):
- """Creates a new HttpRpcServer.
-
- Args:
- host: The host to send requests to.
- auth_function: A function that takes no arguments and returns an
- (email, password) tuple when called. Will be called if authentication
- is required.
- host_override: The host header to send to the server (defaults to host).
- extra_headers: A dict of extra headers to append to every request.
- save_cookies: If True, save the authentication cookies to local disk.
- If False, use an in-memory cookiejar instead. Subclasses must
- implement this functionality. Defaults to False.
- """
- self.host = host
- self.host_override = host_override
- self.auth_function = auth_function
- self.authenticated = False
- self.extra_headers = extra_headers
- self.save_cookies = save_cookies
- self.opener = self._GetOpener()
- if self.host_override:
- logging.info("Server: %s; Host: %s", self.host, self.host_override)
- else:
- logging.info("Server: %s", self.host)
-
- def _GetOpener(self):
- """Returns an OpenerDirector for making HTTP requests.
-
- Returns:
- A urllib2.OpenerDirector object.
- """
- raise NotImplementedError()
-
- def _CreateRequest(self, url, data=None):
- """Creates a new urllib request."""
- logging.debug("Creating request for: '%s' with payload:\n%s", url, data)
- req = urllib2.Request(url, data=data)
- if self.host_override:
- req.add_header("Host", self.host_override)
- for key, value in self.extra_headers.iteritems():
- req.add_header(key, value)
- return req
-
- def _GetAuthToken(self, email, password):
- """Uses ClientLogin to authenticate the user, returning an auth token.
-
- Args:
- email: The user's email address
- password: The user's password
-
- Raises:
- ClientLoginError: If there was an error authenticating with ClientLogin.
- HTTPError: If there was some other form of HTTP error.
-
- Returns:
- The authentication token returned by ClientLogin.
- """
- account_type = "GOOGLE"
- if self.host.endswith(".google.com") and not force_google_account:
- # Needed for use inside Google.
- account_type = "HOSTED"
- req = self._CreateRequest(
- url="https://www.google.com/accounts/ClientLogin",
- data=urllib.urlencode({
- "Email": email,
- "Passwd": password,
- "service": "ah",
- "source": "rietveld-codereview-upload",
- "accountType": account_type,
- }),
- )
- try:
- response = self.opener.open(req)
- response_body = response.read()
- response_dict = dict(x.split("=")
- for x in response_body.split("\n") if x)
- return response_dict["Auth"]
- except urllib2.HTTPError, e:
- if e.code == 403:
- body = e.read()
- response_dict = dict(x.split("=", 1) for x in body.split("\n") if x)
- raise ClientLoginError(req.get_full_url(), e.code, e.msg,
- e.headers, response_dict)
- else:
- raise
-
- def _GetAuthCookie(self, auth_token):
- """Fetches authentication cookies for an authentication token.
-
- Args:
- auth_token: The authentication token returned by ClientLogin.
-
- Raises:
- HTTPError: If there was an error fetching the authentication cookies.
- """
- # This is a dummy value to allow us to identify when we're successful.
- continue_location = "http://localhost/"
- args = {"continue": continue_location, "auth": auth_token}
- req = self._CreateRequest("http://%s/_ah/login?%s" %
- (self.host, urllib.urlencode(args)))
- try:
- response = self.opener.open(req)
- except urllib2.HTTPError, e:
- response = e
- if (response.code != 302 or
- response.info()["location"] != continue_location):
- raise urllib2.HTTPError(req.get_full_url(), response.code, response.msg,
- response.headers, response.fp)
- self.authenticated = True
-
- def _Authenticate(self):
- """Authenticates the user.
-
- The authentication process works as follows:
- 1) We get a username and password from the user
- 2) We use ClientLogin to obtain an AUTH token for the user
- (see http://code.google.com/apis/accounts/AuthForInstalledApps.html).
- 3) We pass the auth token to /_ah/login on the server to obtain an
- authentication cookie. If login was successful, it tries to redirect
- us to the URL we provided.
-
- If we attempt to access the upload API without first obtaining an
- authentication cookie, it returns a 401 response (or a 302) and
- directs us to authenticate ourselves with ClientLogin.
- """
- for i in range(3):
- credentials = self.auth_function()
- try:
- auth_token = self._GetAuthToken(credentials[0], credentials[1])
- except ClientLoginError, e:
- if e.reason == "BadAuthentication":
- print >>sys.stderr, "Invalid username or password."
- continue
- if e.reason == "CaptchaRequired":
- print >>sys.stderr, (
- "Please go to\n"
- "https://www.google.com/accounts/DisplayUnlockCaptcha\n"
- "and verify you are a human. Then try again.")
- break
- if e.reason == "NotVerified":
- print >>sys.stderr, "Account not verified."
- break
- if e.reason == "TermsNotAgreed":
- print >>sys.stderr, "User has not agreed to TOS."
- break
- if e.reason == "AccountDeleted":
- print >>sys.stderr, "The user account has been deleted."
- break
- if e.reason == "AccountDisabled":
- print >>sys.stderr, "The user account has been disabled."
- break
- if e.reason == "ServiceDisabled":
- print >>sys.stderr, ("The user's access to the service has been "
- "disabled.")
- break
- if e.reason == "ServiceUnavailable":
- print >>sys.stderr, "The service is not available; try again later."
- break
- raise
- self._GetAuthCookie(auth_token)
- return
-
- def Send(self, request_path, payload=None,
- content_type="application/octet-stream",
- timeout=None,
- **kwargs):
- """Sends an RPC and returns the response.
-
- Args:
- request_path: The path to send the request to, eg /api/appversion/create.
- payload: The body of the request, or None to send an empty request.
- content_type: The Content-Type header to use.
- timeout: timeout in seconds; default None i.e. no timeout.
- (Note: for large requests on OS X, the timeout doesn't work right.)
- kwargs: Any keyword arguments are converted into query string parameters.
-
- Returns:
- The response body, as a string.
- """
- # TODO: Don't require authentication. Let the server say
- # whether it is necessary.
- if not self.authenticated:
- self._Authenticate()
-
- old_timeout = socket.getdefaulttimeout()
- socket.setdefaulttimeout(timeout)
- try:
- tries = 0
- while True:
- tries += 1
- args = dict(kwargs)
- url = "http://%s%s" % (self.host, request_path)
- if args:
- url += "?" + urllib.urlencode(args)
- req = self._CreateRequest(url=url, data=payload)
- req.add_header("Content-Type", content_type)
- try:
- f = self.opener.open(req)
- response = f.read()
- f.close()
- return response
- except urllib2.HTTPError, e:
- if tries > 3:
- raise
- elif e.code == 401 or e.code == 302:
- self._Authenticate()
- else:
- raise
- finally:
- socket.setdefaulttimeout(old_timeout)
+ """Provides a common interface for a simple RPC server."""
+
+ def __init__(self, host, auth_function, host_override=None, extra_headers={}, save_cookies=False):
+ """Creates a new HttpRpcServer.
+
+ Args:
+ host: The host to send requests to.
+ auth_function: A function that takes no arguments and returns an
+ (email, password) tuple when called. Will be called if authentication
+ is required.
+ host_override: The host header to send to the server (defaults to host).
+ extra_headers: A dict of extra headers to append to every request.
+ save_cookies: If True, save the authentication cookies to local disk.
+ If False, use an in-memory cookiejar instead. Subclasses must
+ implement this functionality. Defaults to False.
+ """
+ self.host = host
+ self.host_override = host_override
+ self.auth_function = auth_function
+ self.authenticated = False
+ self.extra_headers = extra_headers
+ self.save_cookies = save_cookies
+ self.opener = self._GetOpener()
+ if self.host_override:
+ logging.info("Server: %s; Host: %s", self.host, self.host_override)
+ else:
+ logging.info("Server: %s", self.host)
+
+ def _GetOpener(self):
+ """Returns an OpenerDirector for making HTTP requests.
+
+ Returns:
+ A urllib2.OpenerDirector object.
+ """
+ raise NotImplementedError()
+
+ def _CreateRequest(self, url, data=None):
+ """Creates a new urllib request."""
+ logging.debug("Creating request for: '%s' with payload:\n%s", url, data)
+ req = urllib2.Request(url, data=data)
+ if self.host_override:
+ req.add_header("Host", self.host_override)
+ for key, value in self.extra_headers.iteritems():
+ req.add_header(key, value)
+ return req
+
+ def _GetAuthToken(self, email, password):
+ """Uses ClientLogin to authenticate the user, returning an auth token.
+
+ Args:
+ email: The user's email address
+ password: The user's password
+
+ Raises:
+ ClientLoginError: If there was an error authenticating with ClientLogin.
+ HTTPError: If there was some other form of HTTP error.
+
+ Returns:
+ The authentication token returned by ClientLogin.
+ """
+ account_type = "GOOGLE"
+ if self.host.endswith(".google.com") and not force_google_account:
+ # Needed for use inside Google.
+ account_type = "HOSTED"
+ req = self._CreateRequest(
+ url="https://www.google.com/accounts/ClientLogin",
+ data=urllib.urlencode({
+ "Email": email,
+ "Passwd": password,
+ "service": "ah",
+ "source": "rietveld-codereview-upload",
+ "accountType": account_type,
+ }),
+ )
+ try:
+ response = self.opener.open(req)
+ response_body = response.read()
+ response_dict = dict(x.split("=") for x in response_body.split("\n") if x)
+ return response_dict["Auth"]
+ except urllib2.HTTPError, e:
+ if e.code == 403:
+ body = e.read()
+ response_dict = dict(x.split("=", 1) for x in body.split("\n") if x)
+ raise ClientLoginError(req.get_full_url(), e.code, e.msg, e.headers, response_dict)
+ else:
+ raise
+
+ def _GetAuthCookie(self, auth_token):
+ """Fetches authentication cookies for an authentication token.
+
+ Args:
+ auth_token: The authentication token returned by ClientLogin.
+
+ Raises:
+ HTTPError: If there was an error fetching the authentication cookies.
+ """
+ # This is a dummy value to allow us to identify when we're successful.
+ continue_location = "http://localhost/"
+ args = {"continue": continue_location, "auth": auth_token}
+ req = self._CreateRequest("http://%s/_ah/login?%s" % (self.host, urllib.urlencode(args)))
+ try:
+ response = self.opener.open(req)
+ except urllib2.HTTPError, e:
+ response = e
+ if (response.code != 302 or
+ response.info()["location"] != continue_location):
+ raise urllib2.HTTPError(req.get_full_url(), response.code, response.msg, response.headers, response.fp)
+ self.authenticated = True
+
+ def _Authenticate(self):
+ """Authenticates the user.
+
+ The authentication process works as follows:
+ 1) We get a username and password from the user
+ 2) We use ClientLogin to obtain an AUTH token for the user
+ (see http://code.google.com/apis/accounts/AuthForInstalledApps.html).
+ 3) We pass the auth token to /_ah/login on the server to obtain an
+ authentication cookie. If login was successful, it tries to redirect
+ us to the URL we provided.
+
+ If we attempt to access the upload API without first obtaining an
+ authentication cookie, it returns a 401 response (or a 302) and
+ directs us to authenticate ourselves with ClientLogin.
+ """
+ for i in range(3):
+ credentials = self.auth_function()
+ try:
+ auth_token = self._GetAuthToken(credentials[0], credentials[1])
+ except ClientLoginError, e:
+ if e.reason == "BadAuthentication":
+ print >>sys.stderr, "Invalid username or password."
+ continue
+ if e.reason == "CaptchaRequired":
+ print >>sys.stderr, (
+ "Please go to\n"
+ "https://www.google.com/accounts/DisplayUnlockCaptcha\n"
+ "and verify you are a human. Then try again.")
+ break
+ if e.reason == "NotVerified":
+ print >>sys.stderr, "Account not verified."
+ break
+ if e.reason == "TermsNotAgreed":
+ print >>sys.stderr, "User has not agreed to TOS."
+ break
+ if e.reason == "AccountDeleted":
+ print >>sys.stderr, "The user account has been deleted."
+ break
+ if e.reason == "AccountDisabled":
+ print >>sys.stderr, "The user account has been disabled."
+ break
+ if e.reason == "ServiceDisabled":
+ print >>sys.stderr, "The user's access to the service has been disabled."
+ break
+ if e.reason == "ServiceUnavailable":
+ print >>sys.stderr, "The service is not available; try again later."
+ break
+ raise
+ self._GetAuthCookie(auth_token)
+ return
+
+ def Send(self, request_path, payload=None,
+ content_type="application/octet-stream",
+ timeout=None,
+ **kwargs):
+ """Sends an RPC and returns the response.
+
+ Args:
+ request_path: The path to send the request to, eg /api/appversion/create.
+ payload: The body of the request, or None to send an empty request.
+ content_type: The Content-Type header to use.
+ timeout: timeout in seconds; default None i.e. no timeout.
+ (Note: for large requests on OS X, the timeout doesn't work right.)
+ kwargs: Any keyword arguments are converted into query string parameters.
+
+ Returns:
+ The response body, as a string.
+ """
+ # TODO: Don't require authentication. Let the server say
+ # whether it is necessary.
+ if not self.authenticated:
+ self._Authenticate()
+
+ old_timeout = socket.getdefaulttimeout()
+ socket.setdefaulttimeout(timeout)
+ try:
+ tries = 0
+ while True:
+ tries += 1
+ args = dict(kwargs)
+ url = "http://%s%s" % (self.host, request_path)
+ if args:
+ url += "?" + urllib.urlencode(args)
+ req = self._CreateRequest(url=url, data=payload)
+ req.add_header("Content-Type", content_type)
+ try:
+ f = self.opener.open(req)
+ response = f.read()
+ f.close()
+ return response
+ except urllib2.HTTPError, e:
+ if tries > 3:
+ raise
+ elif e.code == 401 or e.code == 302:
+ self._Authenticate()
+ else:
+ raise
+ finally:
+ socket.setdefaulttimeout(old_timeout)
class HttpRpcServer(AbstractRpcServer):
- """Provides a simplified RPC-style interface for HTTP requests."""
-
- def _Authenticate(self):
- """Save the cookie jar after authentication."""
- super(HttpRpcServer, self)._Authenticate()
- if self.save_cookies:
- StatusUpdate("Saving authentication cookies to %s" % self.cookie_file)
- self.cookie_jar.save()
-
- def _GetOpener(self):
- """Returns an OpenerDirector that supports cookies and ignores redirects.
-
- Returns:
- A urllib2.OpenerDirector object.
- """
- opener = urllib2.OpenerDirector()
- opener.add_handler(urllib2.ProxyHandler())
- opener.add_handler(urllib2.UnknownHandler())
- opener.add_handler(urllib2.HTTPHandler())
- opener.add_handler(urllib2.HTTPDefaultErrorHandler())
- opener.add_handler(urllib2.HTTPSHandler())
- opener.add_handler(urllib2.HTTPErrorProcessor())
- if self.save_cookies:
- self.cookie_file = os.path.expanduser("~/.codereview_upload_cookies_" + server)
- self.cookie_jar = cookielib.MozillaCookieJar(self.cookie_file)
- if os.path.exists(self.cookie_file):
- try:
- self.cookie_jar.load()
- self.authenticated = True
- StatusUpdate("Loaded authentication cookies from %s" %
- self.cookie_file)
- except (cookielib.LoadError, IOError):
- # Failed to load cookies - just ignore them.
- pass
- else:
- # Create an empty cookie file with mode 600
- fd = os.open(self.cookie_file, os.O_CREAT, 0600)
- os.close(fd)
- # Always chmod the cookie file
- os.chmod(self.cookie_file, 0600)
- else:
- # Don't save cookies across runs of update.py.
- self.cookie_jar = cookielib.CookieJar()
- opener.add_handler(urllib2.HTTPCookieProcessor(self.cookie_jar))
- return opener
-
-
-parser = optparse.OptionParser(usage="%prog [options] [-- diff_options]")
-parser.add_option("-y", "--assume_yes", action="store_true",
- dest="assume_yes", default=False,
- help="Assume that the answer to yes/no questions is 'yes'.")
-# Logging
-group = parser.add_option_group("Logging options")
-group.add_option("-q", "--quiet", action="store_const", const=0,
- dest="verbose", help="Print errors only.")
-group.add_option("-v", "--verbose", action="store_const", const=2,
- dest="verbose", default=1,
- help="Print info level logs (default).")
-group.add_option("--noisy", action="store_const", const=3,
- dest="verbose", help="Print all logs.")
-# Review server
-group = parser.add_option_group("Review server options")
-group.add_option("-s", "--server", action="store", dest="server",
- default="codereview.appspot.com",
- metavar="SERVER",
- help=("The server to upload to. The format is host[:port]. "
- "Defaults to '%default'."))
-group.add_option("-e", "--email", action="store", dest="email",
- metavar="EMAIL", default=None,
- help="The username to use. Will prompt if omitted.")
-group.add_option("-H", "--host", action="store", dest="host",
- metavar="HOST", default=None,
- help="Overrides the Host header sent with all RPCs.")
-group.add_option("--no_cookies", action="store_false",
- dest="save_cookies", default=True,
- help="Do not save authentication cookies to local disk.")
-# Issue
-group = parser.add_option_group("Issue options")
-group.add_option("-d", "--description", action="store", dest="description",
- metavar="DESCRIPTION", default=None,
- help="Optional description when creating an issue.")
-group.add_option("-f", "--description_file", action="store",
- dest="description_file", metavar="DESCRIPTION_FILE",
- default=None,
- help="Optional path of a file that contains "
- "the description when creating an issue.")
-group.add_option("-r", "--reviewers", action="store", dest="reviewers",
- metavar="REVIEWERS", default=None,
- help="Add reviewers (comma separated email addresses).")
-group.add_option("--cc", action="store", dest="cc",
- metavar="CC", default=None,
- help="Add CC (comma separated email addresses).")
-group.add_option("--private", action="store_true", dest="private",
- default=False,
- help="Make the issue restricted to reviewers and those CCed")
-# Upload options
-group = parser.add_option_group("Patch options")
-group.add_option("-m", "--message", action="store", dest="message",
- metavar="MESSAGE", default=None,
- help="A message to identify the patch. "
- "Will prompt if omitted.")
-group.add_option("-i", "--issue", type="int", action="store",
- metavar="ISSUE", default=None,
- help="Issue number to which to add. Defaults to new issue.")
-group.add_option("--download_base", action="store_true",
- dest="download_base", default=False,
- help="Base files will be downloaded by the server "
- "(side-by-side diffs may not work on files with CRs).")
-group.add_option("--rev", action="store", dest="revision",
- metavar="REV", default=None,
- help="Branch/tree/revision to diff against (used by DVCS).")
-group.add_option("--send_mail", action="store_true",
- dest="send_mail", default=False,
- help="Send notification email to reviewers.")
-group.add_option("--vcs", action="store", dest="vcs",
- metavar="VCS", default=None,
- help=("Version control system (optional, usually upload.py "
- "already guesses the right VCS)."))
+ """Provides a simplified RPC-style interface for HTTP requests."""
+
+ def _Authenticate(self):
+ """Save the cookie jar after authentication."""
+ super(HttpRpcServer, self)._Authenticate()
+ if self.save_cookies:
+ StatusUpdate("Saving authentication cookies to %s" % self.cookie_file)
+ self.cookie_jar.save()
+
+ def _GetOpener(self):
+ """Returns an OpenerDirector that supports cookies and ignores redirects.
+
+ Returns:
+ A urllib2.OpenerDirector object.
+ """
+ opener = urllib2.OpenerDirector()
+ opener.add_handler(urllib2.ProxyHandler())
+ opener.add_handler(urllib2.UnknownHandler())
+ opener.add_handler(urllib2.HTTPHandler())
+ opener.add_handler(urllib2.HTTPDefaultErrorHandler())
+ opener.add_handler(urllib2.HTTPSHandler())
+ opener.add_handler(urllib2.HTTPErrorProcessor())
+ if self.save_cookies:
+ self.cookie_file = os.path.expanduser("~/.codereview_upload_cookies_" + server)
+ self.cookie_jar = cookielib.MozillaCookieJar(self.cookie_file)
+ if os.path.exists(self.cookie_file):
+ try:
+ self.cookie_jar.load()
+ self.authenticated = True
+ StatusUpdate("Loaded authentication cookies from %s" % self.cookie_file)
+ except (cookielib.LoadError, IOError):
+ # Failed to load cookies - just ignore them.
+ pass
+ else:
+ # Create an empty cookie file with mode 600
+ fd = os.open(self.cookie_file, os.O_CREAT, 0600)
+ os.close(fd)
+ # Always chmod the cookie file
+ os.chmod(self.cookie_file, 0600)
+ else:
+ # Don't save cookies across runs of update.py.
+ self.cookie_jar = cookielib.CookieJar()
+ opener.add_handler(urllib2.HTTPCookieProcessor(self.cookie_jar))
+ return opener
def GetRpcServer(options):
- """Returns an instance of an AbstractRpcServer.
-
- Returns:
- A new AbstractRpcServer, on which RPC calls can be made.
- """
-
- rpc_server_class = HttpRpcServer
-
- def GetUserCredentials():
- """Prompts the user for a username and password."""
- email = options.email
- if email is None:
- email = GetEmail("Email (login for uploading to %s)" % options.server)
- password = getpass.getpass("Password for %s: " % email)
- return (email, password)
-
- # If this is the dev_appserver, use fake authentication.
- host = (options.host or options.server).lower()
- if host == "localhost" or host.startswith("localhost:"):
- email = options.email
- if email is None:
- email = "test@example.com"
- logging.info("Using debug user %s. Override with --email" % email)
- server = rpc_server_class(
- options.server,
- lambda: (email, "password"),
- host_override=options.host,
- extra_headers={"Cookie":
- 'dev_appserver_login="%s:False"' % email},
- save_cookies=options.save_cookies)
- # Don't try to talk to ClientLogin.
- server.authenticated = True
- return server
-
- return rpc_server_class(options.server, GetUserCredentials,
- host_override=options.host,
- save_cookies=options.save_cookies)
+ """Returns an instance of an AbstractRpcServer.
+
+ Returns:
+ A new AbstractRpcServer, on which RPC calls can be made.
+ """
+
+ rpc_server_class = HttpRpcServer
+
+ def GetUserCredentials():
+ """Prompts the user for a username and password."""
+ email = options.email
+ if email is None:
+ email = GetEmail("Email (login for uploading to %s)" % options.server)
+ password = getpass.getpass("Password for %s: " % email)
+ return (email, password)
+
+ # If this is the dev_appserver, use fake authentication.
+ host = (options.host or options.server).lower()
+ if host == "localhost" or host.startswith("localhost:"):
+ email = options.email
+ if email is None:
+ email = "test@example.com"
+ logging.info("Using debug user %s. Override with --email" % email)
+ server = rpc_server_class(
+ options.server,
+ lambda: (email, "password"),
+ host_override=options.host,
+ extra_headers={"Cookie": 'dev_appserver_login="%s:False"' % email},
+ save_cookies=options.save_cookies)
+ # Don't try to talk to ClientLogin.
+ server.authenticated = True
+ return server
+
+ return rpc_server_class(options.server, GetUserCredentials,
+ host_override=options.host, save_cookies=options.save_cookies)
def EncodeMultipartFormData(fields, files):
- """Encode form fields for multipart/form-data.
-
- Args:
- fields: A sequence of (name, value) elements for regular form fields.
- files: A sequence of (name, filename, value) elements for data to be
- uploaded as files.
- Returns:
- (content_type, body) ready for httplib.HTTP instance.
-
- Source:
- http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/146306
- """
- BOUNDARY = '-M-A-G-I-C---B-O-U-N-D-A-R-Y-'
- CRLF = '\r\n'
- lines = []
- for (key, value) in fields:
- lines.append('--' + BOUNDARY)
- lines.append('Content-Disposition: form-data; name="%s"' % key)
- lines.append('')
- if type(value) == unicode:
- value = value.encode("utf-8")
- lines.append(value)
- for (key, filename, value) in files:
- if type(filename) == unicode:
- filename = filename.encode("utf-8")
- if type(value) == unicode:
- value = value.encode("utf-8")
- lines.append('--' + BOUNDARY)
- lines.append('Content-Disposition: form-data; name="%s"; filename="%s"' %
- (key, filename))
- lines.append('Content-Type: %s' % GetContentType(filename))
- lines.append('')
- lines.append(value)
- lines.append('--' + BOUNDARY + '--')
- lines.append('')
- body = CRLF.join(lines)
- content_type = 'multipart/form-data; boundary=%s' % BOUNDARY
- return content_type, body
+ """Encode form fields for multipart/form-data.
+
+ Args:
+ fields: A sequence of (name, value) elements for regular form fields.
+ files: A sequence of (name, filename, value) elements for data to be
+ uploaded as files.
+ Returns:
+ (content_type, body) ready for httplib.HTTP instance.
+
+ Source:
+ http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/146306
+ """
+ BOUNDARY = '-M-A-G-I-C---B-O-U-N-D-A-R-Y-'
+ CRLF = '\r\n'
+ lines = []
+ for (key, value) in fields:
+ typecheck(key, str)
+ typecheck(value, str)
+ lines.append('--' + BOUNDARY)
+ lines.append('Content-Disposition: form-data; name="%s"' % key)
+ lines.append('')
+ lines.append(value)
+ for (key, filename, value) in files:
+ typecheck(key, str)
+ typecheck(filename, str)
+ typecheck(value, str)
+ lines.append('--' + BOUNDARY)
+ lines.append('Content-Disposition: form-data; name="%s"; filename="%s"' % (key, filename))
+ lines.append('Content-Type: %s' % GetContentType(filename))
+ lines.append('')
+ lines.append(value)
+ lines.append('--' + BOUNDARY + '--')
+ lines.append('')
+ body = CRLF.join(lines)
+ content_type = 'multipart/form-data; boundary=%s' % BOUNDARY
+ return content_type, body
def GetContentType(filename):
- """Helper to guess the content-type from the filename."""
- return mimetypes.guess_type(filename)[0] or 'application/octet-stream'
+ """Helper to guess the content-type from the filename."""
+ return mimetypes.guess_type(filename)[0] or 'application/octet-stream'
# Use a shell for subcommands on Windows to get a PATH search.
use_shell = sys.platform.startswith("win")
def RunShellWithReturnCode(command, print_output=False,
- universal_newlines=True,
- env=os.environ):
- """Executes a command and returns the output from stdout and the return code.
-
- Args:
- command: Command to execute.
- print_output: If True, the output is printed to stdout.
- If False, both stdout and stderr are ignored.
- universal_newlines: Use universal_newlines flag (default: True).
-
- Returns:
- Tuple (output, return code)
- """
- logging.info("Running %s", command)
- p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
- shell=use_shell, universal_newlines=universal_newlines,
- env=env)
- if print_output:
- output_array = []
- while True:
- line = p.stdout.readline()
- if not line:
- break
- print line.strip("\n")
- output_array.append(line)
- output = "".join(output_array)
- else:
- output = p.stdout.read()
- p.wait()
- errout = p.stderr.read()
- if print_output and errout:
- print >>sys.stderr, errout
- p.stdout.close()
- p.stderr.close()
- return output, p.returncode
+ universal_newlines=True, env=os.environ):
+ """Executes a command and returns the output from stdout and the return code.
+
+ Args:
+ command: Command to execute.
+ print_output: If True, the output is printed to stdout.
+ If False, both stdout and stderr are ignored.
+ universal_newlines: Use universal_newlines flag (default: True).
+
+ Returns:
+ Tuple (output, return code)
+ """
+ logging.info("Running %s", command)
+ p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
+ shell=use_shell, universal_newlines=universal_newlines, env=env)
+ if print_output:
+ output_array = []
+ while True:
+ line = p.stdout.readline()
+ if not line:
+ break
+ print line.strip("\n")
+ output_array.append(line)
+ output = "".join(output_array)
+ else:
+ output = p.stdout.read()
+ p.wait()
+ errout = p.stderr.read()
+ if print_output and errout:
+ print >>sys.stderr, errout
+ p.stdout.close()
+ p.stderr.close()
+ return output, p.returncode
def RunShell(command, silent_ok=False, universal_newlines=True,
- print_output=False, env=os.environ):
- data, retcode = RunShellWithReturnCode(command, print_output,
- universal_newlines, env)
- if retcode:
- ErrorExit("Got error status from %s:\n%s" % (command, data))
- if not silent_ok and not data:
- ErrorExit("No output from %s" % command)
- return data
+ print_output=False, env=os.environ):
+ data, retcode = RunShellWithReturnCode(command, print_output, universal_newlines, env)
+ if retcode:
+ ErrorExit("Got error status from %s:\n%s" % (command, data))
+ if not silent_ok and not data:
+ ErrorExit("No output from %s" % command)
+ return data
class VersionControlSystem(object):
- """Abstract base class providing an interface to the VCS."""
-
- def __init__(self, options):
- """Constructor.
-
- Args:
- options: Command line options.
- """
- self.options = options
-
- def GenerateDiff(self, args):
- """Return the current diff as a string.
-
- Args:
- args: Extra arguments to pass to the diff command.
- """
- raise NotImplementedError(
- "abstract method -- subclass %s must override" % self.__class__)
-
- def GetUnknownFiles(self):
- """Return a list of files unknown to the VCS."""
- raise NotImplementedError(
- "abstract method -- subclass %s must override" % self.__class__)
-
- def CheckForUnknownFiles(self):
- """Show an "are you sure?" prompt if there are unknown files."""
- unknown_files = self.GetUnknownFiles()
- if unknown_files:
- print "The following files are not added to version control:"
- for line in unknown_files:
- print line
- prompt = "Are you sure to continue?(y/N) "
- answer = raw_input(prompt).strip()
- if answer != "y":
- ErrorExit("User aborted")
-
- def GetBaseFile(self, filename):
- """Get the content of the upstream version of a file.
-
- Returns:
- A tuple (base_content, new_content, is_binary, status)
- base_content: The contents of the base file.
- new_content: For text files, this is empty. For binary files, this is
- the contents of the new file, since the diff output won't contain
- information to reconstruct the current file.
- is_binary: True iff the file is binary.
- status: The status of the file.
- """
-
- raise NotImplementedError(
- "abstract method -- subclass %s must override" % self.__class__)
-
-
- def GetBaseFiles(self, diff):
- """Helper that calls GetBase file for each file in the patch.
-
- Returns:
- A dictionary that maps from filename to GetBaseFile's tuple. Filenames
- are retrieved based on lines that start with "Index:" or
- "Property changes on:".
- """
- files = {}
- for line in diff.splitlines(True):
- if line.startswith('Index:') or line.startswith('Property changes on:'):
- unused, filename = line.split(':', 1)
- # On Windows if a file has property changes its filename uses '\'
- # instead of '/'.
- filename = filename.strip().replace('\\', '/')
- files[filename] = self.GetBaseFile(filename)
- return files
-
-
- def UploadBaseFiles(self, issue, rpc_server, patch_list, patchset, options,
- files):
- """Uploads the base files (and if necessary, the current ones as well)."""
-
- def UploadFile(filename, file_id, content, is_binary, status, is_base):
- """Uploads a file to the server."""
- file_too_large = False
- if is_base:
- type = "base"
- else:
- type = "current"
- if len(content) > MAX_UPLOAD_SIZE:
- print ("Not uploading the %s file for %s because it's too large." %
- (type, filename))
- file_too_large = True
- content = ""
- checksum = md5(content).hexdigest()
- if options.verbose > 0 and not file_too_large:
- print "Uploading %s file for %s" % (type, filename)
- url = "/%d/upload_content/%d/%d" % (int(issue), int(patchset), file_id)
- form_fields = [("filename", filename),
- ("status", status),
- ("checksum", checksum),
- ("is_binary", str(is_binary)),
- ("is_current", str(not is_base)),
- ]
- if file_too_large:
- form_fields.append(("file_too_large", "1"))
- if options.email:
- form_fields.append(("user", options.email))
- ctype, body = EncodeMultipartFormData(form_fields,
- [("data", filename, content)])
- response_body = rpc_server.Send(url, body,
- content_type=ctype)
- if not response_body.startswith("OK"):
- StatusUpdate(" --> %s" % response_body)
- sys.exit(1)
-
- patches = dict()
- [patches.setdefault(v, k) for k, v in patch_list]
- for filename in patches.keys():
- base_content, new_content, is_binary, status = files[filename]
- file_id_str = patches.get(filename)
- if file_id_str.find("nobase") != -1:
- base_content = None
- file_id_str = file_id_str[file_id_str.rfind("_") + 1:]
- file_id = int(file_id_str)
- if base_content != None:
- UploadFile(filename, file_id, base_content, is_binary, status, True)
- if new_content != None:
- UploadFile(filename, file_id, new_content, is_binary, status, False)
-
- def IsImage(self, filename):
- """Returns true if the filename has an image extension."""
- mimetype = mimetypes.guess_type(filename)[0]
- if not mimetype:
- return False
- return mimetype.startswith("image/")
-
- def IsBinary(self, filename):
- """Returns true if the guessed mimetyped isnt't in text group."""
- mimetype = mimetypes.guess_type(filename)[0]
- if not mimetype:
- return False # e.g. README, "real" binaries usually have an extension
- # special case for text files which don't start with text/
- if mimetype in TEXT_MIMETYPES:
- return False
- return not mimetype.startswith("text/")
-
-
-class SubversionVCS(VersionControlSystem):
- """Implementation of the VersionControlSystem interface for Subversion."""
-
- def __init__(self, options):
- super(SubversionVCS, self).__init__(options)
- if self.options.revision:
- match = re.match(r"(\d+)(:(\d+))?", self.options.revision)
- if not match:
- ErrorExit("Invalid Subversion revision %s." % self.options.revision)
- self.rev_start = match.group(1)
- self.rev_end = match.group(3)
- else:
- self.rev_start = self.rev_end = None
- # Cache output from "svn list -r REVNO dirname".
- # Keys: dirname, Values: 2-tuple (ouput for start rev and end rev).
- self.svnls_cache = {}
- # SVN base URL is required to fetch files deleted in an older revision.
- # Result is cached to not guess it over and over again in GetBaseFile().
- required = self.options.download_base or self.options.revision is not None
- self.svn_base = self._GuessBase(required)
-
- def GuessBase(self, required):
- """Wrapper for _GuessBase."""
- return self.svn_base
-
- def _GuessBase(self, required):
- """Returns the SVN base URL.
-
- Args:
- required: If true, exits if the url can't be guessed, otherwise None is
- returned.
- """
- info = RunShell(["svn", "info"])
- for line in info.splitlines():
- words = line.split()
- if len(words) == 2 and words[0] == "URL:":
- url = words[1]
- scheme, netloc, path, params, query, fragment = urlparse.urlparse(url)
- username, netloc = urllib.splituser(netloc)
- if username:
- logging.info("Removed username from base URL")
- if netloc.endswith("svn.python.org"):
- if netloc == "svn.python.org":
- if path.startswith("/projects/"):
- path = path[9:]
- elif netloc != "pythondev@svn.python.org":
- ErrorExit("Unrecognized Python URL: %s" % url)
- base = "http://svn.python.org/view/*checkout*%s/" % path
- logging.info("Guessed Python base = %s", base)
- elif netloc.endswith("svn.collab.net"):
- if path.startswith("/repos/"):
- path = path[6:]
- base = "http://svn.collab.net/viewvc/*checkout*%s/" % path
- logging.info("Guessed CollabNet base = %s", base)
- elif netloc.endswith(".googlecode.com"):
- path = path + "/"
- base = urlparse.urlunparse(("http", netloc, path, params,
- query, fragment))
- logging.info("Guessed Google Code base = %s", base)
- else:
- path = path + "/"
- base = urlparse.urlunparse((scheme, netloc, path, params,
- query, fragment))
- logging.info("Guessed base = %s", base)
- return base
- if required:
- ErrorExit("Can't find URL in output from svn info")
- return None
-
- def GenerateDiff(self, args):
- cmd = ["svn", "diff"]
- if self.options.revision:
- cmd += ["-r", self.options.revision]
- cmd.extend(args)
- data = RunShell(cmd)
- count = 0
- for line in data.splitlines():
- if line.startswith("Index:") or line.startswith("Property changes on:"):
- count += 1
- logging.info(line)
- if not count:
- ErrorExit("No valid patches found in output from svn diff")
- return data
-
- def _CollapseKeywords(self, content, keyword_str):
- """Collapses SVN keywords."""
- # svn cat translates keywords but svn diff doesn't. As a result of this
- # behavior patching.PatchChunks() fails with a chunk mismatch error.
- # This part was originally written by the Review Board development team
- # who had the same problem (http://reviews.review-board.org/r/276/).
- # Mapping of keywords to known aliases
- svn_keywords = {
- # Standard keywords
- 'Date': ['Date', 'LastChangedDate'],
- 'Revision': ['Revision', 'LastChangedRevision', 'Rev'],
- 'Author': ['Author', 'LastChangedBy'],
- 'HeadURL': ['HeadURL', 'URL'],
- 'Id': ['Id'],
-
- # Aliases
- 'LastChangedDate': ['LastChangedDate', 'Date'],
- 'LastChangedRevision': ['LastChangedRevision', 'Rev', 'Revision'],
- 'LastChangedBy': ['LastChangedBy', 'Author'],
- 'URL': ['URL', 'HeadURL'],
- }
-
- def repl(m):
- if m.group(2):
- return "$%s::%s$" % (m.group(1), " " * len(m.group(3)))
- return "$%s$" % m.group(1)
- keywords = [keyword
- for name in keyword_str.split(" ")
- for keyword in svn_keywords.get(name, [])]
- return re.sub(r"\$(%s):(:?)([^\$]+)\$" % '|'.join(keywords), repl, content)
-
- def GetUnknownFiles(self):
- status = RunShell(["svn", "status", "--ignore-externals"], silent_ok=True)
- unknown_files = []
- for line in status.split("\n"):
- if line and line[0] == "?":
- unknown_files.append(line)
- return unknown_files
-
- def ReadFile(self, filename):
- """Returns the contents of a file."""
- file = open(filename, 'rb')
- result = ""
- try:
- result = file.read()
- finally:
- file.close()
- return result
-
- def GetStatus(self, filename):
- """Returns the status of a file."""
- if not self.options.revision:
- status = RunShell(["svn", "status", "--ignore-externals", filename])
- if not status:
- ErrorExit("svn status returned no output for %s" % filename)
- status_lines = status.splitlines()
- # If file is in a cl, the output will begin with
- # "\n--- Changelist 'cl_name':\n". See
- # http://svn.collab.net/repos/svn/trunk/notes/changelist-design.txt
- if (len(status_lines) == 3 and
- not status_lines[0] and
- status_lines[1].startswith("--- Changelist")):
- status = status_lines[2]
- else:
- status = status_lines[0]
- # If we have a revision to diff against we need to run "svn list"
- # for the old and the new revision and compare the results to get
- # the correct status for a file.
- else:
- dirname, relfilename = os.path.split(filename)
- if dirname not in self.svnls_cache:
- cmd = ["svn", "list", "-r", self.rev_start, dirname or "."]
- out, returncode = RunShellWithReturnCode(cmd)
- if returncode:
- ErrorExit("Failed to get status for %s." % filename)
- old_files = out.splitlines()
- args = ["svn", "list"]
- if self.rev_end:
- args += ["-r", self.rev_end]
- cmd = args + [dirname or "."]
- out, returncode = RunShellWithReturnCode(cmd)
- if returncode:
- ErrorExit("Failed to run command %s" % cmd)
- self.svnls_cache[dirname] = (old_files, out.splitlines())
- old_files, new_files = self.svnls_cache[dirname]
- if relfilename in old_files and relfilename not in new_files:
- status = "D "
- elif relfilename in old_files and relfilename in new_files:
- status = "M "
- else:
- status = "A "
- return status
-
- def GetBaseFile(self, filename):
- status = self.GetStatus(filename)
- base_content = None
- new_content = None
-
- # If a file is copied its status will be "A +", which signifies
- # "addition-with-history". See "svn st" for more information. We need to
- # upload the original file or else diff parsing will fail if the file was
- # edited.
- if status[0] == "A" and status[3] != "+":
- # We'll need to upload the new content if we're adding a binary file
- # since diff's output won't contain it.
- mimetype = RunShell(["svn", "propget", "svn:mime-type", filename],
- silent_ok=True)
- base_content = ""
- is_binary = bool(mimetype) and not mimetype.startswith("text/")
- if is_binary and self.IsImage(filename):
- new_content = self.ReadFile(filename)
- elif (status[0] in ("M", "D", "R") or
- (status[0] == "A" and status[3] == "+") or # Copied file.
- (status[0] == " " and status[1] == "M")): # Property change.
- args = []
- if self.options.revision:
- url = "%s/%s@%s" % (self.svn_base, filename, self.rev_start)
- else:
- # Don't change filename, it's needed later.
- url = filename
- args += ["-r", "BASE"]
- cmd = ["svn"] + args + ["propget", "svn:mime-type", url]
- mimetype, returncode = RunShellWithReturnCode(cmd)
- if returncode:
- # File does not exist in the requested revision.
- # Reset mimetype, it contains an error message.
- mimetype = ""
- get_base = False
- is_binary = bool(mimetype) and not mimetype.startswith("text/")
- if status[0] == " ":
- # Empty base content just to force an upload.
- base_content = ""
- elif is_binary:
- if self.IsImage(filename):
- get_base = True
- if status[0] == "M":
- if not self.rev_end:
- new_content = self.ReadFile(filename)
- else:
- url = "%s/%s@%s" % (self.svn_base, filename, self.rev_end)
- new_content = RunShell(["svn", "cat", url],
- universal_newlines=True, silent_ok=True)
- else:
- base_content = ""
- else:
- get_base = True
-
- if get_base:
- if is_binary:
- universal_newlines = False
- else:
- universal_newlines = True
- if self.rev_start:
- # "svn cat -r REV delete_file.txt" doesn't work. cat requires
- # the full URL with "@REV" appended instead of using "-r" option.
- url = "%s/%s@%s" % (self.svn_base, filename, self.rev_start)
- base_content = RunShell(["svn", "cat", url],
- universal_newlines=universal_newlines,
- silent_ok=True)
- else:
- base_content = RunShell(["svn", "cat", filename],
- universal_newlines=universal_newlines,
- silent_ok=True)
- if not is_binary:
- args = []
- if self.rev_start:
- url = "%s/%s@%s" % (self.svn_base, filename, self.rev_start)
- else:
- url = filename
- args += ["-r", "BASE"]
- cmd = ["svn"] + args + ["propget", "svn:keywords", url]
- keywords, returncode = RunShellWithReturnCode(cmd)
- if keywords and not returncode:
- base_content = self._CollapseKeywords(base_content, keywords)
- else:
- StatusUpdate("svn status returned unexpected output: %s" % status)
- sys.exit(1)
- return base_content, new_content, is_binary, status[0:5]
-
-
-class GitVCS(VersionControlSystem):
- """Implementation of the VersionControlSystem interface for Git."""
-
- def __init__(self, options):
- super(GitVCS, self).__init__(options)
- # Map of filename -> (hash before, hash after) of base file.
- # Hashes for "no such file" are represented as None.
- self.hashes = {}
- # Map of new filename -> old filename for renames.
- self.renames = {}
-
- def GenerateDiff(self, extra_args):
- # This is more complicated than svn's GenerateDiff because we must convert
- # the diff output to include an svn-style "Index:" line as well as record
- # the hashes of the files, so we can upload them along with our diff.
-
- # Special used by git to indicate "no such content".
- NULL_HASH = "0"*40
-
- extra_args = extra_args[:]
- if self.options.revision:
- extra_args = [self.options.revision] + extra_args
- extra_args.append('-M')
-
- # --no-ext-diff is broken in some versions of Git, so try to work around
- # this by overriding the environment (but there is still a problem if the
- # git config key "diff.external" is used).
- env = os.environ.copy()
- if 'GIT_EXTERNAL_DIFF' in env: del env['GIT_EXTERNAL_DIFF']
- gitdiff = RunShell(["git", "diff", "--no-ext-diff", "--full-index"]
- + extra_args, env=env)
- svndiff = []
- filecount = 0
- filename = None
- for line in gitdiff.splitlines():
- match = re.match(r"diff --git a/(.*) b/(.*)$", line)
- if match:
- filecount += 1
- # Intentionally use the "after" filename so we can show renames.
- filename = match.group(2)
- svndiff.append("Index: %s\n" % filename)
- if match.group(1) != match.group(2):
- self.renames[match.group(2)] = match.group(1)
- else:
- # The "index" line in a git diff looks like this (long hashes elided):
- # index 82c0d44..b2cee3f 100755
- # We want to save the left hash, as that identifies the base file.
- match = re.match(r"index (\w+)\.\.(\w+)", line)
- if match:
- before, after = (match.group(1), match.group(2))
- if before == NULL_HASH:
- before = None
- if after == NULL_HASH:
- after = None
- self.hashes[filename] = (before, after)
- svndiff.append(line + "\n")
- if not filecount:
- ErrorExit("No valid patches found in output from git diff")
- return "".join(svndiff)
-
- def GetUnknownFiles(self):
- status = RunShell(["git", "ls-files", "--exclude-standard", "--others"],
- silent_ok=True)
- return status.splitlines()
-
- def GetFileContent(self, file_hash, is_binary):
- """Returns the content of a file identified by its git hash."""
- data, retcode = RunShellWithReturnCode(["git", "show", file_hash],
- universal_newlines=not is_binary)
- if retcode:
- ErrorExit("Got error status from 'git show %s'" % file_hash)
- return data
-
- def GetBaseFile(self, filename):
- hash_before, hash_after = self.hashes.get(filename, (None,None))
- base_content = None
- new_content = None
- is_binary = self.IsBinary(filename)
- status = None
-
- if filename in self.renames:
- status = "A +" # Match svn attribute name for renames.
- if filename not in self.hashes:
- # If a rename doesn't change the content, we never get a hash.
- base_content = RunShell(["git", "show", filename])
- elif not hash_before:
- status = "A"
- base_content = ""
- elif not hash_after:
- status = "D"
- else:
- status = "M"
-
- is_image = self.IsImage(filename)
-
- # Grab the before/after content if we need it.
- # We should include file contents if it's text or it's an image.
- if not is_binary or is_image:
- # Grab the base content if we don't have it already.
- if base_content is None and hash_before:
- base_content = self.GetFileContent(hash_before, is_binary)
- # Only include the "after" file if it's an image; otherwise it
- # it is reconstructed from the diff.
- if is_image and hash_after:
- new_content = self.GetFileContent(hash_after, is_binary)
-
- return (base_content, new_content, is_binary, status)
+ """Abstract base class providing an interface to the VCS."""
+
+ def __init__(self, options):
+ """Constructor.
+
+ Args:
+ options: Command line options.
+ """
+ self.options = options
+
+ def GenerateDiff(self, args):
+ """Return the current diff as a string.
+
+ Args:
+ args: Extra arguments to pass to the diff command.
+ """
+ raise NotImplementedError(
+ "abstract method -- subclass %s must override" % self.__class__)
+
+ def GetUnknownFiles(self):
+ """Return a list of files unknown to the VCS."""
+ raise NotImplementedError(
+ "abstract method -- subclass %s must override" % self.__class__)
+
+ def CheckForUnknownFiles(self):
+ """Show an "are you sure?" prompt if there are unknown files."""
+ unknown_files = self.GetUnknownFiles()
+ if unknown_files:
+ print "The following files are not added to version control:"
+ for line in unknown_files:
+ print line
+ prompt = "Are you sure to continue?(y/N) "
+ answer = raw_input(prompt).strip()
+ if answer != "y":
+ ErrorExit("User aborted")
+
+ def GetBaseFile(self, filename):
+ """Get the content of the upstream version of a file.
+
+ Returns:
+ A tuple (base_content, new_content, is_binary, status)
+ base_content: The contents of the base file.
+ new_content: For text files, this is empty. For binary files, this is
+ the contents of the new file, since the diff output won't contain
+ information to reconstruct the current file.
+ is_binary: True iff the file is binary.
+ status: The status of the file.
+ """
+
+ raise NotImplementedError(
+ "abstract method -- subclass %s must override" % self.__class__)
+
+
+ def GetBaseFiles(self, diff):
+ """Helper that calls GetBase file for each file in the patch.
+
+ Returns:
+ A dictionary that maps from filename to GetBaseFile's tuple. Filenames
+ are retrieved based on lines that start with "Index:" or
+ "Property changes on:".
+ """
+ files = {}
+ for line in diff.splitlines(True):
+ if line.startswith('Index:') or line.startswith('Property changes on:'):
+ unused, filename = line.split(':', 1)
+ # On Windows if a file has property changes its filename uses '\'
+ # instead of '/'.
+ filename = filename.strip().replace('\\', '/')
+ files[filename] = self.GetBaseFile(filename)
+ return files
+
+
+ def UploadBaseFiles(self, issue, rpc_server, patch_list, patchset, options,
+ files):
+ """Uploads the base files (and if necessary, the current ones as well)."""
+
+ def UploadFile(filename, file_id, content, is_binary, status, is_base):
+ """Uploads a file to the server."""
+ set_status("uploading " + filename)
+ file_too_large = False
+ if is_base:
+ type = "base"
+ else:
+ type = "current"
+ if len(content) > MAX_UPLOAD_SIZE:
+ print ("Not uploading the %s file for %s because it's too large." %
+ (type, filename))
+ file_too_large = True
+ content = ""
+ checksum = md5(content).hexdigest()
+ if options.verbose > 0 and not file_too_large:
+ print "Uploading %s file for %s" % (type, filename)
+ url = "/%d/upload_content/%d/%d" % (int(issue), int(patchset), file_id)
+ form_fields = [
+ ("filename", filename),
+ ("status", status),
+ ("checksum", checksum),
+ ("is_binary", str(is_binary)),
+ ("is_current", str(not is_base)),
+ ]
+ if file_too_large:
+ form_fields.append(("file_too_large", "1"))
+ if options.email:
+ form_fields.append(("user", options.email))
+ ctype, body = EncodeMultipartFormData(form_fields, [("data", filename, content)])
+ response_body = rpc_server.Send(url, body, content_type=ctype)
+ if not response_body.startswith("OK"):
+ StatusUpdate(" --> %s" % response_body)
+ sys.exit(1)
+
+ # Don't want to spawn too many threads, nor do we want to
+ # hit Rietveld too hard, or it will start serving 500 errors.
+ # When 8 works, it's no better than 4, and sometimes 8 is
+ # too many for Rietveld to handle.
+ MAX_PARALLEL_UPLOADS = 4
+
+ sema = threading.BoundedSemaphore(MAX_PARALLEL_UPLOADS)
+ upload_threads = []
+ finished_upload_threads = []
+
+ class UploadFileThread(threading.Thread):
+ def __init__(self, args):
+ threading.Thread.__init__(self)
+ self.args = args
+ def run(self):
+ UploadFile(*self.args)
+ finished_upload_threads.append(self)
+ sema.release()
+
+ def StartUploadFile(*args):
+ sema.acquire()
+ while len(finished_upload_threads) > 0:
+ t = finished_upload_threads.pop()
+ upload_threads.remove(t)
+ t.join()
+ t = UploadFileThread(args)
+ upload_threads.append(t)
+ t.start()
+
+ def WaitForUploads():
+ for t in upload_threads:
+ t.join()
+
+ patches = dict()
+ [patches.setdefault(v, k) for k, v in patch_list]
+ for filename in patches.keys():
+ base_content, new_content, is_binary, status = files[filename]
+ file_id_str = patches.get(filename)
+ if file_id_str.find("nobase") != -1:
+ base_content = None
+ file_id_str = file_id_str[file_id_str.rfind("_") + 1:]
+ file_id = int(file_id_str)
+ if base_content != None:
+ StartUploadFile(filename, file_id, base_content, is_binary, status, True)
+ if new_content != None:
+ StartUploadFile(filename, file_id, new_content, is_binary, status, False)
+ WaitForUploads()
+
+ def IsImage(self, filename):
+ """Returns true if the filename has an image extension."""
+ mimetype = mimetypes.guess_type(filename)[0]
+ if not mimetype:
+ return False
+ return mimetype.startswith("image/")
+
+ def IsBinary(self, filename):
+ """Returns true if the guessed mimetyped isnt't in text group."""
+ mimetype = mimetypes.guess_type(filename)[0]
+ if not mimetype:
+ return False # e.g. README, "real" binaries usually have an extension
+ # special case for text files which don't start with text/
+ if mimetype in TEXT_MIMETYPES:
+ return False
+ return not mimetype.startswith("text/")
+
+class FakeMercurialUI(object):
+ def __init__(self):
+ self.quiet = True
+ self.output = ''
+
+ def write(self, *args, **opts):
+ self.output += ' '.join(args)
+use_hg_shell = False # set to True to shell out to hg always; slower
class MercurialVCS(VersionControlSystem):
- """Implementation of the VersionControlSystem interface for Mercurial."""
-
- def __init__(self, options, repo_dir):
- super(MercurialVCS, self).__init__(options)
- # Absolute path to repository (we can be in a subdir)
- self.repo_dir = os.path.normpath(repo_dir)
- # Compute the subdir
- cwd = os.path.normpath(os.getcwd())
- assert cwd.startswith(self.repo_dir)
- self.subdir = cwd[len(self.repo_dir):].lstrip(r"\/")
- if self.options.revision:
- self.base_rev = self.options.revision
- else:
- mqparent, err = RunShellWithReturnCode(['hg', 'log', '--rev', 'qparent', '--template={node}'])
- if not err:
- self.base_rev = mqparent
- else:
- self.base_rev = RunShell(["hg", "parent", "-q"]).split(':')[1].strip()
- def _GetRelPath(self, filename):
- """Get relative path of a file according to the current directory,
- given its logical path in the repo."""
- assert filename.startswith(self.subdir), (filename, self.subdir)
- return filename[len(self.subdir):].lstrip(r"\/")
-
- def GenerateDiff(self, extra_args):
- # If no file specified, restrict to the current subdir
- extra_args = extra_args or ["."]
- cmd = ["hg", "diff", "--git", "-r", self.base_rev] + extra_args
- data = RunShell(cmd, silent_ok=True)
- svndiff = []
- filecount = 0
- for line in data.splitlines():
- m = re.match("diff --git a/(\S+) b/(\S+)", line)
- if m:
- # Modify line to make it look like as it comes from svn diff.
- # With this modification no changes on the server side are required
- # to make upload.py work with Mercurial repos.
- # NOTE: for proper handling of moved/copied files, we have to use
- # the second filename.
- filename = m.group(2)
- svndiff.append("Index: %s" % filename)
- svndiff.append("=" * 67)
- filecount += 1
- logging.info(line)
- else:
- svndiff.append(line)
- if not filecount:
- ErrorExit("No valid patches found in output from hg diff")
- return "\n".join(svndiff) + "\n"
-
- def GetUnknownFiles(self):
- """Return a list of files unknown to the VCS."""
- args = []
- status = RunShell(["hg", "status", "--rev", self.base_rev, "-u", "."],
- silent_ok=True)
- unknown_files = []
- for line in status.splitlines():
- st, fn = line.split(" ", 1)
- if st == "?":
- unknown_files.append(fn)
- return unknown_files
-
- def GetBaseFile(self, filename):
- # "hg status" and "hg cat" both take a path relative to the current subdir
- # rather than to the repo root, but "hg diff" has given us the full path
- # to the repo root.
- base_content = ""
- new_content = None
- is_binary = False
- oldrelpath = relpath = self._GetRelPath(filename)
- # "hg status -C" returns two lines for moved/copied files, one otherwise
- out = RunShell(["hg", "status", "-C", "--rev", self.base_rev, relpath])
- out = out.splitlines()
- # HACK: strip error message about missing file/directory if it isn't in
- # the working copy
- if out[0].startswith('%s: ' % relpath):
- out = out[1:]
- status, what = out[0].split(' ', 1)
- if len(out) > 1 and status == "A" and what == relpath:
- oldrelpath = out[1].strip()
- status = "M"
- if ":" in self.base_rev:
- base_rev = self.base_rev.split(":", 1)[0]
- else:
- base_rev = self.base_rev
- if status != "A":
- base_content = RunShell(["hg", "cat", "-r", base_rev, oldrelpath],
- silent_ok=True)
- is_binary = "\0" in base_content # Mercurial's heuristic
- if status != "R":
- new_content = open(relpath, "rb").read()
- is_binary = is_binary or "\0" in new_content
- if is_binary and base_content:
- # Fetch again without converting newlines
- base_content = RunShell(["hg", "cat", "-r", base_rev, oldrelpath],
- silent_ok=True, universal_newlines=False)
- if not is_binary or not self.IsImage(relpath):
- new_content = None
- return base_content, new_content, is_binary, status
+ """Implementation of the VersionControlSystem interface for Mercurial."""
+
+ def __init__(self, options, ui, repo):
+ super(MercurialVCS, self).__init__(options)
+ self.ui = ui
+ self.repo = repo
+ # Absolute path to repository (we can be in a subdir)
+ self.repo_dir = os.path.normpath(repo.root)
+ # Compute the subdir
+ cwd = os.path.normpath(os.getcwd())
+ assert cwd.startswith(self.repo_dir)
+ self.subdir = cwd[len(self.repo_dir):].lstrip(r"\/")
+ if self.options.revision:
+ self.base_rev = self.options.revision
+ else:
+ mqparent, err = RunShellWithReturnCode(['hg', 'log', '--rev', 'qparent', '--template={node}'])
+ if not err:
+ self.base_rev = mqparent
+ else:
+ self.base_rev = RunShell(["hg", "parents", "-q"]).split(':')[1].strip()
+ def _GetRelPath(self, filename):
+ """Get relative path of a file according to the current directory,
+ given its logical path in the repo."""
+ assert filename.startswith(self.subdir), (filename, self.subdir)
+ return filename[len(self.subdir):].lstrip(r"\/")
+
+ def GenerateDiff(self, extra_args):
+ # If no file specified, restrict to the current subdir
+ extra_args = extra_args or ["."]
+ cmd = ["hg", "diff", "--git", "-r", self.base_rev] + extra_args
+ data = RunShell(cmd, silent_ok=True)
+ svndiff = []
+ filecount = 0
+ for line in data.splitlines():
+ m = re.match("diff --git a/(\S+) b/(\S+)", line)
+ if m:
+ # Modify line to make it look like as it comes from svn diff.
+ # With this modification no changes on the server side are required
+ # to make upload.py work with Mercurial repos.
+ # NOTE: for proper handling of moved/copied files, we have to use
+ # the second filename.
+ filename = m.group(2)
+ svndiff.append("Index: %s" % filename)
+ svndiff.append("=" * 67)
+ filecount += 1
+ logging.info(line)
+ else:
+ svndiff.append(line)
+ if not filecount:
+ ErrorExit("No valid patches found in output from hg diff")
+ return "\n".join(svndiff) + "\n"
+
+ def GetUnknownFiles(self):
+ """Return a list of files unknown to the VCS."""
+ args = []
+ status = RunShell(["hg", "status", "--rev", self.base_rev, "-u", "."],
+ silent_ok=True)
+ unknown_files = []
+ for line in status.splitlines():
+ st, fn = line.split(" ", 1)
+ if st == "?":
+ unknown_files.append(fn)
+ return unknown_files
+
+ def GetBaseFile(self, filename):
+ set_status("inspecting " + filename)
+ # "hg status" and "hg cat" both take a path relative to the current subdir
+ # rather than to the repo root, but "hg diff" has given us the full path
+ # to the repo root.
+ base_content = ""
+ new_content = None
+ is_binary = False
+ oldrelpath = relpath = self._GetRelPath(filename)
+ # "hg status -C" returns two lines for moved/copied files, one otherwise
+ if use_hg_shell:
+ out = RunShell(["hg", "status", "-C", "--rev", self.base_rev, relpath])
+ else:
+ fui = FakeMercurialUI()
+ ret = commands.status(fui, self.repo, *[relpath], **{'rev': [self.base_rev], 'copies': True})
+ if ret:
+ raise util.Abort(ret)
+ out = fui.output
+ out = out.splitlines()
+ # HACK: strip error message about missing file/directory if it isn't in
+ # the working copy
+ if out[0].startswith('%s: ' % relpath):
+ out = out[1:]
+ status, what = out[0].split(' ', 1)
+ if len(out) > 1 and status == "A" and what == relpath:
+ oldrelpath = out[1].strip()
+ status = "M"
+ if ":" in self.base_rev:
+ base_rev = self.base_rev.split(":", 1)[0]
+ else:
+ base_rev = self.base_rev
+ if status != "A":
+ if use_hg_shell:
+ base_content = RunShell(["hg", "cat", "-r", base_rev, oldrelpath], silent_ok=True)
+ else:
+ base_content = str(self.repo[base_rev][oldrelpath].data())
+ is_binary = "\0" in base_content # Mercurial's heuristic
+ if status != "R":
+ new_content = open(relpath, "rb").read()
+ is_binary = is_binary or "\0" in new_content
+ if is_binary and base_content and use_hg_shell:
+ # Fetch again without converting newlines
+ base_content = RunShell(["hg", "cat", "-r", base_rev, oldrelpath],
+ silent_ok=True, universal_newlines=False)
+ if not is_binary or not self.IsImage(relpath):
+ new_content = None
+ return base_content, new_content, is_binary, status
# NOTE: The SplitPatch function is duplicated in engine.py, keep them in sync.
def SplitPatch(data):
- """Splits a patch into separate pieces for each file.
-
- Args:
- data: A string containing the output of svn diff.
-
- Returns:
- A list of 2-tuple (filename, text) where text is the svn diff output
- pertaining to filename.
- """
- patches = []
- filename = None
- diff = []
- for line in data.splitlines(True):
- new_filename = None
- if line.startswith('Index:'):
- unused, new_filename = line.split(':', 1)
- new_filename = new_filename.strip()
- elif line.startswith('Property changes on:'):
- unused, temp_filename = line.split(':', 1)
- # When a file is modified, paths use '/' between directories, however
- # when a property is modified '\' is used on Windows. Make them the same
- # otherwise the file shows up twice.
- temp_filename = temp_filename.strip().replace('\\', '/')
- if temp_filename != filename:
- # File has property changes but no modifications, create a new diff.
- new_filename = temp_filename
- if new_filename:
- if filename and diff:
- patches.append((filename, ''.join(diff)))
- filename = new_filename
- diff = [line]
- continue
- if diff is not None:
- diff.append(line)
- if filename and diff:
- patches.append((filename, ''.join(diff)))
- return patches
+ """Splits a patch into separate pieces for each file.
+
+ Args:
+ data: A string containing the output of svn diff.
+
+ Returns:
+ A list of 2-tuple (filename, text) where text is the svn diff output
+ pertaining to filename.
+ """
+ patches = []
+ filename = None
+ diff = []
+ for line in data.splitlines(True):
+ new_filename = None
+ if line.startswith('Index:'):
+ unused, new_filename = line.split(':', 1)
+ new_filename = new_filename.strip()
+ elif line.startswith('Property changes on:'):
+ unused, temp_filename = line.split(':', 1)
+ # When a file is modified, paths use '/' between directories, however
+ # when a property is modified '\' is used on Windows. Make them the same
+ # otherwise the file shows up twice.
+ temp_filename = temp_filename.strip().replace('\\', '/')
+ if temp_filename != filename:
+ # File has property changes but no modifications, create a new diff.
+ new_filename = temp_filename
+ if new_filename:
+ if filename and diff:
+ patches.append((filename, ''.join(diff)))
+ filename = new_filename
+ diff = [line]
+ continue
+ if diff is not None:
+ diff.append(line)
+ if filename and diff:
+ patches.append((filename, ''.join(diff)))
+ return patches
def UploadSeparatePatches(issue, rpc_server, patchset, data, options):
- """Uploads a separate patch for each file in the diff output.
-
- Returns a list of [patch_key, filename] for each file.
- """
- patches = SplitPatch(data)
- rv = []
- for patch in patches:
- if len(patch[1]) > MAX_UPLOAD_SIZE:
- print ("Not uploading the patch for " + patch[0] +
- " because the file is too large.")
- continue
- form_fields = [("filename", patch[0])]
- if not options.download_base:
- form_fields.append(("content_upload", "1"))
- files = [("data", "data.diff", patch[1])]
- ctype, body = EncodeMultipartFormData(form_fields, files)
- url = "/%d/upload_patch/%d" % (int(issue), int(patchset))
- print "Uploading patch for " + patch[0]
- response_body = rpc_server.Send(url, body, content_type=ctype)
- lines = response_body.splitlines()
- if not lines or lines[0] != "OK":
- StatusUpdate(" --> %s" % response_body)
- sys.exit(1)
- rv.append([lines[1], patch[0]])
- return rv
-
-
-def GuessVCSName():
- """Helper to guess the version control system.
-
- This examines the current directory, guesses which VersionControlSystem
- we're using, and returns an string indicating which VCS is detected.
-
- Returns:
- A pair (vcs, output). vcs is a string indicating which VCS was detected
- and is one of VCS_GIT, VCS_MERCURIAL, VCS_SUBVERSION, or VCS_UNKNOWN.
- output is a string containing any interesting output from the vcs
- detection routine, or None if there is nothing interesting.
- """
- # Mercurial has a command to get the base directory of a repository
- # Try running it, but don't die if we don't have hg installed.
- # NOTE: we try Mercurial first as it can sit on top of an SVN working copy.
- try:
- out, returncode = RunShellWithReturnCode(["hg", "root"])
- if returncode == 0:
- return (VCS_MERCURIAL, out.strip())
- except OSError, (errno, message):
- if errno != 2: # ENOENT -- they don't have hg installed.
- raise
-
- # Subversion has a .svn in all working directories.
- if os.path.isdir('.svn'):
- logging.info("Guessed VCS = Subversion")
- return (VCS_SUBVERSION, None)
-
- # Git has a command to test if you're in a git tree.
- # Try running it, but don't die if we don't have git installed.
- try:
- out, returncode = RunShellWithReturnCode(["git", "rev-parse",
- "--is-inside-work-tree"])
- if returncode == 0:
- return (VCS_GIT, None)
- except OSError, (errno, message):
- if errno != 2: # ENOENT -- they don't have git installed.
- raise
-
- return (VCS_UNKNOWN, None)
-
-
-def GuessVCS(options):
- """Helper to guess the version control system.
-
- This verifies any user-specified VersionControlSystem (by command line
- or environment variable). If the user didn't specify one, this examines
- the current directory, guesses which VersionControlSystem we're using,
- and returns an instance of the appropriate class. Exit with an error
- if we can't figure it out.
-
- Returns:
- A VersionControlSystem instance. Exits if the VCS can't be guessed.
- """
- vcs = options.vcs
- if not vcs:
- vcs = os.environ.get("CODEREVIEW_VCS")
- if vcs:
- v = VCS_ABBREVIATIONS.get(vcs.lower())
- if v is None:
- ErrorExit("Unknown version control system %r specified." % vcs)
- (vcs, extra_output) = (v, None)
- else:
- (vcs, extra_output) = GuessVCSName()
-
- if vcs == VCS_MERCURIAL:
- if extra_output is None:
- extra_output = RunShell(["hg", "root"]).strip()
- return MercurialVCS(options, extra_output)
- elif vcs == VCS_SUBVERSION:
- return SubversionVCS(options)
- elif vcs == VCS_GIT:
- return GitVCS(options)
-
- ErrorExit(("Could not guess version control system. "
- "Are you in a working copy directory?"))
-
-
-def RealMain(argv, data=None):
- """The real main function.
-
- Args:
- argv: Command line arguments.
- data: Diff contents. If None (default) the diff is generated by
- the VersionControlSystem implementation returned by GuessVCS().
-
- Returns:
- A 2-tuple (issue id, patchset id).
- The patchset id is None if the base files are not uploaded by this
- script (applies only to SVN checkouts).
- """
- logging.basicConfig(format=("%(asctime).19s %(levelname)s %(filename)s:"
- "%(lineno)s %(message)s "))
- os.environ['LC_ALL'] = 'C'
- options, args = parser.parse_args(argv[1:])
- global verbosity
- verbosity = options.verbose
- if verbosity >= 3:
- logging.getLogger().setLevel(logging.DEBUG)
- elif verbosity >= 2:
- logging.getLogger().setLevel(logging.INFO)
- vcs = GuessVCS(options)
- if isinstance(vcs, SubversionVCS):
- # base field is only allowed for Subversion.
- # Note: Fetching base files may become deprecated in future releases.
- base = vcs.GuessBase(options.download_base)
- else:
- base = None
- if not base and options.download_base:
- options.download_base = True
- logging.info("Enabled upload of base file")
- if not options.assume_yes:
- vcs.CheckForUnknownFiles()
- if data is None:
- data = vcs.GenerateDiff(args)
- files = vcs.GetBaseFiles(data)
- if verbosity >= 1:
- print "Upload server:", options.server, "(change with -s/--server)"
- if options.issue:
- prompt = "Message describing this patch set: "
- else:
- prompt = "New issue subject: "
- message = options.message or raw_input(prompt).strip()
- if not message:
- ErrorExit("A non-empty message is required")
- rpc_server = GetRpcServer(options)
- form_fields = [("subject", message)]
- if base:
- form_fields.append(("base", base))
- if options.issue:
- form_fields.append(("issue", str(options.issue)))
- if options.email:
- form_fields.append(("user", options.email))
- if options.reviewers:
- for reviewer in options.reviewers.split(','):
- if "@" in reviewer and not reviewer.split("@")[1].count(".") == 1:
- ErrorExit("Invalid email address: %s" % reviewer)
- form_fields.append(("reviewers", options.reviewers))
- if options.cc:
- for cc in options.cc.split(','):
- if "@" in cc and not cc.split("@")[1].count(".") == 1:
- ErrorExit("Invalid email address: %s" % cc)
- form_fields.append(("cc", options.cc))
- description = options.description
- if options.description_file:
- if options.description:
- ErrorExit("Can't specify description and description_file")
- file = open(options.description_file, 'r')
- description = file.read()
- file.close()
- if description:
- form_fields.append(("description", description))
- # Send a hash of all the base file so the server can determine if a copy
- # already exists in an earlier patchset.
- base_hashes = ""
- for file, info in files.iteritems():
- if not info[0] is None:
- checksum = md5(info[0]).hexdigest()
- if base_hashes:
- base_hashes += "|"
- base_hashes += checksum + ":" + file
- form_fields.append(("base_hashes", base_hashes))
- if options.private:
- if options.issue:
- print "Warning: Private flag ignored when updating an existing issue."
- else:
- form_fields.append(("private", "1"))
- # If we're uploading base files, don't send the email before the uploads, so
- # that it contains the file status.
- if options.send_mail and options.download_base:
- form_fields.append(("send_mail", "1"))
- if not options.download_base:
- form_fields.append(("content_upload", "1"))
- if len(data) > MAX_UPLOAD_SIZE:
- print "Patch is large, so uploading file patches separately."
- uploaded_diff_file = []
- form_fields.append(("separate_patches", "1"))
- else:
- uploaded_diff_file = [("data", "data.diff", data)]
- ctype, body = EncodeMultipartFormData(form_fields, uploaded_diff_file)
- response_body = rpc_server.Send("/upload", body, content_type=ctype)
- patchset = None
- if not options.download_base or not uploaded_diff_file:
- lines = response_body.splitlines()
- if len(lines) >= 2:
- msg = lines[0]
- patchset = lines[1].strip()
- patches = [x.split(" ", 1) for x in lines[2:]]
- else:
- msg = response_body
- else:
- msg = response_body
- if not response_body.startswith("Issue created.") and \
- not response_body.startswith("Issue updated."):
- print >>sys.stderr, msg
- sys.exit(0)
- issue = msg[msg.rfind("/")+1:]
-
- if not uploaded_diff_file:
- result = UploadSeparatePatches(issue, rpc_server, patchset, data, options)
- if not options.download_base:
- patches = result
-
- if not options.download_base:
- vcs.UploadBaseFiles(issue, rpc_server, patches, patchset, options, files)
- if options.send_mail:
- rpc_server.Send("/" + issue + "/mail", payload="")
- return issue, patchset
-
-
-def main():
- try:
- RealMain(sys.argv)
- except KeyboardInterrupt:
- print
- StatusUpdate("Interrupted.")
- sys.exit(1)
+ """Uploads a separate patch for each file in the diff output.
+ Returns a list of [patch_key, filename] for each file.
+ """
+ patches = SplitPatch(data)
+ rv = []
+ for patch in patches:
+ set_status("uploading patch for " + patch[0])
+ if len(patch[1]) > MAX_UPLOAD_SIZE:
+ print ("Not uploading the patch for " + patch[0] +
+ " because the file is too large.")
+ continue
+ form_fields = [("filename", patch[0])]
+ if not options.download_base:
+ form_fields.append(("content_upload", "1"))
+ files = [("data", "data.diff", patch[1])]
+ ctype, body = EncodeMultipartFormData(form_fields, files)
+ url = "/%d/upload_patch/%d" % (int(issue), int(patchset))
+ print "Uploading patch for " + patch[0]
+ response_body = rpc_server.Send(url, body, content_type=ctype)
+ lines = response_body.splitlines()
+ if not lines or lines[0] != "OK":
+ StatusUpdate(" --> %s" % response_body)
+ sys.exit(1)
+ rv.append([lines[1], patch[0]])
+ return rv
diff --git a/lib/godoc/godoc.html b/lib/godoc/godoc.html
index aef7f4dc4..f1d9c2ad9 100644
--- a/lib/godoc/godoc.html
+++ b/lib/godoc/godoc.html
@@ -1,136 +1,45 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
- "http://www.w3.org/TR/html4/transitional.dtd">
+<!DOCTYPE html>
<html>
<head>
-
- <meta http-equiv="content-type" content="text/html; charset=utf-8">
- <title>{Title|html-esc}</title>
-
- <link rel="stylesheet" type="text/css" href="/doc/style.css">
- <script type="text/javascript" src="/doc/godocs.js"></script>
-
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+{.section Title}
+ <title>{@|html-esc} - The Go Programming Language</title>
+{.or}
+ <title>The Go Programming Language</title>
+{.end}
+<link rel="stylesheet" href="/doc/all.css" type="text/css" media="all" charset="utf-8">
+<!--[if lt IE 8]>
+<link rel="stylesheet" href="/doc/ie.css" type="text/css">
+<![endif]-->
+<script type="text/javascript" src="/doc/godocs.js"></script>
</head>
-
<body>
-
- <script>
- // Catch 'enter' key down events and trigger the search form submission.
- function codesearchKeyDown(event) {.meta-left}
- if (event.which == 13) {.meta-left}
- var form = document.getElementById('codesearch');
- var query = document.getElementById('codesearchQuery');
- form.q.value = "lang:go package:go.googlecode.com " + query.value;
- document.getElementById('codesearch').submit();
- {.meta-right}
- return true;
- {.meta-right}
-
- // Capture the submission event and construct the query parameter.
- function codeSearchSubmit() {.meta-left}
- var query = document.getElementById('codesearchQuery');
- var form = document.getElementById('codesearch');
- form.q.value = "lang:go package:go.googlecode.com " + query.value;
- return true;
- {.meta-right}
- </script>
-
-<div id="topnav">
- <table summary="">
- <tr>
- <td id="headerImage">
- <a href="/"><img src="/doc/logo-153x55.png" height="55" width="153" alt="Go Home Page" style="border:0" /></a>
- </td>
- <td>
- <div id="headerDocSetTitle">The Go Programming Language</div>
- </td>
- <td>
- <!-- <table>
- <tr>
- <td>
- <! The input box is outside of the form because we want to add
- a couple of restricts to the query before submitting. If we just
- add the restricts to the text box before submitting, then they
- appear in the box when the user presses 'back'. Thus we use a
- hidden field in the form. However, there's no way to stop the
- non-hidden text box from also submitting a value unless we move
- it outside of the form
- <input type="search" id="codesearchQuery" value="" size="30" onkeydown="return codesearchKeyDown(event);"/>
- <form method="GET" action="http://www.google.com/codesearch" id="codesearch" class="search" onsubmit="return codeSearchSubmit();" style="display:inline;">
- <input type="hidden" name="q" value=""/>
- <input type="submit" value="Code search" />
- <span style="color: red">(TODO: remove for now?)</span>
- </form>
- </td>
- </tr>
- <tr>
- <td>
- <span style="color: gray;">(e.g. &ldquo;pem&rdquo; or &ldquo;xml&rdquo;)</span>
- </td>
- </tr>
- </table> -->
- </td>
- </tr>
- </table>
-</div>
-
-<div id="linkList">
- <ul>
- <li class="navhead"><a href="/">Home</a></li>
- <li class="blank">&nbsp;</li>
-
- <li class="navhead"><a href="/doc/go_learning.html">Go Resources</a></li>
- <li class="navhead"><a href="/doc/install.html">Installing Go</a></li>
- <li class="blank">&nbsp;</li>
-
- <li class="navhead">Selected Documents</li>
- <li><a href="/doc/go_tutorial.html">Tutorial</a></li>
- <li><a href="/doc/effective_go.html">Effective Go</a></li>
- <li><a href="/doc/go_faq.html">FAQ</a></li>
- <li><a href="/doc/go_lang_faq.html">Language Design FAQ</a></li>
- <li><a href="/doc/go_programming_faq.html">Programming FAQ</a></li>
-
- <li class="blank">&nbsp;</li>
- <li class="navhead">References</li>
- <li><a href="/doc/go_spec.html">Language Specification</a></li>
- <li><a href="/pkg">Package documentation</a></li>
- {.repeated section PkgRoots}
- <li><a href="/pkg/{@|html-esc}">Package documentation for {@|html-esc}</a></li>
- {.end}
- <li><a href="/cmd">Command documentation</a></li>
- <li><a href="/src">Source files</a></li>
-
- <li class="blank">&nbsp;</li>
- <li class="navhead">Help &amp; Community</li>
- <li><a href="http://blog.golang.org/">Go Blog</a></li>
- <li><a href="http://groups.google.com/group/golang-nuts">Go Nuts mailing list</a></li>
- <li>#go-nuts on irc.freenode.net</li>
- <li><a href="http://twitter.com/go_nuts">@go_nuts on Twitter</a></li>
- <li><a href="http://youtube.com/user/gocoding">gocoding YouTube Channel</a></li>
- <li><a href="http://code.google.com/p/go/issues/list">Issue tracker</a></li>
- <li><a href="http://code.google.com/p/go/wiki/WikiIndex">Go Wiki</a></li>
-
- <li class="blank">&nbsp;</li>
- <li class="navhead">Go Dashboard</li>
- <li><a href="http://godashboard.appspot.com/">Build Status</a></li>
- <li><a href="http://godashboard.appspot.com/package">External Packages</a></li>
- <li><a href="http://godashboard.appspot.com/benchmarks">Benchmarks</a></li>
-
- <li class="blank">&nbsp;</li>
- <li class="blank">&nbsp;</li>
- <li class="navhead">Go code search</li>
- <form method="GET" action="/search" class="search">
- <input type="search" name="q" value="{Query|html-esc}" size="25" style="width:80%; max-width:200px" />
- <input type="submit" value="Go" />
- </form>
-
- <li class="blank">&nbsp;</li>
- <li class="navhead">Last update</li>
- <li>{Timestamp|time}</li>
- <li>Build version {Version|html-esc}</li>
- </ul>
-</div>
-
-<div id="content">
+<div id="container">
+ <div id="topnav">
+ <h1 id="title">The Go Programming Language</h1>
+ <div id="nav-main">
+ <ul>
+ <li><a href="/">Home</a></li><li><a href="/doc/install.html">Getting Started</a></li><li><a href="/doc/docs.html">Documentation</a></li><li><a href="/doc/contrib.html">Contributing</a></li><li><a href="/doc/community.html">Community</a></li>
+ </ul>
+ <div class="quickref">
+ <form method="GET" action="/search">
+ {.section PkgRoots}
+ {.repeated section PkgRoots}
+ <a href="/pkg/{@|html-esc}">{@|html-esc}</a> <span class="sep">|</span>
+ {.end}
+ {.or}
+ References:
+ {.end}
+ <a href="/pkg/">Packages</a> <span class="sep">|</span>
+ <a href="/cmd/">Commands</a> <span class="sep">|</span>
+ <a href="/doc/go_spec.html">Specification</a>
+ <input id="search" type="text" name="q" value="{.section Query}{Query|html-esc}{.or}code search{.end}" class="{.section Query}{.or}inactive{.end}" />
+ </form>
+ </div>
+ </div>
+ <a id="logo-box" href="/"></a>
+ </div>
+ <div id="content">
<!-- Menu is HTML-escaped elsewhere -->
{.section Menu}
<div id="menu">
@@ -153,13 +62,10 @@
<!-- Content is HTML-escaped elsewhere -->
{Content}
+ </div>
+ <div id="site-info">
+ <p>Build version {Version|html-esc}. Except as noted, this content is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/3.0/">Creative Commons Attribution 3.0 License</a>.</p>
+ </div>
</div>
-
-<div id="footer">
-<p>Except as noted, this content is
- licensed under <a href="http://creativecommons.org/licenses/by/3.0/">
- Creative Commons Attribution 3.0</a>.
-</div>
-
</body>
</html>
diff --git a/lib/godoc/package.html b/lib/godoc/package.html
index 0eff78e45..5dc61b7cd 100644
--- a/lib/godoc/package.html
+++ b/lib/godoc/package.html
@@ -6,17 +6,19 @@
{.section PAst}
<pre>
- {@|html}
+ {@ FSet|html}
</pre>
{.end}
{.section PDoc}
<!-- PackageName is printed as title by the top-level template -->
{.section IsPkg}
+ {# ImportPath is a string - no need for FSet}
<p><code>import "{ImportPath|html-esc}"</code></p>
{.end}
{Doc|html-comment}
{.section IsPkg}
{.section Filenames}
+ {# Filenames are strings - no need for FSet}
<p>
<h4>Package files</h4>
<span style="font-size:90%">
@@ -31,44 +33,46 @@
<h2 id="Constants">Constants</h2>
{.repeated section @}
{Doc|html-comment}
- <pre>{Decl|html}</pre>
+ <pre>{Decl FSet|html}</pre>
{.end}
{.end}
{.section Vars}
<h2 id="Variables">Variables</h2>
{.repeated section @}
{Doc|html-comment}
- <pre>{Decl|html}</pre>
+ <pre>{Decl FSet|html}</pre>
{.end}
{.end}
{.section Funcs}
{.repeated section @}
- <h2 id="{Name|html-esc}">func <a href="/{Decl|url-pos}">{Name|html-esc}</a></h2>
- <p><code>{Decl|html}</code></p>
+ {# Name is a string - no need for FSet}
+ <h2 id="{Name|html-esc}">func <a href="/{Decl FSet|url-pos}">{Name|html-esc}</a></h2>
+ <p><code>{Decl FSet|html}</code></p>
{Doc|html-comment}
{.end}
{.end}
{.section Types}
{.repeated section @}
- <h2 id="{Type.Name|html-esc}">type <a href="/{Decl|url-pos}">{Type.Name|html-esc}</a></h2>
+ {# Type.Name is a string - no need for FSet}
+ <h2 id="{Type.Name FSet|html-esc}">type <a href="/{Decl FSet|url-pos}">{Type.Name FSet|html-esc}</a></h2>
{Doc|html-comment}
- <p><pre>{Decl|html}</pre></p>
+ <p><pre>{Decl FSet|html}</pre></p>
{.repeated section Consts}
{Doc|html-comment}
- <pre>{Decl|html}</pre>
+ <pre>{Decl FSet|html}</pre>
{.end}
{.repeated section Vars}
{Doc|html-comment}
- <pre>{Decl|html}</pre>
+ <pre>{Decl FSet|html}</pre>
{.end}
{.repeated section Factories}
- <h3 id="{Type.Name|html-esc}.{Name|html-esc}">func <a href="/{Decl|url-pos}">{Name|html-esc}</a></h3>
- <p><code>{Decl|html}</code></p>
+ <h3 id="{Type.Name FSet|html-esc}.{Name|html-esc}">func <a href="/{Decl FSet|url-pos}">{Name|html-esc}</a></h3>
+ <p><code>{Decl FSet|html}</code></p>
{Doc|html-comment}
{.end}
{.repeated section Methods}
- <h3 id="{Type.Name|html-esc}.{Name|html-esc}">func ({Recv|html}) <a href="/{Decl|url-pos}">{Name|html-esc}</a></h3>
- <p><code>{Decl|html}</code></p>
+ <h3 id="{Type.Name FSet|html-esc}.{Name|html-esc}">func ({Recv FSet|html}) <a href="/{Decl FSet|url-pos}">{Name|html-esc}</a></h3>
+ <p><code>{Decl FSet|html}</code></p>
{Doc|html-comment}
{.end}
{.end}
@@ -83,12 +87,14 @@
{.section PList}
<h2>Other packages</h2>
<p>
+ {# PLIst entries are strings - no need for FSet}
{.repeated section @}
- <a href="?p={@|html}">{@|html}</a><br />
+ <a href="?p={@|html-esc}">{@|html-esc}</a><br />
{.end}
</p>
{.end}
{.section Dirs}
+ {# DirList entries are numbers and strings - no need for FSet}
<h2 id="Subdirectories">Subdirectories</h2>
<p>
<table class="layout">
@@ -98,12 +104,12 @@
<th align="left">Synopsis</th>
</tr>
<tr>
- <th align="left"><a href="..">..<a></th>
+ <th align="left"><a href="..">..</a></th>
</tr>
{.repeated section List}
<tr>
{Depth|padding}
- <td align="left" colspan="{Height|html-esc}"><a href="{Path|html-esc}">{Name|html-esc}<a></td>
+ <td align="left" colspan="{Height|html-esc}"><a href="{Path|html-esc}">{Name|html-esc}</a></td>
<td></td>
<td align="left">{Synopsis|html-esc}</td>
</tr>
diff --git a/lib/godoc/package.txt b/lib/godoc/package.txt
index 124771edd..6fe992dbe 100644
--- a/lib/godoc/package.txt
+++ b/lib/godoc/package.txt
@@ -1,5 +1,5 @@
{.section PAst}
-{@}
+{@ FSet}
{.end}
{.section PDoc}
{.section IsPkg}
@@ -12,14 +12,14 @@ COMMAND DOCUMENTATION
{.end}
{.section Doc}
-{@}
+{@ FSet}
{.end}
{.section Consts}
CONSTANTS
{.repeated section @}
-{Decl}
+{Decl FSet}
{Doc}
{.end}
{.end}
@@ -28,7 +28,7 @@ CONSTANTS
VARIABLES
{.repeated section @}
-{Decl}
+{Decl FSet}
{Doc}
{.end}
{.end}
@@ -37,7 +37,7 @@ VARIABLES
FUNCTIONS
{.repeated section @}
-{Decl}
+{Decl FSet}
{Doc}
{.end}
{.end}
@@ -46,22 +46,22 @@ FUNCTIONS
TYPES
{.repeated section @}
-{Decl}
+{Decl FSet}
{Doc}
{.repeated section Consts}
-{Decl}
+{Decl FSet}
{Doc}
{.end}
{.repeated section Vars}
-{Decl}
+{Decl FSet}
{Doc}
{.end}
{.repeated section Factories}
-{Decl}
+{Decl FSet}
{Doc}
{.end}
{.repeated section Methods}
-{Decl}
+{Decl FSet}
{Doc}
{.end}
{.end}
diff --git a/lib/godoc/search.html b/lib/godoc/search.html
index febd7e569..3d3dd1958 100644
--- a/lib/godoc/search.html
+++ b/lib/godoc/search.html
@@ -4,10 +4,9 @@
license that can be found in the LICENSE file.
-->
-{.section Accurate}
-{.or}
+{.section Alert}
<p>
- <span class="alert" style="font-size:120%">Indexing in progress - result may be inaccurate</span>
+ <span class="alert" style="font-size:120%">{@}</span>
</p>
{.end}
{.section Alt}
@@ -26,8 +25,8 @@
{.repeated section Files}
{.repeated section Groups}
{.repeated section Infos}
- <a href="/{File.Path|url-src}?h={Query|html-esc}#L{@|infoLine}">{File.Path|url-src}:{@|infoLine}</a>
- <pre>{@|infoSnippet}</pre>
+ <a href="/{File.Path|url-src}?h={Query|urlquery-esc}#L{@|infoLine}">{File.Path|url-src}:{@|infoLine}</a>
+ {@|infoSnippet}
{.end}
{.end}
{.end}
@@ -38,7 +37,7 @@
{.repeated section @}
<h3 id="Local_{Pak.Path|url-pkg}">package <a href="/{Pak.Path|url-pkg}">{Pak.Name|html-esc}</a></h3>
{.repeated section Files}
- <a href="/{File.Path|url-src}?h={Query|html-esc}">{File.Path|url-src}</a>
+ <a href="/{File.Path|url-src}?h={Query|urlquery-esc}">{File.Path|url-src}</a>
<table class="layout">
{.repeated section Groups}
<tr>
@@ -47,7 +46,7 @@
<td align="left" width="4"></td>
<td>
{.repeated section Infos}
- <a href="/{File.Path|url-src}?h={Query|html-esc}#L{@|infoLine}">{@|infoLine}</a>
+ <a href="/{File.Path|url-src}?h={Query|urlquery-esc}#L{@|infoLine}">{@|infoLine}</a>
{.end}
</td>
</tr>
@@ -57,12 +56,36 @@
{.end}
{.end}
{.end}
-{.section Illegal}
- <p>
- <span class="alert" style="font-size:120%">Illegal query syntax</span>
- </p>
+{.section Textual}
+ {.section Complete}
+ <h2 id="Textual">{Found|html-esc} textual occurrences</h2>
+ {.or}
+ <h2 id="Textual">More than {Found|html-esc} textual occurrences</h2>
+ <p>
+ <span class="alert" style="font-size:120%">Not all files or lines containing "{Query|html-esc}" are shown.</span>
+ </p>
+ {.end}
<p>
- A legal query is a single identifier (such as <a href="search?q=ToLower">ToLower</a>)
- or a qualified identifier (such as <a href="search?q=math.Sin">math.Sin</a>).
+ <table class="layout">
+ {.repeated section @}
+ <tr>
+ <td align="left" valign="top">
+ <a href="/{Filename|url-src}?h={Query|urlquery-esc}">{Filename|url-src}</a>:
+ </td>
+ <td align="left" width="4"></td>
+ <th align="left" valign="top">{Lines|numlines}</th>
+ <td align="left" width="4"></td>
+ <td align="left">
+ {.repeated section Lines}
+ <a href="/{Filename|url-src}?h={Query|urlquery-esc}#L{@|html-esc}">{@|html-esc}</a>
+ {.end}
+ </td>
+ </tr>
+ {.end}
+ {.section Complete}
+ {.or}
+ <tr><td align="left">...</td></tr>
+ {.end}
+ </table>
</p>
{.end}
diff --git a/lib/godoc/search.txt b/lib/godoc/search.txt
index 90266292c..eff4d36fc 100644
--- a/lib/godoc/search.txt
+++ b/lib/godoc/search.txt
@@ -1,9 +1,8 @@
QUERY
-{Query}
+ {Query}
-{.section Accurate}
-{.or}
-INDEXING IN PROGRESS - RESULT MAY BE INACCURATE
+{.section Alert}
+{@}
{.end}
{.section Alt}
@@ -45,9 +44,18 @@ package {Pak.Name}
{.end}
{.end}
{.end}
-{.section Illegal}
-ILLEGAL QUERY SYNTAX
+{.section Textual}
+{.section Complete}
+{Found} TEXTUAL OCCURENCES
+{.or}
+MORE THAN {Found} TEXTUAL OCCURENCES
+{.end}
-A legal query is a single identifier (such as ToLower)
-or a qualified identifier (such as math.Sin).
+{.repeated section @}
+{Lines|numlines} {Filename|url-src}
+{.end}
+{.section Complete}
+{.or}
+... ...
+{.end}
{.end}
diff --git a/lib/godoc/source.html b/lib/godoc/source.html
deleted file mode 100644
index 645517012..000000000
--- a/lib/godoc/source.html
+++ /dev/null
@@ -1,23 +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.
--->
-
-<script src="http://www.google.com/jsapi"></script>
-<script src="/doc/popups.js"></script>
-<script>
-var popup_data = [
-{.repeated section Data}
- '{@|popupInfo}',
-{.end}
-]
-
-google.load("jquery", "1");
-google.setOnLoadCallback(function() {.meta-left}
- godocs_bindPopups(popup_data);
-{.meta-right});
-</script>
-
-{# Source is HTML-escaped elsewhere}
-<pre>{Source}</pre>
diff --git a/misc/arm/a b/misc/arm/a
index 140b47e29..701f4941f 100755
--- a/misc/arm/a
+++ b/misc/arm/a
@@ -29,7 +29,7 @@ exp ()
rloc=/data/local/tmp/retval
rsize=$(adb shell "ls -l $rloc"|tr -s ' '|cut -d' ' -f4)
rcheck=38
-if [ $rsize != $rcheck ] ; then
+if [ "$rsize" != "$rcheck" ]; then
# echo "debug: retval size incorrect want $rcheck, got $rsize. uploading"
echo >/tmp/adb.retval '#!/system/bin/sh
"$@"
@@ -39,11 +39,20 @@ echo RETVAL: $?'
fi
# run the main binary
-if [ "$*" != "$1" ]; then
- args=$(echo $*| cut -d' ' -f2-)
+if [ "-g" == "$1" ]; then
+ adb forward tcp:$2 tcp:$2
+ args=$(echo $*| cut -d' ' -f4-)
+ adb push $3 /data/local/tmp/$3 >/dev/null 2>&1
+ adb shell "$(exp GOARCH) $(exp GOTRACEBACK) $(exp GOGC) \
+ gdbserver :$2 /data/local/tmp/retval /data/local/tmp/$3 $args" \
+ 2>&1|tr -d '\r' |tee /tmp/adb.out|grep -v RETVAL
+else
+ if [ "$*" != "$1" ]; then
+ args=$(echo $*| cut -d' ' -f2-)
+ fi
+ adb push $1 /data/local/tmp/$1 >/dev/null 2>&1
+ adb shell "$(exp GOARCH) $(exp GOTRACEBACK) $(exp GOGC) \
+ /data/local/tmp/retval /data/local/tmp/$1 $args" \
+ 2>&1|tr -d '\r' |tee /tmp/adb.out|grep -v RETVAL
fi
-adb push $1 /data/local/tmp/$1 >/dev/null 2>&1
-adb shell "$(exp GOARCH) $(exp GOTRACEBACK) $(exp GOGC) \
- /data/local/tmp/retval /data/local/tmp/$1 $args" \
- 2>&1|tr -d '\r' |tee /tmp/adb.out|grep -v RETVAL
exit $(grep RETVAL /tmp/adb.out|tr -d '\n\r'| cut -d' ' -f2)
diff --git a/misc/bash/go b/misc/bash/go
index 711020ac9..caced154f 100644
--- a/misc/bash/go
+++ b/misc/bash/go
@@ -3,4 +3,4 @@
complete -f -X '!*.8' 8l
complete -f -X '!*.6' 6l
complete -f -X '!*.5' 5l
-complete -f -X '!*.go' 8g 6g 5g
+complete -f -X '!*.go' 8g 6g 5g gofmt gccgo
diff --git a/misc/bbedit/Go.plist b/misc/bbedit/Go.plist
index 71bb9bc5e..39c8f0dc3 100755
--- a/misc/bbedit/Go.plist
+++ b/misc/bbedit/Go.plist
@@ -6,15 +6,22 @@
BBLMColorsSyntax = YES;
BBLMIsCaseSensitive = YES;
BBLMKeywordList = (
+ append,
bool,
break,
byte,
cap,
case,
chan,
+ close,
+ closed,
cmplx,
+ complex,
+ complex128,
+ complex64,
const,
continue,
+ copy,
default,
defer,
else,
@@ -43,8 +50,12 @@
new,
nil,
package,
+ panic,
+ print,
+ println,
range,
real,
+ recover,
return,
select,
string,
diff --git a/misc/cgo/gmp/Makefile b/misc/cgo/gmp/Makefile
index ad5db33c2..fc6209f27 100644
--- a/misc/cgo/gmp/Makefile
+++ b/misc/cgo/gmp/Makefile
@@ -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 ../../../src/Make.$(GOARCH)
+include ../../../src/Make.inc
TARG=gmp
diff --git a/misc/cgo/life/Makefile b/misc/cgo/life/Makefile
index cbcdc9927..5a10380ed 100644
--- a/misc/cgo/life/Makefile
+++ b/misc/cgo/life/Makefile
@@ -2,30 +2,20 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../../src/Make.$(GOARCH)
+include ../../../src/Make.inc
TARG=life
CGOFILES=\
- life.go
+ life.go\
-LDPATH_freebsd=-Wl,-R,`pwd`
-LDPATH_linux=-Wl,-R,`pwd`
-LDPATH_darwin=
+CGO_OFILES=\
+ c-life.o\
-CGO_LDFLAGS=_cgo_export.o c-life.so $(LDPATH_$(GOOS))
-CGO_DEPS=_cgo_export.o c-life.so
-
-CLEANFILES += life
+CLEANFILES+=life
include ../../../src/Make.pkg
-c-life.o: c-life.c _cgo_export.h
- gcc $(_CGO_CFLAGS_$(GOARCH)) -g -c -fPIC $(CFLAGS) c-life.c
-
-c-life.so: c-life.o
- gcc $(_CGO_CFLAGS_$(GOARCH)) -o $@ c-life.o $(_CGO_LDFLAGS_$(GOOS))
-
life: install main.go
$(GC) main.go
$(LD) -o $@ main.$O
diff --git a/misc/cgo/life/c-life.c b/misc/cgo/life/c-life.c
index 71555a9c7..657245595 100644
--- a/misc/cgo/life/c-life.c
+++ b/misc/cgo/life/c-life.c
@@ -6,6 +6,8 @@
#include "life.h"
#include "_cgo_export.h"
+const int MYCONST = 0;
+
// Do the actual manipulation of the life board in C. This could be
// done easily in Go, we are just using C for demonstration
// purposes.
diff --git a/misc/cgo/life/golden.out b/misc/cgo/life/golden.out
new file mode 100644
index 000000000..539d2106d
--- /dev/null
+++ b/misc/cgo/life/golden.out
@@ -0,0 +1,17 @@
+* life
+
+
+ XXX XXX
+
+
+
+
+
+
+
+ XXX XXX
+
+
+
+
+
diff --git a/misc/cgo/life/life.go b/misc/cgo/life/life.go
index 036802853..ec000ce3a 100644
--- a/misc/cgo/life/life.go
+++ b/misc/cgo/life/life.go
@@ -23,7 +23,7 @@ var chans [4]chan bool
//export GoStart
// Double return value is just for testing.
func GoStart(i, xdim, ydim, xstart, xend, ystart, yend C.int, a *C.int, n *C.int) (int, int) {
- c := make(chan bool)
+ c := make(chan bool, int(C.MYCONST))
go func() {
C.DoStep(xdim, ydim, xstart, xend, ystart, yend, a, n)
c <- true
diff --git a/misc/cgo/life/life.h b/misc/cgo/life/life.h
index b6e94cf1d..b2011b25f 100644
--- a/misc/cgo/life/life.h
+++ b/misc/cgo/life/life.h
@@ -4,3 +4,4 @@
extern void Step(int, int, int *, int *);
extern void DoStep(int, int, int, int, int, int, int *, int *);
+extern const int MYCONST;
diff --git a/misc/cgo/life/main.go b/misc/cgo/life/main.go
index 7c2c0c73e..9cfed434b 100644
--- a/misc/cgo/life/main.go
+++ b/misc/cgo/life/main.go
@@ -29,7 +29,7 @@ func main() {
}
}
- life.Run(*gen, *dim, *dim, &a)
+ life.Run(*gen, *dim, *dim, a[:])
for i := 0; i < *dim; i++ {
for j := 0; j < *dim; j++ {
diff --git a/misc/cgo/life/test.bash b/misc/cgo/life/test.bash
new file mode 100755
index 000000000..5c5fba1a9
--- /dev/null
+++ b/misc/cgo/life/test.bash
@@ -0,0 +1,11 @@
+#!/bin/sh
+# Copyright 2010 The Go 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
+gomake life
+echo '*' life >run.out
+./life >>run.out
+diff run.out golden.out
+gomake clean
diff --git a/misc/cgo/stdio/Makefile b/misc/cgo/stdio/Makefile
index 2e3d46631..fc925e607 100644
--- a/misc/cgo/stdio/Makefile
+++ b/misc/cgo/stdio/Makefile
@@ -2,16 +2,19 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../../src/Make.$(GOARCH)
+include ../../../src/Make.inc
TARG=stdio
CGOFILES=\
- file.go
+ align.go\
+ file.go\
+ test.go\
+ test1.go\
CLEANFILES+=hello fib chain run.out
include ../../../src/Make.pkg
%: install %.go
- $(QUOTED_GOBIN)/$(GC) $*.go
- $(QUOTED_GOBIN)/$(LD) -o $@ $*.$O
+ $(GC) $*.go
+ $(LD) -o $@ $*.$O
diff --git a/misc/cgo/stdio/align.go b/misc/cgo/stdio/align.go
new file mode 100644
index 000000000..6cdfd902f
--- /dev/null
+++ b/misc/cgo/stdio/align.go
@@ -0,0 +1,78 @@
+package stdio
+
+/*
+#include <stdio.h>
+
+typedef unsigned char Uint8;
+typedef unsigned short Uint16;
+
+typedef enum {
+ MOD1 = 0x0000,
+ MODX = 0x8000
+} SDLMod;
+
+typedef enum {
+ A = 1,
+ B = 322,
+ SDLK_LAST
+} SDLKey;
+
+typedef struct SDL_keysym {
+ Uint8 scancode;
+ SDLKey sym;
+ SDLMod mod;
+ Uint16 unicode;
+} SDL_keysym;
+
+typedef struct SDL_KeyboardEvent {
+ Uint8 typ;
+ Uint8 which;
+ Uint8 state;
+ SDL_keysym keysym;
+} SDL_KeyboardEvent;
+
+void makeEvent(SDL_KeyboardEvent *event) {
+ unsigned char *p;
+ int i;
+
+ p = (unsigned char*)event;
+ for (i=0; i<sizeof *event; i++) {
+ p[i] = i;
+ }
+}
+
+int same(SDL_KeyboardEvent* e, Uint8 typ, Uint8 which, Uint8 state, Uint8 scan, SDLKey sym, SDLMod mod, Uint16 uni) {
+ return e->typ == typ && e->which == which && e->state == state && e->keysym.scancode == scan && e->keysym.sym == sym && e->keysym.mod == mod && e->keysym.unicode == uni;
+}
+
+void cTest(SDL_KeyboardEvent *event) {
+ printf("C: %#x %#x %#x %#x %#x %#x %#x\n", event->typ, event->which, event->state,
+ event->keysym.scancode, event->keysym.sym, event->keysym.mod, event->keysym.unicode);
+ fflush(stdout);
+}
+
+*/
+import "C"
+
+import (
+ "fmt"
+ "syscall"
+)
+
+func TestAlign() {
+ if syscall.ARCH == "amd64" {
+ // alignment is known to be broken on amd64.
+ // http://code.google.com/p/go/issues/detail?id=609
+ return
+ }
+ var evt C.SDL_KeyboardEvent
+ C.makeEvent(&evt)
+ if C.same(&evt, evt.typ, evt.which, evt.state, evt.keysym.scancode, evt.keysym.sym, evt.keysym.mod, evt.keysym.unicode) == 0 {
+ fmt.Println("*** bad alignment")
+ C.cTest(&evt)
+ fmt.Printf("Go: %#x %#x %#x %#x %#x %#x %#x\n",
+ evt.typ, evt.which, evt.state, evt.keysym.scancode,
+ evt.keysym.sym, evt.keysym.mod, evt.keysym.unicode)
+ fmt.Println(evt)
+ }
+}
diff --git a/misc/cgo/stdio/chain.go b/misc/cgo/stdio/chain.go
index dd5e01542..c2b105072 100644
--- a/misc/cgo/stdio/chain.go
+++ b/misc/cgo/stdio/chain.go
@@ -22,7 +22,7 @@ func link(left chan<- int, right <-chan int) {
runtime.LockOSThread()
for {
v := <-right
- stdio.Puts(strconv.Itoa(v))
+ stdio.Stdout.WriteString(strconv.Itoa(v) + "\n")
left <- 1+v
}
}
@@ -38,6 +38,6 @@ func main() {
for i := 0; i < R; i++ {
right <- 0
x := <-leftmost
- stdio.Puts(strconv.Itoa(x))
+ stdio.Stdout.WriteString(strconv.Itoa(x) + "\n")
}
}
diff --git a/misc/cgo/stdio/fib.go b/misc/cgo/stdio/fib.go
index 63ae04988..c02e31fd8 100644
--- a/misc/cgo/stdio/fib.go
+++ b/misc/cgo/stdio/fib.go
@@ -26,7 +26,7 @@ func fibber(c, out chan int64, i int64) {
}
for {
j := <-c
- stdio.Puts(strconv.Itoa64(j))
+ stdio.Stdout.WriteString(strconv.Itoa64(j) + "\n")
out <- j
<-out
i += j
diff --git a/misc/cgo/stdio/file.go b/misc/cgo/stdio/file.go
index 7d1f22280..021cbf909 100644
--- a/misc/cgo/stdio/file.go
+++ b/misc/cgo/stdio/file.go
@@ -10,33 +10,35 @@ see ../gmp/gmp.go.
package stdio
-// TODO(rsc): Remove fflushstdout when C.fflush(C.stdout) works in cgo.
-
/*
#include <stdio.h>
#include <stdlib.h>
+#include <sys/stat.h>
+#include <errno.h>
-void fflushstdout(void) { fflush(stdout); }
+char* greeting = "hello, world";
*/
import "C"
import "unsafe"
-/*
type File C.FILE
var Stdout = (*File)(C.stdout)
var Stderr = (*File)(C.stderr)
-func (f *File) WriteString(s string) {
- p := C.CString(s);
- C.fputs(p, (*C.FILE)(f));
- C.free(p);
-}
-*/
+// Test reference to library symbol.
+// Stdout and stderr are too special to be a reliable test.
+var myerr = C.sys_errlist
-func Puts(s string) {
+func (f *File) WriteString(s string) {
p := C.CString(s)
- C.puts(p)
+ C.fputs(p, (*C.FILE)(f))
C.free(unsafe.Pointer(p))
- C.fflushstdout()
+ f.Flush()
+}
+
+func (f *File) Flush() {
+ C.fflush((*C.FILE)(f))
}
+
+var Greeting = C.GoString(C.greeting)
diff --git a/misc/cgo/stdio/hello.go b/misc/cgo/stdio/hello.go
index 47f9de02f..9cb6e6884 100644
--- a/misc/cgo/stdio/hello.go
+++ b/misc/cgo/stdio/hello.go
@@ -4,9 +4,26 @@
package main
-import "stdio"
+import (
+ "os"
+ "stdio"
+)
func main() {
- // stdio.Stdout.WriteString("hello, world\n");
- stdio.Puts("hello, world")
+ stdio.Stdout.WriteString(stdio.Greeting + "\n")
+
+ l := stdio.Atol("123")
+ if l != 123 {
+ println("Atol 123: ", l)
+ panic("bad atol")
+ }
+
+ n, err := stdio.Strtol("asdf", 123)
+ if n != 0 || err != os.EINVAL {
+ println("Strtol: ", n, err)
+ panic("bad atoi2")
+ }
+
+ stdio.TestAlign()
+ stdio.TestEnum()
}
diff --git a/misc/cgo/stdio/test.bash b/misc/cgo/stdio/test.bash
index b8b5f6911..82e3f7b45 100755
--- a/misc/cgo/stdio/test.bash
+++ b/misc/cgo/stdio/test.bash
@@ -4,8 +4,7 @@
# license that can be found in the LICENSE file.
set -e
-GOBIN="${GOBIN:-$HOME/bin}"
-"$GOBIN"/gomake hello fib chain
+gomake hello fib chain
echo '*' hello >run.out
./hello >>run.out
echo '*' fib >>run.out
@@ -13,4 +12,4 @@ echo '*' fib >>run.out
echo '*' chain >>run.out
./chain >>run.out
diff run.out golden.out
-"$GOBIN"/gomake clean
+gomake clean
diff --git a/misc/cgo/stdio/test.go b/misc/cgo/stdio/test.go
new file mode 100644
index 000000000..8f21603ca
--- /dev/null
+++ b/misc/cgo/stdio/test.go
@@ -0,0 +1,144 @@
+// Copyright 2010 The Go 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 cgo.
+
+package stdio
+
+/*
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+#define SHIFT(x, y) ((x)<<(y))
+#define KILO SHIFT(1, 10)
+
+enum E {
+ Enum1 = 1,
+ Enum2 = 2,
+};
+
+typedef unsigned char uuid_t[20];
+
+void uuid_generate(uuid_t x) {
+ x[0] = 0;
+}
+
+struct S {
+ int x;
+};
+
+extern enum E myConstFunc(struct S* const ctx, int const id, struct S **const filter);
+
+enum E myConstFunc(struct S *const ctx, int const id, struct S **const filter) { return 0; }
+
+// issue 1222
+typedef union {
+ long align;
+} xxpthread_mutex_t;
+
+struct ibv_async_event {
+ union {
+ int x;
+ } element;
+};
+
+struct ibv_context {
+ xxpthread_mutex_t mutex;
+};
+*/
+import "C"
+import (
+ "os"
+ "unsafe"
+)
+
+const EINVAL = C.EINVAL /* test #define */
+
+var KILO = C.KILO
+
+func uuidgen() {
+ var uuid C.uuid_t
+ C.uuid_generate(&uuid[0])
+}
+
+func Size(name string) (int64, os.Error) {
+ var st C.struct_stat
+ p := C.CString(name)
+ _, err := C.stat(p, &st)
+ C.free(unsafe.Pointer(p))
+ if err != nil {
+ return 0, err
+ }
+ return int64(C.ulong(st.st_size)), nil
+}
+
+func Strtol(s string, base int) (int, os.Error) {
+ p := C.CString(s)
+ n, err := C.strtol(p, nil, C.int(base))
+ C.free(unsafe.Pointer(p))
+ return int(n), err
+}
+
+func Atol(s string) int {
+ p := C.CString(s)
+ n := C.atol(p)
+ C.free(unsafe.Pointer(p))
+ return int(n)
+}
+
+func TestConst() {
+ C.myConstFunc(nil, 0, nil)
+}
+
+func TestEnum() {
+ if C.Enum1 != 1 || C.Enum2 != 2 {
+ println("bad enum", C.Enum1, C.Enum2)
+ }
+}
+
+func TestAtol() {
+ l := Atol("123")
+ if l != 123 {
+ println("Atol 123: ", l)
+ panic("bad atol")
+ }
+}
+
+func TestErrno() {
+ n, err := Strtol("asdf", 123)
+ if n != 0 || err != os.EINVAL {
+ println("Strtol: ", n, err)
+ panic("bad strtol")
+ }
+}
+
+func TestMultipleAssign() {
+ p := C.CString("123")
+ n, m := C.strtol(p, nil, 345), C.strtol(p, nil, 10)
+ if n != 0 || m != 234 {
+ println("Strtol x2: ", n, m)
+ panic("bad strtol x2")
+ }
+ C.free(unsafe.Pointer(p))
+}
+
+var (
+ uint = (C.uint)(0)
+ ulong C.ulong
+ char C.char
+)
+
+type Context struct {
+ ctx *C.struct_ibv_context
+}
+
+func Test() {
+ TestAlign()
+ TestAtol()
+ TestEnum()
+ TestErrno()
+ TestConst()
+}
diff --git a/misc/cgo/stdio/test1.go b/misc/cgo/stdio/test1.go
new file mode 100644
index 000000000..dce2ef83c
--- /dev/null
+++ b/misc/cgo/stdio/test1.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.
+
+// This file contains test cases for cgo.
+
+package stdio
+
+/*
+// issue 1222
+typedef union {
+ long align;
+} xxpthread_mutex_t;
+
+struct ibv_async_event {
+ union {
+ int x;
+ } element;
+};
+
+struct ibv_context {
+ xxpthread_mutex_t mutex;
+};
+*/
+import "C"
+
+type AsyncEvent struct {
+ event C.struct_ibv_async_event
+}
diff --git a/misc/dashboard/README b/misc/dashboard/README
index b2bc3c2d3..72d5546a4 100644
--- a/misc/dashboard/README
+++ b/misc/dashboard/README
@@ -24,11 +24,19 @@ export GOARCH=XXX
export GOOS=XXX
export GOBIN=/gobuild/bin
export PATH=$PATH:/gobuild/bin
-export BUILDER=XXX
+export BUILDER=$GOOS-$GOARCH
export BUILDHOST=godashboard.appspot.com
-* Write the key ~gobuild/.gobuildkey (you need to get it from someone who knows
- the key)
+* Write the key ~gobuild/.gobuildkey
+ You need to get it from someone who knows the key.
+ You may also use a filename of the form .gobuildkey-$BUILDER if you
+ wish to run builders for multiple targets.
+
+* Append your username and password googlecode.com credentials from
+ https://code.google.com/hosting/settings
+ to the buildkey file in the format "Username\nPassword\n".
+ (This is for uploading tarballs to the project downloads section,
+ and is an optional step.)
* sudo apt-get install bison gcc libc6-dev ed make
* cd ~gobuild
diff --git a/misc/dashboard/buildcontrol.py b/misc/dashboard/buildcontrol.py
index 91b684f79..ec503e7ff 100644
--- a/misc/dashboard/buildcontrol.py
+++ b/misc/dashboard/buildcontrol.py
@@ -18,6 +18,8 @@ buildhost = ''
buildport = -1
buildkey = ''
+upload_project = "go"
+
def main(args):
global buildport, buildhost, buildkey
@@ -35,14 +37,23 @@ def main(args):
buildport = int(os.environ['BUILDPORT'])
try:
- buildkey = file('%s/.gobuildkey-%s' % (os.environ['HOME'], os.environ['BUILDER']), 'r').read().strip()
+ buildkeyfile = file('%s/.gobuildkey-%s' % (os.environ['HOME'], os.environ['BUILDER']), 'r')
+ buildkey = buildkeyfile.readline().strip()
except IOError:
try:
- buildkey = file('%s/.gobuildkey' % os.environ['HOME'], 'r').read().strip()
+ buildkeyfile = file('%s/.gobuildkey' % os.environ['HOME'], 'r')
+ buildkey = buildkeyfile.readline().strip()
except IOError:
print >>sys.stderr, "Need key in ~/.gobuildkey-%s or ~/.gobuildkey" % os.environ['BUILDER']
return
+ # get upload credentials
+ try:
+ username = buildkeyfile.readline().strip()
+ password = buildkeyfile.readline().strip()
+ except:
+ username, password = None, None
+
if args[1] == 'init':
return doInit(args)
elif args[1] == 'hwget':
@@ -55,6 +66,8 @@ def main(args):
return doRecord(args)
elif args[1] == 'benchmarks':
return doBenchmarks(args)
+ elif args[1] == 'upload':
+ return doUpload(args, username, password)
else:
return usage(args[0])
@@ -68,6 +81,7 @@ Commands:
next <builder>: get the next revision number to by built by the given builder
record <builder> <rev> <ok|log file>: record a build result
benchmarks <builder> <rev> <log file>: record benchmark numbers
+ upload <builder> <summary> <tar file>: upload tarball to googlecode
''' % name)
return 1
@@ -165,6 +179,29 @@ def doBenchmarks(args):
e.append(b)
return command('benchmarks', {'node': c.node, 'builder': builder, 'benchmarkdata': binascii.b2a_base64(''.join(e))})
+def doUpload(args, username, password):
+ # fail gracefully if no username or password set
+ if not username or not password:
+ return
+
+ if len(args) != 5:
+ return usage(args[0])
+ builder = args[2]
+ summary = args[3]
+ filename = args[4]
+
+ from googlecode_upload import upload
+ code, msg, url = upload(
+ filename, # filename
+ upload_project, # 'go'
+ username,
+ password,
+ summary,
+ builder.split('-'), # labels
+ )
+ if code != 201:
+ raise Failed('Upload returned code %s msg "%s".' % (code, msg))
+
def encodeMultipartFormdata(fields, files):
"""fields is a sequence of (name, value) elements for regular form fields.
files is a sequence of (name, filename, value) elements for data to be uploaded as files"""
diff --git a/misc/dashboard/buildcron.sh b/misc/dashboard/buildcron.sh
index 5f4300796..7aa70ce57 100644
--- a/misc/dashboard/buildcron.sh
+++ b/misc/dashboard/buildcron.sh
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/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.
@@ -48,7 +48,7 @@ fi
mkdir -p $GOROOT/bin
cd $GOROOT/..
-cp go/misc/dashboard/builder.sh go/misc/dashboard/buildcontrol.py .
+cp go/misc/dashboard/{builder.sh,buildcontrol.py,googlecode_upload.py} .
chmod a+x builder.sh buildcontrol.py
cd go
../buildcontrol.py next $BUILDER
diff --git a/misc/dashboard/builder.sh b/misc/dashboard/builder.sh
index b302acec2..4a8d117bf 100644
--- a/misc/dashboard/builder.sh
+++ b/misc/dashboard/builder.sh
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/usr/bin/env bash
# Copyright 2009 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
@@ -31,8 +31,9 @@ fi
export PATH=$PATH:`pwd`/candidate/bin
export GOBIN=`pwd`/candidate/bin
+export GOROOT_FINAL=/usr/local/go
-while true ; do
+while true ; do (
cd go || fatal "Cannot cd into 'go'"
hg pull -u || fatal "hg sync failed"
rev=`python ../buildcontrol.py next $BUILDER`
@@ -72,7 +73,23 @@ while true ; do
python ../../../buildcontrol.py benchmarks $BUILDER $rev ../../benchmarks || fatal "Cannot record benchmarks"
cd .. || fatal "failed to cd out of pkg"
fi
+ # check if we're at a release (via the hg summary)
+ # if so, package the tar.gz and upload to googlecode
+ SUMMARY=$(hg log -l 1 | grep summary\: | awk '{print $2}')
+ if [[ "x${SUMMARY:0:7}" == "xrelease" ]]; then
+ echo "Uploading binary to googlecode"
+ TARBALL="go.$SUMMARY.$BUILDER.tar.gz"
+ ./clean.bash --nopkg
+ # move contents of candidate/ to candidate/go/ for archival
+ cd ../.. || fatal "Cannot cd up"
+ mv candidate go-candidate || fatal "Cannot rename candidate"
+ mkdir candidate || fatal "Cannot mkdir candidate"
+ mv go-candidate candidate/go || fatal "Cannot mv directory"
+ cd candidate || fatal "Cannot cd candidate"
+ # build tarball
+ tar czf ../$TARBALL go || fatal "Cannot create tarball"
+ ../buildcontrol.py upload $BUILDER $SUMMARY ../$TARBALL || fatal "Cannot upload tarball"
+ fi
fi
- cd ../.. || fatal "Cannot cd up"
sleep 10
-done
+) done
diff --git a/src/pkg/once/Makefile b/misc/dashboard/builder/Makefile
index e87fbf810..7270a3f42 100644
--- a/src/pkg/once/Makefile
+++ b/misc/dashboard/builder/Makefile
@@ -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 ../../Make.$(GOARCH)
+include ../../../src/Make.inc
-TARG=once
+TARG=gobuilder
GOFILES=\
- once.go\
+ exec.go\
+ hg.go\
+ http.go\
+ main.go\
-include ../../Make.pkg
+include ../../../src/Make.cmd
diff --git a/misc/dashboard/builder/doc.go b/misc/dashboard/builder/doc.go
new file mode 100644
index 000000000..54a9adfc0
--- /dev/null
+++ b/misc/dashboard/builder/doc.go
@@ -0,0 +1,54 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+
+Go Builder is a continuous build client for the Go project.
+It integrates with the Go Dashboard AppEngine application.
+
+Go Builder is intended to run continuously as a background process.
+
+It periodically pulls updates from the Go Mercurial repository.
+
+When a newer revision is found, Go Builder creates a clone of the repository,
+runs all.bash, and reports build success or failure to the Go Dashboard.
+
+For a successful build, Go Builder will also run benchmarks
+(cd $GOROOT/src/pkg; make bench) and send the results to the Go Dashboard.
+
+For a release revision (a change description that matches "release.YYYY-MM-DD"),
+Go Builder will create a tar.gz archive of the GOROOT and deliver it to the
+Go Google Code project's downloads section.
+
+Usage:
+
+ gobuilder goos-goarch...
+
+ Several goos-goarch combinations can be provided, and the builder will
+ build them in serial.
+
+Optional flags:
+
+ -dashboard="godashboard.appspot.com": Go Dashboard Host
+ The location of the Go Dashboard application to which Go Builder will
+ report its results.
+
+ -bench: Run benchmarks
+
+ -release: Build and deliver binary release archive
+
+The key file should be located at $HOME/.gobuilder or, for a builder-specific
+key, $HOME/.gobuilder-$BUILDER (eg, $HOME/.gobuilder-linux-amd64).
+
+The build key file is a text file of the format:
+
+ godashboard-key
+ googlecode-username
+ googlecode-password
+
+If the Google Code credentials are not provided the archival step
+will be skipped.
+
+*/
+package documentation
diff --git a/misc/dashboard/builder/exec.go b/misc/dashboard/builder/exec.go
new file mode 100644
index 000000000..6236c915a
--- /dev/null
+++ b/misc/dashboard/builder/exec.go
@@ -0,0 +1,65 @@
+package main
+
+import (
+ "bytes"
+ "exec"
+ "io"
+ "os"
+ "strings"
+)
+
+// run is a simple wrapper for exec.Run/Close
+func run(envv []string, dir string, argv ...string) os.Error {
+ bin, err := pathLookup(argv[0])
+ if err != nil {
+ return err
+ }
+ p, err := exec.Run(bin, argv, envv, dir,
+ exec.DevNull, exec.DevNull, exec.PassThrough)
+ if err != nil {
+ return err
+ }
+ return p.Close()
+}
+
+// runLog runs a process and returns the combined stdout/stderr,
+// as well as writing it to logfile (if specified).
+func runLog(envv []string, logfile, dir string, argv ...string) (output string, exitStatus int, err os.Error) {
+ bin, err := pathLookup(argv[0])
+ if err != nil {
+ return
+ }
+ p, err := exec.Run(bin, argv, envv, dir,
+ exec.DevNull, exec.Pipe, exec.MergeWithStdout)
+ if err != nil {
+ return
+ }
+ defer p.Close()
+ b := new(bytes.Buffer)
+ var w io.Writer = b
+ if logfile != "" {
+ f, err := os.Open(logfile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
+ if err != nil {
+ return
+ }
+ defer f.Close()
+ w = io.MultiWriter(f, b)
+ }
+ _, err = io.Copy(w, p.Stdout)
+ if err != nil {
+ return
+ }
+ wait, err := p.Wait(0)
+ if err != nil {
+ return
+ }
+ return b.String(), wait.WaitStatus.ExitStatus(), nil
+}
+
+// Find bin in PATH if a relative or absolute path hasn't been specified
+func pathLookup(s string) (string, os.Error) {
+ if strings.HasPrefix(s, "/") || strings.HasPrefix(s, "./") || strings.HasPrefix(s, "../") {
+ return s, nil
+ }
+ return exec.LookPath(s)
+}
diff --git a/misc/dashboard/builder/hg.go b/misc/dashboard/builder/hg.go
new file mode 100644
index 000000000..5d2f63a17
--- /dev/null
+++ b/misc/dashboard/builder/hg.go
@@ -0,0 +1,54 @@
+package main
+
+import (
+ "fmt"
+ "os"
+ "strconv"
+ "strings"
+)
+
+type Commit struct {
+ num int // mercurial revision number
+ node string // mercurial hash
+ parent string // hash of commit's parent
+ user string // author's Name <email>
+ date string // date of commit
+ desc string // description
+}
+
+// getCommit returns details about the Commit specified by the revision hash
+func getCommit(rev string) (c Commit, err os.Error) {
+ defer func() {
+ if err != nil {
+ err = fmt.Errorf("getCommit: %s: %s", rev, err)
+ }
+ }()
+ parts, err := getCommitParts(rev)
+ if err != nil {
+ return
+ }
+ num, err := strconv.Atoi(parts[0])
+ if err != nil {
+ return
+ }
+ parent := ""
+ if num > 0 {
+ prev := strconv.Itoa(num - 1)
+ if pparts, err := getCommitParts(prev); err == nil {
+ parent = pparts[1]
+ }
+ }
+ user := strings.Replace(parts[2], "&lt;", "<", -1)
+ user = strings.Replace(user, "&gt;", ">", -1)
+ return Commit{num, parts[1], parent, user, parts[3], parts[4]}, nil
+}
+
+func getCommitParts(rev string) (parts []string, err os.Error) {
+ const format = "{rev}>{node}>{author|escape}>{date}>{desc}"
+ s, _, err := runLog(nil, "", goroot,
+ "hg", "log", "-r", rev, "-l", "1", "--template", format)
+ if err != nil {
+ return
+ }
+ return strings.Split(s, ">", 5), nil
+}
diff --git a/misc/dashboard/builder/http.go b/misc/dashboard/builder/http.go
new file mode 100644
index 000000000..02f281061
--- /dev/null
+++ b/misc/dashboard/builder/http.go
@@ -0,0 +1,70 @@
+package main
+
+import (
+ "bytes"
+ "encoding/base64"
+ "encoding/binary"
+ "fmt"
+ "http"
+ "os"
+ "regexp"
+)
+
+// getHighWater returns the current highwater revision hash for this builder
+func (b *Builder) getHighWater() (rev string, err os.Error) {
+ url := fmt.Sprintf("http://%s/hw-get?builder=%s", *dashboard, b.name)
+ r, _, err := http.Get(url)
+ if err != nil {
+ return
+ }
+ buf := new(bytes.Buffer)
+ _, err = buf.ReadFrom(r.Body)
+ if err != nil {
+ return
+ }
+ r.Body.Close()
+ return buf.String(), nil
+}
+
+// recordResult sends build results to the dashboard
+func (b *Builder) recordResult(buildLog string, c Commit) os.Error {
+ return httpCommand("build", map[string]string{
+ "builder": b.name,
+ "key": b.key,
+ "node": c.node,
+ "parent": c.parent,
+ "user": c.user,
+ "date": c.date,
+ "desc": c.desc,
+ "log": buildLog,
+ })
+}
+
+// match lines like: "package.BechmarkFunc 100000 999 ns/op"
+var benchmarkRegexp = regexp.MustCompile("([^\n\t ]+)[\t ]+([0-9]+)[\t ]+([0-9]+) ns/op")
+
+// recordBenchmarks sends benchmark results to the dashboard
+func (b *Builder) recordBenchmarks(benchLog string, c Commit) os.Error {
+ results := benchmarkRegexp.FindAllStringSubmatch(benchLog, -1)
+ var buf bytes.Buffer
+ b64 := base64.NewEncoder(base64.StdEncoding, &buf)
+ for _, r := range results {
+ for _, s := range r[1:] {
+ binary.Write(b64, binary.BigEndian, uint16(len(s)))
+ b64.Write([]byte(s))
+ }
+ }
+ b64.Close()
+ return httpCommand("benchmarks", map[string]string{
+ "builder": b.name,
+ "key": b.key,
+ "node": c.node,
+ "benchmarkdata": buf.String(),
+ })
+}
+
+func httpCommand(cmd string, args map[string]string) os.Error {
+ url := fmt.Sprintf("http://%v/%v", *dashboard, cmd)
+ _, err := http.PostForm(url, args)
+ return err
+}
diff --git a/misc/dashboard/builder/main.go b/misc/dashboard/builder/main.go
new file mode 100644
index 000000000..32a2e10da
--- /dev/null
+++ b/misc/dashboard/builder/main.go
@@ -0,0 +1,340 @@
+package main
+
+import (
+ "container/vector"
+ "flag"
+ "fmt"
+ "io/ioutil"
+ "log"
+ "os"
+ "path"
+ "regexp"
+ "strconv"
+ "strings"
+ "time"
+)
+
+const (
+ codeProject = "go"
+ codePyScript = "misc/dashboard/googlecode_upload.py"
+ hgUrl = "https://go.googlecode.com/hg/"
+ waitInterval = 10e9 // time to wait before checking for new revs
+ mkdirPerm = 0750
+)
+
+type Builder struct {
+ name string
+ goos, goarch string
+ key string
+ codeUsername string
+ codePassword string
+}
+
+type BenchRequest struct {
+ builder *Builder
+ commit Commit
+ path string
+}
+
+var (
+ buildroot = flag.String("buildroot", path.Join(os.TempDir(), "gobuilder"), "Directory under which to build")
+ dashboard = flag.String("dashboard", "godashboard.appspot.com", "Go Dashboard Host")
+ runBenchmarks = flag.Bool("bench", false, "Run benchmarks")
+ buildRelease = flag.Bool("release", false, "Build and upload binary release archives")
+ buildRevision = flag.String("rev", "", "Build specified revision and exit")
+ buildCmd = flag.String("cmd", "./all.bash", "Build command (specify absolute or relative to go/src/)")
+)
+
+var (
+ goroot string
+ releaseRegexp = regexp.MustCompile(`^release\.[0-9\-.]+`)
+ benchRequests vector.Vector
+)
+
+func main() {
+ flag.Usage = func() {
+ fmt.Fprintf(os.Stderr, "usage: %s goos-goarch...\n", os.Args[0])
+ flag.PrintDefaults()
+ os.Exit(2)
+ }
+ flag.Parse()
+ if len(flag.Args()) == 0 {
+ flag.Usage()
+ }
+ goroot = path.Join(*buildroot, "goroot")
+ builders := make([]*Builder, len(flag.Args()))
+ for i, builder := range flag.Args() {
+ b, err := NewBuilder(builder)
+ if err != nil {
+ log.Exit(err)
+ }
+ builders[i] = b
+ }
+ if err := os.RemoveAll(*buildroot); err != nil {
+ log.Exitf("Error removing build root (%s): %s", *buildroot, err)
+ }
+ if err := os.Mkdir(*buildroot, mkdirPerm); err != nil {
+ log.Exitf("Error making build root (%s): %s", *buildroot, err)
+ }
+ if err := run(nil, *buildroot, "hg", "clone", hgUrl, goroot); err != nil {
+ log.Exit("Error cloning repository:", err)
+ }
+ // if specified, build revision and return
+ if *buildRevision != "" {
+ c, err := getCommit(*buildRevision)
+ if err != nil {
+ log.Exit("Error finding revision: ", err)
+ }
+ for _, b := range builders {
+ if err := b.buildCommit(c); err != nil {
+ log.Println(err)
+ }
+ runQueuedBenchmark()
+ }
+ return
+ }
+ // check for new commits and build them
+ for {
+ err := run(nil, goroot, "hg", "pull", "-u")
+ if err != nil {
+ log.Println("hg pull failed:", err)
+ time.Sleep(waitInterval)
+ continue
+ }
+ built := false
+ for _, b := range builders {
+ if b.build() {
+ built = true
+ }
+ }
+ // only run benchmarks if we didn't build anything
+ // so that they don't hold up the builder queue
+ if !built {
+ if !runQueuedBenchmark() {
+ // if we have no benchmarks to do, pause
+ time.Sleep(waitInterval)
+ }
+ // after running one benchmark,
+ // continue to find and build new revisions.
+ }
+ }
+}
+
+func runQueuedBenchmark() bool {
+ if benchRequests.Len() == 0 {
+ return false
+ }
+ runBenchmark(benchRequests.Pop().(BenchRequest))
+ return true
+}
+
+func runBenchmark(r BenchRequest) {
+ // run benchmarks and send to dashboard
+ log.Println(r.builder.name, "benchmarking", r.commit.num)
+ defer os.RemoveAll(r.path)
+ pkg := path.Join(r.path, "go", "src", "pkg")
+ bin := path.Join(r.path, "go", "bin")
+ env := []string{
+ "GOOS=" + r.builder.goos,
+ "GOARCH=" + r.builder.goarch,
+ "PATH=" + bin + ":" + os.Getenv("PATH"),
+ }
+ logfile := path.Join(r.path, "bench.log")
+ benchLog, _, err := runLog(env, logfile, pkg, "gomake", "bench")
+ if err != nil {
+ log.Println(r.builder.name, "gomake bench:", err)
+ return
+ }
+ if err = r.builder.recordBenchmarks(benchLog, r.commit); err != nil {
+ log.Println("recordBenchmarks:", err)
+ }
+}
+
+func NewBuilder(builder string) (*Builder, os.Error) {
+ b := &Builder{name: builder}
+
+ // get goos/goarch from builder string
+ s := strings.Split(builder, "-", 3)
+ if len(s) == 2 {
+ b.goos, b.goarch = s[0], s[1]
+ } else {
+ return nil, fmt.Errorf("unsupported builder form: %s", builder)
+ }
+
+ // read keys from keyfile
+ fn := path.Join(os.Getenv("HOME"), ".gobuildkey")
+ if s := fn + "-" + b.name; isFile(s) { // builder-specific file
+ fn = s
+ }
+ c, err := ioutil.ReadFile(fn)
+ if err != nil {
+ return nil, fmt.Errorf("readKeys %s (%s): %s", b.name, fn, err)
+ }
+ v := strings.Split(string(c), "\n", -1)
+ b.key = v[0]
+ if len(v) >= 3 {
+ b.codeUsername, b.codePassword = v[1], v[2]
+ }
+
+ return b, nil
+}
+
+// build checks for a new commit for this builder
+// and builds it if one is found.
+// It returns true if a build was attempted.
+func (b *Builder) build() bool {
+ defer func() {
+ err := recover()
+ if err != nil {
+ log.Println(b.name, "build:", err)
+ }
+ }()
+ c, err := b.nextCommit()
+ if err != nil {
+ log.Println(err)
+ return false
+ }
+ if c == nil {
+ return false
+ }
+ err = b.buildCommit(*c)
+ if err != nil {
+ log.Println(err)
+ }
+ return true
+}
+
+// nextCommit returns the next unbuilt Commit for this builder
+func (b *Builder) nextCommit() (nextC *Commit, err os.Error) {
+ defer func() {
+ if err != nil {
+ err = fmt.Errorf("%s nextCommit: %s", b.name, err)
+ }
+ }()
+ hw, err := b.getHighWater()
+ if err != nil {
+ return
+ }
+ c, err := getCommit(hw)
+ if err != nil {
+ return
+ }
+ next := c.num + 1
+ c, err = getCommit(strconv.Itoa(next))
+ if err == nil && c.num == next {
+ return &c, nil
+ }
+ return nil, nil
+}
+
+func (b *Builder) buildCommit(c Commit) (err os.Error) {
+ defer func() {
+ if err != nil {
+ err = fmt.Errorf("%s buildCommit: %d: %s", b.name, c.num, err)
+ }
+ }()
+
+ log.Println(b.name, "building", c.num)
+
+ // create place in which to do work
+ workpath := path.Join(*buildroot, b.name+"-"+strconv.Itoa(c.num))
+ err = os.Mkdir(workpath, mkdirPerm)
+ if err != nil {
+ return
+ }
+ benchRequested := false
+ defer func() {
+ if !benchRequested {
+ os.RemoveAll(workpath)
+ }
+ }()
+
+ // clone repo
+ err = run(nil, workpath, "hg", "clone", goroot, "go")
+ if err != nil {
+ return
+ }
+
+ // update to specified revision
+ err = run(nil, path.Join(workpath, "go"),
+ "hg", "update", "-r", strconv.Itoa(c.num))
+ if err != nil {
+ return
+ }
+
+ // set up environment for build/bench execution
+ env := []string{
+ "GOOS=" + b.goos,
+ "GOARCH=" + b.goarch,
+ "GOHOSTOS=" + os.Getenv("GOHOSTOS"),
+ "GOHOSTARCH=" + os.Getenv("GOHOSTARCH"),
+ "GOROOT_FINAL=/usr/local/go",
+ "PATH=" + os.Getenv("PATH"),
+ }
+ srcDir := path.Join(workpath, "go", "src")
+
+ // build
+ logfile := path.Join(workpath, "build.log")
+ buildLog, status, err := runLog(env, logfile, srcDir, *buildCmd)
+ if err != nil {
+ return fmt.Errorf("all.bash: %s", err)
+ }
+ if status != 0 {
+ // record failure
+ return b.recordResult(buildLog, c)
+ }
+
+ // record success
+ if err = b.recordResult("", c); err != nil {
+ return fmt.Errorf("recordResult: %s", err)
+ }
+
+ // send benchmark request if benchmarks are enabled
+ if *runBenchmarks {
+ benchRequests.Insert(0, BenchRequest{
+ builder: b,
+ commit: c,
+ path: workpath,
+ })
+ benchRequested = true
+ }
+
+ // finish here if codeUsername and codePassword aren't set
+ if b.codeUsername == "" || b.codePassword == "" || !*buildRelease {
+ return
+ }
+
+ // if this is a release, create tgz and upload to google code
+ if release := releaseRegexp.FindString(c.desc); release != "" {
+ // clean out build state
+ err = run(env, srcDir, "./clean.bash", "--nopkg")
+ if err != nil {
+ return fmt.Errorf("clean.bash: %s", err)
+ }
+ // upload binary release
+ fn := fmt.Sprintf("go.%s.%s-%s.tar.gz", release, b.goos, b.goarch)
+ err = run(nil, workpath, "tar", "czf", fn, "go")
+ if err != nil {
+ return fmt.Errorf("tar: %s", err)
+ }
+ err = run(nil, workpath, path.Join(goroot, codePyScript),
+ "-s", release,
+ "-p", codeProject,
+ "-u", b.codeUsername,
+ "-w", b.codePassword,
+ "-l", fmt.Sprintf("%s,%s", b.goos, b.goarch),
+ fn)
+ }
+
+ return
+}
+
+func isDirectory(name string) bool {
+ s, err := os.Stat(name)
+ return err == nil && s.IsDirectory()
+}
+
+func isFile(name string) bool {
+ s, err := os.Stat(name)
+ return err == nil && (s.IsRegular() || s.IsSymlink())
+}
diff --git a/misc/dashboard/godashboard/package.py b/misc/dashboard/godashboard/package.py
index 6c3bd9995..cf59bf3e8 100644
--- a/misc/dashboard/godashboard/package.py
+++ b/misc/dashboard/godashboard/package.py
@@ -17,6 +17,7 @@ from google.appengine.ext.webapp import template
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.api import users
from google.appengine.api import mail
+from google.appengine.api import urlfetch
import binascii
import datetime
import hashlib
@@ -29,6 +30,11 @@ import time
import urllib2
import sets
+# local imports
+import toutf8
+
+template.register_template_library('toutf8')
+
# Storage model for package info recorded on server.
# Just path, count, and time of last install.
class Package(db.Model):
@@ -50,36 +56,91 @@ re_bitbucket = re.compile(r'^bitbucket\.org/[a-z0-9A-Z_.\-]+/[a-z0-9A-Z_.\-]+$')
re_googlecode = re.compile(r'^[a-z0-9\-]+\.googlecode\.com/(svn|hg)$')
re_github = re.compile(r'^github\.com/[a-z0-9A-Z_.\-]+/[a-z0-9A-Z_.\-]+$')
+def vc_to_web(path):
+ if re_bitbucket.match(path):
+ check_url = 'http://' + path + '/?cmd=heads'
+ web = 'http://' + path + '/'
+ elif re_github.match(path):
+ # github doesn't let you fetch the .git directory anymore.
+ # fetch .git/info/refs instead, like git clone would.
+ check_url = 'http://'+path+'.git/info/refs'
+ web = 'http://' + path
+ elif re_googlecode.match(path):
+ check_url = 'http://'+path
+ web = 'http://code.google.com/p/' + path[:path.index('.')]
+ else:
+ return False, False
+ return web, check_url
+
+re_bitbucket_web = re.compile(r'bitbucket\.org/([a-z0-9A-Z_.\-]+)/([a-z0-9A-Z_.\-]+)')
+re_googlecode_web = re.compile(r'code.google.com/p/([a-z0-9\-]+)')
+re_github_web = re.compile(r'github\.com/([a-z0-9A-Z_.\-]+)/([a-z0-9A-Z_.\-]+)')
+re_striphttp = re.compile(r'http://(www\.)?')
+
+def web_to_vc(url):
+ url = re_striphttp.sub('', url)
+ m = re_bitbucket_web.match(url)
+ if m:
+ return 'bitbucket.org/'+m.group(1)+'/'+m.group(2)
+ m = re_github_web.match(url)
+ if m:
+ return 'github.com/'+m.group(1)+'/'+m.group(2)
+ m = re_googlecode_web.match(url)
+ if m:
+ path = m.group(1)+'.googlecode.com/'
+ # perform http request to path/hg to check if they're using mercurial
+ vcs = 'svn'
+ try:
+ response = urlfetch.fetch('http://'+path+'hg', deadline=1)
+ if response.status_code == 200:
+ vcs = 'hg'
+ except: pass
+ return path + vcs
+ return False
+
MaxPathLength = 100
+CacheTimeout = 3600
class PackagePage(webapp.RequestHandler):
def get(self):
if self.request.get('fmt') == 'json':
return self.json()
- q = Package.all()
- q.order('-last_install')
- by_time = q.fetch(100)
+ html = memcache.get('view-package')
+ if not html:
+ q = Package.all()
+ q.order('-last_install')
+ by_time = q.fetch(100)
- q = Package.all()
- q.order('-count')
- by_count = q.fetch(100)
+ q = Package.all()
+ q.order('-count')
+ by_count = q.fetch(100)
- self.response.headers['Content-Type'] = 'text/html; charset=utf-8'
- path = os.path.join(os.path.dirname(__file__), 'package.html')
- self.response.out.write(template.render(path, {"by_time": by_time, "by_count": by_count}))
+ self.response.headers['Content-Type'] = 'text/html; charset=utf-8'
+ path = os.path.join(os.path.dirname(__file__), 'package.html')
+ html = template.render(
+ path,
+ {"by_time": by_time, "by_count": by_count}
+ )
+ memcache.set('view-package', html, time=CacheTimeout)
+
+ self.response.out.write(html)
def json(self):
- self.response.set_status(200)
- self.response.headers['Content-Type'] = 'text/plain; charset=utf-8'
- q = Package.all()
- s = '{"packages": ['
- sep = ''
- for r in q.fetch(1000):
- s += '%s\n\t{"path": "%s", "last_install": "%s", "count": "%s"}' % (sep, r.path, r.last_install, r.count)
- sep = ','
- s += '\n]}\n'
- self.response.out.write(s)
+ json = memcache.get('view-package-json')
+ if not json:
+ self.response.set_status(200)
+ self.response.headers['Content-Type'] = 'text/plain; charset=utf-8'
+ q = Package.all()
+ s = '{"packages": ['
+ sep = ''
+ for r in q.fetch(1000):
+ s += '%s\n\t{"path": "%s", "last_install": "%s", "count": "%s"}' % (sep, r.path, r.last_install, r.count)
+ sep = ','
+ s += '\n]}\n'
+ json = s
+ memcache.set('view-package-json', json, time=CacheTimeoout)
+ self.response.out.write(json)
def can_get_url(self, url):
try:
@@ -104,18 +165,8 @@ class PackagePage(webapp.RequestHandler):
p = Package.get_by_key_name(key)
if p is None:
# not in datastore - verify URL before creating
- if re_bitbucket.match(path):
- check_url = 'http://' + path + '/?cmd=heads'
- web = 'http://' + path + '/'
- elif re_github.match(path):
- # github doesn't let you fetch the .git directory anymore.
- # fetch .git/info/refs instead, like git clone would.
- check_url = 'http://'+path+'.git/info/refs'
- web = 'http://' + path
- elif re_googlecode.match(path):
- check_url = 'http://'+path
- web = 'http://code.google.com/p/' + path[:path.index('.')]
- else:
+ web, check_url = vc_to_web(path)
+ if not web:
logging.error('unrecognized path: %s', path)
return False
if not self.can_get_url(check_url):
@@ -150,9 +201,27 @@ class ProjectPage(webapp.RequestHandler):
self.redirect(users.create_logout_url("/project"))
elif self.request.path == "/project/edit" and admin:
self.edit()
+ elif self.request.path == "/project/assoc" and admin:
+ self.assoc()
else:
self.list()
+ def assoc(self):
+ projects = Project.all()
+ for p in projects:
+ if p.package:
+ continue
+ path = web_to_vc(p.web_url)
+ if not path:
+ continue
+ pkg = Package.get_by_key_name("pkg-"+path)
+ if not pkg:
+ self.response.out.write('no: %s %s<br>' % (p.web_url, path))
+ continue
+ p.package = pkg
+ p.put()
+ self.response.out.write('yes: %s %s<br>' % (p.web_url, path))
+
def post(self):
if self.request.path == "/project/edit":
self.edit(True)
@@ -177,30 +246,40 @@ class ProjectPage(webapp.RequestHandler):
self.list({"submitMsg": "Your project has been submitted."})
- def list(self, data={}):
- projects = Project.all().order('category').order('name')
-
- admin = users.is_current_user_admin()
- if not admin:
- projects = projects.filter('approved =', True)
-
- projects = list(projects)
-
- tags = sets.Set()
- for p in projects:
- for t in p.tags:
- tags.add(t)
-
- tag = self.request.get("tag", None)
+ def list(self, additional_data={}):
+ cache_key = 'view-project-data'
+ tag = self.request.get('tag', None)
if tag:
- projects = filter(lambda x: tag in x.tags, projects)
+ cache_key += '-'+tag
+ data = memcache.get(cache_key)
+ admin = users.is_current_user_admin()
+ if admin or not data:
+ projects = Project.all().order('category').order('name')
+ if not admin:
+ projects = projects.filter('approved =', True)
+ projects = list(projects)
+
+ tags = sets.Set()
+ for p in projects:
+ for t in p.tags:
+ tags.add(t)
+
+ if tag:
+ projects = filter(lambda x: tag in x.tags, projects)
+
+ data = {}
+ data['tag'] = tag
+ data['tags'] = tags
+ data['projects'] = projects
+ data['admin']= admin
+ if not admin:
+ memcache.set(cache_key, data, time=CacheTimeout)
+
+ for k, v in additional_data.items():
+ data[k] = v
self.response.headers['Content-Type'] = 'text/html; charset=utf-8'
path = os.path.join(os.path.dirname(__file__), 'project.html')
- data["tag"] = tag
- data["tags"] = tags
- data["projects"] = projects
- data["admin"] = admin
self.response.out.write(template.render(path, data))
def edit(self, save=False):
@@ -228,7 +307,8 @@ class ProjectPage(webapp.RequestHandler):
p.approved = self.request.get("approved") == "1"
p.tags = filter(lambda x: x, self.request.get("tags", "").split(","))
p.put()
- self.redirect("/project")
+ memcache.delete('view-project-data')
+ self.redirect('/project')
return
# get all project categories and tags
diff --git a/misc/dashboard/godashboard/project-edit.html b/misc/dashboard/godashboard/project-edit.html
index 5f1ca3b11..ce18fb3fb 100644
--- a/misc/dashboard/godashboard/project-edit.html
+++ b/misc/dashboard/godashboard/project-edit.html
@@ -1,11 +1,11 @@
<html>
<head>
+<link href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/base/jquery-ui.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="http://www.google.com/jsapi"></script>
<script>
google.load("jquery", "1");
+google.load("jqueryui", "1.8.2");
</script>
-<script type="text/javascript" src="/static/jquery.autocomplete.min.js"></script>
-<link rel="stylesheet" type="text/css" href="/static/jquery.autocomplete.css" />
</head>
<body>
<form action="/project/edit?orig_name={{p.name}}" method="POST">
@@ -38,8 +38,10 @@ var cats = [
{% endfor %}
];
-$('#tags').autocomplete(tags);
-$('#cats').autocomplete(cats);
+google.setOnLoadCallback(function() {
+ $('#tags').autocomplete({source:tags});
+ $('#cats').autocomplete({source:cats});
+});
</script>
</body>
</html>
diff --git a/misc/dashboard/godashboard/project-notify.txt b/misc/dashboard/godashboard/project-notify.txt
index 3a165908c..f55bf6421 100644
--- a/misc/dashboard/godashboard/project-notify.txt
+++ b/misc/dashboard/godashboard/project-notify.txt
@@ -5,5 +5,5 @@ Description: {{project.descr}}
URL: {{project.web_url}}
To edit/approve/delete:
-http://godashboard.appspot.com/project/edit?name={{project.name|urlencode}}
+http://godashboard.appspot.com/project/edit?name={{project.name|toutf8|urlencode}}
diff --git a/misc/dashboard/godashboard/toutf8.py b/misc/dashboard/godashboard/toutf8.py
new file mode 100644
index 000000000..544c681b6
--- /dev/null
+++ b/misc/dashboard/godashboard/toutf8.py
@@ -0,0 +1,14 @@
+# Copyright 2010 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+# This is a Django custom template filter to work around the
+# fact that GAE's urlencode filter doesn't handle unicode strings.
+
+from google.appengine.ext import webapp
+
+register = webapp.template.create_template_register()
+
+@register.filter
+def toutf8(value):
+ return value.encode("utf-8")
diff --git a/misc/dashboard/googlecode_upload.py b/misc/dashboard/googlecode_upload.py
new file mode 100755
index 000000000..3b1d432ff
--- /dev/null
+++ b/misc/dashboard/googlecode_upload.py
@@ -0,0 +1,248 @@
+#!/usr/bin/env python2
+#
+# Copyright 2006, 2007 Google Inc. All Rights Reserved.
+# Author: danderson@google.com (David Anderson)
+#
+# Script for uploading files to a Google Code project.
+#
+# This is intended to be both a useful script for people who want to
+# streamline project uploads and a reference implementation for
+# uploading files to Google Code projects.
+#
+# To upload a file to Google Code, you need to provide a path to the
+# file on your local machine, a small summary of what the file is, a
+# project name, and a valid account that is a member or owner of that
+# project. You can optionally provide a list of labels that apply to
+# the file. The file will be uploaded under the same name that it has
+# in your local filesystem (that is, the "basename" or last path
+# component). Run the script with '--help' to get the exact syntax
+# and available options.
+#
+# Note that the upload script requests that you enter your
+# googlecode.com password. This is NOT your Gmail account password!
+# This is the password you use on googlecode.com for committing to
+# Subversion and uploading files. You can find your password by going
+# to http://code.google.com/hosting/settings when logged in with your
+# Gmail account. If you have already committed to your project's
+# Subversion repository, the script will automatically retrieve your
+# credentials from there (unless disabled, see the output of '--help'
+# for details).
+#
+# If you are looking at this script as a reference for implementing
+# your own Google Code file uploader, then you should take a look at
+# the upload() function, which is the meat of the uploader. You
+# basically need to build a multipart/form-data POST request with the
+# right fields and send it to https://PROJECT.googlecode.com/files .
+# Authenticate the request using HTTP Basic authentication, as is
+# shown below.
+#
+# Licensed under the terms of the Apache Software License 2.0:
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Questions, comments, feature requests and patches are most welcome.
+# Please direct all of these to the Google Code users group:
+# http://groups.google.com/group/google-code-hosting
+
+"""Google Code file uploader script.
+"""
+
+__author__ = 'danderson@google.com (David Anderson)'
+
+import httplib
+import os.path
+import optparse
+import getpass
+import base64
+import sys
+
+
+def upload(file, project_name, user_name, password, summary, labels=None):
+ """Upload a file to a Google Code project's file server.
+
+ Args:
+ file: The local path to the file.
+ project_name: The name of your project on Google Code.
+ user_name: Your Google account name.
+ password: The googlecode.com password for your account.
+ Note that this is NOT your global Google Account password!
+ summary: A small description for the file.
+ labels: an optional list of label strings with which to tag the file.
+
+ Returns: a tuple:
+ http_status: 201 if the upload succeeded, something else if an
+ error occured.
+ http_reason: The human-readable string associated with http_status
+ file_url: If the upload succeeded, the URL of the file on Google
+ Code, None otherwise.
+ """
+ # The login is the user part of user@gmail.com. If the login provided
+ # is in the full user@domain form, strip it down.
+ if user_name.endswith('@gmail.com'):
+ user_name = user_name[:user_name.index('@gmail.com')]
+
+ form_fields = [('summary', summary)]
+ if labels is not None:
+ form_fields.extend([('label', l.strip()) for l in labels])
+
+ content_type, body = encode_upload_request(form_fields, file)
+
+ upload_host = '%s.googlecode.com' % project_name
+ upload_uri = '/files'
+ auth_token = base64.b64encode('%s:%s'% (user_name, password))
+ headers = {
+ 'Authorization': 'Basic %s' % auth_token,
+ 'User-Agent': 'Googlecode.com uploader v0.9.4',
+ 'Content-Type': content_type,
+ }
+
+ server = httplib.HTTPSConnection(upload_host)
+ server.request('POST', upload_uri, body, headers)
+ resp = server.getresponse()
+ server.close()
+
+ if resp.status == 201:
+ location = resp.getheader('Location', None)
+ else:
+ location = None
+ return resp.status, resp.reason, location
+
+
+def encode_upload_request(fields, file_path):
+ """Encode the given fields and file into a multipart form body.
+
+ fields is a sequence of (name, value) pairs. file is the path of
+ the file to upload. The file will be uploaded to Google Code with
+ the same file name.
+
+ Returns: (content_type, body) ready for httplib.HTTP instance
+ """
+ BOUNDARY = '----------Googlecode_boundary_reindeer_flotilla'
+ CRLF = '\r\n'
+
+ body = []
+
+ # Add the metadata about the upload first
+ for key, value in fields:
+ body.extend(
+ ['--' + BOUNDARY,
+ 'Content-Disposition: form-data; name="%s"' % key,
+ '',
+ value,
+ ])
+
+ # Now add the file itself
+ file_name = os.path.basename(file_path)
+ f = open(file_path, 'rb')
+ file_content = f.read()
+ f.close()
+
+ body.extend(
+ ['--' + BOUNDARY,
+ 'Content-Disposition: form-data; name="filename"; filename="%s"'
+ % file_name,
+ # The upload server determines the mime-type, no need to set it.
+ 'Content-Type: application/octet-stream',
+ '',
+ file_content,
+ ])
+
+ # Finalize the form body
+ body.extend(['--' + BOUNDARY + '--', ''])
+
+ return 'multipart/form-data; boundary=%s' % BOUNDARY, CRLF.join(body)
+
+
+def upload_find_auth(file_path, project_name, summary, labels=None,
+ user_name=None, password=None, tries=3):
+ """Find credentials and upload a file to a Google Code project's file server.
+
+ file_path, project_name, summary, and labels are passed as-is to upload.
+
+ Args:
+ file_path: The local path to the file.
+ project_name: The name of your project on Google Code.
+ summary: A small description for the file.
+ labels: an optional list of label strings with which to tag the file.
+ config_dir: Path to Subversion configuration directory, 'none', or None.
+ user_name: Your Google account name.
+ tries: How many attempts to make.
+ """
+
+ while tries > 0:
+ if user_name is None:
+ # Read username if not specified or loaded from svn config, or on
+ # subsequent tries.
+ sys.stdout.write('Please enter your googlecode.com username: ')
+ sys.stdout.flush()
+ user_name = sys.stdin.readline().rstrip()
+ if password is None:
+ # Read password if not loaded from svn config, or on subsequent tries.
+ print 'Please enter your googlecode.com password.'
+ print '** Note that this is NOT your Gmail account password! **'
+ print 'It is the password you use to access Subversion repositories,'
+ print 'and can be found here: http://code.google.com/hosting/settings'
+ password = getpass.getpass()
+
+ status, reason, url = upload(file_path, project_name, user_name, password,
+ summary, labels)
+ # Returns 403 Forbidden instead of 401 Unauthorized for bad
+ # credentials as of 2007-07-17.
+ if status in [httplib.FORBIDDEN, httplib.UNAUTHORIZED]:
+ # Rest for another try.
+ user_name = password = None
+ tries = tries - 1
+ else:
+ # We're done.
+ break
+
+ return status, reason, url
+
+
+def main():
+ parser = optparse.OptionParser(usage='googlecode-upload.py -s SUMMARY '
+ '-p PROJECT [options] FILE')
+ parser.add_option('-s', '--summary', dest='summary',
+ help='Short description of the file')
+ parser.add_option('-p', '--project', dest='project',
+ help='Google Code project name')
+ parser.add_option('-u', '--user', dest='user',
+ help='Your Google Code username')
+ parser.add_option('-w', '--password', dest='password',
+ help='Your Google Code password')
+ parser.add_option('-l', '--labels', dest='labels',
+ help='An optional list of comma-separated labels to attach '
+ 'to the file')
+
+ options, args = parser.parse_args()
+
+ if not options.summary:
+ parser.error('File summary is missing.')
+ elif not options.project:
+ parser.error('Project name is missing.')
+ elif len(args) < 1:
+ parser.error('File to upload not provided.')
+ elif len(args) > 1:
+ parser.error('Only one file may be specified.')
+
+ file_path = args[0]
+
+ if options.labels:
+ labels = options.labels.split(',')
+ else:
+ labels = None
+
+ status, reason, url = upload_find_auth(file_path, options.project,
+ options.summary, labels,
+ options.user, options.password)
+ if url:
+ print 'The file was uploaded successfully.'
+ print 'URL: %s' % url
+ return 0
+ else:
+ print 'An error occurred. Your file was not uploaded.'
+ print 'Google Code upload server said: %s (%s)' % (reason, status)
+ return 1
+
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/misc/emacs/go-mode.el b/misc/emacs/go-mode.el
index e27ee7438..2624e87cb 100644
--- a/misc/emacs/go-mode.el
+++ b/misc/emacs/go-mode.el
@@ -27,8 +27,8 @@
(defvar go-mode-syntax-table
(let ((st (make-syntax-table)))
- ;; Symbols
- (modify-syntax-entry ?_ "_" st)
+ ;; Add _ to :word: character class
+ (modify-syntax-entry ?_ "w" st)
;; Operators (punctuation)
(modify-syntax-entry ?+ "." st)
@@ -92,7 +92,7 @@ some syntax analysis.")
;; Map key type
(,(concat "\\<map\\s *\\[" type-name) 1 font-lock-type-face)
;; Channel value type
- (,(concat "\\<chan\\s *\\(?:<-\\)?" type-name) 1 font-lock-type-face)
+ (,(concat "\\<chan\\>\\s *\\(?:<-\\)?" type-name) 1 font-lock-type-face)
;; new/make type
(,(concat "\\<\\(?:new\\|make\\)\\>\\(?:\\s \\|)\\)*(" type-name) 1 font-lock-type-face)
;; Type conversion
diff --git a/misc/fraise/go.plist b/misc/fraise/go.plist
new file mode 100644
index 000000000..298361501
--- /dev/null
+++ b/misc/fraise/go.plist
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>beginCommand</key>
+ <string></string>
+ <key>endCommand</key>
+ <string></string>
+ <key>beginInstruction</key>
+ <string></string>
+ <key>endInstruction</key>
+ <string></string>
+ <key>beginVariable</key>
+ <string></string>
+ <key>endVariable</key>
+ <string></string>
+ <key>firstString</key>
+ <string>&quot;</string>
+ <key>secondString</key>
+ <string>&apos;</string>
+ <key>firstSingleLineComment</key>
+ <string>//</string>
+ <key>secondSingleLineComment</key>
+ <string></string>
+ <key>beginFirstMultiLineComment</key>
+ <string>/*</string>
+ <key>endFirstMultiLineComment</key>
+ <string>*/</string>
+ <key>beginSecondMultiLineComment</key>
+ <string></string>
+ <key>endSecondMultiLineComment</key>
+ <string></string>
+ <key>functionDefinition</key>
+ <string>^func\s*.*\(.*\)\s?\{</string>
+ <key>removeFromFunction</key>
+ <string></string>
+ <key>keywordsCaseSensitive</key>
+ <true/>
+ <key>recolourKeywordIfAlreadyColoured</key>
+ <true/>
+ <key>keywords</key>
+ <array>
+ <string>break</string>
+ <string>case</string>
+ <string>chan</string>
+ <string>const</string>
+ <string>continue</string>
+ <string>default</string>
+ <string>defer</string>
+ <string>else</string>
+ <string>fallthrough</string>
+ <string>for</string>
+ <string>func</string>
+ <string>go</string>
+ <string>goto</string>
+ <string>if</string>
+ <string>import</string>
+ <string>interface</string>
+ <string>map</string>
+ <string>package</string>
+ <string>range</string>
+ <string>return</string>
+ <string>select</string>
+ <string>struct</string>
+ <string>switch</string>
+ <string>type</string>
+ <string>var</string>
+ <string>bool</string>
+ <string>byte</string>
+ <string>chan</string>
+ <string>complex64</string>
+ <string>complex128</string>
+ <string>float</string>
+ <string>float32</string>
+ <string>float64</string>
+ <string>int</string>
+ <string>int8</string>
+ <string>int16</string>
+ <string>int32</string>
+ <string>int64</string>
+ <string>map</string>
+ <string>string</string>
+ <string>uint</string>
+ <string>uintptr</string>
+ <string>uint8</string>
+ <string>uint16</string>
+ <string>uint32</string>
+ <string>uint64</string>
+ </array>
+ <key>autocompleteWords</key>
+ <array/>
+</dict>
+</plist>
diff --git a/misc/fraise/readme.txt b/misc/fraise/readme.txt
new file mode 100644
index 000000000..fb0f2c8c1
--- /dev/null
+++ b/misc/fraise/readme.txt
@@ -0,0 +1,16 @@
+##Instructions for enabling Go syntax highlighting in Fraise.app##
+1. Move go.plist to /Applications/Fraise.app/Contents/Resources/Syntax\ Definitions/
+2. Open /Applications/Fraise.app/Contents/Resources/SyntaxDefinitions.plist and add
+
+ <dict>
+ <key>name</key>
+ <string>GoogleGo</string>
+ <key>file</key>
+ <string>go</string>
+ <key>extensions</key>
+ <string>go</string>
+ </dict>
+
+before </array>
+
+3. Restart Fraise and you're good to Go! \ No newline at end of file
diff --git a/misc/goplay/Makefile b/misc/goplay/Makefile
new file mode 100644
index 000000000..28d024511
--- /dev/null
+++ b/misc/goplay/Makefile
@@ -0,0 +1,13 @@
+# Copyright 2010 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../src/Make.inc
+
+TARG=goplay
+
+GOFILES=\
+ goplay.go\
+
+include ../../src/Make.cmd
+
diff --git a/misc/goplay/README b/misc/goplay/README
new file mode 100644
index 000000000..e8a1d290f
--- /dev/null
+++ b/misc/goplay/README
@@ -0,0 +1 @@
+See doc.go.
diff --git a/misc/goplay/doc.go b/misc/goplay/doc.go
new file mode 100644
index 000000000..9685551bd
--- /dev/null
+++ b/misc/goplay/doc.go
@@ -0,0 +1,25 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Goplay is a web interface for experimenting with Go code.
+// It is similar to the Go Playground: http://golang.org/doc/play/
+//
+// To use goplay, first build and install it:
+// $ cd $GOROOT/misc/goplay
+// $ gomake install
+// Then, run it:
+// $ goplay
+// and load http://localhost:3999/ in a web browser.
+//
+// You should see a Hello World program, which you can compile and run by
+// pressing shift-enter. There is also a "compile-on-keypress" feature that can
+// be enabled by checking a checkbox.
+//
+// WARNING! CUIDADO! ACHTUNG! ATTENZIONE!
+// A note on security: anyone with access to the goplay web interface can run
+// arbitrary code on your computer. Goplay is not a sandbox, and has no other
+// security mechanisms. Do not deploy it in untrusted environments.
+// By default, goplay listens only on localhost. This can be overridden with
+// the -http parameter. Do so at your own risk.
+package documentation
diff --git a/misc/goplay/goplay.go b/misc/goplay/goplay.go
new file mode 100644
index 000000000..5923360f6
--- /dev/null
+++ b/misc/goplay/goplay.go
@@ -0,0 +1,314 @@
+// Copyright 2010 The Go Authors. 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"
+ "http"
+ "io"
+ "io/ioutil"
+ "log"
+ "os"
+ "runtime"
+ "strconv"
+ "template"
+)
+
+var (
+ httpListen = flag.String("http", "127.0.0.1:3999", "host:port to listen on")
+ htmlOutput = flag.Bool("html", false, "render program output as HTML")
+)
+
+var (
+ // a source of numbers, for naming temporary files
+ uniq = make(chan int)
+ // the architecture-identifying character of the tool chain, 5, 6, or 8
+ archChar string
+)
+
+func main() {
+ flag.Parse()
+
+ // set archChar
+ switch runtime.GOARCH {
+ case "arm":
+ archChar = "5"
+ case "amd64":
+ archChar = "6"
+ case "386":
+ archChar = "8"
+ default:
+ log.Exitln("unrecognized GOARCH:", runtime.GOARCH)
+ }
+
+ // source of unique numbers
+ go func() {
+ for i := 0; ; i++ {
+ uniq <- i
+ }
+ }()
+
+ http.HandleFunc("/", FrontPage)
+ http.HandleFunc("/compile", Compile)
+ log.Exit(http.ListenAndServe(*httpListen, nil))
+}
+
+// FrontPage is an HTTP handler that renders the goplay interface.
+// If a filename is supplied in the path component of the URI,
+// its contents will be put in the interface's text area.
+// Otherwise, the default "hello, world" program is displayed.
+func FrontPage(w http.ResponseWriter, req *http.Request) {
+ data, err := ioutil.ReadFile(req.URL.Path[1:])
+ if err != nil {
+ data = helloWorld
+ }
+ frontPage.Execute(data, w)
+}
+
+// Compile is an HTTP handler that reads Go source code from the request,
+// compiles and links the code (returning any errors), runs the program,
+// and sends the program's output as the HTTP response.
+func Compile(w http.ResponseWriter, req *http.Request) {
+ // x is the base name for .go, .6, executable files
+ x := os.TempDir() + "/compile" + strconv.Itoa(<-uniq)
+ src := x + ".go"
+ obj := x + "." + archChar
+ bin := x
+ if runtime.GOOS == "windows" {
+ bin += ".exe"
+ }
+
+ // write request Body to x.go
+ f, err := os.Open(src, os.O_CREAT|os.O_WRONLY|os.O_TRUNC, 0666)
+ if err != nil {
+ error(w, nil, err)
+ return
+ }
+ defer os.Remove(src)
+ defer f.Close()
+ _, err = io.Copy(f, req.Body)
+ if err != nil {
+ error(w, nil, err)
+ return
+ }
+ f.Close()
+
+ // build x.go, creating x.6
+ out, err := run(archChar+"g", "-o", obj, src)
+ defer os.Remove(obj)
+ if err != nil {
+ error(w, out, err)
+ return
+ }
+
+ // link x.6, creating x (the program binary)
+ out, err = run(archChar+"l", "-o", bin, obj)
+ defer os.Remove(bin)
+ if err != nil {
+ error(w, out, err)
+ return
+ }
+
+ // run x
+ out, err = run(bin)
+ if err != nil {
+ error(w, out, err)
+ }
+
+ // write the output of x as the http response
+ if *htmlOutput {
+ w.Write(out)
+ } else {
+ output.Execute(out, w)
+ }
+}
+
+// error writes compile, link, or runtime errors to the HTTP connection.
+// The JavaScript interface uses the 404 status code to identify the error.
+func error(w http.ResponseWriter, out []byte, err os.Error) {
+ w.WriteHeader(404)
+ if out != nil {
+ output.Execute(out, w)
+ } else {
+ output.Execute(err.String(), w)
+ }
+}
+
+// run executes the specified command and returns its output and an error.
+func run(cmd ...string) ([]byte, os.Error) {
+ // find the specified binary
+ bin, err := exec.LookPath(cmd[0])
+ if err != nil {
+ // report binary as well as the error
+ return nil, os.NewError(cmd[0] + ": " + err.String())
+ }
+
+ // run the binary and read its combined stdout and stderr into a buffer
+ p, err := exec.Run(bin, cmd, os.Environ(), "", exec.DevNull, exec.Pipe, exec.MergeWithStdout)
+ if err != nil {
+ return nil, err
+ }
+ var buf bytes.Buffer
+ io.Copy(&buf, p.Stdout)
+ w, err := p.Wait(0)
+ p.Close()
+ if err != nil {
+ return nil, err
+ }
+
+ // set the error return value if the program had a non-zero exit status
+ if !w.Exited() || w.ExitStatus() != 0 {
+ err = os.ErrorString("running " + cmd[0] + ": " + w.String())
+ }
+
+ return buf.Bytes(), err
+}
+
+var frontPage, output *template.Template // HTML templates
+
+func init() {
+ frontPage = template.New(nil)
+ frontPage.SetDelims("«", "»")
+ if err := frontPage.Parse(frontPageText); err != nil {
+ panic(err)
+ }
+ output = template.MustParse(outputText, nil)
+}
+
+var outputText = `<pre>{@|html}</pre>`
+
+var frontPageText = `<!doctype html>
+<html>
+<head>
+<style>
+pre, textarea {
+ font-family: Monaco, 'Courier New', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
+ font-size: 100%;
+}
+.hints {
+ font-size: 0.8em;
+ text-align: right;
+}
+#edit, #output, #errors { width: 100%; text-align: left; }
+#edit { height: 500px; }
+#output { color: #00c; }
+#errors { color: #c00; }
+</style>
+<script>
+
+function insertTabs(n) {
+ // find the selection start and end
+ var cont = document.getElementById("edit");
+ var start = cont.selectionStart;
+ var end = cont.selectionEnd;
+ // split the textarea content into two, and insert n tabs
+ var v = cont.value;
+ var u = v.substr(0, start);
+ for (var i=0; i<n; i++) {
+ u += "\t";
+ }
+ u += v.substr(end);
+ // set revised content
+ cont.value = u;
+ // reset caret position after inserted tabs
+ cont.selectionStart = start+n;
+ cont.selectionEnd = start+n;
+}
+
+function autoindent(el) {
+ var curpos = el.selectionStart;
+ var tabs = 0;
+ while (curpos > 0) {
+ curpos--;
+ if (el.value[curpos] == "\t") {
+ tabs++;
+ } else if (tabs > 0 || el.value[curpos] == "\n") {
+ break;
+ }
+ }
+ setTimeout(function() {
+ insertTabs(tabs);
+ }, 1);
+}
+
+function keyHandler() {
+ var e = window.event;
+ if (e.keyCode == 9) { // tab
+ insertTabs(1);
+ e.preventDefault();
+ return false;
+ }
+ if (e.keyCode == 13) { // enter
+ if (e.shiftKey) { // +shift
+ compile(e.target);
+ e.preventDefault();
+ return false;
+ } else {
+ autoindent(e.target);
+ }
+ }
+ return true;
+}
+
+var xmlreq;
+
+function autocompile() {
+ if(!document.getElementById("autocompile").checked) {
+ return;
+ }
+ compile();
+}
+
+function compile() {
+ var prog = document.getElementById("edit").value;
+ var req = new XMLHttpRequest();
+ xmlreq = req;
+ req.onreadystatechange = compileUpdate;
+ req.open("POST", "/compile", true);
+ req.setRequestHeader("Content-Type", "text/plain; charset=utf-8");
+ req.send(prog);
+}
+
+function compileUpdate() {
+ var req = xmlreq;
+ if(!req || req.readyState != 4) {
+ return;
+ }
+ if(req.status == 200) {
+ document.getElementById("output").innerHTML = req.responseText;
+ document.getElementById("errors").innerHTML = "";
+ } else {
+ document.getElementById("errors").innerHTML = req.responseText;
+ document.getElementById("output").innerHTML = "";
+ }
+}
+</script>
+</head>
+<body>
+<table width="100%"><tr><td width="60%" valign="top">
+<textarea autofocus="true" id="edit" spellcheck="false" onkeydown="keyHandler();" onkeyup="autocompile();">«@|html»</textarea>
+<div class="hints">
+(Shift-Enter to compile and run.)&nbsp;&nbsp;&nbsp;&nbsp;
+<input type="checkbox" id="autocompile" value="checked" /> Compile and run after each keystroke
+</div>
+<td width="3%">
+<td width="27%" align="right" valign="top">
+<div id="output"></div>
+</table>
+<div id="errors"></div>
+</body>
+</html>
+`
+
+var helloWorld = []byte(`package main
+
+import "fmt"
+
+func main() {
+ fmt.Println("hello, world")
+}
+`)
diff --git a/misc/kate/go.xml b/misc/kate/go.xml
index e8728fd84..3a5c39c94 100644
--- a/misc/kate/go.xml
+++ b/misc/kate/go.xml
@@ -42,6 +42,7 @@
<item> bool </item>
<item> byte </item>
<item> chan </item>
+ <item> complex </item>
<item> complex64 </item>
<item> complex128 </item>
<item> float </item>
@@ -62,6 +63,7 @@
<item> uint64 </item>
</list>
<list name="functions">
+ <item> append </item>
<item> cap </item>
<item> close </item>
<item> closed </item>
diff --git a/misc/vim/syntax/go.vim b/misc/vim/syntax/go.vim
index 244503ca3..7adbe8e35 100644
--- a/misc/vim/syntax/go.vim
+++ b/misc/vim/syntax/go.vim
@@ -85,8 +85,8 @@ syn match goType /\<func\>/
syn match goDeclaration /^func\>/
" Predefined functions and values
-syn keyword goBuiltins cap close closed cmplx copy imag len make
-syn keyword goBuiltins new panic panicln print println real
+syn keyword goBuiltins append cap close closed cmplx copy imag len
+syn keyword goBuiltins make new panic print println real recover
syn keyword goConstants iota true false nil
hi def link goBuiltins Keyword
@@ -95,8 +95,8 @@ hi def link goConstants Keyword
" Comments; their contents
syn keyword goTodo contained TODO FIXME XXX BUG
syn cluster goCommentGroup contains=goTodo
-syn region goComment start="/\*" end="\*/" contains=@goCommentGroup
-syn region goComment start="//" end="$" contains=@goCommentGroup
+syn region goComment start="/\*" end="\*/" contains=@goCommentGroup,@Spell
+syn region goComment start="//" end="$" contains=@goCommentGroup,@Spell
hi def link goComment Comment
hi def link goTodo Todo
@@ -136,7 +136,7 @@ syn region goBlock start="{" end="}" transparent fold
syn region goParen start='(' end=')' transparent
" Integers
-syn match goDecimalInt "\<\d\+\>"
+syn match goDecimalInt "\<\d\+\([Ee]\d\+\)\?\>"
syn match goHexadecimalInt "\<0x\x\+\>"
syn match goOctalInt "\<0\o\+\>"
syn match goOctalError "\<0\o*[89]\d*\>"
diff --git a/misc/zsh/go b/misc/zsh/go
new file mode 100644
index 000000000..f17763d93
--- /dev/null
+++ b/misc/zsh/go
@@ -0,0 +1,14 @@
+# install in /etc/zsh/zshrc or your personal .zshrc
+
+# gc
+prefixes=(5 6 8)
+for p in $prefixes; do
+ compctl -g "*.${p}" ${p}l
+ compctl -g "*.go" ${p}g
+done
+
+# standard go tools
+compctl -g "*.go" gofmt
+
+# gccgo
+compctl -g "*.go" gccgo
diff --git a/pkg/~place-holder~ b/pkg/~place-holder~
deleted file mode 100644
index 0ea2de6ea..000000000
--- a/pkg/~place-holder~
+++ /dev/null
@@ -1,4 +0,0 @@
-Package binaries are installed in this directory tree.
-
-Mercurial does not maintain empty directories.
-This file helps.
diff --git a/src/Make.386 b/src/Make.386
deleted file mode 100644
index 9560cd0fd..000000000
--- a/src/Make.386
+++ /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.
-
-O=8
-AS=${O}a
-CC=${O}c
-GC=${O}g
-LD=${O}l
-OS=568vq
-CFLAGS=-FVw
diff --git a/src/Make.amd64 b/src/Make.amd64
deleted file mode 100644
index 20585c4a8..000000000
--- a/src/Make.amd64
+++ /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.
-
-O=6
-AS=${O}a
-CC=${O}c
-GC=${O}g
-LD=${O}l
-OS=568vq
-CFLAGS=-FVw
diff --git a/src/Make.arm b/src/Make.arm
deleted file mode 100644
index 9acef0755..000000000
--- a/src/Make.arm
+++ /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.
-
-O=5
-AS=${O}a
-CC=${O}c
-GC=${O}g
-LD=${O}l
-OS=568vq
-CFLAGS=-FVw
diff --git a/src/Make.ccmd b/src/Make.ccmd
new file mode 100644
index 000000000..cb2b25512
--- /dev/null
+++ b/src/Make.ccmd
@@ -0,0 +1,44 @@
+# Copyright 2010 The Go 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) -lbio -l9 -lm $(HOST_LDFLAGS)
+
+$(OFILES): $(HFILES)
+
+CLEANFILES+=y.tab.[ch]
+
+clean:
+ rm -f *.$(HOST_O) $(TARG) $(CLEANFILES)
+
+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)
+
+%.$(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
new file mode 100644
index 000000000..ebe4f84b9
--- /dev/null
+++ b/src/Make.clib
@@ -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.
+
+# Makefile included for C libraries
+
+all: $(LIB)
+
+%.$(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)
+
+
+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
index b2a184b82..34f5663bc 100644
--- a/src/Make.cmd
+++ b/src/Make.cmd
@@ -2,22 +2,21 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-all: $(TARG)
+ifeq ($(GOOS),windows)
+TARG:=$(TARG).exe
+endif
-# ugly hack to deal with whitespaces in $GOROOT
-nullstring :=
-space := $(nullstring) # a space at the end
-QUOTED_GOROOT:=$(subst $(space),\ ,$(GOROOT))
+all: $(TARG)
include $(QUOTED_GOROOT)/src/Make.common
PREREQ+=$(patsubst %,%.make,$(DEPS))
-$(TARG): _go_.$O $(OFILES)
- $(QUOTED_GOBIN)/$(LD) -o $@ _go_.$O $(OFILES)
+$(TARG): _go_.$O
+ $(LD) -o $@ _go_.$O
_go_.$O: $(GOFILES) $(PREREQ)
- $(QUOTED_GOBIN)/$(GC) -o $@ $(GOFILES)
+ $(GC) -o $@ $(GOFILES)
install: $(QUOTED_GOBIN)/$(TARG)
diff --git a/src/Make.common b/src/Make.common
index 42bb64e84..e3f415a1f 100644
--- a/src/Make.common
+++ b/src/Make.common
@@ -2,25 +2,12 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-# GNU Make syntax:
-ifndef GOBIN
-GOBIN=$(HOME)/bin
-endif
-
-# ugly hack to deal with whitespaces in $GOBIN
-nullstring :=
-space := $(nullstring) # a space at the end
-ifndef GOBIN
-QUOTED_HOME=$(subst $(space),\ ,$(HOME))
-GOBIN=$(QUOTED_HOME)/bin
-endif
-QUOTED_GOBIN=$(subst $(space),\ ,$(GOBIN))
-
-# ugly hack to deal with whitespaces in $GOROOT
-QUOTED_GOROOT:=$(subst $(space),\ ,$(GOROOT))
-
clean:
rm -rf *.o *.a *.[$(OS)] [$(OS)].out $(CLEANFILES)
%.make:
- (cd $* && $(QUOTED_GOBIN)/gomake install)
+ (cd $* && gomake install)
+
+.PHONY: all clean nuke install coverage test bench testpackage-clean\
+ importpath dir
+
diff --git a/src/Make.conf b/src/Make.conf
deleted file mode 100644
index fa7177aa8..000000000
--- a/src/Make.conf
+++ /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.
-
-CFLAGS=-ggdb -I"$(GOROOT)"/include -O2 -fno-inline
-O=o
-YFLAGS=-d
-# GNU Make syntax:
-nullstring :=
-space := $(nullstring) # a space at the end
-ifndef GOBIN
-QUOTED_HOME=$(subst $(space),\ ,$(HOME))
-GOBIN=$(QUOTED_HOME)/bin
-endif
-QUOTED_GOBIN=$(subst $(space),\ ,$(GOBIN))
-
-CC=$(QUOTED_GOBIN)/quietgcc
-LD=$(QUOTED_GOBIN)/quietgcc
-PWD=$(shell pwd)
-
-%.$O: %.c
- $(CC) $(CFLAGS) -c "$(PWD)"/$*.c
diff --git a/src/Make.inc b/src/Make.inc
new file mode 100644
index 000000000..2889c7edf
--- /dev/null
+++ b/src/Make.inc
@@ -0,0 +1,146 @@
+# Copyright 2009 The Go 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
+
+ifeq ($(GOOS),darwin)
+else ifeq ($(GOOS),freebsd)
+else ifeq ($(GOOS),linux)
+else ifeq ($(GOOS),tiny)
+else ifeq ($(GOOS),plan9)
+else ifeq ($(GOOS),windows)
+else
+$(error Invalid $$GOOS '$(GOOS)'; must be darwin, freebsd, linux, plan9, tiny, or windows)
+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 ($(GOARCH),386)
+O:=8
+else ifeq ($(GOARCH),amd64)
+O:=6
+else ifeq ($(GOARCH),arm)
+
+O:=5
+ifeq ($(GOOS),linux)
+else
+$(error Invalid $$GOOS '$(GOOS)' for GOARCH=arm; must be linux)
+endif
+
+else
+$(error Invalid $$GOARCH '$(GOARCH)'; must be 386, amd64, or arm)
+endif
+
+# Save for recursive make to avoid recomputing.
+export GOARCH GOOS GOHOSTARCH GOHOSTOS
+
+# 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)
+
+# 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 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
index 39c19611e..ec7d5722e 100644
--- a/src/Make.pkg
+++ b/src/Make.pkg
@@ -6,13 +6,18 @@ all: package
package: _obj/$(TARG).a
testpackage: _test/$(TARG).a
-# ugly hack to deal with whitespaces in $GOROOT
-nullstring :=
-space := $(nullstring) # a space at the end
-QUOTED_GOROOT:=$(subst $(space),\ ,$(GOROOT))
-
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))
@@ -31,27 +36,26 @@ INSTALLFILES+=$(pkgdir)/$(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
-CGOTARG=cgo_$(subst /,_,$(TARG))
-GOFILES+=$(patsubst %.go,%.cgo1.go,$(CGOFILES))
-GOFILES+=_cgo_gotypes.go
-OFILES+=_cgo_defun.$O
-GCC_OFILES=$(patsubst %.go,%.cgo2.o,$(CGOFILES))
-INSTALLFILES+=$(pkgdir)/$(CGOTARG).so
+GOFILES+=$(patsubst %.go,%.cgo1.go,$(CGOFILES)) _cgo_gotypes.go
+CGO_OFILES+=$(patsubst %.go,%.cgo2.o,$(CGOFILES)) _cgo_export.o
+OFILES+=_cgo_defun.$O _cgo_import.$O $(CGO_OFILES)
endif
PREREQ+=$(patsubst %,%.make,$(DEPS))
coverage:
- $(QUOTED_GOBIN)/gotest
- $(QUOTED_GOBIN)/6cov -g $(shell pwd) $O.out | grep -v '_test\.go:'
+ gotest
+ 6cov -g $(shell pwd) $O.out | grep -v '_test\.go:'
-CLEANFILES+=*.cgo1.go *.cgo2.c _cgo_defun.c _cgo_gotypes.go _cgo_export.* *.so _obj _test _testmain.go
+CLEANFILES+=*.cgo1.go *.cgo2.c _cgo_defun.c _cgo_gotypes.go _cgo_export.*
+CLEANFILES+=_cgo_.c _cgo_import.c _cgo_main.c
+CLEANFILES+=*.so _obj _test _testmain.go *.exe
test:
- $(QUOTED_GOBIN)/gotest
+ gotest
bench:
- $(QUOTED_GOBIN)/gotest -benchmarks=. -match="Do not run tests"
+ gotest -benchmarks=. -match="Do not run tests"
nuke: clean
rm -f $(pkgdir)/$(TARG).a
@@ -66,20 +70,20 @@ $(pkgdir)/$(TARG).a: _obj/$(TARG).a
cp _obj/$(TARG).a "$@"
_go_.$O: $(GOFILES) $(PREREQ)
- $(QUOTED_GOBIN)/$(GC) -o $@ $(GOFILES)
+ $(GC) -o $@ $(GOFILES)
_gotest_.$O: $(GOFILES) $(GOTESTFILES) $(PREREQ)
- $(QUOTED_GOBIN)/$(GC) -o $@ $(GOFILES) $(GOTESTFILES)
+ $(GC) -o $@ $(GOFILES) $(GOTESTFILES)
_obj/$(TARG).a: _go_.$O $(OFILES)
@mkdir -p _obj/$(dir)
rm -f _obj/$(TARG).a
- $(QUOTED_GOBIN)/gopack grc $@ _go_.$O $(OFILES)
+ gopack grc $@ _go_.$O $(OFILES)
_test/$(TARG).a: _gotest_.$O $(OFILES)
@mkdir -p _test/$(dir)
rm -f _test/$(TARG).a
- $(QUOTED_GOBIN)/gopack grc $@ _gotest_.$O $(OFILES)
+ gopack grc $@ _gotest_.$O $(OFILES)
importpath:
@echo $(TARG)
@@ -107,58 +111,66 @@ dir:
# x.cgo2.c - C implementations compiled with gcc to create a dynamic library
#
-_cgo_defun.c _cgo_gotypes.go _cgo_export.c _cgo_export.h: $(CGOFILES)
- CGOPKGPATH=$(dir) $(QUOTED_GOBIN)/cgo $(CGO_CFLAGS) $(CGOFILES)
+ifdef CGOFILES
+_cgo_defun.c: $(CGOFILES)
+ CGOPKGPATH=$(dir) cgo -- $(CGO_CFLAGS) $(CGOFILES)
-# Ugly but necessary
-%.cgo1.go: _cgo_defun.c _cgo_gotypes.go
+# Ugly but necessary - cgo writes these files too.
+_cgo_gotypes.go _cgo_export.c _cgo_export.h _cgo_main.c: _cgo_defun.c
@true
-%.cgo2.c: _cgo_defun.c _cgo_gotypes.go
+%.cgo1.go %.cgo2.c: _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) $*.c
-%.cgo2.o: %.cgo2.c
- gcc $(_CGO_CFLAGS_$(GOARCH)) -fPIC -O2 -o $@ -c $(CGO_CFLAGS) $*.cgo2.c
+# 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.
-_cgo_export.o: _cgo_export.c _cgo_export.h
- gcc $(_CGO_CFLAGS_$(GOARCH)) -fPIC -O2 -o $@ -c $(CGO_CFLAGS) _cgo_export.c
+_cgo_main.o: _cgo_main.c
+ $(HOST_CC) $(_CGO_CFLAGS_$(GOARCH)) -g -fPIC -O2 -o $@ -c $(CGO_CFLAGS) _cgo_main.c
+
+_cgo1_.o: _cgo_main.o $(CGO_OFILES)
+ $(HOST_CC) $(_CGO_CFLAGS_$(GOARCH)) -g -fPIC -O2 -o $@ $^ $(CGO_LDFLAGS)
+
+_cgo_import.c: _cgo1_.o
+ 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).
-RUNTIME_CFLAGS_amd64=-D_64BIT
-RUNTIME_CFLAGS=-I"$(GOROOT)/src/pkg/runtime" $(RUNTIME_CFLAGS_$(GOARCH))
-
# 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
-
-# Compile x.cgo4.c with gcc to make package_x.so.
+# 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: _cgo_defun.c
- $(QUOTED_GOBIN)/$(CC) $(CFLAGS) $(RUNTIME_CFLAGS) _cgo_defun.c
-
-_cgo_.so: $(GCC_OFILES) $(CGO_DEPS)
- gcc $(_CGO_CFLAGS_$(GOARCH)) -o $@ $(GCC_OFILES) $(CGO_LDFLAGS) $(_CGO_LDFLAGS_$(GOOS))
-
-$(pkgdir)/$(CGOTARG).so: _cgo_.so
- @test -d $(QUOTED_GOROOT)/pkg && mkdir -p $(pkgdir)/$(dir)
- cp _cgo_.so "$@"
+ $(CC) $(CFLAGS) $(RUNTIME_CFLAGS) _cgo_defun.c
# Generic build rules.
# These come last so that the rules above can override them
# for more specific file names.
%.$O: %.c
- $(QUOTED_GOBIN)/$(CC) $(CFLAGS) $*.c
+ $(CC) $(CFLAGS) $*.c
%.$O: %.s
- $(QUOTED_GOBIN)/$(AS) $*.s
+ $(AS) $*.s
%.$O: $(HFILES)
diff --git a/src/all-arm.bash b/src/all-arm.bash
deleted file mode 100755
index 73db3fb85..000000000
--- a/src/all-arm.bash
+++ /dev/null
@@ -1,30 +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.
-
-set -e
-
-export GOOS=linux
-export GOARCH=arm
-
-bash make.bash
-
-# TODO(kaib): add in proper tests
-#bash run.bash
-
-set -e
-
-xcd() {
- echo
- echo --- cd $1
- builtin cd $1
-}
-
-# temporarily turn GC off
-# TODO(kaib): reenable GC once everything else works
-export GOGC=off
-
-(xcd ../test
-./run-arm
-) || exit $?
diff --git a/src/all-nacl.bash b/src/all-nacl.bash
deleted file mode 100755
index 0238c2a3e..000000000
--- a/src/all-nacl.bash
+++ /dev/null
@@ -1,48 +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.
-
-# TODO(rsc): delete in favor of all.bash once nacl support is complete
-
-export GOARCH=386
-export GOOS=nacl
-export GORUN=${GORUN:-$GOROOT/misc/nacl/naclrun}
-
-set -e
-bash make.bash
-
-xcd() {
- echo
- echo --- cd $1
- builtin cd $1
-}
-
-(xcd pkg
-make install
-make test
-) || exit $?
-
-(xcd pkg/exp/nacl/srpc
-make clean
-make install
-) || exit $?
-
-(xcd pkg/exp/nacl/av
-make clean
-make install
-) || exit $?
-
-(xcd pkg/exp/4s
-make clean
-make
-) || exit $?
-
-(xcd pkg/exp/spacewar
-make clean
-make
-) || exit $?
-
-(xcd ../test
-./run
-) || exit $?
diff --git a/src/all.bash b/src/all.bash
index 00c1ca74d..00110d2da 100755
--- a/src/all.bash
+++ b/src/all.bash
@@ -4,5 +4,11 @@
# license that can be found in the LICENSE file.
set -e
-bash make.bash
-bash run.bash --no-rebuild
+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
+
diff --git a/src/clean.bash b/src/clean.bash
index 567e6e319..d96eb52df 100755
--- a/src/clean.bash
+++ b/src/clean.bash
@@ -5,16 +5,21 @@
set -e
-if [ -z "$GOROOT" ] ; then
- echo '$GOROOT not set'
+if [ ! -f env.bash ]; then
+ echo 'clean.bash must be run from $GOROOT/src' 1>&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
-GOBIN="${GOBIN:-$HOME/bin}"
-
-rm -rf "$GOROOT"/pkg/${GOOS}_$GOARCH
+if [ "$1" != "--nopkg" ]; then
+ rm -rf "$GOROOT"/pkg/${GOOS}_$GOARCH
+fi
rm -f "$GOROOT"/lib/*.a
-for i in lib9 libbio libcgo libmach cmd pkg \
+for i in lib9 libbio libmach cmd pkg \
../misc/cgo/gmp ../misc/cgo/stdio \
../test/bench ../test/garbage
do(
@@ -22,6 +27,6 @@ do(
if test -f clean.bash; then
bash clean.bash
else
- "$GOBIN"/gomake clean
+ gomake clean
fi
)done
diff --git a/src/cmd/5a/Makefile b/src/cmd/5a/Makefile
index f01b017da..f4463c97b 100644
--- a/src/cmd/5a/Makefile
+++ b/src/cmd/5a/Makefile
@@ -2,10 +2,10 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.conf
+include ../../Make.inc
+O:=$(HOST_O)
-TARG=\
- 5a\
+TARG=5a
HFILES=\
a.h\
@@ -15,26 +15,11 @@ HFILES=\
OFILES=\
y.tab.$O\
lex.$O\
-# ../5l/enam.$O\
+ ../5l/enam.$O\
YFILES=\
a.y\
-$(TARG): $(OFILES)
- $(LD) -o $(TARG) -L"$(GOROOT)"/lib $(OFILES) -lbio -l9
-
-$(OFILES): $(HFILES)
+include ../../Make.ccmd
lex.$O: ../cc/macbody ../cc/lexbody
-
-y.tab.h: $(YFILES)
- bison -y $(YFLAGS) $(YFILES)
-
-y.tab.c: y.tab.h
- test -f y.tab.c && touch y.tab.c
-
-clean:
- rm -f *.$O $(TARG) *.5 enam.c 5.out a.out y.tab.h y.tab.c
-
-install: $(TARG)
- cp $(TARG) "$(GOBIN)"/$(TARG)
diff --git a/src/cmd/5a/a.h b/src/cmd/5a/a.h
index 6cd5af8c6..bc4f433e1 100644
--- a/src/cmd/5a/a.h
+++ b/src/cmd/5a/a.h
@@ -1,7 +1,7 @@
// Inferno utils/5a/a.h
// http://code.google.com/p/inferno-os/source/browse/utils/5a/a.h
//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
@@ -148,6 +148,7 @@ EXTERN int pass;
EXTERN char* pathname;
EXTERN int32 pc;
EXTERN int peekc;
+EXTERN int32 stmtline;
EXTERN int sym;
EXTERN char* symb;
EXTERN int thechar;
@@ -157,7 +158,7 @@ EXTERN Biobuf obuf;
void* alloc(int32);
void* allocn(void*, int32, int32);
-void ensuresymb(int32);
+void ensuresymb(int32);
void errorexit(void);
void pushio(void);
void newio(void);
diff --git a/src/cmd/5a/a.y b/src/cmd/5a/a.y
index bb30ac698..b39c916ab 100644
--- a/src/cmd/5a/a.y
+++ b/src/cmd/5a/a.y
@@ -1,7 +1,7 @@
// Inferno utils/5a/a.y
// http://code.google.com/p/inferno-os/source/browse/utils/5a/a.y
//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
@@ -63,7 +63,11 @@
%type <gen> imm ximm name oreg ireg nireg ioreg imsr
%%
prog:
-| prog line
+| prog
+ {
+ stmtline = lineno;
+ }
+ line
line:
LLAB ':'
diff --git a/src/cmd/5a/lex.c b/src/cmd/5a/lex.c
index 2cc0993e4..b36094a78 100644
--- a/src/cmd/5a/lex.c
+++ b/src/cmd/5a/lex.c
@@ -1,7 +1,7 @@
// Inferno utils/5a/lex.c
// http://code.google.com/p/inferno-os/source/browse/utils/5a/lex.c
//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
@@ -658,10 +658,10 @@ jackpot:
Bputc(&obuf, a);
Bputc(&obuf, scond);
Bputc(&obuf, reg);
- Bputc(&obuf, lineno);
- Bputc(&obuf, lineno>>8);
- Bputc(&obuf, lineno>>16);
- Bputc(&obuf, lineno>>24);
+ Bputc(&obuf, stmtline);
+ Bputc(&obuf, stmtline>>8);
+ Bputc(&obuf, stmtline>>16);
+ Bputc(&obuf, stmtline>>24);
zaddr(g1, sf);
zaddr(g2, st);
diff --git a/src/cmd/5c/Makefile b/src/cmd/5c/Makefile
index b534206f3..70b614e8a 100644
--- a/src/cmd/5c/Makefile
+++ b/src/cmd/5c/Makefile
@@ -2,10 +2,10 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.conf
+include ../../Make.inc
+O:=$(HOST_O)
-TARG=\
- 5c\
+TARG=5c
HFILES=\
gc.h\
@@ -26,18 +26,9 @@ OFILES=\
../5l/enam.$O\
LIB=\
- ../cc/cc.a$O
+ ../cc/cc.a\
-$(TARG): $(OFILES) $(LIB)
- $(LD) -o $(TARG) -L"$(GOROOT)"/lib $(OFILES) $(LIB) -lbio -l9
-
-$(OFILES): $(HFILES)
-
-clean:
- rm -f *.$O $(TARG) *.5 enam.c 5.out a.out
-
-install: $(TARG)
- cp $(TARG) "$(GOBIN)"/$(TARG)
+include ../../Make.ccmd
%.$O: ../cc/%.c
- $(CC) $(CFLAGS) -c -I. -o $@ ../cc/$*.c
+ $(HOST_CC) $(HOST_CFLAGS) -c -I. -o $@ ../cc/$*.c
diff --git a/src/cmd/5c/list.c b/src/cmd/5c/list.c
index c792c130d..ab0fae83c 100644
--- a/src/cmd/5c/list.c
+++ b/src/cmd/5c/list.c
@@ -59,7 +59,7 @@ Bconv(Fmt *fp)
if(str[0])
strcat(str, " ");
if(var[i].sym == S) {
- sprint(ss, "$%ld", var[i].offset);
+ sprint(ss, "$%d", var[i].offset);
s = ss;
} else
s = var[i].sym->name;
@@ -204,7 +204,7 @@ Dconv(Fmt *fp)
break;
case D_BRANCH:
- sprint(str, "%ld(PC)", a->offset-pc);
+ sprint(str, "%d(PC)", a->offset-pc);
break;
case D_FCONST:
@@ -307,7 +307,7 @@ Nconv(Fmt *fp)
a = va_arg(fp->args, Adr*);
s = a->sym;
if(s == S) {
- sprint(str, "%ld", a->offset);
+ sprint(str, "%d", a->offset);
goto out;
}
switch(a->name) {
@@ -316,23 +316,23 @@ Nconv(Fmt *fp)
break;
case D_NONE:
- sprint(str, "%ld", a->offset);
+ sprint(str, "%d", a->offset);
break;
case D_EXTERN:
- sprint(str, "%s+%ld(SB)", s->name, a->offset);
+ sprint(str, "%s+%d(SB)", s->name, a->offset);
break;
case D_STATIC:
- sprint(str, "%s<>+%ld(SB)", s->name, a->offset);
+ sprint(str, "%s<>+%d(SB)", s->name, a->offset);
break;
case D_AUTO:
- sprint(str, "%s-%ld(SP)", s->name, -a->offset);
+ sprint(str, "%s-%d(SP)", s->name, -a->offset);
break;
case D_PARAM:
- sprint(str, "%s+%ld(FP)", s->name, a->offset);
+ sprint(str, "%s+%d(FP)", s->name, a->offset);
break;
}
out:
diff --git a/src/cmd/5c/mul.c b/src/cmd/5c/mul.c
index 121f67d5b..ff50c4845 100644
--- a/src/cmd/5c/mul.c
+++ b/src/cmd/5c/mul.c
@@ -115,7 +115,7 @@ mulcon0(int32 v)
if(docode(hintab[g].hint, m->code, 1, 0))
return m;
- print("multiply table failure %ld\n", v);
+ print("multiply table failure %d\n", v);
m->code[0] = 0;
return 0;
@@ -132,7 +132,7 @@ no:
if(gen1(g)) {
if(docode(hint, m->code, 1, 0))
return m;
- print("multiply table failure %ld\n", v);
+ print("multiply table failure %d\n", v);
break;
}
}
diff --git a/src/cmd/5c/peep.c b/src/cmd/5c/peep.c
index 4959d414d..8945ee732 100644
--- a/src/cmd/5c/peep.c
+++ b/src/cmd/5c/peep.c
@@ -1324,8 +1324,6 @@ predicable(Prog *p)
|| p->as == ASIGNAME
|| p->as == ATEXT
|| p->as == AWORD
- || p->as == ADYNT
- || p->as == AINIT
|| p->as == ABCASE
|| p->as == ACASE)
return 0;
diff --git a/src/cmd/5c/reg.c b/src/cmd/5c/reg.c
index f2d38d519..8c9794418 100644
--- a/src/cmd/5c/reg.c
+++ b/src/cmd/5c/reg.c
@@ -309,7 +309,7 @@ loop2:
if(debug['R'] && debug['v']) {
print("\nprop structure:\n");
for(r = firstr; r != R; r = r->link) {
- print("%ld:%P", r->loop, r->prog);
+ print("%d:%P", r->loop, r->prog);
for(z=0; z<BITS; z++)
bit.b[z] = r->set.b[z] |
r->refahead.b[z] | r->calahead.b[z] |
@@ -955,7 +955,7 @@ paint1(Reg *r, int bn)
if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb) {
change -= CLOAD * r->loop;
if(debug['R'] && debug['v'])
- print("%ld%P\tld %B $%d\n", r->loop,
+ print("%d%P\td %B $%d\n", r->loop,
r->prog, blsh(bn), change);
}
for(;;) {
@@ -965,21 +965,21 @@ paint1(Reg *r, int bn)
if(r->use1.b[z] & bb) {
change += CREF * r->loop;
if(debug['R'] && debug['v'])
- print("%ld%P\tu1 %B $%d\n", r->loop,
+ print("%d%P\tu1 %B $%d\n", r->loop,
p, blsh(bn), change);
}
if((r->use2.b[z]|r->set.b[z]) & bb) {
change += CREF * r->loop;
if(debug['R'] && debug['v'])
- print("%ld%P\tu2 %B $%d\n", r->loop,
+ print("%d%P\tu2 %B $%d\n", r->loop,
p, blsh(bn), change);
}
if(STORE(r) & r->regdiff.b[z] & bb) {
change -= CLOAD * r->loop;
if(debug['R'] && debug['v'])
- print("%ld%P\tst %B $%d\n", r->loop,
+ print("%d%P\tst %B $%d\n", r->loop,
p, blsh(bn), change);
}
diff --git a/src/cmd/5c/swt.c b/src/cmd/5c/swt.c
index cefbf53d9..43eb73c94 100644
--- a/src/cmd/5c/swt.c
+++ b/src/cmd/5c/swt.c
@@ -47,7 +47,7 @@ swit1(C1 *q, int nc, int32 def, Node *n)
if(nc < 5) {
for(i=0; i<nc; i++) {
if(debug['W'])
- print("case = %.8lux\n", q->val);
+ print("case = %.8ux\n", q->val);
gopcode(OEQ, nodconst(q->val), n, Z);
patch(p, q->label);
q++;
@@ -60,7 +60,7 @@ swit1(C1 *q, int nc, int32 def, Node *n)
i = nc / 2;
r = q+i;
if(debug['W'])
- print("case > %.8lux\n", r->val);
+ print("case > %.8ux\n", r->val);
gopcode(OGT, nodconst(r->val), n, Z);
sp = p;
gopcode(OEQ, nodconst(r->val), n, Z); /* just gen the B.EQ */
@@ -68,7 +68,7 @@ swit1(C1 *q, int nc, int32 def, Node *n)
swit1(q, i, def, n);
if(debug['W'])
- print("case < %.8lux\n", r->val);
+ print("case < %.8ux\n", r->val);
patch(sp, pc);
swit1(r+1, nc-i-1, def, n);
return;
@@ -81,7 +81,7 @@ direct:
patch(p, def);
for(i=0; i<nc; i++) {
if(debug['W'])
- print("case = %.8lux\n", q->val);
+ print("case = %.8ux\n", q->val);
while(q->val != v) {
nextpc();
p->as = ABCASE;
@@ -227,7 +227,7 @@ mulcon(Node *n, Node *nn)
return 0;
}
if(debug['M'] && debug['v'])
- print("%L multiply: %ld\n", n->lineno, v);
+ print("%L multiply: %d\n", n->lineno, v);
memmove(code, m->code, sizeof(m->code));
code[sizeof(m->code)] = 0;
@@ -606,7 +606,7 @@ zaddr(char *bp, Adr *a, int s)
}
int32
-align(int32 i, Type *t, int op)
+align(int32 i, Type *t, int op, int32 *maxalign)
{
int32 o;
Type *v;
@@ -620,7 +620,9 @@ align(int32 i, Type *t, int op)
break;
case Asu2: /* padding at end of a struct */
- w = SZ_LONG;
+ w = *maxalign;
+ if(w < 1)
+ w = 1;
if(packflg)
w = packflg;
break;
@@ -628,10 +630,16 @@ align(int32 i, Type *t, int op)
case Ael1: /* initial align of struct element */
for(v=t; v->etype==TARRAY; v=v->link)
;
- w = ewidth[v->etype];
- if(w <= 0 || w >= SZ_LONG)
- w = SZ_LONG;
- if(packflg)
+ if(v->etype == TSTRUCT || v->etype == TUNION)
+ w = v->align;
+ else {
+ w = ewidth[v->etype];
+ if(w == 8)
+ w = 4;
+ }
+ if(w < 1 || w > SZ_LONG)
+ fatal(Z, "align");
+ if(packflg)
w = packflg;
break;
@@ -641,8 +649,8 @@ align(int32 i, Type *t, int op)
case Aarg0: /* initial passbyptr argument in arg list */
if(typesuv[t->etype]) {
- o = align(o, types[TIND], Aarg1);
- o = align(o, types[TIND], Aarg2);
+ o = align(o, types[TIND], Aarg1, nil);
+ o = align(o, types[TIND], Aarg2, nil);
}
break;
@@ -661,14 +669,16 @@ align(int32 i, Type *t, int op)
break;
case Aaut3: /* total align of automatic */
- o = align(o, t, Ael2);
- o = align(o, t, Ael1);
+ o = align(o, t, Ael2, nil);
+ o = align(o, t, Ael1, nil);
w = SZ_LONG; /* because of a pun in cc/dcl.c:contig() */
break;
}
o = xround(o, w);
+ if(maxalign != nil && *maxalign < w)
+ *maxalign = w;
if(debug['A'])
- print("align %s %ld %T = %ld\n", bnames[op], i, t, o);
+ print("align %s %d %T = %d\n", bnames[op], i, t, o);
return o;
}
diff --git a/src/cmd/5c/txt.c b/src/cmd/5c/txt.c
index 9dac0312f..0f17cea89 100644
--- a/src/cmd/5c/txt.c
+++ b/src/cmd/5c/txt.c
@@ -388,7 +388,7 @@ err:
void
regsalloc(Node *n, Node *nn)
{
- cursafe = align(cursafe, nn->type, Aaut3);
+ cursafe = align(cursafe, nn->type, Aaut3, nil);
maxargsafe = maxround(maxargsafe, cursafe+curarg);
*n = *nodsafe;
n->xoffset = -(stkoff + cursafe);
@@ -402,22 +402,22 @@ regaalloc1(Node *n, Node *nn)
{
nodreg(n, nn, REGARG);
reg[REGARG]++;
- curarg = align(curarg, nn->type, Aarg1);
- curarg = align(curarg, nn->type, Aarg2);
+ curarg = align(curarg, nn->type, Aarg1, nil);
+ curarg = align(curarg, nn->type, Aarg2, nil);
maxargsafe = maxround(maxargsafe, cursafe+curarg);
}
void
regaalloc(Node *n, Node *nn)
{
- curarg = align(curarg, nn->type, Aarg1);
+ curarg = align(curarg, nn->type, Aarg1, nil);
*n = *nn;
n->op = OINDREG;
n->reg = REGSP;
n->xoffset = curarg + SZ_LONG;
n->complex = 0;
n->addable = 20;
- curarg = align(curarg, nn->type, Aarg2);
+ curarg = align(curarg, nn->type, Aarg2, nil);
maxargsafe = maxround(maxargsafe, cursafe+curarg);
}
@@ -580,7 +580,8 @@ void
gmove(Node *f, Node *t)
{
int ft, tt, a;
- Node nod;
+ Node nod, nod1;
+ Prog *p1;
ft = f->type->etype;
tt = t->type->etype;
@@ -709,21 +710,53 @@ gmove(Node *f, Node *t)
}
break;
case TUINT:
- case TINT:
case TULONG:
+ if(tt == TFLOAT || tt == TDOUBLE) {
+ // ugly and probably longer than necessary,
+ // but vfp has a single instruction for this,
+ // so hopefully it won't last long.
+ //
+ // tmp = f
+ // tmp1 = tmp & 0x80000000
+ // tmp ^= tmp1
+ // t = float(int32(tmp))
+ // if(tmp1)
+ // t += 2147483648.
+ //
+ regalloc(&nod, f, Z);
+ regalloc(&nod1, f, Z);
+ gins(AMOVW, f, &nod);
+ gins(AMOVW, &nod, &nod1);
+ gins(AAND, nodconst(0x80000000), &nod1);
+ gins(AEOR, &nod1, &nod);
+ if(tt == TFLOAT)
+ gins(AMOVWF, &nod, t);
+ else
+ gins(AMOVWD, &nod, t);
+ gins(ACMP, nodconst(0), Z);
+ raddr(&nod1, p);
+ gins(ABEQ, Z, Z);
+ regfree(&nod);
+ regfree(&nod1);
+ p1 = p;
+ regalloc(&nod, t, Z);
+ gins(AMOVF, nodfconst(2147483648.), &nod);
+ gins(AADDF, &nod, t);
+ regfree(&nod);
+ patch(p1, pc);
+ return;
+ }
+ // fall through
+
+ case TINT:
case TLONG:
case TIND:
switch(tt) {
case TDOUBLE:
- case TVLONG:
gins(AMOVWD, f, t);
- if(ft == TULONG) {
- }
return;
case TFLOAT:
gins(AMOVWF, f, t);
- if(ft == TULONG) {
- }
return;
case TINT:
case TUINT:
@@ -741,7 +774,6 @@ gmove(Node *f, Node *t)
case TSHORT:
switch(tt) {
case TDOUBLE:
- case TVLONG:
regalloc(&nod, f, Z);
gins(AMOVH, f, &nod);
gins(AMOVWD, &nod, t);
@@ -771,7 +803,6 @@ gmove(Node *f, Node *t)
case TUSHORT:
switch(tt) {
case TDOUBLE:
- case TVLONG:
regalloc(&nod, f, Z);
gins(AMOVHU, f, &nod);
gins(AMOVWD, &nod, t);
@@ -801,7 +832,6 @@ gmove(Node *f, Node *t)
case TCHAR:
switch(tt) {
case TDOUBLE:
- case TVLONG:
regalloc(&nod, f, Z);
gins(AMOVB, f, &nod);
gins(AMOVWD, &nod, t);
@@ -831,7 +861,6 @@ gmove(Node *f, Node *t)
case TUCHAR:
switch(tt) {
case TDOUBLE:
- case TVLONG:
regalloc(&nod, f, Z);
gins(AMOVBU, f, &nod);
gins(AMOVWD, &nod, t);
diff --git a/src/cmd/5g/Makefile b/src/cmd/5g/Makefile
index 123af19cd..6873fbc68 100644
--- a/src/cmd/5g/Makefile
+++ b/src/cmd/5g/Makefile
@@ -2,10 +2,10 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.conf
+include ../../Make.inc
+O:=$(HOST_O)
-TARG=\
- 5g
+TARG=5g
HFILES=\
../gc/go.h\
@@ -21,18 +21,15 @@ OFILES=\
ggen.$O\
gsubr.$O\
cgen.$O\
- cgen64.$O
+ cgen64.$O\
+ cplx.$O\
+ reg.$O\
+ peep.$O\
LIB=\
- ../gc/gc.a$O
+ ../gc/gc.a\
-$(TARG): $(OFILES) $(LIB)
- $(LD) -o $(TARG) -L"$(GOROOT)"/lib $(OFILES) $(LIB) -lbio -l9 -lm
+include ../../Make.ccmd
-$(OFILES): $(HFILES)
-
-clean:
- rm -f *.o $(TARG) *.5 enam.c 5.out a.out
-
-install: $(TARG)
- cp $(TARG) "$(GOBIN)"/$(TARG)
+%.$O: ../gc/%.c
+ $(HOST_CC) $(HOST_CFLAGS) -c -I. -o $@ ../gc/$*.c
diff --git a/src/cmd/5g/cgen.c b/src/cmd/5g/cgen.c
index 8072c3ceb..1328f4be6 100644
--- a/src/cmd/5g/cgen.c
+++ b/src/cmd/5g/cgen.c
@@ -4,33 +4,6 @@
#include "gg.h"
-void
-mgen(Node *n, Node *n1, Node *rg)
-{
- n1->ostk = 0;
- n1->op = OEMPTY;
-
- if(n->addable) {
- *n1 = *n;
- n1->ostk = 0;
- if(n1->op == OREGISTER || n1->op == OINDREG)
- reg[n->val.u.reg]++;
- return;
- }
- if(n->type->width > widthptr)
- tempname(n1, n->type);
- else
- regalloc(n1, n->type, rg);
- cgen(n, n1);
-}
-
-void
-mfree(Node *n)
-{
- if(n->op == OREGISTER)
- regfree(n);
-}
-
/*
* generate:
* res = n;
@@ -55,12 +28,6 @@ cgen(Node *n, Node *res)
if(res == N || res->type == T)
fatal("cgen: res nil");
- // TODO compile complex
- if(n != N && n->type != T && iscomplex[n->type->etype])
- return;
- if(res != N && res->type != T && iscomplex[res->type->etype])
- return;
-
while(n->op == OCONVNOP)
n = n->left;
@@ -80,6 +47,7 @@ cgen(Node *n, Node *res)
goto ret;
}
+
// update addressability for string, slice
// can't do in walk because n->left->addable
// changes if n->left is an escaping local variable.
@@ -96,7 +64,9 @@ cgen(Node *n, Node *res)
// if both are addressable, move
if(n->addable && res->addable) {
- if (is64(n->type) || is64(res->type) || n->op == OREGISTER || res->op == OREGISTER) {
+ if(is64(n->type) || is64(res->type) ||
+ n->op == OREGISTER || res->op == OREGISTER ||
+ iscomplex[n->type->etype] || iscomplex[res->type->etype]) {
gmove(n, res);
} else {
regalloc(&n1, n->type, N);
@@ -126,8 +96,13 @@ cgen(Node *n, Node *res)
return;
}
+ if(complexop(n, res)) {
+ complexgen(n, res);
+ return;
+ }
+
// if n is sudoaddable generate addr and move
- if (!is64(n->type) && !is64(res->type)) {
+ if (!is64(n->type) && !is64(res->type) && !iscomplex[n->type->etype] && !iscomplex[res->type->etype]) {
a = optoas(OAS, n->type);
if(sudoaddable(a, n, &addr, &w)) {
if (res->op != OREGISTER) {
@@ -195,8 +170,8 @@ cgen(Node *n, Node *res)
case OREAL:
case OIMAG:
case OCMPLX:
- // TODO compile complex
- return;
+ fatal("unexpected complex");
+ break;
// these call bgen to get a bool value
case OOROR:
@@ -269,10 +244,26 @@ cgen(Node *n, Node *res)
cgen(nl, res);
break;
}
-
- mgen(nl, &n1, res);
- gmove(&n1, res);
- mfree(&n1);
+ if(nl->addable && !is64(nl->type)) {
+ regalloc(&n1, nl->type, res);
+ gmove(nl, &n1);
+ } else {
+ if(n->type->width > widthptr || is64(nl->type) || isfloat[nl->type->etype])
+ tempname(&n1, nl->type);
+ else
+ regalloc(&n1, nl->type, res);
+ cgen(nl, &n1);
+ }
+ if(n->type->width > widthptr || is64(n->type) || isfloat[n->type->etype])
+ tempname(&n2, n->type);
+ else
+ regalloc(&n2, n->type, N);
+ gmove(&n1, &n2);
+ gmove(&n2, res);
+ if(n1.op == OREGISTER)
+ regfree(&n1);
+ if(n2.op == OREGISTER)
+ regfree(&n2);
break;
case ODOT:
@@ -461,6 +452,41 @@ ret:
}
/*
+ * generate array index into res.
+ * n might be any size; res is 32-bit.
+ * returns Prog* to patch to panic call.
+ */
+Prog*
+cgenindex(Node *n, Node *res)
+{
+ Node tmp, lo, hi, zero, n1, n2;
+
+ if(!is64(n->type)) {
+ cgen(n, res);
+ return nil;
+ }
+
+ tempname(&tmp, types[TINT64]);
+ cgen(n, &tmp);
+ split64(&tmp, &lo, &hi);
+ gmove(&lo, res);
+ if(debug['B']) {
+ splitclean();
+ return nil;
+ }
+ regalloc(&n1, types[TINT32], N);
+ regalloc(&n2, types[TINT32], N);
+ nodconst(&zero, types[TINT32], 0);
+ gmove(&hi, &n1);
+ gmove(&zero, &n2);
+ gcmp(ACMP, &n1, &n2);
+ regfree(&n2);
+ regfree(&n1);
+ splitclean();
+ return gbranch(ABNE, T);
+}
+
+/*
* generate:
* res = &n;
*/
@@ -469,10 +495,10 @@ agen(Node *n, Node *res)
{
Node *nl, *nr;
Node n1, n2, n3, n4, n5, tmp;
- Prog *p1;
+ Prog *p1, *p2;
uint32 w;
uint64 v;
- Type *t;
+ int r;
if(debug['g']) {
dump("\nagen-res", res);
@@ -504,7 +530,22 @@ agen(Node *n, Node *res)
break;
case OCALLMETH:
- cgen_callmeth(n, 0);
+ case OCALLFUNC:
+ // Release res so that it is available for cgen_call.
+ // Pick it up again after the call.
+ r = -1;
+ if(n->ullman >= UINF) {
+ if(res->op == OREGISTER || res->op == OINDREG) {
+ r = res->val.u.reg;
+ reg[r]--;
+ }
+ }
+ if(n->op == OCALLMETH)
+ cgen_callmeth(n, 0);
+ else
+ cgen_call(n, 0);
+ if(r >= 0)
+ reg[r]++;
cgen_aret(n, res);
break;
@@ -513,36 +554,36 @@ agen(Node *n, Node *res)
cgen_aret(n, res);
break;
- case OCALLFUNC:
- cgen_call(n, 0);
- cgen_aret(n, res);
- break;
-
case OINDEX:
- // TODO(rsc): uint64 indices
+ p2 = nil; // to be patched to panicindex.
w = n->type->width;
if(nr->addable) {
- agenr(nl, &n3, res);
- if(!isconst(nr, CTINT)) {
+ if(!isconst(nr, CTINT))
tempname(&tmp, types[TINT32]);
- cgen(nr, &tmp);
+ if(!isconst(nl, CTSTR))
+ agenr(nl, &n3, res);
+ if(!isconst(nr, CTINT)) {
+ p2 = cgenindex(nr, &tmp);
regalloc(&n1, tmp.type, N);
gmove(&tmp, &n1);
}
} else if(nl->addable) {
if(!isconst(nr, CTINT)) {
tempname(&tmp, types[TINT32]);
- cgen(nr, &tmp);
+ p2 = cgenindex(nr, &tmp);
regalloc(&n1, tmp.type, N);
gmove(&tmp, &n1);
}
- regalloc(&n3, types[tptr], res);
- agen(nl, &n3);
+ if(!isconst(nl, CTSTR)) {
+ regalloc(&n3, types[tptr], res);
+ agen(nl, &n3);
+ }
} else {
tempname(&tmp, types[TINT32]);
- cgen(nr, &tmp);
+ p2 = cgenindex(nr, &tmp);
nr = &tmp;
- agenr(nl, &n3, res);
+ if(!isconst(nl, CTSTR))
+ agenr(nl, &n3, res);
regalloc(&n1, tmp.type, N);
gins(optoas(OAS, tmp.type), &tmp, &n1);
}
@@ -556,9 +597,10 @@ agen(Node *n, Node *res)
// constant index
if(isconst(nr, CTINT)) {
+ if(isconst(nl, CTSTR))
+ fatal("constant string constant index");
v = mpgetfix(nr->val.u.xval);
- if(isslice(nl->type)) {
-
+ if(isslice(nl->type) || nl->type->etype == TSTRING) {
if(!debug['B'] && !n->etype) {
n1 = n3;
n1.op = OINDREG;
@@ -582,13 +624,6 @@ agen(Node *n, Node *res)
n1.type = types[tptr];
n1.xoffset = Array_array;
gmove(&n1, &n3);
- } else
- if(!debug['B'] && !n->etype) {
- if(v < 0)
- yyerror("out of bounds on array");
- else
- if(v >= nl->type->bound)
- yyerror("out of bounds on array");
}
nodconst(&n2, types[tptr], v*w);
@@ -602,19 +637,17 @@ agen(Node *n, Node *res)
break;
}
- // type of the index
- t = types[TUINT32];
- if(issigned[n1.type->etype])
- t = types[TINT32];
-
- regalloc(&n2, t, &n1); // i
+ regalloc(&n2, types[TINT32], &n1); // i
gmove(&n1, &n2);
regfree(&n1);
if(!debug['B'] && !n->etype) {
// check bounds
regalloc(&n4, types[TUINT32], N);
- if(isslice(nl->type)) {
+ if(isconst(nl, CTSTR)) {
+ nodconst(&n1, types[TUINT32], nl->val.u.sval->len);
+ gmove(&n1, &n4);
+ } else if(isslice(nl->type) || nl->type->etype == TSTRING) {
n1 = n3;
n1.op = OINDREG;
n1.type = types[tptr];
@@ -627,11 +660,18 @@ agen(Node *n, Node *res)
gcmp(optoas(OCMP, types[TUINT32]), &n2, &n4);
regfree(&n4);
p1 = gbranch(optoas(OLT, types[TUINT32]), T);
+ if(p2)
+ patch(p2, pc);
ginscall(panicindex, 0);
patch(p1, pc);
}
-
- if(isslice(nl->type)) {
+
+ if(isconst(nl, CTSTR)) {
+ regalloc(&n3, types[tptr], res);
+ p1 = gins(AMOVW, N, &n3);
+ datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from);
+ p1->from.type = D_CONST;
+ } else if(isslice(nl->type) || nl->type->etype == TSTRING) {
n1 = n3;
n1.op = OINDREG;
n1.type = types[tptr];
@@ -653,10 +693,10 @@ agen(Node *n, Node *res)
else if(w == 8)
gshift(AADD, &n2, SHIFT_LL, 3, &n3);
} else {
- regalloc(&n4, t, N);
- nodconst(&n1, t, w);
+ regalloc(&n4, types[TUINT32], N);
+ nodconst(&n1, types[TUINT32], w);
gmove(&n1, &n4);
- gins(optoas(OMUL, t), &n4, &n2);
+ gins(optoas(OMUL, types[TUINT32]), &n4, &n2);
gins(optoas(OADD, types[tptr]), &n2, &n3);
regfree(&n4);
gmove(&n3, res);
@@ -769,12 +809,8 @@ igen(Node *n, Node *a, Node *res)
void
agenr(Node *n, Node *a, Node *res)
{
- Node n1;
-
- tempname(&n1, types[tptr]);
- agen(n, &n1);
regalloc(a, types[tptr], res);
- gmove(&n1, a);
+ agen(n, a);
}
/*
@@ -796,15 +832,12 @@ bgen(Node *n, int true, Prog *to)
if(n == N)
n = nodbool(1);
+ if(n->ninit != nil)
+ genlist(n->ninit);
+
nl = n->left;
nr = n->right;
- // TODO compile complex
- if(nl != N && nl->type != T && iscomplex[nl->type->etype])
- return;
- if(nr != N && nr->type != T && iscomplex[nr->type->etype])
- return;
-
if(n->type == T) {
convlit(&n, types[TBOOL]);
if(n->type == T)
@@ -925,6 +958,7 @@ bgen(Node *n, int true, Prog *to)
goto ret;
}
a = brcom(a);
+ true = !true;
}
// make simplest on right
@@ -985,6 +1019,11 @@ bgen(Node *n, int true, Prog *to)
break;
}
+ if(iscomplex[nl->type->etype]) {
+ complexbool(a, nl, nr, true, to);
+ break;
+ }
+
if(is64(nr->type)) {
if(!nl->addable) {
tempname(&n1, nl->type);
@@ -1031,7 +1070,16 @@ bgen(Node *n, int true, Prog *to)
cgen(nr, &n2);
gcmp(optoas(OCMP, nr->type), &n1, &n2);
- patch(gbranch(a, nr->type), to);
+ if(isfloat[nl->type->etype]) {
+ p1 = gbranch(ABVS, nr->type);
+ patch(gbranch(a, nr->type), to);
+ if(n->op == ONE)
+ patch(p1, to);
+ else
+ patch(p1, pc);
+ } else {
+ patch(gbranch(a, nr->type), to);
+ }
regfree(&n1);
regfree(&n2);
@@ -1088,7 +1136,7 @@ stkof(Node *n)
t = structfirst(&flist, getoutarg(t));
if(t != T)
- return t->width;
+ return t->width + 4; // correct for LR
break;
}
diff --git a/src/cmd/5g/cgen64.c b/src/cmd/5g/cgen64.c
index a22f4a548..716ec5ed5 100644
--- a/src/cmd/5g/cgen64.c
+++ b/src/cmd/5g/cgen64.c
@@ -439,12 +439,12 @@ olsh_break:
p3 = gbranch(ABLO, T);
// shift == 32
+ p1 = gins(AMOVW, &bh, &al);
+ p1->scond = C_SCOND_EQ;
if(bh.type->etype == TINT32)
p1 = gshift(AMOVW, &bh, SHIFT_AR, 31, &ah);
else
- p1 = gins(AEOR, &al, &al);
- p1->scond = C_SCOND_EQ;
- p1 = gins(AMOVW, &bh, &al);
+ p1 = gins(AEOR, &ah, &ah);
p1->scond = C_SCOND_EQ;
p4 = gbranch(ABEQ, T);
diff --git a/src/cmd/5g/galign.c b/src/cmd/5g/galign.c
index 76affbf00..9c8760aea 100644
--- a/src/cmd/5g/galign.c
+++ b/src/cmd/5g/galign.c
@@ -25,7 +25,6 @@ Typedef typedefs[] =
void
betypeinit(void)
{
- maxround = 4;
widthptr = 4;
zprog.link = P;
diff --git a/src/cmd/5g/gg.h b/src/cmd/5g/gg.h
index c62efeb6c..603c09fc8 100644
--- a/src/cmd/5g/gg.h
+++ b/src/cmd/5g/gg.h
@@ -33,12 +33,13 @@ struct Addr
struct Prog
{
- short as; // opcode
+ short as; // opcode
uint32 loc; // pc offset in this func
uint32 lineno; // source line that generated this
Addr from; // src address
- Addr to; // dst address
+ Addr to; // dst address
Prog* link; // next instruction in this func
+ void* regp; // points to enclosing Reg struct
char reg; // doubles as width in DATA op
uchar scond;
};
@@ -90,6 +91,7 @@ void ginscall(Node*, int);
* cgen
*/
void agen(Node*, Node*);
+Prog* cgenindex(Node *, Node *);
void igen(Node*, Node*, Node*);
void agenr(Node *n, Node *a, Node *res);
vlong fieldoffset(Type*, Node*);
diff --git a/src/cmd/5g/ggen.c b/src/cmd/5g/ggen.c
index 3243bb863..42a89415d 100644
--- a/src/cmd/5g/ggen.c
+++ b/src/cmd/5g/ggen.c
@@ -61,11 +61,14 @@ compile(Node *fn)
pl = newplist();
pl->name = curfn->nname;
+
+ setlineno(curfn);
nodconst(&nod1, types[TINT32], 0);
ptxt = gins(ATEXT, curfn->nname, &nod1);
afunclit(&ptxt->from);
+ ginit();
genlist(curfn->enter);
pret = nil;
@@ -78,6 +81,7 @@ compile(Node *fn)
}
genlist(curfn->nbody);
+ gclean();
checklabels();
if(nerrors != 0)
goto ret;
@@ -87,29 +91,32 @@ compile(Node *fn)
if(pret)
patch(pret, pc);
+ ginit();
+ if(hasdefer)
+ ginscall(deferreturn, 0);
if(curfn->exit)
genlist(curfn->exit);
+ gclean();
if(nerrors != 0)
goto ret;
- if(hasdefer)
- ginscall(deferreturn, 0);
+ if(curfn->endlineno)
+ lineno = curfn->endlineno;
pc->as = ARET; // overwrite AEND
pc->lineno = lineno;
- /* TODO(kaib): Add back register optimizations
- if(!debug['N'] || debug['R'] || debug['P'])
+ if(!debug['N'] || debug['R'] || debug['P']) {
regopt(ptxt);
- */
+ }
// fill in argument size
ptxt->to.type = D_CONST2;
ptxt->reg = 0; // flags
- ptxt->to.offset2 = rnd(curfn->type->argwid, maxround);
+ ptxt->to.offset2 = rnd(curfn->type->argwid, widthptr);
// fill in final stack size
if(stksize > maxstksize)
maxstksize = stksize;
- ptxt->to.offset = rnd(maxstksize+maxarg, maxround);
+ ptxt->to.offset = rnd(maxstksize+maxarg, widthptr);
maxstksize = 0;
if(debug['f'])
@@ -203,6 +210,7 @@ ginscall(Node *f, int proc)
void
cgen_callinter(Node *n, Node *res, int proc)
{
+ int r;
Node *i, *f;
Node tmpi, nodo, nodr, nodsp;
@@ -216,6 +224,14 @@ cgen_callinter(Node *n, Node *res, int proc)
i = i->left; // interface
+ // Release res register during genlist and cgen,
+ // which might have their own function calls.
+ r = -1;
+ if(res != N && (res->op == OREGISTER || res->op == OINDREG)) {
+ r = res->val.u.reg;
+ reg[r]--;
+ }
+
if(!i->addable) {
tempname(&tmpi, i->type);
cgen(i, &tmpi);
@@ -223,6 +239,8 @@ cgen_callinter(Node *n, Node *res, int proc)
}
genlist(n->list); // args
+ if(r >= 0)
+ reg[r]++;
regalloc(&nodr, types[tptr], res);
regalloc(&nodo, types[tptr], &nodr);
@@ -427,10 +445,10 @@ cgen_asop(Node *n)
case OOR:
a = optoas(n->etype, nl->type);
if(nl->addable) {
- regalloc(&n2, nl->type, N);
regalloc(&n3, nr->type, N);
- cgen(nl, &n2);
cgen(nr, &n3);
+ regalloc(&n2, nl->type, N);
+ cgen(nl, &n2);
gins(a, &n3, &n2);
cgen(&n2, nl);
regfree(&n2);
@@ -439,13 +457,14 @@ cgen_asop(Node *n)
}
if(nr->ullman < UINF)
if(sudoaddable(a, nl, &addr, &w)) {
+ w = optoas(OAS, nl->type);
regalloc(&n2, nl->type, N);
- regalloc(&n3, nr->type, N);
- p1 = gins(AMOVW, N, &n2);
+ p1 = gins(w, N, &n2);
p1->from = addr;
+ regalloc(&n3, nr->type, N);
cgen(nr, &n3);
gins(a, &n3, &n2);
- p1 = gins(AMOVW, &n2, N);
+ p1 = gins(w, &n2, N);
p1->to = addr;
regfree(&n2);
regfree(&n3);
@@ -544,7 +563,7 @@ cgen_shift(int op, Node *nl, Node *nr, Node *res)
cgen(nl, &n1);
sc = mpgetfix(nr->val.u.xval);
if(sc == 0) {
- return;
+ // nothing to do
} else if(sc >= nl->type->width*8) {
if(op == ORSH && issigned[nl->type->etype])
gshift(AMOVW, &n1, SHIFT_AR, w, &n1);
@@ -682,6 +701,29 @@ regcmp(const void *va, const void *vb)
static Prog* throwpc;
+// We're only going to bother inlining if we can
+// convert all the arguments to 32 bits safely. Can we?
+static int
+fix64(NodeList *nn, int n)
+{
+ NodeList *l;
+ Node *r;
+ int i;
+
+ l = nn;
+ for(i=0; i<n; i++) {
+ r = l->n->right;
+ if(is64(r->type) && !smallintconst(r)) {
+ if(r->op == OCONV)
+ r = r->left;
+ if(is64(r->type))
+ return 0;
+ }
+ l = l->next;
+ }
+ return 1;
+}
+
void
getargs(NodeList *nn, Node *reg, int n)
{
@@ -710,7 +752,7 @@ getargs(NodeList *nn, Node *reg, int n)
void
cmpandthrow(Node *nl, Node *nr)
{
- vlong cl, cr;
+ vlong cl;
Prog *p1;
int op;
Node *c, n1, n2;
@@ -720,17 +762,8 @@ cmpandthrow(Node *nl, Node *nr)
cl = mpgetfix(nl->val.u.xval);
if(cl == 0)
return;
- if(smallintconst(nr)) {
- cr = mpgetfix(nr->val.u.xval);
- if(cl > cr) {
- if(throwpc == nil) {
- throwpc = pc;
- ginscall(panicslice, 0);
- } else
- patch(gbranch(AB, T), throwpc);
- }
+ if(smallintconst(nr))
return;
- }
// put the constant on the right
op = brrev(op);
@@ -794,6 +827,8 @@ cgen_inline(Node *n, Node *res)
goto no;
if(!n->left->addable)
goto no;
+ if(n->left->sym == S)
+ goto no;
if(n->left->sym->pkg != runtimepkg)
goto no;
if(strcmp(n->left->sym->name, "slicearray") == 0)
@@ -811,6 +846,8 @@ cgen_inline(Node *n, Node *res)
slicearray:
if(!sleasy(res))
goto no;
+ if(!fix64(n->list, 5))
+ goto no;
getargs(n->list, nodes, 5);
// if(hb[3] > nel[1]) goto throw
@@ -902,6 +939,8 @@ slicearray:
return 1;
sliceslice:
+ if(!fix64(n->list, narg))
+ goto no;
ntemp.op = OXXX;
if(!sleasy(n->list->n->right)) {
Node *n0;
diff --git a/src/cmd/5g/gobj.c b/src/cmd/5g/gobj.c
index c4564ed66..bf59534b9 100644
--- a/src/cmd/5g/gobj.c
+++ b/src/cmd/5g/gobj.c
@@ -633,10 +633,10 @@ dsymptr(Sym *s, int off, Sym *x, int xoff)
void
-genembedtramp(Type *rcvr, Type *method, Sym *newnam)
+genembedtramp(Type *rcvr, Type *method, Sym *newnam, int iface)
{
// TODO(kaib): re-implement genembedtramp
- genwrapper(rcvr, method, newnam);
+ genwrapper(rcvr, method, newnam, iface);
/*
Sym *e;
int c, d, o;
@@ -705,7 +705,7 @@ out:
p->to.type = D_OREG;
p->to.reg = NREG;
p->to.name = D_EXTERN;
- p->to.sym = methodsym(method->sym, ptrto(f->type));
+ p->to.sym = methodsym(method->sym, ptrto(f->type), 0);
//print("4. %P\n", p);
pc->as = ARET; // overwrite AEND
diff --git a/src/cmd/5g/gsubr.c b/src/cmd/5g/gsubr.c
index 700602c35..133a21b3e 100644
--- a/src/cmd/5g/gsubr.c
+++ b/src/cmd/5g/gsubr.c
@@ -197,9 +197,50 @@ afunclit(Addr *a)
}
}
+static int resvd[] =
+{
+ 9, // reserved for m
+ 10, // reserved for g
+};
+
+void
+ginit(void)
+{
+ int i;
+
+ for(i=0; i<nelem(reg); i++)
+ reg[i] = 0;
+ for(i=0; i<nelem(resvd); i++)
+ reg[resvd[i]]++;
+}
+
+void
+gclean(void)
+{
+ int i;
+
+ for(i=0; i<nelem(resvd); i++)
+ reg[resvd[i]]--;
+
+ for(i=0; i<nelem(reg); i++)
+ if(reg[i])
+ yyerror("reg %R left allocated\n", i);
+}
+
int32
anyregalloc(void)
{
+ int i, j;
+
+ for(i=0; i<nelem(reg); i++) {
+ if(reg[i] == 0)
+ goto ok;
+ for(j=0; j<nelem(resvd); j++)
+ if(resvd[j] == i)
+ goto ok;
+ return 1;
+ ok:;
+ }
return 0;
}
@@ -264,6 +305,11 @@ regalloc(Node *n, Type *t, Node *o)
goto out;
yyerror("out of floating point registers");
goto err;
+
+ case TCOMPLEX64:
+ case TCOMPLEX128:
+ tempname(n, t);
+ return;
}
yyerror("regalloc: unknown type %T", t);
@@ -293,6 +339,8 @@ regfree(Node *n)
print("regalloc fix %d float %d\n", fixfree, floatfree);
}
+ if(n->op == ONAME && iscomplex[n->type->etype])
+ return;
if(n->op != OREGISTER && n->op != OINDREG)
fatal("regfree: not a register");
i = n->val.u.reg;
@@ -498,6 +546,11 @@ gmove(Node *f, Node *t)
tt = simsimtype(t->type);
cvt = t->type;
+ if(iscomplex[ft] || iscomplex[tt]) {
+ complexmove(f, t);
+ return;
+ }
+
// cannot have two memory operands;
// except 64-bit, which always copies via registers anyway.
if(!is64(f->type) && !is64(t->type) && ismem(f) && ismem(t))
@@ -715,56 +768,109 @@ gmove(Node *f, Node *t)
* float to integer
*/
case CASE(TFLOAT32, TINT8):
- case CASE(TFLOAT32, TINT16):
- case CASE(TFLOAT32, TINT32):
case CASE(TFLOAT32, TUINT8):
+ case CASE(TFLOAT32, TINT16):
case CASE(TFLOAT32, TUINT16):
+ case CASE(TFLOAT32, TINT32):
case CASE(TFLOAT32, TUINT32):
- fa = AMOVF;
- a = AMOVFW;
- ta = AMOVW;
- goto fltconv;
+// case CASE(TFLOAT32, TUINT64):
case CASE(TFLOAT64, TINT8):
- case CASE(TFLOAT64, TINT16):
- case CASE(TFLOAT64, TINT32):
case CASE(TFLOAT64, TUINT8):
+ case CASE(TFLOAT64, TINT16):
case CASE(TFLOAT64, TUINT16):
+ case CASE(TFLOAT64, TINT32):
case CASE(TFLOAT64, TUINT32):
- fa = AMOVD;
- a = AMOVDW;
+// case CASE(TFLOAT64, TUINT64):
+ fa = AMOVF;
+ a = AMOVFW;
+ if(ft == TFLOAT64) {
+ fa = AMOVD;
+ a = AMOVDW;
+ }
ta = AMOVW;
- goto fltconv;
+ switch(tt) {
+ case TINT8:
+ ta = AMOVB;
+ break;
+ case TUINT8:
+ ta = AMOVBU;
+ break;
+ case TINT16:
+ ta = AMOVH;
+ break;
+ case TUINT16:
+ ta = AMOVHU;
+ break;
+ }
- case CASE(TFLOAT32, TUINT64):
- case CASE(TFLOAT64, TUINT64):
- fatal("gmove TFLOAT, UINT64 not implemented");
+ regalloc(&r1, types[ft], f);
+ regalloc(&r2, types[tt], t);
+ gins(fa, f, &r1); // load to fpu
+ p1 = gins(a, &r1, &r1); // convert to w
+ switch(tt) {
+ case TUINT8:
+ case TUINT16:
+ case TUINT32:
+ p1->scond |= C_UBIT;
+ }
+ gins(AMOVW, &r1, &r2); // copy to cpu
+ gins(ta, &r2, t); // store
+ regfree(&r1);
+ regfree(&r2);
return;
/*
* integer to float
*/
case CASE(TINT8, TFLOAT32):
- case CASE(TINT16, TFLOAT32):
- case CASE(TINT32, TFLOAT32):
case CASE(TUINT8, TFLOAT32):
+ case CASE(TINT16, TFLOAT32):
case CASE(TUINT16, TFLOAT32):
+ case CASE(TINT32, TFLOAT32):
case CASE(TUINT32, TFLOAT32):
- fa = AMOVW;
- a = AMOVWF;
- ta = AMOVF;
- goto fltconv;
-
case CASE(TINT8, TFLOAT64):
- case CASE(TINT16, TFLOAT64):
- case CASE(TINT32, TFLOAT64):
case CASE(TUINT8, TFLOAT64):
+ case CASE(TINT16, TFLOAT64):
case CASE(TUINT16, TFLOAT64):
+ case CASE(TINT32, TFLOAT64):
case CASE(TUINT32, TFLOAT64):
fa = AMOVW;
- a = AMOVWD;
- ta = AMOVD;
- goto fltconv;
+ switch(ft) {
+ case TINT8:
+ fa = AMOVB;
+ break;
+ case TUINT8:
+ fa = AMOVBU;
+ break;
+ case TINT16:
+ fa = AMOVH;
+ break;
+ case TUINT16:
+ fa = AMOVHU;
+ break;
+ }
+ a = AMOVWF;
+ ta = AMOVF;
+ if(tt == TFLOAT64) {
+ a = AMOVWD;
+ ta = AMOVD;
+ }
+ regalloc(&r1, types[ft], f);
+ regalloc(&r2, types[tt], t);
+ gins(fa, f, &r1); // load to cpu
+ gins(AMOVW, &r1, &r2); // copy to fpu
+ p1 = gins(a, &r2, &r2); // convert
+ switch(ft) {
+ case TUINT8:
+ case TUINT16:
+ case TUINT32:
+ p1->scond |= C_UBIT;
+ }
+ gins(ta, &r2, t); // store
+ regfree(&r1);
+ regfree(&r2);
+ return;
case CASE(TUINT64, TFLOAT32):
case CASE(TUINT64, TFLOAT64):
@@ -831,16 +937,6 @@ trunc64:
splitclean();
return;
-fltconv:
- regalloc(&r1, types[ft], f);
- regalloc(&r2, types[tt], t);
- gins(fa, f, &r1);
- gins(a, &r1, &r2);
- gins(ta, &r2, t);
- regfree(&r1);
- regfree(&r2);
- return;
-
fatal:
// should not happen
fatal("gmove %N -> %N", f, t);
@@ -951,7 +1047,7 @@ gshift(int as, Node *lhs, int32 stype, int32 sval, Node *rhs)
{
Prog *p;
- if (sval <= 0 || sval > 32)
+ if(sval <= 0 || sval > 32)
fatal("bad shift value: %d", sval);
sval = sval&0x1f;
@@ -983,7 +1079,7 @@ checkoffset(Addr *a, int canemitcode)
if(a->offset < unmappedzero)
return;
if(!canemitcode)
- fatal("checkoffset %#llx, cannot emit code", a->offset);
+ fatal("checkoffset %#x, cannot emit code", a->offset);
// cannot rely on unmapped nil page at 0 to catch
// reference with large offset. instead, emit explicit
@@ -1014,7 +1110,7 @@ naddr(Node *n, Addr *a, int canemitcode)
break;
case OREGISTER:
- if (n->val.u.reg <= REGALLOC_RMAX) {
+ if(n->val.u.reg <= REGALLOC_RMAX) {
a->type = D_REG;
a->reg = n->val.u.reg;
} else {
@@ -1314,15 +1410,21 @@ optoas(int op, Type *t)
case CASE(OAS, TBOOL):
case CASE(OAS, TINT8):
- case CASE(OAS, TUINT8):
a = AMOVB;
break;
+ case CASE(OAS, TUINT8):
+ a = AMOVBU;
+ break;
+
case CASE(OAS, TINT16):
- case CASE(OAS, TUINT16):
a = AMOVH;
break;
+ case CASE(OAS, TUINT16):
+ a = AMOVHU;
+ break;
+
case CASE(OAS, TINT32):
case CASE(OAS, TUINT32):
case CASE(OAS, TPTR32):
@@ -1554,7 +1656,7 @@ sudoaddable(int as, Node *n, Addr *a, int *w)
int64 v;
Node n1, n2, n3, n4, *nn, *l, *r;
Node *reg, *reg1;
- Prog *p1;
+ Prog *p1, *p2;
Type *t;
if(n->type == T)
@@ -1579,6 +1681,8 @@ sudoaddable(int as, Node *n, Addr *a, int *w)
goto odot;
case OINDEX:
+ if(n->left->type->etype == TSTRING)
+ return 0;
cleani += 2;
reg = &clean[cleani-1];
reg1 = &clean[cleani-2];
@@ -1692,8 +1796,8 @@ oindex:
if(issigned[r->type->etype])
t = types[TINT32];
regalloc(reg1, t, N);
- regalloc(&n3, r->type, reg1);
- cgen(r, &n3);
+ regalloc(&n3, types[TINT32], reg1);
+ p2 = cgenindex(r, &n3);
gmove(&n3, reg1);
regfree(&n3);
@@ -1734,6 +1838,8 @@ oindex:
gcmp(optoas(OCMP, types[TUINT32]), reg1, &n3);
regfree(&n3);
p1 = gbranch(optoas(OLT, types[TUINT32]), T);
+ if(p2)
+ patch(p2, pc);
ginscall(panicindex, 0);
patch(p1, pc);
}
@@ -1746,14 +1852,20 @@ oindex:
gmove(&n2, reg);
}
- if (*w == 1)
+ switch(*w) {
+ case 1:
gins(AADD, reg1, reg);
- else if(*w == 2)
+ break;
+ case 2:
gshift(AADD, reg1, SHIFT_LL, 1, reg);
- else if(*w == 4)
+ break;
+ case 4:
gshift(AADD, reg1, SHIFT_LL, 2, reg);
- else if(*w == 8)
+ break;
+ case 8:
gshift(AADD, reg1, SHIFT_LL, 3, reg);
+ break;
+ }
naddr(reg1, a, 1);
a->type = D_OREG;
@@ -1799,19 +1911,6 @@ oindex_const:
n1.type = types[tptr];
n1.xoffset = Array_array;
gmove(&n1, reg);
-
- } else
- if(!debug['B']) {
- if(v < 0) {
- yyerror("out of bounds on array");
- } else
- if(o & OPtrto) {
- if(v >= l->type->type->bound)
- yyerror("out of bounds on array");
- } else
- if(v >= l->type->bound) {
- yyerror("out of bounds on array");
- }
}
n2 = *reg;
diff --git a/src/cmd/5g/list.c b/src/cmd/5g/list.c
index 19027829c..ce74d6478 100644
--- a/src/cmd/5g/list.c
+++ b/src/cmd/5g/list.c
@@ -49,28 +49,28 @@ listinit(void)
int
Pconv(Fmt *fp)
{
- char str[STRINGSZ];
+ char str[STRINGSZ], str1[STRINGSZ];
Prog *p;
p = va_arg(fp->args, Prog*);
sconsize = 8;
switch(p->as) {
default:
+ snprint(str1, sizeof(str1), "%A%C", p->as, p->scond);
if(p->reg == NREG)
- snprint(str, sizeof(str), "%.4ld (%L) %-7A%C %D,%D",
- p->loc, p->lineno, p->as, p->scond, &p->from, &p->to);
- else if (p->from.type != D_FREG)
- snprint(str, sizeof(str), "%.4ld (%L) %-7A%C %D,R%d,%D",
- p->loc, p->lineno, p->as, p->scond, &p->from, p->reg, &p->to);
+ snprint(str, sizeof(str), "%.4d (%L) %-7s %D,%D",
+ p->loc, p->lineno, str1, &p->from, &p->to);
else
- snprint(str, sizeof(str), "%.4ld (%L) %-7A%C %D,F%d,%D",
+ if (p->from.type != D_FREG) {
+ snprint(str, sizeof(str), "%.4d (%L) %-7s %D,R%d,%D",
+ p->loc, p->lineno, str1, &p->from, p->reg, &p->to);
+ } else
+ snprint(str, sizeof(str), "%.4d (%L) %-7A%C %D,F%d,%D",
p->loc, p->lineno, p->as, p->scond, &p->from, p->reg, &p->to);
break;
case ADATA:
- case AINIT:
- case ADYNT:
- snprint(str, sizeof(str), "%.4ld (%L) %-7A %D/%d,%D",
+ snprint(str, sizeof(str), "%.4d (%L) %-7A %D/%d,%D",
p->loc, p->lineno, p->as, &p->from, p->reg, &p->to);
break;
}
@@ -154,10 +154,16 @@ Dconv(Fmt *fp)
break;
case D_BRANCH:
- if(a->sym != S)
- sprint(str, "%s+%d(APC)", a->sym->name, a->offset);
- else
- sprint(str, "%d(APC)", a->offset);
+ if(a->branch == P || a->branch->loc == 0) {
+ if(a->sym != S)
+ sprint(str, "%s+%d(APC)", a->sym->name, a->offset);
+ else
+ sprint(str, "%d(APC)", a->offset);
+ } else
+ if(a->sym != S)
+ sprint(str, "%s+%d(APC)", a->sym->name, a->branch->loc);
+ else
+ sprint(str, "%d(APC)", a->branch->loc);
break;
case D_FCONST:
diff --git a/src/cmd/5g/opt.h b/src/cmd/5g/opt.h
index 1b0366290..9a4e17571 100644
--- a/src/cmd/5g/opt.h
+++ b/src/cmd/5g/opt.h
@@ -128,7 +128,7 @@ Reg* rega(void);
int rcmp(const void*, const void*);
void regopt(Prog*);
void addmove(Reg*, int, int, int);
-Bits mkvar(Reg*, Adr*);
+Bits mkvar(Reg *r, Adr *a, int);
void prop(Reg*, Bits, Bits);
void loopit(Reg*, int32);
void synch(Reg*, Bits);
diff --git a/src/cmd/5g/peep.c b/src/cmd/5g/peep.c
new file mode 100644
index 000000000..32333e8a9
--- /dev/null
+++ b/src/cmd/5g/peep.c
@@ -0,0 +1,1511 @@
+// Inferno utils/5c/peep.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5g/peep.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+
+#include "gg.h"
+#include "opt.h"
+
+int xtramodes(Reg*, Adr*);
+int shiftprop(Reg *r);
+void constprop(Adr *c1, Adr *v1, Reg *r);
+void predicate(void);
+int copyau1(Prog *p, Adr *v);
+int isdconst(Addr *a);
+
+void
+peep(void)
+{
+ Reg *r, *r1, *r2;
+ Prog *p, *p1;
+ int t;
+/*
+ * complete R structure
+ */
+ t = 0;
+ for(r=firstr; r!=R; r=r1) {
+ r1 = r->link;
+ if(r1 == R)
+ break;
+ p = r->prog->link;
+ while(p != r1->prog)
+ switch(p->as) {
+ default:
+ r2 = rega();
+ r->link = r2;
+ r2->link = r1;
+
+ r2->prog = p;
+ r2->p1 = r;
+ r->s1 = r2;
+ r2->s1 = r1;
+ r1->p1 = r2;
+
+ r = r2;
+ t++;
+
+ case ADATA:
+ case AGLOBL:
+ case ANAME:
+ case ASIGNAME:
+ p = p->link;
+ }
+ }
+
+loop1:
+ t = 0;
+ for(r=firstr; r!=R; r=r->link) {
+ p = r->prog;
+ switch(p->as) {
+ case ASLL:
+ case ASRL:
+ case ASRA:
+ /*
+ * elide shift into D_SHIFT operand of subsequent instruction
+ */
+ if(shiftprop(r)) {
+ excise(r);
+ t++;
+ break;
+ }
+ break;
+
+ case AMOVW:
+ case AMOVF:
+ case AMOVD:
+ if(!regtyp(&p->to))
+ break;
+ if(isdconst(&p->from)) {
+ constprop(&p->from, &p->to, r->s1);
+ break;
+ }
+ if(!regtyp(&p->from))
+ break;
+ if(p->from.type != p->to.type)
+ break;
+ if(copyprop(r)) {
+ excise(r);
+ t++;
+ break;
+ }
+ if(subprop(r) && copyprop(r)) {
+ excise(r);
+ t++;
+ break;
+ }
+ }
+ }
+ if(t)
+ goto loop1;
+ /*
+ * look for MOVB x,R; MOVB R,R
+ */
+ for(r=firstr; r!=R; r=r->link) {
+ p = r->prog;
+ switch(p->as) {
+ default:
+ continue;
+ case AEOR:
+ /*
+ * EOR -1,x,y => MVN x,y
+ */
+ if(isdconst(&p->from) && p->from.offset == -1) {
+ p->as = AMVN;
+ p->from.type = D_REG;
+ if(p->reg != NREG)
+ p->from.reg = p->reg;
+ else
+ p->from.reg = p->to.reg;
+ p->reg = NREG;
+ }
+ continue;
+ case AMOVH:
+ case AMOVHU:
+ case AMOVB:
+ case AMOVBU:
+ if(p->to.type != D_REG)
+ continue;
+ break;
+ }
+ r1 = r->link;
+ if(r1 == R)
+ continue;
+ p1 = r1->prog;
+ if(p1->as != p->as)
+ continue;
+ if(p1->from.type != D_REG || p1->from.reg != p->to.reg)
+ continue;
+ if(p1->to.type != D_REG || p1->to.reg != p->to.reg)
+ continue;
+ excise(r1);
+ }
+
+ for(r=firstr; r!=R; r=r->link) {
+ p = r->prog;
+ switch(p->as) {
+ case AMOVW:
+ case AMOVB:
+ case AMOVBU:
+ if(p->from.type == D_OREG && p->from.offset == 0)
+ xtramodes(r, &p->from);
+ else if(p->to.type == D_OREG && p->to.offset == 0)
+ xtramodes(r, &p->to);
+ else
+ continue;
+ break;
+ case ACMP:
+ /*
+ * elide CMP $0,x if calculation of x can set condition codes
+ */
+ if(isdconst(&p->from) || p->from.offset != 0)
+ continue;
+ r2 = r->s1;
+ if(r2 == R)
+ continue;
+ t = r2->prog->as;
+ switch(t) {
+ default:
+ continue;
+ case ABEQ:
+ case ABNE:
+ case ABMI:
+ case ABPL:
+ break;
+ case ABGE:
+ t = ABPL;
+ break;
+ case ABLT:
+ t = ABMI;
+ break;
+ case ABHI:
+ t = ABNE;
+ break;
+ case ABLS:
+ t = ABEQ;
+ break;
+ }
+ r1 = r;
+ do
+ r1 = uniqp(r1);
+ while (r1 != R && r1->prog->as == ANOP);
+ if(r1 == R)
+ continue;
+ p1 = r1->prog;
+ if(p1->to.type != D_REG)
+ continue;
+ if(p1->to.reg != p->reg)
+ if(!(p1->as == AMOVW && p1->from.type == D_REG && p1->from.reg == p->reg))
+ continue;
+ switch(p1->as) {
+ default:
+ continue;
+ case AMOVW:
+ if(p1->from.type != D_REG)
+ continue;
+ case AAND:
+ case AEOR:
+ case AORR:
+ case ABIC:
+ case AMVN:
+ case ASUB:
+ case ARSB:
+ case AADD:
+ case AADC:
+ case ASBC:
+ case ARSC:
+ break;
+ }
+ p1->scond |= C_SBIT;
+ r2->prog->as = t;
+ excise(r);
+ continue;
+ }
+ }
+
+ predicate();
+}
+
+Reg*
+uniqp(Reg *r)
+{
+ Reg *r1;
+
+ r1 = r->p1;
+ if(r1 == R) {
+ r1 = r->p2;
+ if(r1 == R || r1->p2link != R)
+ return R;
+ } else
+ if(r->p2 != R)
+ return R;
+ return r1;
+}
+
+Reg*
+uniqs(Reg *r)
+{
+ Reg *r1;
+
+ r1 = r->s1;
+ if(r1 == R) {
+ r1 = r->s2;
+ if(r1 == R)
+ return R;
+ } else
+ if(r->s2 != R)
+ return R;
+ return r1;
+}
+
+int
+regtyp(Adr *a)
+{
+
+ if(a->type == D_REG)
+ return 1;
+ if(a->type == D_FREG)
+ return 1;
+ return 0;
+}
+
+/*
+ * the idea is to substitute
+ * one register for another
+ * from one MOV to another
+ * MOV a, R0
+ * ADD b, R0 / no use of R1
+ * MOV R0, R1
+ * would be converted to
+ * MOV a, R1
+ * ADD b, R1
+ * MOV R1, R0
+ * hopefully, then the former or latter MOV
+ * will be eliminated by copy propagation.
+ */
+int
+subprop(Reg *r0)
+{
+ Prog *p;
+ Adr *v1, *v2;
+ Reg *r;
+ int t;
+
+ p = r0->prog;
+ v1 = &p->from;
+ if(!regtyp(v1))
+ return 0;
+ v2 = &p->to;
+ if(!regtyp(v2))
+ return 0;
+ for(r=uniqp(r0); r!=R; r=uniqp(r)) {
+ if(uniqs(r) == R)
+ break;
+ p = r->prog;
+ switch(p->as) {
+ case ABL:
+ return 0;
+
+ case ACMP:
+ case ACMN:
+ case AADD:
+ case ASUB:
+ case ARSB:
+ case ASLL:
+ case ASRL:
+ case ASRA:
+ case AORR:
+ case AAND:
+ case AEOR:
+ case AMUL:
+ case ADIV:
+ case ADIVU:
+
+ case ACMPF:
+ case ACMPD:
+ case AADDD:
+ case AADDF:
+ case ASUBD:
+ case ASUBF:
+ case AMULD:
+ case AMULF:
+ case ADIVD:
+ case ADIVF:
+ if(p->to.type == v1->type)
+ if(p->to.reg == v1->reg) {
+ if(p->reg == NREG)
+ p->reg = p->to.reg;
+ goto gotit;
+ }
+ break;
+
+ case AMOVF:
+ case AMOVD:
+ case AMOVW:
+ if(p->to.type == v1->type)
+ if(p->to.reg == v1->reg)
+ goto gotit;
+ break;
+
+ case AMOVM:
+ t = 1<<v2->reg;
+ if((p->from.type == D_CONST && (p->from.offset&t)) ||
+ (p->to.type == D_CONST && (p->to.offset&t)))
+ return 0;
+ break;
+ }
+ if(copyau(&p->from, v2) ||
+ copyau1(p, v2) ||
+ copyau(&p->to, v2))
+ break;
+ if(copysub(&p->from, v1, v2, 0) ||
+ copysub1(p, v1, v2, 0) ||
+ copysub(&p->to, v1, v2, 0))
+ break;
+ }
+ return 0;
+
+gotit:
+ copysub(&p->to, v1, v2, 1);
+ if(debug['P']) {
+ print("gotit: %D->%D\n%P", v1, v2, r->prog);
+ if(p->from.type == v2->type)
+ print(" excise");
+ print("\n");
+ }
+ for(r=uniqs(r); r!=r0; r=uniqs(r)) {
+ p = r->prog;
+ copysub(&p->from, v1, v2, 1);
+ copysub1(p, v1, v2, 1);
+ copysub(&p->to, v1, v2, 1);
+ if(debug['P'])
+ print("%P\n", r->prog);
+ }
+ t = v1->reg;
+ v1->reg = v2->reg;
+ v2->reg = t;
+ if(debug['P'])
+ print("%P last\n", r->prog);
+ return 1;
+}
+
+/*
+ * The idea is to remove redundant copies.
+ * v1->v2 F=0
+ * (use v2 s/v2/v1/)*
+ * set v1 F=1
+ * use v2 return fail
+ * -----------------
+ * v1->v2 F=0
+ * (use v2 s/v2/v1/)*
+ * set v1 F=1
+ * set v2 return success
+ */
+int
+copyprop(Reg *r0)
+{
+ Prog *p;
+ Adr *v1, *v2;
+ Reg *r;
+
+ p = r0->prog;
+ v1 = &p->from;
+ v2 = &p->to;
+ if(copyas(v1, v2))
+ return 1;
+ for(r=firstr; r!=R; r=r->link)
+ r->active = 0;
+ return copy1(v1, v2, r0->s1, 0);
+}
+
+int
+copy1(Adr *v1, Adr *v2, Reg *r, int f)
+{
+ int t;
+ Prog *p;
+
+ if(r->active) {
+ if(debug['P'])
+ print("act set; return 1\n");
+ return 1;
+ }
+ r->active = 1;
+ if(debug['P'])
+ print("copy %D->%D f=%d\n", v1, v2, f);
+ for(; r != R; r = r->s1) {
+ p = r->prog;
+ if(debug['P'])
+ print("%P", p);
+ if(!f && uniqp(r) == R) {
+ f = 1;
+ if(debug['P'])
+ print("; merge; f=%d", f);
+ }
+ t = copyu(p, v2, A);
+ switch(t) {
+ case 2: /* rar, cant split */
+ if(debug['P'])
+ print("; %Drar; return 0\n", v2);
+ return 0;
+
+ case 3: /* set */
+ if(debug['P'])
+ print("; %Dset; return 1\n", v2);
+ return 1;
+
+ case 1: /* used, substitute */
+ case 4: /* use and set */
+ if(f) {
+ if(!debug['P'])
+ return 0;
+ if(t == 4)
+ print("; %Dused+set and f=%d; return 0\n", v2, f);
+ else
+ print("; %Dused and f=%d; return 0\n", v2, f);
+ return 0;
+ }
+ if(copyu(p, v2, v1)) {
+ if(debug['P'])
+ print("; sub fail; return 0\n");
+ return 0;
+ }
+ if(debug['P'])
+ print("; sub%D/%D", v2, v1);
+ if(t == 4) {
+ if(debug['P'])
+ print("; %Dused+set; return 1\n", v2);
+ return 1;
+ }
+ break;
+ }
+ if(!f) {
+ t = copyu(p, v1, A);
+ if(!f && (t == 2 || t == 3 || t == 4)) {
+ f = 1;
+ if(debug['P'])
+ print("; %Dset and !f; f=%d", v1, f);
+ }
+ }
+ if(debug['P'])
+ print("\n");
+ if(r->s2)
+ if(!copy1(v1, v2, r->s2, f))
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * The idea is to remove redundant constants.
+ * $c1->v1
+ * ($c1->v2 s/$c1/v1)*
+ * set v1 return
+ * The v1->v2 should be eliminated by copy propagation.
+ */
+void
+constprop(Adr *c1, Adr *v1, Reg *r)
+{
+ Prog *p;
+
+ if(debug['P'])
+ print("constprop %D->%D\n", c1, v1);
+ for(; r != R; r = r->s1) {
+ p = r->prog;
+ if(debug['P'])
+ print("%P", p);
+ if(uniqp(r) == R) {
+ if(debug['P'])
+ print("; merge; return\n");
+ return;
+ }
+ if(p->as == AMOVW && copyas(&p->from, c1)) {
+ if(debug['P'])
+ print("; sub%D/%D", &p->from, v1);
+ p->from = *v1;
+ } else if(copyu(p, v1, A) > 1) {
+ if(debug['P'])
+ print("; %Dset; return\n", v1);
+ return;
+ }
+ if(debug['P'])
+ print("\n");
+ if(r->s2)
+ constprop(c1, v1, r->s2);
+ }
+}
+
+/*
+ * ASLL x,y,w
+ * .. (not use w, not set x y w)
+ * AXXX w,a,b (a != w)
+ * .. (not use w)
+ * (set w)
+ * ----------- changed to
+ * ..
+ * AXXX (x<<y),a,b
+ * ..
+ */
+#define FAIL(msg) { if(debug['P']) print("\t%s; FAILURE\n", msg); return 0; }
+int
+shiftprop(Reg *r)
+{
+ Reg *r1;
+ Prog *p, *p1, *p2;
+ int n, o;
+ Adr a;
+
+ p = r->prog;
+ if(p->to.type != D_REG)
+ FAIL("BOTCH: result not reg");
+ n = p->to.reg;
+ a = zprog.from;
+ if(p->reg != NREG && p->reg != p->to.reg) {
+ a.type = D_REG;
+ a.reg = p->reg;
+ }
+ if(debug['P'])
+ print("shiftprop\n%P", p);
+ r1 = r;
+ for(;;) {
+ /* find first use of shift result; abort if shift operands or result are changed */
+ r1 = uniqs(r1);
+ if(r1 == R)
+ FAIL("branch");
+ if(uniqp(r1) == R)
+ FAIL("merge");
+ p1 = r1->prog;
+ if(debug['P'])
+ print("\n%P", p1);
+ switch(copyu(p1, &p->to, A)) {
+ case 0: /* not used or set */
+ if((p->from.type == D_REG && copyu(p1, &p->from, A) > 1) ||
+ (a.type == D_REG && copyu(p1, &a, A) > 1))
+ FAIL("args modified");
+ continue;
+ case 3: /* set, not used */
+ FAIL("BOTCH: noref");
+ }
+ break;
+ }
+ /* check whether substitution can be done */
+ switch(p1->as) {
+ default:
+ FAIL("non-dpi");
+ case AAND:
+ case AEOR:
+ case AADD:
+ case AADC:
+ case AORR:
+ case ASUB:
+ case ARSB:
+ case ASBC:
+ case ARSC:
+ if(p1->reg == n || (p1->reg == NREG && p1->to.type == D_REG && p1->to.reg == n)) {
+ if(p1->from.type != D_REG)
+ FAIL("can't swap");
+ p1->reg = p1->from.reg;
+ p1->from.reg = n;
+ switch(p1->as) {
+ case ASUB:
+ p1->as = ARSB;
+ break;
+ case ARSB:
+ p1->as = ASUB;
+ break;
+ case ASBC:
+ p1->as = ARSC;
+ break;
+ case ARSC:
+ p1->as = ASBC;
+ break;
+ }
+ if(debug['P'])
+ print("\t=>%P", p1);
+ }
+ case ABIC:
+ case ACMP:
+ case ACMN:
+ if(p1->reg == n)
+ FAIL("can't swap");
+ if(p1->reg == NREG && p1->to.reg == n)
+ FAIL("shift result used twice");
+ case AMVN:
+ if(p1->from.type == D_SHIFT)
+ FAIL("shift result used in shift");
+ if(p1->from.type != D_REG || p1->from.reg != n)
+ FAIL("BOTCH: where is it used?");
+ break;
+ }
+ /* check whether shift result is used subsequently */
+ p2 = p1;
+ if(p1->to.reg != n)
+ for (;;) {
+ r1 = uniqs(r1);
+ if(r1 == R)
+ FAIL("inconclusive");
+ p1 = r1->prog;
+ if(debug['P'])
+ print("\n%P", p1);
+ switch(copyu(p1, &p->to, A)) {
+ case 0: /* not used or set */
+ continue;
+ case 3: /* set, not used */
+ break;
+ default:/* used */
+ FAIL("reused");
+ }
+ break;
+ }
+
+ /* make the substitution */
+ p2->from.type = D_SHIFT;
+ p2->from.reg = NREG;
+ o = p->reg;
+ if(o == NREG)
+ o = p->to.reg;
+
+ switch(p->from.type){
+ case D_CONST:
+ o |= (p->from.offset&0x1f)<<7;
+ break;
+ case D_REG:
+ o |= (1<<4) | (p->from.reg<<8);
+ break;
+ }
+ switch(p->as){
+ case ASLL:
+ o |= 0<<5;
+ break;
+ case ASRL:
+ o |= 1<<5;
+ break;
+ case ASRA:
+ o |= 2<<5;
+ break;
+ }
+ p2->from.offset = o;
+ if(debug['P'])
+ print("\t=>%P\tSUCCEED\n", p2);
+ return 1;
+}
+
+Reg*
+findpre(Reg *r, Adr *v)
+{
+ Reg *r1;
+
+ for(r1=uniqp(r); r1!=R; r=r1,r1=uniqp(r)) {
+ if(uniqs(r1) != r)
+ return R;
+ switch(copyu(r1->prog, v, A)) {
+ case 1: /* used */
+ case 2: /* read-alter-rewrite */
+ return R;
+ case 3: /* set */
+ case 4: /* set and used */
+ return r1;
+ }
+ }
+ return R;
+}
+
+Reg*
+findinc(Reg *r, Reg *r2, Adr *v)
+{
+ Reg *r1;
+ Prog *p;
+
+
+ for(r1=uniqs(r); r1!=R && r1!=r2; r=r1,r1=uniqs(r)) {
+ if(uniqp(r1) != r)
+ return R;
+ switch(copyu(r1->prog, v, A)) {
+ case 0: /* not touched */
+ continue;
+ case 4: /* set and used */
+ p = r1->prog;
+ if(p->as == AADD)
+ if(isdconst(&p->from))
+ if(p->from.offset > -4096 && p->from.offset < 4096)
+ return r1;
+ default:
+ return R;
+ }
+ }
+ return R;
+}
+
+int
+nochange(Reg *r, Reg *r2, Prog *p)
+{
+ Adr a[3];
+ int i, n;
+
+ if(r == r2)
+ return 1;
+ n = 0;
+ if(p->reg != NREG && p->reg != p->to.reg) {
+ a[n].type = D_REG;
+ a[n++].reg = p->reg;
+ }
+ switch(p->from.type) {
+ case D_SHIFT:
+ a[n].type = D_REG;
+ a[n++].reg = p->from.offset&0xf;
+ case D_REG:
+ a[n].type = D_REG;
+ a[n++].reg = p->from.reg;
+ }
+ if(n == 0)
+ return 1;
+ for(; r!=R && r!=r2; r=uniqs(r)) {
+ p = r->prog;
+ for(i=0; i<n; i++)
+ if(copyu(p, &a[i], A) > 1)
+ return 0;
+ }
+ return 1;
+}
+
+int
+findu1(Reg *r, Adr *v)
+{
+ for(; r != R; r = r->s1) {
+ if(r->active)
+ return 0;
+ r->active = 1;
+ switch(copyu(r->prog, v, A)) {
+ case 1: /* used */
+ case 2: /* read-alter-rewrite */
+ case 4: /* set and used */
+ return 1;
+ case 3: /* set */
+ return 0;
+ }
+ if(r->s2)
+ if (findu1(r->s2, v))
+ return 1;
+ }
+ return 0;
+}
+
+int
+finduse(Reg *r, Adr *v)
+{
+ Reg *r1;
+
+ for(r1=firstr; r1!=R; r1=r1->link)
+ r1->active = 0;
+ return findu1(r, v);
+}
+
+int
+xtramodes(Reg *r, Adr *a)
+{
+ Reg *r1, *r2, *r3;
+ Prog *p, *p1;
+ Adr v;
+
+ p = r->prog;
+ if(debug['h'] && p->as == AMOVB && p->from.type == D_OREG) /* byte load */
+ return 0;
+ v = *a;
+ v.type = D_REG;
+ r1 = findpre(r, &v);
+ if(r1 != R) {
+ p1 = r1->prog;
+ if(p1->to.type == D_REG && p1->to.reg == v.reg)
+ switch(p1->as) {
+ case AADD:
+ if(p1->from.type == D_REG ||
+ (p1->from.type == D_SHIFT && (p1->from.offset&(1<<4)) == 0 &&
+ (p->as != AMOVB || (a == &p->from && (p1->from.offset&~0xf) == 0))) ||
+ (p1->from.type == D_CONST &&
+ p1->from.offset > -4096 && p1->from.offset < 4096))
+ if(nochange(uniqs(r1), r, p1)) {
+ if(a != &p->from || v.reg != p->to.reg)
+ if (finduse(r->s1, &v)) {
+ if(p1->reg == NREG || p1->reg == v.reg)
+ /* pre-indexing */
+ p->scond |= C_WBIT;
+ else return 0;
+ }
+ switch (p1->from.type) {
+ case D_REG:
+ /* register offset */
+ a->type = D_SHIFT;
+ a->offset = p1->from.reg;
+ break;
+ case D_SHIFT:
+ /* scaled register offset */
+ a->type = D_SHIFT;
+ case D_CONST:
+ /* immediate offset */
+ a->offset = p1->from.offset;
+ break;
+ }
+ if(p1->reg != NREG)
+ a->reg = p1->reg;
+ excise(r1);
+ return 1;
+ }
+ break;
+ case AMOVW:
+ if(p1->from.type == D_REG)
+ if((r2 = findinc(r1, r, &p1->from)) != R) {
+ for(r3=uniqs(r2); r3->prog->as==ANOP; r3=uniqs(r3))
+ ;
+ if(r3 == r) {
+ /* post-indexing */
+ p1 = r2->prog;
+ a->reg = p1->to.reg;
+ a->offset = p1->from.offset;
+ p->scond |= C_PBIT;
+ if(!finduse(r, &r1->prog->to))
+ excise(r1);
+ excise(r2);
+ return 1;
+ }
+ }
+ break;
+ }
+ }
+ if(a != &p->from || a->reg != p->to.reg)
+ if((r1 = findinc(r, R, &v)) != R) {
+ /* post-indexing */
+ p1 = r1->prog;
+ a->offset = p1->from.offset;
+ p->scond |= C_PBIT;
+ excise(r1);
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * return
+ * 1 if v only used (and substitute),
+ * 2 if read-alter-rewrite
+ * 3 if set
+ * 4 if set and used
+ * 0 otherwise (not touched)
+ */
+int
+copyu(Prog *p, Adr *v, Adr *s)
+{
+
+ switch(p->as) {
+
+ default:
+ if(debug['P'])
+ print(" (?)");
+ return 2;
+
+ case AMOVM:
+ if(v->type != D_REG)
+ return 0;
+ if(p->from.type == D_CONST) { /* read reglist, read/rar */
+ if(s != A) {
+ if(p->from.offset&(1<<v->reg))
+ return 1;
+ if(copysub(&p->to, v, s, 1))
+ return 1;
+ return 0;
+ }
+ if(copyau(&p->to, v)) {
+ if(p->scond&C_WBIT)
+ return 2;
+ return 1;
+ }
+ if(p->from.offset&(1<<v->reg))
+ return 1;
+ } else { /* read/rar, write reglist */
+ if(s != A) {
+ if(p->to.offset&(1<<v->reg))
+ return 1;
+ if(copysub(&p->from, v, s, 1))
+ return 1;
+ return 0;
+ }
+ if(copyau(&p->from, v)) {
+ if(p->scond&C_WBIT)
+ return 2;
+ if(p->to.offset&(1<<v->reg))
+ return 4;
+ return 1;
+ }
+ if(p->to.offset&(1<<v->reg))
+ return 3;
+ }
+ return 0;
+
+ case ANOP: /* read, write */
+ case AMOVW:
+ case AMOVF:
+ case AMOVD:
+ case AMOVH:
+ case AMOVHU:
+ case AMOVB:
+ case AMOVBU:
+ case AMOVDW:
+ case AMOVWD:
+ case AMOVFD:
+ case AMOVDF:
+ if(p->scond&(C_WBIT|C_PBIT))
+ if(v->type == D_REG) {
+ if(p->from.type == D_OREG || p->from.type == D_SHIFT) {
+ if(p->from.reg == v->reg)
+ return 2;
+ } else {
+ if(p->to.reg == v->reg)
+ return 2;
+ }
+ }
+ if(s != A) {
+ if(copysub(&p->from, v, s, 1))
+ return 1;
+ if(!copyas(&p->to, v))
+ if(copysub(&p->to, v, s, 1))
+ return 1;
+ return 0;
+ }
+ if(copyas(&p->to, v)) {
+ if(copyau(&p->from, v))
+ return 4;
+ return 3;
+ }
+ if(copyau(&p->from, v))
+ return 1;
+ if(copyau(&p->to, v))
+ return 1;
+ return 0;
+
+ case AADD: /* read, read, write */
+ case ASUB:
+ case ARSB:
+ case ASLL:
+ case ASRL:
+ case ASRA:
+ case AORR:
+ case AAND:
+ case AEOR:
+ case AMUL:
+ case ADIV:
+ case ADIVU:
+ case AADDF:
+ case AADDD:
+ case ASUBF:
+ case ASUBD:
+ case AMULF:
+ case AMULD:
+ case ADIVF:
+ case ADIVD:
+
+ case ACMPF:
+ case ACMPD:
+ case ACMP:
+ case ACMN:
+ case ACASE:
+ if(s != A) {
+ if(copysub(&p->from, v, s, 1))
+ return 1;
+ if(copysub1(p, v, s, 1))
+ return 1;
+ if(!copyas(&p->to, v))
+ if(copysub(&p->to, v, s, 1))
+ return 1;
+ return 0;
+ }
+ if(copyas(&p->to, v)) {
+ if(p->reg == NREG)
+ p->reg = p->to.reg;
+ if(copyau(&p->from, v))
+ return 4;
+ if(copyau1(p, v))
+ return 4;
+ return 3;
+ }
+ if(copyau(&p->from, v))
+ return 1;
+ if(copyau1(p, v))
+ return 1;
+ if(copyau(&p->to, v))
+ return 1;
+ return 0;
+
+ case ABEQ: /* read, read */
+ case ABNE:
+ case ABCS:
+ case ABHS:
+ case ABCC:
+ case ABLO:
+ case ABMI:
+ case ABPL:
+ case ABVS:
+ case ABVC:
+ case ABHI:
+ case ABLS:
+ case ABGE:
+ case ABLT:
+ case ABGT:
+ case ABLE:
+ if(s != A) {
+ if(copysub(&p->from, v, s, 1))
+ return 1;
+ return copysub1(p, v, s, 1);
+ }
+ if(copyau(&p->from, v))
+ return 1;
+ if(copyau1(p, v))
+ return 1;
+ return 0;
+
+ case AB: /* funny */
+ if(s != A) {
+ if(copysub(&p->to, v, s, 1))
+ return 1;
+ return 0;
+ }
+ if(copyau(&p->to, v))
+ return 1;
+ return 0;
+
+ case ARET: /* funny */
+ if(v->type == D_REG)
+ if(v->reg == REGRET)
+ return 2;
+ if(v->type == D_FREG)
+ if(v->reg == FREGRET)
+ return 2;
+
+ case ABL: /* funny */
+ if(v->type == D_REG) {
+ if(v->reg <= REGEXT && v->reg > exregoffset)
+ return 2;
+ if(v->reg == REGARG)
+ return 2;
+ }
+ if(v->type == D_FREG)
+ if(v->reg <= FREGEXT && v->reg > exfregoffset)
+ return 2;
+
+ if(s != A) {
+ if(copysub(&p->to, v, s, 1))
+ return 1;
+ return 0;
+ }
+ if(copyau(&p->to, v))
+ return 4;
+ return 3;
+
+ case ATEXT: /* funny */
+ if(v->type == D_REG)
+ if(v->reg == REGARG)
+ return 3;
+ return 0;
+ }
+ return 0;
+}
+
+int
+a2type(Prog *p)
+{
+
+ switch(p->as) {
+
+ case ACMP:
+ case ACMN:
+
+ case AADD:
+ case ASUB:
+ case ARSB:
+ case ASLL:
+ case ASRL:
+ case ASRA:
+ case AORR:
+ case AAND:
+ case AEOR:
+ case AMUL:
+ case ADIV:
+ case ADIVU:
+ return D_REG;
+
+ case ACMPF:
+ case ACMPD:
+
+ case AADDF:
+ case AADDD:
+ case ASUBF:
+ case ASUBD:
+ case AMULF:
+ case AMULD:
+ case ADIVF:
+ case ADIVD:
+ return D_FREG;
+ }
+ return D_NONE;
+}
+
+/*
+ * direct reference,
+ * could be set/use depending on
+ * semantics
+ */
+int
+copyas(Adr *a, Adr *v)
+{
+
+ if(regtyp(v)) {
+ if(a->type == v->type)
+ if(a->reg == v->reg)
+ return 1;
+ } else
+ if(v->type == D_CONST) { /* for constprop */
+ if(a->type == v->type)
+ if(a->name == v->name)
+ if(a->sym == v->sym)
+ if(a->reg == v->reg)
+ if(a->offset == v->offset)
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * either direct or indirect
+ */
+int
+copyau(Adr *a, Adr *v)
+{
+
+ if(copyas(a, v))
+ return 1;
+ if(v->type == D_REG) {
+ if(a->type == D_CONST && a->reg != NREG) {
+ if(v->reg == a->reg)
+ return 1;
+ } else
+ if(a->type == D_OREG) {
+ if(v->reg == a->reg)
+ return 1;
+ } else
+ if(a->type == D_REGREG) {
+ if(v->reg == a->reg)
+ return 1;
+ if(a->offset == v->reg)
+ return 1;
+ } else
+ if(a->type == D_SHIFT) {
+ if((a->offset&0xf) == v->reg)
+ return 1;
+ if((a->offset&(1<<4)) && (a->offset>>8) == v->reg)
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int
+copyau1(Prog *p, Adr *v)
+{
+
+ if(regtyp(v)) {
+ if(a2type(p) == v->type)
+ if(p->reg == v->reg) {
+ if(a2type(p) != v->type)
+ print("botch a2type %P\n", p);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * substitute s for v in a
+ * return failure to substitute
+ */
+int
+copysub(Adr *a, Adr *v, Adr *s, int f)
+{
+
+ if(f)
+ if(copyau(a, v)) {
+ if(a->type == D_SHIFT) {
+ if((a->offset&0xf) == v->reg)
+ a->offset = (a->offset&~0xf)|s->reg;
+ if((a->offset&(1<<4)) && (a->offset>>8) == v->reg)
+ a->offset = (a->offset&~(0xf<<8))|(s->reg<<8);
+ } else
+ if(a->type == D_REGREG) {
+ if(a->offset == v->reg)
+ a->offset = s->reg;
+ if(a->reg == v->reg)
+ a->reg = s->reg;
+ } else
+ a->reg = s->reg;
+ }
+ return 0;
+}
+
+int
+copysub1(Prog *p1, Adr *v, Adr *s, int f)
+{
+
+ if(f)
+ if(copyau1(p1, v))
+ p1->reg = s->reg;
+ return 0;
+}
+
+struct {
+ int opcode;
+ int notopcode;
+ int scond;
+ int notscond;
+} predinfo[] = {
+ { ABEQ, ABNE, 0x0, 0x1, },
+ { ABNE, ABEQ, 0x1, 0x0, },
+ { ABCS, ABCC, 0x2, 0x3, },
+ { ABHS, ABLO, 0x2, 0x3, },
+ { ABCC, ABCS, 0x3, 0x2, },
+ { ABLO, ABHS, 0x3, 0x2, },
+ { ABMI, ABPL, 0x4, 0x5, },
+ { ABPL, ABMI, 0x5, 0x4, },
+ { ABVS, ABVC, 0x6, 0x7, },
+ { ABVC, ABVS, 0x7, 0x6, },
+ { ABHI, ABLS, 0x8, 0x9, },
+ { ABLS, ABHI, 0x9, 0x8, },
+ { ABGE, ABLT, 0xA, 0xB, },
+ { ABLT, ABGE, 0xB, 0xA, },
+ { ABGT, ABLE, 0xC, 0xD, },
+ { ABLE, ABGT, 0xD, 0xC, },
+};
+
+typedef struct {
+ Reg *start;
+ Reg *last;
+ Reg *end;
+ int len;
+} Joininfo;
+
+enum {
+ Join,
+ Split,
+ End,
+ Branch,
+ Setcond,
+ Toolong
+};
+
+enum {
+ Falsecond,
+ Truecond,
+ Delbranch,
+ Keepbranch
+};
+
+int
+isbranch(Prog *p)
+{
+ return (ABEQ <= p->as) && (p->as <= ABLE);
+}
+
+int
+predicable(Prog *p)
+{
+ switch(p->as) {
+ case ANOP:
+ case AXXX:
+ case ADATA:
+ case AGLOBL:
+ case AGOK:
+ case AHISTORY:
+ case ANAME:
+ case ASIGNAME:
+ case ATEXT:
+ case AWORD:
+ case ABCASE:
+ case ACASE:
+ return 0;
+ }
+ if(isbranch(p))
+ return 0;
+ return 1;
+}
+
+/*
+ * Depends on an analysis of the encodings performed by 5l.
+ * These seem to be all of the opcodes that lead to the "S" bit
+ * being set in the instruction encodings.
+ *
+ * C_SBIT may also have been set explicitly in p->scond.
+ */
+int
+modifiescpsr(Prog *p)
+{
+ switch(p->as) {
+ case ATST:
+ case ATEQ:
+ case ACMN:
+ case ACMP:
+ case AMULU:
+ case ADIVU:
+ case AMUL:
+ case ADIV:
+ case AMOD:
+ case AMODU:
+ case ABL:
+ return 1;
+ }
+ if(p->scond & C_SBIT)
+ return 1;
+ return 0;
+}
+
+/*
+ * Find the maximal chain of instructions starting with r which could
+ * be executed conditionally
+ */
+int
+joinsplit(Reg *r, Joininfo *j)
+{
+ j->start = r;
+ j->last = r;
+ j->len = 0;
+ do {
+ if (r->p2 && (r->p1 || r->p2->p2link)) {
+ j->end = r;
+ return Join;
+ }
+ if (r->s1 && r->s2) {
+ j->end = r;
+ return Split;
+ }
+ j->last = r;
+ if (r->prog->as != ANOP)
+ j->len++;
+ if (!r->s1 && !r->s2) {
+ j->end = r->link;
+ return End;
+ }
+ if (r->s2) {
+ j->end = r->s2;
+ return Branch;
+ }
+ if (modifiescpsr(r->prog)) {
+ j->end = r->s1;
+ return Setcond;
+ }
+ r = r->s1;
+ } while (j->len < 4);
+ j->end = r;
+ return Toolong;
+}
+
+Reg*
+successor(Reg *r)
+{
+ if(r->s1)
+ return r->s1;
+ else
+ return r->s2;
+}
+
+void
+applypred(Reg *rstart, Joininfo *j, int cond, int branch)
+{
+ int pred;
+ Reg *r;
+
+ if(j->len == 0)
+ return;
+ if(cond == Truecond)
+ pred = predinfo[rstart->prog->as - ABEQ].scond;
+ else
+ pred = predinfo[rstart->prog->as - ABEQ].notscond;
+
+ for(r = j->start;; r = successor(r)) {
+ if (r->prog->as == AB) {
+ if (r != j->last || branch == Delbranch)
+ excise(r);
+ else {
+ if (cond == Truecond)
+ r->prog->as = predinfo[rstart->prog->as - ABEQ].opcode;
+ else
+ r->prog->as = predinfo[rstart->prog->as - ABEQ].notopcode;
+ }
+ }
+ else
+ if (predicable(r->prog))
+ r->prog->scond = (r->prog->scond&~C_SCOND)|pred;
+ if (r->s1 != r->link) {
+ r->s1 = r->link;
+ r->link->p1 = r;
+ }
+ if (r == j->last)
+ break;
+ }
+}
+
+void
+predicate(void)
+{
+ Reg *r;
+ int t1, t2;
+ Joininfo j1, j2;
+
+ for(r=firstr; r!=R; r=r->link) {
+ if (isbranch(r->prog)) {
+ t1 = joinsplit(r->s1, &j1);
+ t2 = joinsplit(r->s2, &j2);
+ if(j1.last->link != j2.start)
+ continue;
+ if(j1.end == j2.end)
+ if((t1 == Branch && (t2 == Join || t2 == Setcond)) ||
+ (t2 == Join && (t1 == Join || t1 == Setcond))) {
+ applypred(r, &j1, Falsecond, Delbranch);
+ applypred(r, &j2, Truecond, Delbranch);
+ excise(r);
+ continue;
+ }
+ if(t1 == End || t1 == Branch) {
+ applypred(r, &j1, Falsecond, Keepbranch);
+ excise(r);
+ continue;
+ }
+ }
+ }
+}
+
+int
+isdconst(Addr *a)
+{
+ if(a->type == D_CONST && a->reg == NREG)
+ return 1;
+ return 0;
+}
diff --git a/src/cmd/5g/reg.c b/src/cmd/5g/reg.c
new file mode 100644
index 000000000..5011e75cc
--- /dev/null
+++ b/src/cmd/5g/reg.c
@@ -0,0 +1,1329 @@
+// Inferno utils/5c/reg.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5g/reg.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+
+#include "gg.h"
+#include "opt.h"
+
+#define P2R(p) (Reg*)(p->reg)
+
+ void addsplits(void);
+ int noreturn(Prog *p);
+static int first = 0;
+
+Reg*
+rega(void)
+{
+ Reg *r;
+
+ r = freer;
+ if(r == R) {
+ r = mal(sizeof(*r));
+ } else
+ freer = r->link;
+
+ *r = zreg;
+ return r;
+}
+
+int
+rcmp(const void *a1, const void *a2)
+{
+ Rgn *p1, *p2;
+ int c1, c2;
+
+ p1 = (Rgn*)a1;
+ p2 = (Rgn*)a2;
+ c1 = p2->cost;
+ c2 = p1->cost;
+ if(c1 -= c2)
+ return c1;
+ return p2->varno - p1->varno;
+}
+
+static void
+setoutvar(void)
+{
+ Type *t;
+ Node *n;
+ Addr a;
+ Iter save;
+ Bits bit;
+ int z;
+
+ t = structfirst(&save, getoutarg(curfn->type));
+ while(t != T) {
+ n = nodarg(t, 1);
+ a = zprog.from;
+ naddr(n, &a, 0);
+ bit = mkvar(R, &a, 0);
+ for(z=0; z<BITS; z++)
+ ovar.b[z] |= bit.b[z];
+ t = structnext(&save);
+ }
+//if(bany(b))
+//print("ovars = %Q\n", &ovar);
+}
+
+void
+excise(Reg *r)
+{
+ Prog *p;
+
+ p = r->prog;
+ p->as = ANOP;
+ p->scond = zprog.scond;
+ p->from = zprog.from;
+ p->to = zprog.to;
+ p->reg = zprog.reg;
+}
+
+static void
+setaddrs(Bits bit)
+{
+ int i, n;
+ Var *v;
+ Sym *s;
+
+ while(bany(&bit)) {
+ // convert each bit to a variable
+ i = bnum(bit);
+ s = var[i].sym;
+ 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)
+ v->addr = 2;
+ }
+ }
+}
+
+void
+regopt(Prog *firstp)
+{
+ Reg *r, *r1;
+ Prog *p;
+ int i, z, nr;
+ uint32 vreg;
+ Bits bit;
+
+return; // disabled for the moment
+ if(first == 0) {
+ fmtinstall('Q', Qconv);
+ }
+ first++;
+
+ if(debug['K']) {
+ if(first != 20)
+ return;
+// debug['R'] = 2;
+// debug['P'] = 2;
+ print("optimizing %S\n", curfn->nname->sym);
+ }
+
+ // count instructions
+ nr = 0;
+ for(p=firstp; p!=P; p=p->link)
+ nr++;
+
+ // if too big dont bother
+ if(nr >= 10000) {
+// print("********** %S is too big (%d)\n", curfn->nname->sym, nr);
+ return;
+ }
+
+ r1 = R;
+ firstr = R;
+ lastr = R;
+ nvar = 0;
+ regbits = 0;
+ for(z=0; z<BITS; z++) {
+ externs.b[z] = 0;
+ params.b[z] = 0;
+ consts.b[z] = 0;
+ addrs.b[z] = 0;
+ ovar.b[z] = 0;
+ }
+
+ // build list of return variables
+ setoutvar();
+
+ /*
+ * pass 1
+ * build aux data structure
+ * allocate pcs
+ * find use and set of variables
+ */
+ nr = 0;
+ for(p=firstp; p != P; p = p->link) {
+ switch(p->as) {
+ case ADATA:
+ case AGLOBL:
+ case ANAME:
+ case ASIGNAME:
+ continue;
+ }
+ r = rega();
+ nr++;
+ if(firstr == R) {
+ firstr = r;
+ lastr = r;
+ } else {
+ lastr->link = r;
+ r->p1 = lastr;
+ lastr->s1 = r;
+ lastr = r;
+ }
+ r->prog = p;
+ p->regp = r;
+
+ r1 = r->p1;
+ if(r1 != R) {
+ switch(r1->prog->as) {
+ case ARET:
+ case AB:
+ case ARFE:
+ r->p1 = R;
+ r1->s1 = R;
+ }
+ }
+
+ /*
+ * left side always read
+ */
+ bit = mkvar(r, &p->from, p->as==AMOVW);
+ for(z=0; z<BITS; z++)
+ r->use1.b[z] |= bit.b[z];
+
+ /*
+ * right side depends on opcode
+ */
+ bit = mkvar(r, &p->to, 0);
+ if(bany(&bit))
+ switch(p->as) {
+ default:
+ yyerror("reg: unknown op: %A", p->as);
+ break;
+
+ /*
+ * right side write
+ */
+ case ANOP:
+ case AMOVB:
+ case AMOVBU:
+ case AMOVH:
+ case AMOVHU:
+ case AMOVW:
+ case AMOVF:
+ case AMOVD:
+ for(z=0; z<BITS; z++)
+ r->set.b[z] |= bit.b[z];
+ break;
+
+ /*
+ * funny
+ */
+ case ABL:
+ for(z=0; z<BITS; z++)
+ addrs.b[z] |= bit.b[z];
+ break;
+ }
+
+ if(p->as == AMOVM) {
+ z = p->to.offset;
+ if(p->from.type == D_CONST)
+ z = p->from.offset;
+ for(i=0; z; i++) {
+ if(z&1)
+ regbits |= RtoB(i);
+ z >>= 1;
+ }
+ }
+ }
+ if(firstr == R)
+ return;
+
+ /*
+ * pass 2
+ * turn branch references to pointers
+ * build back pointers
+ */
+ for(r=firstr; r!=R; r=r->link) {
+ p = r->prog;
+ if(p->to.type == D_BRANCH) {
+ if(p->to.branch == P)
+ fatal("pnil %P", p);
+ r1 = p->to.branch->regp;
+ if(r1 == R)
+ fatal("rnil %P", p);
+ if(r1 == r) {
+ //fatal("ref to self %P", p);
+ continue;
+ }
+ r->s2 = r1;
+ r->p2link = r1->p2;
+ r1->p2 = r;
+ }
+ }
+ if(debug['R']) {
+ p = firstr->prog;
+ print("\n%L %D\n", p->lineno, &p->from);
+ }
+
+ /*
+ * pass 2.5
+ * find looping structure
+ */
+ for(r = firstr; r != R; r = r->link)
+ r->active = 0;
+ change = 0;
+ loopit(firstr, nr);
+
+ /*
+ * pass 3
+ * iterate propagating usage
+ * back until flow graph is complete
+ */
+loop1:
+ change = 0;
+ for(r = firstr; r != R; r = r->link)
+ r->active = 0;
+ for(r = firstr; r != R; r = r->link)
+ if(r->prog->as == ARET)
+ prop(r, zbits, zbits);
+loop11:
+ /* pick up unreachable code */
+ i = 0;
+ for(r = firstr; r != R; r = r1) {
+ r1 = r->link;
+ if(r1 && r1->active && !r->active) {
+ prop(r, zbits, zbits);
+ i = 1;
+ }
+ }
+ if(i)
+ goto loop11;
+ if(change)
+ goto loop1;
+
+
+ /*
+ * pass 4
+ * iterate propagating register/variable synchrony
+ * forward until graph is complete
+ */
+loop2:
+ change = 0;
+ for(r = firstr; r != R; r = r->link)
+ r->active = 0;
+ synch(firstr, zbits);
+ if(change)
+ goto loop2;
+
+ addsplits();
+
+ if(debug['R'] > 1) {
+ print("\nprop structure:\n");
+ for(r = firstr; r != R; r = r->link) {
+ print("%d:%P", r->loop, r->prog);
+ for(z=0; z<BITS; z++) {
+ bit.b[z] = r->set.b[z] |
+ r->refahead.b[z] | r->calahead.b[z] |
+ r->refbehind.b[z] | r->calbehind.b[z] |
+ r->use1.b[z] | r->use2.b[z];
+ }
+
+ if(bany(&bit)) {
+ print("\t");
+ if(bany(&r->use1))
+ print(" u1=%Q", r->use1);
+ if(bany(&r->use2))
+ print(" u2=%Q", r->use2);
+ if(bany(&r->set))
+ print(" st=%Q", r->set);
+ if(bany(&r->refahead))
+ print(" ra=%Q", r->refahead);
+ if(bany(&r->calahead))
+ print(" ca=%Q", r->calahead);
+ if(bany(&r->refbehind))
+ print(" rb=%Q", r->refbehind);
+ if(bany(&r->calbehind))
+ print(" cb=%Q", r->calbehind);
+ }
+ print("\n");
+ }
+ }
+
+ /*
+ * pass 5
+ * isolate regions
+ * calculate costs (paint1)
+ */
+ r = firstr;
+ if(r) {
+ for(z=0; z<BITS; z++)
+ bit.b[z] = (r->refahead.b[z] | r->calahead.b[z]) &
+ ~(externs.b[z] | params.b[z] | addrs.b[z] | consts.b[z]);
+ if(bany(&bit) & !r->refset) {
+ // should never happen - all variables are preset
+ if(debug['w'])
+ print("%L: used and not set: %Q\n", r->prog->lineno, bit);
+ r->refset = 1;
+ }
+ }
+
+ for(r = firstr; r != R; r = r->link)
+ r->act = zbits;
+ rgp = region;
+ nregion = 0;
+ for(r = firstr; r != R; r = r->link) {
+ for(z=0; z<BITS; z++)
+ bit.b[z] = r->set.b[z] &
+ ~(r->refahead.b[z] | r->calahead.b[z] | addrs.b[z]);
+ if(bany(&bit) && !r->refset) {
+ if(debug['w'])
+ print("%L: set and not used: %Q\n", r->prog->lineno, bit);
+ r->refset = 1;
+ excise(r);
+ }
+ for(z=0; z<BITS; z++)
+ bit.b[z] = LOAD(r) & ~(r->act.b[z] | addrs.b[z]);
+ while(bany(&bit)) {
+ i = bnum(bit);
+ rgp->enter = r;
+ rgp->varno = i;
+ change = 0;
+ if(debug['R'] > 1)
+ print("\n");
+ paint1(r, i);
+ bit.b[i/32] &= ~(1L<<(i%32));
+ if(change <= 0) {
+ if(debug['R'])
+ print("%L $%d: %Q\n",
+ r->prog->lineno, change, blsh(i));
+ continue;
+ }
+ rgp->cost = change;
+ nregion++;
+ if(nregion >= NRGN) {
+ if(debug['R'] > 1)
+ print("too many regions\n");
+ goto brk;
+ }
+ rgp++;
+ }
+ }
+brk:
+ qsort(region, nregion, sizeof(region[0]), rcmp);
+
+ /*
+ * pass 6
+ * determine used registers (paint2)
+ * replace code (paint3)
+ */
+ rgp = region;
+ for(i=0; i<nregion; i++) {
+ bit = blsh(rgp->varno);
+ vreg = paint2(rgp->enter, rgp->varno);
+ vreg = allreg(vreg, rgp);
+ if(debug['R']) {
+ if(rgp->regno >= NREG)
+ print("%L $%d F%d: %Q\n",
+ rgp->enter->prog->lineno,
+ rgp->cost,
+ rgp->regno-NREG,
+ bit);
+ else
+ print("%L $%d R%d: %Q\n",
+ rgp->enter->prog->lineno,
+ rgp->cost,
+ rgp->regno,
+ bit);
+ }
+ if(rgp->regno != 0)
+ paint3(rgp->enter, rgp->varno, vreg, rgp->regno);
+ rgp++;
+ }
+ /*
+ * pass 7
+ * peep-hole on basic block
+ */
+ if(!debug['R'] || debug['P']) {
+// peep();
+ }
+
+ /*
+ * last pass
+ * eliminate nops
+ * free aux structures
+ */
+ for(p = firstp; p != P; p = p->link) {
+ while(p->link != P && p->link->as == ANOP)
+ p->link = p->link->link;
+ if(p->to.type == D_BRANCH)
+ while(p->to.branch != P && p->to.branch->as == ANOP)
+ p->to.branch = p->to.branch->link;
+ }
+ if(r1 != R) {
+ r1->link = freer;
+ freer = firstr;
+ }
+}
+
+void
+addsplits(void)
+{
+ Reg *r, *r1;
+ int z, i;
+ Bits bit;
+
+ for(r = firstr; r != R; r = r->link) {
+ if(r->loop > 1)
+ continue;
+ if(r->prog->as == ABL)
+ continue;
+ for(r1 = r->p2; r1 != R; r1 = r1->p2link) {
+ if(r1->loop <= 1)
+ continue;
+ for(z=0; z<BITS; z++)
+ bit.b[z] = r1->calbehind.b[z] &
+ (r->refahead.b[z] | r->use1.b[z] | r->use2.b[z]) &
+ ~(r->calahead.b[z] & addrs.b[z]);
+ while(bany(&bit)) {
+ i = bnum(bit);
+ bit.b[i/32] &= ~(1L << (i%32));
+ }
+ }
+ }
+}
+
+/*
+ * add mov b,rn
+ * just after r
+ */
+void
+addmove(Reg *r, int bn, int rn, int f)
+{
+ Prog *p, *p1;
+ Adr *a;
+ Var *v;
+
+ p1 = mal(sizeof(*p1));
+ *p1 = zprog;
+ p = r->prog;
+
+ p1->link = p->link;
+ p->link = p1;
+ p1->lineno = p->lineno;
+
+ v = var + bn;
+
+ a = &p1->to;
+ a->sym = v->sym;
+ a->name = v->name;
+ a->offset = v->offset;
+ a->etype = v->etype;
+ a->type = D_OREG;
+ if(a->etype == TARRAY || a->sym == S)
+ a->type = D_CONST;
+
+ switch(v->etype) {
+ default:
+ print("What is this %E\n", v->etype);
+
+ case TINT32:
+ case TUINT32:
+ case TPTR32:
+ case TBOOL:
+ p1->as = AMOVW;
+ break;
+ case TINT8:
+ case TUINT8:
+ p1->as = AMOVB;
+ break;
+ case TINT16:
+ case TUINT16:
+ p1->as = AMOVH;
+ break;
+ case TFLOAT32:
+ p1->as = AMOVF;
+ break;
+ case TFLOAT64:
+ p1->as = AMOVD;
+ break;
+ }
+
+ p1->from.type = D_REG;
+ p1->from.reg = rn;
+ if(rn >= NREG) {
+ p1->from.type = D_FREG;
+ p1->from.reg = rn-NREG;
+ }
+ if(!f) {
+ p1->from = *a;
+ *a = zprog.from;
+ a->type = D_REG;
+ a->reg = rn;
+ if(rn >= NREG) {
+ a->type = D_FREG;
+ a->reg = rn-NREG;
+ }
+ if(v->etype == TUINT8)
+ p1->as = AMOVBU;
+ if(v->etype == TUINT16)
+ p1->as = AMOVHU;
+ }
+ if(debug['R'])
+ print("%P\t.a%P\n", p, p1);
+}
+
+static int
+overlap(int32 o1, int w1, int32 o2, int w2)
+{
+ int32 t1, t2;
+
+ t1 = o1+w1;
+ t2 = o2+w2;
+
+ if(!(t1 > o2 && t2 > o1))
+ return 0;
+
+ return 1;
+}
+
+Bits
+mkvar(Reg *r, Adr *a, int docon)
+{
+ Var *v;
+ int i, t, n, et, z, w, flag;
+ int32 o;
+ Bits bit;
+ Sym *s;
+
+ // mark registers used
+ t = a->type;
+ n = D_NONE;
+
+ switch(t) {
+ default:
+ print("type %d %d %D\n", t, a->name, a);
+ goto none;
+
+ case D_CONST:
+ if(a->reg != NREG)
+ r->regu |= RtoB(a->reg);
+ // fallthrough
+
+ case D_NONE:
+ case D_FCONST:
+ case D_BRANCH:
+ goto none;
+
+ case D_REGREG:
+ if(a->offset != NREG)
+ r->regu |= RtoB(a->offset);
+ // fallthrough
+
+ case D_REG:
+ case D_SHIFT:
+ case D_OREG:
+ if(a->reg != NREG)
+ r->regu |= RtoB(a->reg);
+ break;
+
+ case D_FREG:
+ if(a->reg != NREG)
+ r->regu |= FtoB(a->reg);
+ break;
+ }
+
+ switch(a->name) {
+ default:
+ goto none;
+
+ case D_EXTERN:
+ case D_STATIC:
+ case D_AUTO:
+ case D_PARAM:
+ n = a->name;
+ break;
+ }
+
+ flag = 0;
+// if(a->pun)
+// flag = 1;
+
+ s = a->sym;
+ if(s == S)
+ goto none;
+ if(s->name[0] == '.')
+ goto none;
+ et = a->etype;
+ o = a->offset;
+ w = a->width;
+
+ for(i=0; i<nvar; i++) {
+ v = var+i;
+ if(v->sym == s && v->name == n) {
+ if(v->offset == o)
+ if(v->etype == et)
+ if(v->width == w)
+ if(!flag)
+ return blsh(i);
+
+ // if they overlaps, disable both
+ if(overlap(v->offset, v->width, o, w)) {
+ v->addr = 1;
+ flag = 1;
+ }
+ }
+ }
+
+ switch(et) {
+ case 0:
+ case TFUNC:
+ case TARRAY:
+ case TSTRING:
+ goto none;
+ }
+
+ if(nvar >= NVAR) {
+ if(debug['w'] > 1 && s)
+ fatal("variable not optimized: %D", a);
+ 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
+
+ if(debug['R'])
+ print("bit=%2d et=%E pun=%d %D\n", i, et, flag, a);
+
+out:
+ bit = blsh(i);
+ if(n == D_EXTERN || n == D_STATIC)
+ for(z=0; z<BITS; z++)
+ externs.b[z] |= bit.b[z];
+ if(n == D_PARAM)
+ for(z=0; z<BITS; z++)
+ params.b[z] |= bit.b[z];
+
+// if(t == D_CONST) {
+// if(s == S) {
+// for(z=0; z<BITS; z++)
+// consts.b[z] |= bit.b[z];
+// return bit;
+// }
+// if(et != TARRAY)
+// for(z=0; z<BITS; z++)
+// addrs.b[z] |= bit.b[z];
+// for(z=0; z<BITS; z++)
+// params.b[z] |= bit.b[z];
+// return bit;
+// }
+// if(t != D_OREG)
+// goto none;
+
+ return bit;
+
+none:
+ return zbits;
+}
+
+void
+prop(Reg *r, Bits ref, Bits cal)
+{
+ Reg *r1, *r2;
+ int z;
+
+ for(r1 = r; r1 != R; r1 = r1->p1) {
+ for(z=0; z<BITS; z++) {
+ ref.b[z] |= r1->refahead.b[z];
+ if(ref.b[z] != r1->refahead.b[z]) {
+ r1->refahead.b[z] = ref.b[z];
+ change++;
+ }
+ cal.b[z] |= r1->calahead.b[z];
+ if(cal.b[z] != r1->calahead.b[z]) {
+ r1->calahead.b[z] = cal.b[z];
+ change++;
+ }
+ }
+ switch(r1->prog->as) {
+ case ABL:
+ if(noreturn(r1->prog))
+ break;
+ for(z=0; z<BITS; z++) {
+ cal.b[z] |= ref.b[z] | externs.b[z];
+ ref.b[z] = 0;
+ }
+ break;
+
+ case ATEXT:
+ for(z=0; z<BITS; z++) {
+ cal.b[z] = 0;
+ ref.b[z] = 0;
+ }
+ break;
+
+ case ARET:
+ for(z=0; z<BITS; z++) {
+ cal.b[z] = externs.b[z] | ovar.b[z];
+ ref.b[z] = 0;
+ }
+ break;
+ }
+ for(z=0; z<BITS; z++) {
+ ref.b[z] = (ref.b[z] & ~r1->set.b[z]) |
+ r1->use1.b[z] | r1->use2.b[z];
+ cal.b[z] &= ~(r1->set.b[z] | r1->use1.b[z] | r1->use2.b[z]);
+ r1->refbehind.b[z] = ref.b[z];
+ r1->calbehind.b[z] = cal.b[z];
+ }
+ if(r1->active)
+ break;
+ r1->active = 1;
+ }
+ for(; r != r1; r = r->p1)
+ for(r2 = r->p2; r2 != R; r2 = r2->p2link)
+ prop(r2, r->refbehind, r->calbehind);
+}
+
+/*
+ * find looping structure
+ *
+ * 1) find reverse postordering
+ * 2) find approximate dominators,
+ * the actual dominators if the flow graph is reducible
+ * otherwise, dominators plus some other non-dominators.
+ * See Matthew S. Hecht and Jeffrey D. Ullman,
+ * "Analysis of a Simple Algorithm for Global Data Flow Problems",
+ * Conf. Record of ACM Symp. on Principles of Prog. Langs, Boston, Massachusetts,
+ * Oct. 1-3, 1973, pp. 207-217.
+ * 3) find all nodes with a predecessor dominated by the current node.
+ * such a node is a loop head.
+ * recursively, all preds with a greater rpo number are in the loop
+ */
+int32
+postorder(Reg *r, Reg **rpo2r, int32 n)
+{
+ Reg *r1;
+
+ r->rpo = 1;
+ r1 = r->s1;
+ if(r1 && !r1->rpo)
+ n = postorder(r1, rpo2r, n);
+ r1 = r->s2;
+ if(r1 && !r1->rpo)
+ n = postorder(r1, rpo2r, n);
+ rpo2r[n] = r;
+ n++;
+ return n;
+}
+
+int32
+rpolca(int32 *idom, int32 rpo1, int32 rpo2)
+{
+ int32 t;
+
+ if(rpo1 == -1)
+ return rpo2;
+ while(rpo1 != rpo2){
+ if(rpo1 > rpo2){
+ t = rpo2;
+ rpo2 = rpo1;
+ rpo1 = t;
+ }
+ while(rpo1 < rpo2){
+ t = idom[rpo2];
+ if(t >= rpo2)
+ fatal("bad idom");
+ rpo2 = t;
+ }
+ }
+ return rpo1;
+}
+
+int
+doms(int32 *idom, int32 r, int32 s)
+{
+ while(s > r)
+ s = idom[s];
+ return s == r;
+}
+
+int
+loophead(int32 *idom, Reg *r)
+{
+ int32 src;
+
+ src = r->rpo;
+ if(r->p1 != R && doms(idom, src, r->p1->rpo))
+ return 1;
+ for(r = r->p2; r != R; r = r->p2link)
+ if(doms(idom, src, r->rpo))
+ return 1;
+ return 0;
+}
+
+void
+loopmark(Reg **rpo2r, int32 head, Reg *r)
+{
+ if(r->rpo < head || r->active == head)
+ return;
+ r->active = head;
+ r->loop += LOOP;
+ if(r->p1 != R)
+ loopmark(rpo2r, head, r->p1);
+ for(r = r->p2; r != R; r = r->p2link)
+ loopmark(rpo2r, head, r);
+}
+
+void
+loopit(Reg *r, int32 nr)
+{
+ Reg *r1;
+ int32 i, d, me;
+
+ if(nr > maxnr) {
+ rpo2r = mal(nr * sizeof(Reg*));
+ idom = mal(nr * sizeof(int32));
+ maxnr = nr;
+ }
+ d = postorder(r, rpo2r, 0);
+ if(d > nr)
+ fatal("too many reg nodes");
+ nr = d;
+ for(i = 0; i < nr / 2; i++){
+ r1 = rpo2r[i];
+ rpo2r[i] = rpo2r[nr - 1 - i];
+ rpo2r[nr - 1 - i] = r1;
+ }
+ for(i = 0; i < nr; i++)
+ rpo2r[i]->rpo = i;
+
+ idom[0] = 0;
+ for(i = 0; i < nr; i++){
+ r1 = rpo2r[i];
+ me = r1->rpo;
+ d = -1;
+ if(r1->p1 != R && r1->p1->rpo < me)
+ d = r1->p1->rpo;
+ for(r1 = r1->p2; r1 != nil; r1 = r1->p2link)
+ if(r1->rpo < me)
+ d = rpolca(idom, d, r1->rpo);
+ idom[i] = d;
+ }
+
+ for(i = 0; i < nr; i++){
+ r1 = rpo2r[i];
+ r1->loop++;
+ if(r1->p2 != R && loophead(idom, r1))
+ loopmark(rpo2r, i, r1);
+ }
+}
+
+void
+synch(Reg *r, Bits dif)
+{
+ Reg *r1;
+ int z;
+
+ for(r1 = r; r1 != R; r1 = r1->s1) {
+ for(z=0; z<BITS; z++) {
+ dif.b[z] = (dif.b[z] &
+ ~(~r1->refbehind.b[z] & r1->refahead.b[z])) |
+ r1->set.b[z] | r1->regdiff.b[z];
+ if(dif.b[z] != r1->regdiff.b[z]) {
+ r1->regdiff.b[z] = dif.b[z];
+ change++;
+ }
+ }
+ if(r1->active)
+ break;
+ r1->active = 1;
+ for(z=0; z<BITS; z++)
+ dif.b[z] &= ~(~r1->calbehind.b[z] & r1->calahead.b[z]);
+ if(r1->s2 != R)
+ synch(r1->s2, dif);
+ }
+}
+
+uint32
+allreg(uint32 b, Rgn *r)
+{
+ Var *v;
+ int i;
+
+ v = var + r->varno;
+ r->regno = 0;
+ switch(v->etype) {
+
+ default:
+ fatal("unknown etype %d/%E", bitno(b), v->etype);
+ break;
+
+ case TINT8:
+ case TUINT8:
+ case TINT16:
+ case TUINT16:
+ case TINT32:
+ case TUINT32:
+ case TINT:
+ case TUINT:
+ case TUINTPTR:
+ case TBOOL:
+ case TPTR32:
+ i = BtoR(~b);
+ if(i && r->cost >= 0) {
+ r->regno = i;
+ return RtoB(i);
+ }
+ break;
+
+ case TFLOAT32:
+ case TFLOAT64:
+ case TFLOAT:
+ i = BtoF(~b);
+ if(i && r->cost >= 0) {
+ r->regno = i+NREG;
+ return FtoB(i);
+ }
+ break;
+
+ case TINT64:
+ case TUINT64:
+ case TPTR64:
+ case TINTER:
+ case TSTRUCT:
+ case TARRAY:
+ break;
+ }
+ return 0;
+}
+
+void
+paint1(Reg *r, int bn)
+{
+ Reg *r1;
+ Prog *p;
+ int z;
+ uint32 bb;
+
+ z = bn/32;
+ bb = 1L<<(bn%32);
+ if(r->act.b[z] & bb)
+ return;
+ for(;;) {
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ r1 = r->p1;
+ if(r1 == R)
+ break;
+ if(!(r1->refahead.b[z] & bb))
+ break;
+ if(r1->act.b[z] & bb)
+ break;
+ r = r1;
+ }
+
+ if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb) {
+ change -= CLOAD * r->loop;
+ if(debug['R'] > 1)
+ print("%d%P\td %Q $%d\n", r->loop,
+ r->prog, blsh(bn), change);
+ }
+ for(;;) {
+ r->act.b[z] |= bb;
+ p = r->prog;
+
+ if(r->use1.b[z] & bb) {
+ change += CREF * r->loop;
+ if(debug['R'] > 1)
+ print("%d%P\tu1 %Q $%d\n", r->loop,
+ p, blsh(bn), change);
+ }
+
+ if((r->use2.b[z]|r->set.b[z]) & bb) {
+ change += CREF * r->loop;
+ if(debug['R'] > 1)
+ print("%d%P\tu2 %Q $%d\n", r->loop,
+ p, blsh(bn), change);
+ }
+
+ if(STORE(r) & r->regdiff.b[z] & bb) {
+ change -= CLOAD * r->loop;
+ if(debug['R'] > 1)
+ print("%d%P\tst %Q $%d\n", r->loop,
+ p, blsh(bn), change);
+ }
+
+ if(r->refbehind.b[z] & bb)
+ for(r1 = r->p2; r1 != R; r1 = r1->p2link)
+ if(r1->refahead.b[z] & bb)
+ paint1(r1, bn);
+
+ if(!(r->refahead.b[z] & bb))
+ break;
+ r1 = r->s2;
+ if(r1 != R)
+ if(r1->refbehind.b[z] & bb)
+ paint1(r1, bn);
+ r = r->s1;
+ if(r == R)
+ break;
+ if(r->act.b[z] & bb)
+ break;
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ }
+}
+
+uint32
+paint2(Reg *r, int bn)
+{
+ Reg *r1;
+ int z;
+ uint32 bb, vreg;
+
+ z = bn/32;
+ bb = 1L << (bn%32);
+ vreg = regbits;
+ if(!(r->act.b[z] & bb))
+ return vreg;
+ for(;;) {
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ r1 = r->p1;
+ if(r1 == R)
+ break;
+ if(!(r1->refahead.b[z] & bb))
+ break;
+ if(!(r1->act.b[z] & bb))
+ break;
+ r = r1;
+ }
+ for(;;) {
+ r->act.b[z] &= ~bb;
+
+ vreg |= r->regu;
+
+ if(r->refbehind.b[z] & bb)
+ for(r1 = r->p2; r1 != R; r1 = r1->p2link)
+ if(r1->refahead.b[z] & bb)
+ vreg |= paint2(r1, bn);
+
+ if(!(r->refahead.b[z] & bb))
+ break;
+ r1 = r->s2;
+ if(r1 != R)
+ if(r1->refbehind.b[z] & bb)
+ vreg |= paint2(r1, bn);
+ r = r->s1;
+ if(r == R)
+ break;
+ if(!(r->act.b[z] & bb))
+ break;
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ }
+ return vreg;
+}
+
+void
+paint3(Reg *r, int bn, int32 rb, int rn)
+{
+ Reg *r1;
+ Prog *p;
+ int z;
+ uint32 bb;
+
+ z = bn/32;
+ bb = 1L << (bn%32);
+ if(r->act.b[z] & bb)
+ return;
+ for(;;) {
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ r1 = r->p1;
+ if(r1 == R)
+ break;
+ if(!(r1->refahead.b[z] & bb))
+ break;
+ if(r1->act.b[z] & bb)
+ break;
+ r = r1;
+ }
+
+ if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb)
+ addmove(r, bn, rn, 0);
+ for(;;) {
+ r->act.b[z] |= bb;
+ p = r->prog;
+
+ if(r->use1.b[z] & bb) {
+ if(debug['R'])
+ print("%P", p);
+ addreg(&p->from, rn);
+ if(debug['R'])
+ print("\t.c%P\n", p);
+ }
+ if((r->use2.b[z]|r->set.b[z]) & bb) {
+ if(debug['R'])
+ print("%P", p);
+ addreg(&p->to, rn);
+ if(debug['R'])
+ print("\t.c%P\n", p);
+ }
+
+ if(STORE(r) & r->regdiff.b[z] & bb)
+ addmove(r, bn, rn, 1);
+ r->regu |= rb;
+
+ if(r->refbehind.b[z] & bb)
+ for(r1 = r->p2; r1 != R; r1 = r1->p2link)
+ if(r1->refahead.b[z] & bb)
+ paint3(r1, bn, rb, rn);
+
+ if(!(r->refahead.b[z] & bb))
+ break;
+ r1 = r->s2;
+ if(r1 != R)
+ if(r1->refbehind.b[z] & bb)
+ paint3(r1, bn, rb, rn);
+ r = r->s1;
+ if(r == R)
+ break;
+ if(r->act.b[z] & bb)
+ break;
+ if(!(r->refbehind.b[z] & bb))
+ break;
+ }
+}
+
+void
+addreg(Adr *a, int rn)
+{
+
+ a->sym = 0;
+ a->name = D_NONE;
+ a->type = D_REG;
+ a->reg = rn;
+ if(rn >= NREG) {
+ a->type = D_FREG;
+ a->reg = rn-NREG;
+ }
+}
+
+/*
+ * bit reg
+ * 0 R0
+ * 1 R1
+ * ... ...
+ * 10 R10
+ */
+int32
+RtoB(int r)
+{
+
+ if(r < 2 || r >= REGTMP-2) // excluded R9 and R10 for m and g
+ return 0;
+ return 1L << r;
+}
+
+int
+BtoR(int32 b)
+{
+ b &= 0x01fcL; // excluded R9 and R10 for m and g
+ if(b == 0)
+ return 0;
+ return bitno(b);
+}
+
+/*
+ * bit reg
+ * 18 F2
+ * 19 F3
+ * ... ...
+ * 23 F7
+ */
+int32
+FtoB(int f)
+{
+
+ if(f < 2 || f > NFREG-1)
+ return 0;
+ return 1L << (f + 16);
+}
+
+int
+BtoF(int32 b)
+{
+
+ b &= 0xfc0000L;
+ if(b == 0)
+ return 0;
+ return bitno(b) - 16;
+}
+
+static Sym* symlist[10];
+
+int
+noreturn(Prog *p)
+{
+ Sym *s;
+ int i;
+
+ if(symlist[0] == S) {
+ symlist[0] = pkglookup("panicindex", runtimepkg);
+ symlist[1] = pkglookup("panicslice", runtimepkg);
+ symlist[2] = pkglookup("throwinit", runtimepkg);
+ symlist[3] = pkglookup("panic", runtimepkg);
+ }
+
+ s = p->to.sym;
+ if(s == S)
+ return 0;
+ for(i=0; symlist[i]!=S; i++)
+ if(s == symlist[i])
+ return 1;
+ return 0;
+}
diff --git a/src/cmd/5l/5.out.h b/src/cmd/5l/5.out.h
index c06441c1c..a25c0f71d 100644
--- a/src/cmd/5l/5.out.h
+++ b/src/cmd/5l/5.out.h
@@ -58,6 +58,7 @@
#define NFREG 8
#define FREGRET 0
#define FREGEXT 7
+#define FREGTMP 15
/* compiler allocates register variables F0 up */
/* compiler allocates external registers F7 down */
@@ -158,8 +159,8 @@ enum as
ARET,
ATEXT,
AWORD,
- ADYNT,
- AINIT,
+ ADYNT_,
+ AINIT_,
ABCASE,
ACASE,
@@ -188,7 +189,7 @@ enum as
#define C_PBIT (1<<5)
#define C_WBIT (1<<6)
#define C_FBIT (1<<7) /* psr flags-only */
-#define C_UBIT (1<<7) /* up bit */
+#define C_UBIT (1<<7) /* up bit, unsigned bit */
#define C_SCOND_EQ 0
#define C_SCOND_NE 1
@@ -246,6 +247,7 @@ enum as
/* internal only */
#define D_SIZE (D_NONE+40)
+#define D_PCREL (D_NONE+41)
/*
* this is the ranlib header
diff --git a/src/cmd/5l/Makefile b/src/cmd/5l/Makefile
index b9780f098..71798724b 100644
--- a/src/cmd/5l/Makefile
+++ b/src/cmd/5l/Makefile
@@ -2,24 +2,29 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.conf
+include ../../Make.inc
+O:=$(HOST_O)
-TARG=\
- 5l\
+TARG=5l
OFILES=\
asm.$O\
+ data.$O\
elf.$O\
enam.$O\
+ ldelf.$O\
+ ldmacho.$O\
lib.$O\
list.$O\
noop.$O\
obj.$O\
optab.$O\
pass.$O\
+ prof.$O\
thumb.$O\
softfloat.$O\
span.$O\
+ symtab.$O\
go.$O\
HFILES=\
@@ -27,19 +32,12 @@ HFILES=\
../5l/5.out.h\
../ld/elf.h\
-$(TARG): $(OFILES)
- $(LD) -o $(TARG) -L"$(GOROOT)"/lib $(OFILES) -lbio -l9
-
-$(OFILES): $(HFILES)
+include ../../Make.ccmd
enam.c: 5.out.h
sh mkenam
-clean:
- rm -f *.o $(TARG) *.5 enam.c 5.out a.out
-
-install: $(TARG)
- cp $(TARG) "$(GOBIN)"/$(TARG)
+CLEANFILES+=enam.c
%.$O: ../ld/%.c
- $(CC) $(CFLAGS) -c -I. ../ld/$*.c
+ $(HOST_CC) $(HOST_CFLAGS) -c -I. ../ld/$*.c
diff --git a/src/cmd/5l/asm.c b/src/cmd/5l/asm.c
index 45e6e734f..7ceea59b6 100644
--- a/src/cmd/5l/asm.c
+++ b/src/cmd/5l/asm.c
@@ -28,6 +28,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+// Writing object files.
+
#include "l.h"
#include "../ld/lib.h"
#include "../ld/elf.h"
@@ -50,127 +52,11 @@ entryvalue(void)
s = lookup(a, 0);
if(s->type == 0)
return INITTEXT;
- switch(s->type) {
- case STEXT:
- case SLEAF:
- break;
- case SDATA:
- if(dlm)
- return s->value+INITDAT;
- default:
+ if(s->type != STEXT)
diag("entry not text: %s", s->name);
- }
return s->value;
}
-vlong
-addstring(Sym *s, char *str)
-{
- int n, m;
- vlong r;
- Prog *p;
-
- if(s->type == 0)
- s->type = SDATA;
- s->reachable = 1;
- r = s->value;
- n = strlen(str)+1;
- while(n > 0) {
- m = n;
- if(m > NSNAME)
- m = NSNAME;
- p = newdata(s, s->value, m, D_EXTERN);
- p->to.type = D_SCONST;
- p->to.sval = mal(NSNAME);
- memmove(p->to.sval, str, m);
- s->value += m;
- str += m;
- n -= m;
- }
- return r;
-}
-
-vlong
-adduintxx(Sym *s, uint64 v, int wid)
-{
- vlong r;
- Prog *p;
-
- if(s->type == 0)
- s->type = SDATA;
- s->reachable = 1;
- r = s->value;
- p = newdata(s, s->value, wid, D_EXTERN);
- s->value += wid;
- p->to.type = D_CONST;
- p->to.offset = v;
- return r;
-}
-
-vlong
-adduint8(Sym *s, uint8 v)
-{
- return adduintxx(s, v, 1);
-}
-
-vlong
-adduint16(Sym *s, uint16 v)
-{
- return adduintxx(s, v, 2);
-}
-
-vlong
-adduint32(Sym *s, uint32 v)
-{
- return adduintxx(s, v, 4);
-}
-
-vlong
-adduint64(Sym *s, uint64 v)
-{
- return adduintxx(s, v, 8);
-}
-
-vlong
-addaddr(Sym *s, Sym *t)
-{
- vlong r;
- Prog *p;
- enum { Ptrsize = 4 };
-
- if(s->type == 0)
- s->type = SDATA;
- s->reachable = 1;
- r = s->value;
- p = newdata(s, s->value, Ptrsize, D_EXTERN);
- s->value += Ptrsize;
- p->to.type = D_ADDR;
- p->to.index = D_EXTERN;
- p->to.offset = 0;
- p->to.sym = t;
- return r;
-}
-
-vlong
-addsize(Sym *s, Sym *t)
-{
- vlong r;
- Prog *p;
- enum { Ptrsize = 4 };
-
- if(s->type == 0)
- s->type = SDATA;
- s->reachable = 1;
- r = s->value;
- p = newdata(s, s->value, Ptrsize, D_EXTERN);
- s->value += Ptrsize;
- p->to.type = D_SIZE;
- p->to.index = D_EXTERN;
- p->to.offset = 0;
- p->to.sym = t;
- return r;
-}
-
enum {
ElfStrEmpty,
ElfStrInterp,
@@ -188,6 +74,8 @@ enum {
ElfStrGosymtab,
ElfStrGopclntab,
ElfStrShstrtab,
+ ElfStrRelPlt,
+ ElfStrPlt,
NElfStr
};
@@ -209,21 +97,67 @@ needlib(char *name)
return 0;
}
+int nelfsym = 1;
+
+void
+adddynrel(Sym *s, Reloc *r)
+{
+ diag("adddynrel: unsupported binary format");
+}
+
+void
+adddynsym(Sym *s)
+{
+ diag("adddynsym: not implemented");
+}
+
+static void
+elfsetupplt(void)
+{
+ // TODO
+}
+
+int
+archreloc(Reloc *r, Sym *s, vlong *val)
+{
+ return -1;
+}
+
+void
+adddynlib(char *lib)
+{
+ Sym *s;
+
+ if(!needlib(lib))
+ return;
+
+ if(iself) {
+ s = lookup(".dynstr", 0);
+ if(s->size == 0)
+ addstring(s, "");
+ elfwritedynent(lookup(".dynamic", 0), DT_NEEDED, addstring(s, lib));
+ } else {
+ diag("adddynlib: unsupported binary format");
+ }
+}
+
void
doelf(void)
{
- Sym *s, *shstrtab, *dynamic, *dynstr, *d;
- int h, nsym, t;
+ Sym *s, *shstrtab, *dynstr;
if(!iself)
return;
/* predefine strings we need for section headers */
shstrtab = lookup(".shstrtab", 0);
+ shstrtab->type = SELFDATA;
shstrtab->reachable = 1;
+
elfstr[ElfStrEmpty] = addstring(shstrtab, "");
elfstr[ElfStrText] = addstring(shstrtab, ".text");
elfstr[ElfStrData] = addstring(shstrtab, ".data");
+ addstring(shstrtab, ".rodata");
elfstr[ElfStrBss] = addstring(shstrtab, ".bss");
if(!debug['s']) {
elfstr[ElfStrGosymcounts] = addstring(shstrtab, ".gosymcounts");
@@ -241,6 +175,8 @@ doelf(void)
elfstr[ElfStrDynsym] = addstring(shstrtab, ".dynsym");
elfstr[ElfStrDynstr] = addstring(shstrtab, ".dynstr");
elfstr[ElfStrRel] = addstring(shstrtab, ".rel");
+ elfstr[ElfStrRelPlt] = addstring(shstrtab, ".rel.plt");
+ elfstr[ElfStrPlt] = addstring(shstrtab, ".plt");
/* interpreter string */
s = lookup(".interp", 0);
@@ -257,7 +193,8 @@ doelf(void)
s = lookup(".dynstr", 0);
s->type = SELFDATA;
s->reachable = 1;
- addstring(s, "");
+ if(s->size == 0)
+ addstring(s, "");
dynstr = s;
/* relocation table */
@@ -269,92 +206,35 @@ doelf(void)
s = lookup(".got", 0);
s->reachable = 1;
s->type = SELFDATA;
+
+ /* hash */
+ s = lookup(".hash", 0);
+ s->reachable = 1;
+ s->type = SELFDATA;
- /* got.plt - ??? */
+ /* got.plt */
s = lookup(".got.plt", 0);
s->reachable = 1;
- s->type = SELFDATA;
+ s->type = SDATA; // writable, so not SELFDATA
- /* hash */
- s = lookup(".hash", 0);
+ s = lookup(".plt", 0);
+ s->reachable = 1;
+ s->type = SELFDATA;
+
+ s = lookup(".rel.plt", 0);
s->reachable = 1;
s->type = SELFDATA;
+
+ elfsetupplt();
/* define dynamic elf table */
s = lookup(".dynamic", 0);
s->reachable = 1;
s->type = SELFDATA;
- dynamic = s;
-
- /*
- * relocation entries for dynimp symbols
- */
- nsym = 1; // sym 0 is reserved
- for(h=0; h<NHASH; h++) {
- for(s=hash[h]; s!=S; s=s->link) {
- if(!s->reachable || (s->type != SDATA && s->type != SBSS) || s->dynimpname == nil)
- continue;
-
- if(!s->dynexport) {
- d = lookup(".rel", 0);
- addaddr(d, s);
- adduint32(d, ELF32_R_INFO(nsym, R_ARM_ABS32));
- }
-
- nsym++;
-
- d = lookup(".dynsym", 0);
- adduint32(d, addstring(lookup(".dynstr", 0), s->dynimpname));
- /* value */
- if(!s->dynexport)
- adduint32(d, 0);
- else
- addaddr(d, s);
-
- /* size of object */
- adduint32(d, 0);
-
- /* type */
- t = STB_GLOBAL << 4;
- if(s->dynexport && s->type == STEXT)
- t |= STT_FUNC;
- else
- t |= STT_OBJECT;
- adduint8(d, t);
-
- /* reserved */
- adduint8(d, 0);
-
- /* section where symbol is defined */
- if(!s->dynexport)
- adduint16(d, SHN_UNDEF);
- else {
- switch(s->type) {
- default:
- case STEXT:
- t = 9;
- break;
- case SDATA:
- t = 10;
- break;
- case SBSS:
- t = 11;
- break;
- }
- adduint16(d, t);
- }
-
- if(!s->dynexport && needlib(s->dynimplib))
- elfwritedynent(dynamic, DT_NEEDED, addstring(dynstr, s->dynimplib));
- }
- }
-
- elfdynhash(nsym);
/*
* .dynamic table
*/
- s = dynamic;
elfwritedynentsym(s, DT_HASH, lookup(".hash", 0));
elfwritedynentsym(s, DT_SYMTAB, lookup(".dynsym", 0));
elfwritedynent(s, DT_SYMENT, ELF32SYMSIZE);
@@ -365,6 +245,10 @@ doelf(void)
elfwritedynent(s, DT_RELENT, ELF32RELSIZE);
if(rpath)
elfwritedynent(s, DT_RUNPATH, addstring(dynstr, rpath));
+ elfwritedynentsym(s, DT_PLTGOT, lookup(".got.plt", 0));
+ 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_NULL, 0);
}
}
@@ -372,16 +256,18 @@ doelf(void)
vlong
datoff(vlong addr)
{
- if(addr >= INITDAT)
- return addr - INITDAT + rnd(HEADR+textsize, INITRND);
- diag("datoff %#llx", addr);
+ if(addr >= segdata.vaddr)
+ return addr - segdata.vaddr + segdata.fileoff;
+ if(addr >= segtext.vaddr)
+ return addr - segtext.vaddr + segtext.fileoff;
+ diag("datoff %#x", addr);
return 0;
}
void
shsym(Elf64_Shdr *sh, Sym *s)
{
- sh->addr = s->value + INITDAT;
+ sh->addr = symaddr(s);
sh->off = datoff(sh->addr);
sh->size = s->size;
}
@@ -400,103 +286,47 @@ phsh(Elf64_Phdr *ph, Elf64_Shdr *sh)
void
asmb(void)
{
- Prog *p;
- int32 t, etext;
+ int32 t;
int a, dynsym;
- uint32 va, fo, w, symo, startva;
- uint32 symdatva = SYMDATVA;
+ uint32 va, fo, w, startva;
int strtabsize;
- Optab *o;
ElfEhdr *eh;
ElfPhdr *ph, *pph;
ElfShdr *sh;
+ Section *sect;
strtabsize = 0;
- symo = 0;
if(debug['v'])
- Bprint(&bso, "%5.2f asm\n", cputime());
+ Bprint(&bso, "%5.2f asmb\n", cputime());
Bflush(&bso);
- OFFSET = HEADR;
- seek(cout, OFFSET, 0);
- pc = INITTEXT;
- for(p = firstp; p != P; p = p->link) {
- setarch(p);
- if(p->as == ATEXT) {
- curtext = p;
- autosize = p->to.offset + 4;
- }
- if(p->pc != pc) {
- diag("phase error %lux sb %lux",
- p->pc, pc);
- if(!debug['a'])
- prasm(curp);
- pc = p->pc;
- }
- curp = p;
- o = oplook(p); /* could probably avoid this call */
- if(thumb)
- thumbasmout(p, o);
- else
- asmout(p, o);
- pc += o->size;
- }
- while(pc-INITTEXT < textsize) {
- cput(0);
- pc++;
- }
- if(debug['a'])
- Bprint(&bso, "\n");
- Bflush(&bso);
- cflush();
+ sect = segtext.sect;
+ seek(cout, sect->vaddr - segtext.vaddr + segtext.fileoff, 0);
+ codeblk(sect->vaddr, sect->len);
- /* output strings in text segment */
- etext = INITTEXT + textsize;
- for(t = pc; t < etext; t += sizeof(buf)-100) {
- if(etext-t > sizeof(buf)-100)
- datblk(t, sizeof(buf)-100, 1);
- else
- datblk(t, etext-t, 1);
- }
+ /* output read-only data in text segment */
+ sect = segtext.sect->next;
+ seek(cout, sect->vaddr - segtext.vaddr + segtext.fileoff, 0);
+ datblk(sect->vaddr, sect->len);
- /* output section header strings */
- curtext = P;
- switch(HEADTYPE) {
- case 0:
- case 1:
- case 2:
- case 5:
- OFFSET = HEADR+textsize;
- seek(cout, OFFSET, 0);
- break;
- case 3:
- OFFSET = rnd(HEADR+textsize, 4096);
- seek(cout, OFFSET, 0);
- break;
- case 6:
- OFFSET = rnd(HEADR+textsize, INITRND);
- seek(cout, OFFSET, 0);
- break;
- }
- if(dlm){
- char buf[8];
+ if(debug['v'])
+ Bprint(&bso, "%5.2f datblk\n", cputime());
+ Bflush(&bso);
- write(cout, buf, INITDAT-textsize);
- textsize = INITDAT;
- }
- for(t = 0; t < datsize; t += sizeof(buf)-100) {
- if(datsize-t > sizeof(buf)-100)
- datblk(t, sizeof(buf)-100, 0);
- else
- datblk(t, datsize-t, 0);
- }
- cflush();
+ seek(cout, segdata.fileoff, 0);
+ datblk(segdata.vaddr, segdata.filelen);
+
+ /* output read-only data in text segment */
+ sect = segtext.sect->next;
+ seek(cout, sect->vaddr - segtext.vaddr + segtext.fileoff, 0);
+ datblk(sect->vaddr, sect->len);
/* output symbol table */
symsize = 0;
lcsize = 0;
if(!debug['s']) {
+ // TODO: rationalize
if(debug['v'])
Bprint(&bso, "%5.2f sym\n", cputime());
Bflush(&bso);
@@ -508,45 +338,24 @@ asmb(void)
debug['s'] = 1;
break;
case 2:
- OFFSET = HEADR+textsize+datsize;
+ OFFSET = HEADR+textsize+segdata.filelen;
seek(cout, OFFSET, 0);
break;
case 3:
- OFFSET += rnd(datsize, 4096);
+ OFFSET += rnd(segdata.filelen, 4096);
seek(cout, OFFSET, 0);
break;
case 6:
- symo = rnd(HEADR+textsize, INITRND)+datsize+strtabsize;
- symo = rnd(symo, INITRND);
- seek(cout, symo + 8, 0);
+ OFFSET += segdata.filelen;
+ seek(cout, rnd(OFFSET, INITRND), 0);
break;
}
if(!debug['s'])
- asmsym();
- if(debug['v'])
- Bprint(&bso, "%5.2f pc\n", cputime());
- Bflush(&bso);
- if(!debug['s'])
- asmlc();
- if(!debug['s'])
asmthumbmap();
- if(dlm)
- asmdyn();
- if(!debug['s'])
- strnput("", INITRND-(8+symsize+lcsize)%INITRND);
- cflush();
- seek(cout, symo, 0);
- lputl(symsize);
- lputl(lcsize);
- cflush();
- }
- else if(dlm){
- seek(cout, HEADR+textsize+datsize, 0);
- asmdyn();
cflush();
}
- curtext = P;
+ cursym = nil;
if(debug['v'])
Bprint(&bso, "%5.2f header\n", cputime());
Bflush(&bso);
@@ -568,10 +377,10 @@ asmb(void)
lputl(0xef000011); /* SWI - exit code */
lputl(textsize+HEADR); /* text size */
- lputl(datsize); /* data size */
+ lputl(segdata.filelen); /* data size */
lputl(0); /* sym size */
- lputl(bsssize); /* bss size */
+ lputl(segdata.len - segdata.filelen); /* bss size */
lputl(0); /* sym type */
lputl(INITTEXT-HEADR); /* text addr */
lputl(0); /* workspace - ignored */
@@ -586,13 +395,10 @@ asmb(void)
lputl(0xe1a0f00e); /* B (R14) - zero init return */
break;
case 2: /* plan 9 */
- if(dlm)
- lput(0x80000000|0x647); /* magic */
- else
- lput(0x647); /* magic */
+ lput(0x647); /* magic */
lput(textsize); /* sizes */
- lput(datsize);
- lput(bsssize);
+ lput(segdata.filelen);
+ lput(segdata.len - segdata.filelen);
lput(symsize); /* nsyms */
lput(entryvalue()); /* va of entry */
lput(0L);
@@ -601,8 +407,8 @@ asmb(void)
case 3: /* boot for NetBSD */
lput((143<<16)|0413); /* magic */
lputl(rnd(HEADR+textsize, 4096));
- lputl(rnd(datsize, 4096));
- lputl(bsssize);
+ lputl(rnd(segdata.filelen, 4096));
+ lputl(segdata.len - segdata.filelen);
lputl(symsize); /* nsyms */
lputl(entryvalue()); /* va of entry */
lputl(0L);
@@ -650,41 +456,8 @@ asmb(void)
phsh(ph, sh);
}
- ph = newElfPhdr();
- ph->type = PT_LOAD;
- ph->flags = PF_X+PF_R;
- ph->vaddr = va;
- ph->paddr = va;
- ph->off = fo;
- ph->filesz = w;
- ph->memsz = w;
- ph->align = INITRND;
-
- fo = rnd(fo+w, INITRND);
- va = rnd(va+w, INITRND);
- w = datsize;
-
- ph = newElfPhdr();
- ph->type = PT_LOAD;
- ph->flags = PF_W+PF_R;
- ph->off = fo;
- ph->vaddr = va;
- ph->paddr = va;
- ph->filesz = w;
- ph->memsz = w+bsssize;
- ph->align = INITRND;
-
- if(!debug['s']) {
- ph = newElfPhdr();
- ph->type = PT_LOAD;
- ph->flags = PF_R;
- ph->off = symo;
- ph->vaddr = symdatva;
- ph->paddr = symdatva;
- ph->filesz = rnd(8+symsize+lcsize, INITRND);
- ph->memsz = rnd(8+symsize+lcsize, INITRND);
- ph->align = INITRND;
- }
+ elfphload(&segtext);
+ elfphload(&segdata);
/* Dynamic linking sections */
if (!debug['d']) { /* -d suppresses dynamic loader format */
@@ -766,81 +539,23 @@ asmb(void)
ph->flags = PF_W+PF_R;
ph->align = 4;
- fo = ELFRESERVE;
- va = startva + fo;
- w = textsize;
-
- /*
- * The alignments are bigger than they really need
- * to be here, but they are necessary to keep the
- * arm strip from moving everything around.
- */
-
- sh = newElfShdr(elfstr[ElfStrText]);
- sh->type = SHT_PROGBITS;
- sh->flags = SHF_ALLOC+SHF_EXECINSTR;
- sh->addr = va;
- sh->off = fo;
- sh->size = w;
- sh->addralign = ELFRESERVE;
-
- fo = rnd(fo+w, INITRND);
- va = rnd(va+w, INITRND);
- w = datsize;
-
- sh = newElfShdr(elfstr[ElfStrData]);
- sh->type = SHT_PROGBITS;
- sh->flags = SHF_WRITE+SHF_ALLOC;
- sh->addr = va + elfdatsize;
- sh->off = fo + elfdatsize;
- sh->size = w - elfdatsize;
- sh->addralign = INITRND;
-
- fo += w;
- va += w;
- w = bsssize;
-
- sh = newElfShdr(elfstr[ElfStrBss]);
- sh->type = SHT_NOBITS;
- sh->flags = SHF_WRITE+SHF_ALLOC;
- sh->addr = va;
- sh->off = fo;
- sh->size = w;
- sh->addralign = 4;
+ for(sect=segtext.sect; sect!=nil; sect=sect->next)
+ elfshbits(sect);
+ for(sect=segdata.sect; sect!=nil; sect=sect->next)
+ elfshbits(sect);
if (!debug['s']) {
- fo = symo;
- w = 8;
-
sh = newElfShdr(elfstr[ElfStrGosymtab]);
sh->type = SHT_PROGBITS;
sh->flags = SHF_ALLOC;
- sh->off = fo;
- sh->size = w;
- sh->addralign = INITRND;
- sh->addr = symdatva;
-
- fo += w;
- w = symsize;
-
- sh = newElfShdr(elfstr[ElfStrGosymtab]);
- sh->type = SHT_PROGBITS;
- sh->flags = SHF_ALLOC;
- sh->off = fo;
- sh->size = w;
sh->addralign = 1;
- sh->addr = symdatva + 8;
-
- fo += w;
- w = lcsize;
+ shsym(sh, lookup("symtab", 0));
sh = newElfShdr(elfstr[ElfStrGopclntab]);
sh->type = SHT_PROGBITS;
sh->flags = SHF_ALLOC;
- sh->off = fo;
- sh->size = w;
sh->addralign = 1;
- sh->addr = symdatva + 8 + lcsize;
+ shsym(sh, lookup("pclntab", 0));
}
sh = newElfShstrtab(elfstr[ElfStrShstrtab]);
@@ -879,27 +594,16 @@ asmb(void)
}
cflush();
if(debug['c']){
- print("textsize=%ld\n", textsize);
- print("datsize=%ld\n", datsize);
- print("bsssize=%ld\n", bsssize);
- print("symsize=%ld\n", symsize);
- print("lcsize=%ld\n", lcsize);
- print("total=%ld\n", textsize+datsize+bsssize+symsize+lcsize);
+ print("textsize=%d\n", textsize);
+ print("datsize=%d\n", segdata.filelen);
+ print("bsssize=%d\n", segdata.len - segdata.filelen);
+ print("symsize=%d\n", symsize);
+ print("lcsize=%d\n", lcsize);
+ print("total=%d\n", textsize+segdata.len+symsize+lcsize);
}
}
void
-strnput(char *s, int n)
-{
- for(; *s; s++){
- cput(*s);
- n--;
- }
- for(; n > 0; n--)
- cput(0);
-}
-
-void
cput(int c)
{
cbp[0] = c;
@@ -987,7 +691,7 @@ cflush(void)
/* no bug if cbc < 0 since obuf(cbuf) followed by ibuf in buf! */
n = sizeof(buf.cbuf) - cbc;
if(n)
- write(cout, buf.cbuf, n);
+ ewrite(cout, buf.cbuf, n);
cbp = buf.cbuf;
cbc = sizeof(buf.cbuf);
}
@@ -996,223 +700,16 @@ void
nopstat(char *f, Count *c)
{
if(c->outof)
- Bprint(&bso, "%s delay %ld/%ld (%.2f)\n", f,
+ Bprint(&bso, "%s delay %d/%d (%.2f)\n", f,
c->outof - c->count, c->outof,
(double)(c->outof - c->count)/c->outof);
}
-void
-asmsym(void)
-{
- Prog *p;
- Auto *a;
- Sym *s;
- int h;
-
- s = lookup("etext", 0);
- if(s->type == STEXT)
- putsymb(s->name, 'T', s->value, s->version);
-
- for(h=0; h<NHASH; h++)
- for(s=hash[h]; s!=S; s=s->link)
- switch(s->type) {
- case SCONST:
- putsymb(s->name, 'D', s->value, s->version);
- continue;
-
- case SDATA:
- case SELFDATA:
- putsymb(s->name, 'D', s->value+INITDAT, s->version);
- continue;
-
- case SBSS:
- putsymb(s->name, 'B', s->value+INITDAT, s->version);
- continue;
-
- case SFIXED:
- putsymb(s->name, 'B', s->value, s->version);
- continue;
-
- case SSTRING:
- putsymb(s->name, 'T', s->value, s->version);
- continue;
-
- case SFILE:
- putsymb(s->name, 'f', s->value, s->version);
- continue;
- }
-
- for(p=textp; p!=P; p=p->cond) {
- s = p->from.sym;
- if(s->type != STEXT && s->type != SLEAF)
- continue;
-
- /* filenames first */
- for(a=p->to.autom; a; a=a->link)
- if(a->type == D_FILE)
- putsymb(a->asym->name, 'z', a->aoffset, 0);
- else
- if(a->type == D_FILE1)
- putsymb(a->asym->name, 'Z', a->aoffset, 0);
-
- if(!s->reachable)
- continue;
-
- if(s->type == STEXT)
- putsymb(s->name, 'T', s->value, s->version);
- else
- putsymb(s->name, 'L', s->value, s->version);
-
- /* frame, auto and param after */
- putsymb(".frame", 'm', p->to.offset+4, 0);
- for(a=p->to.autom; a; a=a->link)
- if(a->type == D_AUTO)
- putsymb(a->asym->name, 'a', -a->aoffset, 0);
- else
- if(a->type == D_PARAM)
- putsymb(a->asym->name, 'p', a->aoffset, 0);
- }
- if(debug['v'] || debug['n'])
- Bprint(&bso, "symsize = %lud\n", symsize);
- Bflush(&bso);
-}
-
-void
-putsymb(char *s, int t, int32 v, int ver)
-{
- int i, f;
-
- if(t == 'f')
- s++;
- lput(v);
- if(ver)
- t += 'a' - 'A';
- cput(t+0x80); /* 0x80 is variable length */
-
- if(t == 'Z' || t == 'z') {
- cput(s[0]);
- for(i=1; s[i] != 0 || s[i+1] != 0; i += 2) {
- cput(s[i]);
- cput(s[i+1]);
- }
- cput(0);
- cput(0);
- i++;
- }
- else {
- for(i=0; s[i]; i++)
- cput(s[i]);
- cput(0);
- }
- // TODO(rsc): handle go parameter
- lput(0);
-
- symsize += 4 + 1 + i + 1 + 4;
-
- if(debug['n']) {
- if(t == 'z' || t == 'Z') {
- Bprint(&bso, "%c %.8lux ", t, v);
- for(i=1; s[i] != 0 || s[i+1] != 0; i+=2) {
- f = ((s[i]&0xff) << 8) | (s[i+1]&0xff);
- Bprint(&bso, "/%x", f);
- }
- Bprint(&bso, "\n");
- return;
- }
- if(ver)
- Bprint(&bso, "%c %.8lux %s<%d>\n", t, v, s, ver);
- else
- Bprint(&bso, "%c %.8lux %s\n", t, v, s);
- }
-}
-
-#define MINLC 4
-void
-asmlc(void)
-{
- int32 oldpc, oldlc;
- Prog *p;
- int32 v, s;
-
- oldpc = INITTEXT;
- oldlc = 0;
- for(p = firstp; p != P; p = p->link) {
- setarch(p);
- if(p->line == oldlc || p->as == ATEXT || p->as == ANOP) {
- if(p->as == ATEXT)
- curtext = p;
- if(debug['L'])
- Bprint(&bso, "%6lux %P\n",
- p->pc, p);
- continue;
- }
- if(debug['L'])
- Bprint(&bso, "\t\t%6ld", lcsize);
- v = (p->pc - oldpc) / MINLC;
- while(v) {
- s = 127;
- if(v < 127)
- s = v;
- cput(s+128); /* 129-255 +pc */
- if(debug['L'])
- Bprint(&bso, " pc+%ld*%d(%ld)", s, MINLC, s+128);
- v -= s;
- lcsize++;
- }
- s = p->line - oldlc;
- oldlc = p->line;
- oldpc = p->pc + MINLC;
- if(s > 64 || s < -64) {
- cput(0); /* 0 vv +lc */
- cput(s>>24);
- cput(s>>16);
- cput(s>>8);
- cput(s);
- if(debug['L']) {
- if(s > 0)
- Bprint(&bso, " lc+%ld(%d,%ld)\n",
- s, 0, s);
- else
- Bprint(&bso, " lc%ld(%d,%ld)\n",
- s, 0, s);
- Bprint(&bso, "%6lux %P\n",
- p->pc, p);
- }
- lcsize += 5;
- continue;
- }
- if(s > 0) {
- cput(0+s); /* 1-64 +lc */
- if(debug['L']) {
- Bprint(&bso, " lc+%ld(%ld)\n", s, 0+s);
- Bprint(&bso, "%6lux %P\n",
- p->pc, p);
- }
- } else {
- cput(64-s); /* 65-128 -lc */
- if(debug['L']) {
- Bprint(&bso, " lc%ld(%ld)\n", s, 64-s);
- Bprint(&bso, "%6lux %P\n",
- p->pc, p);
- }
- }
- lcsize++;
- }
- while(lcsize & 1) {
- s = 129;
- cput(s);
- lcsize++;
- }
- if(debug['v'] || debug['L'])
- Bprint(&bso, "lcsize = %ld\n", lcsize);
- Bflush(&bso);
-}
-
static void
outt(int32 f, int32 l)
{
if(debug['L'])
- Bprint(&bso, "tmap: %lux-%lux\n", f, l);
+ Bprint(&bso, "tmap: %ux-%ux\n", f, l);
lput(f);
lput(l);
}
@@ -1227,186 +724,46 @@ asmthumbmap(void)
return;
pc = 0;
lastt = -1;
- for(p = firstp; p != P; p = p->link){
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ p = cursym->text;
pc = p->pc - INITTEXT;
- if(p->as == ATEXT){
- setarch(p);
- if(thumb){
- if(p->from.sym->foreign){ // 8 bytes of ARM first
- if(lastt >= 0){
- outt(lastt, pc-1);
- lastt = -1;
- }
- pc += 8;
- }
- if(lastt < 0)
- lastt = pc;
- }
- else{
- if(p->from.sym->foreign){ // 4 bytes of THUMB first
- if(lastt < 0)
- lastt = pc;
- pc += 4;
- }
+ setarch(p);
+ if(thumb){
+ if(p->from.sym->foreign){ // 8 bytes of ARM first
if(lastt >= 0){
outt(lastt, pc-1);
lastt = -1;
}
+ pc += 8;
}
+ if(lastt < 0)
+ lastt = pc;
}
- }
- if(lastt >= 0)
- outt(lastt, pc+1);
-}
-
-void
-datblk(int32 s, int32 n, int str)
-{
- Sym *v;
- Prog *p;
- char *cast;
- int32 a, l, fl, j, d;
- int i, c;
-
- memset(buf.dbuf, 0, n+100);
- for(p = datap; p != P; p = p->link) {
- if(str != (p->from.sym->type == SSTRING))
- continue;
- curp = p;
- a = p->from.sym->value + p->from.offset;
- l = a - s;
- c = p->reg;
- i = 0;
- if(l < 0) {
- if(l+c <= 0)
- continue;
- while(l < 0) {
- l++;
- i++;
- }
- }
- if(l >= n)
- continue;
- if(p->as != AINIT && p->as != ADYNT) {
- for(j=l+(c-i)-1; j>=l; j--)
- if(buf.dbuf[j]) {
- print("%P\n", p);
- diag("multiple initialization");
- break;
- }
- }
- switch(p->to.type) {
- default:
- diag("unknown mode in initialization%P", p);
- break;
-
- case D_FCONST:
- switch(c) {
- default:
- case 4:
- fl = ieeedtof(p->to.ieee);
- cast = (char*)&fl;
- for(; i<c; i++) {
- buf.dbuf[l] = cast[fnuxi4[i]];
- l++;
- }
- break;
- case 8:
- cast = (char*)p->to.ieee;
- for(; i<c; i++) {
- buf.dbuf[l] = cast[fnuxi8[i]];
- l++;
- }
- break;
- }
- break;
-
- case D_SCONST:
- for(; i<c; i++) {
- buf.dbuf[l] = p->to.sval[i];
- l++;
- }
- break;
-
- case D_CONST:
- d = p->to.offset;
- v = p->to.sym;
- if(v) {
- switch(v->type) {
- case SUNDEF:
- ckoff(v, d);
- d += v->value;
- break;
- case STEXT:
- case SLEAF:
- d += v->value;
-#ifdef CALLEEBX
- d += fnpinc(v);
-#else
- if(v->thumb)
- d++; // T bit
-#endif
- break;
- case SSTRING:
- d += v->value;
- break;
- case SDATA:
- case SBSS:
- if(p->to.type == D_SIZE)
- d += v->size;
- else
- d += v->value + INITDAT;
- break;
- }
- if(dlm)
- dynreloc(v, a+INITDAT, 1);
- }
- cast = (char*)&d;
- switch(c) {
- default:
- diag("bad nuxi %d %d%P", c, i, curp);
- break;
- case 1:
- for(; i<c; i++) {
- buf.dbuf[l] = cast[inuxi1[i]];
- l++;
- }
- break;
- case 2:
- for(; i<c; i++) {
- buf.dbuf[l] = cast[inuxi2[i]];
- l++;
- }
- break;
- case 4:
- for(; i<c; i++) {
- buf.dbuf[l] = cast[inuxi4[i]];
- l++;
- }
- break;
- }
- break;
-
- case D_SBIG:
- if(debug['a'] && i == 0) {
- Bprint(&bso, "\t%P\n", curp);
+ else{
+ if(p->from.sym->foreign){ // 4 bytes of THUMB first
+ if(lastt < 0)
+ lastt = pc;
+ pc += 4;
}
- for(; i<c; i++) {
- buf.dbuf[l] = p->to.sbig[i];
- l++;
+ if(lastt >= 0){
+ outt(lastt, pc-1);
+ lastt = -1;
}
- break;
}
+ if(cursym->next == nil)
+ for(; p != P; p = p->link)
+ pc = p->pc = INITTEXT;
}
- write(cout, buf.dbuf, n);
+ if(lastt >= 0)
+ outt(lastt, pc+1);
}
void
-asmout(Prog *p, Optab *o)
+asmout(Prog *p, Optab *o, int32 *out)
{
int32 o1, o2, o3, o4, o5, o6, v;
int r, rf, rt, rt2;
- Sym *s;
+ Reloc *rel;
PP = p;
o1 = 0;
@@ -1416,7 +773,7 @@ PP = p;
o5 = 0;
o6 = 0;
armsize += o->size;
-if(debug['P']) print("%ulx: %P type %d\n", (uint32)(p->pc), p, o->type);
+if(debug['P']) print("%ux: %P type %d\n", (uint32)(p->pc), p, o->type);
switch(o->type) {
default:
diag("unknown asm %d", o->type);
@@ -1424,7 +781,7 @@ if(debug['P']) print("%ulx: %P type %d\n", (uint32)(p->pc), p, o->type);
break;
case 0: /* pseudo ops */
-if(debug['G']) print("%ulx: %s: arm %d %d %d %d\n", (uint32)(p->pc), p->from.sym->name, p->from.sym->thumb, p->from.sym->foreign, p->from.sym->fnptr, p->from.sym->used);
+if(debug['G']) print("%ux: %s: arm %d %d %d\n", (uint32)(p->pc), p->from.sym->name, p->from.sym->thumb, p->from.sym->foreign, p->from.sym->fnptr);
break;
case 1: /* op R,[R],R */
@@ -1485,14 +842,7 @@ if(debug['G']) print("%ulx: %s: arm %d %d %d %d\n", (uint32)(p->pc), p->from.sym
case 5: /* bra s */
v = -8;
- if(p->cond == UP) {
- s = p->to.sym;
- if(s->type != SUNDEF)
- diag("bad branch sym type");
- v = (uint32)s->value >> (Roffset-2);
- dynreloc(s, p->pc, 0);
- }
- else if(p->cond != P)
+ if(p->cond != P)
v = (p->cond->pc - pc) - 8;
#ifdef CALLEEBX
if(p->as == ABL)
@@ -1553,18 +903,17 @@ if(debug['G']) print("%ulx: %s: arm %d %d %d %d\n", (uint32)(p->pc), p->from.sym
break;
case 11: /* word */
- switch(aclass(&p->to)) {
- case C_LCON:
- if(!dlm)
- break;
- if(p->to.name != D_EXTERN && p->to.name != D_STATIC)
- break;
- case C_ADDR:
- if(p->to.sym->type == SUNDEF)
- ckoff(p->to.sym, p->to.offset);
- dynreloc(p->to.sym, p->pc, 1);
- }
+ aclass(&p->to);
o1 = instoffset;
+ if(p->to.sym != S) {
+ rel = addrel(cursym);
+ rel->off = pc - cursym->value;
+ rel->siz = 4;
+ rel->type = D_ADDR;
+ rel->sym = p->to.sym;
+ rel->add = p->to.offset;
+ o1 = 0;
+ }
break;
case 12: /* movw $lcon, reg */
@@ -1890,38 +1239,15 @@ if(debug['G']) print("%ulx: %s: arm %d %d %d %d\n", (uint32)(p->pc), p->from.sym
case 54: /* floating point arith */
o1 = oprrr(p->as, p->scond);
- if(p->from.type == D_FCONST) {
- rf = chipfloat(p->from.ieee);
- if(rf < 0){
- diag("invalid floating-point immediate\n%P", p);
- rf = 0;
- }
- rf |= (1<<3);
- } else
- rf = p->from.reg;
+ rf = p->from.reg;
rt = p->to.reg;
r = p->reg;
- if(p->to.type == D_NONE)
- rt = 0; /* CMP[FD] */
- else if(o1 & (1<<15))
- r = 0; /* monadic */
- else if(r == NREG)
+ if(r == NREG) {
r = rt;
- o1 |= rf | (r<<16) | (rt<<12);
- break;
-
- case 55: /* floating point fix and float */
- o1 = oprrr(p->as, p->scond);
- rf = p->from.reg;
- rt = p->to.reg;
- if(p->to.type == D_NONE){
- rt = 0;
- diag("to.type==D_NONE (asm/fp)");
+ if(p->as == AMOVF || p->as == AMOVD)
+ r = 0;
}
- if(p->from.type == D_REG)
- o1 |= (rf<<12) | (rt<<16);
- else
- o1 |= rf | (rt<<12);
+ o1 |= rf | (r<<16) | (rt<<12);
break;
case 56: /* move to FP[CS]R */
@@ -1983,11 +1309,8 @@ if(debug['G']) print("%ulx: %s: arm %d %d %d %d\n", (uint32)(p->pc), p->from.sym
break;
case 63: /* bcase */
- if(p->cond != P) {
+ if(p->cond != P)
o1 = p->cond->pc;
- if(dlm)
- dynreloc(S, p->pc, 1);
- }
break;
/* reloc ops */
@@ -2114,7 +1437,7 @@ if(debug['G']) print("%ulx: %s: arm %d %d %d %d\n", (uint32)(p->pc), p->from.sym
if(p->to.sym->thumb)
v |= 1; // T bit
o1 = olr(8, REGPC, REGTMP, p->scond&C_SCOND); // mov 8(PC), Rtmp
- o2 = oprrr(AADD, p->scond) | immrot(8) | (REGPC<<16) | (REGLINK<<12); // add 8,PC, LR
+ o2 = oprrr(AADD, p->scond) | immrot(8) | (REGPC<<16) | (REGLINK<<12); // add 8,PC, LR
o3 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | REGTMP; // bx Rtmp
o4 = opbra(AB, 14); // B over o6
o5 = v;
@@ -2132,7 +1455,7 @@ if(debug['G']) print("%ulx: %s: arm %d %d %d %d\n", (uint32)(p->pc), p->from.sym
o1 |= immrot(instoffset);
o1 |= p->to.reg << 16;
o1 |= REGTMP << 12;
- o2 = oprrr(AADD, p->scond) | immrot(0) | (REGPC<<16) | (REGLINK<<12); // mov PC, LR
+ o2 = oprrr(AADD, p->scond) | immrot(0) | (REGPC<<16) | (REGLINK<<12); // mov PC, LR
o3 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | REGTMP; // BX Rtmp
break;
case 76: /* bx O(R) when returning from fn*/
@@ -2164,35 +1487,114 @@ if(debug['G']) print("%ulx: %s: arm %d %d %d %d\n", (uint32)(p->pc), p->from.sym
o1 |= p->to.reg << 12;
o1 |= (p->scond & C_SCOND) << 28;
break;
+ case 80: /* fmov zfcon,freg */
+ if((p->scond & C_SCOND) != C_SCOND_NONE)
+ diag("floating point cannot be conditional"); // cant happen
+ o1 = 0xf3000110; // EOR 64
+
+ // always clears the double float register
+ r = p->to.reg;
+ o1 |= r << 0;
+ o1 |= r << 12;
+ o1 |= r << 16;
+ break;
+ case 81: /* fmov sfcon,freg */
+ o1 = 0x0eb00a00; // VMOV imm 32
+ if(p->as == AMOVD)
+ o1 = 0xeeb00b00; // VMOV imm 64
+ o1 |= (p->scond & C_SCOND) << 28;
+ o1 |= p->to.reg << 12;
+ v = chipfloat(&p->from.ieee);
+ o1 |= (v&0xf) << 0;
+ o1 |= (v&0xf0) << 12;
+ break;
+ case 82: /* fcmp freg,freg, */
+ o1 = oprrr(p->as, p->scond);
+ o1 |= (p->reg<<12) | (p->from.reg<<0);
+ o2 = 0x0ef1fa10; // VMRS R15
+ o2 |= (p->scond & C_SCOND) << 28;
+ break;
+ case 83: /* fcmp freg,, */
+ o1 = oprrr(p->as, p->scond);
+ o1 |= (p->from.reg<<12) | (1<<16);
+ o2 = 0x0ef1fa10; // VMRS R15
+ o2 |= (p->scond & C_SCOND) << 28;
+ break;
+ case 84: /* movfw freg,freg - truncate float-to-fix */
+ o1 = oprrr(p->as, p->scond);
+ o1 |= (p->from.reg<<0);
+ o1 |= (p->to.reg<<12);
+ break;
+ case 85: /* movwf freg,freg - fix-to-float */
+ o1 = oprrr(p->as, p->scond);
+ o1 |= (p->from.reg<<0);
+ o1 |= (p->to.reg<<12);
+ break;
+ case 86: /* movfw freg,reg - truncate float-to-fix */
+ // macro for movfw freg,FTMP; movw FTMP,reg
+ o1 = oprrr(p->as, p->scond);
+ o1 |= (p->from.reg<<0);
+ o1 |= (FREGTMP<<12);
+ o2 = oprrr(AMOVFW+AEND, p->scond);
+ o2 |= (FREGTMP<<16);
+ o2 |= (p->to.reg<<12);
+ break;
+ case 87: /* movwf reg,freg - fix-to-float */
+ // macro for movw reg,FTMP; movwf FTMP,freg
+ o1 = oprrr(AMOVWF+AEND, p->scond);
+ o1 |= (p->from.reg<<12);
+ o1 |= (FREGTMP<<16);
+ o2 = oprrr(p->as, p->scond);
+ o2 |= (FREGTMP<<0);
+ o2 |= (p->to.reg<<12);
+ break;
+ case 88: /* movw reg,freg */
+ o1 = oprrr(AMOVWF+AEND, p->scond);
+ o1 |= (p->from.reg<<12);
+ o1 |= (p->to.reg<<16);
+ break;
+ case 89: /* movw freg,reg */
+ o1 = oprrr(AMOVFW+AEND, p->scond);
+ o1 |= (p->from.reg<<16);
+ o1 |= (p->to.reg<<12);
+ break;
}
+
+ out[0] = o1;
+ out[1] = o2;
+ out[2] = o3;
+ out[3] = o4;
+ out[4] = o5;
+ out[5] = o6;
+ return;
v = p->pc;
switch(o->size) {
default:
if(debug['a'])
- Bprint(&bso, " %.8lux:\t\t%P\n", v, p);
+ Bprint(&bso, " %.8ux:\t\t%P\n", v, p);
break;
case 4:
if(debug['a'])
- Bprint(&bso, " %.8lux: %.8lux\t%P\n", v, o1, p);
+ Bprint(&bso, " %.8ux: %.8ux\t%P\n", v, o1, p);
lputl(o1);
break;
case 8:
if(debug['a'])
- Bprint(&bso, " %.8lux: %.8lux %.8lux%P\n", v, o1, o2, p);
+ Bprint(&bso, " %.8ux: %.8ux %.8ux%P\n", v, o1, o2, p);
lputl(o1);
lputl(o2);
break;
case 12:
if(debug['a'])
- Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux%P\n", v, o1, o2, o3, p);
+ Bprint(&bso, " %.8ux: %.8ux %.8ux %.8ux%P\n", v, o1, o2, o3, p);
lputl(o1);
lputl(o2);
lputl(o3);
break;
case 16:
if(debug['a'])
- Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux %.8lux%P\n",
+ Bprint(&bso, " %.8ux: %.8ux %.8ux %.8ux %.8ux%P\n",
v, o1, o2, o3, o4, p);
lputl(o1);
lputl(o2);
@@ -2201,7 +1603,7 @@ if(debug['G']) print("%ulx: %s: arm %d %d %d %d\n", (uint32)(p->pc), p->from.sym
break;
case 20:
if(debug['a'])
- Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux %.8lux %.8lux%P\n",
+ Bprint(&bso, " %.8ux: %.8ux %.8ux %.8ux %.8ux %.8ux%P\n",
v, o1, o2, o3, o4, o5, p);
lputl(o1);
lputl(o2);
@@ -2211,7 +1613,7 @@ if(debug['G']) print("%ulx: %s: arm %d %d %d %d\n", (uint32)(p->pc), p->from.sym
break;
case 24:
if(debug['a'])
- Bprint(&bso, " %.8lux: %.8lux %.8lux %.8lux %.8lux %.8lux %.8lux%P\n",
+ Bprint(&bso, " %.8ux: %.8ux %.8ux %.8ux %.8ux %.8ux %.8ux%P\n",
v, o1, o2, o3, o4, o5, o6, p);
lputl(o1);
lputl(o2);
@@ -2262,26 +1664,51 @@ oprrr(int a, int sc)
case ASRA: return o | (0xd<<21) | (2<<5);
case ASWI: return o | (0xf<<24);
- case AADDD: return o | (0xe<<24) | (0x0<<20) | (1<<8) | (1<<7);
- case AADDF: return o | (0xe<<24) | (0x0<<20) | (1<<8);
- case AMULD: return o | (0xe<<24) | (0x1<<20) | (1<<8) | (1<<7);
- case AMULF: return o | (0xe<<24) | (0x1<<20) | (1<<8);
- case ASUBD: return o | (0xe<<24) | (0x2<<20) | (1<<8) | (1<<7);
- case ASUBF: return o | (0xe<<24) | (0x2<<20) | (1<<8);
- case ADIVD: return o | (0xe<<24) | (0x4<<20) | (1<<8) | (1<<7);
- case ADIVF: return o | (0xe<<24) | (0x4<<20) | (1<<8);
- case ACMPD:
- case ACMPF: return o | (0xe<<24) | (0x9<<20) | (0xF<<12) | (1<<8) | (1<<4); /* arguably, ACMPF should expand to RNDF, CMPD */
-
- case AMOVF:
- case AMOVDF: return o | (0xe<<24) | (0x0<<20) | (1<<15) | (1<<8);
- case AMOVD:
- case AMOVFD: return o | (0xe<<24) | (0x0<<20) | (1<<15) | (1<<8) | (1<<7);
-
- case AMOVWF: return o | (0xe<<24) | (0<<20) | (1<<8) | (1<<4);
- case AMOVWD: return o | (0xe<<24) | (0<<20) | (1<<8) | (1<<4) | (1<<7);
- case AMOVFW: return o | (0xe<<24) | (1<<20) | (1<<8) | (1<<4);
- case AMOVDW: return o | (0xe<<24) | (1<<20) | (1<<8) | (1<<4) | (1<<7);
+ case AADDD: return o | (0xe<<24) | (0x3<<20) | (0xb<<8) | (0<<4);
+ case AADDF: return o | (0xe<<24) | (0x3<<20) | (0xa<<8) | (0<<4);
+ case ASUBD: return o | (0xe<<24) | (0x3<<20) | (0xb<<8) | (4<<4);
+ case ASUBF: return o | (0xe<<24) | (0x3<<20) | (0xa<<8) | (4<<4);
+ case AMULD: return o | (0xe<<24) | (0x2<<20) | (0xb<<8) | (0<<4);
+ case AMULF: return o | (0xe<<24) | (0x2<<20) | (0xa<<8) | (0<<4);
+ case ADIVD: return o | (0xe<<24) | (0x8<<20) | (0xb<<8) | (0<<4);
+ case ADIVF: return o | (0xe<<24) | (0x8<<20) | (0xa<<8) | (0<<4);
+ case ACMPD: return o | (0xe<<24) | (0xb<<20) | (4<<16) | (0xb<<8) | (0xc<<4);
+ case ACMPF: return o | (0xe<<24) | (0xb<<20) | (4<<16) | (0xa<<8) | (0xc<<4);
+
+ case AMOVF: return o | (0xe<<24) | (0xb<<20) | (0<<16) | (0xa<<8) | (4<<4);
+ case AMOVD: return o | (0xe<<24) | (0xb<<20) | (0<<16) | (0xb<<8) | (4<<4);
+
+ case AMOVDF: return o | (0xe<<24) | (0xb<<20) | (7<<16) | (0xa<<8) | (0xc<<4) |
+ (1<<8); // dtof
+ case AMOVFD: return o | (0xe<<24) | (0xb<<20) | (7<<16) | (0xa<<8) | (0xc<<4) |
+ (0<<8); // dtof
+
+ case AMOVWF:
+ if((sc & C_UBIT) == 0)
+ o |= 1<<7; /* signed */
+ return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) |
+ (0<<18) | (0<<8); // toint, double
+ case AMOVWD:
+ if((sc & C_UBIT) == 0)
+ o |= 1<<7; /* signed */
+ return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) |
+ (0<<18) | (1<<8); // toint, double
+
+ case AMOVFW:
+ if((sc & C_UBIT) == 0)
+ o |= 1<<16; /* signed */
+ return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) |
+ (1<<18) | (0<<8) | (1<<7); // toint, double, trunc
+ case AMOVDW:
+ if((sc & C_UBIT) == 0)
+ o |= 1<<16; /* signed */
+ return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) |
+ (1<<18) | (1<<8) | (1<<7); // toint, double, trunc
+
+ case AMOVWF+AEND: // copy WtoF
+ return o | (0xe<<24) | (0x0<<20) | (0xb<<8) | (1<<4);
+ case AMOVFW+AEND: // copy FtoW
+ return o | (0xe<<24) | (0x1<<20) | (0xb<<8) | (1<<4);
}
diag("bad rrr %d", a);
prasm(curp);
@@ -2337,12 +1764,13 @@ olr(int32 v, int b, int r, int sc)
o |= 1 << 23;
if(sc & C_WBIT)
o |= 1 << 21;
- o |= (0x1<<26) | (1<<20);
+ o |= (1<<26) | (1<<20);
if(v < 0) {
+ if(sc & C_UBIT) diag(".U on neg offset");
v = -v;
o ^= 1 << 23;
}
- if(v >= (1<<12))
+ if(v >= (1<<12) || v < 0)
diag("literal span too large: %d (R%d)\n%P", v, b, PP);
o |= v;
o |= b << 16;
@@ -2367,7 +1795,7 @@ olhr(int32 v, int b, int r, int sc)
v = -v;
o ^= 1 << 23;
}
- if(v >= (1<<8))
+ if(v >= (1<<8) || v < 0)
diag("literal span too large: %d (R%d)\n%P", v, b, PP);
o |= (v&0xf)|((v>>4)<<8)|(1<<22);
o |= b << 16;
@@ -2434,25 +1862,25 @@ ofsr(int a, int r, int32 v, int b, int sc, Prog *p)
o |= 1 << 24;
if(sc & C_WBIT)
o |= 1 << 21;
- o |= (6<<25) | (1<<24) | (1<<23);
+ o |= (6<<25) | (1<<24) | (1<<23) | (10<<8);
if(v < 0) {
v = -v;
o ^= 1 << 23;
}
if(v & 3)
diag("odd offset for floating point op: %d\n%P", v, p);
- else if(v >= (1<<10))
+ else
+ if(v >= (1<<10) || v < 0)
diag("literal span too large: %d\n%P", v, p);
o |= (v>>2) & 0xFF;
o |= b << 16;
o |= r << 12;
- o |= 1 << 8;
switch(a) {
default:
diag("bad fst %A", a);
case AMOVD:
- o |= 1<<15;
+ o |= 1 << 8;
case AMOVF:
break;
}
@@ -2481,28 +1909,104 @@ omvl(Prog *p, Adr *a, int dr)
return o1;
}
-static Ieee chipfloats[] = {
- {0x00000000, 0x00000000}, /* 0 */
- {0x00000000, 0x3ff00000}, /* 1 */
- {0x00000000, 0x40000000}, /* 2 */
- {0x00000000, 0x40080000}, /* 3 */
- {0x00000000, 0x40100000}, /* 4 */
- {0x00000000, 0x40140000}, /* 5 */
- {0x00000000, 0x3fe00000}, /* .5 */
- {0x00000000, 0x40240000}, /* 10 */
-};
+int
+chipzero(Ieee *e)
+{
+ if(e->l != 0 || e->h != 0)
+ return -1;
+ return 0;
+}
int
chipfloat(Ieee *e)
{
- Ieee *p;
int n;
+ ulong h;
- for(n = sizeof(chipfloats)/sizeof(chipfloats[0]); --n >= 0;){
- p = &chipfloats[n];
- if(p->l == e->l && p->h == e->h)
- return n;
- }
+ if(e->l != 0 || (e->h&0xffff) != 0)
+ goto no;
+ h = e->h & 0x7fc00000;
+ if(h != 0x40000000 && h != 0x3fc00000)
+ goto no;
+ n = 0;
+
+ // sign bit (a)
+ if(e->h & 0x80000000)
+ n |= 1<<7;
+
+ // exp sign bit (b)
+ if(h == 0x3fc00000)
+ n |= 1<<6;
+
+ // rest of exp and mantissa (cd-efgh)
+ n |= (e->h >> 16) & 0x3f;
+
+//print("match %.8lux %.8lux %d\n", e->l, e->h, n);
+ return n;
+
+no:
return -1;
}
+
+void
+genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
+{
+ Auto *a;
+ Sym *s;
+ int h;
+
+ s = lookup("etext", 0);
+ if(s->type == STEXT)
+ put(s, s->name, 'T', s->value, s->size, s->version, 0);
+
+ for(h=0; h<NHASH; h++) {
+ for(s=hash[h]; s!=S; s=s->hash) {
+ switch(s->type) {
+ case SCONST:
+ case SRODATA:
+ case SDATA:
+ case SELFDATA:
+ if(!s->reachable)
+ continue;
+ put(s, s->name, 'D', s->value, s->size, s->version, s->gotype);
+ continue;
+
+ case SBSS:
+ if(!s->reachable)
+ continue;
+ put(s, s->name, 'B', s->value, s->size, s->version, s->gotype);
+ continue;
+
+ case SFILE:
+ put(nil, s->name, 'f', s->value, 0, s->version, 0);
+ continue;
+ }
+ }
+ }
+
+ for(s = textp; s != nil; s = s->next) {
+ /* filenames first */
+ for(a=s->autom; a; a=a->link)
+ if(a->type == D_FILE)
+ put(nil, a->asym->name, 'z', a->aoffset, 0, 0, 0);
+ else
+ if(a->type == D_FILE1)
+ put(nil, a->asym->name, 'Z', a->aoffset, 0, 0, 0);
+
+ put(s, s->name, 'T', s->value, s->size, s->version, s->gotype);
+
+ /* frame, auto and param after */
+ put(nil, ".frame", 'm', s->text->to.offset+4, 0, 0, 0);
+
+ for(a=s->autom; a; a=a->link)
+ if(a->type == D_AUTO)
+ put(nil, a->asym->name, 'a', -a->aoffset, 0, 0, a->gotype);
+ else
+ if(a->type == D_PARAM)
+ put(nil, a->asym->name, 'p', a->aoffset, 0, 0, a->gotype);
+ }
+ if(debug['v'] || debug['n'])
+ Bprint(&bso, "symsize = %ud\n", symsize);
+ Bflush(&bso);
+}
diff --git a/src/cmd/5l/doc.go b/src/cmd/5l/doc.go
index b09995d71..6f7408116 100644
--- a/src/cmd/5l/doc.go
+++ b/src/cmd/5l/doc.go
@@ -20,8 +20,8 @@ Original options are listed in the link above.
Options new in this version:
--L dir1,dir2,..
- Search for libraries (package files) in the comma-separated list of directories.
+-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.
diff --git a/src/cmd/5l/l.h b/src/cmd/5l/l.h
index c6659cfab..4e7ccea88 100644
--- a/src/cmd/5l/l.h
+++ b/src/cmd/5l/l.h
@@ -45,20 +45,21 @@ enum
/* do not undefine this - code will be removed eventually */
#define CALLEEBX
+#define dynptrsize 0
+
typedef struct Adr Adr;
typedef struct Sym Sym;
typedef struct Autom Auto;
typedef struct Prog Prog;
+typedef struct Reloc Reloc;
typedef struct Optab Optab;
typedef struct Oprang Oprang;
typedef uchar Opcross[32][2][32];
typedef struct Count Count;
-typedef struct Use Use;
#define P ((Prog*)0)
#define S ((Sym*)0)
-#define U ((Use*)0)
-#define TNAME (curtext&&curtext->from.sym?curtext->from.sym->name:noname)
+#define TNAME (cursym?cursym->name:noname)
struct Adr
{
@@ -66,14 +67,10 @@ struct Adr
{
int32 u0offset;
char* u0sval;
- Ieee* u0ieee;
+ Ieee u0ieee;
char* u0sbig;
} u0;
- union
- {
- Auto* u1autom;
- Sym* u1sym;
- } u1;
+ Sym* sym;
char type;
uchar index; // not used on arm, required by ld/go.c
char reg;
@@ -85,11 +82,18 @@ struct Adr
#define offset u0.u0offset
#define sval u0.u0sval
+#define scon sval
#define ieee u0.u0ieee
#define sbig u0.u0sbig
-#define autom u1.u1autom
-#define sym u1.u1sym
+struct Reloc
+{
+ int32 off;
+ uchar siz;
+ int16 type;
+ int32 add;
+ Sym* sym;
+};
struct Prog
{
@@ -112,35 +116,51 @@ struct Prog
uchar reg;
uchar align;
};
+
#define regused u0.u0regused
#define forwd u0.u0forwd
+#define datasize reg
+#define textflag reg
struct Sym
{
- char *name;
+ char* name;
short type;
short version;
- short become;
- short frame;
- uchar subtype;
uchar dupok;
uchar reachable;
uchar dynexport;
+ uchar leaf;
+ int32 dynid;
+ int32 plt;
+ int32 got;
int32 value;
int32 sig;
int32 size;
- uchar used;
+ uchar special;
uchar thumb; // thumb code
uchar foreign; // called by arm if thumb, by thumb if arm
uchar fnptr; // used as fn ptr
- Use* use;
- Sym* link;
- Prog* text;
- Prog* data;
+ Sym* hash; // in hash table
+ Sym* next; // in text or data list
+ Sym* sub; // in SSUB list
+ Sym* outer; // container of sub
Sym* gotype;
char* file;
char* dynimpname;
char* dynimplib;
+
+ // STEXT
+ Auto* autom;
+ Prog* text;
+
+ // SDATA, SBSS
+ uchar* p;
+ int32 np;
+ int32 maxp;
+ Reloc* r;
+ int32 nr;
+ int32 maxr;
};
#define SIGNINTERN (1729*325*1729)
@@ -174,34 +194,24 @@ struct Count
int32 count;
int32 outof;
};
-struct Use
-{
- Prog* p; /* use */
- Prog* ct; /* curtext */
- Use* link;
-};
enum
{
Sxxx,
-
+
+ /* order here is order in output file */
STEXT = 1,
+ SRODATA,
+ SELFDATA,
SDATA,
SBSS,
- SDATA1,
+
SXREF,
- SLEAF,
SFILE,
SCONST,
- SSTRING,
- SUNDEF,
- SREMOVED,
+ SDYNIMPORT,
- SIMPORT,
- SEXPORT,
-
- SFIXED,
- SELFDATA,
+ SSUB = 1<<8,
LFROM = 1<<0,
LTO = 1<<1,
@@ -221,7 +231,9 @@ enum
C_SCON, /* 0xffff */
C_BCON, /* thumb */
C_LCON,
- C_FCON,
+ C_ZFCON,
+ C_SFCON,
+ C_LFCON,
C_GCON, /* thumb */
C_RACON,
@@ -229,9 +241,6 @@ enum
C_LACON,
C_GACON, /* thumb */
- C_RECON,
- C_LECON,
-
C_SBRA,
C_LBRA,
C_GBRA, /* thumb */
@@ -242,12 +251,6 @@ enum
C_SAUTO, /* -0xfff to 0xfff */
C_LAUTO,
- C_HEXT,
- C_FEXT,
- C_HFEXT,
- C_SEXT,
- C_LEXT,
-
C_HOREG,
C_FOREG,
C_HFOREG,
@@ -262,7 +265,7 @@ enum
C_HREG,
C_OFFPC, /* thumb */
- C_ADDR, /* relocatable address */
+ C_ADDR, /* reference to relocatable address */
C_GOK,
@@ -271,7 +274,6 @@ enum
LABEL = 1<<1,
LEAF = 1<<2,
- BIG = (1<<12)-4,
STRINGSZ = 200,
NHASH = 10007,
NHUNK = 100000,
@@ -279,9 +281,7 @@ enum
NENT = 100,
MAXIO = 8192,
MAXHIST = 20, /* limit of path elements for history symbols */
-
- Roffset = 22, /* no. bits for offset in relocation address */
- Rindex = 10, /* no. bits for index in relocation address */
+ MINLC = 4,
};
EXTERN union
@@ -310,23 +310,18 @@ EXTERN int32 INITTEXT; /* text location */
EXTERN char* INITENTRY; /* entry point */
EXTERN int32 autosize;
EXTERN Biobuf bso;
-EXTERN int32 bsssize;
EXTERN int cbc;
EXTERN uchar* cbp;
EXTERN int cout;
EXTERN Auto* curauto;
EXTERN Auto* curhist;
EXTERN Prog* curp;
-EXTERN Prog* curtext;
-EXTERN Prog* datap;
-EXTERN int32 datsize;
+EXTERN Sym* cursym;
+EXTERN Sym* datap;
EXTERN int32 elfdatsize;
EXTERN char debug[128];
-EXTERN Prog* edatap;
-EXTERN Prog* etextp;
-EXTERN Prog* firstp;
+EXTERN Sym* etextp;
EXTERN char* noname;
-EXTERN int xrefresolv;
EXTERN Prog* lastp;
EXTERN int32 lcsize;
EXTERN char literal[32];
@@ -341,7 +336,7 @@ EXTERN uchar repop[ALAST];
EXTERN char* rpath;
EXTERN uint32 stroffset;
EXTERN int32 symsize;
-EXTERN Prog* textp;
+EXTERN Sym* textp;
EXTERN int32 textsize;
EXTERN int version;
EXTERN char xcmp[C_GOK+1][C_GOK+1];
@@ -352,14 +347,6 @@ EXTERN int thumb;
EXTERN int seenthumb;
EXTERN int armsize;
-EXTERN int doexp, dlm;
-EXTERN int imports, nimports;
-EXTERN int exports, nexports;
-EXTERN char* EXPTAB;
-EXTERN Prog undefp;
-
-#define UP (&undefp)
-
extern char* anames[];
extern Optab optab[];
extern Optab thumboptab[];
@@ -384,6 +371,7 @@ EXTERN Prog* prog_modu;
int Aconv(Fmt*);
int Cconv(Fmt*);
int Dconv(Fmt*);
+int Iconv(Fmt*);
int Nconv(Fmt*);
int Oconv(Fmt*);
int Pconv(Fmt*);
@@ -393,36 +381,29 @@ int thumbaclass(Adr*, Prog*);
void addhist(int32, int);
Prog* appendp(Prog*);
void asmb(void);
-void asmdyn(void);
-void asmlc(void);
void asmthumbmap(void);
-void asmout(Prog*, Optab*);
+void asmout(Prog*, Optab*, int32*);
void thumbasmout(Prog*, Optab*);
-void asmsym(void);
int32 atolwhex(char*);
Prog* brloop(Prog*);
void buildop(void);
void thumbbuildop(void);
void buildrep(int, int);
void cflush(void);
-void ckoff(Sym*, int32);
+int chipzero(Ieee*);
int chipfloat(Ieee*);
int cmp(int, int);
int compound(Prog*);
double cputime(void);
-void datblk(int32, int32, int);
void diag(char*, ...);
void divsig(void);
void dodata(void);
void doprof1(void);
void doprof2(void);
-void dynreloc(Sym*, int32, int);
int32 entryvalue(void);
void exchange(Prog*);
-void export(void);
void follow(void);
void hputl(int);
-void import(void);
int isnop(Prog*);
void listinit(void);
Sym* lookup(char*, int);
@@ -430,10 +411,8 @@ void cput(int);
void hput(int32);
void lput(int32);
void lputl(int32);
-void mkfwd(void);
void* mysbrk(uint32);
void names(void);
-Prog* newdata(Sym *s, int o, int w, int t);
void nocache(Prog*);
int ocmp(const void*, const void*);
int32 opirr(int);
@@ -454,18 +433,17 @@ void prasm(Prog*);
void prepend(Prog*, Prog*);
Prog* prg(void);
int pseudo(Prog*);
-void putsymb(char*, int, int32, int);
int32 regoff(Adr*);
int relinv(int);
int32 rnd(int32, int32);
void softfloat(void);
void span(void);
void strnput(char*, int);
+int32 symaddr(Sym*);
void undef(void);
void wput(int32);
void wputl(ushort w);
void xdefine(char*, int, int32);
-void xfol(Prog*);
void noops(void);
int32 immrot(uint32);
int32 immaddr(int32);
@@ -475,7 +453,6 @@ int isbranch(Prog*);
int fnpinc(Sym *);
int fninc(Sym *);
void thumbcount(void);
-void reachable(void);
void fnptrs(void);
void doelf(void);
diff --git a/src/cmd/5l/list.c b/src/cmd/5l/list.c
index 9cbb5501c..b4df89587 100644
--- a/src/cmd/5l/list.c
+++ b/src/cmd/5l/list.c
@@ -28,6 +28,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+// Printing.
+
#include "l.h"
#include "../ld/lib.h"
@@ -42,6 +44,7 @@ listinit(void)
fmtinstall('S', Sconv);
fmtinstall('N', Nconv);
fmtinstall('O', Oconv); // C_type constants
+ fmtinstall('I', Iconv);
}
void
@@ -53,7 +56,6 @@ prasm(Prog *p)
int
Pconv(Fmt *fp)
{
- char str[STRINGSZ], *s;
Prog *p;
int a;
@@ -62,42 +64,41 @@ Pconv(Fmt *fp)
a = p->as;
switch(a) {
default:
- s = str;
- s += sprint(s, "(%d)", p->line);
+ fmtprint(fp, "(%d)", p->line);
if(p->reg == NREG)
- sprint(s, " %A%C %D,%D",
+ fmtprint(fp, " %A%C %D,%D",
a, p->scond, &p->from, &p->to);
else
if(p->from.type != D_FREG)
- sprint(s, " %A%C %D,R%d,%D",
+ fmtprint(fp, " %A%C %D,R%d,%D",
a, p->scond, &p->from, p->reg, &p->to);
else
- sprint(s, " %A%C %D,F%d,%D",
+ fmtprint(fp, " %A%C %D,F%d,%D",
a, p->scond, &p->from, p->reg, &p->to);
break;
case ASWPW:
case ASWPBU:
- sprint(str, "(%d) %A%C R%d,%D,%D",
+ fmtprint(fp, "(%d) %A%C R%d,%D,%D",
p->line, a, p->scond, p->reg, &p->from, &p->to);
break;
case ADATA:
- case AINIT:
- case ADYNT:
- sprint(str, "(%d) %A%C %D/%d,%D",
+ case AINIT_:
+ case ADYNT_:
+ fmtprint(fp, "(%d) %A%C %D/%d,%D",
p->line, a, p->scond, &p->from, p->reg, &p->to);
break;
case AWORD:
- sprint(str, "WORD %x", p->to.offset);
+ fmtprint(fp, "(%d) WORD %D", p->line, &p->to);
break;
case ADWORD:
- sprint(str, "DWORD %x %x", p->from.offset, p->to.offset);
+ fmtprint(fp, "(%d) DWORD %D %D", p->line, &p->from, &p->to);
break;
}
- return fmtstrcpy(fp, str);
+ return 0;
}
int
@@ -164,98 +165,98 @@ Dconv(Fmt *fp)
switch(a->type) {
default:
- sprint(str, "GOK-type(%d)", a->type);
+ snprint(str, sizeof str, "GOK-type(%d)", a->type);
break;
case D_NONE:
str[0] = 0;
if(a->name != D_NONE || a->reg != NREG || a->sym != S)
- sprint(str, "%N(R%d)(NONE)", a, a->reg);
+ snprint(str, sizeof str, "%N(R%d)(NONE)", a, a->reg);
break;
case D_CONST:
if(a->reg == NREG)
- sprint(str, "$%N", a);
+ snprint(str, sizeof str, "$%N", a);
else
- sprint(str, "$%N(R%d)", a, a->reg);
+ snprint(str, sizeof str, "$%N(R%d)", a, a->reg);
break;
case D_CONST2:
- sprint(str, "$%d-%d", a->offset, a->offset2);
+ snprint(str, sizeof str, "$%d-%d", a->offset, a->offset2);
break;
case D_SHIFT:
v = a->offset;
op = "<<>>->@>" + (((v>>5) & 3) << 1);
if(v & (1<<4))
- sprint(str, "R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15);
+ snprint(str, sizeof str, "R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15);
else
- sprint(str, "R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31);
+ snprint(str, sizeof str, "R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31);
if(a->reg != NREG)
- sprint(str+strlen(str), "(R%d)", a->reg);
+ seprint(str+strlen(str), str+sizeof str, "(R%d)", a->reg);
break;
case D_OCONST:
- sprint(str, "$*$%N", a);
+ snprint(str, sizeof str, "$*$%N", a);
if(a->reg != NREG)
- sprint(str, "%N(R%d)(CONST)", a, a->reg);
+ snprint(str, sizeof str, "%N(R%d)(CONST)", a, a->reg);
break;
case D_OREG:
if(a->reg != NREG)
- sprint(str, "%N(R%d)", a, a->reg);
+ snprint(str, sizeof str, "%N(R%d)", a, a->reg);
else
- sprint(str, "%N", a);
+ snprint(str, sizeof str, "%N", a);
break;
case D_REG:
- sprint(str, "R%d", a->reg);
+ snprint(str, sizeof str, "R%d", a->reg);
if(a->name != D_NONE || a->sym != S)
- sprint(str, "%N(R%d)(REG)", a, a->reg);
+ snprint(str, sizeof str, "%N(R%d)(REG)", a, a->reg);
break;
case D_REGREG:
- sprint(str, "(R%d,R%d)", a->reg, (int)a->offset);
+ snprint(str, sizeof str, "(R%d,R%d)", a->reg, (int)a->offset);
if(a->name != D_NONE || a->sym != S)
- sprint(str, "%N(R%d)(REG)", a, a->reg);
+ snprint(str, sizeof str, "%N(R%d)(REG)", a, a->reg);
break;
case D_FREG:
- sprint(str, "F%d", a->reg);
+ snprint(str, sizeof str, "F%d", a->reg);
if(a->name != D_NONE || a->sym != S)
- sprint(str, "%N(R%d)(REG)", a, a->reg);
+ snprint(str, sizeof str, "%N(R%d)(REG)", a, a->reg);
break;
case D_PSR:
switch(a->reg) {
case 0:
- sprint(str, "CPSR");
+ snprint(str, sizeof str, "CPSR");
break;
case 1:
- sprint(str, "SPSR");
+ snprint(str, sizeof str, "SPSR");
break;
default:
- sprint(str, "PSR%d", a->reg);
+ snprint(str, sizeof str, "PSR%d", a->reg);
break;
}
if(a->name != D_NONE || a->sym != S)
- sprint(str, "%N(PSR%d)(REG)", a, a->reg);
+ snprint(str, sizeof str, "%N(PSR%d)(REG)", a, a->reg);
break;
case D_FPCR:
switch(a->reg){
case 0:
- sprint(str, "FPSR");
+ snprint(str, sizeof str, "FPSR");
break;
case 1:
- sprint(str, "FPCR");
+ snprint(str, sizeof str, "FPCR");
break;
default:
- sprint(str, "FCR%d", a->reg);
+ snprint(str, sizeof str, "FCR%d", a->reg);
break;
}
if(a->name != D_NONE || a->sym != S)
- sprint(str, "%N(FCR%d)(REG)", a, a->reg);
+ snprint(str, sizeof str, "%N(FCR%d)(REG)", a, a->reg);
break;
@@ -263,22 +264,22 @@ Dconv(Fmt *fp)
if(curp->cond != P) {
v = curp->cond->pc;
if(a->sym != S)
- sprint(str, "%s+%.5lux(BRANCH)", a->sym->name, v);
+ snprint(str, sizeof str, "%s+%.5ux(BRANCH)", a->sym->name, v);
else
- sprint(str, "%.5lux(BRANCH)", v);
+ snprint(str, sizeof str, "%.5ux(BRANCH)", v);
} else
if(a->sym != S)
- sprint(str, "%s+%d(APC)", a->sym->name, a->offset);
+ snprint(str, sizeof str, "%s+%d(APC)", a->sym->name, a->offset);
else
- sprint(str, "%d(APC)", a->offset);
+ snprint(str, sizeof str, "%d(APC)", a->offset);
break;
case D_FCONST:
- sprint(str, "$%e", ieeedtod(a->ieee));
+ snprint(str, sizeof str, "$%e", ieeedtod(&a->ieee));
break;
case D_SCONST:
- sprint(str, "$\"%S\"", a->sval);
+ snprint(str, sizeof str, "$\"%S\"", a->sval);
break;
}
return fmtstrcpy(fp, str);
@@ -374,15 +375,45 @@ Sconv(Fmt *fp)
return fmtstrcpy(fp, str);
}
+int
+Iconv(Fmt *fp)
+{
+ int i, n;
+ uint32 *p;
+ char *s;
+ Fmt fmt;
+
+ n = fp->prec;
+ fp->prec = 0;
+ if(!(fp->flags&FmtPrec) || n < 0)
+ return fmtstrcpy(fp, "%I");
+ fp->flags &= ~FmtPrec;
+ p = va_arg(fp->args, uint32*);
+
+ // format into temporary buffer and
+ // call fmtstrcpy to handle padding.
+ fmtstrinit(&fmt);
+ for(i=0; i<n/4; i++) {
+ if(i > 0)
+ fmtprint(&fmt, " ");
+ fmtprint(&fmt, "%.8ux", *p++);
+ }
+ s = fmtstrflush(&fmt);
+ fmtstrcpy(fp, s);
+ free(s);
+ return 0;
+}
+
static char*
cnames[] =
{
[C_ADDR] = "C_ADDR",
[C_BCON] = "C_BCON",
[C_FAUTO] = "C_FAUTO",
- [C_FCON] = "C_FCON",
+ [C_ZFCON] = "C_SFCON",
+ [C_SFCON] = "C_SFCON",
+ [C_LFCON] = "C_LFCON",
[C_FCR] = "C_FCR",
- [C_FEXT] = "C_FEXT",
[C_FOREG] = "C_FOREG",
[C_FREG] = "C_FREG",
[C_GACON] = "C_GACON",
@@ -391,9 +422,7 @@ cnames[] =
[C_GOK] = "C_GOK",
[C_GOREG] = "C_GOREG",
[C_HAUTO] = "C_HAUTO",
- [C_HEXT] = "C_HEXT",
[C_HFAUTO] = "C_HFAUTO",
- [C_HFEXT] = "C_HFEXT",
[C_HFOREG] = "C_HFOREG",
[C_HOREG] = "C_HOREG",
[C_HREG] = "C_HREG",
@@ -401,8 +430,6 @@ cnames[] =
[C_LAUTO] = "C_LAUTO",
[C_LBRA] = "C_LBRA",
[C_LCON] = "C_LCON",
- [C_LECON] = "C_LECON",
- [C_LEXT] = "C_LEXT",
[C_LOREG] = "C_LOREG",
[C_NCON] = "C_NCON",
[C_NONE] = "C_NONE",
@@ -411,7 +438,6 @@ cnames[] =
[C_PSR] = "C_PSR",
[C_RACON] = "C_RACON",
[C_RCON] = "C_RCON",
- [C_RECON] = "C_RECON",
[C_REG] = "C_REG",
[C_REGREG] = "C_REGREG",
[C_ROREG] = "C_ROREG",
@@ -419,7 +445,6 @@ cnames[] =
[C_SAUTO] = "C_SAUTO",
[C_SBRA] = "C_SBRA",
[C_SCON] = "C_SCON",
- [C_SEXT] = "C_SEXT",
[C_SHIFT] = "C_SHIFT",
[C_SOREG] = "C_SOREG",
[C_SP] = "C_SP",
@@ -443,19 +468,22 @@ Oconv(Fmt *fp)
void
diag(char *fmt, ...)
{
- char buf[STRINGSZ], *tn;
+ char buf[STRINGSZ], *tn, *sep;
va_list arg;
- tn = "??none??";
- if(curtext != P && curtext->from.sym != S)
- tn = curtext->from.sym->name;
+ tn = "";
+ sep = "";
+ if(cursym != S) {
+ tn = cursym->name;
+ sep = ": ";
+ }
va_start(arg, fmt);
vseprint(buf, buf+sizeof(buf), fmt, arg);
va_end(arg);
- print("%s: %s\n", tn, buf);
+ print("%s%s%s\n", tn, sep, buf);
nerrors++;
- if(nerrors > 10) {
+ if(nerrors > 20) {
print("too many errors\n");
errorexit();
}
diff --git a/src/cmd/5l/noop.c b/src/cmd/5l/noop.c
index 41d235a09..5def0d3f1 100644
--- a/src/cmd/5l/noop.c
+++ b/src/cmd/5l/noop.c
@@ -28,12 +28,16 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+// Code transformations.
+
#include "l.h"
+#include "../ld/lib.h"
// see ../../runtime/proc.c:/StackGuard
enum
{
StackBig = 4096,
+ StackSmall = 128,
};
static Sym* sym_div;
@@ -110,14 +114,12 @@ void
noops(void)
{
Prog *p, *q, *q1, *q2;
- int o, curframe, curbecome, maxbecome, foreign;
+ int o, foreign;
Prog *pmorestack;
Sym *symmorestack;
/*
* find leaf subroutines
- * become sizes
- * frame sizes
* strip NOPs
* expand RET
* expand BECOME pseudo
@@ -127,780 +129,662 @@ noops(void)
Bprint(&bso, "%5.2f noops\n", cputime());
Bflush(&bso);
- pmorestack = P;
symmorestack = lookup("runtime.morestack", 0);
-
- if(symmorestack->type == STEXT)
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT) {
- if(p->from.sym == symmorestack) {
- pmorestack = p;
- p->reg |= NOSPLIT;
- break;
- }
- }
+ if(symmorestack->type != STEXT) {
+ diag("runtime·morestack not defined");
+ errorexit();
}
- // TODO(kaib): make lack of morestack an error
-// if(pmorestack == P)
-// diag("runtime·morestack not defined");
-
- curframe = 0;
- curbecome = 0;
- maxbecome = 0;
- curtext = 0;
+ pmorestack = symmorestack->text;
+ pmorestack->reg |= NOSPLIT;
q = P;
- for(p = firstp; p != P; p = p->link) {
- setarch(p);
-
- /* find out how much arg space is used in this TEXT */
- if(p->to.type == D_OREG && p->to.reg == REGSP)
- if(p->to.offset > curframe)
- curframe = p->to.offset;
-
- switch(p->as) {
- case ATEXT:
- if(curtext && curtext->from.sym) {
- curtext->from.sym->frame = curframe;
- curtext->from.sym->become = curbecome;
- if(curbecome > maxbecome)
- maxbecome = curbecome;
- }
- curframe = 0;
- curbecome = 0;
-
- p->mark |= LEAF;
- curtext = p;
- break;
-
- case ARET:
- /* special form of RET is BECOME */
- if(p->from.type == D_CONST)
- if(p->from.offset > curbecome)
- curbecome = p->from.offset;
- break;
-
- case ADIV:
- case ADIVU:
- case AMOD:
- case AMODU:
- q = p;
- if(prog_div == P)
- initdiv();
- if(curtext != P)
- curtext->mark &= ~LEAF;
- setdiv(p->as);
- continue;
-
- case ANOP:
- q1 = p->link;
- q->link = q1; /* q is non-nop */
- q1->mark |= p->mark;
- continue;
-
- case ABL:
- case ABX:
- if(curtext != P)
- curtext->mark &= ~LEAF;
-
- case ABCASE:
- case AB:
-
- case ABEQ:
- case ABNE:
- case ABCS:
- case ABHS:
- case ABCC:
- case ABLO:
- case ABMI:
- case ABPL:
- case ABVS:
- case ABVC:
- case ABHI:
- case ABLS:
- case ABGE:
- case ABLT:
- case ABGT:
- case ABLE:
-
- q1 = p->cond;
- if(q1 != P) {
- while(q1->as == ANOP) {
- q1 = q1->link;
- p->cond = q1;
- }
- }
- break;
- }
- q = p;
- }
-
- if(curtext && curtext->from.sym) {
- curtext->from.sym->frame = curframe;
- curtext->from.sym->become = curbecome;
- if(curbecome > maxbecome)
- maxbecome = curbecome;
- }
-
- if(debug['b'])
- print("max become = %d\n", maxbecome);
- xdefine("ALEFbecome", STEXT, maxbecome);
-
- curtext = 0;
- for(p = firstp; p != P; p = p->link) {
- setarch(p);
- switch(p->as) {
- case ATEXT:
- curtext = p;
- break;
- case ABL:
- // case ABX:
- if(curtext != P && curtext->from.sym != S && curtext->to.offset >= 0) {
- o = maxbecome - curtext->from.sym->frame;
- if(o <= 0)
- break;
- /* calling a become or calling a variable */
- if(p->to.sym == S || p->to.sym->become) {
- curtext->to.offset += o;
- if(debug['b']) {
- curp = p;
- print("%D calling %D increase %d\n",
- &curtext->from, &p->to, o);
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ for(p = cursym->text; p != P; p = p->link) {
+ setarch(p);
+
+ switch(p->as) {
+ case ATEXT:
+ p->mark |= LEAF;
+ break;
+
+ case ARET:
+ break;
+
+ case ADIV:
+ case ADIVU:
+ case AMOD:
+ case AMODU:
+ q = p;
+ if(prog_div == P)
+ initdiv();
+ cursym->text->mark &= ~LEAF;
+ setdiv(p->as);
+ continue;
+
+ case ANOP:
+ q1 = p->link;
+ q->link = q1; /* q is non-nop */
+ if(q1 != P)
+ q1->mark |= p->mark;
+ continue;
+
+ case ABL:
+ case ABX:
+ cursym->text->mark &= ~LEAF;
+
+ case ABCASE:
+ case AB:
+
+ case ABEQ:
+ case ABNE:
+ case ABCS:
+ case ABHS:
+ case ABCC:
+ case ABLO:
+ case ABMI:
+ case ABPL:
+ case ABVS:
+ case ABVC:
+ case ABHI:
+ case ABLS:
+ case ABGE:
+ case ABLT:
+ case ABGT:
+ case ABLE:
+ q1 = p->cond;
+ if(q1 != P) {
+ while(q1->as == ANOP) {
+ q1 = q1->link;
+ p->cond = q1;
}
}
+ break;
}
- break;
+ q = p;
}
}
- for(p = firstp; p != P; p = p->link) {
- setarch(p);
- o = p->as;
- switch(o) {
- case ATEXT:
- curtext = p;
- autosize = p->to.offset + 4;
- if(autosize <= 4)
- if(curtext->mark & LEAF) {
- p->to.offset = -4;
- autosize = 0;
- }
-
- if(!autosize && !(curtext->mark & LEAF)) {
- if(debug['v'])
- Bprint(&bso, "save suppressed in: %s\n",
- curtext->from.sym->name);
- Bflush(&bso);
- curtext->mark |= LEAF;
- }
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ for(p = cursym->text; p != P; p = p->link) {
+ setarch(p);
+ o = p->as;
+ switch(o) {
+ case ATEXT:
+ autosize = p->to.offset + 4;
+ if(autosize <= 4)
+ if(cursym->text->mark & LEAF) {
+ p->to.offset = -4;
+ autosize = 0;
+ }
+
+ if(!autosize && !(cursym->text->mark & LEAF)) {
+ if(debug['v'])
+ Bprint(&bso, "save suppressed in: %s\n",
+ cursym->name);
+ Bflush(&bso);
+ cursym->text->mark |= LEAF;
+ }
#ifdef CALLEEBX
- if(p->from.sym->foreign){
- if(thumb)
- // don't allow literal pool to seperate these
- p = adword(0xe28f7001, 0xe12fff17, p); // arm add 1, pc, r7 and bx r7
- // p = aword(0xe12fff17, aword(0xe28f7001, p)); // arm add 1, pc, r7 and bx r7
- else
- p = aword(0x4778, p); // thumb bx pc and 2 bytes padding
- }
+ if(p->from.sym->foreign){
+ if(thumb)
+ // don't allow literal pool to seperate these
+ p = adword(0xe28f7001, 0xe12fff17, p); // arm add 1, pc, r7 and bx r7
+ // p = aword(0xe12fff17, aword(0xe28f7001, p)); // arm add 1, pc, r7 and bx r7
+ else
+ p = aword(0x4778, p); // thumb bx pc and 2 bytes padding
+ }
#endif
- if(curtext->mark & LEAF) {
- if(curtext->from.sym)
- curtext->from.sym->type = SLEAF;
- if(!autosize)
+ if(cursym->text->mark & LEAF) {
+ cursym->leaf = 1;
+ if(!autosize)
+ break;
+ }
+
+ if(thumb){
+ if(!(p->reg & NOSPLIT))
+ diag("stack splitting not supported in thumb");
+ if(!(cursym->text->mark & LEAF)){
+ q = movrr(nil, REGLINK, REGTMPT-1, p);
+ p->link = q;
+ q1 = prg();
+ q1->as = AMOVW;
+ q1->line = p->line;
+ q1->from.type = D_REG;
+ q1->from.reg = REGTMPT-1;
+ q1->to.type = D_OREG;
+ q1->to.name = D_NONE;
+ q1->to.reg = REGSP;
+ q1->to.offset = 0;
+ q1->link = q->link;
+ q->link = q1;
+ }
+ if(autosize){
+ q2 = prg();
+ q2->as = ASUB;
+ q2->line = p->line;
+ q2->from.type = D_CONST;
+ q2->from.offset = autosize;
+ q2->to.type = D_REG;
+ q2->to.reg = REGSP;
+ q2->link = p->link;
+ p->link = q2;
+ }
break;
- }
-
- if(thumb){
- if(!(p->reg & NOSPLIT))
- diag("stack splitting not supported in thumb");
- if(!(curtext->mark & LEAF)){
- q = movrr(nil, REGLINK, REGTMPT-1, p);
- p->link = q;
+ }
+
+ if(p->reg & NOSPLIT) {
q1 = prg();
q1->as = AMOVW;
+ q1->scond |= C_WBIT;
q1->line = p->line;
q1->from.type = D_REG;
- q1->from.reg = REGTMPT-1;
+ q1->from.reg = REGLINK;
q1->to.type = D_OREG;
- q1->to.name = D_NONE;
+ q1->to.offset = -autosize;
q1->to.reg = REGSP;
- q1->to.offset = 0;
- q1->link = q->link;
- q->link = q1;
- }
- if(autosize){
- q2 = prg();
- q2->as = ASUB;
- q2->line = p->line;
- q2->from.type = D_CONST;
- q2->from.offset = autosize;
- q2->to.type = D_REG;
- q2->to.reg = REGSP;
- q2->link = p->link;
- p->link = q2;
+ q1->link = p->link;
+ p->link = q1;
+ } else if (autosize < StackBig) {
+ // split stack check for small functions
+ // MOVW g_stackguard(g), R1
+ // CMP R1, $-autosize(SP)
+ // MOVW.LO $autosize, R1
+ // MOVW.LO $args, R2
+ // MOVW.LO R14, R3
+ // BL.LO runtime.morestack(SB) // modifies LR
+ // MOVW.W R14,$-autosize(SP)
+
+ // TODO(kaib): add more trampolines
+ // TODO(kaib): put stackguard in register
+ // TODO(kaib): add support for -K and underflow detection
+
+ // MOVW g_stackguard(g), R1
+ p = appendp(p);
+ p->as = AMOVW;
+ p->from.type = D_OREG;
+ p->from.reg = REGG;
+ p->to.type = D_REG;
+ p->to.reg = 1;
+
+ if(autosize < StackSmall) {
+ // CMP R1, SP
+ p = appendp(p);
+ p->as = ACMP;
+ p->from.type = D_REG;
+ p->from.reg = 1;
+ p->reg = REGSP;
+ } else {
+ // MOVW $-autosize(SP), R2
+ // CMP R1, R2
+ p = appendp(p);
+ p->as = AMOVW;
+ p->from.type = D_CONST;
+ p->from.reg = REGSP;
+ p->from.offset = -autosize;
+ p->to.type = D_REG;
+ p->to.reg = 2;
+
+ p = appendp(p);
+ p->as = ACMP;
+ p->from.type = D_REG;
+ p->from.reg = 1;
+ p->reg = 2;
+ }
+
+ // MOVW.LO $autosize, R1
+ p = appendp(p);
+ p->as = AMOVW;
+ p->scond = C_SCOND_LO;
+ p->from.type = D_CONST;
+ p->from.offset = 0;
+ p->to.type = D_REG;
+ p->to.reg = 1;
+
+ // MOVW.LO $args +4, R2
+ // also need to store the extra 4 bytes.
+ p = appendp(p);
+ p->as = AMOVW;
+ p->scond = C_SCOND_LO;
+ p->from.type = D_CONST;
+ p->from.offset = ((cursym->text->to.offset2 + 3) & ~3) + 4;
+ p->to.type = D_REG;
+ p->to.reg = 2;
+
+ // MOVW.LO R14, R3
+ p = appendp(p);
+ p->as = AMOVW;
+ p->scond = C_SCOND_LO;
+ p->from.type = D_REG;
+ p->from.reg = REGLINK;
+ p->to.type = D_REG;
+ p->to.reg = 3;
+
+ // BL.LO runtime.morestack(SB) // modifies LR
+ p = appendp(p);
+ p->as = ABL;
+ p->scond = C_SCOND_LO;
+ p->to.type = D_BRANCH;
+ p->to.sym = symmorestack;
+ p->cond = pmorestack;
+
+ // MOVW.W R14,$-autosize(SP)
+ p = appendp(p);
+ p->as = AMOVW;
+ p->scond |= C_WBIT;
+ p->from.type = D_REG;
+ p->from.reg = REGLINK;
+ p->to.type = D_OREG;
+ p->to.offset = -autosize;
+ p->to.reg = REGSP;
+ } else { // > StackBig
+ // MOVW $autosize, R1
+ // MOVW $args, R2
+ // MOVW R14, R3
+ // BL runtime.morestack(SB) // modifies LR
+ // MOVW.W R14,$-autosize(SP)
+
+ // MOVW $autosize, R1
+ p = appendp(p);
+ p->as = AMOVW;
+ p->from.type = D_CONST;
+ p->from.offset = autosize;
+ p->to.type = D_REG;
+ p->to.reg = 1;
+
+ // MOVW $args +4, R2
+ // also need to store the extra 4 bytes.
+ p = appendp(p);
+ p->as = AMOVW;
+ p->from.type = D_CONST;
+ p->from.offset = ((cursym->text->to.offset2 + 3) & ~3) + 4;
+ p->to.type = D_REG;
+ p->to.reg = 2;
+
+ // MOVW R14, R3
+ p = appendp(p);
+ p->as = AMOVW;
+ p->from.type = D_REG;
+ p->from.reg = REGLINK;
+ p->to.type = D_REG;
+ p->to.reg = 3;
+
+ // BL runtime.morestack(SB) // modifies LR
+ p = appendp(p);
+ p->as = ABL;
+ p->to.type = D_BRANCH;
+ p->to.sym = symmorestack;
+ p->cond = pmorestack;
+
+ // MOVW.W R14,$-autosize(SP)
+ p = appendp(p);
+ p->as = AMOVW;
+ p->scond |= C_WBIT;
+ p->from.type = D_REG;
+ p->from.reg = REGLINK;
+ p->to.type = D_OREG;
+ p->to.offset = -autosize;
+ p->to.reg = REGSP;
}
break;
- }
-
- if(p->reg & NOSPLIT) {
- q1 = prg();
- q1->as = AMOVW;
- q1->scond |= C_WBIT;
- q1->line = p->line;
- q1->from.type = D_REG;
- q1->from.reg = REGLINK;
- q1->to.type = D_OREG;
- q1->to.offset = -autosize;
- q1->to.reg = REGSP;
- q1->link = p->link;
- p->link = q1;
- } else if (autosize < StackBig) {
- // split stack check for small functions
- // MOVW g_stackguard(g), R1
- // CMP R1, $-autosize(SP)
- // MOVW.LO $autosize, R1
- // MOVW.LO $args, R2
- // MOVW.LO R14, R3
- // BL.LO runtime.morestack(SB) // modifies LR
- // MOVW.W R14,$-autosize(SP)
-
- // TODO(kaib): add more trampolines
- // TODO(kaib): put stackguard in register
- // TODO(kaib): add support for -K and underflow detection
-
- // MOVW g_stackguard(g), R1
- p = appendp(p);
- p->as = AMOVW;
- p->from.type = D_OREG;
- p->from.reg = REGG;
- p->to.type = D_REG;
- p->to.reg = 1;
-
- // CMP R1, $-autosize(SP)
- p = appendp(p);
- p->as = ACMP;
- p->from.type = D_REG;
- p->from.reg = 1;
- p->from.offset = -autosize;
- p->reg = REGSP;
-
- // MOVW.LO $autosize, R1
- p = appendp(p);
- p->as = AMOVW;
- p->scond = C_SCOND_LO;
- p->from.type = D_CONST;
- p->from.offset = 0;
- p->to.type = D_REG;
- p->to.reg = 1;
-
- // MOVW.LO $args +4, R2
- // also need to store the extra 4 bytes.
- p = appendp(p);
- p->as = AMOVW;
- p->scond = C_SCOND_LO;
- p->from.type = D_CONST;
- p->from.offset = ((curtext->to.offset2 + 3) & ~3) + 4;
- p->to.type = D_REG;
- p->to.reg = 2;
-
- // MOVW.LO R14, R3
- p = appendp(p);
- p->as = AMOVW;
- p->scond = C_SCOND_LO;
- p->from.type = D_REG;
- p->from.reg = REGLINK;
- p->to.type = D_REG;
- p->to.reg = 3;
-
- // BL.LO runtime.morestack(SB) // modifies LR
- p = appendp(p);
- p->as = ABL;
- p->scond = C_SCOND_LO;
- p->to.type = D_BRANCH;
- p->to.sym = symmorestack;
- p->cond = pmorestack;
-
- // MOVW.W R14,$-autosize(SP)
- p = appendp(p);
- p->as = AMOVW;
- p->scond |= C_WBIT;
- p->from.type = D_REG;
- p->from.reg = REGLINK;
- p->to.type = D_OREG;
- p->to.offset = -autosize;
- p->to.reg = REGSP;
- } else { // > StackBig
- // MOVW $autosize, R1
- // MOVW $args, R2
- // MOVW R14, R3
- // BL runtime.morestack(SB) // modifies LR
- // MOVW.W R14,$-autosize(SP)
-
- // MOVW $autosize, R1
- p = appendp(p);
- p->as = AMOVW;
- p->from.type = D_CONST;
- p->from.offset = autosize;
- p->to.type = D_REG;
- p->to.reg = 1;
-
- // MOVW $args +4, R2
- // also need to store the extra 4 bytes.
- p = appendp(p);
- p->as = AMOVW;
- p->from.type = D_CONST;
- p->from.offset = ((curtext->to.offset2 + 3) & ~3) + 4;
- p->to.type = D_REG;
- p->to.reg = 2;
-
- // MOVW R14, R3
- p = appendp(p);
- p->as = AMOVW;
- p->from.type = D_REG;
- p->from.reg = REGLINK;
- p->to.type = D_REG;
- p->to.reg = 3;
-
- // BL runtime.morestack(SB) // modifies LR
- p = appendp(p);
- p->as = ABL;
- p->to.type = D_BRANCH;
- p->to.sym = symmorestack;
- p->cond = pmorestack;
-
- // MOVW.W R14,$-autosize(SP)
- p = appendp(p);
- p->as = AMOVW;
- p->scond |= C_WBIT;
- p->from.type = D_REG;
- p->from.reg = REGLINK;
- p->to.type = D_OREG;
- p->to.offset = -autosize;
- p->to.reg = REGSP;
- }
- break;
-
- case ARET:
- nocache(p);
- foreign = seenthumb && curtext->from.sym != S && (curtext->from.sym->foreign || curtext->from.sym->fnptr);
-// print("%s %d %d\n", curtext->from.sym->name, curtext->from.sym->foreign, curtext->from.sym->fnptr);
- if(p->from.type == D_CONST)
- goto become;
- if(curtext->mark & LEAF) {
- if(!autosize) {
- if(thumb){
- p = fnret(p, REGLINK, foreign, p);
+
+ case ARET:
+ nocache(p);
+ foreign = seenthumb && (cursym->foreign || cursym->fnptr);
+// print("%s %d %d\n", cursym->name, cursym->foreign, cursym->fnptr);
+ if(cursym->text->mark & LEAF) {
+ if(!autosize) {
+ if(thumb){
+ p = fnret(p, REGLINK, foreign, p);
+ break;
+ }
+// if(foreign) print("ABXRET 1 %s\n", cursym->name);
+ p->as = foreign ? ABXRET : AB;
+ p->from = zprg.from;
+ p->to.type = D_OREG;
+ p->to.offset = 0;
+ p->to.reg = REGLINK;
break;
}
-// if(foreign) print("ABXRET 1 %s\n", curtext->from.sym->name);
- p->as = foreign ? ABXRET : AB;
- p->from = zprg.from;
- p->to.type = D_OREG;
- p->to.offset = 0;
- p->to.reg = REGLINK;
- break;
}
- }
- if(thumb){
- if(curtext->mark & LEAF){
- if(autosize){
- p->as = AADD;
- p->from.type = D_CONST;
- p->from.offset = autosize;
+ if(thumb){
+ if(cursym->text->mark & LEAF){
+ if(autosize){
+ p->as = AADD;
+ p->from.type = D_CONST;
+ p->from.offset = autosize;
+ p->to.type = D_REG;
+ p->to.reg = REGSP;
+ q = nil;
+ }
+ else
+ q = p;
+ q = fnret(q, REGLINK, foreign, p);
+ if(q != p)
+ p->link = q;
+ }
+ else{
+ p->as = AMOVW;
+ p->from.type = D_OREG;
+ p->from.name = D_NONE;
+ p->from.reg = REGSP;
+ p->from.offset = 0;
p->to.type = D_REG;
- p->to.reg = REGSP;
- q = nil;
+ p->to.reg = REGTMPT-1;
+ if(autosize){
+ q = prg();
+ q->as = AADD;
+ q->from.type = D_CONST;
+ q->from.offset = autosize;
+ q->to.type = D_REG;
+ q->to.reg = REGSP;
+ q->link = p->link;
+ p->link = q;
+ }
+ else
+ q = p;
+ q1 = fnret(nil, REGTMPT-1, foreign, p);
+ q1->link = q->link;
+ q->link = q1;
}
- else
- q = p;
- q = fnret(q, REGLINK, foreign, p);
- if(q != p)
- p->link = q;
+ break;
}
- else{
+ if(foreign) {
+// if(foreign) print("ABXRET 3 %s\n", cursym->name);
+#define R 1
p->as = AMOVW;
p->from.type = D_OREG;
p->from.name = D_NONE;
p->from.reg = REGSP;
p->from.offset = 0;
p->to.type = D_REG;
- p->to.reg = REGTMPT-1;
- if(autosize){
- q = prg();
- q->as = AADD;
- q->from.type = D_CONST;
- q->from.offset = autosize;
- q->to.type = D_REG;
- q->to.reg = REGSP;
- q->link = p->link;
- p->link = q;
- }
- else
- q = p;
- q1 = fnret(nil, REGTMPT-1, foreign, p);
+ p->to.reg = R;
+ q = prg();
+ q->as = AADD;
+ q->scond = p->scond;
+ q->line = p->line;
+ q->from.type = D_CONST;
+ q->from.offset = autosize;
+ q->to.type = D_REG;
+ q->to.reg = REGSP;
+ q->link = p->link;
+ p->link = q;
+ q1 = prg();
+ q1->as = ABXRET;
+ q1->scond = p->scond;
+ q1->line = p->line;
+ q1->to.type = D_OREG;
+ q1->to.offset = 0;
+ q1->to.reg = R;
q1->link = q->link;
q->link = q1;
+#undef R
+ }
+ else {
+ p->as = AMOVW;
+ p->scond |= C_PBIT;
+ p->from.type = D_OREG;
+ p->from.offset = autosize;
+ p->from.reg = REGSP;
+ p->to.type = D_REG;
+ p->to.reg = REGPC;
}
break;
- }
- if(foreign) {
-// if(foreign) print("ABXRET 3 %s\n", curtext->from.sym->name);
-#define R 1
+
+ case ADIV:
+ case ADIVU:
+ case AMOD:
+ case AMODU:
+ if(debug['M'])
+ break;
+ if(p->from.type != D_REG)
+ break;
+ if(p->to.type != D_REG)
+ break;
+ q1 = p;
+
+ /* MOV a,4(SP) */
+ q = prg();
+ q->link = p->link;
+ p->link = q;
+ p = q;
+
p->as = AMOVW;
- p->from.type = D_OREG;
- p->from.name = D_NONE;
- p->from.reg = REGSP;
- p->from.offset = 0;
- p->to.type = D_REG;
- p->to.reg = R;
+ p->line = q1->line;
+ p->from.type = D_REG;
+ p->from.reg = q1->from.reg;
+ p->to.type = D_OREG;
+ p->to.reg = REGSP;
+ p->to.offset = 4;
+
+ /* MOV b,REGTMP */
q = prg();
- q->as = AADD;
- q->scond = p->scond;
- q->line = p->line;
- q->from.type = D_CONST;
- q->from.offset = autosize;
- q->to.type = D_REG;
- q->to.reg = REGSP;
q->link = p->link;
p->link = q;
- q1 = prg();
- q1->as = ABXRET;
- q1->scond = p->scond;
- q1->line = p->line;
- q1->to.type = D_OREG;
- q1->to.offset = 0;
- q1->to.reg = R;
- q1->link = q->link;
- q->link = q1;
-#undef R
- }
- else {
+ p = q;
+
p->as = AMOVW;
- p->scond |= C_PBIT;
- p->from.type = D_OREG;
- p->from.offset = autosize;
- p->from.reg = REGSP;
+ p->line = q1->line;
+ p->from.type = D_REG;
+ p->from.reg = q1->reg;
+ if(q1->reg == NREG)
+ p->from.reg = q1->to.reg;
p->to.type = D_REG;
- p->to.reg = REGPC;
- }
- break;
-
- become:
- if(foreign){
- diag("foreign become - help");
- break;
- }
- if(thumb){
- diag("thumb become - help");
- break;
- }
- print("arm become\n");
- if(curtext->mark & LEAF) {
-
- if(!autosize) {
- p->as = AB;
- p->from = zprg.from;
+ p->to.reg = prog_div->from.sym->thumb ? REGTMPT : REGTMP;
+ p->to.offset = 0;
+
+ /* CALL appropriate */
+ q = prg();
+ q->link = p->link;
+ p->link = q;
+ p = q;
+
+#ifdef CALLEEBX
+ p->as = ABL;
+#else
+ if(prog_div->from.sym->thumb)
+ p->as = thumb ? ABL : ABX;
+ else
+ p->as = thumb ? ABX : ABL;
+#endif
+ p->line = q1->line;
+ p->to.type = D_BRANCH;
+ p->cond = p;
+ switch(o) {
+ case ADIV:
+ p->cond = prog_div;
+ p->to.sym = sym_div;
+ break;
+ case ADIVU:
+ p->cond = prog_divu;
+ p->to.sym = sym_divu;
+ break;
+ case AMOD:
+ p->cond = prog_mod;
+ p->to.sym = sym_mod;
+ break;
+ case AMODU:
+ p->cond = prog_modu;
+ p->to.sym = sym_modu;
break;
}
- }
- q = prg();
- q->scond = p->scond;
- q->line = p->line;
- q->as = AB;
- q->from = zprg.from;
- q->to = p->to;
- q->cond = p->cond;
- q->link = p->link;
- p->link = q;
- if(thumb){
- q1 = prg();
- q1->line = p->line;
- q1->as = AADD;
- q1->from.type = D_CONST;
- q1->from.offset = autosize;
- q1->to.type = D_REG;
- q1->to.reg = REGSP;
+
+ /* MOV REGTMP, b */
+ q = prg();
+ q->link = p->link;
+ p->link = q;
+ p = q;
+
p->as = AMOVW;
- p->line = p->line;
- p->from.type = D_OREG;
- p->from.name = D_NONE;
- p->from.reg = REGSP;
+ p->line = q1->line;
+ p->from.type = D_REG;
+ p->from.reg = prog_div->from.sym->thumb ? REGTMPT : REGTMP;
p->from.offset = 0;
p->to.type = D_REG;
- p->to.reg = REGTMPT-1;
- q1->link = q;
- p->link = q1;
- q2 = movrr(nil, REGTMPT-1, REGLINK, p);
- q2->link = q;
- q1->link = q2;
- break;
- }
- p->as = AMOVW;
- p->scond |= C_PBIT;
- p->from = zprg.from;
- p->from.type = D_OREG;
- p->from.offset = autosize;
- p->from.reg = REGSP;
- p->to = zprg.to;
- p->to.type = D_REG;
- p->to.reg = REGLINK;
-
- break;
-
- case ADIV:
- case ADIVU:
- case AMOD:
- case AMODU:
- if(debug['M'])
- break;
- if(p->from.type != D_REG)
- break;
- if(p->to.type != D_REG)
- break;
- q1 = p;
-
- /* MOV a,4(SP) */
- q = prg();
- q->link = p->link;
- p->link = q;
- p = q;
-
- p->as = AMOVW;
- p->line = q1->line;
- p->from.type = D_REG;
- p->from.reg = q1->from.reg;
- p->to.type = D_OREG;
- p->to.reg = REGSP;
- p->to.offset = 4;
-
- /* MOV b,REGTMP */
- q = prg();
- q->link = p->link;
- p->link = q;
- p = q;
-
- p->as = AMOVW;
- p->line = q1->line;
- p->from.type = D_REG;
- p->from.reg = q1->reg;
- if(q1->reg == NREG)
- p->from.reg = q1->to.reg;
- p->to.type = D_REG;
- p->to.reg = prog_div != UP && prog_div->from.sym->thumb ? REGTMPT : REGTMP;
- p->to.offset = 0;
-
- /* CALL appropriate */
- q = prg();
- q->link = p->link;
- p->link = q;
- p = q;
-
-#ifdef CALLEEBX
- p->as = ABL;
-#else
- if(prog_div != UP && prog_div->from.sym->thumb)
- p->as = thumb ? ABL : ABX;
- else
- p->as = thumb ? ABX : ABL;
-#endif
- p->line = q1->line;
- p->to.type = D_BRANCH;
- p->cond = p;
- switch(o) {
- case ADIV:
- p->cond = prog_div;
- p->to.sym = sym_div;
- break;
- case ADIVU:
- p->cond = prog_divu;
- p->to.sym = sym_divu;
- break;
- case AMOD:
- p->cond = prog_mod;
- p->to.sym = sym_mod;
+ p->to.reg = q1->to.reg;
+
+ /* ADD $8,SP */
+ q = prg();
+ q->link = p->link;
+ p->link = q;
+ p = q;
+
+ p->as = AADD;
+ p->from.type = D_CONST;
+ p->from.reg = NREG;
+ p->from.offset = 8;
+ p->reg = NREG;
+ p->to.type = D_REG;
+ p->to.reg = REGSP;
+
+ /* SUB $8,SP */
+ q1->as = ASUB;
+ q1->from.type = D_CONST;
+ q1->from.offset = 8;
+ q1->from.reg = NREG;
+ q1->reg = NREG;
+ q1->to.type = D_REG;
+ q1->to.reg = REGSP;
+
break;
- case AMODU:
- p->cond = prog_modu;
- p->to.sym = sym_modu;
+ case AMOVW:
+ if(thumb){
+ Adr *a = &p->from;
+
+ if(a->type == D_CONST && ((a->name == D_NONE && a->reg == REGSP) || a->name == D_AUTO || a->name == D_PARAM) && (a->offset & 3))
+ diag("SP offset not multiple of 4");
+ }
break;
- }
-
- /* MOV REGTMP, b */
- q = prg();
- q->link = p->link;
- p->link = q;
- p = q;
-
- p->as = AMOVW;
- p->line = q1->line;
- p->from.type = D_REG;
- p->from.reg = prog_div != UP && prog_div->from.sym->thumb ? REGTMPT : REGTMP;
- p->from.offset = 0;
- p->to.type = D_REG;
- p->to.reg = q1->to.reg;
-
- /* ADD $8,SP */
- q = prg();
- q->link = p->link;
- p->link = q;
- p = q;
-
- p->as = AADD;
- p->from.type = D_CONST;
- p->from.reg = NREG;
- p->from.offset = 8;
- p->reg = NREG;
- p->to.type = D_REG;
- p->to.reg = REGSP;
-
- /* SUB $8,SP */
- q1->as = ASUB;
- q1->from.type = D_CONST;
- q1->from.offset = 8;
- q1->from.reg = NREG;
- q1->reg = NREG;
- q1->to.type = D_REG;
- q1->to.reg = REGSP;
-
- break;
- case AMOVW:
- if(thumb){
- Adr *a = &p->from;
-
- if(a->type == D_CONST && ((a->name == D_NONE && a->reg == REGSP) || a->name == D_AUTO || a->name == D_PARAM) && (a->offset & 3))
- diag("SP offset not multiple of 4");
- }
- break;
- case AMOVB:
- case AMOVBU:
- case AMOVH:
- case AMOVHU:
- if(thumb){
- if(p->from.type == D_OREG && (p->from.name == D_AUTO || p->from.name == D_PARAM || (p->from.name == D_CONST && p->from.reg == REGSP))){
- q = prg();
- *q = *p;
- if(p->from.name == D_AUTO)
- q->from.offset += autosize;
- else if(p->from.name == D_PARAM)
- q->from.offset += autosize+4;
- q->from.name = D_NONE;
- q->from.reg = REGTMPT;
- p = movrr(p, REGSP, REGTMPT, p);
- q->link = p->link;
- p->link = q;
+ case AMOVB:
+ case AMOVBU:
+ case AMOVH:
+ case AMOVHU:
+ if(thumb){
+ if(p->from.type == D_OREG && (p->from.name == D_AUTO || p->from.name == D_PARAM || (p->from.name == D_CONST && p->from.reg == REGSP))){
+ q = prg();
+ *q = *p;
+ if(p->from.name == D_AUTO)
+ q->from.offset += autosize;
+ else if(p->from.name == D_PARAM)
+ q->from.offset += autosize+4;
+ q->from.name = D_NONE;
+ q->from.reg = REGTMPT;
+ p = movrr(p, REGSP, REGTMPT, p);
+ q->link = p->link;
+ p->link = q;
+ }
+ if(p->to.type == D_OREG && (p->to.name == D_AUTO || p->to.name == D_PARAM || (p->to.name == D_CONST && p->to.reg == REGSP))){
+ q = prg();
+ *q = *p;
+ if(p->to.name == D_AUTO)
+ q->to.offset += autosize;
+ else if(p->to.name == D_PARAM)
+ q->to.offset += autosize+4;
+ q->to.name = D_NONE;
+ q->to.reg = REGTMPT;
+ p = movrr(p, REGSP, REGTMPT, p);
+ q->link = p->link;
+ p->link = q;
+ if(q->to.offset < 0 || q->to.offset > 255){ // complicated
+ p->to.reg = REGTMPT+1; // mov sp, r8
+ q1 = prg();
+ q1->line = p->line;
+ q1->as = AMOVW;
+ q1->from.type = D_CONST;
+ q1->from.offset = q->to.offset;
+ q1->to.type = D_REG;
+ q1->to.reg = REGTMPT; // mov $o, r7
+ p->link = q1;
+ q1->link = q;
+ q1 = prg();
+ q1->line = p->line;
+ q1->as = AADD;
+ q1->from.type = D_REG;
+ q1->from.reg = REGTMPT+1;
+ q1->to.type = D_REG;
+ q1->to.reg = REGTMPT; // add r8, r7
+ p->link->link = q1;
+ q1->link = q;
+ q->to.offset = 0; // mov* r, 0(r7)
+ /* phew */
+ }
+ }
}
- if(p->to.type == D_OREG && (p->to.name == D_AUTO || p->to.name == D_PARAM || (p->to.name == D_CONST && p->to.reg == REGSP))){
- q = prg();
- *q = *p;
- if(p->to.name == D_AUTO)
- q->to.offset += autosize;
- else if(p->to.name == D_PARAM)
- q->to.offset += autosize+4;
- q->to.name = D_NONE;
- q->to.reg = REGTMPT;
- p = movrr(p, REGSP, REGTMPT, p);
- q->link = p->link;
- p->link = q;
- if(q->to.offset < 0 || q->to.offset > 255){ // complicated
- p->to.reg = REGTMPT+1; // mov sp, r8
- q1 = prg();
- q1->line = p->line;
- q1->as = AMOVW;
- q1->from.type = D_CONST;
- q1->from.offset = q->to.offset;
- q1->to.type = D_REG;
- q1->to.reg = REGTMPT; // mov $o, r7
- p->link = q1;
- q1->link = q;
- q1 = prg();
- q1->line = p->line;
- q1->as = AADD;
- q1->from.type = D_REG;
- q1->from.reg = REGTMPT+1;
- q1->to.type = D_REG;
- q1->to.reg = REGTMPT; // add r8, r7
- p->link->link = q1;
- q1->link = q;
- q->to.offset = 0; // mov* r, 0(r7)
- /* phew */
+ break;
+ case AMOVM:
+ if(thumb){
+ if(p->from.type == D_OREG){
+ if(p->from.offset == 0)
+ p->from.type = D_REG;
+ else
+ diag("non-zero AMOVM offset");
+ }
+ else if(p->to.type == D_OREG){
+ if(p->to.offset == 0)
+ p->to.type = D_REG;
+ else
+ diag("non-zero AMOVM offset");
}
}
- }
- break;
- case AMOVM:
- if(thumb){
- if(p->from.type == D_OREG){
- if(p->from.offset == 0)
+ break;
+ case AB:
+ if(thumb && p->to.type == D_OREG){
+ if(p->to.offset == 0){
+ p->as = AMOVW;
p->from.type = D_REG;
- else
- diag("non-zero AMOVM offset");
- }
- else if(p->to.type == D_OREG){
- if(p->to.offset == 0)
+ p->from.reg = p->to.reg;
p->to.type = D_REG;
- else
- diag("non-zero AMOVM offset");
- }
- }
- break;
- case AB:
- if(thumb && p->to.type == D_OREG){
- if(p->to.offset == 0){
- p->as = AMOVW;
- p->from.type = D_REG;
- p->from.reg = p->to.reg;
- p->to.type = D_REG;
- p->to.reg = REGPC;
- }
- else{
- p->as = AADD;
- p->from.type = D_CONST;
- p->from.offset = p->to.offset;
- p->reg = p->to.reg;
- p->to.type = D_REG;
- p->to.reg = REGTMPT-1;
- q = prg();
- q->as = AMOVW;
- q->line = p->line;
- q->from.type = D_REG;
- q->from.reg = REGTMPT-1;
- q->to.type = D_REG;
- q->to.reg = REGPC;
- q->link = p->link;
- p->link = q;
+ p->to.reg = REGPC;
+ }
+ else{
+ p->as = AADD;
+ p->from.type = D_CONST;
+ p->from.offset = p->to.offset;
+ p->reg = p->to.reg;
+ p->to.type = D_REG;
+ p->to.reg = REGTMPT-1;
+ q = prg();
+ q->as = AMOVW;
+ q->line = p->line;
+ q->from.type = D_REG;
+ q->from.reg = REGTMPT-1;
+ q->to.type = D_REG;
+ q->to.reg = REGPC;
+ q->link = p->link;
+ p->link = q;
+ }
}
- }
- if(seenthumb && !thumb && p->to.type == D_OREG && p->to.reg == REGLINK){
- // print("warn %s: b (R%d) assuming a return\n", curtext->from.sym->name, p->to.reg);
- p->as = ABXRET;
- }
- break;
- case ABL:
- case ABX:
- if(thumb && p->to.type == D_OREG){
- if(p->to.offset == 0){
- p->as = o;
- p->from.type = D_NONE;
- p->to.type = D_REG;
+ if(seenthumb && !thumb && p->to.type == D_OREG && p->to.reg == REGLINK){
+ // print("warn %s: b (R%d) assuming a return\n", cursym->name, p->to.reg);
+ p->as = ABXRET;
}
- else{
- p->as = AADD;
- p->from.type = D_CONST;
- p->from.offset = p->to.offset;
- p->reg = p->to.reg;
- p->to.type = D_REG;
- p->to.reg = REGTMPT-1;
- q = prg();
- q->as = o;
- q->line = p->line;
- q->from.type = D_NONE;
- q->to.type = D_REG;
- q->to.reg = REGTMPT-1;
- q->link = p->link;
- p->link = q;
+ break;
+ case ABL:
+ case ABX:
+ if(thumb && p->to.type == D_OREG){
+ if(p->to.offset == 0){
+ p->as = o;
+ p->from.type = D_NONE;
+ p->to.type = D_REG;
+ }
+ else{
+ p->as = AADD;
+ p->from.type = D_CONST;
+ p->from.offset = p->to.offset;
+ p->reg = p->to.reg;
+ p->to.type = D_REG;
+ p->to.reg = REGTMPT-1;
+ q = prg();
+ q->as = o;
+ q->line = p->line;
+ q->from.type = D_NONE;
+ q->to.type = D_REG;
+ q->to.reg = REGTMPT-1;
+ q->link = p->link;
+ p->link = q;
+ }
}
+ break;
}
- break;
}
}
}
@@ -911,12 +795,9 @@ sigdiv(char *n)
Sym *s;
s = lookup(n, 0);
- if(s->type == STEXT){
+ if(s->type == STEXT)
if(s->sig == 0)
s->sig = SIGNINTERN;
- }
- else if(s->type == 0 || s->type == SXREF)
- s->type = SUNDEF;
}
void
@@ -928,25 +809,10 @@ divsig(void)
sigdiv("_modu");
}
-static void
-sdiv(Sym *s)
-{
- if(s->type == 0 || s->type == SXREF){
- /* undefsym(s); */
- s->type = SXREF;
- if(s->sig == 0)
- s->sig = SIGNINTERN;
- s->subtype = SIMPORT;
- }
- else if(s->type != STEXT)
- diag("undefined: %s", s->name);
-}
-
void
initdiv(void)
{
Sym *s2, *s3, *s4, *s5;
- Prog *p;
if(prog_div != P)
return;
@@ -954,38 +820,25 @@ initdiv(void)
sym_divu = s3 = lookup("_divu", 0);
sym_mod = s4 = lookup("_mod", 0);
sym_modu = s5 = lookup("_modu", 0);
- if(dlm) {
- sdiv(s2); if(s2->type == SXREF) prog_div = UP;
- sdiv(s3); if(s3->type == SXREF) prog_divu = UP;
- sdiv(s4); if(s4->type == SXREF) prog_mod = UP;
- sdiv(s5); if(s5->type == SXREF) prog_modu = UP;
- }
- for(p = firstp; p != P; p = p->link)
- if(p->as == ATEXT) {
- if(p->from.sym == s2)
- prog_div = p;
- if(p->from.sym == s3)
- prog_divu = p;
- if(p->from.sym == s4)
- prog_mod = p;
- if(p->from.sym == s5)
- prog_modu = p;
- }
+ prog_div = s2->text;
+ prog_divu = s3->text;
+ prog_mod = s4->text;
+ prog_modu = s5->text;
if(prog_div == P) {
diag("undefined: %s", s2->name);
- prog_div = curtext;
+ prog_div = cursym->text;
}
if(prog_divu == P) {
diag("undefined: %s", s3->name);
- prog_divu = curtext;
+ prog_divu = cursym->text;
}
if(prog_mod == P) {
diag("undefined: %s", s4->name);
- prog_mod = curtext;
+ prog_mod = cursym->text;
}
if(prog_modu == P) {
diag("undefined: %s", s5->name);
- prog_modu = curtext;
+ prog_modu = cursym->text;
}
}
@@ -1000,7 +853,7 @@ setdiv(int as)
case AMOD: p = prog_mod; break;
case AMODU: p = prog_modu; break;
}
- if(p != UP && thumb != p->from.sym->thumb)
+ if(thumb != p->from.sym->thumb)
p->from.sym->foreign = 1;
}
diff --git a/src/cmd/5l/obj.c b/src/cmd/5l/obj.c
index e3597e040..cb9ad9805 100644
--- a/src/cmd/5l/obj.c
+++ b/src/cmd/5l/obj.c
@@ -28,6 +28,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+// Reading object files.
+
#define EXTERN
#include "l.h"
#include "../ld/lib.h"
@@ -50,28 +52,6 @@ char *thestring = "arm";
* -H5 -T0xC0008010 -R1024 is ipaq
*/
-static int
-isobjfile(char *f)
-{
- int n, v;
- Biobuf *b;
- char buf1[5], buf2[SARMAG];
-
- b = Bopen(f, OREAD);
- if(b == nil)
- return 0;
- n = Bread(b, buf1, 5);
- if(n == 5 && (buf1[2] == 1 && buf1[3] == '<' || buf1[3] == 1 && buf1[4] == '<'))
- v = 1; /* good enough for our purposes */
- else{
- Bseek(b, 0, 0);
- n = Bread(b, buf2, SARMAG);
- v = n == SARMAG && strncmp(buf2, ARMAG, SARMAG) == 0;
- }
- Bterm(b);
- return v;
-}
-
static char*
linkername[] =
{
@@ -94,7 +74,6 @@ main(int argc, char *argv[])
cout = -1;
listinit();
nerrors = 0;
- curtext = P;
outfile = "5.out";
HEADTYPE = -1;
INITTEXT = -1;
@@ -231,10 +210,10 @@ main(int argc, char *argv[])
break;
}
if(INITDAT != 0 && INITRND != 0)
- print("warning: -D0x%lux is ignored because of -R0x%lux\n",
+ print("warning: -D0x%ux is ignored because of -R0x%ux\n",
INITDAT, INITRND);
if(debug['v'])
- Bprint(&bso, "HEADER = -H0x%d -T0x%lux -D0x%lux -R0x%lux\n",
+ Bprint(&bso, "HEADER = -H0x%d -T0x%ux -D0x%ux -R0x%ux\n",
HEADTYPE, INITTEXT, INITDAT, INITRND);
Bflush(&bso);
zprg.as = AGOK;
@@ -247,9 +226,6 @@ main(int argc, char *argv[])
buildop();
thumbbuildop(); // could build on demand
histgen = 0;
- textp = P;
- datap = P;
- edatap = P;
pc = 0;
dtype = 4;
nuxiinit();
@@ -257,8 +233,6 @@ main(int argc, char *argv[])
version = 0;
cbp = buf.cbuf;
cbc = sizeof(buf.cbuf);
- firstp = prg();
- lastp = firstp;
addlibpath("command line", "command line", argv[0], "main");
loadlib();
@@ -268,52 +242,30 @@ main(int argc, char *argv[])
for(i=0; i<nelem(linkername); i++)
mark(lookup(linkername[i], 0));
deadcode();
-
- firstp = firstp->link;
- if(firstp == P)
- goto out;
- if(doexp || dlm){
- EXPTAB = "_exporttab";
- zerosig(EXPTAB);
- zerosig("etext");
- zerosig("edata");
- zerosig("end");
- if(dlm){
- initdiv();
- import();
- HEADTYPE = 2;
- INITTEXT = INITDAT = 0;
- INITRND = 8;
- INITENTRY = EXPTAB;
- }
- else
- divsig();
- export();
+ if(textp == nil) {
+ diag("no code");
+ errorexit();
}
+
patch();
if(debug['p'])
if(debug['1'])
doprof1();
else
doprof2();
- if(debug['u'])
- reachable();
doelf();
- dodata();
- if(seenthumb && debug['f'])
- fnptrs();
follow();
- if(firstp == P) {
- diag("no code");
- errorexit();
- }
softfloat();
noops();
span();
+ pclntab();
+ symtab();
+ dodata();
+ address();
+ reloc();
asmb();
undef();
-out:
if(debug['c']){
thumbcount();
print("ARM size = %d\n", armsize);
@@ -327,7 +279,7 @@ out:
errorexit();
}
-void
+static void
zaddr(Biobuf *f, Adr *a, Sym *h[])
{
int i, c;
@@ -355,7 +307,7 @@ zaddr(Biobuf *f, Adr *a, Sym *h[])
if(a->type == D_CONST || a->type == D_OCONST) {
if(a->name == D_EXTERN || a->name == D_STATIC) {
s = a->sym;
- if(s != S && (s->type == STEXT || s->type == SLEAF || s->type == SCONST || s->type == SXREF)) {
+ if(s != S && (s->type == STEXT || s->type == SCONST || s->type == SXREF)) {
if(0 && !s->fnptr && s->name[0] != '.')
print("%s used as function pointer\n", s->name);
s->fnptr = 1; // over the top cos of SXREF
@@ -398,9 +350,8 @@ zaddr(Biobuf *f, Adr *a, Sym *h[])
break;
case D_FCONST:
- a->ieee = mal(sizeof(Ieee));
- a->ieee->l = Bget4(f);
- a->ieee->h = Bget4(f);
+ a->ieee.l = Bget4(f);
+ a->ieee.h = Bget4(f);
break;
}
s = a->sym;
@@ -441,7 +392,7 @@ void
ldobj1(Biobuf *f, char *pkg, int64 len, char *pn)
{
int32 ipc;
- Prog *p, *t;
+ Prog *p;
Sym *h[NSYM], *s, *di;
int v, o, r, skip;
uint32 sig;
@@ -449,7 +400,9 @@ ldobj1(Biobuf *f, char *pkg, int64 len, char *pn)
int ntext;
int32 eof;
char src[1024], *x;
+ Prog *lastp;
+ lastp = nil;
ntext = 0;
eof = Boffset(f) + len;
di = S;
@@ -499,13 +452,17 @@ loop:
if(sig != 0){
if(s->sig != 0 && s->sig != sig)
- diag("incompatible type signatures %lux(%s) and %lux(%s) for %s", s->sig, s->file, sig, pn, s->name);
+ diag("incompatible type signatures %ux(%s) and %ux(%s) for %s", s->sig, s->file, sig, pn, s->name);
s->sig = sig;
s->file = pn;
}
if(debug['W'])
print(" ANAME %s\n", s->name);
+ if(o < 0 || o >= nelem(h)) {
+ fprint(2, "%s: mangled input file\n", pn);
+ errorexit();
+ }
h[o] = s;
if((v == D_EXTERN || v == D_STATIC) && s->type == 0)
s->type = SXREF;
@@ -533,8 +490,8 @@ loop:
zaddr(f, &p->from, h);
zaddr(f, &p->to, h);
- if(p->reg > NREG)
- diag("register out of range %d", p->reg);
+ if(p->as != ATEXT && p->as != AGLOBL && p->reg > NREG)
+ diag("register out of range %A %d", p->as, p->reg);
p->link = P;
p->cond = P;
@@ -559,10 +516,10 @@ loop:
case AEND:
histtoauto();
- if(curtext != P)
- curtext->to.autom = curauto;
+ if(cursym != nil && cursym->text)
+ cursym->autom = curauto;
curauto = 0;
- curtext = P;
+ cursym = nil;
if(Boffset(f) == eof)
return;
goto newloop;
@@ -582,98 +539,31 @@ loop:
s->type = SBSS;
s->value = 0;
}
- if(p->to.offset > s->value)
- s->value = p->to.offset;
+ if(p->to.offset > s->size)
+ s->size = p->to.offset;
if(p->reg & DUPOK)
s->dupok = 1;
break;
- case ADYNT:
- s = p->from.sym;
- if(p->to.sym == S) {
- diag("DYNT without a sym\n%P", p);
- break;
- }
- di = p->to.sym;
- p->reg = 4;
- if(di->type == SXREF) {
- if(debug['z'])
- Bprint(&bso, "%P set to %d\n", p, dtype);
- di->type = SCONST;
- di->value = dtype;
- dtype += 4;
- }
- if(s == S)
- break;
-
- p->from.offset = di->value;
- s->type = SDATA;
- if(curtext == P) {
- diag("DYNT not in text: %P", p);
- break;
- }
- p->to.sym = curtext->from.sym;
- p->to.type = D_CONST;
- if(s != S) {
- p->dlink = s->data;
- s->data = p;
- }
- if(edatap == P)
- datap = p;
- else
- edatap->link = p;
- edatap = p;
- break;
-
- case AINIT:
- s = p->from.sym;
- if(s == S) {
- diag("INIT without a sym\n%P", p);
- break;
- }
- if(di == S) {
- diag("INIT without previous DYNT\n%P", p);
- break;
- }
- p->from.offset = di->value;
- s->type = SDATA;
- if(s != S) {
- p->dlink = s->data;
- s->data = p;
- }
- if(edatap == P)
- datap = p;
- else
- edatap->link = p;
- edatap = p;
- break;
-
case ADATA:
// Assume that AGLOBL comes after ADATA.
// If we've seen an AGLOBL that said this sym was DUPOK,
// ignore any more ADATA we see, which must be
// redefinitions.
s = p->from.sym;
- if(s != S && s->dupok) {
+ if(s->dupok) {
if(debug['v'])
Bprint(&bso, "skipping %s in %s: dupok\n", s->name, pn);
goto loop;
}
- if(s != S) {
- p->dlink = s->data;
- s->data = p;
- if(s->file == nil)
- s->file = pn;
- else if(s->file != pn) {
- diag("multiple initialization for %s: in both %s and %s", s->name, s->file, pn);
- errorexit();
- }
+ if(s->file == nil)
+ s->file = pn;
+ else if(s->file != pn) {
+ diag("multiple initialization for %s: in both %s and %s", s->name, s->file, pn);
+ errorexit();
}
- if(edatap == P)
- datap = p;
- else
- edatap->link = p;
- edatap = p;
+ savedata(s, p);
+ unmal(p, sizeof *p);
break;
case AGOK:
@@ -683,31 +573,24 @@ loop:
break;
case ATEXT:
- s = p->from.sym;
- if(ntext++ == 0 && s->type != 0 && s->type != SXREF) {
- /* redefinition, so file has probably been seen before */
- if(debug['v'])
- Bprint(&bso, "skipping: %s: redefinition: %s", pn, s->name);
- return;
- }
- setarch(p);
- setthumb(p);
- p->align = 4;
- if(curtext != P) {
+ if(cursym != nil && cursym->text) {
histtoauto();
- curtext->to.autom = curauto;
+ cursym->autom = curauto;
curauto = 0;
}
- skip = 0;
- curtext = p;
- autosize = (p->to.offset+3L) & ~3L;
- p->to.offset = autosize;
- autosize += 4;
s = p->from.sym;
if(s == S) {
diag("TEXT must have a name\n%P", p);
errorexit();
}
+ cursym = s;
+ if(ntext++ == 0 && s->type != 0 && s->type != SXREF) {
+ /* redefinition, so file has probably been seen before */
+ if(debug['v'])
+ Bprint(&bso, "skipping: %s: redefinition: %s", pn, s->name);
+ return;
+ }
+ skip = 0;
if(s->type != 0 && s->type != SXREF) {
if(p->reg & DUPOK) {
skip = 1;
@@ -715,21 +598,24 @@ loop:
}
diag("redefinition: %s\n%P", s->name, p);
}
+ if(etextp)
+ etextp->next = s;
+ else
+ textp = s;
+ etextp = s;
+ setarch(p);
+ setthumb(p);
+ p->align = 4;
+ autosize = (p->to.offset+3L) & ~3L;
+ p->to.offset = autosize;
+ autosize += 4;
s->type = STEXT;
s->text = p;
s->value = pc;
s->thumb = thumb;
- lastp->link = p;
lastp = p;
p->pc = pc;
pc++;
- if(textp == P) {
- textp = p;
- etextp = p;
- goto loop;
- }
- etextp->cond = p;
- etextp = p;
break;
case ASUB:
@@ -778,27 +664,15 @@ loop:
if(skip)
goto casedef;
- if(p->from.type == D_FCONST && chipfloat(p->from.ieee) < 0) {
+ if(p->from.type == D_FCONST && chipfloat(&p->from.ieee) < 0 &&
+ (chipzero(&p->from.ieee) < 0 || (p->scond & C_SCOND) != C_SCOND_NONE)) {
/* size sb 9 max */
- sprint(literal, "$%lux", ieeedtof(p->from.ieee));
+ sprint(literal, "$%ux", ieeedtof(&p->from.ieee));
s = lookup(literal, 0);
if(s->type == 0) {
s->type = SBSS;
- s->value = 4;
- t = prg();
- t->as = ADATA;
- t->line = p->line;
- t->from.type = D_OREG;
- t->from.sym = s;
- t->from.name = D_EXTERN;
- t->reg = 4;
- t->to = p->from;
- if(edatap == P)
- datap = t;
- else
- edatap->link = t;
- edatap = t;
- t->link = P;
+ adduint32(s, ieeedtof(&p->from.ieee));
+ s->reachable = 0;
}
p->from.type = D_OREG;
p->from.sym = s;
@@ -813,28 +687,17 @@ loop:
if(skip)
goto casedef;
- if(p->from.type == D_FCONST && chipfloat(p->from.ieee) < 0) {
+ if(p->from.type == D_FCONST && chipfloat(&p->from.ieee) < 0 &&
+ (chipzero(&p->from.ieee) < 0 || (p->scond & C_SCOND) != C_SCOND_NONE)) {
/* size sb 18 max */
- sprint(literal, "$%lux.%lux",
- p->from.ieee->l, p->from.ieee->h);
+ sprint(literal, "$%ux.%ux",
+ p->from.ieee.l, p->from.ieee.h);
s = lookup(literal, 0);
if(s->type == 0) {
s->type = SBSS;
- s->value = 8;
- t = prg();
- t->as = ADATA;
- t->line = p->line;
- t->from.type = D_OREG;
- t->from.sym = s;
- t->from.name = D_EXTERN;
- t->reg = 8;
- t->to = p->from;
- if(edatap == P)
- datap = t;
- else
- edatap->link = t;
- edatap = t;
- t->link = P;
+ adduint32(s, p->from.ieee.l);
+ adduint32(s, p->from.ieee.h);
+ s->reachable = 0;
}
p->from.type = D_OREG;
p->from.sym = s;
@@ -847,13 +710,17 @@ loop:
casedef:
if(skip)
nopout(p);
-
+ p->pc = pc;
+ pc++;
if(p->to.type == D_BRANCH)
p->to.offset += ipc;
+ if(lastp == nil) {
+ if(p->as != ANOP)
+ diag("unexpected instruction: %P", p);
+ break;
+ }
lastp->link = p;
lastp = p;
- p->pc = pc;
- pc++;
break;
}
goto loop;
@@ -872,191 +739,13 @@ prg(void)
return p;
}
-void
-doprof1(void)
-{
- Sym *s;
- int32 n;
- Prog *p, *q;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f profile 1\n", cputime());
- Bflush(&bso);
- s = lookup("__mcount", 0);
- n = 1;
- for(p = firstp->link; p != P; p = p->link) {
- setarch(p);
- if(p->as == ATEXT) {
- q = prg();
- q->line = p->line;
- q->link = datap;
- datap = q;
- q->as = ADATA;
- q->from.type = D_OREG;
- q->from.name = D_EXTERN;
- q->from.offset = n*4;
- q->from.sym = s;
- q->reg = 4;
- q->to = p->from;
- q->to.type = D_CONST;
-
- q = prg();
- q->line = p->line;
- q->pc = p->pc;
- q->link = p->link;
- p->link = q;
- p = q;
- p->as = AMOVW;
- p->from.type = D_OREG;
- p->from.name = D_EXTERN;
- p->from.sym = s;
- p->from.offset = n*4 + 4;
- p->to.type = D_REG;
- p->to.reg = thumb ? REGTMPT : REGTMP;
-
- q = prg();
- q->line = p->line;
- q->pc = p->pc;
- q->link = p->link;
- p->link = q;
- p = q;
- p->as = AADD;
- p->from.type = D_CONST;
- p->from.offset = 1;
- p->to.type = D_REG;
- p->to.reg = thumb ? REGTMPT : REGTMP;
-
- q = prg();
- q->line = p->line;
- q->pc = p->pc;
- q->link = p->link;
- p->link = q;
- p = q;
- p->as = AMOVW;
- p->from.type = D_REG;
- p->from.reg = thumb ? REGTMPT : REGTMP;
- p->to.type = D_OREG;
- p->to.name = D_EXTERN;
- p->to.sym = s;
- p->to.offset = n*4 + 4;
-
- n += 2;
- continue;
- }
- }
- q = prg();
- q->line = 0;
- q->link = datap;
- datap = q;
-
- q->as = ADATA;
- q->from.type = D_OREG;
- q->from.name = D_EXTERN;
- q->from.sym = s;
- q->reg = 4;
- q->to.type = D_CONST;
- q->to.offset = n;
-
- s->type = SBSS;
- s->value = n*4;
-}
-
-void
-doprof2(void)
-{
- Sym *s2, *s4;
- Prog *p, *q, *ps2, *ps4;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f profile 2\n", cputime());
- Bflush(&bso);
- s2 = lookup("_profin", 0);
- s4 = lookup("_profout", 0);
- if(s2->type != STEXT || s4->type != STEXT) {
- diag("_profin/_profout not defined");
- return;
- }
- ps2 = P;
- ps4 = P;
- for(p = firstp; p != P; p = p->link) {
- setarch(p);
- if(p->as == ATEXT) {
- if(p->from.sym == s2) {
- ps2 = p;
- p->reg = 1;
- }
- if(p->from.sym == s4) {
- ps4 = p;
- p->reg = 1;
- }
- }
- }
- for(p = firstp; p != P; p = p->link) {
- setarch(p);
- if(p->as == ATEXT) {
- if(p->reg & NOPROF) {
- for(;;) {
- q = p->link;
- if(q == P)
- break;
- if(q->as == ATEXT)
- break;
- p = q;
- }
- continue;
- }
-
- /*
- * BL profin, R2
- */
- q = prg();
- q->line = p->line;
- q->pc = p->pc;
- q->link = p->link;
- p->link = q;
- p = q;
- p->as = ABL;
- p->to.type = D_BRANCH;
- p->cond = ps2;
- p->to.sym = s2;
-
- continue;
- }
- if(p->as == ARET) {
- /*
- * RET
- */
- q = prg();
- q->as = ARET;
- q->from = p->from;
- q->to = p->to;
- q->link = p->link;
- p->link = q;
-
- /*
- * BL profout
- */
- p->as = ABL;
- p->from = zprg.from;
- p->to = zprg.to;
- p->to.type = D_BRANCH;
- p->cond = ps4;
- p->to.sym = s4;
-
- p = q;
-
- continue;
- }
- }
-}
-
static void
puntfp(Prog *p)
{
USED(p);
/* floating point - punt for now */
- curtext->reg = NREG; /* ARM */
- curtext->from.sym->thumb = 0;
+ cursym->text->reg = NREG; /* ARM */
+ cursym->thumb = 0;
thumb = 0;
// print("%s: generating ARM code (contains floating point ops %d)\n", curtext->from.sym->name, p->line);
}
diff --git a/src/cmd/5l/optab.c b/src/cmd/5l/optab.c
index 92fe12fc2..96b216837 100644
--- a/src/cmd/5l/optab.c
+++ b/src/cmd/5l/optab.c
@@ -34,8 +34,6 @@ Optab optab[] =
{
/* struct Optab:
OPCODE, from, prog->reg, to, type,size,param,flag */
- { ATEXT, C_LEXT, C_NONE, C_LCON, 0, 0, 0 },
- { ATEXT, C_LEXT, C_REG, C_LCON, 0, 0, 0 },
{ ATEXT, C_ADDR, C_NONE, C_LCON, 0, 0, 0 },
{ ATEXT, C_ADDR, C_REG, C_LCON, 0, 0, 0 },
@@ -56,7 +54,6 @@ Optab optab[] =
{ AMVN, C_SHIFT,C_NONE, C_REG, 3, 4, 0 },
{ ACMP, C_SHIFT,C_REG, C_NONE, 3, 4, 0 },
- { AMOVW, C_RECON,C_NONE, C_REG, 4, 4, REGSB },
{ AMOVW, C_RACON,C_NONE, C_REG, 4, 4, REGSP },
{ AB, C_NONE, C_NONE, C_SBRA, 5, 4, 0, LPOOL },
@@ -81,7 +78,6 @@ Optab optab[] =
{ AWORD, C_NONE, C_NONE, C_LCON, 11, 4, 0 },
{ AWORD, C_NONE, C_NONE, C_GCON, 11, 4, 0 },
- { AWORD, C_NONE, C_NONE, C_LEXT, 11, 4, 0 },
{ AWORD, C_NONE, C_NONE, C_ADDR, 11, 4, 0 },
{ AMOVW, C_NCON, C_NONE, C_REG, 12, 4, 0 },
@@ -109,85 +105,64 @@ Optab optab[] =
{ AMULL, C_REG, C_REG, C_REGREG, 17, 4, 0 },
- { AMOVW, C_REG, C_NONE, C_SEXT, 20, 4, REGSB },
{ AMOVW, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP },
{ AMOVW, C_REG, C_NONE, C_SOREG, 20, 4, 0 },
- { AMOVB, C_REG, C_NONE, C_SEXT, 20, 4, REGSB },
{ AMOVB, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP },
{ AMOVB, C_REG, C_NONE, C_SOREG, 20, 4, 0 },
- { AMOVBU, C_REG, C_NONE, C_SEXT, 20, 4, REGSB },
{ AMOVBU, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP },
{ AMOVBU, C_REG, C_NONE, C_SOREG, 20, 4, 0 },
- { AMOVW, C_SEXT, C_NONE, C_REG, 21, 4, REGSB },
{ AMOVW, C_SAUTO,C_NONE, C_REG, 21, 4, REGSP },
{ AMOVW, C_SOREG,C_NONE, C_REG, 21, 4, 0 },
- { AMOVBU, C_SEXT, C_NONE, C_REG, 21, 4, REGSB },
{ AMOVBU, C_SAUTO,C_NONE, C_REG, 21, 4, REGSP },
{ AMOVBU, C_SOREG,C_NONE, C_REG, 21, 4, 0 },
- { AMOVB, C_SEXT, C_NONE, C_REG, 22, 12, REGSB },
{ AMOVB, C_SAUTO,C_NONE, C_REG, 22, 12, REGSP },
{ AMOVB, C_SOREG,C_NONE, C_REG, 22, 12, 0 },
- { AMOVH, C_SEXT, C_NONE, C_REG, 22, 12, REGSB },
{ AMOVH, C_SAUTO,C_NONE, C_REG, 22, 12, REGSP },
{ AMOVH, C_SOREG,C_NONE, C_REG, 22, 12, 0 },
- { AMOVHU, C_SEXT, C_NONE, C_REG, 22, 12, REGSB },
{ AMOVHU, C_SAUTO,C_NONE, C_REG, 22, 12, REGSP },
{ AMOVHU, C_SOREG,C_NONE, C_REG, 22, 12, 0 },
- { AMOVH, C_REG, C_NONE, C_SEXT, 23, 12, REGSB },
{ AMOVH, C_REG, C_NONE, C_SAUTO, 23, 12, REGSP },
{ AMOVH, C_REG, C_NONE, C_SOREG, 23, 12, 0 },
- { AMOVHU, C_REG, C_NONE, C_SEXT, 23, 12, REGSB },
{ AMOVHU, C_REG, C_NONE, C_SAUTO, 23, 12, REGSP },
{ AMOVHU, C_REG, C_NONE, C_SOREG, 23, 12, 0 },
- { AMOVW, C_REG, C_NONE, C_LEXT, 30, 8, REGSB, LTO },
{ AMOVW, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO },
{ AMOVW, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO },
{ AMOVW, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO },
- { AMOVB, C_REG, C_NONE, C_LEXT, 30, 8, REGSB, LTO },
{ AMOVB, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO },
{ AMOVB, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO },
{ AMOVB, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO },
- { AMOVBU, C_REG, C_NONE, C_LEXT, 30, 8, REGSB, LTO },
{ AMOVBU, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO },
{ AMOVBU, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO },
{ AMOVBU, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO },
- { AMOVW, C_LEXT, C_NONE, C_REG, 31, 8, REGSB, LFROM },
{ AMOVW, C_LAUTO,C_NONE, C_REG, 31, 8, REGSP, LFROM },
{ AMOVW, C_LOREG,C_NONE, C_REG, 31, 8, 0, LFROM },
{ AMOVW, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM },
- { AMOVBU, C_LEXT, C_NONE, C_REG, 31, 8, REGSB, LFROM },
{ AMOVBU, C_LAUTO,C_NONE, C_REG, 31, 8, REGSP, LFROM },
{ AMOVBU, C_LOREG,C_NONE, C_REG, 31, 8, 0, LFROM },
{ AMOVBU, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM },
- { AMOVB, C_LEXT, C_NONE, C_REG, 32, 16, REGSB, LFROM },
{ AMOVB, C_LAUTO,C_NONE, C_REG, 32, 16, REGSP, LFROM },
{ AMOVB, C_LOREG,C_NONE, C_REG, 32, 16, 0, LFROM },
{ AMOVB, C_ADDR, C_NONE, C_REG, 66, 16, 0, LFROM },
- { AMOVH, C_LEXT, C_NONE, C_REG, 32, 16, REGSB, LFROM },
{ AMOVH, C_LAUTO,C_NONE, C_REG, 32, 16, REGSP, LFROM },
{ AMOVH, C_LOREG,C_NONE, C_REG, 32, 16, 0, LFROM },
{ AMOVH, C_ADDR, C_NONE, C_REG, 66, 16, 0, LFROM },
- { AMOVHU, C_LEXT, C_NONE, C_REG, 32, 16, REGSB, LFROM },
{ AMOVHU, C_LAUTO,C_NONE, C_REG, 32, 16, REGSP, LFROM },
{ AMOVHU, C_LOREG,C_NONE, C_REG, 32, 16, 0, LFROM },
{ AMOVHU, C_ADDR, C_NONE, C_REG, 66, 16, 0, LFROM },
- { AMOVH, C_REG, C_NONE, C_LEXT, 33, 24, REGSB, LTO },
{ AMOVH, C_REG, C_NONE, C_LAUTO, 33, 24, REGSP, LTO },
{ AMOVH, C_REG, C_NONE, C_LOREG, 33, 24, 0, LTO },
{ AMOVH, C_REG, C_NONE, C_ADDR, 67, 24, 0, LTO },
- { AMOVHU, C_REG, C_NONE, C_LEXT, 33, 24, REGSB, LTO },
{ AMOVHU, C_REG, C_NONE, C_LAUTO, 33, 24, REGSP, LTO },
{ AMOVHU, C_REG, C_NONE, C_LOREG, 33, 24, 0, LTO },
{ AMOVHU, C_REG, C_NONE, C_ADDR, 67, 24, 0, LTO },
- { AMOVW, C_LECON,C_NONE, C_REG, 34, 8, REGSB, LFROM },
{ AMOVW, C_LACON,C_NONE, C_REG, 34, 8, REGSP, LFROM },
{ AMOVW, C_PSR, C_NONE, C_REG, 35, 4, 0 },
@@ -201,19 +176,15 @@ Optab optab[] =
{ ARFE, C_NONE, C_NONE, C_NONE, 41, 4, 0 },
- { AMOVF, C_FREG, C_NONE, C_FEXT, 50, 4, REGSB },
{ AMOVF, C_FREG, C_NONE, C_FAUTO, 50, 4, REGSP },
{ AMOVF, C_FREG, C_NONE, C_FOREG, 50, 4, 0 },
- { AMOVF, C_FEXT, C_NONE, C_FREG, 51, 4, REGSB },
{ AMOVF, C_FAUTO,C_NONE, C_FREG, 51, 4, REGSP },
{ AMOVF, C_FOREG,C_NONE, C_FREG, 51, 4, 0 },
- { AMOVF, C_FREG, C_NONE, C_LEXT, 52, 12, REGSB, LTO },
{ AMOVF, C_FREG, C_NONE, C_LAUTO, 52, 12, REGSP, LTO },
{ AMOVF, C_FREG, C_NONE, C_LOREG, 52, 12, 0, LTO },
- { AMOVF, C_LEXT, C_NONE, C_FREG, 53, 12, REGSB, LFROM },
{ AMOVF, C_LAUTO,C_NONE, C_FREG, 53, 12, REGSP, LFROM },
{ AMOVF, C_LOREG,C_NONE, C_FREG, 53, 12, 0, LFROM },
@@ -222,17 +193,8 @@ Optab optab[] =
{ AADDF, C_FREG, C_NONE, C_FREG, 54, 4, 0 },
{ AADDF, C_FREG, C_REG, C_FREG, 54, 4, 0 },
- { AADDF, C_FCON, C_NONE, C_FREG, 54, 4, 0 },
- { AADDF, C_FCON, C_REG, C_FREG, 54, 4, 0 },
- { AMOVF, C_FCON, C_NONE, C_FREG, 54, 4, 0 },
{ AMOVF, C_FREG, C_NONE, C_FREG, 54, 4, 0 },
- { ACMPF, C_FREG, C_REG, C_NONE, 54, 4, 0 },
- { ACMPF, C_FCON, C_REG, C_NONE, 54, 4, 0 },
-
- { AMOVFW, C_FREG, C_NONE, C_REG, 55, 4, 0 },
- { AMOVFW, C_REG, C_NONE, C_FREG, 55, 4, 0 },
-
{ AMOVW, C_REG, C_NONE, C_FCR, 56, 4, 0 },
{ AMOVW, C_FCR, C_NONE, C_REG, 57, 4, 0 },
@@ -248,41 +210,46 @@ Optab optab[] =
{ ACASE, C_REG, C_NONE, C_NONE, 62, 4, 0 },
{ ABCASE, C_NONE, C_NONE, C_SBRA, 63, 4, 0 },
- { AMOVH, C_REG, C_NONE, C_HEXT, 70, 4, REGSB, V4 },
{ AMOVH, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, V4 },
{ AMOVH, C_REG, C_NONE, C_HOREG, 70, 4, 0, V4 },
- { AMOVHU, C_REG, C_NONE, C_HEXT, 70, 4, REGSB, V4 },
{ AMOVHU, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, V4 },
{ AMOVHU, C_REG, C_NONE, C_HOREG, 70, 4, 0, V4 },
- { AMOVB, C_HEXT, C_NONE, C_REG, 71, 4, REGSB, V4 },
{ AMOVB, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, V4 },
{ AMOVB, C_HOREG,C_NONE, C_REG, 71, 4, 0, V4 },
- { AMOVH, C_HEXT, C_NONE, C_REG, 71, 4, REGSB, V4 },
{ AMOVH, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, V4 },
{ AMOVH, C_HOREG,C_NONE, C_REG, 71, 4, 0, V4 },
- { AMOVHU, C_HEXT, C_NONE, C_REG, 71, 4, REGSB, V4 },
{ AMOVHU, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, V4 },
{ AMOVHU, C_HOREG,C_NONE, C_REG, 71, 4, 0, V4 },
- { AMOVH, C_REG, C_NONE, C_LEXT, 72, 8, REGSB, LTO|V4 },
{ AMOVH, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO|V4 },
{ AMOVH, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO|V4 },
- { AMOVHU, C_REG, C_NONE, C_LEXT, 72, 8, REGSB, LTO|V4 },
{ AMOVHU, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO|V4 },
{ AMOVHU, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO|V4 },
- { AMOVB, C_LEXT, C_NONE, C_REG, 73, 8, REGSB, LFROM|V4 },
{ AMOVB, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM|V4 },
{ AMOVB, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM|V4 },
- { AMOVH, C_LEXT, C_NONE, C_REG, 73, 8, REGSB, LFROM|V4 },
{ AMOVH, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM|V4 },
{ AMOVH, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM|V4 },
- { AMOVHU, C_LEXT, C_NONE, C_REG, 73, 8, REGSB, LFROM|V4 },
{ AMOVHU, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM|V4 },
{ AMOVHU, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM|V4 },
{ ALDREX, C_SOREG,C_NONE, C_REG, 77, 4, 0 },
{ ASTREX, C_SOREG,C_REG, C_REG, 78, 4, 0 },
+ { AMOVF, C_ZFCON,C_NONE, C_FREG, 80, 4, 0 },
+ { AMOVF, C_SFCON,C_NONE, C_FREG, 81, 4, 0 },
+
+ { ACMPF, C_FREG, C_REG, C_NONE, 82, 8, 0 },
+ { ACMPF, C_FREG, C_NONE, C_NONE, 83, 8, 0 },
+
+ { AMOVFW, C_FREG, C_NONE, C_FREG, 84, 4, 0 },
+ { AMOVWF, C_FREG, C_NONE, C_FREG, 85, 4, 0 },
+
+ { AMOVFW, C_FREG, C_NONE, C_REG, 86, 8, 0 },
+ { AMOVWF, C_REG, C_NONE, C_FREG, 87, 8, 0 },
+
+ { AMOVW, C_REG, C_NONE, C_FREG, 88, 4, 0 },
+ { AMOVW, C_FREG, C_NONE, C_REG, 89, 4, 0 },
+
{ AXXX, C_NONE, C_NONE, C_NONE, 0, 4, 0 },
};
diff --git a/src/cmd/5l/pass.c b/src/cmd/5l/pass.c
index 06b1792b4..e16b34171 100644
--- a/src/cmd/5l/pass.c
+++ b/src/cmd/5l/pass.c
@@ -28,147 +28,12 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+// Code and data passes.
+
#include "l.h"
#include "../ld/lib.h"
-void
-dodata(void)
-{
- int i, t;
- Sym *s;
- Prog *p;
- int32 orig, v;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f dodata\n", cputime());
- Bflush(&bso);
- for(p = datap; p != P; p = p->link) {
- s = p->from.sym;
- if(p->as == ADYNT || p->as == AINIT)
- s->value = dtype;
- if(s->type == SBSS)
- s->type = SDATA;
- if(s->type != SDATA && s->type != SELFDATA)
- diag("initialize non-data (%d): %s\n%P",
- s->type, s->name, p);
- v = p->from.offset + p->reg;
- if(v > s->value)
- diag("initialize bounds (%ld/%ld): %s\n%P",
- v, s->value, s->name, p);
- if((s->type == SBSS || s->type == SDATA) && (p->to.type == D_CONST || p->to.type == D_OCONST) && (p->to.name == D_EXTERN || p->to.name == D_STATIC)){
- s = p->to.sym;
- if(s != S && (s->type == STEXT || s->type == SLEAF || s->type == SCONST || s->type == SXREF))
- s->fnptr = 1;
- }
- }
-
- if(debug['t']) {
- /*
- * pull out string constants
- */
- for(p = datap; p != P; p = p->link) {
- s = p->from.sym;
- if(p->to.type == D_SCONST)
- s->type = SSTRING;
- }
- }
-
- /*
- * pass 0
- * assign elf data - must be segregated from real data
- */
- orig = 0;
- for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->link) {
- if(!s->reachable || s->type != SELFDATA)
- continue;
- v = s->value;
- while(v & 3)
- v++;
- s->size = v;
- s->value = orig;
- orig += v;
- }
- elfdatsize = orig;
-
- /*
- * pass 1
- * assign 'small' variables to data segment
- * (rational is that data segment is more easily
- * addressed through offset on R12)
- */
- for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->link) {
- t = s->type;
- if(t != SDATA && t != SBSS)
- continue;
- v = s->value;
- if(v == 0) {
- diag("%s: no size", s->name);
- v = 1;
- }
- while(v & 3)
- v++;
- s->size = v;
- s->value = v;
- if(v > MINSIZ)
- continue;
- s->value = orig;
- orig += v;
- s->type = SDATA1;
- }
-
- /*
- * pass 2
- * assign large 'data' variables to data segment
- */
- for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->link) {
- t = s->type;
- if(t != SDATA) {
- if(t == SDATA1)
- s->type = SDATA;
- continue;
- }
- v = s->value;
- s->size = v;
- s->value = orig;
- orig += v;
- }
-
- while(orig & 7)
- orig++;
- datsize = orig;
-
- /*
- * pass 3
- * everything else to bss segment
- */
- for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->link) {
- if(s->type != SBSS)
- continue;
- v = s->value;
- s->size = v;
- s->value = orig;
- orig += v;
- }
- while(orig & 7)
- orig++;
- bsssize = orig-datsize;
-
- xdefine("setR12", SDATA, 0L+BIG);
- xdefine("bdata", SDATA, 0L);
- xdefine("data", SBSS, 0);
- xdefine("edata", SDATA, datsize);
- xdefine("end", SBSS, datsize+bsssize);
- xdefine("etext", STEXT, 0L);
-
- if(debug['s'])
- xdefine("symdat", SFIXED, 0);
- else
- xdefine("symdat", SFIXED, SYMDATVA);
-}
+static void xfol(Prog*, Prog**);
void
undef(void)
@@ -177,7 +42,7 @@ undef(void)
Sym *s;
for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->link)
+ for(s = hash[i]; s != S; s = s->hash)
if(s->type == SXREF)
diag("%s: not defined", s->name);
}
@@ -223,20 +88,23 @@ relinv(int a)
void
follow(void)
{
+ Prog *firstp, *lastp;
+
if(debug['v'])
Bprint(&bso, "%5.2f follow\n", cputime());
Bflush(&bso);
- firstp = prg();
- lastp = firstp;
- xfol(textp);
-
- firstp = firstp->link;
- lastp->link = P;
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ firstp = prg();
+ lastp = firstp;
+ xfol(cursym->text, &lastp);
+ lastp->link = nil;
+ cursym->text = firstp->link;
+ }
}
-void
-xfol(Prog *p)
+static void
+xfol(Prog *p, Prog **last)
{
Prog *q, *r;
int a, i;
@@ -246,12 +114,6 @@ loop:
return;
setarch(p);
a = p->as;
- if(a == ATEXT)
- curtext = p;
- if(!curtext->from.sym->reachable) {
- p = p->cond;
- goto loop;
- }
if(a == AB) {
q = p->cond;
if(q != P && q->as != ATEXT) {
@@ -263,7 +125,7 @@ loop:
}
if(p->mark & FOLL) {
for(i=0,q=p; i<4; i++,q=q->link) {
- if(q == lastp)
+ if(q == *last || q == nil)
break;
a = q->as;
if(a == ANOP) {
@@ -272,7 +134,7 @@ loop:
}
if(a == AB || (a == ARET && q->scond == 14) || a == ARFE)
goto copy;
- if(!q->cond || (q->cond->mark&FOLL))
+ if(q->cond == P || (q->cond->mark&FOLL))
continue;
if(a != ABEQ && a != ABNE)
continue;
@@ -285,12 +147,12 @@ loop:
r->mark |= FOLL;
if(p != q) {
p = p->link;
- lastp->link = r;
- lastp = r;
+ (*last)->link = r;
+ *last = r;
continue;
}
- lastp->link = r;
- lastp = r;
+ (*last)->link = r;
+ *last = r;
if(a == AB || (a == ARET && q->scond == 14) || a == ARFE)
return;
r->as = ABNE;
@@ -299,7 +161,7 @@ loop:
r->cond = p->link;
r->link = p->cond;
if(!(r->link->mark&FOLL))
- xfol(r->link);
+ xfol(r->link, last);
if(!(r->cond->mark&FOLL))
print("cant happen 2\n");
return;
@@ -315,8 +177,8 @@ loop:
p = q;
}
p->mark |= FOLL;
- lastp->link = p;
- lastp = p;
+ (*last)->link = p;
+ *last = p;
if(a == AB || (a == ARET && p->scond == 14) || a == ARFE){
return;
}
@@ -329,7 +191,7 @@ loop:
p->link = p->cond;
p->cond = q;
}
- xfol(p->link);
+ xfol(p->link, last);
q = brchain(p->cond);
if(q == P)
q = p->cond;
@@ -349,7 +211,7 @@ patch(void)
{
int32 c, vexit;
Prog *p, *q;
- Sym *s, *s1;
+ Sym *s;
int a;
if(debug['v'])
@@ -358,113 +220,71 @@ patch(void)
mkfwd();
s = lookup("exit", 0);
vexit = s->value;
- for(p = firstp; p != P; p = p->link) {
- setarch(p);
- a = p->as;
- if(a == ATEXT)
- curtext = p;
- if(seenthumb && a == ABL){
- // if((s = p->to.sym) != S && (s1 = curtext->from.sym) != S)
- // print("%s calls %s\n", s1->name, s->name);
- if((s = p->to.sym) != S && (s1 = curtext->from.sym) != S && s->thumb != s1->thumb)
- s->foreign = 1;
- }
- if((a == ABL || a == ABX || a == AB || a == ARET) &&
- p->to.type != D_BRANCH && p->to.sym != S) {
- s = p->to.sym;
- switch(s->type) {
- default:
- diag("undefined: %s", s->name);
- s->type = STEXT;
- s->value = vexit;
- continue; // avoid more error messages
- case STEXT:
- p->to.offset = s->value;
- p->to.type = D_BRANCH;
- break;
- case SUNDEF:
- if(p->as != ABL)
- diag("help: SUNDEF in AB || ARET");
- p->to.offset = 0;
- p->to.type = D_BRANCH;
- p->cond = UP;
- break;
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ for(p = cursym->text; p != P; p = p->link) {
+ setarch(p);
+ a = p->as;
+ if(seenthumb && a == ABL){
+ // if((s = p->to.sym) != S && (s1 = curtext->from.sym) != S)
+ // print("%s calls %s\n", s1->name, s->name);
+ if((s = p->to.sym) != S && s->thumb != cursym->thumb)
+ s->foreign = 1;
}
- }
- if(p->to.type != D_BRANCH || p->cond == UP)
- continue;
- c = p->to.offset;
- for(q = firstp; q != P;) {
- if(q->forwd != P)
- if(c >= q->forwd->pc) {
- q = q->forwd;
+ if((a == ABL || a == ABX || a == AB || a == ARET) &&
+ p->to.type != D_BRANCH && p->to.sym != S) {
+ s = p->to.sym;
+ switch(s->type) {
+ default:
+ diag("undefined: %s", s->name);
+ s->type = STEXT;
+ s->value = vexit;
+ continue; // avoid more error messages
+ case STEXT:
+ p->to.offset = s->value;
+ p->to.type = D_BRANCH;
+ break;
+ }
+ }
+ if(p->to.type != D_BRANCH)
continue;
+ c = p->to.offset;
+ for(q = textp->text; q != P;) {
+ if(c == q->pc)
+ break;
+ if(q->forwd != P && c >= q->forwd->pc)
+ q = q->forwd;
+ else
+ q = q->link;
}
- if(c == q->pc)
- break;
- q = q->link;
- }
- if(q == P) {
- diag("branch out of range %ld\n%P", c, p);
- p->to.type = D_NONE;
+ if(q == P) {
+ diag("branch out of range %d\n%P", c, p);
+ p->to.type = D_NONE;
+ }
+ p->cond = q;
}
- p->cond = q;
}
- for(p = firstp; p != P; p = p->link) {
- setarch(p);
- a = p->as;
- if(p->as == ATEXT)
- curtext = p;
- if(seenthumb && a == ABL) {
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ for(p = cursym->text; p != P; p = p->link) {
+ setarch(p);
+ a = p->as;
+ if(seenthumb && a == ABL) {
#ifdef CALLEEBX
- if(0)
- {}
+ if(0)
+ {}
#else
- if((s = p->to.sym) != S && (s->foreign || s->fnptr))
- p->as = ABX;
+ if((s = p->to.sym) != S && (s->foreign || s->fnptr))
+ p->as = ABX;
#endif
- else if(p->to.type == D_OREG)
- p->as = ABX;
- }
- if(p->cond != P && p->cond != UP) {
- p->cond = brloop(p->cond);
- if(p->cond != P)
- if(p->to.type == D_BRANCH)
- p->to.offset = p->cond->pc;
- }
- }
-}
-
-#define LOG 5
-void
-mkfwd(void)
-{
- Prog *p;
- int32 dwn[LOG], cnt[LOG], i;
- Prog *lst[LOG];
-
- for(i=0; i<LOG; i++) {
- if(i == 0)
- cnt[i] = 1; else
- cnt[i] = LOG * cnt[i-1];
- dwn[i] = 1;
- lst[i] = P;
- }
- i = 0;
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT)
- curtext = p;
- i--;
- if(i < 0)
- i = LOG-1;
- p->forwd = P;
- dwn[i]--;
- if(dwn[i] <= 0) {
- dwn[i] = cnt[i];
- if(lst[i] != P)
- lst[i]->forwd = p;
- lst[i] = p;
+ else if(p->to.type == D_OREG)
+ p->as = ABX;
+ }
+ if(p->cond != P) {
+ p->cond = brloop(p->cond);
+ if(p->cond != P)
+ if(p->to.type == D_BRANCH)
+ p->to.offset = p->cond->pc;
+ }
}
}
}
@@ -543,462 +363,3 @@ rnd(int32 v, int32 r)
v -= c;
return v;
}
-
-#define Reachable(n) if((s = lookup(n, 0)) != nil) s->used++
-
-static void
-rused(Adr *a)
-{
- Sym *s = a->sym;
-
- if(s == S)
- return;
- if(a->type == D_OREG || a->type == D_OCONST || a->type == D_CONST){
- if(a->name == D_EXTERN || a->name == D_STATIC){
- if(s->used == 0)
- s->used = 1;
- }
- }
- else if(a->type == D_BRANCH){
- if(s->used == 0)
- s->used = 1;
- }
-}
-
-void
-reachable()
-{
- Prog *p, *prev, *prevt, *nextt, *q;
- Sym *s, *s0;
- int i, todo;
- char *a;
-
- Reachable("_div");
- Reachable("_divu");
- Reachable("_mod");
- Reachable("_modu");
- a = INITENTRY;
- if(*a >= '0' && *a <= '9')
- return;
- s = lookup(a, 0);
- if(s == nil)
- return;
- if(s->type == 0){
- s->used = 1; // to stop asm complaining
- for(p = firstp; p != P && p->as != ATEXT; p = p->link)
- ;
- if(p == nil)
- return;
- s = p->from.sym;
- }
- s->used = 1;
- do{
- todo = 0;
- for(p = firstp; p != P; p = p->link){
- if(p->as == ATEXT && (s0 = p->from.sym)->used == 1){
- todo = 1;
- for(q = p->link; q != P && q->as != ATEXT; q = q->link){
- rused(&q->from);
- rused(&q->to);
- }
- s0->used = 2;
- }
- }
- for(p = datap; p != P; p = p->link){
- if((s0 = p->from.sym)->used == 1){
- todo = 1;
- for(q = p; q != P; q = q->link){ // data can be scattered
- if(q->from.sym == s0)
- rused(&q->to);
- }
- s0->used = 2;
- }
- }
- }while(todo);
- prev = nil;
- prevt = nextt = nil;
- for(p = firstp; p != P; ){
- if(p->as == ATEXT){
- prevt = nextt;
- nextt = p;
- }
- if(p->as == ATEXT && (s0 = p->from.sym)->used == 0){
- s0->type = SREMOVED;
- for(q = p->link; q != P && q->as != ATEXT; q = q->link)
- ;
- if(q != p->cond)
- diag("bad ptr in reachable()");
- if(prev == nil)
- firstp = q;
- else
- prev->link = q;
- if(q == nil)
- lastp = prev;
- if(prevt == nil)
- textp = q;
- else
- prevt->cond = q;
- if(q == nil)
- etextp = prevt;
- nextt = prevt;
- if(debug['V'])
- print("%s unused\n", s0->name);
- p = q;
- }
- else{
- prev = p;
- p = p->link;
- }
- }
- prevt = nil;
- for(p = datap; p != nil; ){
- if((s0 = p->from.sym)->used == 0){
- s0->type = SREMOVED;
- prev = prevt;
- for(q = p; q != nil; q = q->link){
- if(q->from.sym == s0){
- if(prev == nil)
- datap = q->link;
- else
- prev->link = q->link;
- }
- else
- prev = q;
- }
- if(debug['V'])
- print("%s unused (data)\n", s0->name);
- p = prevt->link;
- }
- else{
- prevt = p;
- p = p->link;
- }
- }
- for(i=0; i<NHASH; i++){
- for(s = hash[i]; s != S; s = s->link){
- if(s->used == 0)
- s->type = SREMOVED;
- }
- }
-}
-
-static void
-fused(Adr *a, Prog *p, Prog *ct)
-{
- Sym *s = a->sym;
- Use *u;
-
- if(s == S)
- return;
- if(a->type == D_OREG || a->type == D_OCONST || a->type == D_CONST){
- if(a->name == D_EXTERN || a->name == D_STATIC){
- u = malloc(sizeof(Use));
- u->p = p;
- u->ct = ct;
- u->link = s->use;
- s->use = u;
- }
- }
- else if(a->type == D_BRANCH){
- u = malloc(sizeof(Use));
- u->p = p;
- u->ct = ct;
- u->link = s->use;
- s->use = u;
- }
-}
-
-static int
-ckfpuse(Prog *p, Prog *ct, Sym *fp, Sym *r)
-{
- int reg;
-
- USED(fp);
- USED(ct);
- if(p->from.sym == r && p->as == AMOVW && (p->from.type == D_CONST || p->from.type == D_OREG) && p->reg == NREG && p->to.type == D_REG){
- reg = p->to.reg;
- for(p = p->link; p != P && p->as != ATEXT; p = p->link){
- if((p->as == ABL || p->as == ABX) && p->to.type == D_OREG && p->to.reg == reg)
- return 1;
- if(!debug['F'] && (isbranch(p) || p->as == ARET)){
- // print("%s: branch %P in %s\n", fp->name, p, ct->from.sym->name);
- return 0;
- }
- if((p->from.type == D_REG || p->from.type == D_OREG) && p->from.reg == reg){
- if(!debug['F'] && p->to.type != D_REG){
- // print("%s: store %P in %s\n", fp->name, p, ct->from.sym->name);
- return 0;
- }
- reg = p->to.reg;
- }
- }
- }
- // print("%s: no MOVW O(R), R\n", fp->name);
- return debug['F'];
-}
-
-static void
-setfpuse(Prog *p, Sym *fp, Sym *r)
-{
- int reg;
-
- if(p->from.sym == r && p->as == AMOVW && (p->from.type == D_CONST || p->from.type == D_OREG) && p->reg == NREG && p->to.type == D_REG){
- reg = p->to.reg;
- for(p = p->link; p != P && p->as != ATEXT; p = p->link){
- if((p->as == ABL || p->as == ABX) && p->to.type == D_OREG && p->to.reg == reg){
- fp->fnptr = 0;
- p->as = ABL; // safe to do so
-// print("simplified %s call\n", fp->name);
- break;
- }
- if(!debug['F'] && (isbranch(p) || p->as == ARET))
- diag("bad setfpuse call");
- if((p->from.type == D_REG || p->from.type == D_OREG) && p->from.reg == reg){
- if(!debug['F'] && p->to.type != D_REG)
- diag("bad setfpuse call");
- reg = p->to.reg;
- }
- }
- }
-}
-
-static int
-cksymuse(Sym *s, int t)
-{
- Prog *p;
-
- for(p = datap; p != P; p = p->link){
- if(p->from.sym == s && p->to.sym != nil && strcmp(p->to.sym->name, ".string") != 0 && p->to.sym->thumb != t){
- // print("%s %s %d %d ", p->from.sym->name, p->to.sym->name, p->to.sym->thumb, t);
- return 0;
- }
- }
- return 1;
-}
-
-/* check the use of s at the given point */
-static int
-ckuse(Sym *s, Sym *s0, Use *u)
-{
- Sym *s1;
-
- s1 = u->p->from.sym;
-// print("ckuse %s %s %s\n", s->name, s0->name, s1 ? s1->name : "nil");
- if(u->ct == nil){ /* in data area */
- if(s0 == s && !cksymuse(s1, s0->thumb)){
- // print("%s: cksymuse fails\n", s0->name);
- return 0;
- }
- for(u = s1->use; u != U; u = u->link)
- if(!ckuse(s1, s0, u))
- return 0;
- }
- else{ /* in text area */
- if(u->ct->from.sym->thumb != s0->thumb){
- // print("%s(%d): foreign call %s(%d)\n", s0->name, s0->thumb, u->ct->from.sym->name, u->ct->from.sym->thumb);
- return 0;
- }
- return ckfpuse(u->p, u->ct, s0, s);
- }
- return 1;
-}
-
-static void
-setuse(Sym *s, Sym *s0, Use *u)
-{
- Sym *s1;
-
- s1 = u->p->from.sym;
- if(u->ct == nil){ /* in data area */
- for(u = s1->use; u != U; u = u->link)
- setuse(s1, s0, u);
- }
- else{ /* in text area */
- setfpuse(u->p, s0, s);
- }
-}
-
-/* detect BX O(R) which can be done as BL O(R) */
-void
-fnptrs()
-{
- int i;
- Sym *s;
- Prog *p;
- Use *u;
-
- for(i=0; i<NHASH; i++){
- for(s = hash[i]; s != S; s = s->link){
- if(s->fnptr && (s->type == STEXT || s->type == SLEAF || s->type == SCONST)){
- // print("%s : fnptr %d %d\n", s->name, s->thumb, s->foreign);
- }
- }
- }
- /* record use of syms */
- for(p = firstp; p != P; p = p->link){
- if(p->as == ATEXT)
- curtext = p;
- else{
- fused(&p->from, p, curtext);
- fused(&p->to, p, curtext);
- }
- }
- for(p = datap; p != P; p = p->link)
- fused(&p->to, p, nil);
-
- /* now look for fn ptrs */
- for(i=0; i<NHASH; i++){
- for(s = hash[i]; s != S; s = s->link){
- if(s->fnptr && (s->type == STEXT || s->type == SLEAF || s->type == SCONST)){
- for(u = s->use; u != U; u = u->link){
- if(!ckuse(s, s, u))
- break;
- }
- if(u == U){ // can simplify
- for(u = s->use; u != U; u = u->link)
- setuse(s, s, u);
- }
- }
- }
- }
-
- /* now free Use structures */
-}
-
-void
-import(void)
-{
- int i;
- Sym *s;
-
- for(i = 0; i < NHASH; i++)
- for(s = hash[i]; s != S; s = s->link)
- if(s->sig != 0 && s->type == SXREF && (nimports == 0 || s->subtype == SIMPORT)){
- undefsym(s);
- Bprint(&bso, "IMPORT: %s sig=%lux v=%ld\n", s->name, s->sig, s->value);
- }
-}
-
-void
-ckoff(Sym *s, int32 v)
-{
- if(v < 0 || v >= 1<<Roffset)
- diag("relocation offset %ld for %s out of range", v, s->name);
-}
-
-Prog*
-newdata(Sym *s, int o, int w, int t)
-{
- Prog *p;
-
- p = prg();
- p->link = datap;
- datap = p;
- p->as = ADATA;
- p->reg = w;
- p->from.type = D_OREG;
- p->from.name = t;
- p->from.sym = s;
- p->from.offset = o;
- p->to.type = D_CONST;
- p->to.name = D_NONE;
- s->data = p;
- return p;
-}
-
-void
-export(void)
-{
- int i, j, n, off, nb, sv, ne;
- Sym *s, *et, *str, **esyms;
- Prog *p;
- char buf[NSNAME], *t;
-
- n = 0;
- for(i = 0; i < NHASH; i++)
- for(s = hash[i]; s != S; s = s->link)
- if(s->sig != 0 && s->type != SXREF && s->type != SUNDEF && (nexports == 0 || s->subtype == SEXPORT))
- n++;
- esyms = malloc(n*sizeof(Sym*));
- ne = n;
- n = 0;
- for(i = 0; i < NHASH; i++)
- for(s = hash[i]; s != S; s = s->link)
- if(s->sig != 0 && s->type != SXREF && s->type != SUNDEF && (nexports == 0 || s->subtype == SEXPORT))
- esyms[n++] = s;
- for(i = 0; i < ne-1; i++)
- for(j = i+1; j < ne; j++)
- if(strcmp(esyms[i]->name, esyms[j]->name) > 0){
- s = esyms[i];
- esyms[i] = esyms[j];
- esyms[j] = s;
- }
-
- nb = 0;
- off = 0;
- et = lookup(EXPTAB, 0);
- if(et->type != 0 && et->type != SXREF)
- diag("%s already defined", EXPTAB);
- et->type = SDATA;
- str = lookup(".string", 0);
- if(str->type == 0)
- str->type = SDATA;
- sv = str->value;
- for(i = 0; i < ne; i++){
- s = esyms[i];
- Bprint(&bso, "EXPORT: %s sig=%lux t=%d\n", s->name, s->sig, s->type);
-
- /* signature */
- p = newdata(et, off, sizeof(int32), D_EXTERN);
- off += sizeof(int32);
- p->to.offset = s->sig;
-
- /* address */
- p = newdata(et, off, sizeof(int32), D_EXTERN);
- off += sizeof(int32);
- p->to.name = D_EXTERN;
- p->to.sym = s;
-
- /* string */
- t = s->name;
- n = strlen(t)+1;
- for(;;){
- buf[nb++] = *t;
- sv++;
- if(nb >= NSNAME){
- p = newdata(str, sv-NSNAME, NSNAME, D_STATIC);
- p->to.type = D_SCONST;
- p->to.sval = malloc(NSNAME);
- memmove(p->to.sval, buf, NSNAME);
- nb = 0;
- }
- if(*t++ == 0)
- break;
- }
-
- /* name */
- p = newdata(et, off, sizeof(int32), D_EXTERN);
- off += sizeof(int32);
- p->to.name = D_STATIC;
- p->to.sym = str;
- p->to.offset = sv-n;
- }
-
- if(nb > 0){
- p = newdata(str, sv-nb, nb, D_STATIC);
- p->to.type = D_SCONST;
- p->to.sval = malloc(NSNAME);
- memmove(p->to.sval, buf, nb);
- }
-
- for(i = 0; i < 3; i++){
- newdata(et, off, sizeof(int32), D_EXTERN);
- off += sizeof(int32);
- }
- et->value = off;
- if(sv == 0)
- sv = 1;
- str->value = sv;
- exports = ne;
- free(esyms);
-}
diff --git a/src/cmd/5l/prof.c b/src/cmd/5l/prof.c
new file mode 100644
index 000000000..ad115a8ca
--- /dev/null
+++ b/src/cmd/5l/prof.c
@@ -0,0 +1,214 @@
+// Inferno utils/5l/obj.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5l/obj.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+// Profiling.
+
+#include "l.h"
+#include "../ld/lib.h"
+
+void
+doprof1(void)
+{
+#if 0 // TODO(rsc)
+ Sym *s;
+ int32 n;
+ Prog *p, *q;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f profile 1\n", cputime());
+ Bflush(&bso);
+ s = lookup("__mcount", 0);
+ n = 1;
+ for(p = firstp->link; p != P; p = p->link) {
+ setarch(p);
+ if(p->as == ATEXT) {
+ q = prg();
+ q->line = p->line;
+ q->link = datap;
+ datap = q;
+ q->as = ADATA;
+ q->from.type = D_OREG;
+ q->from.name = D_EXTERN;
+ q->from.offset = n*4;
+ q->from.sym = s;
+ q->reg = 4;
+ q->to = p->from;
+ q->to.type = D_CONST;
+
+ q = prg();
+ q->line = p->line;
+ q->pc = p->pc;
+ q->link = p->link;
+ p->link = q;
+ p = q;
+ p->as = AMOVW;
+ p->from.type = D_OREG;
+ p->from.name = D_EXTERN;
+ p->from.sym = s;
+ p->from.offset = n*4 + 4;
+ p->to.type = D_REG;
+ p->to.reg = thumb ? REGTMPT : REGTMP;
+
+ q = prg();
+ q->line = p->line;
+ q->pc = p->pc;
+ q->link = p->link;
+ p->link = q;
+ p = q;
+ p->as = AADD;
+ p->from.type = D_CONST;
+ p->from.offset = 1;
+ p->to.type = D_REG;
+ p->to.reg = thumb ? REGTMPT : REGTMP;
+
+ q = prg();
+ q->line = p->line;
+ q->pc = p->pc;
+ q->link = p->link;
+ p->link = q;
+ p = q;
+ p->as = AMOVW;
+ p->from.type = D_REG;
+ p->from.reg = thumb ? REGTMPT : REGTMP;
+ p->to.type = D_OREG;
+ p->to.name = D_EXTERN;
+ p->to.sym = s;
+ p->to.offset = n*4 + 4;
+
+ n += 2;
+ continue;
+ }
+ }
+ q = prg();
+ q->line = 0;
+ q->link = datap;
+ datap = q;
+
+ q->as = ADATA;
+ q->from.type = D_OREG;
+ q->from.name = D_EXTERN;
+ q->from.sym = s;
+ q->reg = 4;
+ q->to.type = D_CONST;
+ q->to.offset = n;
+
+ s->type = SBSS;
+ s->value = n*4;
+#endif
+}
+
+void
+doprof2(void)
+{
+ Sym *s2, *s4;
+ Prog *p, *q, *ps2, *ps4;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f profile 2\n", cputime());
+ Bflush(&bso);
+ s2 = lookup("_profin", 0);
+ s4 = lookup("_profout", 0);
+ if(s2->type != STEXT || s4->type != STEXT) {
+ diag("_profin/_profout not defined");
+ return;
+ }
+ ps2 = P;
+ ps4 = P;
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ p = cursym->text;
+ setarch(p);
+ if(cursym == s2) {
+ ps2 = p;
+ p->reg = 1;
+ }
+ if(cursym == s4) {
+ ps4 = p;
+ p->reg = 1;
+ }
+ }
+ for(cursym = textp; cursym != nil; cursym = cursym->next)
+ for(p = cursym->text; p != P; p = p->link) {
+ setarch(p);
+ if(p->as == ATEXT) {
+ if(p->reg & NOPROF) {
+ for(;;) {
+ q = p->link;
+ if(q == P)
+ break;
+ if(q->as == ATEXT)
+ break;
+ p = q;
+ }
+ continue;
+ }
+
+ /*
+ * BL profin, R2
+ */
+ q = prg();
+ q->line = p->line;
+ q->pc = p->pc;
+ q->link = p->link;
+ p->link = q;
+ p = q;
+ p->as = ABL;
+ p->to.type = D_BRANCH;
+ p->cond = ps2;
+ p->to.sym = s2;
+
+ continue;
+ }
+ if(p->as == ARET) {
+ /*
+ * RET
+ */
+ q = prg();
+ q->as = ARET;
+ q->from = p->from;
+ q->to = p->to;
+ q->link = p->link;
+ p->link = q;
+
+ /*
+ * BL profout
+ */
+ p->as = ABL;
+ p->from = zprg.from;
+ p->to = zprg.to;
+ p->to.type = D_BRANCH;
+ p->cond = ps4;
+ p->to.sym = s4;
+
+ p = q;
+
+ continue;
+ }
+ }
+}
diff --git a/src/cmd/5l/softfloat.c b/src/cmd/5l/softfloat.c
index 82874ee1c..fd66b0969 100644
--- a/src/cmd/5l/softfloat.c
+++ b/src/cmd/5l/softfloat.c
@@ -5,67 +5,82 @@
#define EXTERN
#include "l.h"
+// Software floating point.
+
void
-softfloat()
+softfloat(void)
{
Prog *p, *next, *psfloat;
Sym *symsfloat;
int wasfloat;
-
+
+ if(!debug['F'])
+ return;
+
symsfloat = lookup("_sfloat", 0);
psfloat = P;
if(symsfloat->type == STEXT)
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT) {
- if(p->from.sym == symsfloat) {
- psfloat = p;
- break;
- }
- }
- }
+ psfloat = symsfloat->text;
+
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ wasfloat = 0;
+ for(p = cursym->text; p != P; p = p->link)
+ if(p->cond != P)
+ p->cond->mark |= LABEL;
+ for(p = cursym->text; p != P; p = p->link) {
+ switch(p->as) {
+ case AMOVW:
+ if(p->to.type == D_FREG || p->from.type == D_FREG)
+ goto soft;
+ goto notsoft;
+
+ case AMOVWD:
+ case AMOVWF:
+ case AMOVDW:
+ case AMOVFW:
+ case AMOVFD:
+ case AMOVDF:
+ case AMOVF:
+ case AMOVD:
+
+ case ACMPF:
+ case ACMPD:
+ case AADDF:
+ case AADDD:
+ case ASUBF:
+ case ASUBD:
+ case AMULF:
+ case AMULD:
+ case ADIVF:
+ case ADIVD:
+ goto soft;
- wasfloat = 0;
- p = firstp;
- for(p = firstp; p != P; p = p->link) {
- switch(p->as) {
- case AMOVWD:
- case AMOVWF:
- case AMOVDW:
- case AMOVFW:
- case AMOVFD:
- case AMOVDF:
- case AMOVF:
- case AMOVD:
- case ACMPF:
- case ACMPD:
- case AADDF:
- case AADDD:
- case ASUBF:
- case ASUBD:
- case AMULF:
- case AMULD:
- case ADIVF:
- case ADIVD:
- if (psfloat == P)
- diag("floats used with _sfloat not defined");
- if (!wasfloat) {
- next = prg();
- *next = *p;
+ default:
+ goto notsoft;
- // BL _sfloat(SB)
- *p = zprg;
- p->link = next;
- p->as = ABL;
- p->to.type = D_BRANCH;
- p->to.sym = symsfloat;
- p->cond = psfloat;
+ soft:
+ if (psfloat == P)
+ diag("floats used with _sfloat not defined");
+ if (!wasfloat || (p->mark&LABEL)) {
+ next = prg();
+ *next = *p;
+
+ // BL _sfloat(SB)
+ *p = zprg;
+ p->link = next;
+ p->as = ABL;
+ p->to.type = D_BRANCH;
+ p->to.sym = symsfloat;
+ p->cond = psfloat;
+
+ p = next;
+ wasfloat = 1;
+ }
+ break;
- p = next;
- wasfloat = 1;
+ notsoft:
+ wasfloat = 0;
}
- break;
- default:
- wasfloat = 0;
}
}
}
diff --git a/src/cmd/5l/span.c b/src/cmd/5l/span.c
index a97af07f9..be0f5e8b3 100644
--- a/src/cmd/5l/span.c
+++ b/src/cmd/5l/span.c
@@ -28,6 +28,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+// Instruction layout.
+
#include "l.h"
#include "../ld/lib.h"
@@ -52,9 +54,9 @@ ispad(Prog *p)
{
if(p->as != AMOVW)
return 0;
- if(p->from.type != D_REG || p->from.reg != REGSB)
+ if(p->from.type != D_REG || p->from.reg != REGTMP)
return 0;
- if(p->to.type != D_REG || p->to.reg != REGSB)
+ if(p->to.type != D_REG || p->to.reg != REGTMP)
return 0;
return 1;
}
@@ -100,7 +102,7 @@ fnpinc(Sym *s)
if(!debug['f'])
diag("fnptr == 0 in fnpinc");
if(s->foreign)
- diag("bad usage in fnpinc %s %d %d %d", s->name, s->used, s->foreign, s->thumb);
+ diag("bad usage in fnpinc %s %d %d", s->name, s->foreign, s->thumb);
return 0;
}
/* 0, 1, 2, 3 squared */
@@ -119,9 +121,9 @@ pad(Prog *p, int pc)
q->as = AMOVW;
q->line = p->line;
q->from.type = D_REG;
- q->from.reg = REGSB;
+ q->from.reg = REGTMP;
q->to.type = D_REG;
- q->to.reg = REGSB;
+ q->to.reg = REGTMP;
q->pc = pc;
q->link = p->link;
return q;
@@ -132,7 +134,7 @@ scan(Prog *op, Prog *p, int c)
{
Prog *q;
- for(q = op->link; q != p; q = q->link){
+ for(q = op->link; q != p && q != P; q = q->link){
q->pc = c;
c += oplook(q)->size;
nocache(q);
@@ -163,11 +165,12 @@ void
span(void)
{
Prog *p, *op;
- Sym *setext, *s;
Optab *o;
- int m, bflag, i;
- int32 c, otxt, v;
+ int m, bflag, i, v;
+ int32 c, otxt, out[6];
int lastthumb = -1;
+ Section *sect;
+ uchar *bp;
if(debug['v'])
Bprint(&bso, "%5.2f span\n", cputime());
@@ -176,61 +179,65 @@ span(void)
bflag = 0;
c = INITTEXT;
op = nil;
+ p = nil;
otxt = c;
- for(p = firstp; p != P; op = p, p = p->link) {
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ p = cursym->text;
setarch(p);
p->pc = c;
- o = oplook(p);
- m = o->size;
- // must check literal pool here in case p generates many instructions
- if(blitrl){
- if(thumb && isbranch(p))
- pool.extra += brextra(p);
- if(checkpool(op, p->as == ACASE ? casesz(p) : m))
- c = p->pc = scan(op, p, c);
- }
- if(m == 0) {
- if(p->as == ATEXT) {
- if(blitrl && lastthumb != -1 && lastthumb != thumb){ // flush literal pool
- if(flushpool(op, 0, 1))
- c = p->pc = scan(op, p, c);
- }
- lastthumb = thumb;
- curtext = p;
- autosize = p->to.offset + 4;
- if(p->from.sym != S)
- p->from.sym->value = c;
- /* need passes to resolve branches */
- if(c-otxt >= 1L<<17)
- bflag = 1;
- otxt = c;
- if(thumb && blitrl)
+ cursym->value = c;
+
+ lastthumb = thumb;
+ autosize = p->to.offset + 4;
+ if(p->from.sym != S)
+ p->from.sym->value = c;
+ /* need passes to resolve branches */
+ if(c-otxt >= 1L<<17)
+ bflag = 1;
+ otxt = c;
+ if(thumb && blitrl)
+ pool.extra += brextra(p);
+
+ for(op = p, p = p->link; p != P; op = p, p = p->link) {
+ curp = p;
+ setarch(p);
+ p->pc = c;
+ o = oplook(p);
+ m = o->size;
+ // must check literal pool here in case p generates many instructions
+ if(blitrl){
+ if(thumb && isbranch(p))
pool.extra += brextra(p);
+ if(checkpool(op, p->as == ACASE ? casesz(p) : m))
+ c = p->pc = scan(op, p, c);
+ }
+ if(m == 0) {
+ diag("zero-width instruction\n%P", p);
continue;
}
- diag("zero-width instruction\n%P", p);
- continue;
- }
- switch(o->flag & (LFROM|LTO|LPOOL)) {
- case LFROM:
- addpool(p, &p->from);
- break;
- case LTO:
- addpool(p, &p->to);
- break;
- case LPOOL:
- if ((p->scond&C_SCOND) == 14)
+ switch(o->flag & (LFROM|LTO|LPOOL)) {
+ case LFROM:
+ addpool(p, &p->from);
+ break;
+ case LTO:
+ addpool(p, &p->to);
+ break;
+ case LPOOL:
+ if ((p->scond&C_SCOND) == 14)
+ flushpool(p, 0, 0);
+ break;
+ }
+ if(p->as==AMOVW && p->to.type==D_REG && p->to.reg==REGPC && (p->scond&C_SCOND) == 14)
flushpool(p, 0, 0);
- break;
+ c += m;
}
- if(p->as==AMOVW && p->to.type==D_REG && p->to.reg==REGPC && (p->scond&C_SCOND) == 14)
- flushpool(p, 0, 0);
- c += m;
- if(blitrl && p->link == P){
- if(thumb && isbranch(p))
- pool.extra += brextra(p);
- checkpool(p, 0);
+ if(blitrl){
+ if(thumb && isbranch(op))
+ pool.extra += brextra(op);
+ if(checkpool(op, 0))
+ c = scan(op, P, c);
}
+ cursym->size = c - cursym->value;
}
/*
@@ -244,48 +251,52 @@ span(void)
Bprint(&bso, "%5.2f span1\n", cputime());
bflag = 0;
c = INITTEXT;
- for(p = firstp; p != P; p = p->link) {
- setarch(p);
- p->pc = c;
- if(thumb && isbranch(p))
- nocache(p);
- o = oplook(p);
-/* very larg branches
- if(o->type == 6 && p->cond) {
- otxt = p->cond->pc - c;
- if(otxt < 0)
- otxt = -otxt;
- if(otxt >= (1L<<17) - 10) {
- q = prg();
- q->link = p->link;
- p->link = q;
- q->as = AB;
- q->to.type = D_BRANCH;
- q->cond = p->cond;
- p->cond = q;
- q = prg();
- q->link = p->link;
- p->link = q;
- q->as = AB;
- q->to.type = D_BRANCH;
- q->cond = q->link->link;
- bflag = 1;
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ cursym->value = c;
+ for(p = cursym->text; p != P; p = p->link) {
+ curp = p;
+ setarch(p);
+ p->pc = c;
+ if(thumb && isbranch(p))
+ nocache(p);
+ o = oplook(p);
+/* very large branches
+ if(o->type == 6 && p->cond) {
+ otxt = p->cond->pc - c;
+ if(otxt < 0)
+ otxt = -otxt;
+ if(otxt >= (1L<<17) - 10) {
+ q = prg();
+ q->link = p->link;
+ p->link = q;
+ q->as = AB;
+ q->to.type = D_BRANCH;
+ q->cond = p->cond;
+ p->cond = q;
+ q = prg();
+ q->link = p->link;
+ p->link = q;
+ q->as = AB;
+ q->to.type = D_BRANCH;
+ q->cond = q->link->link;
+ bflag = 1;
+ }
}
- }
*/
- m = o->size;
- if(m == 0) {
- if(p->as == ATEXT) {
- curtext = p;
- autosize = p->to.offset + 4;
- if(p->from.sym != S)
- p->from.sym->value = c;
+ m = o->size;
+ if(m == 0) {
+ if(p->as == ATEXT) {
+ autosize = p->to.offset + 4;
+ if(p->from.sym != S)
+ p->from.sym->value = c;
+ continue;
+ }
+ diag("zero-width instruction\n%P", p);
continue;
}
- diag("zero-width instruction\n%P", p);
- continue;
+ c += m;
}
- c += m;
+ cursym->size = c - cursym->value;
}
}
@@ -304,107 +315,94 @@ span(void)
c = INITTEXT;
oop = op = nil;
again = 0;
- for(p = firstp; p != P; oop = op, op = p, p = p->link){
- setarch(p);
- if(p->pc != c)
- again = 1;
- p->pc = c;
- if(thumb && isbranch(p))
- nocache(p);
- o = oplook(p);
- m = o->size;
- if(passes == 1 && thumb && isbranch(p)){ // start conservative so unneeded alignment is not added
- if(p->as == ABL)
- m = 4;
- else
- m = 2;
- p->align = 0;
- }
- if(p->align){
- if((p->align == 4 && (c&3)) || (p->align == 2 && !(c&3))){
- if(ispad(op)){
- oop->link = p;
- op = oop;
- c -= 2;
- p->pc = c;
- }
- else{
- op->link = pad(op, c);
- op = op->link;
- c += 2;
- p->pc = c;
- }
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ cursym->value = c;
+ for(p = cursym->text; p != P; oop = op, op = p, p = p->link) {
+ curp = p;
+ setarch(p);
+ if(p->pc != c)
again = 1;
+ p->pc = c;
+ if(thumb && isbranch(p))
+ nocache(p);
+ o = oplook(p);
+ m = o->size;
+ if(passes == 1 && thumb && isbranch(p)){ // start conservative so unneeded alignment is not added
+ if(p->as == ABL)
+ m = 4;
+ else
+ m = 2;
+ p->align = 0;
}
- }
- if(m == 0) {
- if(p->as == ATEXT) {
- curtext = p;
- autosize = p->to.offset + 4;
- if(p->from.sym != S)
- p->from.sym->value = c;
- continue;
+ if(p->align){
+ if((p->align == 4 && (c&3)) || (p->align == 2 && !(c&3))){
+ if(ispad(op)){
+ oop->link = p;
+ op = oop;
+ c -= 2;
+ p->pc = c;
+ }
+ else{
+ op->link = pad(op, c);
+ op = op->link;
+ c += 2;
+ p->pc = c;
+ }
+ again = 1;
+ }
+ }
+ if(m == 0) {
+ if(p->as == ATEXT) {
+ autosize = p->to.offset + 4;
+ if(p->from.sym != S)
+ p->from.sym->value = c;
+ continue;
+ }
}
+ c += m;
}
- c += m;
+ cursym->size = c - cursym->value;
}
if(c != lastc || again){
lastc = c;
goto loop;
}
}
-
- if(0 && seenthumb){ // rm redundant padding - obsolete
- int d;
-
- op = nil;
- d = 0;
- for(p = firstp; p != P; op = p, p = p->link){
- p->pc -= d;
- if(p->as == ATEXT){
- if(p->from.sym != S)
- p->from.sym->value -= d;
-// if(p->from.sym != S) print("%s %ux %d %d %d\n", p->from.sym->name ? p->from.sym->name : "?", p->from.sym->value, p->from.sym->thumb, p->from.sym->foreign, p->from.sym->fnptr);
- }
- if(ispad(p) && p->link != P && ispad(p->link)){
- op->link = p->link->link;
- d += 4;
- p = op;
+ c = rnd(c, 8);
+
+ /*
+ * lay out the code. all the pc-relative code references,
+ * even cross-function, are resolved now;
+ * only data references need to be relocated.
+ * with more work we could leave cross-function
+ * code references to be relocated too, and then
+ * perhaps we'd be able to parallelize the span loop above.
+ */
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ p = cursym->text;
+ setarch(p);
+ autosize = p->to.offset + 4;
+ symgrow(cursym, cursym->size);
+
+ bp = cursym->p;
+ for(p = p->link; p != P; p = p->link) {
+ curp = p;
+ pc = p->pc;
+ curp = p;
+ o = oplook(p);
+ asmout(p, o, out);
+ for(i=0; i<o->size/4; i++) {
+ v = out[i];
+ *bp++ = v;
+ *bp++ = v>>8;
+ *bp++ = v>>16;
+ *bp++ = v>>24;
}
}
- // print("%d bytes removed (padding)\n", d);
- c -= d;
}
-
- if(debug['t']) {
- /*
- * add strings to text segment
- */
- c = rnd(c, 8);
- for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->link) {
- if(s->type != SSTRING)
- continue;
- v = s->value;
- while(v & 3)
- v++;
- s->value = c;
- c += v;
- }
- }
-
- c = rnd(c, 8);
-
- setext = lookup("etext", 0);
- if(setext != S) {
- setext->value = c;
- textsize = c - INITTEXT;
- }
- if(INITRND)
- INITDAT = rnd(c, INITRND);
- if(debug['v'])
- Bprint(&bso, "tsize = %lux\n", textsize);
- Bflush(&bso);
+ sect = addsection(&segtext, ".text", 05);
+ sect->vaddr = INITTEXT;
+ sect->len = c - INITTEXT;
}
/*
@@ -437,7 +435,7 @@ flushpool(Prog *p, int skip, int force)
if(blitrl) {
if(skip){
- if(0 && skip==1)print("note: flush literal pool at %lux: len=%lud ref=%lux\n", p->pc+4, pool.size, pool.start);
+ if(0 && skip==1)print("note: flush literal pool at %ux: len=%ud ref=%ux\n", p->pc+4, pool.size, pool.start);
q = prg();
q->as = AB;
q->to.type = D_BRANCH;
@@ -523,10 +521,10 @@ xdefine(char *p, int t, int32 v)
Sym *s;
s = lookup(p, 0);
- if(s->type == 0 || s->type == SXREF) {
- s->type = t;
- s->value = v;
- }
+ s->type = t;
+ s->value = v;
+ s->reachable = 1;
+ s->special = 1;
}
int32
@@ -583,6 +581,38 @@ immhalf(int32 v)
return 0;
}
+int32
+symaddr(Sym *s)
+{
+ int32 v;
+
+ v = s->value;
+ switch(s->type) {
+ default:
+ diag("unexpected type %d in symaddr(%s)", s->type, s->name);
+ return 0;
+
+ case STEXT:
+/* TODO(rsc): what is this for?
+#ifdef CALLEEBX
+ v += fnpinc(s);
+#else
+ if(s->thumb)
+ v++; // T bit
+#endif
+*/
+ break;
+
+ case SELFDATA:
+ case SRODATA:
+ case SDATA:
+ case SBSS:
+ case SCONST:
+ break;
+ }
+ return v;
+}
+
int
aclass(Adr *a)
{
@@ -619,36 +649,9 @@ aclass(Adr *a)
}
s = a->sym;
t = s->type;
- if(t == 0 || t == SXREF) {
- diag("undefined external: %s in %s",
- s->name, TNAME);
- s->type = SDATA;
- }
- if(dlm) {
- switch(t) {
- default:
- instoffset = s->value + a->offset + INITDAT;
- break;
- case SUNDEF:
- case STEXT:
- case SCONST:
- case SLEAF:
- case SSTRING:
- instoffset = s->value + a->offset;
- break;
- }
- return C_ADDR;
- }
- instoffset = s->value + a->offset - BIG;
- t = immaddr(instoffset);
- if(t) {
- if(immhalf(instoffset))
- return immfloat(t) ? C_HFEXT : C_HEXT;
- if(immfloat(t))
- return C_FEXT;
- return C_SEXT;
- }
- return C_LEXT;
+ instoffset = 0; // s.b. unused but just in case
+ return C_ADDR;
+
case D_AUTO:
instoffset = autosize + a->offset;
t = immaddr(instoffset);
@@ -703,32 +706,17 @@ aclass(Adr *a)
case D_STATIC:
s = a->sym;
t = s->type;
- if(t == 0 || t == SXREF) {
- diag("undefined external: %s in %s",
- s->name, TNAME);
- s->type = SDATA;
- }
- if(s->type == SFIXED) {
- instoffset = s->value + a->offset;
- return C_LCON;
- }
- instoffset = s->value + a->offset + INITDAT;
- if(s->type == STEXT || s->type == SLEAF || s->type == SUNDEF) {
- instoffset = s->value + a->offset;
-#ifdef CALLEEBX
- instoffset += fnpinc(s);
-#else
- if(s->thumb)
- instoffset++; // T bit
-#endif
- return C_LCON;
- }
- return C_LCON;
+ instoffset = 0; // s.b. unused but just in case
+ return C_ADDR;
}
return C_GOK;
case D_FCONST:
- return C_FCON;
+ if(chipzero(&a->ieee) >= 0)
+ return C_ZFCON;
+ if(chipfloat(&a->ieee) >= 0)
+ return C_SFCON;
+ return C_LFCON;
case D_CONST:
case D_CONST2:
@@ -753,37 +741,7 @@ aclass(Adr *a)
if(s == S)
break;
t = s->type;
- switch(t) {
- case 0:
- case SXREF:
- diag("undefined external: %s in %s",
- s->name, TNAME);
- s->type = SDATA;
- break;
- case SFIXED:
- instoffset = s->value + a->offset;
- return C_LCON;
- case SUNDEF:
- case STEXT:
- case SSTRING:
- case SCONST:
- case SLEAF:
- instoffset = s->value + a->offset;
-#ifdef CALLEEBX
- instoffset += fnpinc(s);
-#else
- if(s->thumb)
- instoffset++; // T bit
-#endif
- return C_LCON;
- }
- if(!dlm) {
- instoffset = s->value + a->offset - BIG;
- t = immrot(instoffset);
- if(t && instoffset != 0)
- return C_RECON;
- }
- instoffset = s->value + a->offset + INITDAT;
+ instoffset = 0; // s.b. unused but just in case
return C_LCON;
case D_AUTO:
@@ -895,21 +853,11 @@ cmp(int a, int b)
if(b == C_RACON)
return 1;
break;
- case C_LECON:
- if(b == C_RECON)
+ case C_LFCON:
+ if(b == C_ZFCON || b == C_SFCON)
return 1;
break;
- case C_HFEXT:
- return b == C_HEXT || b == C_FEXT;
- case C_FEXT:
- case C_HEXT:
- return b == C_HFEXT;
- case C_SEXT:
- return cmp(C_HFEXT, b);
- case C_LEXT:
- return cmp(C_SEXT, b);
-
case C_HFAUTO:
return b == C_HAUTO || b == C_FAUTO;
case C_FAUTO:
@@ -1091,17 +1039,20 @@ buildop(void)
break;
case AMOVFW:
- oprange[AMOVWF] = oprange[r];
- oprange[AMOVWD] = oprange[r];
oprange[AMOVDW] = oprange[r];
break;
+ case AMOVWF:
+ oprange[AMOVWD] = oprange[r];
+ break;
+
case AMULL:
oprange[AMULA] = oprange[r];
oprange[AMULAL] = oprange[r];
oprange[AMULLU] = oprange[r];
oprange[AMULALU] = oprange[r];
break;
+
case ALDREX:
case ASTREX:
break;
@@ -1146,159 +1097,3 @@ buildrep(int x, int as)
oprange[as].start = 0;
}
*/
-
-enum{
- ABSD = 0,
- ABSU = 1,
- RELD = 2,
- RELU = 3,
-};
-
-int modemap[4] = { 0, 1, -1, 2, };
-
-typedef struct Reloc Reloc;
-
-struct Reloc
-{
- int n;
- int t;
- uchar *m;
- uint32 *a;
-};
-
-Reloc rels;
-
-static void
-grow(Reloc *r)
-{
- int t;
- uchar *m, *nm;
- uint32 *a, *na;
-
- t = r->t;
- r->t += 64;
- m = r->m;
- a = r->a;
- r->m = nm = malloc(r->t*sizeof(uchar));
- r->a = na = malloc(r->t*sizeof(uint32));
- memmove(nm, m, t*sizeof(uchar));
- memmove(na, a, t*sizeof(uint32));
- free(m);
- free(a);
-}
-
-void
-dynreloc(Sym *s, int32 v, int abs)
-{
- int i, k, n;
- uchar *m;
- uint32 *a;
- Reloc *r;
-
- if(v&3)
- diag("bad relocation address");
- v >>= 2;
- if(s != S && s->type == SUNDEF)
- k = abs ? ABSU : RELU;
- else
- k = abs ? ABSD : RELD;
- /* Bprint(&bso, "R %s a=%ld(%lx) %d\n", s->name, a, a, k); */
- k = modemap[k];
- r = &rels;
- n = r->n;
- if(n >= r->t)
- grow(r);
- m = r->m;
- a = r->a;
- for(i = n; i > 0; i--){
- if(v < a[i-1]){ /* happens occasionally for data */
- m[i] = m[i-1];
- a[i] = a[i-1];
- }
- else
- break;
- }
- m[i] = k;
- a[i] = v;
- r->n++;
-}
-
-static int
-sput(char *s)
-{
- char *p;
-
- p = s;
- while(*s)
- cput(*s++);
- cput(0);
- return s-p+1;
-}
-
-void
-asmdyn()
-{
- int i, n, t, c;
- Sym *s;
- uint32 la, ra, *a;
- vlong off;
- uchar *m;
- Reloc *r;
-
- cflush();
- off = seek(cout, 0, 1);
- lput(0);
- t = 0;
- lput(imports);
- t += 4;
- for(i = 0; i < NHASH; i++)
- for(s = hash[i]; s != S; s = s->link)
- if(s->type == SUNDEF){
- lput(s->sig);
- t += 4;
- t += sput(s->name);
- }
-
- la = 0;
- r = &rels;
- n = r->n;
- m = r->m;
- a = r->a;
- lput(n);
- t += 4;
- for(i = 0; i < n; i++){
- ra = *a-la;
- if(*a < la)
- diag("bad relocation order");
- if(ra < 256)
- c = 0;
- else if(ra < 65536)
- c = 1;
- else
- c = 2;
- cput((c<<6)|*m++);
- t++;
- if(c == 0){
- cput(ra);
- t++;
- }
- else if(c == 1){
- wput(ra);
- t += 2;
- }
- else{
- lput(ra);
- t += 4;
- }
- la = *a++;
- }
-
- cflush();
- seek(cout, off, 0);
- lput(t);
-
- if(debug['v']){
- Bprint(&bso, "import table entries = %d\n", imports);
- Bprint(&bso, "export table entries = %d\n", exports);
- }
-}
diff --git a/src/cmd/5l/thumb.c b/src/cmd/5l/thumb.c
index 97292f640..b2ba630c3 100644
--- a/src/cmd/5l/thumb.c
+++ b/src/cmd/5l/thumb.c
@@ -203,9 +203,8 @@ thumbaclass(Adr *a, Prog *p)
a->sym->name, TNAME);
a->sym->type = SDATA;
}
- instoffset = a->sym->value + a->offset + INITDAT;
- return C_LEXT; /* INITDAT unknown at this stage */
- // return immacon(instoffset, p, C_SEXT, C_LEXT);
+ instoffset = a->sym->value + a->offset;
+ return C_ADDR; /* INITDAT unknown at this stage */
case D_AUTO:
instoffset = autosize + a->offset;
return immauto(instoffset, p);
@@ -235,8 +234,8 @@ thumbaclass(Adr *a, Prog *p)
s->name, TNAME);
s->type = SDATA;
}
- instoffset = s->value + a->offset + INITDAT;
- if(s->type == STEXT || s->type == SLEAF){
+ instoffset = s->value + a->offset;
+ if(s->type == STEXT){
instoffset = s->value + a->offset;
#ifdef CALLEEBX
instoffset += fnpinc(s);
@@ -252,7 +251,7 @@ thumbaclass(Adr *a, Prog *p)
return C_GOK;
case D_FCONST:
diag("D_FCONST in thumaclass");
- return C_FCON;
+ return C_LFCON;
case D_CONST:
switch(a->name) {
case D_NONE:
@@ -275,7 +274,6 @@ thumbaclass(Adr *a, Prog *p)
break;
case SCONST:
case STEXT:
- case SLEAF:
instoffset = s->value + a->offset;
#ifdef CALLEEBX
instoffset += fnpinc(s);
@@ -285,7 +283,7 @@ thumbaclass(Adr *a, Prog *p)
#endif
return C_LCON;
}
- instoffset = s->value + a->offset + INITDAT;
+ instoffset = s->value + a->offset;
return C_LCON; /* INITDAT unknown at this stage */
// return immcon(instoffset, p);
case D_AUTO:
@@ -358,8 +356,8 @@ thumbaclass(Adr *a, Prog *p)
// as a1 a2 a3 type size param lit vers
Optab thumboptab[] =
{
- { ATEXT, C_LEXT, C_NONE, C_LCON, 0, 0, 0 },
- { ATEXT, C_LEXT, C_REG, C_LCON, 0, 0, 0 },
+ { ATEXT, C_ADDR, C_NONE, C_LCON, 0, 0, 0 },
+ { ATEXT, C_ADDR, C_REG, C_LCON, 0, 0, 0 },
{ AMVN, C_REG, C_NONE, C_REG, 1, 2, 0 },
{ ASRL, C_REG, C_NONE, C_REG, 1, 2, 0 },
{ ACMP, C_REG, C_REG, C_NONE, 1, 2, 0 },
@@ -412,37 +410,27 @@ Optab thumboptab[] =
{ ASWI, C_NONE, C_NONE, C_LCON, 16, 2, 0 },
{ AWORD, C_NONE, C_NONE, C_LCON, 17, 4, 0 },
{ AWORD, C_NONE, C_NONE, C_GCON, 17, 4, 0 },
- { AWORD, C_NONE, C_NONE, C_LEXT, 17, 4, 0 },
+ { AWORD, C_NONE, C_NONE, C_ADDR, 17, 4, 0 },
{ ADWORD, C_LCON, C_NONE, C_LCON, 50, 8, 0 },
{ AMOVW, C_SAUTO, C_NONE, C_REG, 18, 2, REGSP },
{ AMOVW, C_LAUTO, C_NONE, C_REG, 33, 6, 0, LFROM },
// { AMOVW, C_OFFPC, C_NONE, C_REG, 18, 2, REGPC, LFROM },
- { AMOVW, C_SEXT, C_NONE, C_REG, 30, 4, 0 },
{ AMOVW, C_SOREG, C_NONE, C_REG, 19, 2, 0 },
- { AMOVHU, C_SEXT, C_NONE, C_REG, 30, 4, 0 },
{ AMOVHU, C_SOREG, C_NONE, C_REG, 19, 2, 0 },
- { AMOVBU, C_SEXT, C_NONE, C_REG, 30, 4, 0 },
{ AMOVBU, C_SOREG, C_NONE, C_REG, 19, 2, 0 },
{ AMOVW, C_REG, C_NONE, C_SAUTO, 20, 2, 0 },
{ AMOVW, C_REG, C_NONE, C_LAUTO, 34, 6, 0, LTO },
- { AMOVW, C_REG, C_NONE, C_SEXT, 31, 4, 0 },
{ AMOVW, C_REG, C_NONE, C_SOREG, 21, 2, 0 },
- { AMOVH, C_REG, C_NONE, C_SEXT, 31, 4, 0 },
{ AMOVH, C_REG, C_NONE, C_SOREG, 21, 2, 0 },
- { AMOVB, C_REG, C_NONE, C_SEXT, 31, 4, 0 },
{ AMOVB, C_REG, C_NONE, C_SOREG, 21, 2, 0 },
- { AMOVHU, C_REG, C_NONE, C_SEXT, 31, 4, 0 },
{ AMOVHU, C_REG, C_NONE, C_SOREG, 21, 2, 0 },
- { AMOVBU, C_REG, C_NONE, C_SEXT, 31, 4, 0 },
{ AMOVBU, C_REG, C_NONE, C_SOREG, 21, 2, 0 },
{ AMOVW, C_REG, C_NONE, C_REG, 22, 2, 0 },
{ AMOVB, C_REG, C_NONE, C_REG, 23, 4, 0 },
{ AMOVH, C_REG, C_NONE, C_REG, 23, 4, 0 },
{ AMOVBU, C_REG, C_NONE, C_REG, 23, 4, 0 },
{ AMOVHU, C_REG, C_NONE, C_REG, 23, 4, 0 },
- { AMOVH, C_SEXT, C_NONE, C_REG, 32, 6, 0 },
{ AMOVH, C_SOREG, C_NONE, C_REG, 24, 4, 0 },
- { AMOVB, C_SEXT, C_NONE, C_REG, 32, 6, 0 },
{ AMOVB, C_SOREG, C_NONE, C_REG, 24, 4, 0 },
{ AMOVW, C_SACON, C_NONE, C_REG, 25, 2, 0 },
{ AMOVW, C_LACON, C_NONE, C_REG, 35, 4, 0 },
@@ -469,16 +457,16 @@ Optab thumboptab[] =
{ AMOVB, C_REG, C_NONE, C_GOREG, 29, 4, 0, LTO },
{ AMOVHU, C_REG, C_NONE, C_GOREG, 29, 4, 0, LTO },
{ AMOVBU, C_REG, C_NONE, C_GOREG, 29, 4, 0, LTO },
- { AMOVW, C_LEXT, C_NONE, C_REG, 30, 4, 0, LFROM },
- { AMOVH, C_LEXT, C_NONE, C_REG, 32, 6, 0, LFROM },
- { AMOVB, C_LEXT, C_NONE, C_REG, 32, 6, 0, LFROM },
- { AMOVHU, C_LEXT, C_NONE, C_REG, 30, 4, 0, LFROM },
- { AMOVBU, C_LEXT, C_NONE, C_REG, 30, 4, 0, LFROM },
- { AMOVW, C_REG, C_NONE, C_LEXT, 31, 4, 0, LTO },
- { AMOVH, C_REG, C_NONE, C_LEXT, 31, 4, 0, LTO },
- { AMOVB, C_REG, C_NONE, C_LEXT, 31, 4, 0, LTO },
- { AMOVHU, C_REG, C_NONE, C_LEXT, 31, 4, 0, LTO },
- { AMOVBU, C_REG, C_NONE, C_LEXT, 31, 4, 0, LTO },
+ { AMOVW, C_ADDR, C_NONE, C_REG, 30, 4, 0, LFROM },
+ { AMOVH, C_ADDR, C_NONE, C_REG, 32, 6, 0, LFROM },
+ { AMOVB, C_ADDR, C_NONE, C_REG, 32, 6, 0, LFROM },
+ { AMOVHU, C_ADDR, C_NONE, C_REG, 30, 4, 0, LFROM },
+ { AMOVBU, C_ADDR, C_NONE, C_REG, 30, 4, 0, LFROM },
+ { AMOVW, C_REG, C_NONE, C_ADDR, 31, 4, 0, LTO },
+ { AMOVH, C_REG, C_NONE, C_ADDR, 31, 4, 0, LTO },
+ { AMOVB, C_REG, C_NONE, C_ADDR, 31, 4, 0, LTO },
+ { AMOVHU, C_REG, C_NONE, C_ADDR, 31, 4, 0, LTO },
+ { AMOVBU, C_REG, C_NONE, C_ADDR, 31, 4, 0, LTO },
{ AXXX, C_NONE, C_NONE, C_NONE, 0, 2, 0 },
};
@@ -683,7 +671,7 @@ thumbasmout(Prog *p, Optab *o)
rt = p->to.reg;
r = p->reg;
o1 = o2 = o3 = o4 = o5 = o6 = o7 = 0;
-if(debug['P']) print("%ulx: %P type %d %d\n", (uint32)(p->pc), p, o->type, p->align);
+if(debug['P']) print("%ux: %P type %d %d\n", (uint32)(p->pc), p, o->type, p->align);
opcount[o->type] += o->size;
switch(o->type) {
default:
@@ -691,7 +679,7 @@ if(debug['P']) print("%ulx: %P type %d %d\n", (uint32)(p->pc), p, o->type, p->al
prasm(p);
break;
case 0: /* pseudo ops */
-if(debug['G']) print("%ulx: %s: thumb\n", (uint32)(p->pc), p->from.sym->name);
+if(debug['G']) print("%ux: %s: thumb\n", (uint32)(p->pc), p->from.sym->name);
break;
case 1: /* op R, -, R or op R, R, - */
o1 = thumboprr(p->as);
@@ -981,6 +969,7 @@ if(debug['G']) print("%ulx: %s: thumb\n", (uint32)(p->pc), p->from.sym->name);
}
break;
case 30: /* AMOVW... *addr, R */
+ diag("likely broken"); // does this still refer to SB?
thumbaclass(&p->from, p);
o1 = mv(p, rt, instoffset); // MOV addr, rtmp
o2 = thumbopmv(p->as, 1);
@@ -988,6 +977,7 @@ if(debug['G']) print("%ulx: %s: thumb\n", (uint32)(p->pc), p->from.sym->name);
o2 |= (rt<<3) | rt; // MOV* 0(rtmp), R
break;
case 31: /* AMOVW... R, *addr */
+ diag("likely broken"); // does this still refer to SB?
thumbaclass(&p->to, p);
o1 = mv(p, REGTMPT, instoffset);
o2 = thumbopmv(p->as, 0);
@@ -1162,29 +1152,29 @@ if(debug['G']) print("%ulx: %s: thumb\n", (uint32)(p->pc), p->from.sym->name);
switch(o->size) {
default:
if(debug['a'])
- Bprint(&bso, " %.8lux:\t\t%P\n", v, p);
+ Bprint(&bso, " %.8ux:\t\t%P\n", v, p);
break;
case 2:
if(debug['a'])
- Bprint(&bso, " %.8lux: %.8lux\t%P\n", v, o1, p);
+ Bprint(&bso, " %.8ux: %.8ux\t%P\n", v, o1, p);
hputl(o1);
break;
case 4:
if(debug['a'])
- Bprint(&bso, " %.8lux: %.8lux %.8lux\t%P\n", v, o1, o2, p);
+ Bprint(&bso, " %.8ux: %.8ux %.8ux\t%P\n", v, o1, o2, p);
hputl(o1);
hputl(o2);
break;
case 6:
if(debug['a'])
- Bprint(&bso, "%.8lux: %.8lux %.8lux %.8lux\t%P\n", v, o1, o2, o3, p);
+ Bprint(&bso, "%.8ux: %.8ux %.8ux %.8ux\t%P\n", v, o1, o2, o3, p);
hputl(o1);
hputl(o2);
hputl(o3);
break;
case 8:
if(debug['a'])
- Bprint(&bso, "%.8lux: %.8lux %.8lux %.8lux %.8lux\t%P\n", v, o1, o2, o3, o4, p);
+ Bprint(&bso, "%.8ux: %.8ux %.8ux %.8ux %.8ux\t%P\n", v, o1, o2, o3, o4, p);
hputl(o1);
hputl(o2);
hputl(o3);
@@ -1192,7 +1182,7 @@ if(debug['G']) print("%ulx: %s: thumb\n", (uint32)(p->pc), p->from.sym->name);
break;
case 10:
if(debug['a'])
- Bprint(&bso, "%.8lux: %.8lux %.8lux %.8lux %.8lux %.8lux\t%P\n", v, o1, o2, o3, o4, o5, p);
+ Bprint(&bso, "%.8ux: %.8ux %.8ux %.8ux %.8ux %.8ux\t%P\n", v, o1, o2, o3, o4, o5, p);
hputl(o1);
hputl(o2);
hputl(o3);
@@ -1201,7 +1191,7 @@ if(debug['G']) print("%ulx: %s: thumb\n", (uint32)(p->pc), p->from.sym->name);
break;
case 12:
if(debug['a'])
- Bprint(&bso, "%.8lux: %.8lux %.8lux %.8lux %.8lux %.8lux %.8lux\t%P\n", v, o1, o2, o3, o4, o5, o6, p);
+ Bprint(&bso, "%.8ux: %.8ux %.8ux %.8ux %.8ux %.8ux %.8ux\t%P\n", v, o1, o2, o3, o4, o5, o6, p);
hputl(o1);
hputl(o2);
hputl(o3);
@@ -1211,7 +1201,7 @@ if(debug['G']) print("%ulx: %s: thumb\n", (uint32)(p->pc), p->from.sym->name);
break;
case 14:
if(debug['a'])
- Bprint(&bso, "%.8lux: %.8lux %.8lux %.8lux %.8lux %.8lux %.8lux %.8lux\t%P\n", v, o1, o2, o3, o4, o5, o6, o7, p);
+ Bprint(&bso, "%.8ux: %.8ux %.8ux %.8ux %.8ux %.8ux %.8ux %.8ux\t%P\n", v, o1, o2, o3, o4, o5, o6, o7, p);
hputl(o1);
hputl(o2);
hputl(o3);
@@ -1223,12 +1213,12 @@ if(debug['G']) print("%ulx: %s: thumb\n", (uint32)(p->pc), p->from.sym->name);
}
if(debug['G']){
if(o->type == 17){
- print("%lx: word %ld\n", p->pc, (o2<<16)+o1);
+ print("%x: word %d\n", p->pc, (o2<<16)+o1);
return;
}
if(o->type == 50){
- print("%lx: word %ld\n", p->pc, (o2<<16)+o1);
- print("%lx: word %ld\n", p->pc, (o4<<16)+o3);
+ print("%x: word %d\n", p->pc, (o2<<16)+o1);
+ print("%x: word %d\n", p->pc, (o4<<16)+o3);
return;
}
if(o->size > 0) dis(o1, p->pc);
diff --git a/src/cmd/6a/Makefile b/src/cmd/6a/Makefile
index 21d824708..30180bd24 100644
--- a/src/cmd/6a/Makefile
+++ b/src/cmd/6a/Makefile
@@ -2,10 +2,10 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.conf
+include ../../Make.inc
+O:=$(HOST_O)
-TARG=\
- 6a\
+TARG=6a
HFILES=\
a.h\
@@ -20,21 +20,6 @@ OFILES=\
YFILES=\
a.y\
-$(TARG): $(OFILES)
- $(LD) -o $(TARG) -L"$(GOROOT)"/lib $(OFILES) -lbio -l9
-
-$(OFILES): $(HFILES)
+include ../../Make.ccmd
lex.$O: ../cc/macbody ../cc/lexbody
-
-y.tab.h: $(YFILES)
- bison -y $(YFLAGS) $(YFILES)
-
-y.tab.c: y.tab.h
- test -f y.tab.c && touch y.tab.c
-
-clean:
- rm -f *.$O $(TARG) *.6 enam.c 6.out a.out y.tab.h y.tab.c
-
-install: $(TARG)
- cp $(TARG) "$(GOBIN)"/$(TARG)
diff --git a/src/cmd/6a/a.h b/src/cmd/6a/a.h
index a713acc9f..9030081ca 100644
--- a/src/cmd/6a/a.h
+++ b/src/cmd/6a/a.h
@@ -1,7 +1,7 @@
// Inferno utils/6a/a.h
// http://code.google.com/p/inferno-os/source/browse/utils/6a/a.h
//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
@@ -50,7 +50,7 @@ typedef struct Ref Ref;
typedef struct Gen Gen;
typedef struct Io Io;
typedef struct Hist Hist;
-typedef struct Gen2 Gen2;
+typedef struct Gen2 Gen2;
#define MAXALIGN 7
#define FPCHIP 1
@@ -161,6 +161,7 @@ EXTERN int pass;
EXTERN char* pathname;
EXTERN int32 pc;
EXTERN int peekc;
+EXTERN int32 stmtline;
EXTERN int sym;
EXTERN char* symb;
EXTERN int thechar;
@@ -168,9 +169,9 @@ EXTERN char* thestring;
EXTERN int32 thunk;
EXTERN Biobuf obuf;
-void* alloc(int32);
+void* alloc(int32);
void* allocn(void*, int32, int32);
-void ensuresymb(int32);
+void ensuresymb(int32);
void errorexit(void);
void pushio(void);
void newio(void);
diff --git a/src/cmd/6a/a.y b/src/cmd/6a/a.y
index 804f638a0..770f676fe 100644
--- a/src/cmd/6a/a.y
+++ b/src/cmd/6a/a.y
@@ -1,7 +1,7 @@
// Inferno utils/6a/a.y
// http://code.google.com/p/inferno-os/source/browse/utils/6a/a.y
//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
@@ -60,7 +60,11 @@
%type <gen2> spec1 spec2 spec3 spec4 spec5 spec6 spec7 spec8 spec9
%%
prog:
-| prog line
+| prog
+ {
+ stmtline = lineno;
+ }
+ line
line:
LLAB ':'
@@ -453,6 +457,12 @@ omem:
$$.type = D_INDIR+D_SP;
$$.offset = $1;
}
+| con '(' LSREG ')'
+ {
+ $$ = nullgen;
+ $$.type = D_INDIR+$3;
+ $$.offset = $1;
+ }
| con '(' LLREG '*' con ')'
{
$$ = nullgen;
diff --git a/src/cmd/6a/lex.c b/src/cmd/6a/lex.c
index 81273b297..1b8bb6344 100644
--- a/src/cmd/6a/lex.c
+++ b/src/cmd/6a/lex.c
@@ -1,7 +1,7 @@
// Inferno utils/6a/lex.c
// http://code.google.com/p/inferno-os/source/browse/utils/6a/lex.c
//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
@@ -1260,10 +1260,10 @@ jackpot:
}
Bputc(&obuf, a);
Bputc(&obuf, a>>8);
- Bputc(&obuf, lineno);
- Bputc(&obuf, lineno>>8);
- Bputc(&obuf, lineno>>16);
- Bputc(&obuf, lineno>>24);
+ Bputc(&obuf, stmtline);
+ Bputc(&obuf, stmtline>>8);
+ Bputc(&obuf, stmtline>>16);
+ Bputc(&obuf, stmtline>>24);
zaddr(&g2->from, sf);
zaddr(&g2->to, st);
diff --git a/src/cmd/6c/Makefile b/src/cmd/6c/Makefile
index 53a8e80e6..484e16def 100644
--- a/src/cmd/6c/Makefile
+++ b/src/cmd/6c/Makefile
@@ -2,10 +2,10 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.conf
+include ../../Make.inc
+O:=$(HOST_O)
-TARG=\
- 6c\
+TARG=6c
HFILES=\
gc.h\
@@ -28,18 +28,9 @@ OFILES=\
../6l/enam.$O\
LIB=\
- ../cc/cc.a$O
+ ../cc/cc.a\
-$(TARG): $(OFILES) $(LIB)
- $(LD) -o $(TARG) -L"$(GOROOT)"/lib $(OFILES) $(LIB) -lbio -l9
-
-$(OFILES): $(HFILES)
-
-clean:
- rm -f *.$O $(TARG) *.6 enam.c 6.out a.out
-
-install: $(TARG)
- cp $(TARG) "$(GOBIN)"/$(TARG)
+include ../../Make.ccmd
%.$O: ../cc/%.c
- $(CC) $(CFLAGS) -c -I. -o $@ ../cc/$*.c
+ $(HOST_CC) $(HOST_CFLAGS) -c -I. -o $@ ../cc/$*.c
diff --git a/src/cmd/6c/cgen.c b/src/cmd/6c/cgen.c
index 39452c989..90394884f 100644
--- a/src/cmd/6c/cgen.c
+++ b/src/cmd/6c/cgen.c
@@ -57,6 +57,12 @@ cgen(Node *n, Node *nn)
l = n->left;
r = n->right;
o = n->op;
+
+ if(n->op == OEXREG || (nn != Z && nn->op == OEXREG)) {
+ gmove(n, nn);
+ return;
+ }
+
if(n->addable >= INDEXED) {
if(nn == Z) {
switch(o) {
@@ -1922,7 +1928,7 @@ vaddr(Node *n, int a)
int32
hi64v(Node *n)
{
- if(align(0, types[TCHAR], Aarg1)) /* isbigendian */
+ if(align(0, types[TCHAR], Aarg1, nil)) /* isbigendian */
return (int32)(n->vconst) & ~0L;
else
return (int32)((uvlong)n->vconst>>32) & ~0L;
@@ -1931,7 +1937,7 @@ hi64v(Node *n)
int32
lo64v(Node *n)
{
- if(align(0, types[TCHAR], Aarg1)) /* isbigendian */
+ if(align(0, types[TCHAR], Aarg1, nil)) /* isbigendian */
return (int32)((uvlong)n->vconst>>32) & ~0L;
else
return (int32)(n->vconst) & ~0L;
diff --git a/src/cmd/6c/div.c b/src/cmd/6c/div.c
index d67ef8df7..bad6c5e27 100644
--- a/src/cmd/6c/div.c
+++ b/src/cmd/6c/div.c
@@ -120,7 +120,7 @@ sdivgen(Node *l, Node *r, Node *ax, Node *dx)
if(c < 0)
c = -c;
a = sdiv(c, &m, &s);
-//print("a=%d i=%ld s=%d m=%lux\n", a, (long)r->vconst, s, m);
+//print("a=%d i=%d s=%d m=%ux\n", a, (long)r->vconst, s, m);
gins(AMOVL, nodconst(m), ax);
gins(AIMULL, l, Z);
gins(AMOVL, l, ax);
@@ -141,7 +141,7 @@ udivgen(Node *l, Node *r, Node *ax, Node *dx)
Node nod;
a = udiv(r->vconst, &m, &s, &t);
-//print("a=%ud i=%ld p=%d s=%d m=%lux\n", a, (long)r->vconst, t, s, m);
+//print("a=%ud i=%d p=%d s=%d m=%ux\n", a, (long)r->vconst, t, s, m);
if(t != 0) {
gins(AMOVL, l, ax);
gins(ASHRL, nodconst(t), ax);
diff --git a/src/cmd/6c/list.c b/src/cmd/6c/list.c
index ba517ca0a..4293203c0 100644
--- a/src/cmd/6c/list.c
+++ b/src/cmd/6c/list.c
@@ -78,22 +78,23 @@ Pconv(Fmt *fp)
p = va_arg(fp->args, Prog*);
switch(p->as) {
case ADATA:
- sprint(str, " %A %D/%d,%D",
- p->as, &p->from, p->from.scale, &p->to);
+ sprint(str, "(%L) %A %D/%d,%D",
+ p->lineno, p->as, &p->from, p->from.scale, &p->to);
break;
case ATEXT:
if(p->from.scale) {
- sprint(str, " %A %D,%d,%lD",
- p->as, &p->from, p->from.scale, &p->to);
+ sprint(str, "(%L) %A %D,%d,%lD",
+ p->lineno, p->as, &p->from, p->from.scale, &p->to);
break;
}
- sprint(str, " %A %D,%lD",
- p->as, &p->from, &p->to);
+ sprint(str, "(%L) %A %D,%lD",
+ p->lineno, p->as, &p->from, &p->to);
break;
default:
- sprint(str, " %A %D,%lD", p->as, &p->from, &p->to);
+ sprint(str, "(%L) %A %D,%lD",
+ p->lineno, p->as, &p->from, &p->to);
break;
}
return fmtstrcpy(fp, str);
diff --git a/src/cmd/6c/mul.c b/src/cmd/6c/mul.c
index eefeacaed..ab6883e7a 100644
--- a/src/cmd/6c/mul.c
+++ b/src/cmd/6c/mul.c
@@ -355,7 +355,7 @@ mulgen1(uint32 v, Node *n)
mulparam(v, p);
found:
-// print("v=%.lx a=%d n=%d s=%d g=%d o=%d \n", p->value, p->alg, p->neg, p->shift, p->arg, p->off);
+// print("v=%.x a=%d n=%d s=%d g=%d o=%d \n", p->value, p->alg, p->neg, p->shift, p->arg, p->off);
if(p->alg < 0)
return 0;
diff --git a/src/cmd/6c/peep.c b/src/cmd/6c/peep.c
index 01793bfc5..13fd25e73 100644
--- a/src/cmd/6c/peep.c
+++ b/src/cmd/6c/peep.c
@@ -797,8 +797,6 @@ copyu(Prog *p, Adr *v, Adr *s)
return 3;
case ACALL: /* funny */
- if(REGEXT && v->type <= REGEXT && v->type > exregoffset)
- return 2;
if(REGARG >= 0 && v->type == REGARG)
return 2;
diff --git a/src/cmd/6c/reg.c b/src/cmd/6c/reg.c
index 431501202..996128f75 100644
--- a/src/cmd/6c/reg.c
+++ b/src/cmd/6c/reg.c
@@ -448,7 +448,7 @@ regopt(Prog *p)
if(debug['R'] && debug['v']) {
print("\nlooping structure:\n");
for(r = firstr; r != R; r = r->link) {
- print("%ld:%P", r->loop, r->prog);
+ print("%d:%P", r->loop, r->prog);
for(z=0; z<BITS; z++)
bit.b[z] = r->use1.b[z] |
r->use2.b[z] |
@@ -1113,7 +1113,7 @@ paint1(Reg *r, int bn)
if(LOAD(r) & ~(r->set.b[z]&~(r->use1.b[z]|r->use2.b[z])) & bb) {
change -= CLOAD * r->loop;
if(debug['R'] && debug['v'])
- print("%ld%P\tld %B $%d\n", r->loop,
+ print("%d%P\td %B $%d\n", r->loop,
r->prog, blsh(bn), change);
}
for(;;) {
@@ -1123,21 +1123,21 @@ paint1(Reg *r, int bn)
if(r->use1.b[z] & bb) {
change += CREF * r->loop;
if(debug['R'] && debug['v'])
- print("%ld%P\tu1 %B $%d\n", r->loop,
+ print("%d%P\tu1 %B $%d\n", r->loop,
p, blsh(bn), change);
}
if((r->use2.b[z]|r->set.b[z]) & bb) {
change += CREF * r->loop;
if(debug['R'] && debug['v'])
- print("%ld%P\tu2 %B $%d\n", r->loop,
+ print("%d%P\tu2 %B $%d\n", r->loop,
p, blsh(bn), change);
}
if(STORE(r) & r->regdiff.b[z] & bb) {
change -= CLOAD * r->loop;
if(debug['R'] && debug['v'])
- print("%ld%P\tst %B $%d\n", r->loop,
+ print("%d%P\tst %B $%d\n", r->loop,
p, blsh(bn), change);
}
@@ -1174,7 +1174,7 @@ regset(Reg *r, uint32 bb)
while(b = bb & ~(bb-1)) {
v.type = b & 0xFFFF? BtoR(b): BtoF(b);
if(v.type == 0)
- diag(Z, "zero v.type for %#lux", b);
+ diag(Z, "zero v.type for %#ux", b);
c = copyu(r->prog, &v, A);
if(c == 3)
set |= b;
diff --git a/src/cmd/6c/sgen.c b/src/cmd/6c/sgen.c
index b8247a1b7..42045f8fa 100644
--- a/src/cmd/6c/sgen.c
+++ b/src/cmd/6c/sgen.c
@@ -131,6 +131,10 @@ xcom(Node *n)
n->addable = 11;
break;
+ case OEXREG:
+ n->addable = 0;
+ break;
+
case OREGISTER:
n->addable = 12;
break;
diff --git a/src/cmd/6c/swt.c b/src/cmd/6c/swt.c
index 668a1fdbc..47975a0c8 100644
--- a/src/cmd/6c/swt.c
+++ b/src/cmd/6c/swt.c
@@ -503,7 +503,7 @@ zaddr(Biobuf *b, Adr *a, int s)
}
int32
-align(int32 i, Type *t, int op)
+align(int32 i, Type *t, int op, int32 *maxalign)
{
int32 o;
Type *v;
@@ -517,7 +517,9 @@ align(int32 i, Type *t, int op)
break;
case Asu2: /* padding at end of a struct */
- w = SZ_VLONG;
+ w = *maxalign;
+ if(w < 1)
+ w = 1;
if(packflg)
w = packflg;
break;
@@ -525,10 +527,13 @@ align(int32 i, Type *t, int op)
case Ael1: /* initial align of struct element */
for(v=t; v->etype==TARRAY; v=v->link)
;
- w = ewidth[v->etype];
- if(w <= 0 || w >= SZ_VLONG)
- w = SZ_VLONG;
- if(packflg)
+ if(v->etype == TSTRUCT || v->etype == TUNION)
+ w = v->align;
+ else
+ w = ewidth[v->etype];
+ if(w < 1 || w > SZ_VLONG)
+ fatal(Z, "align");
+ if(packflg)
w = packflg;
break;
@@ -538,8 +543,8 @@ align(int32 i, Type *t, int op)
case Aarg0: /* initial passbyptr argument in arg list */
if(typesu[t->etype]) {
- o = align(o, types[TIND], Aarg1);
- o = align(o, types[TIND], Aarg2);
+ o = align(o, types[TIND], Aarg1, nil);
+ o = align(o, types[TIND], Aarg2, nil);
}
break;
@@ -560,13 +565,15 @@ align(int32 i, Type *t, int op)
break;
case Aaut3: /* total align of automatic */
- o = align(o, t, Ael1);
- o = align(o, t, Ael2);
+ o = align(o, t, Ael1, nil);
+ o = align(o, t, Ael2, nil);
break;
}
o = xround(o, w);
+ if(maxalign && *maxalign < w)
+ *maxalign = w;
if(debug['A'])
- print("align %s %ld %T = %ld\n", bnames[op], i, t, o);
+ print("align %s %d %T = %d\n", bnames[op], i, t, o);
return o;
}
diff --git a/src/cmd/6c/txt.c b/src/cmd/6c/txt.c
index f96c40f8e..a78ba227b 100644
--- a/src/cmd/6c/txt.c
+++ b/src/cmd/6c/txt.c
@@ -38,8 +38,7 @@ ginit(void)
thechar = '6';
thestring = "amd64";
- exregoffset = REGEXT;
- exfregoffset = FREGEXT;
+ dodefine("_64BIT");
listinit();
nstring = 0;
mnstring = 0;
@@ -425,7 +424,7 @@ err:
void
regsalloc(Node *n, Node *nn)
{
- cursafe = align(cursafe, nn->type, Aaut3);
+ cursafe = align(cursafe, nn->type, Aaut3, nil);
maxargsafe = maxround(maxargsafe, cursafe+curarg);
*n = *nodsafe;
n->xoffset = -(stkoff + cursafe);
@@ -441,22 +440,22 @@ regaalloc1(Node *n, Node *nn)
diag(n, "regaalloc1 and REGARG<0");
nodreg(n, nn, REGARG);
reg[REGARG]++;
- curarg = align(curarg, nn->type, Aarg1);
- curarg = align(curarg, nn->type, Aarg2);
+ curarg = align(curarg, nn->type, Aarg1, nil);
+ curarg = align(curarg, nn->type, Aarg2, nil);
maxargsafe = maxround(maxargsafe, cursafe+curarg);
}
void
regaalloc(Node *n, Node *nn)
{
- curarg = align(curarg, nn->type, Aarg1);
+ curarg = align(curarg, nn->type, Aarg1, nil);
*n = *nn;
n->op = OINDREG;
n->reg = REGSP;
n->xoffset = curarg;
n->complex = 0;
n->addable = 20;
- curarg = align(curarg, nn->type, Aarg2);
+ curarg = align(curarg, nn->type, Aarg2, nil);
maxargsafe = maxround(maxargsafe, cursafe+curarg);
}
@@ -491,6 +490,10 @@ naddr(Node *n, Adr *a)
a->sym = S;
break;
+ case OEXREG:
+ a->type = D_INDIR + D_GS;
+ a->offset = n->reg - 1;
+ break;
case OIND:
naddr(n->left, a);
@@ -1502,11 +1505,11 @@ exreg(Type *t)
int32 o;
if(typechlpv[t->etype]) {
- if(exregoffset <= REGEXT-4)
+ if(exregoffset >= 64)
return 0;
o = exregoffset;
- exregoffset--;
- return o;
+ exregoffset += 8;
+ return o+1; // +1 to avoid 0 == failure; naddr's case OEXREG will subtract 1.
}
return 0;
}
diff --git a/src/cmd/6g/Makefile b/src/cmd/6g/Makefile
index 712cfc60c..023f5d111 100644
--- a/src/cmd/6g/Makefile
+++ b/src/cmd/6g/Makefile
@@ -2,10 +2,10 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.conf
+include ../../Make.inc
+O:=$(HOST_O)
-TARG=\
- 6g
+TARG=6g
HFILES=\
../gc/go.h\
@@ -26,18 +26,9 @@ OFILES=\
../6l/enam.$O\
LIB=\
- ../gc/gc.a$O
+ ../gc/gc.a\
-$(TARG): $(OFILES) $(LIB)
- $(LD) -o $(TARG) -L"$(GOROOT)"/lib $(OFILES) $(LIB) -lbio -l9 -lm
-
-$(OFILES): $(HFILES)
-
-clean:
- rm -f $(TARG) enam.c 6.out a.out *.$O *.6
-
-install: $(TARG)
- cp $(TARG) "$(GOBIN)"/$(TARG)
+include ../../Make.ccmd
%.$O: ../gc/%.c
- $(CC) $(CFLAGS) -c -I. -o $@ ../gc/$*.c
+ $(HOST_CC) $(HOST_CFLAGS) -c -I. -o $@ ../gc/$*.c
diff --git a/src/cmd/6g/cgen.c b/src/cmd/6g/cgen.c
index aacc0d06f..d4d22fd61 100644
--- a/src/cmd/6g/cgen.c
+++ b/src/cmd/6g/cgen.c
@@ -418,7 +418,7 @@ void
agen(Node *n, Node *res)
{
Node *nl, *nr;
- Node n1, n2, n3, tmp, n4;
+ Node n1, n2, n3, tmp, n4, n5;
Prog *p1;
uint32 w;
uint64 v;
@@ -477,8 +477,10 @@ agen(Node *n, Node *res)
regalloc(&n1, nr->type, N);
cgen(nr, &n1);
}
- regalloc(&n3, types[tptr], res);
- agen(nl, &n3);
+ if(!isconst(nl, CTSTR)) {
+ regalloc(&n3, types[tptr], res);
+ agen(nl, &n3);
+ }
goto index;
}
tempname(&tmp, nr->type);
@@ -486,8 +488,10 @@ agen(Node *n, Node *res)
nr = &tmp;
irad:
- regalloc(&n3, types[tptr], res);
- agen(nl, &n3);
+ if(!isconst(nl, CTSTR)) {
+ regalloc(&n3, types[tptr], res);
+ agen(nl, &n3);
+ }
if(!isconst(nr, CTINT)) {
regalloc(&n1, nr->type, N);
cgen(nr, &n1);
@@ -501,7 +505,7 @@ agen(Node *n, Node *res)
// explicit check for nil if array is large enough
// that we might derive too big a pointer.
- if(!isslice(nl->type) && nl->type->width >= unmappedzero) {
+ if(isfixedarray(nl->type) && nl->type->width >= unmappedzero) {
regalloc(&n4, types[tptr], &n3);
gmove(&n3, &n4);
n4.op = OINDREG;
@@ -516,15 +520,16 @@ agen(Node *n, Node *res)
// constant index
if(isconst(nr, CTINT)) {
+ if(isconst(nl, CTSTR))
+ fatal("constant string constant index"); // front end should handle
v = mpgetfix(nr->val.u.xval);
- if(isslice(nl->type)) {
-
+ if(isslice(nl->type) || nl->type->etype == TSTRING) {
if(!debug['B'] && !n->etype) {
n1 = n3;
n1.op = OINDREG;
n1.type = types[tptr];
n1.xoffset = Array_nel;
- nodconst(&n2, types[TUINT64], v);
+ nodconst(&n2, types[TUINT32], v);
gins(optoas(OCMP, types[TUINT32]), &n1, &n2);
p1 = gbranch(optoas(OGT, types[TUINT32]), T);
ginscall(panicindex, 0);
@@ -536,18 +541,9 @@ agen(Node *n, Node *res)
n1.type = types[tptr];
n1.xoffset = Array_array;
gmove(&n1, &n3);
- } else
- if(!debug['B'] && !n->etype) {
- if(v < 0)
- yyerror("out of bounds on array");
- else
- if(v >= nl->type->bound)
- yyerror("out of bounds on array");
}
- nodconst(&n2, types[tptr], v*w);
- gins(optoas(OADD, types[tptr]), &n2, &n3);
-
+ ginscon(optoas(OADD, types[tptr]), v*w, &n3);
gmove(&n3, res);
regfree(&n3);
break;
@@ -564,20 +560,43 @@ agen(Node *n, Node *res)
if(!debug['B'] && !n->etype) {
// check bounds
- if(isslice(nl->type)) {
+ n5.op = OXXX;
+ t = types[TUINT32];
+ if(is64(nr->type))
+ t = types[TUINT64];
+ if(isconst(nl, CTSTR)) {
+ nodconst(&n1, t, nl->val.u.sval->len);
+ } else if(isslice(nl->type) || nl->type->etype == TSTRING) {
n1 = n3;
n1.op = OINDREG;
- n1.type = types[tptr];
+ n1.type = types[TUINT32];
n1.xoffset = Array_nel;
- } else
- nodconst(&n1, types[TUINT64], nl->type->bound);
- gins(optoas(OCMP, types[TUINT32]), &n2, &n1);
- p1 = gbranch(optoas(OLT, types[TUINT32]), T);
+ if(is64(nr->type)) {
+ regalloc(&n5, t, N);
+ gmove(&n1, &n5);
+ n1 = n5;
+ }
+ } else {
+ nodconst(&n1, t, nl->type->bound);
+ }
+ gins(optoas(OCMP, t), &n2, &n1);
+ p1 = gbranch(optoas(OLT, t), T);
+ if(n5.op != OXXX)
+ regfree(&n5);
ginscall(panicindex, 0);
patch(p1, pc);
}
- if(isslice(nl->type)) {
+ if(isconst(nl, CTSTR)) {
+ regalloc(&n3, types[tptr], res);
+ p1 = gins(ALEAQ, N, &n3);
+ datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from);
+ p1->from.scale = 1;
+ p1->from.index = n2.val.u.reg;
+ goto indexdone;
+ }
+
+ if(isslice(nl->type) || nl->type->etype == TSTRING) {
n1 = n3;
n1.op = OINDREG;
n1.type = types[tptr];
@@ -591,12 +610,12 @@ agen(Node *n, Node *res)
p1->from.index = p1->from.type;
p1->from.type = p1->to.type + D_INDIR;
} else {
- nodconst(&n1, t, w);
- gins(optoas(OMUL, t), &n1, &n2);
+ ginscon(optoas(OMUL, t), w, &n2);
gins(optoas(OADD, types[tptr]), &n2, &n3);
gmove(&n3, res);
}
+ indexdone:
gmove(&n3, res);
regfree(&n2);
regfree(&n3);
@@ -616,10 +635,8 @@ agen(Node *n, Node *res)
fatal("agen: bad ONAME class %#x", n->class);
}
cgen(n->heapaddr, res);
- if(n->xoffset != 0) {
- nodconst(&n1, types[TINT64], n->xoffset);
- gins(optoas(OADD, types[tptr]), &n1, res);
- }
+ if(n->xoffset != 0)
+ ginscon(optoas(OADD, types[tptr]), n->xoffset, res);
break;
case OIND:
@@ -628,10 +645,8 @@ agen(Node *n, Node *res)
case ODOT:
agen(nl, res);
- if(n->xoffset != 0) {
- nodconst(&n1, types[TINT64], n->xoffset);
- gins(optoas(OADD, types[tptr]), &n1, res);
- }
+ if(n->xoffset != 0)
+ ginscon(optoas(OADD, types[tptr]), n->xoffset, res);
break;
case ODOTPTR:
@@ -648,8 +663,7 @@ agen(Node *n, Node *res)
gins(ATESTB, nodintconst(0), &n1);
regfree(&n1);
}
- nodconst(&n1, types[TINT64], n->xoffset);
- gins(optoas(OADD, types[tptr]), &n1, res);
+ ginscon(optoas(OADD, types[tptr]), n->xoffset, res);
}
break;
}
@@ -694,6 +708,9 @@ bgen(Node *n, int true, Prog *to)
if(n == N)
n = nodbool(1);
+ if(n->ninit != nil)
+ genlist(n->ninit);
+
nl = n->left;
nr = n->right;
@@ -1006,6 +1023,10 @@ sgen(Node *n, Node *ns, int32 w)
if(w < 0)
fatal("sgen copy %d", w);
+ if(w == 16)
+ if(componentgen(n, ns))
+ return;
+
// offset on the stack
osrc = stkof(n);
odst = stkof(ns);
@@ -1099,3 +1120,163 @@ sgen(Node *n, Node *ns, int32 w)
restx(&nodr, &oldr);
restx(&cx, &oldcx);
}
+
+static int
+cadable(Node *n)
+{
+ if(!n->addable) {
+ // dont know how it happens,
+ // but it does
+ return 0;
+ }
+
+ switch(n->op) {
+ case ONAME:
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * copy a structure component by component
+ * return 1 if can do, 0 if cant.
+ * nr is N for copy zero
+ */
+int
+componentgen(Node *nr, Node *nl)
+{
+ Node nodl, nodr;
+ int freel, freer;
+
+ freel = 0;
+ freer = 0;
+
+ switch(nl->type->etype) {
+ default:
+ goto no;
+
+ case TARRAY:
+ if(!isslice(nl->type))
+ goto no;
+ case TSTRING:
+ case TINTER:
+ break;
+ }
+
+ nodl = *nl;
+ if(!cadable(nl)) {
+ if(nr == N || !cadable(nr))
+ goto no;
+ igen(nl, &nodl, N);
+ freel = 1;
+ }
+
+ if(nr != N) {
+ nodr = *nr;
+ if(!cadable(nr)) {
+ igen(nr, &nodr, N);
+ freer = 1;
+ }
+ }
+
+ switch(nl->type->etype) {
+ case TARRAY:
+ if(!isslice(nl->type))
+ goto no;
+
+ nodl.xoffset += Array_array;
+ nodl.type = ptrto(nl->type->type);
+
+ if(nr != N) {
+ nodr.xoffset += Array_array;
+ nodr.type = nodl.type;
+ } else
+ nodconst(&nodr, nodl.type, 0);
+ gmove(&nodr, &nodl);
+
+ nodl.xoffset += Array_nel-Array_array;
+ nodl.type = types[TUINT32];
+
+ if(nr != N) {
+ nodr.xoffset += Array_nel-Array_array;
+ nodr.type = nodl.type;
+ } else
+ nodconst(&nodr, nodl.type, 0);
+ gmove(&nodr, &nodl);
+
+ nodl.xoffset += Array_cap-Array_nel;
+ nodl.type = types[TUINT32];
+
+ if(nr != N) {
+ nodr.xoffset += Array_cap-Array_nel;
+ nodr.type = nodl.type;
+ } else
+ nodconst(&nodr, nodl.type, 0);
+ gmove(&nodr, &nodl);
+
+ goto yes;
+
+ case TSTRING:
+ nodl.xoffset += Array_array;
+ nodl.type = ptrto(types[TUINT8]);
+
+ if(nr != N) {
+ nodr.xoffset += Array_array;
+ nodr.type = nodl.type;
+ } else
+ nodconst(&nodr, nodl.type, 0);
+ gmove(&nodr, &nodl);
+
+ nodl.xoffset += Array_nel-Array_array;
+ nodl.type = types[TUINT32];
+
+ if(nr != N) {
+ nodr.xoffset += Array_nel-Array_array;
+ nodr.type = nodl.type;
+ } else
+ nodconst(&nodr, nodl.type, 0);
+ gmove(&nodr, &nodl);
+
+ goto yes;
+
+ case TINTER:
+ nodl.xoffset += Array_array;
+ nodl.type = ptrto(types[TUINT8]);
+
+ if(nr != N) {
+ nodr.xoffset += Array_array;
+ nodr.type = nodl.type;
+ } else
+ nodconst(&nodr, nodl.type, 0);
+ gmove(&nodr, &nodl);
+
+ nodl.xoffset += Array_nel-Array_array;
+ nodl.type = ptrto(types[TUINT8]);
+
+ if(nr != N) {
+ nodr.xoffset += Array_nel-Array_array;
+ nodr.type = nodl.type;
+ } else
+ nodconst(&nodr, nodl.type, 0);
+ gmove(&nodr, &nodl);
+
+ goto yes;
+
+ case TSTRUCT:
+ goto no;
+ }
+
+no:
+ if(freer)
+ regfree(&nodr);
+ if(freel)
+ regfree(&nodl);
+ return 0;
+
+yes:
+ if(freer)
+ regfree(&nodr);
+ if(freel)
+ regfree(&nodl);
+ return 1;
+}
diff --git a/src/cmd/6g/galign.c b/src/cmd/6g/galign.c
index 68647e21b..bdfc9947e 100644
--- a/src/cmd/6g/galign.c
+++ b/src/cmd/6g/galign.c
@@ -25,7 +25,6 @@ Typedef typedefs[] =
void
betypeinit(void)
{
- maxround = 8;
widthptr = 8;
zprog.link = P;
diff --git a/src/cmd/6g/gg.h b/src/cmd/6g/gg.h
index 353a86dcd..7efb2c252 100644
--- a/src/cmd/6g/gg.h
+++ b/src/cmd/6g/gg.h
@@ -99,6 +99,7 @@ void cgen_aret(Node*, Node*);
int cgen_inline(Node*, Node*);
void restx(Node*, Node*);
void savex(int, Node*, Node*, Node*, Type*);
+int componentgen(Node*, Node*);
/*
* gsubr.c
@@ -122,6 +123,7 @@ Node* nodarg(Type*, int);
void nodreg(Node*, Type*, int);
void nodindreg(Node*, Type*, int);
void gconreg(int, vlong, int);
+void ginscon(int, vlong, Node*);
void buildtxt(void);
Plist* newplist(void);
int isfat(Type*);
diff --git a/src/cmd/6g/ggen.c b/src/cmd/6g/ggen.c
index 59a6d529d..d9fa1793c 100644
--- a/src/cmd/6g/ggen.c
+++ b/src/cmd/6g/ggen.c
@@ -62,6 +62,8 @@ compile(Node *fn)
pl = newplist();
pl->name = curfn->nname;
+ setlineno(curfn);
+
nodconst(&nod1, types[TINT32], 0);
ptxt = gins(ATEXT, curfn->nname, &nod1);
afunclit(&ptxt->from);
@@ -83,6 +85,8 @@ compile(Node *fn)
checklabels();
if(nerrors != 0)
goto ret;
+ if(curfn->endlineno)
+ lineno = curfn->endlineno;
if(curfn->type->outtuple != 0)
ginscall(throwreturn, 0);
@@ -90,13 +94,13 @@ compile(Node *fn)
if(pret)
patch(pret, pc);
ginit();
+ if(hasdefer)
+ ginscall(deferreturn, 0);
if(curfn->exit)
genlist(curfn->exit);
gclean();
if(nerrors != 0)
goto ret;
- if(hasdefer)
- ginscall(deferreturn, 0);
pc->as = ARET; // overwrite AEND
pc->lineno = lineno;
@@ -105,11 +109,11 @@ compile(Node *fn)
}
// fill in argument size
- ptxt->to.offset = rnd(curfn->type->argwid, maxround);
+ ptxt->to.offset = rnd(curfn->type->argwid, widthptr);
// fill in final stack size
ptxt->to.offset <<= 32;
- ptxt->to.offset |= rnd(stksize+maxarg, maxround);
+ ptxt->to.offset |= rnd(stksize+maxarg, widthptr);
if(debug['f'])
frame(0);
@@ -1041,7 +1045,12 @@ clearfat(Node *nl)
if(debug['g'])
dump("\nclearfat", nl);
+
w = nl->type->width;
+ if(w == 16)
+ if(componentgen(N, nl))
+ return;
+
c = w % 8; // bytes
q = w / 8; // quads
@@ -1115,44 +1124,64 @@ getargs(NodeList *nn, Node *reg, int n)
void
cmpandthrow(Node *nl, Node *nr)
{
- vlong cl, cr;
+ vlong cl;
Prog *p1;
int op;
Node *c;
+ Type *t;
+ Node n1;
+
+ if(nl->op == OCONV && is64(nl->type))
+ nl = nl->left;
+ if(nr->op == OCONV && is64(nr->type))
+ nr = nr->left;
op = OLE;
if(smallintconst(nl)) {
cl = mpgetfix(nl->val.u.xval);
if(cl == 0)
return;
- if(smallintconst(nr)) {
- cr = mpgetfix(nr->val.u.xval);
- if(cl > cr) {
- if(throwpc == nil) {
- throwpc = pc;
- ginscall(panicslice, 0);
- } else
- patch(gbranch(AJMP, T), throwpc);
- }
+ if(smallintconst(nr))
return;
- }
-
// put the constant on the right
op = brrev(op);
c = nl;
nl = nr;
nr = c;
}
-
- gins(optoas(OCMP, types[TUINT32]), nl, nr);
+ if(is64(nr->type) && smallintconst(nr))
+ nr->type = types[TUINT32];
+
+ n1.op = OXXX;
+ t = types[TUINT32];
+ if(nl->type->width != t->width || nr->type->width != t->width) {
+ if((is64(nl->type) && nl->op != OLITERAL) || (is64(nr->type) && nr->op != OLITERAL))
+ t = types[TUINT64];
+
+ // Check if we need to use a temporary.
+ // At least one of the arguments is 32 bits
+ // (the len or cap) so one temporary suffices.
+ if(nl->type->width != t->width && nl->op != OLITERAL) {
+ regalloc(&n1, t, nl);
+ gmove(nl, &n1);
+ nl = &n1;
+ } else if(nr->type->width != t->width && nr->op != OLITERAL) {
+ regalloc(&n1, t, nr);
+ gmove(nr, &n1);
+ nr = &n1;
+ }
+ }
+ gins(optoas(OCMP, t), nl, nr);
+ if(n1.op != OXXX)
+ regfree(&n1);
if(throwpc == nil) {
- p1 = gbranch(optoas(op, types[TUINT32]), T);
+ p1 = gbranch(optoas(op, t), T);
throwpc = pc;
ginscall(panicslice, 0);
patch(p1, pc);
} else {
op = brcom(op);
- p1 = gbranch(optoas(op, types[TUINT32]), T);
+ p1 = gbranch(optoas(op, t), T);
patch(p1, throwpc);
}
}
@@ -1183,6 +1212,8 @@ cgen_inline(Node *n, Node *res)
goto no;
if(!n->left->addable)
goto no;
+ if(n->left->sym == S)
+ goto no;
if(n->left->sym->pkg != runtimepkg)
goto no;
if(strcmp(n->left->sym->name, "slicearray") == 0)
@@ -1261,10 +1292,8 @@ slicearray:
if(smallintconst(&nodes[2]) && smallintconst(&nodes[4])) {
v = mpgetfix(nodes[2].val.u.xval) *
mpgetfix(nodes[4].val.u.xval);
- if(v != 0) {
- nodconst(&n1, types[tptr], v);
- gins(optoas(OADD, types[tptr]), &n1, &nodes[0]);
- }
+ if(v != 0)
+ ginscon(optoas(OADD, types[tptr]), v, &nodes[0]);
} else {
regalloc(&n1, types[tptr], &nodes[2]);
gmove(&nodes[2], &n1);
@@ -1310,6 +1339,7 @@ sliceslice:
// if(lb[1] > old.nel[0]) goto throw;
n2 = nodes[0];
n2.xoffset += Array_nel;
+ n2.type = types[TUINT32];
cmpandthrow(&nodes[1], &n2);
// ret.nel = old.nel[0]-lb[1];
@@ -1329,6 +1359,7 @@ sliceslice:
// if(hb[2] > old.cap[0]) goto throw;
n2 = nodes[0];
n2.xoffset += Array_cap;
+ n2.type = types[TUINT32];
cmpandthrow(&nodes[2], &n2);
// if(lb[1] > hb[2]) goto throw;
@@ -1376,10 +1407,8 @@ sliceslice:
gins(optoas(OAS, types[tptr]), &n2, &n1);
v = mpgetfix(nodes[1].val.u.xval) *
mpgetfix(nodes[3].val.u.xval);
- if(v != 0) {
- nodconst(&n2, types[tptr], v);
- gins(optoas(OADD, types[tptr]), &n2, &n1);
- }
+ if(v != 0)
+ ginscon(optoas(OADD, types[tptr]), v, &n1);
} else {
gmove(&nodes[1], &n1);
if(!smallintconst(&nodes[3]) || mpgetfix(nodes[3].val.u.xval) != 1)
diff --git a/src/cmd/6g/gobj.c b/src/cmd/6g/gobj.c
index 7c05054b7..b667ae48a 100644
--- a/src/cmd/6g/gobj.c
+++ b/src/cmd/6g/gobj.c
@@ -633,7 +633,7 @@ dsymptr(Sym *s, int off, Sym *x, int xoff)
}
void
-genembedtramp(Type *rcvr, Type *method, Sym *newnam)
+genembedtramp(Type *rcvr, Type *method, Sym *newnam, int iface)
{
Sym *e;
int c, d, o, mov, add, loaded;
@@ -732,7 +732,7 @@ out:
p = pc;
gins(AJMP, N, N);
p->to.type = D_EXTERN;
- p->to.sym = methodsym(method->sym, ptrto(f->type));
+ p->to.sym = methodsym(method->sym, ptrto(f->type), 0);
//print("6. %P\n", p);
pc->as = ARET; // overwrite AEND
diff --git a/src/cmd/6g/gsubr.c b/src/cmd/6g/gsubr.c
index 52ff6fdea..ebb61ea94 100644
--- a/src/cmd/6g/gsubr.c
+++ b/src/cmd/6g/gsubr.c
@@ -147,6 +147,8 @@ ggloblnod(Node *nam, int32 width)
p->to.sym = S;
p->to.type = D_CONST;
p->to.offset = width;
+ if(nam->readonly)
+ p->from.scale = RODATA;
}
void
@@ -163,6 +165,7 @@ ggloblsym(Sym *s, int32 width, int dupok)
p->to.offset = width;
if(dupok)
p->from.scale = DUPOK;
+ p->from.scale |= RODATA;
}
int
@@ -427,11 +430,33 @@ fatal("shouldnt be used");
void
gconreg(int as, vlong c, int reg)
{
- Node n1, n2;
+ Node nr;
+
+ nodreg(&nr, types[TINT64], reg);
+ ginscon(as, c, &nr);
+}
+
+/*
+ * generate
+ * as $c, n
+ */
+void
+ginscon(int as, vlong c, Node *n2)
+{
+ Node n1, ntmp;
nodconst(&n1, types[TINT64], c);
- nodreg(&n2, types[TINT64], reg);
- gins(as, &n1, &n2);
+
+ if(as != AMOVQ && (c < -1LL<<31 || c >= 1LL<<31)) {
+ // cannot have 64-bit immediokate in ADD, etc.
+ // instead, MOV into register first.
+ regalloc(&ntmp, types[TINT64], N);
+ gins(AMOVQ, &n1, &ntmp);
+ gins(as, &ntmp, n2);
+ regfree(&ntmp);
+ return;
+ }
+ gins(as, &n1, n2);
}
#define CASE(a,b) (((a)<<16)|((b)<<0))
@@ -1683,12 +1708,28 @@ optoas(int op, Type *t)
enum
{
- ODynam = 1<<0,
+ ODynam = 1<<0,
+ OAddable = 1<<1,
};
static Node clean[20];
static int cleani = 0;
+int
+xgen(Node *n, Node *a, int o)
+{
+ regalloc(a, types[tptr], N);
+
+ if(o & ODynam)
+ if(n->addable)
+ if(n->op != OINDREG)
+ if(n->op != OREGISTER)
+ return 1;
+
+ agen(n, a);
+ return 0;
+}
+
void
sudoclean(void)
{
@@ -1716,7 +1757,7 @@ sudoaddable(int as, Node *n, Addr *a)
int o, i, w;
int oary[10];
int64 v;
- Node n1, n2, n3, *nn, *l, *r;
+ Node n1, n2, n3, n4, *nn, *l, *r;
Node *reg, *reg1;
Prog *p1;
Type *t;
@@ -1743,6 +1784,8 @@ sudoaddable(int as, Node *n, Addr *a)
goto odot;
case OINDEX:
+ if(n->left->type->etype == TSTRING)
+ return 0;
goto oindex;
}
return 0;
@@ -1820,7 +1863,7 @@ oindex:
if(l->type->etype != TARRAY)
fatal("not ary");
if(l->type->bound < 0)
- o += ODynam;
+ o |= ODynam;
w = n->type->width;
if(isconst(r, CTINT))
@@ -1836,9 +1879,6 @@ oindex:
break;
}
-// if(sudoaddable(as, l, a))
-// goto oindex_sudo;
-
cleani += 2;
reg = &clean[cleani-1];
reg1 = &clean[cleani-2];
@@ -1847,8 +1887,8 @@ oindex:
// load the array (reg)
if(l->ullman > r->ullman) {
- regalloc(reg, types[tptr], N);
- agen(l, reg);
+ if(xgen(l, reg, o))
+ o |= OAddable;
}
// load the index (reg1)
@@ -1863,49 +1903,89 @@ oindex:
// load the array (reg)
if(l->ullman <= r->ullman) {
- regalloc(reg, types[tptr], N);
- agen(l, reg);
+ if(xgen(l, reg, o))
+ o |= OAddable;
}
if(!(o & ODynam) && l->type->width >= unmappedzero && l->op == OIND) {
// cannot rely on page protections to
// catch array ptr == 0, so dereference.
n2 = *reg;
+ n2.xoffset = 0;
n2.op = OINDREG;
n2.type = types[TUINT8];
- n2.xoffset = 0;
gins(ATESTB, nodintconst(0), &n2);
}
// check bounds
if(!debug['B'] && !n->etype) {
+ // check bounds
+ n4.op = OXXX;
+ t = types[TUINT32];
if(o & ODynam) {
- n2 = *reg;
- n2.op = OINDREG;
- n2.type = types[tptr];
- n2.xoffset = Array_nel;
+ if(o & OAddable) {
+ n2 = *l;
+ n2.xoffset += Array_nel;
+ n2.type = types[TUINT32];
+ if(is64(r->type)) {
+ t = types[TUINT64];
+ regalloc(&n4, t, N);
+ gmove(&n2, &n4);
+ n2 = n4;
+ }
+ } else {
+ n2 = *reg;
+ n2.xoffset = Array_nel;
+ n2.op = OINDREG;
+ n2.type = types[TUINT32];
+ if(is64(r->type)) {
+ t = types[TUINT64];
+ regalloc(&n4, t, N);
+ gmove(&n2, &n4);
+ n2 = n4;
+ }
+ }
} else {
+ if(is64(r->type))
+ t = types[TUINT64];
nodconst(&n2, types[TUINT64], l->type->bound);
}
- gins(optoas(OCMP, types[TUINT32]), reg1, &n2);
- p1 = gbranch(optoas(OLT, types[TUINT32]), T);
+ gins(optoas(OCMP, t), reg1, &n2);
+ p1 = gbranch(optoas(OLT, t), T);
+ if(n4.op != OXXX)
+ regfree(&n4);
ginscall(panicindex, 0);
patch(p1, pc);
}
if(o & ODynam) {
- n2 = *reg;
- n2.op = OINDREG;
- n2.type = types[tptr];
- n2.xoffset = Array_array;
- gmove(&n2, reg);
+ if(o & OAddable) {
+ n2 = *l;
+ n2.xoffset += Array_array;
+ n2.type = types[TUINT64];
+ gmove(&n2, reg);
+ } else {
+ n2 = *reg;
+ n2.xoffset = Array_array;
+ n2.op = OINDREG;
+ n2.type = types[tptr];
+ gmove(&n2, reg);
+ }
}
- naddr(reg1, a, 1);
- a->offset = 0;
- a->scale = w;
- a->index = a->type;
- a->type = reg->val.u.reg + D_INDIR;
+ if(o & OAddable) {
+ naddr(reg1, a, 1);
+ a->offset = 0;
+ a->scale = w;
+ a->index = a->type;
+ a->type = reg->val.u.reg + D_INDIR;
+ } else {
+ naddr(reg1, a, 1);
+ a->offset = 0;
+ a->scale = w;
+ a->index = a->type;
+ a->type = reg->val.u.reg + D_INDIR;
+ }
goto yes;
@@ -1915,15 +1995,6 @@ oindex_const:
// can multiply by width statically
v = mpgetfix(r->val.u.xval);
- if(!debug['B'] && (o & ODynam) == 0) {
- // array indexed by a constant bounds check
- if(v < 0) {
- yyerror("out of bounds on array");
- } else
- if(v >= l->type->bound) {
- yyerror("out of bounds on array");
- }
- }
if(sudoaddable(as, l, a))
goto oindex_const_sudo;
diff --git a/src/cmd/6g/list.c b/src/cmd/6g/list.c
index 9194b1dab..c8077c97a 100644
--- a/src/cmd/6g/list.c
+++ b/src/cmd/6g/list.c
@@ -47,24 +47,28 @@ Pconv(Fmt *fp)
{
char str[STRINGSZ];
Prog *p;
+ char scale[40];
p = va_arg(fp->args, Prog*);
sconsize = 8;
+ scale[0] = '\0';
+ if(p->from.scale != 0 && (p->as == AGLOBL || p->as == ATEXT))
+ snprint(scale, sizeof scale, "%d,", p->from.scale);
switch(p->as) {
default:
- snprint(str, sizeof(str), "%.4ld (%L) %-7A %D,%D",
- p->loc, p->lineno, p->as, &p->from, &p->to);
+ snprint(str, sizeof(str), "%.4d (%L) %-7A %D,%s%D",
+ p->loc, p->lineno, p->as, &p->from, scale, &p->to);
break;
case ADATA:
sconsize = p->from.scale;
- snprint(str, sizeof(str), "%.4ld (%L) %-7A %D/%d,%D",
+ snprint(str, sizeof(str), "%.4d (%L) %-7A %D/%d,%D",
p->loc, p->lineno, p->as, &p->from, sconsize, &p->to);
break;
case ATEXT:
- snprint(str, sizeof(str), "%.4ld (%L) %-7A %D,%lD",
- p->loc, p->lineno, p->as, &p->from, &p->to);
+ snprint(str, sizeof(str), "%.4d (%L) %-7A %D,%s%lD",
+ p->loc, p->lineno, p->as, &p->from, scale, &p->to);
break;
}
return fmtstrcpy(fp, str);
@@ -104,7 +108,7 @@ Dconv(Fmt *fp)
if(a->branch == nil)
snprint(str, sizeof(str), "<nil>");
else
- snprint(str, sizeof(str), "%ld", a->branch->loc);
+ snprint(str, sizeof(str), "%d", a->branch->loc);
break;
case D_EXTERN:
@@ -127,7 +131,7 @@ Dconv(Fmt *fp)
if(fp->flags & FmtLong) {
d1 = a->offset & 0xffffffffLL;
d2 = (a->offset>>32) & 0xffffffffLL;
- snprint(str, sizeof(str), "$%lud-%lud", (ulong)d1, (ulong)d2);
+ snprint(str, sizeof(str), "$%ud-%ud", (ulong)d1, (ulong)d2);
break;
}
snprint(str, sizeof(str), "$%lld", a->offset);
diff --git a/src/cmd/6g/reg.c b/src/cmd/6g/reg.c
index e92740e04..464627066 100644
--- a/src/cmd/6g/reg.c
+++ b/src/cmd/6g/reg.c
@@ -682,17 +682,17 @@ brk:
print("\nstats\n");
if(ostats.ncvtreg)
- print(" %4ld cvtreg\n", ostats.ncvtreg);
+ print(" %4d cvtreg\n", ostats.ncvtreg);
if(ostats.nspill)
- print(" %4ld spill\n", ostats.nspill);
+ print(" %4d spill\n", ostats.nspill);
if(ostats.nreload)
- print(" %4ld reload\n", ostats.nreload);
+ print(" %4d reload\n", ostats.nreload);
if(ostats.ndelmov)
- print(" %4ld delmov\n", ostats.ndelmov);
+ print(" %4d delmov\n", ostats.ndelmov);
if(ostats.nvar)
- print(" %4ld delmov\n", ostats.nvar);
+ print(" %4d delmov\n", ostats.nvar);
if(ostats.naddr)
- print(" %4ld delmov\n", ostats.naddr);
+ print(" %4d delmov\n", ostats.naddr);
memset(&ostats, 0, sizeof(ostats));
}
@@ -1268,7 +1268,7 @@ regset(Reg *r, uint32 bb)
while(b = bb & ~(bb-1)) {
v.type = b & 0xFFFF? BtoR(b): BtoF(b);
if(v.type == 0)
- fatal("zero v.type for %#lux", b);
+ fatal("zero v.type for %#ux", b);
c = copyu(r->prog, &v, A);
if(c == 3)
set |= b;
@@ -1486,7 +1486,7 @@ dumpone(Reg *r)
int z;
Bits bit;
- print("%ld:%P", r->loop, r->prog);
+ print("%d:%P", r->loop, r->prog);
for(z=0; z<BITS; z++)
bit.b[z] =
r->set.b[z] |
@@ -1535,14 +1535,14 @@ dumpit(char *str, Reg *r0)
if(r1 != R) {
print(" pred:");
for(; r1 != R; r1 = r1->p2link)
- print(" %.4lud", r1->prog->loc);
+ print(" %.4ud", r1->prog->loc);
print("\n");
}
// r1 = r->s1;
// if(r1 != R) {
// print(" succ:");
// for(; r1 != R; r1 = r1->s1)
-// print(" %.4lud", r1->prog->loc);
+// print(" %.4ud", r1->prog->loc);
// print("\n");
// }
}
diff --git a/src/cmd/6l/6.out.h b/src/cmd/6l/6.out.h
index ca5e485c0..709f82ccc 100644
--- a/src/cmd/6l/6.out.h
+++ b/src/cmd/6l/6.out.h
@@ -33,6 +33,7 @@
#define NOPROF (1<<0)
#define DUPOK (1<<1)
#define NOSPLIT (1<<2)
+#define RODATA (1<<3)
/*
* amd64
@@ -389,8 +390,8 @@ enum as
AEND,
- ADYNT,
- AINIT,
+ ADYNT_,
+ AINIT_,
ASIGNAME,
@@ -823,6 +824,7 @@ enum
D_INDIR, /* additive */
D_SIZE = D_INDIR + D_INDIR, /* 6l internal */
+ D_PCREL,
T_TYPE = 1<<0,
T_INDEX = 1<<1,
diff --git a/src/cmd/6l/Makefile b/src/cmd/6l/Makefile
index 72bde4465..fba1b42ae 100644
--- a/src/cmd/6l/Makefile
+++ b/src/cmd/6l/Makefile
@@ -2,23 +2,29 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.conf
+include ../../Make.inc
+O:=$(HOST_O)
-TARG=\
- 6l\
+TARG=6l
OFILES=\
asm.$O\
+ data.$O\
+ dwarf.$O\
elf.$O\
enam.$O\
go.$O\
+ ldelf.$O\
+ ldmacho.$O\
lib.$O\
list.$O\
macho.$O\
obj.$O\
optab.$O\
pass.$O\
+ prof.$O\
span.$O\
+ symtab.$O\
HFILES=\
l.h\
@@ -26,20 +32,14 @@ HFILES=\
../ld/lib.h\
../ld/elf.h\
../ld/macho.h\
+ ../ld/dwarf.h\
-$(TARG): $(OFILES)
- $(LD) -o $(TARG) -L"$(GOROOT)"/lib $(OFILES) -lbio -l9
-
-$(OFILES): $(HFILES)
+include ../../Make.ccmd
enam.c: 6.out.h
sh mkenam
-clean:
- rm -f *.$O $(TARG) *.6 enam.c 6.out a.out
-
-install: $(TARG)
- cp $(TARG) "$(GOBIN)"/$(TARG)
+CLEANFILES+=enam.c
%.$O: ../ld/%.c
- $(CC) $(CFLAGS) -c -I. ../ld/$*.c
+ $(HOST_CC) $(HOST_CFLAGS) -c -I. ../ld/$*.c
diff --git a/src/cmd/6l/asm.c b/src/cmd/6l/asm.c
index b45557ebe..9726d227c 100644
--- a/src/cmd/6l/asm.c
+++ b/src/cmd/6l/asm.c
@@ -28,9 +28,12 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+// Writing object files.
+
#include "l.h"
#include "../ld/lib.h"
#include "../ld/elf.h"
+#include "../ld/dwarf.h"
#include "../ld/macho.h"
#define Dbufslop 100
@@ -41,7 +44,6 @@ char linuxdynld[] = "/lib64/ld-linux-x86-64.so.2";
char freebsddynld[] = "/libexec/ld-elf.so.1";
char zeroes[32];
-Prog* datsort(Prog *l);
vlong
entryvalue(void)
@@ -55,15 +57,8 @@ entryvalue(void)
s = lookup(a, 0);
if(s->type == 0)
return INITTEXT;
- switch(s->type) {
- case STEXT:
- break;
- case SDATA:
- if(dlm)
- return s->value+INITDAT;
- default:
+ if(s->type != STEXT)
diag("entry not text: %s", s->name);
- }
return s->value;
}
@@ -113,130 +108,13 @@ vputl(uint64 v)
lputl(v>>32);
}
-void
-strnput(char *s, int n)
-{
- int i;
-
- for(i=0; i<n; i++) {
- cput(*s);
- if(*s != 0)
- s++;
- }
-}
-
-vlong
-addstring(Sym *s, char *str)
-{
- int n, m;
- vlong r;
- Prog *p;
-
- if(s->type == 0)
- s->type = SDATA;
- s->reachable = 1;
- r = s->value;
- n = strlen(str)+1;
- while(n > 0) {
- m = n;
- if(m > sizeof(p->to.scon))
- m = sizeof(p->to.scon);
- p = newdata(s, s->value, m, D_EXTERN);
- p->to.type = D_SCONST;
- memmove(p->to.scon, str, m);
- s->value += m;
- str += m;
- n -= m;
- }
- return r;
-}
-
-vlong
-adduintxx(Sym *s, uint64 v, int wid)
-{
- vlong r;
- Prog *p;
-
- if(s->type == 0)
- s->type = SDATA;
- s->reachable = 1;
- r = s->value;
- p = newdata(s, s->value, wid, D_EXTERN);
- s->value += wid;
- p->to.type = D_CONST;
- p->to.offset = v;
- return r;
-}
-
-vlong
-adduint8(Sym *s, uint8 v)
-{
- return adduintxx(s, v, 1);
-}
-
-vlong
-adduint16(Sym *s, uint16 v)
-{
- return adduintxx(s, v, 2);
-}
-
-vlong
-adduint32(Sym *s, uint32 v)
-{
- return adduintxx(s, v, 4);
-}
-
-vlong
-adduint64(Sym *s, uint64 v)
-{
- return adduintxx(s, v, 8);
-}
-
-vlong
-addaddr(Sym *s, Sym *t)
-{
- vlong r;
- Prog *p;
- enum { Ptrsize = 8 };
-
- if(s->type == 0)
- s->type = SDATA;
- s->reachable = 1;
- r = s->value;
- p = newdata(s, s->value, Ptrsize, D_EXTERN);
- s->value += Ptrsize;
- p->to.type = D_ADDR;
- p->to.index = D_EXTERN;
- p->to.offset = 0;
- p->to.sym = t;
- return r;
-}
-
-vlong
-addsize(Sym *s, Sym *t)
-{
- vlong r;
- Prog *p;
- enum { Ptrsize = 8 };
-
- if(s->type == 0)
- s->type = SDATA;
- s->reachable = 1;
- r = s->value;
- p = newdata(s, s->value, Ptrsize, D_EXTERN);
- s->value += Ptrsize;
- p->to.type = D_SIZE;
- p->to.index = D_EXTERN;
- p->to.offset = 0;
- p->to.sym = t;
- return r;
-}
-
vlong
datoff(vlong addr)
{
- if(addr >= INITDAT)
- return addr - INITDAT + rnd(HEADR+textsize, INITRND);
+ if(addr >= segdata.vaddr)
+ return addr - segdata.vaddr + segdata.fileoff;
+ if(addr >= segtext.vaddr)
+ return addr - segtext.vaddr + segtext.fileoff;
diag("datoff %#llx", addr);
return 0;
}
@@ -260,6 +138,8 @@ enum {
ElfStrShstrtab,
ElfStrSymtab,
ElfStrStrtab,
+ ElfStrRelaPlt,
+ ElfStrPlt,
NElfStr
};
@@ -281,29 +161,461 @@ needlib(char *name)
return 0;
}
+int nelfsym = 1;
+
+static void addpltsym(Sym*);
+static void addgotsym(Sym*);
+
+void
+adddynrel(Sym *s, Reloc *r)
+{
+ Sym *targ, *rela, *got;
+
+ targ = r->sym;
+ cursym = s;
+
+ switch(r->type) {
+ default:
+ if(r->type >= 256) {
+ diag("unexpected relocation type %d", r->type);
+ return;
+ }
+ break;
+
+ // Handle relocations found in ELF object files.
+ case 256 + R_X86_64_PC32:
+ if(targ->dynimpname != nil && !targ->dynexport)
+ diag("unexpected R_X86_64_PC32 relocation for dynamic symbol %s", targ->name);
+ if(targ->type == 0 || targ->type == SXREF)
+ diag("unknown symbol %s in pcrel", targ->name);
+ r->type = D_PCREL;
+ r->add += 4;
+ return;
+
+ case 256 + R_X86_64_PLT32:
+ r->type = D_PCREL;
+ r->add += 4;
+ if(targ->dynimpname != nil && !targ->dynexport) {
+ addpltsym(targ);
+ r->sym = lookup(".plt", 0);
+ r->add += targ->plt;
+ }
+ return;
+
+ case 256 + R_X86_64_GOTPCREL:
+ if(targ->dynimpname == nil || targ->dynexport) {
+ // have symbol
+ // turn MOVQ of GOT entry into LEAQ of symbol itself
+ if(r->off < 2 || s->p[r->off-2] != 0x8b) {
+ diag("unexpected GOT_LOAD reloc for non-dynamic symbol %s", targ->name);
+ return;
+ }
+ s->p[r->off-2] = 0x8d;
+ r->type = D_PCREL;
+ r->add += 4;
+ return;
+ }
+ addgotsym(targ);
+ r->type = D_PCREL;
+ r->sym = lookup(".got", 0);
+ r->add += 4;
+ r->add += targ->got;
+ return;
+
+ case 256 + R_X86_64_64:
+ if(targ->dynimpname != nil && !targ->dynexport)
+ diag("unexpected R_X86_64_64 relocation for dynamic symbol %s", targ->name);
+ r->type = D_ADDR;
+ return;
+
+ // Handle relocations found in Mach-O object files.
+ case 512 + MACHO_X86_64_RELOC_UNSIGNED*2 + 0:
+ case 512 + MACHO_X86_64_RELOC_SIGNED*2 + 0:
+ case 512 + MACHO_X86_64_RELOC_BRANCH*2 + 0:
+ // TODO: What is the difference between all these?
+ r->type = D_ADDR;
+ if(targ->dynimpname != nil && !targ->dynexport)
+ diag("unexpected reloc for dynamic symbol %s", targ->name);
+ return;
+
+ case 512 + MACHO_X86_64_RELOC_BRANCH*2 + 1:
+ if(targ->dynimpname != nil && !targ->dynexport) {
+ addpltsym(targ);
+ r->sym = lookup(".plt", 0);
+ r->add = targ->plt;
+ r->type = D_PCREL;
+ return;
+ }
+ // fall through
+ case 512 + MACHO_X86_64_RELOC_UNSIGNED*2 + 1:
+ case 512 + MACHO_X86_64_RELOC_SIGNED*2 + 1:
+ case 512 + MACHO_X86_64_RELOC_SIGNED_1*2 + 1:
+ case 512 + MACHO_X86_64_RELOC_SIGNED_2*2 + 1:
+ case 512 + MACHO_X86_64_RELOC_SIGNED_4*2 + 1:
+ r->type = D_PCREL;
+ if(targ->dynimpname != nil && !targ->dynexport)
+ diag("unexpected pc-relative reloc for dynamic symbol %s", targ->name);
+ return;
+
+ case 512 + MACHO_X86_64_RELOC_GOT_LOAD*2 + 1:
+ if(targ->dynimpname == nil || targ->dynexport) {
+ // have symbol
+ // turn MOVQ of GOT entry into LEAQ of symbol itself
+ if(r->off < 2 || s->p[r->off-2] != 0x8b) {
+ diag("unexpected GOT_LOAD reloc for non-dynamic symbol %s", targ->name);
+ return;
+ }
+ s->p[r->off-2] = 0x8d;
+ r->type = D_PCREL;
+ return;
+ }
+ // fall through
+ case 512 + MACHO_X86_64_RELOC_GOT*2 + 1:
+ if(targ->dynimpname == nil || targ->dynexport)
+ diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name);
+ addgotsym(targ);
+ r->type = D_PCREL;
+ r->sym = lookup(".got", 0);
+ r->add += targ->got;
+ return;
+ }
+
+ // Handle references to ELF symbols from our own object files.
+ if(targ->dynimpname == nil || targ->dynexport)
+ return;
+
+ switch(r->type) {
+ case D_PCREL:
+ addpltsym(targ);
+ r->sym = lookup(".plt", 0);
+ r->add = targ->plt;
+ return;
+
+ case D_ADDR:
+ if(s->type != SDATA)
+ break;
+ if(iself) {
+ adddynsym(targ);
+ rela = lookup(".rela", 0);
+ addaddrplus(rela, s, r->off);
+ if(r->siz == 8)
+ adduint64(rela, ELF64_R_INFO(targ->dynid, R_X86_64_64));
+ else
+ adduint64(rela, ELF64_R_INFO(targ->dynid, R_X86_64_32));
+ adduint64(rela, r->add);
+ r->type = 256; // ignore during relocsym
+ return;
+ }
+ if(HEADTYPE == 6 && s->size == PtrSize && r->off == 0) {
+ // Mach-O relocations are a royal pain to lay out.
+ // They use a compact stateful bytecode representation
+ // that is too much bother to deal with.
+ // Instead, interpret the C declaration
+ // void *_Cvar_stderr = &stderr;
+ // as making _Cvar_stderr the name of a GOT entry
+ // for stderr. This is separate from the usual GOT entry,
+ // just in case the C code assigns to the variable,
+ // and of course it only works for single pointers,
+ // but we only need to support cgo and that's all it needs.
+ adddynsym(targ);
+ got = lookup(".got", 0);
+ s->type = got->type | SSUB;
+ s->outer = got;
+ s->sub = got->sub;
+ got->sub = s;
+ s->value = got->size;
+ adduint64(got, 0);
+ adduint32(lookup(".linkedit.got", 0), targ->dynid);
+ r->type = 256; // ignore during relocsym
+ return;
+ }
+ break;
+ }
+
+ cursym = s;
+ diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type);
+}
+
+int
+archreloc(Reloc *r, Sym *s, vlong *val)
+{
+ return -1;
+}
+
+static void
+elfsetupplt(void)
+{
+ Sym *plt, *got;
+
+ plt = lookup(".plt", 0);
+ got = lookup(".got.plt", 0);
+ if(plt->size == 0) {
+ // pushq got+8(IP)
+ adduint8(plt, 0xff);
+ adduint8(plt, 0x35);
+ addpcrelplus(plt, got, 8);
+
+ // jmpq got+16(IP)
+ adduint8(plt, 0xff);
+ adduint8(plt, 0x25);
+ addpcrelplus(plt, got, 16);
+
+ // nopl 0(AX)
+ adduint32(plt, 0x00401f0f);
+
+ // assume got->size == 0 too
+ addaddrplus(got, lookup(".dynamic", 0), 0);
+ adduint64(got, 0);
+ adduint64(got, 0);
+ }
+}
+
+static void
+addpltsym(Sym *s)
+{
+ if(s->plt >= 0)
+ return;
+
+ adddynsym(s);
+
+ if(iself) {
+ Sym *plt, *got, *rela;
+
+ plt = lookup(".plt", 0);
+ got = lookup(".got.plt", 0);
+ rela = lookup(".rela.plt", 0);
+ if(plt->size == 0)
+ elfsetupplt();
+
+ // jmpq *got+size(IP)
+ adduint8(plt, 0xff);
+ adduint8(plt, 0x25);
+ addpcrelplus(plt, got, got->size);
+
+ // add to got: pointer to current pos in plt
+ addaddrplus(got, plt, plt->size);
+
+ // pushq $x
+ adduint8(plt, 0x68);
+ adduint32(plt, (got->size-24-8)/8);
+
+ // jmpq .plt
+ adduint8(plt, 0xe9);
+ adduint32(plt, -(plt->size+4));
+
+ // rela
+ addaddrplus(rela, got, got->size-8);
+ adduint64(rela, ELF64_R_INFO(s->dynid, R_X86_64_JMP_SLOT));
+ adduint64(rela, 0);
+
+ s->plt = plt->size - 16;
+ } else if(HEADTYPE == 6) { // Mach-O
+ // To do lazy symbol lookup right, we're supposed
+ // to tell the dynamic loader which library each
+ // symbol comes from and format the link info
+ // section just so. I'm too lazy (ha!) to do that
+ // so for now we'll just use non-lazy pointers,
+ // which don't need to be told which library to use.
+ //
+ // http://networkpx.blogspot.com/2009/09/about-lcdyldinfoonly-command.html
+ // has details about what we're avoiding.
+
+ Sym *plt;
+
+ addgotsym(s);
+ plt = lookup(".plt", 0);
+
+ adduint32(lookup(".linkedit.plt", 0), s->dynid);
+
+ // jmpq *got+size(IP)
+ s->plt = plt->size;
+
+ adduint8(plt, 0xff);
+ adduint8(plt, 0x25);
+ addpcrelplus(plt, lookup(".got", 0), s->got);
+ } else {
+ diag("addpltsym: unsupported binary format");
+ }
+}
+
+static void
+addgotsym(Sym *s)
+{
+ Sym *got, *rela;
+
+ if(s->got >= 0)
+ return;
+
+ adddynsym(s);
+ got = lookup(".got", 0);
+ s->got = got->size;
+ adduint64(got, 0);
+
+ if(iself) {
+ rela = lookup(".rela", 0);
+ addaddrplus(rela, got, s->got);
+ adduint64(rela, ELF64_R_INFO(s->dynid, R_X86_64_GLOB_DAT));
+ adduint64(rela, 0);
+ } else if(HEADTYPE == 6) { // Mach-O
+ adduint32(lookup(".linkedit.got", 0), s->dynid);
+ } else {
+ diag("addgotsym: unsupported binary format");
+ }
+}
+
+void
+adddynsym(Sym *s)
+{
+ Sym *d, *str;
+ int t;
+ char *name;
+
+ if(s->dynid >= 0)
+ return;
+
+ if(s->dynimpname == nil)
+ diag("adddynsym: no dynamic name for %s", s->name);
+
+ if(iself) {
+ s->dynid = nelfsym++;
+
+ d = lookup(".dynsym", 0);
+ name = s->dynimpname;
+ if(name == nil)
+ name = s->name;
+ adduint32(d, addstring(lookup(".dynstr", 0), name));
+ /* type */
+ t = STB_GLOBAL << 4;
+ if(s->dynexport && s->type == STEXT)
+ t |= STT_FUNC;
+ else
+ t |= STT_OBJECT;
+ adduint8(d, t);
+
+ /* reserved */
+ adduint8(d, 0);
+
+ /* section where symbol is defined */
+ if(!s->dynexport && s->dynimpname != nil)
+ adduint16(d, SHN_UNDEF);
+ else {
+ switch(s->type) {
+ default:
+ case STEXT:
+ t = 11;
+ break;
+ case SRODATA:
+ t = 12;
+ break;
+ case SDATA:
+ t = 13;
+ break;
+ case SBSS:
+ t = 14;
+ break;
+ }
+ adduint16(d, t);
+ }
+
+ /* value */
+ if(s->type == SDYNIMPORT)
+ adduint64(d, 0);
+ else
+ addaddr(d, s);
+
+ /* size of object */
+ adduint64(d, 0);
+
+ if(!s->dynexport && s->dynimplib && needlib(s->dynimplib)) {
+ elfwritedynent(lookup(".dynamic", 0), DT_NEEDED,
+ addstring(lookup(".dynstr", 0), s->dynimplib));
+ }
+ } else if(HEADTYPE == 6) {
+ // Mach-o symbol nlist64
+ d = lookup(".dynsym", 0);
+ name = s->dynimpname;
+ if(name == nil)
+ name = s->name;
+ s->dynid = d->size/16;
+ // darwin still puts _ prefixes on all C symbols
+ str = lookup(".dynstr", 0);
+ adduint32(d, str->size);
+ adduint8(str, '_');
+ addstring(str, name);
+ if(s->type == SDYNIMPORT) {
+ adduint8(d, 0x01); // type - N_EXT - external symbol
+ adduint8(d, 0); // section
+ } else {
+ adduint8(d, 0x0f);
+ switch(s->type) {
+ default:
+ case STEXT:
+ adduint8(d, 1);
+ break;
+ case SDATA:
+ adduint8(d, 2);
+ break;
+ case SBSS:
+ adduint8(d, 4);
+ break;
+ }
+ }
+ adduint16(d, 0); // desc
+ if(s->type == SDYNIMPORT)
+ adduint64(d, 0); // value
+ else
+ addaddr(d, s);
+ } else {
+ diag("adddynsym: unsupported binary format");
+ }
+}
+
+void
+adddynlib(char *lib)
+{
+ Sym *s;
+
+ if(!needlib(lib))
+ return;
+
+ if(iself) {
+ s = lookup(".dynstr", 0);
+ if(s->size == 0)
+ addstring(s, "");
+ elfwritedynent(lookup(".dynamic", 0), DT_NEEDED, addstring(s, lib));
+ } else if(HEADTYPE == 6) { // Mach-O
+ machoadddynlib(lib);
+ } else {
+ diag("adddynlib: unsupported binary format");
+ }
+}
+
void
doelf(void)
{
- Sym *s, *shstrtab, *dynamic, *dynstr, *d;
- int h, nsym, t;
+ Sym *s, *shstrtab, *dynstr;
if(HEADTYPE != 7 && HEADTYPE != 9)
return;
/* predefine strings we need for section headers */
shstrtab = lookup(".shstrtab", 0);
+ shstrtab->type = SELFDATA;
+ shstrtab->reachable = 1;
+
elfstr[ElfStrEmpty] = addstring(shstrtab, "");
elfstr[ElfStrText] = addstring(shstrtab, ".text");
elfstr[ElfStrData] = addstring(shstrtab, ".data");
elfstr[ElfStrBss] = addstring(shstrtab, ".bss");
+ addstring(shstrtab, ".elfdata");
+ addstring(shstrtab, ".rodata");
if(!debug['s']) {
elfstr[ElfStrGosymcounts] = addstring(shstrtab, ".gosymcounts");
elfstr[ElfStrGosymtab] = addstring(shstrtab, ".gosymtab");
elfstr[ElfStrGopclntab] = addstring(shstrtab, ".gopclntab");
- if(debug['e']) {
- elfstr[ElfStrSymtab] = addstring(shstrtab, ".symtab");
- elfstr[ElfStrStrtab] = addstring(shstrtab, ".strtab");
- }
+ elfstr[ElfStrSymtab] = addstring(shstrtab, ".symtab");
+ elfstr[ElfStrStrtab] = addstring(shstrtab, ".strtab");
+ dwarfaddshstrings(shstrtab);
}
elfstr[ElfStrShstrtab] = addstring(shstrtab, ".shstrtab");
@@ -316,19 +628,21 @@ doelf(void)
elfstr[ElfStrDynsym] = addstring(shstrtab, ".dynsym");
elfstr[ElfStrDynstr] = addstring(shstrtab, ".dynstr");
elfstr[ElfStrRela] = addstring(shstrtab, ".rela");
+ elfstr[ElfStrRelaPlt] = addstring(shstrtab, ".rela.plt");
+ elfstr[ElfStrPlt] = addstring(shstrtab, ".plt");
/* dynamic symbol table - first entry all zeros */
s = lookup(".dynsym", 0);
s->type = SELFDATA;
s->reachable = 1;
- s->value += ELF64SYMSIZE;
+ s->size += ELF64SYMSIZE;
/* dynamic string table */
s = lookup(".dynstr", 0);
s->type = SELFDATA;
s->reachable = 1;
- s->value += ELF64SYMSIZE;
- addstring(s, "");
+ if(s->size == 0)
+ addstring(s, "");
dynstr = s;
/* relocation table */
@@ -339,15 +653,24 @@ doelf(void)
/* global offset table */
s = lookup(".got", 0);
s->reachable = 1;
+ s->type = SDATA; // writable, so not SELFDATA
+
+ /* hash */
+ s = lookup(".hash", 0);
+ s->reachable = 1;
s->type = SELFDATA;
- /* got.plt - ??? */
s = lookup(".got.plt", 0);
s->reachable = 1;
+ s->type = SDATA; // writable, not SELFDATA
+
+ s = lookup(".plt", 0);
+ s->reachable = 1;
s->type = SELFDATA;
- /* hash */
- s = lookup(".hash", 0);
+ elfsetupplt();
+
+ s = lookup(".rela.plt", 0);
s->reachable = 1;
s->type = SELFDATA;
@@ -355,78 +678,10 @@ doelf(void)
s = lookup(".dynamic", 0);
s->reachable = 1;
s->type = SELFDATA;
- dynamic = s;
-
- /*
- * relocation entries for dynimport symbols
- */
- nsym = 1; // sym 0 is reserved
- for(h=0; h<NHASH; h++) {
- for(s=hash[h]; s!=S; s=s->link) {
- if(!s->reachable || (s->type != STEXT && s->type != SDATA && s->type != SBSS) || s->dynimpname == nil)
- continue;
-
- if(!s->dynexport) {
- d = lookup(".rela", 0);
- addaddr(d, s);
- adduint64(d, ELF64_R_INFO(nsym, R_X86_64_64));
- adduint64(d, 0);
- }
-
- nsym++;
-
- d = lookup(".dynsym", 0);
- adduint32(d, addstring(lookup(".dynstr", 0), s->dynimpname));
- /* type */
- t = STB_GLOBAL << 4;
- if(s->dynexport && s->type == STEXT)
- t |= STT_FUNC;
- else
- t |= STT_OBJECT;
- adduint8(d, t);
-
- /* reserved */
- adduint8(d, 0);
-
- /* section where symbol is defined */
- if(!s->dynexport)
- adduint16(d, SHN_UNDEF);
- else {
- switch(s->type) {
- default:
- case STEXT:
- t = 9;
- break;
- case SDATA:
- t = 10;
- break;
- case SBSS:
- t = 11;
- break;
- }
- adduint16(d, t);
- }
-
- /* value */
- if(!s->dynexport)
- adduint64(d, 0);
- else
- addaddr(d, s);
-
- /* size of object */
- adduint64(d, 0);
-
- if(!s->dynexport && needlib(s->dynimplib))
- elfwritedynent(dynamic, DT_NEEDED, addstring(dynstr, s->dynimplib));
- }
- }
-
- elfdynhash(nsym);
/*
* .dynamic table
*/
- s = dynamic;
elfwritedynentsym(s, DT_HASH, lookup(".hash", 0));
elfwritedynentsym(s, DT_SYMTAB, lookup(".dynsym", 0));
elfwritedynent(s, DT_SYMENT, ELF64SYMSIZE);
@@ -437,6 +692,11 @@ doelf(void)
elfwritedynent(s, DT_RELAENT, ELF64RELASIZE);
if(rpath)
elfwritedynent(s, DT_RUNPATH, addstring(dynstr, rpath));
+
+ elfwritedynentsym(s, DT_PLTGOT, lookup(".got.plt", 0));
+ elfwritedynent(s, DT_PLTREL, DT_RELA);
+ elfwritedynentsymsize(s, DT_PLTRELSZ, lookup(".rela.plt", 0));
+ elfwritedynentsym(s, DT_JMPREL, lookup(".rela.plt", 0));
elfwritedynent(s, DT_NULL, 0);
}
}
@@ -463,15 +723,13 @@ phsh(ElfPhdr *ph, ElfShdr *sh)
void
asmb(void)
{
- Prog *p;
- int32 v, magic;
+ int32 magic;
int a, dynsym;
- uchar *op1;
vlong vl, va, startva, fo, w, symo, elfsymo, elfstro, elfsymsize, machlink;
- vlong symdatva = SYMDATVA;
ElfEhdr *eh;
ElfPhdr *ph, *pph;
ElfShdr *sh;
+ Section *sect;
if(debug['v'])
Bprint(&bso, "%5.2f asmb\n", cputime());
@@ -481,101 +739,51 @@ asmb(void)
elfsymsize = 0;
elfstro = 0;
elfsymo = 0;
- seek(cout, HEADR, 0);
- pc = INITTEXT;
- curp = firstp;
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT)
- curtext = p;
- if(p->pc != pc) {
- if(!debug['a'])
- print("%P\n", curp);
- diag("phase error %llux sb %llux in %s", p->pc, pc, TNAME);
- pc = p->pc;
- }
- curp = p;
- asmins(p);
- a = (andptr - and);
- if(cbc < a)
- cflush();
- if(debug['a']) {
- Bprint(&bso, pcstr, pc);
- for(op1 = and; op1 < andptr; op1++)
- Bprint(&bso, "%.2ux", *op1);
- for(; op1 < and+Maxand; op1++)
- Bprint(&bso, " ");
- Bprint(&bso, "%P\n", curp);
- }
- if(dlm) {
- if(p->as == ATEXT)
- reloca = nil;
- else if(reloca != nil)
- diag("reloc failure: %P", curp);
- }
- memmove(cbp, and, a);
- cbp += a;
- pc += a;
- cbc -= a;
- }
- cflush();
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f codeblk\n", cputime());
+ Bflush(&bso);
+
+ sect = segtext.sect;
+ seek(cout, sect->vaddr - segtext.vaddr + segtext.fileoff, 0);
+ codeblk(sect->vaddr, sect->len);
+
+ /* output read-only data in text segment */
+ sect = segtext.sect->next;
+ seek(cout, sect->vaddr - segtext.vaddr + segtext.fileoff, 0);
+ datblk(sect->vaddr, sect->len);
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f datblk\n", cputime());
+ Bflush(&bso);
+ seek(cout, segdata.fileoff, 0);
+ datblk(segdata.vaddr, segdata.filelen);
+
+ machlink = 0;
+ if(HEADTYPE == 6)
+ machlink = domacholink();
switch(HEADTYPE) {
default:
- diag("unknown header type %ld", HEADTYPE);
+ diag("unknown header type %d", HEADTYPE);
case 2:
case 5:
- seek(cout, HEADR+textsize, 0);
break;
case 6:
debug['8'] = 1; /* 64-bit addresses */
- v = HEADR+textsize;
- seek(cout, v, 0);
- v = rnd(v, 4096) - v;
- while(v > 0) {
- cput(0);
- v--;
- }
- cflush();
break;
-
case 7:
case 9:
debug['8'] = 1; /* 64-bit addresses */
- v = rnd(HEADR+textsize, INITRND);
- seek(cout, v, 0);
-
/* index of elf text section; needed by asmelfsym, double-checked below */
- /* debug['d'] causes 8 extra sections before the .text section */
+ /* !debug['d'] causes extra sections before the .text section */
elftextsh = 1;
if(!debug['d'])
- elftextsh += 8;
+ elftextsh += 10;
break;
}
- if(debug['v'])
- Bprint(&bso, "%5.2f datblk\n", cputime());
- Bflush(&bso);
-
- if(dlm){
- char buf[8];
-
- write(cout, buf, INITDAT-textsize);
- textsize = INITDAT;
- }
-
- datap = datsort(datap);
- for(v = 0; v < datsize; v += sizeof(buf)-Dbufslop) {
- if(datsize-v > sizeof(buf)-Dbufslop)
- datblk(v, sizeof(buf)-Dbufslop);
- else
- datblk(v, datsize-v);
- }
-
- machlink = 0;
- if(HEADTYPE == 6)
- machlink = domacholink();
-
symsize = 0;
spsize = 0;
lcsize = 0;
@@ -589,14 +797,14 @@ asmb(void)
case 2:
case 5:
debug['s'] = 1;
- symo = HEADR+textsize+datsize;
+ symo = HEADR+segtext.len+segdata.filelen;
break;
case 6:
- symo = rnd(HEADR+textsize, INITRND)+rnd(datsize, INITRND)+machlink;
+ symo = rnd(HEADR+segtext.len, INITRND)+rnd(segdata.filelen, INITRND)+machlink;
break;
case 7:
case 9:
- symo = rnd(HEADR+textsize, INITRND)+datsize;
+ symo = rnd(HEADR+segtext.len, INITRND)+segdata.filelen;
symo = rnd(symo, INITRND);
break;
}
@@ -608,8 +816,6 @@ asmb(void)
* line number table
*/
seek(cout, symo+8, 0);
- if(!debug['s'])
- asmsym();
if(debug['v'])
Bprint(&bso, "%5.2f sp\n", cputime());
Bflush(&bso);
@@ -617,30 +823,26 @@ asmb(void)
Bprint(&bso, "%5.2f pc\n", cputime());
Bflush(&bso);
if(!debug['s'])
- asmlc();
- if(dlm)
- asmdyn();
- if(!debug['s'])
strnput("", INITRND-(8+symsize+lcsize)%INITRND);
cflush();
seek(cout, symo, 0);
lputl(symsize);
lputl(lcsize);
cflush();
- if(!debug['s'] && debug['e']) {
+ if(!debug['s']) {
elfsymo = symo+8+symsize+lcsize;
seek(cout, elfsymo, 0);
- asmelfsym();
+ asmelfsym64();
cflush();
elfstro = seek(cout, 0, 1);
elfsymsize = elfstro - elfsymo;
- write(cout, elfstrdat, elfstrsize);
- }
- } else
- if(dlm){
- seek(cout, HEADR+textsize+datsize, 0);
- asmdyn();
- cflush();
+ ewrite(cout, elfstrdat, elfstrsize);
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f dwarf\n", cputime());
+
+ dwarfemitdebugsections();
+ }
}
if(debug['v'])
@@ -652,12 +854,10 @@ asmb(void)
case 2: /* plan9 */
magic = 4*26*26+7;
magic |= 0x00008000; /* fat header */
- if(dlm)
- magic |= 0x80000000; /* dlm */
lputb(magic); /* magic */
- lputb(textsize); /* sizes */
- lputb(datsize);
- lputb(bsssize);
+ lputb(segtext.filelen); /* sizes */
+ lputb(segdata.filelen);
+ lputb(segdata.len - segdata.filelen);
lputb(symsize); /* nsyms */
vl = entryvalue();
lputb(PADDR(vl)); /* va of entry */
@@ -667,19 +867,17 @@ asmb(void)
break;
case 3: /* plan9 */
magic = 4*26*26+7;
- if(dlm)
- magic |= 0x80000000;
lputb(magic); /* magic */
- lputb(textsize); /* sizes */
- lputb(datsize);
- lputb(bsssize);
+ lputb(segtext.filelen); /* sizes */
+ lputb(segdata.filelen);
+ lputb(segdata.len - segdata.filelen);
lputb(symsize); /* nsyms */
lputb(entryvalue()); /* va of entry */
lputb(spsize); /* sp offsets */
lputb(lcsize); /* line offsets */
break;
case 6:
- asmbmacho(symdatva, symo);
+ asmbmacho();
break;
case 7:
case 9:
@@ -689,7 +887,7 @@ asmb(void)
fo = HEADR;
startva = INITTEXT - HEADR;
va = startva + fo;
- w = textsize;
+ w = segtext.filelen;
/* This null SHdr must appear before all others */
sh = newElfShdr(elfstr[ElfStrEmpty]);
@@ -724,41 +922,8 @@ asmb(void)
phsh(ph, sh);
}
- ph = newElfPhdr();
- ph->type = PT_LOAD;
- ph->flags = PF_X+PF_R;
- ph->vaddr = va - fo;
- ph->paddr = va - fo;
- ph->off = 0;
- ph->filesz = w + fo;
- ph->memsz = w + fo;
- ph->align = INITRND;
-
- fo = rnd(fo+w, INITRND);
- va = rnd(va+w, INITRND);
- w = datsize;
-
- ph = newElfPhdr();
- ph->type = PT_LOAD;
- ph->flags = PF_W+PF_R;
- ph->off = fo;
- ph->vaddr = va;
- ph->paddr = va;
- ph->filesz = w;
- ph->memsz = w+bsssize;
- ph->align = INITRND;
-
- if(!debug['s']) {
- ph = newElfPhdr();
- ph->type = PT_LOAD;
- ph->flags = PF_R;
- ph->off = symo;
- ph->vaddr = symdatva;
- ph->paddr = symdatva;
- ph->filesz = rnd(8+symsize+lcsize, INITRND);
- ph->memsz = rnd(8+symsize+lcsize, INITRND);
- ph->align = INITRND;
- }
+ elfphload(&segtext);
+ elfphload(&segdata);
/* Dynamic linking sections */
if (!debug['d']) { /* -d suppresses dynamic loader format */
@@ -776,7 +941,7 @@ asmb(void)
sh->entsize = 8;
sh->addralign = 8;
shsym(sh, lookup(".got.plt", 0));
-
+
dynsym = eh->shnum;
sh = newElfShdr(elfstr[ElfStrDynsym]);
sh->type = SHT_DYNSYM;
@@ -793,6 +958,22 @@ asmb(void)
sh->addralign = 1;
shsym(sh, lookup(".dynstr", 0));
+ sh = newElfShdr(elfstr[ElfStrRelaPlt]);
+ sh->type = SHT_RELA;
+ sh->flags = SHF_ALLOC;
+ sh->entsize = ELF64RELASIZE;
+ sh->addralign = 8;
+ sh->link = dynsym;
+ sh->info = eh->shnum; // .plt
+ shsym(sh, lookup(".rela.plt", 0));
+
+ sh = newElfShdr(elfstr[ElfStrPlt]);
+ sh->type = SHT_PROGBITS;
+ sh->flags = SHF_ALLOC+SHF_EXECINSTR;
+ sh->entsize = 16;
+ sh->addralign = 4;
+ shsym(sh, lookup(".plt", 0));
+
sh = newElfShdr(elfstr[ElfStrHash]);
sh->type = SHT_HASH;
sh->flags = SHF_ALLOC;
@@ -821,6 +1002,17 @@ asmb(void)
ph->type = PT_DYNAMIC;
ph->flags = PF_R + PF_W;
phsh(ph, sh);
+
+ /*
+ * Thread-local storage segment (really just size).
+ */
+ if(tlsoffset != 0) {
+ ph = newElfPhdr();
+ ph->type = PT_TLS;
+ ph->flags = PF_R;
+ ph->memsz = -tlsoffset;
+ ph->align = 8;
+ }
}
ph = newElfPhdr();
@@ -828,93 +1020,41 @@ asmb(void)
ph->flags = PF_W+PF_R;
ph->align = 8;
- fo = ELFRESERVE;
- va = startva + fo;
- w = textsize;
-
if(elftextsh != eh->shnum)
diag("elftextsh = %d, want %d", elftextsh, eh->shnum);
- sh = newElfShdr(elfstr[ElfStrText]);
- sh->type = SHT_PROGBITS;
- sh->flags = SHF_ALLOC+SHF_EXECINSTR;
- sh->addr = va;
- sh->off = fo;
- sh->size = w;
- sh->addralign = 8;
-
- fo = rnd(fo+w, INITRND);
- va = rnd(va+w, INITRND);
- w = datsize;
-
- sh = newElfShdr(elfstr[ElfStrData]);
- sh->type = SHT_PROGBITS;
- sh->flags = SHF_WRITE+SHF_ALLOC;
- sh->addr = va + elfdatsize;
- sh->off = fo + elfdatsize;
- sh->size = w - elfdatsize;
- sh->addralign = 8;
-
- fo += w;
- va += w;
- w = bsssize;
-
- sh = newElfShdr(elfstr[ElfStrBss]);
- sh->type = SHT_NOBITS;
- sh->flags = SHF_WRITE+SHF_ALLOC;
- sh->addr = va;
- sh->off = fo;
- sh->size = w;
- sh->addralign = 8;
+ for(sect=segtext.sect; sect!=nil; sect=sect->next)
+ elfshbits(sect);
+ for(sect=segdata.sect; sect!=nil; sect=sect->next)
+ elfshbits(sect);
if (!debug['s']) {
- fo = symo;
- w = 8;
-
- sh = newElfShdr(elfstr[ElfStrGosymcounts]);
+ sh = newElfShdr(elfstr[ElfStrGosymtab]);
sh->type = SHT_PROGBITS;
sh->flags = SHF_ALLOC;
- sh->off = fo;
- sh->size = w;
sh->addralign = 1;
- sh->addr = symdatva;
-
- fo += w;
- w = symsize;
+ shsym(sh, lookup("symtab", 0));
- sh = newElfShdr(elfstr[ElfStrGosymtab]);
+ sh = newElfShdr(elfstr[ElfStrGopclntab]);
sh->type = SHT_PROGBITS;
sh->flags = SHF_ALLOC;
- sh->off = fo;
- sh->size = w;
sh->addralign = 1;
- sh->addr = symdatva + 8;
+ shsym(sh, lookup("pclntab", 0));
- fo += w;
- w = lcsize;
+ sh = newElfShdr(elfstr[ElfStrSymtab]);
+ sh->type = SHT_SYMTAB;
+ sh->off = elfsymo;
+ sh->size = elfsymsize;
+ sh->addralign = 8;
+ sh->entsize = 24;
+ sh->link = eh->shnum; // link to strtab
- sh = newElfShdr(elfstr[ElfStrGopclntab]);
- sh->type = SHT_PROGBITS;
- sh->flags = SHF_ALLOC;
- sh->off = fo;
- sh->size = w;
+ sh = newElfShdr(elfstr[ElfStrStrtab]);
+ sh->type = SHT_STRTAB;
+ sh->off = elfstro;
+ sh->size = elfstrsize;
sh->addralign = 1;
- sh->addr = symdatva + 8 + symsize;
-
- if(debug['e']) {
- sh = newElfShdr(elfstr[ElfStrSymtab]);
- sh->type = SHT_SYMTAB;
- sh->off = elfsymo;
- sh->size = elfsymsize;
- sh->addralign = 8;
- sh->entsize = 24;
- sh->link = eh->shnum; // link to strtab
-
- sh = newElfShdr(elfstr[ElfStrStrtab]);
- sh->type = SHT_STRTAB;
- sh->off = elfstro;
- sh->size = elfstrsize;
- sh->addralign = 1;
- }
+
+ dwarfaddelfheaders();
}
sh = newElfShstrtab(elfstr[ElfStrShstrtab]);
@@ -961,354 +1101,91 @@ cflush(void)
n = sizeof(buf.cbuf) - cbc;
if(n)
- write(cout, buf.cbuf, n);
+ ewrite(cout, buf.cbuf, n);
cbp = buf.cbuf;
cbc = sizeof(buf.cbuf);
}
-void
-outa(int n, uchar *cast, uchar *map, vlong l)
-{
- int i, j;
-
- Bprint(&bso, pcstr, l);
- for(i=0; i<n; i++) {
- j = i;
- if(map != nil)
- j = map[j];
- Bprint(&bso, "%.2ux", cast[j]);
- }
- for(; i<Maxand; i++)
- Bprint(&bso, " ");
- Bprint(&bso, "%P\n", curp);
-}
-
-/*
- * divide-and-conquer list-link
- * sort of Prog* structures.
- * Used for the data block.
- */
-int
-datcmp(Prog *p1, Prog *p2)
+/* Current position in file */
+vlong
+cpos(void)
{
- vlong v1, v2;
-
- v1 = p1->from.offset;
- v2 = p2->from.offset;
- if(v1 > v2)
- return +1;
- if(v1 < v2)
- return -1;
- return 0;
+ return seek(cout, 0, 1) + sizeof(buf.cbuf) - cbc;
}
-Prog*
-dsort(Prog *l)
-{
- Prog *l1, *l2, *le;
-
- if(l == 0 || l->link == 0)
- return l;
-
- l1 = l;
- l2 = l;
- for(;;) {
- l2 = l2->link;
- if(l2 == 0)
- break;
- l2 = l2->link;
- if(l2 == 0)
- break;
- l1 = l1->link;
- }
-
- l2 = l1->link;
- l1->link = 0;
- l1 = dsort(l);
- l2 = dsort(l2);
-
- /* set up lead element */
- if(datcmp(l1, l2) < 0) {
- l = l1;
- l1 = l1->link;
- } else {
- l = l2;
- l2 = l2->link;
- }
- le = l;
-
- for(;;) {
- if(l1 == 0) {
- while(l2) {
- le->link = l2;
- le = l2;
- l2 = l2->link;
- }
- le->link = 0;
- break;
- }
- if(l2 == 0) {
- while(l1) {
- le->link = l1;
- le = l1;
- l1 = l1->link;
- }
- break;
- }
- if(datcmp(l1, l2) < 0) {
- le->link = l1;
- le = l1;
- l1 = l1->link;
- } else {
- le->link = l2;
- le = l2;
- l2 = l2->link;
- }
- }
- le->link = 0;
- return l;
-}
-
-static Prog *datp;
-
-Prog*
-datsort(Prog *l)
+vlong
+rnd(vlong v, vlong r)
{
- Prog *p;
- Adr *a;
+ vlong c;
- for(p = l; p != P; p = p->link) {
- a = &p->from;
- a->offset += a->sym->value;
- }
- datp = dsort(l);
- return datp;
+ if(r <= 0)
+ return v;
+ v += r - 1;
+ c = v % r;
+ if(c < 0)
+ c += r;
+ v -= c;
+ return v;
}
void
-datblk(int32 s, int32 n)
+genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
{
- Prog *p;
- uchar *cast;
- int32 l, fl, j;
- vlong o;
- int i, c;
- Adr *a;
-
- for(p = datp; p != P; p = p->link) {
- a = &p->from;
- l = a->offset - s;
- if(l+a->scale < 0)
- continue;
- datp = p;
- break;
- }
-
- memset(buf.dbuf, 0, n+Dbufslop);
- for(p = datp; p != P; p = p->link) {
- a = &p->from;
-
- l = a->offset - s;
- if(l >= n)
- break;
-
- c = a->scale;
- i = 0;
- if(l < 0) {
- if(l+c <= 0)
+ Auto *a;
+ Sym *s;
+ int h;
+
+ for(h=0; h<NHASH; h++) {
+ for(s=hash[h]; s!=S; s=s->hash) {
+ switch(s->type&~SSUB) {
+ case SCONST:
+ case SRODATA:
+ case SDATA:
+ case SELFDATA:
+ case SMACHOGOT:
+ if(!s->reachable)
+ continue;
+ put(s, s->name, 'D', symaddr(s), s->size, s->version, s->gotype);
continue;
- i = -l;
- l = 0;
- }
-
- curp = p;
- if(!a->sym->reachable)
- diag("unreachable symbol in datblk - %s", a->sym->name);
- if(a->sym->type == SMACHO)
- continue;
- if(p->as != AINIT && p->as != ADYNT) {
- for(j=l+(c-i)-1; j>=l; j--)
- if(buf.dbuf[j]) {
- print("%P\n", p);
- diag("multiple initialization for %d %d", s, j);
- break;
- }
- }
-
- switch(p->to.type) {
- case D_FCONST:
- switch(c) {
- default:
- case 4:
- fl = ieeedtof(&p->to.ieee);
- cast = (uchar*)&fl;
- for(; i<c; i++) {
- buf.dbuf[l] = cast[fnuxi4[i]];
- l++;
- }
- break;
- case 8:
- cast = (uchar*)&p->to.ieee;
- for(; i<c; i++) {
- buf.dbuf[l] = cast[fnuxi8[i]];
- l++;
- }
- break;
- }
- break;
-
- case D_SCONST:
- for(; i<c; i++) {
- buf.dbuf[l] = p->to.scon[i];
- l++;
- }
- break;
+ case SBSS:
+ if(!s->reachable)
+ continue;
+ put(s, s->name, 'B', symaddr(s), s->size, s->version, s->gotype);
+ continue;
- default:
- o = p->to.offset;
- if(p->to.type == D_SIZE)
- o += p->to.sym->size;
- if(p->to.type == D_ADDR) {
- if(p->to.index != D_STATIC && p->to.index != D_EXTERN)
- diag("DADDR type%P", p);
- if(p->to.sym) {
- if(p->to.sym->type == SUNDEF)
- ckoff(p->to.sym, o);
- if(p->to.sym->type == Sxxx) {
- curtext = p; // show useful name in diag's output
- diag("missing symbol %s", p->to.sym->name);
- }
- o += p->to.sym->value;
- if(p->to.sym->type != STEXT && p->to.sym->type != SUNDEF)
- o += INITDAT;
- if(dlm)
- dynreloc(p->to.sym, l+s+INITDAT, 1);
- }
- }
- fl = o;
- cast = (uchar*)&fl;
- switch(c) {
- default:
- diag("bad nuxi %d %d\n%P", c, i, curp);
- break;
- case 1:
- for(; i<c; i++) {
- buf.dbuf[l] = cast[inuxi1[i]];
- l++;
- }
- break;
- case 2:
- for(; i<c; i++) {
- buf.dbuf[l] = cast[inuxi2[i]];
- l++;
- }
- break;
- case 4:
- for(; i<c; i++) {
- buf.dbuf[l] = cast[inuxi4[i]];
- l++;
- }
- break;
- case 8:
- cast = (uchar*)&o;
- for(; i<c; i++) {
- buf.dbuf[l] = cast[inuxi8[i]];
- l++;
- }
- break;
+ case SFILE:
+ put(nil, s->name, 'f', s->value, 0, s->version, 0);
+ continue;
}
- break;
}
}
- write(cout, buf.dbuf, n);
- if(!debug['a'])
- return;
-
- /*
- * a second pass just to print the asm
- */
- for(p = datap; p != P; p = p->link) {
- a = &p->from;
-
- l = a->offset - s;
- if(l >= n)
- continue;
-
- c = a->scale;
- i = 0;
- if(l < 0)
- continue;
-
- if(a->sym->type == SMACHO)
+ for(s = textp; s != nil; s = s->next) {
+ if(s->text == nil)
continue;
- switch(p->to.type) {
- case D_FCONST:
- switch(c) {
- default:
- case 4:
- fl = ieeedtof(&p->to.ieee);
- cast = (uchar*)&fl;
- outa(c, cast, fnuxi4, l+s+INITDAT);
- break;
- case 8:
- cast = (uchar*)&p->to.ieee;
- outa(c, cast, fnuxi8, l+s+INITDAT);
- break;
- }
- break;
-
- case D_SCONST:
- outa(c, (uchar*)p->to.scon, nil, l+s+INITDAT);
- break;
-
- default:
- o = p->to.offset;
- if(p->to.type == D_SIZE)
- o += p->to.sym->size;
- if(p->to.type == D_ADDR) {
- if(p->to.sym) {
- o += p->to.sym->value;
- if(p->to.sym->type != STEXT && p->to.sym->type != SUNDEF)
- o += INITDAT;
- }
- }
- fl = o;
- cast = (uchar*)&fl;
- switch(c) {
- case 1:
- outa(c, cast, inuxi1, l+s+INITDAT);
- break;
- case 2:
- outa(c, cast, inuxi2, l+s+INITDAT);
- break;
- case 4:
- outa(c, cast, inuxi4, l+s+INITDAT);
- break;
- case 8:
- cast = (uchar*)&o;
- outa(c, cast, inuxi8, l+s+INITDAT);
- break;
- }
- break;
- }
+ /* filenames first */
+ for(a=s->autom; a; a=a->link)
+ if(a->type == D_FILE)
+ put(nil, a->asym->name, 'z', a->aoffset, 0, 0, 0);
+ else
+ if(a->type == D_FILE1)
+ put(nil, a->asym->name, 'Z', a->aoffset, 0, 0, 0);
+
+ put(s, s->name, 'T', s->value, s->size, s->version, s->gotype);
+
+ /* frame, auto and param after */
+ put(nil, ".frame", 'm', s->text->to.offset+8, 0, 0, 0);
+
+ for(a=s->autom; a; a=a->link)
+ if(a->type == D_AUTO)
+ put(nil, a->asym->name, 'a', -a->aoffset, 0, 0, a->gotype);
+ else
+ if(a->type == D_PARAM)
+ put(nil, a->asym->name, 'p', a->aoffset, 0, 0, a->gotype);
}
+ if(debug['v'] || debug['n'])
+ Bprint(&bso, "symsize = %ud\n", symsize);
+ Bflush(&bso);
}
-
-vlong
-rnd(vlong v, vlong r)
-{
- vlong c;
-
- if(r <= 0)
- return v;
- v += r - 1;
- c = v % r;
- if(c < 0)
- c += r;
- v -= c;
- return v;
-}
-
diff --git a/src/cmd/6l/doc.go b/src/cmd/6l/doc.go
index a74e9b5c0..501317f36 100644
--- a/src/cmd/6l/doc.go
+++ b/src/cmd/6l/doc.go
@@ -32,8 +32,8 @@ Options new in this version:
Write Apple Mach-O binaries (default when $GOOS is darwin)
-H7
Write Linux ELF binaries (default when $GOOS is linux)
--L dir1,dir2,..
- Search for libraries (package files) in the comma-separated list of directories.
+-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.
diff --git a/src/cmd/6l/l.h b/src/cmd/6l/l.h
index 3db0b450a..1c52ea89d 100644
--- a/src/cmd/6l/l.h
+++ b/src/cmd/6l/l.h
@@ -44,7 +44,7 @@ enum
#define P ((Prog*)0)
#define S ((Sym*)0)
-#define TNAME (curtext?curtext->from.sym->name:noname)
+#define TNAME (cursym?cursym->name:noname)
#define cput(c)\
{ *cbp++ = c;\
if(--cbc <= 0)\
@@ -56,6 +56,7 @@ typedef struct Sym Sym;
typedef struct Auto Auto;
typedef struct Optab Optab;
typedef struct Movtab Movtab;
+typedef struct Reloc Reloc;
struct Adr
{
@@ -67,11 +68,7 @@ struct Adr
Ieee u0ieee;
char *u0sbig;
} u0;
- union
- {
- Auto* u1autom;
- Sym* u1sym;
- } u1;
+ Sym* sym;
short type;
char index;
char scale;
@@ -83,18 +80,25 @@ struct Adr
#define ieee u0.u0ieee
#define sbig u0.u0sbig
-#define autom u1.u1autom
-#define sym u1.u1sym
+struct Reloc
+{
+ int32 off;
+ uchar siz;
+ int32 type;
+ int64 add;
+ Sym* sym;
+};
struct Prog
{
Adr from;
Adr to;
- Prog *forwd;
+ Prog* forwd;
+ Prog* comefrom;
Prog* link;
- Prog* dlink;
Prog* pcond; /* work on this */
vlong pc;
+ int32 spadj;
int32 line;
short as;
char ft; /* oclass cache */
@@ -102,9 +106,12 @@ struct Prog
uchar mark; /* work on these */
uchar back;
- char width; /* fake for DATA */
+ char width; /* fake for DATA */
char mode; /* 16, 32, or 64 */
};
+#define datasize from.scale
+#define textflag from.scale
+
struct Auto
{
Sym* asym;
@@ -115,25 +122,39 @@ struct Auto
};
struct Sym
{
- char *name;
+ char* name;
short type;
short version;
- short become;
- short frame;
- uchar subtype;
uchar dupok;
uchar reachable;
uchar dynexport;
+ uchar special;
+ int32 dynid;
+ int32 sig;
+ int32 plt;
+ int32 got;
+ Sym* hash; // in hash table
+ Sym* next; // in text or data list
+ Sym* sub; // in SSUB list
+ Sym* outer; // container of sub
vlong value;
vlong size;
- int32 sig;
- Sym* link;
- Prog* text;
- Prog* data;
Sym* gotype;
char* file;
char* dynimpname;
char* dynimplib;
+
+ // STEXT
+ Auto* autom;
+ Prog* text;
+
+ // SDATA, SBSS
+ uchar* p;
+ int32 np;
+ int32 maxp;
+ Reloc* r;
+ int32 nr;
+ int32 maxr;
};
struct Optab
{
@@ -154,21 +175,25 @@ struct Movtab
enum
{
Sxxx,
+
+ /* order here is order in output file */
STEXT = 1,
+ SELFDATA,
+ SMACHOPLT,
+ SRODATA,
SDATA,
+ SMACHOGOT,
SBSS,
- SDATA1,
+
SXREF,
+ SMACHODYNSTR,
+ SMACHODYNSYM,
+ SMACHOINDIRECTPLT,
+ SMACHOINDIRECTGOT,
SFILE,
SCONST,
- SUNDEF,
-
- SIMPORT,
- SEXPORT,
-
- SMACHO,
- SFIXED,
- SELFDATA,
+ SDYNIMPORT,
+ SSUB = 1<<8,
NHASH = 10007,
NHUNK = 100000,
@@ -274,8 +299,6 @@ enum
Rxx = 1<<1, /* extend sib index */
Rxb = 1<<0, /* extend modrm r/m, sib base, or opcode reg */
- Roffset = 22, /* no. bits for offset in relocation address */
- Rindex = 10, /* no. bits for index in relocation address */
Maxand = 10, /* in -a output width of the byte codes */
};
@@ -300,35 +323,30 @@ EXTERN union
EXTERN int32 HEADR;
EXTERN int32 HEADTYPE;
-EXTERN vlong INITDAT;
EXTERN int32 INITRND;
EXTERN vlong INITTEXT;
+EXTERN vlong INITDAT;
EXTERN char* INITENTRY; /* entry point */
EXTERN Biobuf bso;
-EXTERN int32 bsssize;
EXTERN int cbc;
EXTERN char* cbp;
EXTERN char* pcstr;
EXTERN Auto* curauto;
EXTERN Auto* curhist;
EXTERN Prog* curp;
-EXTERN Prog* curtext;
-EXTERN Prog* datap;
-EXTERN Prog* edatap;
-EXTERN vlong datsize;
+EXTERN Sym* cursym;
+EXTERN Sym* datap;
EXTERN vlong elfdatsize;
EXTERN char debug[128];
EXTERN char literal[32];
-EXTERN Prog* etextp;
-EXTERN Prog* firstp;
-EXTERN int xrefresolv;
+EXTERN Sym* textp;
+EXTERN Sym* etextp;
EXTERN char ycover[Ymax*Ymax];
EXTERN uchar* andptr;
EXTERN uchar* rexptr;
EXTERN uchar and[30];
EXTERN int reg[D_NONE];
EXTERN int regrex[D_NONE+1];
-EXTERN Prog* lastp;
EXTERN int32 lcsize;
EXTERN int nerrors;
EXTERN char* noname;
@@ -338,8 +356,7 @@ EXTERN char* rpath;
EXTERN int32 spsize;
EXTERN Sym* symlist;
EXTERN int32 symsize;
-EXTERN Prog* textp;
-EXTERN vlong textsize;
+EXTERN int tlsoffset;
EXTERN int version;
EXTERN Prog zprg;
EXTERN int dtype;
@@ -347,45 +364,29 @@ EXTERN char* paramspace;
EXTERN Sym* adrgotype; // type symbol on last Adr read
EXTERN Sym* fromgotype; // type symbol on last p->from read
-EXTERN Adr* reloca;
-EXTERN int doexp; // export table
-EXTERN int dlm; // dynamically loadable module
-EXTERN int imports, nimports;
-EXTERN int exports, nexports;
-EXTERN char* EXPTAB;
-EXTERN Prog undefp;
EXTERN vlong textstksiz;
EXTERN vlong textarg;
extern char thechar;
-EXTERN int dynptrsize;
EXTERN int elfstrsize;
EXTERN char* elfstrdat;
EXTERN int elftextsh;
-#define UP (&undefp)
-
extern Optab optab[];
extern Optab* opindex[];
extern char* anames[];
int Aconv(Fmt*);
int Dconv(Fmt*);
+int Iconv(Fmt*);
int Pconv(Fmt*);
int Rconv(Fmt*);
int Sconv(Fmt*);
void addhist(int32, int);
void addstackmark(void);
Prog* appendp(Prog*);
-vlong addstring(Sym*, char*);
-vlong adduint32(Sym*, uint32);
-vlong adduint64(Sym*, uint64);
-vlong addaddr(Sym*, Sym*);
-vlong addsize(Sym*, Sym*);
void asmb(void);
void asmdyn(void);
void asmins(Prog*);
-void asmlc(void);
-void asmsp(void);
void asmsym(void);
void asmelfsym(void);
vlong atolwhex(char*);
@@ -393,35 +394,29 @@ Prog* brchain(Prog*);
Prog* brloop(Prog*);
void buildop(void);
void cflush(void);
-void ckoff(Sym*, int32);
Prog* copyp(Prog*);
+vlong cpos(void);
double cputime(void);
void datblk(int32, int32);
void deadcode(void);
void diag(char*, ...);
-void dobss(void);
void dodata(void);
void doelf(void);
-void doinit(void);
void domacho(void);
void doprof1(void);
void doprof2(void);
void dostkoff(void);
-void dynreloc(Sym*, uint32, int);
vlong entryvalue(void);
-void export(void);
void follow(void);
void gethunk(void);
void gotypestrings(void);
-void import(void);
void listinit(void);
Sym* lookup(char*, int);
void lputb(int32);
void lputl(int32);
+void instinit(void);
void main(int, char*[]);
-void mkfwd(void);
void* mysbrk(uint32);
-Prog* newdata(Sym*, int, int, int);
Prog* newtext(Prog*, Sym*);
void nopout(Prog*);
int opsize(Prog*);
@@ -429,19 +424,14 @@ void patch(void);
Prog* prg(void);
void parsetextconst(vlong);
int relinv(int);
-int32 reuse(Prog*, Sym*);
vlong rnd(vlong, vlong);
void span(void);
-void strnput(char*, int);
void undef(void);
-vlong vaddr(Adr*);
vlong symaddr(Sym*);
void vputl(uint64);
void wputb(uint16);
void wputl(uint16);
void xdefine(char*, int, vlong);
-void xfol(Prog*);
-void zaddr(Biobuf*, Adr*, Sym*[]);
void machseg(char*, vlong, vlong, vlong, vlong, uint32, uint32, uint32, uint32);
void machsymseg(uint32, uint32);
@@ -460,3 +450,9 @@ uint32 machheadr(void);
#pragma varargck type "R" int
#pragma varargck type "A" int
#pragma varargck argpos diag 1
+
+/* Used by ../ld/dwarf.c */
+enum
+{
+ DWARFREGSP = 7
+};
diff --git a/src/cmd/6l/list.c b/src/cmd/6l/list.c
index 195e11d1d..f39efa2e8 100644
--- a/src/cmd/6l/list.c
+++ b/src/cmd/6l/list.c
@@ -28,6 +28,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+// Printing.
+
#include "l.h"
#include "../ld/lib.h"
@@ -42,46 +44,36 @@ listinit(void)
fmtinstall('D', Dconv);
fmtinstall('S', Sconv);
fmtinstall('P', Pconv);
+ fmtinstall('I', Iconv);
}
int
Pconv(Fmt *fp)
{
- char str[STRINGSZ], str1[STRINGSZ];
Prog *p;
p = va_arg(fp->args, Prog*);
- if(p == P)
- return fmtstrcpy(fp, "<P>");
-
bigP = p;
-
- snprint(str1, sizeof(str1), "(%ld)", p->line);
switch(p->as) {
case ATEXT:
if(p->from.scale) {
- snprint(str, sizeof(str), "%-7s %-7A %D,%d,%lD",
- str1, p->as, &p->from, p->from.scale, &p->to);
+ fmtprint(fp, "(%d) %A %D,%d,%D",
+ p->line, p->as, &p->from, p->from.scale, &p->to);
break;
}
- snprint(str, sizeof(str), "%-7s %-7A %D,%lD",
- str1, p->as, &p->from, &p->to);
- break;
-
default:
- snprint(str, sizeof(str), "%-7s %-7A %D,%D",
- str1, p->as, &p->from, &p->to);
+ fmtprint(fp, "(%d) %A %D,%D",
+ p->line, p->as, &p->from, &p->to);
break;
-
case ADATA:
- case AINIT:
- case ADYNT:
- snprint(str, sizeof(str), "%-7s %-7A %D/%d,%D",
- str1, p->as, &p->from, p->from.scale, &p->to);
+ case AINIT_:
+ case ADYNT_:
+ fmtprint(fp, "(%d) %A %D/%d,%D",
+ p->line, p->as, &p->from, p->from.scale, &p->to);
break;
}
bigP = P;
- return fmtstrcpy(fp, str);
+ return 0;
}
int
@@ -187,7 +179,7 @@ Dconv(Fmt *fp)
break;
case D_FCONST:
- snprint(str, sizeof(str), "$(%.8lux,%.8lux)", a->ieee.h, a->ieee.l);
+ snprint(str, sizeof(str), "$(%.8ux,%.8ux)", a->ieee.h, a->ieee.l);
break;
case D_SCONST:
@@ -402,19 +394,48 @@ Sconv(Fmt *fp)
return fmtstrcpy(fp, str);
}
+int
+Iconv(Fmt *fp)
+{
+ int i, n;
+ uchar *p;
+ char *s;
+ Fmt fmt;
+
+ n = fp->prec;
+ fp->prec = 0;
+ if(!(fp->flags&FmtPrec) || n < 0)
+ return fmtstrcpy(fp, "%I");
+ fp->flags &= ~FmtPrec;
+ p = va_arg(fp->args, uchar*);
+
+ // format into temporary buffer and
+ // call fmtstrcpy to handle padding.
+ fmtstrinit(&fmt);
+ for(i=0; i<n; i++)
+ fmtprint(&fmt, "%.2ux", *p++);
+ s = fmtstrflush(&fmt);
+ fmtstrcpy(fp, s);
+ free(s);
+ return 0;
+}
+
void
diag(char *fmt, ...)
{
- char buf[STRINGSZ], *tn;
+ char buf[STRINGSZ], *tn, *sep;
va_list arg;
- tn = "??none??";
- if(curtext != P && curtext->from.sym != S)
- tn = curtext->from.sym->name;
+ tn = "";
+ sep = "";
+ if(cursym != S) {
+ tn = cursym->name;
+ sep = ": ";
+ }
va_start(arg, fmt);
vseprint(buf, buf+sizeof(buf), fmt, arg);
va_end(arg);
- print("%s: %s\n", tn, buf);
+ print("%s%s%s\n", tn, sep, buf);
nerrors++;
if(nerrors > 20) {
diff --git a/src/cmd/6l/obj.c b/src/cmd/6l/obj.c
index 5a4b6a3fc..96d78c3b9 100644
--- a/src/cmd/6l/obj.c
+++ b/src/cmd/6l/obj.c
@@ -28,11 +28,14 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+// Reading object files.
+
#define EXTERN
#include "l.h"
#include "../ld/lib.h"
#include "../ld/elf.h"
#include "../ld/macho.h"
+#include "../ld/dwarf.h"
#include <ar.h>
char *noname = "<none>";
@@ -51,28 +54,6 @@ char* paramspace = "FP";
* options used: 189BLQSWabcjlnpsvz
*/
-static int
-isobjfile(char *f)
-{
- int n, v;
- Biobuf *b;
- char buf1[5], buf2[SARMAG];
-
- b = Bopen(f, OREAD);
- if(b == nil)
- return 0;
- n = Bread(b, buf1, 5);
- if(n == 5 && (buf1[2] == 1 && buf1[3] == '<' || buf1[3] == 1 && buf1[4] == '<'))
- v = 1; /* good enough for our purposes */
- else {
- Bseek(b, 0, 0);
- n = Bread(b, buf2, SARMAG);
- v = n == SARMAG && strncmp(buf2, ARMAG, SARMAG) == 0;
- }
- Bterm(b);
- return v;
-}
-
void
usage(void)
{
@@ -83,7 +64,7 @@ usage(void)
void
main(int argc, char *argv[])
{
- int i, c;
+ int c;
Binit(&bso, 1, OWRITE);
cout = -1;
@@ -187,6 +168,11 @@ main(int argc, char *argv[])
INITRND = 4096;
break;
case 6: /* apple MACH */
+ /*
+ * OS X system constant - offset from 0(GS) to our TLS.
+ * Explained in ../../libcgo/darwin_amd64.c.
+ */
+ tlsoffset = 0x8a0;
machoinit();
HEADR = MACHORESERVE;
if(INITRND == -1)
@@ -198,6 +184,13 @@ main(int argc, char *argv[])
break;
case 7: /* elf64 executable */
case 9: /* freebsd */
+ /*
+ * 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.
+ */
+ tlsoffset = -16;
elfinit();
HEADR = ELFRESERVE;
if(INITTEXT == -1)
@@ -209,117 +202,13 @@ main(int argc, char *argv[])
break;
}
if(INITDAT != 0 && INITRND != 0)
- print("warning: -D0x%llux is ignored because of -R0x%lux\n",
+ print("warning: -D0x%llux is ignored because of -R0x%ux\n",
INITDAT, INITRND);
if(debug['v'])
- Bprint(&bso, "HEADER = -H%ld -T0x%llux -D0x%llux -R0x%lux\n",
+ Bprint(&bso, "HEADER = -H%d -T0x%llux -D0x%llux -R0x%ux\n",
HEADTYPE, INITTEXT, INITDAT, INITRND);
Bflush(&bso);
- for(i=1; optab[i].as; i++) {
- c = optab[i].as;
- if(opindex[c] != nil) {
- diag("phase error in optab: %d (%A)", i, c);
- errorexit();
- }
- opindex[c] = &optab[i];
- }
-
- for(i=0; i<Ymax; i++)
- ycover[i*Ymax + i] = 1;
-
- ycover[Yi0*Ymax + Yi8] = 1;
- ycover[Yi1*Ymax + Yi8] = 1;
-
- ycover[Yi0*Ymax + Ys32] = 1;
- ycover[Yi1*Ymax + Ys32] = 1;
- ycover[Yi8*Ymax + Ys32] = 1;
-
- ycover[Yi0*Ymax + Yi32] = 1;
- ycover[Yi1*Ymax + Yi32] = 1;
- ycover[Yi8*Ymax + Yi32] = 1;
- ycover[Ys32*Ymax + Yi32] = 1;
-
- ycover[Yi0*Ymax + Yi64] = 1;
- ycover[Yi1*Ymax + Yi64] = 1;
- ycover[Yi8*Ymax + Yi64] = 1;
- ycover[Ys32*Ymax + Yi64] = 1;
- ycover[Yi32*Ymax + Yi64] = 1;
-
- ycover[Yal*Ymax + Yrb] = 1;
- ycover[Ycl*Ymax + Yrb] = 1;
- ycover[Yax*Ymax + Yrb] = 1;
- ycover[Ycx*Ymax + Yrb] = 1;
- ycover[Yrx*Ymax + Yrb] = 1;
- ycover[Yrl*Ymax + Yrb] = 1;
-
- ycover[Ycl*Ymax + Ycx] = 1;
-
- ycover[Yax*Ymax + Yrx] = 1;
- ycover[Ycx*Ymax + Yrx] = 1;
-
- ycover[Yax*Ymax + Yrl] = 1;
- ycover[Ycx*Ymax + Yrl] = 1;
- ycover[Yrx*Ymax + Yrl] = 1;
-
- ycover[Yf0*Ymax + Yrf] = 1;
-
- ycover[Yal*Ymax + Ymb] = 1;
- ycover[Ycl*Ymax + Ymb] = 1;
- ycover[Yax*Ymax + Ymb] = 1;
- ycover[Ycx*Ymax + Ymb] = 1;
- ycover[Yrx*Ymax + Ymb] = 1;
- ycover[Yrb*Ymax + Ymb] = 1;
- ycover[Yrl*Ymax + Ymb] = 1;
- ycover[Ym*Ymax + Ymb] = 1;
-
- ycover[Yax*Ymax + Yml] = 1;
- ycover[Ycx*Ymax + Yml] = 1;
- ycover[Yrx*Ymax + Yml] = 1;
- ycover[Yrl*Ymax + Yml] = 1;
- ycover[Ym*Ymax + Yml] = 1;
-
- ycover[Yax*Ymax + Ymm] = 1;
- ycover[Ycx*Ymax + Ymm] = 1;
- ycover[Yrx*Ymax + Ymm] = 1;
- ycover[Yrl*Ymax + Ymm] = 1;
- 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;
-
- for(i=0; i<D_NONE; i++) {
- reg[i] = -1;
- if(i >= D_AL && i <= D_R15B) {
- reg[i] = (i-D_AL) & 7;
- if(i >= D_SPB && i <= D_DIB)
- regrex[i] = 0x40;
- if(i >= D_R8B && i <= D_R15B)
- regrex[i] = Rxr | Rxx | Rxb;
- }
- if(i >= D_AH && i<= D_BH)
- reg[i] = 4 + ((i-D_AH) & 7);
- if(i >= D_AX && i <= D_R15) {
- reg[i] = (i-D_AX) & 7;
- if(i >= D_R8)
- regrex[i] = Rxr | Rxx | Rxb;
- }
- if(i >= D_F0 && i <= D_F0+7)
- reg[i] = (i-D_F0) & 7;
- if(i >= D_M0 && i <= D_M0+7)
- reg[i] = (i-D_M0) & 7;
- if(i >= D_X0 && i <= D_X0+15) {
- reg[i] = (i-D_X0) & 7;
- if(i >= D_X0+8)
- regrex[i] = Rxr | Rxx | Rxb;
- }
- if(i >= D_CR+8 && i <= D_CR+15)
- regrex[i] = Rxr;
- }
+ instinit();
zprg.link = P;
zprg.pcond = P;
@@ -334,50 +223,20 @@ main(int argc, char *argv[])
pcstr = "%.6llux ";
nuxiinit();
histgen = 0;
- textp = P;
- datap = P;
- edatap = P;
pc = 0;
dtype = 4;
version = 0;
cbp = buf.cbuf;
cbc = sizeof(buf.cbuf);
- firstp = prg();
- lastp = firstp;
addlibpath("command line", "command line", argv[0], "main");
loadlib();
-
deadcode();
-
- firstp = firstp->link;
- if(firstp == P)
- errorexit();
-
- if(doexp || dlm){
- EXPTAB = "_exporttab";
- zerosig(EXPTAB);
- zerosig("etext");
- zerosig("edata");
- zerosig("end");
- if(dlm){
- import();
- HEADTYPE = 2;
- INITTEXT = 0;
- INITDAT = 0;
- INITRND = 8;
- INITENTRY = EXPTAB;
- }
- export();
- }
-
patch();
follow();
doelf();
if(HEADTYPE == 6)
domacho();
- dodata();
- dobss();
dostkoff();
paramspace = "SP"; /* (FP) now (SP) on output */
if(debug['p'])
@@ -386,12 +245,18 @@ main(int argc, char *argv[])
else
doprof2();
span();
- doinit();
+ addexport();
+ textaddress();
+ pclntab();
+ symtab();
+ dodata();
+ address();
+ reloc();
asmb();
undef();
if(debug['v']) {
Bprint(&bso, "%5.2f cpu time\n", cputime());
- Bprint(&bso, "%ld symbols\n", nsymbol);
+ Bprint(&bso, "%d symbols\n", nsymbol);
Bprint(&bso, "%d sizeof adr\n", sizeof(Adr));
Bprint(&bso, "%d sizeof prog\n", sizeof(Prog));
}
@@ -400,8 +265,19 @@ main(int argc, char *argv[])
errorexit();
}
-void
-zaddr(Biobuf *f, Adr *a, Sym *h[])
+static Sym*
+zsym(char *pn, Biobuf *f, Sym *h[])
+{
+ int o;
+
+ o = Bgetc(f);
+ if(o < 0 || o >= NSYM || h[o] == nil)
+ mangle(pn);
+ return h[o];
+}
+
+static void
+zaddr(char *pn, Biobuf *f, Adr *a, Sym *h[])
{
int t;
int32 l;
@@ -425,7 +301,7 @@ zaddr(Biobuf *f, Adr *a, Sym *h[])
}
a->sym = S;
if(t & T_SYM)
- a->sym = h[Bgetc(f)];
+ a->sym = zsym(pn, f, h);
a->type = D_NONE;
if(t & T_FCONST) {
a->ieee.l = Bget4(f);
@@ -438,16 +314,17 @@ zaddr(Biobuf *f, Adr *a, Sym *h[])
}
if(t & T_TYPE)
a->type = Bgetc(f);
+ if(a->type < 0 || a->type >= D_SIZE)
+ mangle(pn);
adrgotype = S;
if(t & T_GOTYPE)
- adrgotype = h[Bgetc(f)];
+ adrgotype = zsym(pn, f, h);
s = a->sym;
- if(s == S)
- return;
-
t = a->type;
+ if(t == D_INDIR+D_GS)
+ a->offset += tlsoffset;
if(t != D_AUTO && t != D_PARAM) {
- if(adrgotype)
+ if(s && adrgotype)
s->gotype = adrgotype;
return;
}
@@ -484,7 +361,7 @@ void
ldobj1(Biobuf *f, char *pkg, int64 len, char *pn)
{
vlong ipc;
- Prog *p, *t;
+ Prog *p;
int v, o, r, skip, mode;
Sym *h[NSYM], *s, *di;
uint32 sig;
@@ -492,7 +369,9 @@ ldobj1(Biobuf *f, char *pkg, int64 len, char *pn)
int ntext;
vlong eof;
char src[1024];
+ Prog *lastp;
+ lastp = nil;
ntext = 0;
eof = Boffset(f) + len;
di = S;
@@ -549,7 +428,7 @@ loop:
if(sig != 0){
if(s->sig != 0 && s->sig != sig)
diag("incompatible type signatures"
- "%lux(%s) and %lux(%s) for %s",
+ "%ux(%s) and %ux(%s) for %s",
s->sig, s->file, sig, pn, s->name);
s->sig = sig;
s->file = pn;
@@ -557,6 +436,8 @@ loop:
if(debug['W'])
print(" ANAME %s\n", s->name);
+ if(o < 0 || o >= nelem(h))
+ mangle(pn);
h[o] = s;
if((v == D_EXTERN || v == D_STATIC) && s->type == 0)
s->type = SXREF;
@@ -571,6 +452,7 @@ loop:
histfrogp++;
} else
collapsefrog(s);
+ dwarfaddfrag(s->value, s->name);
}
goto loop;
}
@@ -582,9 +464,18 @@ loop:
p->mode = mode;
p->ft = 0;
p->tt = 0;
- zaddr(f, &p->from, h);
+ zaddr(pn, f, &p->from, h);
fromgotype = adrgotype;
- zaddr(f, &p->to, h);
+ zaddr(pn, f, &p->to, h);
+
+ switch(p->as) {
+ case ATEXT:
+ case ADATA:
+ case AGLOBL:
+ if(p->from.sym == S)
+ mangle(pn);
+ break;
+ }
if(debug['W'])
print("%P\n", p);
@@ -606,10 +497,10 @@ loop:
case AEND:
histtoauto();
- if(curtext != P)
- curtext->to.autom = curauto;
+ if(cursym != nil && cursym->text)
+ cursym->autom = curauto;
curauto = 0;
- curtext = P;
+ cursym = nil;
if(Boffset(f) == eof)
return;
goto newloop;
@@ -618,89 +509,41 @@ loop:
s = p->from.sym;
if(s->type == 0 || s->type == SXREF) {
s->type = SBSS;
- s->value = 0;
+ s->size = 0;
}
- if(s->type != SBSS) {
+ if(s->type != SBSS && !s->dupok) {
diag("%s: redefinition: %s in %s",
pn, s->name, TNAME);
s->type = SBSS;
- s->value = 0;
+ s->size = 0;
}
- if(p->to.offset > s->value)
- s->value = p->to.offset;
+ if(p->to.offset > s->size)
+ s->size = p->to.offset;
if(p->from.scale & DUPOK)
s->dupok = 1;
+ if(p->from.scale & RODATA)
+ s->type = SRODATA;
goto loop;
- case ADYNT:
- if(p->to.sym == S) {
- diag("DYNT without a sym\n%P", p);
- break;
- }
- di = p->to.sym;
- p->from.scale = 4;
- if(di->type == SXREF) {
- if(debug['z'])
- Bprint(&bso, "%P set to %d\n", p, dtype);
- di->type = SCONST;
- di->value = dtype;
- dtype += 4;
- }
- if(p->from.sym == S)
- break;
-
- p->from.offset = di->value;
- p->from.sym->type = SDATA;
- if(curtext == P) {
- diag("DYNT not in text: %P", p);
- break;
- }
- p->to.sym = curtext->from.sym;
- p->to.type = D_ADDR;
- p->to.index = D_EXTERN;
- goto data;
-
- case AINIT:
- if(p->from.sym == S) {
- diag("INIT without a sym\n%P", p);
- break;
- }
- if(di == S) {
- diag("INIT without previous DYNT\n%P", p);
- break;
- }
- p->from.offset = di->value;
- p->from.sym->type = SDATA;
- goto data;
-
case ADATA:
- data:
// Assume that AGLOBL comes after ADATA.
// If we've seen an AGLOBL that said this sym was DUPOK,
// ignore any more ADATA we see, which must be
// redefinitions.
s = p->from.sym;
- if(s != S && s->dupok) {
+ if(s->dupok) {
// if(debug['v'])
// Bprint(&bso, "skipping %s in %s: dupok\n", s->name, pn);
goto loop;
}
- if(s != S) {
- p->dlink = s->data;
- s->data = p;
- if(s->file == nil)
- s->file = pn;
- else if(s->file != pn) {
- diag("multiple initialization for %s: in both %s and %s", s->name, s->file, pn);
- errorexit();
- }
+ if(s->file == nil)
+ s->file = pn;
+ else if(s->file != pn) {
+ diag("multiple initialization for %s: in both %s and %s", s->name, s->file, pn);
+ errorexit();
}
- if(edatap == P)
- datap = p;
- else
- edatap->link = p;
- edatap = p;
- p->link = P;
+ savedata(s, p);
+ unmal(p, sizeof *p);
goto loop;
case AGOK:
@@ -710,23 +553,29 @@ loop:
case ATEXT:
s = p->from.sym;
+ if(s->text != nil) {
+ diag("%s: %s: redefinition", pn, s->name);
+ return;
+ }
if(ntext++ == 0 && s->type != 0 && s->type != SXREF) {
/* redefinition, so file has probably been seen before */
if(debug['v'])
Bprint(&bso, "skipping: %s: redefinition: %s", pn, s->name);
return;
}
- if(curtext != P) {
+ if(cursym != nil && cursym->text) {
histtoauto();
- curtext->to.autom = curauto;
+ cursym->autom = curauto;
curauto = 0;
}
skip = 0;
- curtext = p;
- if(s == S) {
- diag("%s: no TEXT symbol: %P", pn, p);
- errorexit();
- }
+ if(etextp)
+ etextp->next = s;
+ else
+ textp = s;
+ etextp = s;
+ s->text = p;
+ cursym = s;
if(s->type != 0 && s->type != SXREF) {
if(p->from.scale & DUPOK) {
skip = 1;
@@ -739,7 +588,10 @@ loop:
diag("%s: type mismatch for %s", pn, s->name);
s->gotype = fromgotype;
}
- newtext(p, s);
+ s->type = STEXT;
+ s->value = pc;
+ lastp = p;
+ p->pc = pc++;
goto loop;
case AMODE:
@@ -772,24 +624,12 @@ loop:
goto casdef;
if(p->from.type == D_FCONST) {
/* size sb 9 max */
- sprint(literal, "$%lux", ieeedtof(&p->from.ieee));
+ sprint(literal, "$%ux", ieeedtof(&p->from.ieee));
s = lookup(literal, 0);
if(s->type == 0) {
- s->type = SBSS;
- s->value = 4;
- t = prg();
- t->as = ADATA;
- t->line = p->line;
- t->from.type = D_EXTERN;
- t->from.sym = s;
- t->from.scale = 4;
- t->to = p->from;
- if(edatap == P)
- datap = t;
- else
- edatap->link = t;
- edatap = t;
- t->link = P;
+ s->type = SDATA;
+ adduint32(s, ieeedtof(&p->from.ieee));
+ s->reachable = 0;
}
p->from.type = D_EXTERN;
p->from.sym = s;
@@ -817,25 +657,14 @@ loop:
goto casdef;
if(p->from.type == D_FCONST) {
/* size sb 18 max */
- sprint(literal, "$%lux.%lux",
+ sprint(literal, "$%ux.%ux",
p->from.ieee.l, p->from.ieee.h);
s = lookup(literal, 0);
if(s->type == 0) {
- s->type = SBSS;
- s->value = 8;
- t = prg();
- t->as = ADATA;
- t->line = p->line;
- t->from.type = D_EXTERN;
- t->from.sym = s;
- t->from.scale = 8;
- t->to = p->from;
- if(edatap == P)
- datap = t;
- else
- edatap->link = t;
- edatap = t;
- t->link = P;
+ s->type = SDATA;
+ adduint32(s, p->from.ieee.l);
+ adduint32(s, p->from.ieee.h);
+ s->reachable = 0;
}
p->from.type = D_EXTERN;
p->from.sym = s;
@@ -847,13 +676,18 @@ loop:
default:
if(skip)
nopout(p);
+ p->pc = pc;
+ pc++;
if(p->to.type == D_BRANCH)
p->to.offset += ipc;
+ if(lastp == nil) {
+ if(p->as != ANOP)
+ diag("unexpected instruction: %P", p);
+ goto loop;
+ }
lastp->link = p;
lastp = p;
- p->pc = pc;
- pc++;
goto loop;
}
goto loop;
@@ -895,154 +729,3 @@ appendp(Prog *q)
p->mode = q->mode;
return p;
}
-
-void
-doprof1(void)
-{
- Sym *s;
- int32 n;
- Prog *p, *q;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f profile 1\n", cputime());
- Bflush(&bso);
- s = lookup("__mcount", 0);
- n = 1;
- for(p = firstp->link; p != P; p = p->link) {
- if(p->as == ATEXT) {
- q = prg();
- q->line = p->line;
- q->link = datap;
- datap = q;
- q->as = ADATA;
- q->from.type = D_EXTERN;
- q->from.offset = n*4;
- q->from.sym = s;
- q->from.scale = 4;
- q->to = p->from;
- q->to.type = D_CONST;
-
- q = prg();
- q->line = p->line;
- q->pc = p->pc;
- q->link = p->link;
- p->link = q;
- p = q;
- p->as = AADDL;
- p->from.type = D_CONST;
- p->from.offset = 1;
- p->to.type = D_EXTERN;
- p->to.sym = s;
- p->to.offset = n*4 + 4;
-
- n += 2;
- continue;
- }
- }
- q = prg();
- q->line = 0;
- q->link = datap;
- datap = q;
-
- q->as = ADATA;
- q->from.type = D_EXTERN;
- q->from.sym = s;
- q->from.scale = 4;
- q->to.type = D_CONST;
- q->to.offset = n;
-
- s->type = SBSS;
- s->value = n*4;
-}
-
-void
-doprof2(void)
-{
- Sym *s2, *s4;
- Prog *p, *q, *ps2, *ps4;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f profile 2\n", cputime());
- Bflush(&bso);
-
- s2 = lookup("_profin", 0);
- s4 = lookup("_profout", 0);
- if(s2->type != STEXT || s4->type != STEXT) {
- diag("_profin/_profout not defined");
- return;
- }
-
- ps2 = P;
- ps4 = P;
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT) {
- if(p->from.sym == s2) {
- p->from.scale = 1;
- ps2 = p;
- }
- if(p->from.sym == s4) {
- p->from.scale = 1;
- ps4 = p;
- }
- }
- }
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT) {
- curtext = p;
-
- if(p->from.scale & NOPROF) { /* dont profile */
- for(;;) {
- q = p->link;
- if(q == P)
- break;
- if(q->as == ATEXT)
- break;
- p = q;
- }
- continue;
- }
-
- /*
- * JMPL profin
- */
- q = prg();
- q->line = p->line;
- q->pc = p->pc;
- q->link = p->link;
- p->link = q;
- p = q;
- p->as = ACALL;
- p->to.type = D_BRANCH;
- p->pcond = ps2;
- p->to.sym = s2;
-
- continue;
- }
- if(p->as == ARET) {
- /*
- * RET
- */
- q = prg();
- q->as = ARET;
- q->from = p->from;
- q->to = p->to;
- q->link = p->link;
- p->link = q;
-
- /*
- * JAL profout
- */
- p->as = ACALL;
- p->from = zprg.from;
- p->to = zprg.to;
- p->to.type = D_BRANCH;
- p->pcond = ps4;
- p->to.sym = s4;
-
- p = q;
-
- continue;
- }
- }
-}
-
diff --git a/src/cmd/6l/optab.c b/src/cmd/6l/optab.c
index c729f0e23..6cc50313e 100644
--- a/src/cmd/6l/optab.c
+++ b/src/cmd/6l/optab.c
@@ -783,7 +783,7 @@ Optab optab[] =
{ AMOVBWSX, ymb_rl, Pq, 0xbe },
{ AMOVBWZX, ymb_rl, Pq, 0xb6 },
{ AMOVO, yxmov, Pe, 0x6f,0x7f },
- { AMOVOU, yxmov, Pf2, 0x6f,0x7f },
+ { AMOVOU, yxmov, Pf3, 0x6f,0x7f },
{ AMOVHLPS, yxr, Pm, 0x12 },
{ AMOVHPD, yxmov, Pe, 0x16,0x17 },
{ AMOVHPS, yxmov, Pm, 0x16,0x17 },
@@ -907,9 +907,9 @@ Optab optab[] =
{ APOPQ, ypopl, Py, 0x58,0x8f,(00) },
{ APOPW, ypopl, Pe, 0x58,0x8f,(00) },
{ APOR, ymm, Py, 0xeb,Pe,0xeb },
- { APSADBW, yxm, Pw, Pe,0xf6 },
+ { APSADBW, yxm, Pq, 0xf6 },
{ APSHUFHW, yxshuf, Pf3, 0x70 },
- { APSHUFL, yxm, Pw, Pe,0x70 },
+ { APSHUFL, yxshuf, Pq, 0x70 },
{ APSHUFLW, yxshuf, Pf2, 0x70 },
{ APSHUFW, ymshuf, Pm, 0x70 },
{ APSLLO, ypsdq, Pq, 0x73,(07) },
diff --git a/src/cmd/6l/pass.c b/src/cmd/6l/pass.c
index f86942926..5c4ed00a6 100644
--- a/src/cmd/6l/pass.c
+++ b/src/cmd/6l/pass.c
@@ -28,9 +28,13 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+// Code and data passes.
+
#include "l.h"
#include "../ld/lib.h"
+static void xfol(Prog*, Prog**);
+
// see ../../runtime/proc.c:/StackGuard
enum
{
@@ -38,157 +42,6 @@ enum
StackBig = 4096,
};
-void
-dodata(void)
-{
- int i;
- Sym *s;
- Prog *p;
- int32 t, u;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f dodata\n", cputime());
- Bflush(&bso);
- for(p = datap; p != P; p = p->link) {
- curtext = p; // for diag messages
- s = p->from.sym;
- if(p->as == ADYNT || p->as == AINIT)
- s->value = dtype;
- if(s->type == SBSS)
- s->type = SDATA;
- if(s->type != SDATA && s->type != SELFDATA)
- diag("initialize non-data (%d): %s\n%P",
- s->type, s->name, p);
- t = p->from.offset + p->width;
- if(t > s->value)
- diag("initialize bounds (%lld): %s\n%P",
- s->value, s->name, p);
- }
-
- /* allocate elf guys - must be segregated from real data */
- datsize = 0;
- for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->link) {
- if(!s->reachable)
- continue;
- if(s->type != SELFDATA)
- continue;
- t = rnd(s->value, 8);
- s->size = t;
- s->value = datsize;
- datsize += t;
- }
- elfdatsize = datsize;
-
- /* allocate small guys */
- for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->link) {
- if(!s->reachable)
- continue;
- if(s->type != SDATA)
- if(s->type != SBSS)
- continue;
- t = s->value;
- if(t == 0 && s->name[0] != '.') {
- diag("%s: no size", s->name);
- t = 1;
- }
- t = rnd(t, 4);
- s->value = t;
- if(t > MINSIZ)
- continue;
- if(t >= 8)
- datsize = rnd(datsize, 8);
- s->size = t;
- s->value = datsize;
- datsize += t;
- s->type = SDATA1;
- }
-
- /* allocate the rest of the data */
- for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->link) {
- if(!s->reachable)
- continue;
- if(s->type != SDATA) {
- if(s->type == SDATA1)
- s->type = SDATA;
- continue;
- }
- t = s->value;
- if(t >= 8)
- datsize = rnd(datsize, 8);
- s->size = t;
- s->value = datsize;
- datsize += t;
- }
- if(datsize)
- datsize = rnd(datsize, 8);
-
- if(debug['j']) {
- /*
- * pad data with bss that fits up to next
- * 8k boundary, then push data to 8k
- */
- u = rnd(datsize, 8192);
- u -= datsize;
- for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->link) {
- if(!s->reachable)
- continue;
- if(s->type != SBSS)
- continue;
- t = s->value;
- if(t > u)
- continue;
- u -= t;
- s->size = t;
- s->value = datsize;
- s->type = SDATA;
- datsize += t;
- }
- datsize += u;
- }
-}
-
-void
-dobss(void)
-{
- int i;
- Sym *s;
- int32 t;
-
- if(dynptrsize > 0) {
- /* dynamic pointer section between data and bss */
- datsize = rnd(datsize, 8);
- }
-
- /* now the bss */
- bsssize = 0;
- for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->link) {
- if(!s->reachable)
- continue;
- if(s->type != SBSS)
- continue;
- t = s->value;
- s->size = t;
- if(t >= 8)
- bsssize = rnd(bsssize, 8);
- s->value = bsssize + dynptrsize + datsize;
- bsssize += t;
- }
-
- xdefine("data", SBSS, 0);
- xdefine("edata", SBSS, datsize);
- xdefine("end", SBSS, dynptrsize + bsssize + datsize);
-
- if(debug['s'])
- xdefine("symdat", SFIXED, 0);
- else
- xdefine("symdat", SFIXED, SYMDATVA);
-}
-
Prog*
brchain(Prog *p)
{
@@ -205,19 +58,61 @@ brchain(Prog *p)
void
follow(void)
{
+ Prog *firstp, *lastp;
if(debug['v'])
Bprint(&bso, "%5.2f follow\n", cputime());
Bflush(&bso);
- firstp = prg();
- lastp = firstp;
- xfol(textp);
- lastp->link = P;
- firstp = firstp->link;
+
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ firstp = prg();
+ lastp = firstp;
+ xfol(cursym->text, &lastp);
+ lastp->link = nil;
+ cursym->text = firstp->link;
+ }
}
-void
-xfol(Prog *p)
+static int
+nofollow(int a)
+{
+ switch(a) {
+ case AJMP:
+ case ARET:
+ case AIRETL:
+ case AIRETQ:
+ case AIRETW:
+ case ARETFL:
+ case ARETFQ:
+ case ARETFW:
+ return 1;
+ }
+ return 0;
+}
+
+static int
+pushpop(int a)
+{
+ switch(a) {
+ case APUSHL:
+ case APUSHFL:
+ case APUSHQ:
+ case APUSHFQ:
+ case APUSHW:
+ case APUSHFW:
+ case APOPL:
+ case APOPFL:
+ case APOPQ:
+ case APOPFQ:
+ case APOPW:
+ case APOPFW:
+ return 1;
+ }
+ return 0;
+}
+
+static void
+xfol(Prog *p, Prog **last)
{
Prog *q;
int i;
@@ -226,55 +121,31 @@ xfol(Prog *p)
loop:
if(p == P)
return;
- if(p->as == ATEXT)
- curtext = p;
- if(!curtext->from.sym->reachable) {
- p = p->pcond;
- goto loop;
- }
if(p->as == AJMP)
if((q = p->pcond) != P && q->as != ATEXT) {
+ /* mark instruction as done and continue layout at target of jump */
p->mark = 1;
p = q;
if(p->mark == 0)
goto loop;
}
if(p->mark) {
- /* copy up to 4 instructions to avoid branch */
+ /*
+ * p goes here, but already used it elsewhere.
+ * copy up to 4 instructions or else branch to other copy.
+ */
for(i=0,q=p; i<4; i++,q=q->link) {
if(q == P)
break;
- if(q == lastp)
+ if(q == *last)
break;
a = q->as;
if(a == ANOP) {
i--;
continue;
}
- switch(a) {
- case AJMP:
- case ARET:
- case AIRETL:
- case AIRETQ:
- case AIRETW:
- case ARETFL:
- case ARETFQ:
- case ARETFW:
-
- case APUSHL:
- case APUSHFL:
- case APUSHQ:
- case APUSHFQ:
- case APUSHW:
- case APUSHFW:
- case APOPL:
- case APOPFL:
- case APOPQ:
- case APOPFQ:
- case APOPW:
- case APOPFW:
- goto brk;
- }
+ if(nofollow(a) || pushpop(a))
+ break; // NOTE(rsc): arm does goto copy
if(q->pcond == P || q->pcond->mark)
continue;
if(a == ACALL || a == ALOOP)
@@ -287,8 +158,8 @@ loop:
q = copyp(p);
p = p->link;
q->mark = 1;
- lastp->link = q;
- lastp = q;
+ (*last)->link = q;
+ *last = q;
if(q->as != a || q->pcond == P || q->pcond->mark)
continue;
@@ -296,14 +167,13 @@ loop:
p = q->pcond;
q->pcond = q->link;
q->link = p;
- xfol(q->link);
+ xfol(q->link, last);
p = q->link;
if(p->mark)
return;
goto loop;
}
} /* */
- brk:;
q = prg();
q->as = AJMP;
q->line = p->line;
@@ -312,15 +182,22 @@ loop:
q->pcond = p;
p = q;
}
+
+ /* emit p */
p->mark = 1;
- lastp->link = p;
- lastp = p;
+ (*last)->link = p;
+ *last = p;
a = p->as;
- if(a == AJMP || a == ARET || a == AIRETL || a == AIRETQ || a == AIRETW ||
- a == ARETFL || a == ARETFQ || a == ARETFW)
+
+ /* continue loop with what comes after p */
+ if(nofollow(a))
return;
- if(p->pcond != P)
- if(a != ACALL) {
+ if(p->pcond != P && a != ACALL) {
+ /*
+ * some kind of conditional branch.
+ * recurse to follow one path.
+ * continue loop on the other.
+ */
q = brchain(p->link);
if(q != P && q->mark)
if(a != ALOOP) {
@@ -328,7 +205,7 @@ loop:
p->link = p->pcond;
p->pcond = q;
}
- xfol(p->link);
+ xfol(p->link, last);
q = brchain(p->pcond);
if(q->mark) {
p->pcond = q;
@@ -376,32 +253,11 @@ relinv(int a)
case AJOC: return AJOS;
}
diag("unknown relation: %s in %s", anames[a], TNAME);
+ errorexit();
return a;
}
void
-doinit(void)
-{
- Sym *s;
- Prog *p;
- int x;
-
- for(p = datap; p != P; p = p->link) {
- x = p->to.type;
- if(x != D_EXTERN && x != D_STATIC)
- continue;
- s = p->to.sym;
- if(s->type == 0 || s->type == SXREF)
- diag("undefined %s initializer of %s",
- s->name, p->from.sym->name);
- p->to.offset += s->value;
- p->to.type = D_CONST;
- if(s->type == SDATA || s->type == SBSS)
- p->to.offset += INITDAT;
- }
-}
-
-void
patch(void)
{
int32 c;
@@ -419,58 +275,58 @@ patch(void)
s = lookup("exit", 0);
vexit = s->value;
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT)
- curtext = p;
+ for(cursym = textp; cursym != nil; cursym = cursym->next)
+ for(p = cursym->text; p != P; p = p->link) {
+ if(HEADTYPE == 7 || HEADTYPE == 9) {
+ // ELF uses FS instead of GS.
+ if(p->from.type == D_INDIR+D_GS)
+ p->from.type = D_INDIR+D_FS;
+ if(p->to.type == D_INDIR+D_GS)
+ p->to.type = D_INDIR+D_FS;
+ }
if(p->as == ACALL || (p->as == AJMP && p->to.type != D_BRANCH)) {
s = p->to.sym;
if(s) {
if(debug['c'])
Bprint(&bso, "%s calls %s\n", TNAME, s->name);
- switch(s->type) {
- default:
+ if((s->type&~SSUB) != STEXT) {
/* diag prints TNAME first */
diag("undefined: %s", s->name);
s->type = STEXT;
s->value = vexit;
continue; // avoid more error messages
- case STEXT:
- p->to.offset = s->value;
- break;
- case SUNDEF:
- p->pcond = UP;
- p->to.offset = 0;
- break;
}
+ if(s->text == nil)
+ continue;
p->to.type = D_BRANCH;
+ p->to.offset = s->text->pc;
+ p->pcond = s->text;
+ continue;
}
}
- if(p->to.type != D_BRANCH || p->pcond == UP)
+ if(p->to.type != D_BRANCH)
continue;
c = p->to.offset;
- for(q = firstp; q != P;) {
- if(q->forwd != P)
- if(c >= q->forwd->pc) {
- q = q->forwd;
- continue;
- }
+ for(q = cursym->text; q != P;) {
if(c == q->pc)
break;
- q = q->link;
+ if(q->forwd != P && c >= q->forwd->pc)
+ q = q->forwd;
+ else
+ q = q->link;
}
if(q == P) {
- diag("branch out of range in %s\n%P [%s]",
- TNAME, p, p->to.sym ? p->to.sym->name : "<nil>");
+ diag("branch out of range in %s (%#ux)\n%P [%s]",
+ TNAME, c, p, p->to.sym ? p->to.sym->name : "<nil>");
p->to.type = D_NONE;
}
p->pcond = q;
}
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT)
- curtext = p;
+ for(cursym = textp; cursym != nil; cursym = cursym->next)
+ for(p = cursym->text; p != P; p = p->link) {
p->mark = 0; /* initialization for follow */
- if(p->pcond != P && p->pcond != UP) {
+ if(p->pcond != P) {
p->pcond = brloop(p->pcond);
if(p->pcond != P)
if(p->to.type == D_BRANCH)
@@ -479,40 +335,6 @@ patch(void)
}
}
-#define LOG 5
-void
-mkfwd(void)
-{
- Prog *p;
- int i;
- int32 dwn[LOG], cnt[LOG];
- Prog *lst[LOG];
-
- for(i=0; i<LOG; i++) {
- if(i == 0)
- cnt[i] = 1; else
- cnt[i] = LOG * cnt[i-1];
- dwn[i] = 1;
- lst[i] = P;
- }
- i = 0;
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT)
- curtext = p;
- i--;
- if(i < 0)
- i = LOG-1;
- p->forwd = P;
- dwn[i]--;
- if(dwn[i] <= 0) {
- dwn[i] = cnt[i];
- if(lst[i] != P)
- lst[i]->forwd = p;
- lst[i] = p;
- }
- }
-}
-
Prog*
brloop(Prog *p)
{
@@ -553,378 +375,275 @@ dostkoff(void)
{
Prog *p, *q, *q1;
int32 autoffset, deltasp;
- int a, f, curframe, curbecome, maxbecome, pcsize;
+ int a, pcsize;
uint32 moreconst1, moreconst2, i;
for(i=0; i<nelem(morename); i++) {
symmorestack[i] = lookup(morename[i], 0);
- pmorestack[i] = P;
- }
-
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT) {
- for(i=0; i<nelem(morename); i++) {
- if(p->from.sym == symmorestack[i]) {
- pmorestack[i] = p;
- break;
- }
- }
- }
- }
-
- for(i=0; i<nelem(morename); i++) {
- if(pmorestack[i] == P)
- diag("morestack trampoline not defined");
- }
-
- curframe = 0;
- curbecome = 0;
- maxbecome = 0;
- curtext = 0;
- for(p = firstp; p != P; p = p->link) {
-
- /* find out how much arg space is used in this TEXT */
- if(p->to.type == (D_INDIR+D_SP))
- if(p->to.offset > curframe)
- curframe = p->to.offset;
-
- switch(p->as) {
- case ATEXT:
- if(curtext && curtext->from.sym) {
- curtext->from.sym->frame = curframe;
- curtext->from.sym->become = curbecome;
- if(curbecome > maxbecome)
- maxbecome = curbecome;
- }
- curframe = 0;
- curbecome = 0;
-
- curtext = p;
- break;
-
- case ARET:
- /* special form of RET is BECOME */
- if(p->from.type == D_CONST)
- if(p->from.offset > curbecome)
- curbecome = p->from.offset;
- break;
- }
- }
- if(curtext && curtext->from.sym) {
- curtext->from.sym->frame = curframe;
- curtext->from.sym->become = curbecome;
- if(curbecome > maxbecome)
- maxbecome = curbecome;
- }
-
- if(debug['b'])
- print("max become = %d\n", maxbecome);
- xdefine("ALEFbecome", STEXT, maxbecome);
-
- curtext = 0;
- for(p = firstp; p != P; p = p->link) {
- switch(p->as) {
- case ATEXT:
- curtext = p;
- break;
- case ACALL:
- if(curtext != P && curtext->from.sym != S && curtext->to.offset >= 0) {
- f = maxbecome - curtext->from.sym->frame;
- if(f <= 0)
- break;
- /* calling a become or calling a variable */
- if(p->to.sym == S || p->to.sym->become) {
- curtext->to.offset += f;
- if(debug['b']) {
- curp = p;
- print("%D calling %D increase %d\n",
- &curtext->from, &p->to, f);
- }
- }
- }
- break;
- }
+ if(symmorestack[i]->type != STEXT)
+ diag("morestack trampoline not defined - %s", morename[i]);
+ pmorestack[i] = symmorestack[i]->text;
}
autoffset = 0;
deltasp = 0;
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT) {
- curtext = p;
- parsetextconst(p->to.offset);
- autoffset = textstksiz;
- if(autoffset < 0)
- autoffset = 0;
-
- q = P;
- q1 = P;
- if((p->from.scale & NOSPLIT) && autoffset >= StackSmall)
- diag("nosplit func likely to overflow stack");
-
- if(!(p->from.scale & NOSPLIT)) {
- if(debug['K']) {
- // 6l -K means check not only for stack
- // overflow but stack underflow.
- // On underflow, INT 3 (breakpoint).
- // Underflow itself is rare but this also
- // catches out-of-sync stack guard info
-
- p = appendp(p);
- p->as = ACMPQ;
- p->from.type = D_INDIR+D_R15;
- p->from.offset = 8;
- p->to.type = D_SP;
-
- p = appendp(p);
- p->as = AJHI;
- p->to.type = D_BRANCH;
- p->to.offset = 4;
- q1 = p;
-
- p = appendp(p);
- p->as = AINT;
- p->from.type = D_CONST;
- p->from.offset = 3;
- }
-
- if(autoffset < StackBig) { // do we need to call morestack?
- if(autoffset <= StackSmall) {
- // small stack
- p = appendp(p);
- p->as = ACMPQ;
- p->from.type = D_SP;
- p->to.type = D_INDIR+D_R15;
- if(q1) {
- q1->pcond = p;
- q1 = P;
- }
- } else {
- // large stack
- p = appendp(p);
- p->as = ALEAQ;
- p->from.type = D_INDIR+D_SP;
- p->from.offset = -(autoffset-StackSmall);
- p->to.type = D_AX;
- if(q1) {
- q1->pcond = p;
- q1 = P;
- }
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ if(cursym->text == nil || cursym->text->link == nil)
+ continue;
- p = appendp(p);
- p->as = ACMPQ;
- p->from.type = D_AX;
- p->to.type = D_INDIR+D_R15;
- }
+ p = cursym->text;
+ parsetextconst(p->to.offset);
+ autoffset = textstksiz;
+ if(autoffset < 0)
+ autoffset = 0;
+
+ q = P;
+ q1 = P;
+ if((p->from.scale & NOSPLIT) && autoffset >= StackSmall)
+ diag("nosplit func likely to overflow stack");
+
+ if(!(p->from.scale & NOSPLIT)) {
+ p = appendp(p); // load g into CX
+ p->as = AMOVQ;
+ if(HEADTYPE == 7 || HEADTYPE == 9) // 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(debug['K']) {
+ // 6l -K means check not only for stack
+ // overflow but stack underflow.
+ // On underflow, INT 3 (breakpoint).
+ // Underflow itself is rare but this also
+ // catches out-of-sync stack guard info
- // common
- p = appendp(p);
- p->as = AJHI;
- p->to.type = D_BRANCH;
- p->to.offset = 4;
- q = p;
- }
+ p = appendp(p);
+ p->as = ACMPQ;
+ p->from.type = D_INDIR+D_CX;
+ p->from.offset = 8;
+ p->to.type = D_SP;
- /* 160 comes from 3 calls (3*8) 4 safes (4*8) and 104 guard */
- moreconst1 = 0;
- if(autoffset+160 > 4096)
- moreconst1 = (autoffset+160) & ~7LL;
- moreconst2 = textarg;
+ p = appendp(p);
+ p->as = AJHI;
+ p->to.type = D_BRANCH;
+ p->to.offset = 4;
+ q1 = p;
- // 4 varieties varieties (const1==0 cross const2==0)
- // and 6 subvarieties of (const1==0 and const2!=0)
p = appendp(p);
- if(moreconst1 == 0 && moreconst2 == 0) {
- p->as = ACALL;
- p->to.type = D_BRANCH;
- p->pcond = pmorestack[0];
- p->to.sym = symmorestack[0];
- if(q1) {
- q1->pcond = p;
- q1 = P;
- }
- } else
- if(moreconst1 != 0 && moreconst2 == 0) {
- p->as = AMOVL;
- p->from.type = D_CONST;
- p->from.offset = moreconst1;
- p->to.type = D_AX;
- if(q1) {
- q1->pcond = p;
- q1 = P;
- }
+ p->as = AINT;
+ p->from.type = D_CONST;
+ p->from.offset = 3;
- p = appendp(p);
- p->as = ACALL;
- p->to.type = D_BRANCH;
- p->pcond = pmorestack[1];
- p->to.sym = symmorestack[1];
- } else
- if(moreconst1 == 0 && moreconst2 <= 48 && moreconst2%8 == 0) {
- i = moreconst2/8 + 3;
- p->as = ACALL;
- p->to.type = D_BRANCH;
- p->pcond = pmorestack[i];
- p->to.sym = symmorestack[i];
- if(q1) {
- q1->pcond = p;
- q1 = P;
- }
- } else
- if(moreconst1 == 0 && moreconst2 != 0) {
- p->as = AMOVL;
- p->from.type = D_CONST;
- p->from.offset = moreconst2;
- p->to.type = D_AX;
- if(q1) {
- q1->pcond = p;
- q1 = P;
- }
+ p = appendp(p);
+ p->as = ANOP;
+ q1->pcond = p;
+ q1 = P;
+ }
+ if(autoffset < StackBig) { // do we need to call morestack?
+ if(autoffset <= StackSmall) {
+ // small stack
p = appendp(p);
- p->as = ACALL;
- p->to.type = D_BRANCH;
- p->pcond = pmorestack[2];
- p->to.sym = symmorestack[2];
+ p->as = ACMPQ;
+ p->from.type = D_SP;
+ p->to.type = D_INDIR+D_CX;
} else {
- p->as = AMOVQ;
- p->from.type = D_CONST;
- p->from.offset = (uint64)moreconst2 << 32;
- p->from.offset |= moreconst1;
+ // large stack
+ p = appendp(p);
+ p->as = ALEAQ;
+ p->from.type = D_INDIR+D_SP;
+ p->from.offset = -(autoffset-StackSmall);
p->to.type = D_AX;
- if(q1) {
- q1->pcond = p;
- q1 = P;
- }
p = appendp(p);
- p->as = ACALL;
- p->to.type = D_BRANCH;
- p->pcond = pmorestack[3];
- p->to.sym = symmorestack[3];
+ p->as = ACMPQ;
+ p->from.type = D_AX;
+ p->to.type = D_INDIR+D_CX;
}
- }
-
- if(q != P)
- q->pcond = p->link;
- if(autoffset) {
+ // common
p = appendp(p);
- p->as = AADJSP;
- p->from.type = D_CONST;
- p->from.offset = autoffset;
- if(q != P)
- q->pcond = p;
+ p->as = AJHI;
+ p->to.type = D_BRANCH;
+ p->to.offset = 4;
+ q = p;
}
- deltasp = autoffset;
- if(debug['K'] > 1 && autoffset) {
- // 6l -KK means double-check for stack overflow
- // even after calling morestack and even if the
- // function is marked as nosplit.
- p = appendp(p);
- p->as = AMOVQ;
- p->from.type = D_INDIR+D_R15;
- p->from.offset = 0;
- p->to.type = D_BX;
+ /* 160 comes from 3 calls (3*8) 4 safes (4*8) and 104 guard */
+ moreconst1 = 0;
+ if(autoffset+160+textarg > 4096)
+ moreconst1 = (autoffset+160) & ~7LL;
+ moreconst2 = textarg;
- p = appendp(p);
- p->as = ASUBQ;
+ // 4 varieties varieties (const1==0 cross const2==0)
+ // and 6 subvarieties of (const1==0 and const2!=0)
+ p = appendp(p);
+ if(moreconst1 == 0 && moreconst2 == 0) {
+ p->as = ACALL;
+ p->to.type = D_BRANCH;
+ p->pcond = pmorestack[0];
+ p->to.sym = symmorestack[0];
+ } else
+ if(moreconst1 != 0 && moreconst2 == 0) {
+ p->as = AMOVL;
p->from.type = D_CONST;
- p->from.offset = StackSmall+32;
- p->to.type = D_BX;
-
- p = appendp(p);
- p->as = ACMPQ;
- p->from.type = D_SP;
- p->to.type = D_BX;
+ p->from.offset = moreconst1;
+ p->to.type = D_AX;
p = appendp(p);
- p->as = AJHI;
+ p->as = ACALL;
p->to.type = D_BRANCH;
- q1 = p;
+ p->pcond = pmorestack[1];
+ p->to.sym = symmorestack[1];
+ } else
+ if(moreconst1 == 0 && moreconst2 <= 48 && moreconst2%8 == 0) {
+ i = moreconst2/8 + 3;
+ p->as = ACALL;
+ p->to.type = D_BRANCH;
+ p->pcond = pmorestack[i];
+ p->to.sym = symmorestack[i];
+ } else
+ if(moreconst1 == 0 && moreconst2 != 0) {
+ p->as = AMOVL;
+ p->from.type = D_CONST;
+ p->from.offset = moreconst2;
+ p->to.type = D_AX;
p = appendp(p);
- p->as = AINT;
+ p->as = ACALL;
+ p->to.type = D_BRANCH;
+ p->pcond = pmorestack[2];
+ p->to.sym = symmorestack[2];
+ } else {
+ p->as = AMOVQ;
p->from.type = D_CONST;
- p->from.offset = 3;
+ p->from.offset = (uint64)moreconst2 << 32;
+ p->from.offset |= moreconst1;
+ p->to.type = D_AX;
p = appendp(p);
- p->as = ANOP;
- q1->pcond = p;
- q1 = P;
+ p->as = ACALL;
+ p->to.type = D_BRANCH;
+ p->pcond = pmorestack[3];
+ p->to.sym = symmorestack[3];
}
}
- pcsize = p->mode/8;
- a = p->from.type;
- if(a == D_AUTO)
- p->from.offset += deltasp;
- if(a == D_PARAM)
- p->from.offset += deltasp + pcsize;
- a = p->to.type;
- if(a == D_AUTO)
- p->to.offset += deltasp;
- if(a == D_PARAM)
- p->to.offset += deltasp + pcsize;
- switch(p->as) {
- default:
- continue;
- case APUSHL:
- case APUSHFL:
- deltasp += 4;
- continue;
- case APUSHQ:
- case APUSHFQ:
- deltasp += 8;
- continue;
- case APUSHW:
- case APUSHFW:
- deltasp += 2;
- continue;
- case APOPL:
- case APOPFL:
- deltasp -= 4;
- continue;
- case APOPQ:
- case APOPFQ:
- deltasp -= 8;
- continue;
- case APOPW:
- case APOPFW:
- deltasp -= 2;
- continue;
- case ARET:
- break;
- }
-
- if(autoffset != deltasp)
- diag("unbalanced PUSH/POP");
- if(p->from.type == D_CONST)
- goto become;
+ if(q != P)
+ q->pcond = p->link;
if(autoffset) {
+ p = appendp(p);
p->as = AADJSP;
p->from.type = D_CONST;
- p->from.offset = -autoffset;
+ p->from.offset = autoffset;
+ p->spadj = autoffset;
+ if(q != P)
+ q->pcond = p;
+ }
+ deltasp = autoffset;
+ if(debug['K'] > 1 && autoffset) {
+ // 6l -KK means double-check for stack overflow
+ // even after calling morestack and even if the
+ // function is marked as nosplit.
p = appendp(p);
- p->as = ARET;
- }
- continue;
+ p->as = AMOVQ;
+ p->from.type = D_INDIR+D_CX;
+ p->from.offset = 0;
+ p->to.type = D_BX;
- become:
- q = p;
- p = appendp(p);
- p->as = AJMP;
- p->to = q->to;
- p->pcond = q->pcond;
+ p = appendp(p);
+ p->as = ASUBQ;
+ p->from.type = D_CONST;
+ p->from.offset = StackSmall+32;
+ p->to.type = D_BX;
- q->as = AADJSP;
- q->from = zprg.from;
- q->from.type = D_CONST;
- q->from.offset = -autoffset;
- q->to = zprg.to;
- continue;
+ p = appendp(p);
+ p->as = ACMPQ;
+ p->from.type = D_SP;
+ p->to.type = D_BX;
+
+ p = appendp(p);
+ p->as = AJHI;
+ p->to.type = D_BRANCH;
+ q1 = p;
+
+ p = appendp(p);
+ p->as = AINT;
+ p->from.type = D_CONST;
+ p->from.offset = 3;
+
+ p = appendp(p);
+ p->as = ANOP;
+ q1->pcond = p;
+ q1 = P;
+ }
+
+ for(; p != P; p = p->link) {
+ pcsize = p->mode/8;
+ a = p->from.type;
+ if(a == D_AUTO)
+ p->from.offset += deltasp;
+ if(a == D_PARAM)
+ p->from.offset += deltasp + pcsize;
+ a = p->to.type;
+ if(a == D_AUTO)
+ p->to.offset += deltasp;
+ if(a == D_PARAM)
+ p->to.offset += deltasp + pcsize;
+
+ switch(p->as) {
+ default:
+ continue;
+ case APUSHL:
+ case APUSHFL:
+ deltasp += 4;
+ p->spadj = 4;
+ continue;
+ case APUSHQ:
+ case APUSHFQ:
+ deltasp += 8;
+ p->spadj = 8;
+ continue;
+ case APUSHW:
+ case APUSHFW:
+ deltasp += 2;
+ p->spadj = 2;
+ continue;
+ case APOPL:
+ case APOPFL:
+ deltasp -= 4;
+ p->spadj = -4;
+ continue;
+ case APOPQ:
+ case APOPFQ:
+ deltasp -= 8;
+ p->spadj = -8;
+ continue;
+ case APOPW:
+ case APOPFW:
+ deltasp -= 2;
+ p->spadj = -2;
+ continue;
+ case ARET:
+ break;
+ }
+
+ if(autoffset != deltasp)
+ diag("unbalanced PUSH/POP");
+
+ if(autoffset) {
+ p->as = AADJSP;
+ p->from.type = D_CONST;
+ p->from.offset = -autoffset;
+ p->spadj = -autoffset;
+ p = appendp(p);
+ p->as = ARET;
+ }
+ }
}
}
@@ -975,180 +694,7 @@ undef(void)
Sym *s;
for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->link)
+ for(s = hash[i]; s != S; s = s->hash)
if(s->type == SXREF)
diag("%s: not defined", s->name);
}
-
-void
-import(void)
-{
- int i;
- Sym *s;
-
- for(i = 0; i < NHASH; i++)
- for(s = hash[i]; s != S; s = s->link)
- if(s->sig != 0 && s->type == SXREF && (nimports == 0 || s->subtype == SIMPORT)){
- if(s->value != 0)
- diag("value != 0 on SXREF");
- undefsym(s);
- Bprint(&bso, "IMPORT: %s sig=%lux v=%lld\n", s->name, s->sig, s->value);
- if(debug['S'])
- s->sig = 0;
- }
-}
-
-void
-ckoff(Sym *s, int32 v)
-{
- if(v < 0 || v >= 1<<Roffset)
- diag("relocation offset %ld for %s out of range", v, s->name);
-}
-
-Prog*
-newdata(Sym *s, int o, int w, int t)
-{
- Prog *p;
-
- p = prg();
- if(edatap == P)
- datap = p;
- else
- edatap->link = p;
- edatap = p;
- p->as = ADATA;
- p->width = w;
- p->from.scale = w;
- p->from.type = t;
- p->from.sym = s;
- p->from.offset = o;
- p->to.type = D_CONST;
- p->dlink = s->data;
- s->data = p;
- return p;
-}
-
-Prog*
-newtext(Prog *p, Sym *s)
-{
- if(p == P) {
- p = prg();
- p->as = ATEXT;
- p->from.sym = s;
- }
- s->type = STEXT;
- s->text = p;
- s->value = pc;
- lastp->link = p;
- lastp = p;
- p->pc = pc++;
- if(textp == P)
- textp = p;
- else
- etextp->pcond = p;
- etextp = p;
- return p;
-}
-
-void
-export(void)
-{
- int i, j, n, off, nb, sv, ne;
- Sym *s, *et, *str, **esyms;
- Prog *p;
- char buf[NSNAME], *t;
-
- n = 0;
- for(i = 0; i < NHASH; i++)
- for(s = hash[i]; s != S; s = s->link)
- if(s->sig != 0 && s->type != SXREF &&
- s->type != SUNDEF &&
- (nexports == 0 || s->subtype == SEXPORT))
- n++;
- esyms = mal(n*sizeof(Sym*));
- ne = n;
- n = 0;
- for(i = 0; i < NHASH; i++)
- for(s = hash[i]; s != S; s = s->link)
- if(s->sig != 0 && s->type != SXREF &&
- s->type != SUNDEF &&
- (nexports == 0 || s->subtype == SEXPORT))
- esyms[n++] = s;
- for(i = 0; i < ne-1; i++)
- for(j = i+1; j < ne; j++)
- if(strcmp(esyms[i]->name, esyms[j]->name) > 0){
- s = esyms[i];
- esyms[i] = esyms[j];
- esyms[j] = s;
- }
-
- nb = 0;
- off = 0;
- et = lookup(EXPTAB, 0);
- if(et->type != 0 && et->type != SXREF)
- diag("%s already defined", EXPTAB);
- et->type = SDATA;
- str = lookup(".string", 0);
- if(str->type == 0)
- str->type = SDATA;
- sv = str->value;
- for(i = 0; i < ne; i++){
- s = esyms[i];
- if(debug['S'])
- s->sig = 0;
- /* Bprint(&bso, "EXPORT: %s sig=%lux t=%d\n", s->name, s->sig, s->type); */
-
- /* signature */
- p = newdata(et, off, sizeof(int32), D_EXTERN);
- off += sizeof(int32);
- p->to.offset = s->sig;
-
- /* address */
- p = newdata(et, off, sizeof(int32), D_EXTERN);
- off += sizeof(int32);
- p->to.type = D_ADDR;
- p->to.index = D_EXTERN;
- p->to.sym = s;
-
- /* string */
- t = s->name;
- n = strlen(t)+1;
- for(;;){
- buf[nb++] = *t;
- sv++;
- if(nb >= NSNAME){
- p = newdata(str, sv-NSNAME, NSNAME, D_STATIC);
- p->to.type = D_SCONST;
- memmove(p->to.scon, buf, NSNAME);
- nb = 0;
- }
- if(*t++ == 0)
- break;
- }
-
- /* name */
- p = newdata(et, off, sizeof(int32), D_EXTERN);
- off += sizeof(int32);
- p->to.type = D_ADDR;
- p->to.index = D_STATIC;
- p->to.sym = str;
- p->to.offset = sv-n;
- }
-
- if(nb > 0){
- p = newdata(str, sv-nb, nb, D_STATIC);
- p->to.type = D_SCONST;
- memmove(p->to.scon, buf, nb);
- }
-
- for(i = 0; i < 3; i++){
- newdata(et, off, sizeof(int32), D_EXTERN);
- off += sizeof(int32);
- }
- et->value = off;
- if(sv == 0)
- sv = 1;
- str->value = sv;
- exports = ne;
- free(esyms);
-}
diff --git a/src/cmd/6l/prof.c b/src/cmd/6l/prof.c
new file mode 100644
index 000000000..25992a40b
--- /dev/null
+++ b/src/cmd/6l/prof.c
@@ -0,0 +1,171 @@
+// Inferno utils/6l/obj.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+// Profiling.
+
+#include "l.h"
+#include "../ld/lib.h"
+
+void
+doprof1(void)
+{
+#if 0
+ Sym *s;
+ int32 n;
+ Prog *p, *q;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f profile 1\n", cputime());
+ Bflush(&bso);
+ s = lookup("__mcount", 0);
+ n = 1;
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ p = cursym->text;
+ q = prg();
+ q->line = p->line;
+ q->link = datap;
+ datap = q;
+ q->as = ADATA;
+ q->from.type = D_EXTERN;
+ q->from.offset = n*4;
+ q->from.sym = s;
+ q->from.scale = 4;
+ q->to = p->from;
+ q->to.type = D_CONST;
+
+ q = prg();
+ q->line = p->line;
+ q->pc = p->pc;
+ q->link = p->link;
+ p->link = q;
+ p = q;
+ p->as = AADDL;
+ p->from.type = D_CONST;
+ p->from.offset = 1;
+ p->to.type = D_EXTERN;
+ p->to.sym = s;
+ p->to.offset = n*4 + 4;
+
+ n += 2;
+ }
+ q = prg();
+ q->line = 0;
+ q->link = datap;
+ datap = q;
+
+ q->as = ADATA;
+ q->from.type = D_EXTERN;
+ q->from.sym = s;
+ q->from.scale = 4;
+ q->to.type = D_CONST;
+ q->to.offset = n;
+
+ s->type = SBSS;
+ s->size = n*4;
+#endif
+}
+
+void
+doprof2(void)
+{
+ Sym *s2, *s4;
+ Prog *p, *q, *ps2, *ps4;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f profile 2\n", cputime());
+ Bflush(&bso);
+
+ s2 = lookup("_profin", 0);
+ s4 = lookup("_profout", 0);
+ if(s2->type != STEXT || s4->type != STEXT) {
+ diag("_profin/_profout not defined");
+ return;
+ }
+
+ ps2 = P;
+ ps4 = P;
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ p = cursym->text;
+ if(p->from.sym == s2) {
+ p->from.scale = 1;
+ ps2 = p;
+ }
+ if(p->from.sym == s4) {
+ p->from.scale = 1;
+ ps4 = p;
+ }
+ }
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ p = cursym->text;
+
+ if(p->from.scale & NOPROF) /* dont profile */
+ continue;
+
+ /*
+ * JMPL profin
+ */
+ q = prg();
+ q->line = p->line;
+ q->pc = p->pc;
+ q->link = p->link;
+ p->link = q;
+ p = q;
+ p->as = ACALL;
+ p->to.type = D_BRANCH;
+ p->pcond = ps2;
+ p->to.sym = s2;
+
+ for(; p; p=p->link) {
+ if(p->as == ARET) {
+ /*
+ * RET
+ */
+ q = prg();
+ q->as = ARET;
+ q->from = p->from;
+ q->to = p->to;
+ q->link = p->link;
+ p->link = q;
+
+ /*
+ * JAL profout
+ */
+ p->as = ACALL;
+ p->from = zprg.from;
+ p->to = zprg.to;
+ p->to.type = D_BRANCH;
+ p->pcond = ps4;
+ p->to.sym = s4;
+
+ p = q;
+ }
+ }
+ }
+}
diff --git a/src/cmd/6l/span.c b/src/cmd/6l/span.c
index 15f931bcb..5251f19bb 100644
--- a/src/cmd/6l/span.c
+++ b/src/cmd/6l/span.c
@@ -28,34 +28,33 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+// Instruction layout.
+
#include "l.h"
#include "../ld/lib.h"
-#include "../ld/elf.h"
static int rexflag;
static int asmode;
+static vlong vaddr(Adr*, Reloc*);
void
-span(void)
+span1(Sym *s)
{
Prog *p, *q;
- int32 v;
- vlong c, idat;
- int m, n, again;
-
- xdefine("etext", STEXT, 0L);
- idat = INITDAT;
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT)
- curtext = p;
- n = 0;
- if(p->to.type == D_BRANCH)
- if(p->pcond == P)
- p->pcond = p;
- if((q = p->pcond) != P)
- if(q->back != 2)
- n = 1;
- p->back = n;
+ int32 c, v, loop;
+ uchar *bp;
+ int n, m, i;
+
+ cursym = s;
+
+ if(s->p != nil)
+ return;
+
+ for(p = s->text; p != P; p = p->link) {
+ p->back = 2; // use short branches first time through
+ if((q = p->pcond) != P && (q->back & 2))
+ p->back |= 1; // backward jump
+
if(p->as == AADJSP) {
p->to.type = D_SP;
v = -p->from.offset;
@@ -70,378 +69,253 @@ span(void)
p->as = ANOP;
}
}
+
n = 0;
+ do {
+ loop = 0;
+ memset(s->r, 0, s->nr*sizeof s->r[0]);
+ s->nr = 0;
+ s->np = 0;
+ c = 0;
+ for(p = s->text; p != P; p = p->link) {
+ p->pc = c;
+
+ // process forward jumps to p
+ for(q = p->comefrom; q != P; q = q->forwd) {
+ v = p->pc - (q->pc + q->mark);
+ if(q->back & 2) { // short
+ if(v > 127) {
+ loop++;
+ q->back ^= 2;
+ }
+ s->p[q->pc+1] = v;
+ } else {
+ bp = s->p + q->pc + q->mark - 4;
+ *bp++ = v;
+ *bp++ = v>>8;
+ *bp++ = v>>16;
+ *bp++ = v>>24;
+ }
+ }
+ p->comefrom = P;
-start:
- if(debug['v'])
- Bprint(&bso, "%5.2f span\n", cputime());
- Bflush(&bso);
- c = INITTEXT;
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT)
- curtext = p;
- if(p->to.type == D_BRANCH)
- if(p->back)
- p->pc = c;
- asmins(p);
- p->pc = c;
- m = andptr-and;
- p->mark = m;
- c += m;
- }
-
-loop:
- n++;
- if(debug['v'])
- Bprint(&bso, "%5.2f span %d\n", cputime(), n);
- Bflush(&bso);
- if(n > 50) {
- print("span must be looping\n");
- errorexit();
- }
- again = 0;
- c = INITTEXT;
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT)
- curtext = p;
- if(p->to.type == D_BRANCH || p->back & 0100) {
- if(p->back)
- p->pc = c;
asmins(p);
+ p->pc = c;
m = andptr-and;
- if(m != p->mark) {
- p->mark = m;
- again++;
- }
+ symgrow(s, p->pc+m);
+ memmove(s->p+p->pc, and, m);
+ p->mark = m;
+ c += m;
}
- p->pc = c;
- c += p->mark;
- }
- if(again) {
- textsize = c;
- goto loop;
- }
- if(INITRND) {
- INITDAT = rnd(c, INITRND);
- if(INITDAT != idat) {
- idat = INITDAT;
- goto start;
+ if(++n > 20) {
+ diag("span must be looping");
+ errorexit();
+ }
+ } while(loop);
+ s->size = c;
+
+ if(debug['a'] > 1) {
+ print("span1 %s %lld (%d tries)\n %.6ux", s->name, s->size, n, 0);
+ for(i=0; i<s->np; i++) {
+ print(" %.2ux", s->p[i]);
+ if(i%16 == 15)
+ print("\n %.6ux", i+1);
+ }
+ if(i%16)
+ print("\n");
+
+ for(i=0; i<s->nr; i++) {
+ Reloc *r;
+
+ r = &s->r[i];
+ print(" rel %#.4ux/%d %s%+lld\n", r->off, r->siz, r->sym->name, r->add);
}
}
- xdefine("etext", STEXT, c);
- if(debug['v'])
- Bprint(&bso, "etext = %llux\n", c);
- Bflush(&bso);
- for(p = textp; p != P; p = p->pcond)
- p->from.sym->value = p->pc;
- textsize = c - INITTEXT;
}
void
-xdefine(char *p, int t, vlong v)
+span(void)
{
- Sym *s;
+ Prog *p, *q;
+ int32 v;
+ int n;
- s = lookup(p, 0);
- if(s->type == 0 || s->type == SXREF) {
- s->type = t;
- s->value = v;
- }
- if(s->type == STEXT && s->value == 0)
- s->value = v;
-}
+ if(debug['v'])
+ Bprint(&bso, "%5.2f span\n", cputime());
-void
-putsymb(char *s, int t, vlong v, vlong size, int ver, Sym *go)
-{
- int i, f, l;
- vlong gv;
-
- if(t == 'f')
- s++;
- l = 4;
- if(!debug['8']){
- lputb(v>>32);
- l = 8;
- }
- lputb(v);
- if(ver)
- t += 'a' - 'A';
- cput(t+0x80); /* 0x80 is variable length */
-
- if(t == 'Z' || t == 'z') {
- cput(s[0]);
- for(i=1; s[i] != 0 || s[i+1] != 0; i += 2) {
- cput(s[i]);
- cput(s[i+1]);
- }
- cput(0);
- cput(0);
- i++;
- }
- else {
- for(i=0; s[i]; i++)
- cput(s[i]);
- cput(0);
- }
- gv = 0;
- if(go) {
- if(!go->reachable)
- diag("unreachable type %s", go->name);
- gv = go->value+INITDAT;
- }
- if(l == 8)
- lputb(gv>>32);
- lputb(gv);
- symsize += l + 1 + i+1 + l;
-
- if(debug['n']) {
- if(t == 'z' || t == 'Z') {
- Bprint(&bso, "%c %.8llux ", t, v);
- for(i=1; s[i] != 0 || s[i+1] != 0; i+=2) {
- f = ((s[i]&0xff) << 8) | (s[i+1]&0xff);
- Bprint(&bso, "/%x", f);
+ // NOTE(rsc): If we get rid of the globals we should
+ // be able to parallelize these iterations.
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ if(cursym->p != nil)
+ continue;
+ // TODO: move into span1
+ for(p = cursym->text; p != P; p = p->link) {
+ n = 0;
+ if(p->to.type == D_BRANCH)
+ if(p->pcond == P)
+ p->pcond = p;
+ if((q = p->pcond) != P)
+ if(q->back != 2)
+ n = 1;
+ p->back = n;
+ if(p->as == AADJSP) {
+ p->to.type = D_SP;
+ v = -p->from.offset;
+ p->from.offset = v;
+ p->as = p->mode != 64? AADDL: AADDQ;
+ if(v < 0) {
+ p->as = p->mode != 64? ASUBL: ASUBQ;
+ v = -v;
+ p->from.offset = v;
+ }
+ if(v == 0)
+ p->as = ANOP;
}
- Bprint(&bso, "\n");
- return;
}
- if(ver)
- Bprint(&bso, "%c %.8llux %s<%d> %s (%.8llux)\n", t, v, s, ver, go ? go->name : "", gv);
- else
- Bprint(&bso, "%c %.8llux %s %s (%.8llux)\n", t, v, s, go ? go->name : "", gv);
+ span1(cursym);
}
}
void
-genasmsym(void (*put)(char*, int, vlong, vlong, int, Sym*))
+xdefine(char *p, int t, vlong v)
{
- Prog *p;
- Auto *a;
Sym *s;
- int h;
-
- s = lookup("etext", 0);
- if(s->type == STEXT)
- put(s->name, 'T', s->value, s->size, s->version, 0);
-
- for(h=0; h<NHASH; h++) {
- for(s=hash[h]; s!=S; s=s->link) {
- switch(s->type) {
- case SCONST:
- if(!s->reachable)
- continue;
- put(s->name, 'D', s->value, s->size, s->version, s->gotype);
- continue;
-
- case SDATA:
- case SELFDATA:
- if(!s->reachable)
- continue;
- put(s->name, 'D', s->value+INITDAT, s->size, s->version, s->gotype);
- continue;
-
- case SMACHO:
- if(!s->reachable)
- continue;
- put(s->name, 'D', s->value+INITDAT+datsize+bsssize, s->size, s->version, s->gotype);
- continue;
-
- case SBSS:
- if(!s->reachable)
- continue;
- put(s->name, 'B', s->value+INITDAT, s->size, s->version, s->gotype);
- continue;
-
- case SFIXED:
- put(s->name, 'B', s->value, s->size, s->version, s->gotype);
- continue;
-
- case SFILE:
- put(s->name, 'f', s->value, 0, s->version, 0);
- continue;
- }
- }
- }
-
- for(p = textp; p != P; p = p->pcond) {
- s = p->from.sym;
- if(s->type != STEXT)
- continue;
- /* filenames first */
- for(a=p->to.autom; a; a=a->link)
- if(a->type == D_FILE)
- put(a->asym->name, 'z', a->aoffset, 0, 0, 0);
- else
- if(a->type == D_FILE1)
- put(a->asym->name, 'Z', a->aoffset, 0, 0, 0);
-
- if(!s->reachable)
- continue;
- put(s->name, 'T', s->value, s->size, s->version, s->gotype);
-
- /* frame, auto and param after */
- put(".frame", 'm', p->to.offset+8, 0, 0, 0);
-
- for(a=p->to.autom; a; a=a->link)
- if(a->type == D_AUTO)
- put(a->asym->name, 'a', -a->aoffset, 0, 0, a->gotype);
- else
- if(a->type == D_PARAM)
- put(a->asym->name, 'p', a->aoffset, 0, 0, a->gotype);
- }
- if(debug['v'] || debug['n'])
- Bprint(&bso, "symsize = %lud\n", symsize);
- Bflush(&bso);
+ s = lookup(p, 0);
+ s->type = t;
+ s->value = v;
+ s->reachable = 1;
+ s->special = 1;
}
void
-asmsym(void)
+instinit(void)
{
- genasmsym(putsymb);
-}
+ int c, i;
-char *elfstrdat;
-int elfstrsize;
-int maxelfstr;
-
-int
-putelfstr(char *s)
-{
- int off, n;
-
- if(elfstrsize == 0 && s[0] != 0) {
- // first entry must be empty string
- putelfstr("");
- }
-
- n = strlen(s)+1;
- if(elfstrsize+n > maxelfstr) {
- maxelfstr = 2*(elfstrsize+n+(1<<20));
- elfstrdat = realloc(elfstrdat, maxelfstr);
- }
- off = elfstrsize;
- elfstrsize += n;
- memmove(elfstrdat+off, s, n);
- return off;
-}
-
-void
-putelfsymb(char *s, int t, vlong addr, vlong size, int ver, Sym *go)
-{
- int bind, type, shndx, stroff;
-
- bind = STB_GLOBAL;
- switch(t) {
- default:
- return;
- case 'T':
- type = STT_FUNC;
- shndx = elftextsh + 0;
- break;
- case 'D':
- type = STT_OBJECT;
- shndx = elftextsh + 1;
- break;
- case 'B':
- type = STT_OBJECT;
- shndx = elftextsh + 2;
- break;
+ for(i=1; optab[i].as; i++) {
+ c = optab[i].as;
+ if(opindex[c] != nil) {
+ diag("phase error in optab: %d (%A)", i, c);
+ errorexit();
+ }
+ opindex[c] = &optab[i];
}
-
- stroff = putelfstr(s);
- lputl(stroff); // string
- cput((bind<<4)|(type&0xF));
- cput(0);
- wputl(shndx);
- vputl(addr);
- vputl(size);
-}
-void
-asmelfsym(void)
-{
- genasmsym(putelfsymb);
-}
-
-void
-asmlc(void)
-{
- vlong oldpc;
- Prog *p;
- int32 oldlc, v, s;
-
- oldpc = INITTEXT;
- oldlc = 0;
- for(p = firstp; p != P; p = p->link) {
- if(p->line == oldlc || p->as == ATEXT || p->as == ANOP) {
- if(p->as == ATEXT)
- curtext = p;
- if(debug['O'])
- Bprint(&bso, "%6llux %P\n",
- p->pc, p);
- continue;
+ for(i=0; i<Ymax; i++)
+ ycover[i*Ymax + i] = 1;
+
+ ycover[Yi0*Ymax + Yi8] = 1;
+ ycover[Yi1*Ymax + Yi8] = 1;
+
+ ycover[Yi0*Ymax + Ys32] = 1;
+ ycover[Yi1*Ymax + Ys32] = 1;
+ ycover[Yi8*Ymax + Ys32] = 1;
+
+ ycover[Yi0*Ymax + Yi32] = 1;
+ ycover[Yi1*Ymax + Yi32] = 1;
+ ycover[Yi8*Ymax + Yi32] = 1;
+ ycover[Ys32*Ymax + Yi32] = 1;
+
+ ycover[Yi0*Ymax + Yi64] = 1;
+ ycover[Yi1*Ymax + Yi64] = 1;
+ ycover[Yi8*Ymax + Yi64] = 1;
+ ycover[Ys32*Ymax + Yi64] = 1;
+ ycover[Yi32*Ymax + Yi64] = 1;
+
+ ycover[Yal*Ymax + Yrb] = 1;
+ ycover[Ycl*Ymax + Yrb] = 1;
+ ycover[Yax*Ymax + Yrb] = 1;
+ ycover[Ycx*Ymax + Yrb] = 1;
+ ycover[Yrx*Ymax + Yrb] = 1;
+ ycover[Yrl*Ymax + Yrb] = 1;
+
+ ycover[Ycl*Ymax + Ycx] = 1;
+
+ ycover[Yax*Ymax + Yrx] = 1;
+ ycover[Ycx*Ymax + Yrx] = 1;
+
+ ycover[Yax*Ymax + Yrl] = 1;
+ ycover[Ycx*Ymax + Yrl] = 1;
+ ycover[Yrx*Ymax + Yrl] = 1;
+
+ ycover[Yf0*Ymax + Yrf] = 1;
+
+ ycover[Yal*Ymax + Ymb] = 1;
+ ycover[Ycl*Ymax + Ymb] = 1;
+ ycover[Yax*Ymax + Ymb] = 1;
+ ycover[Ycx*Ymax + Ymb] = 1;
+ ycover[Yrx*Ymax + Ymb] = 1;
+ ycover[Yrb*Ymax + Ymb] = 1;
+ ycover[Yrl*Ymax + Ymb] = 1;
+ ycover[Ym*Ymax + Ymb] = 1;
+
+ ycover[Yax*Ymax + Yml] = 1;
+ ycover[Ycx*Ymax + Yml] = 1;
+ ycover[Yrx*Ymax + Yml] = 1;
+ ycover[Yrl*Ymax + Yml] = 1;
+ ycover[Ym*Ymax + Yml] = 1;
+
+ ycover[Yax*Ymax + Ymm] = 1;
+ ycover[Ycx*Ymax + Ymm] = 1;
+ ycover[Yrx*Ymax + Ymm] = 1;
+ ycover[Yrl*Ymax + Ymm] = 1;
+ 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;
+
+ for(i=0; i<D_NONE; i++) {
+ reg[i] = -1;
+ if(i >= D_AL && i <= D_R15B) {
+ reg[i] = (i-D_AL) & 7;
+ if(i >= D_SPB && i <= D_DIB)
+ regrex[i] = 0x40;
+ if(i >= D_R8B && i <= D_R15B)
+ regrex[i] = Rxr | Rxx | Rxb;
}
- if(debug['O'])
- Bprint(&bso, "\t\t%6ld", lcsize);
- v = (p->pc - oldpc) / MINLC;
- while(v) {
- s = 127;
- if(v < 127)
- s = v;
- cput(s+128); /* 129-255 +pc */
- if(debug['O'])
- Bprint(&bso, " pc+%ld*%d(%ld)", s, MINLC, s+128);
- v -= s;
- lcsize++;
+ if(i >= D_AH && i<= D_BH)
+ reg[i] = 4 + ((i-D_AH) & 7);
+ if(i >= D_AX && i <= D_R15) {
+ reg[i] = (i-D_AX) & 7;
+ if(i >= D_R8)
+ regrex[i] = Rxr | Rxx | Rxb;
}
- s = p->line - oldlc;
- oldlc = p->line;
- oldpc = p->pc + MINLC;
- if(s > 64 || s < -64) {
- cput(0); /* 0 vv +lc */
- cput(s>>24);
- cput(s>>16);
- cput(s>>8);
- cput(s);
- if(debug['O']) {
- if(s > 0)
- Bprint(&bso, " lc+%ld(%d,%ld)\n",
- s, 0, s);
- else
- Bprint(&bso, " lc%ld(%d,%ld)\n",
- s, 0, s);
- Bprint(&bso, "%6llux %P\n",
- p->pc, p);
- }
- lcsize += 5;
- continue;
+ if(i >= D_F0 && i <= D_F0+7)
+ reg[i] = (i-D_F0) & 7;
+ if(i >= D_M0 && i <= D_M0+7)
+ reg[i] = (i-D_M0) & 7;
+ if(i >= D_X0 && i <= D_X0+15) {
+ reg[i] = (i-D_X0) & 7;
+ if(i >= D_X0+8)
+ regrex[i] = Rxr | Rxx | Rxb;
}
- if(s > 0) {
- cput(0+s); /* 1-64 +lc */
- if(debug['O']) {
- Bprint(&bso, " lc+%ld(%ld)\n", s, 0+s);
- Bprint(&bso, "%6llux %P\n",
- p->pc, p);
- }
- } else {
- cput(64-s); /* 65-128 -lc */
- if(debug['O']) {
- Bprint(&bso, " lc%ld(%ld)\n", s, 64-s);
- Bprint(&bso, "%6llux %P\n",
- p->pc, p);
- }
- }
- lcsize++;
+ if(i >= D_CR+8 && i <= D_CR+15)
+ regrex[i] = Rxr;
}
- while(lcsize & 1) {
- s = 129;
- cput(s);
- lcsize++;
+}
+
+int
+prefixof(Adr *a)
+{
+ switch(a->type) {
+ case D_INDIR+D_CS:
+ return 0x2e;
+ case D_INDIR+D_DS:
+ return 0x3e;
+ case D_INDIR+D_ES:
+ return 0x26;
+ case D_INDIR+D_FS:
+ return 0x64;
+ case D_INDIR+D_GS:
+ return 0x65;
}
- if(debug['v'] || debug['O'])
- Bprint(&bso, "lcsize = %ld\n", lcsize);
- Bflush(&bso);
+ return 0;
}
int
@@ -641,11 +515,11 @@ oclass(Adr *a)
}
void
-asmidx(Adr *a, int base)
+asmidx(int scale, int index, int base)
{
int i;
- switch(a->index) {
+ switch(index) {
default:
goto bad;
@@ -670,10 +544,10 @@ asmidx(Adr *a, int base)
case D_BP:
case D_SI:
case D_DI:
- i = reg[(int)a->index] << 3;
+ i = reg[index] << 3;
break;
}
- switch(a->scale) {
+ switch(scale) {
default:
goto bad;
case 1:
@@ -719,7 +593,7 @@ bas:
*andptr++ = i;
return;
bad:
- diag("asmidx: bad address %D", a);
+ diag("asmidx: bad address %d/%d/%d", scale, index, base);
*andptr++ = 0;
return;
}
@@ -727,10 +601,6 @@ bad:
static void
put4(int32 v)
{
- if(dlm && curp != P && reloca != nil){
- dynreloc(reloca->sym, curp->pc + andptr - &and[0], 1);
- reloca = nil;
- }
andptr[0] = v;
andptr[1] = v>>8;
andptr[2] = v>>16;
@@ -739,12 +609,25 @@ put4(int32 v)
}
static void
-put8(vlong v)
+relput4(Prog *p, Adr *a)
{
- if(dlm && curp != P && reloca != nil){
- dynreloc(reloca->sym, curp->pc + andptr - &and[0], 1); /* TO DO */
- reloca = nil;
+ vlong v;
+ Reloc rel, *r;
+
+ v = vaddr(a, &rel);
+ if(rel.siz != 0) {
+ if(rel.siz != 4)
+ diag("bad reloc");
+ r = addrel(cursym);
+ *r = rel;
+ r->off = p->pc + andptr - and;
}
+ put4(v);
+}
+
+static void
+put8(vlong v)
+{
andptr[0] = v;
andptr[1] = v>>8;
andptr[2] = v>>16;
@@ -756,24 +639,41 @@ put8(vlong v)
andptr += 8;
}
+/*
+static void
+relput8(Prog *p, Adr *a)
+{
+ vlong v;
+ Reloc rel, *r;
+
+ v = vaddr(a, &rel);
+ if(rel.siz != 0) {
+ r = addrel(cursym);
+ *r = rel;
+ r->siz = 8;
+ r->off = p->pc + andptr - and;
+ }
+ put8(v);
+}
+*/
+
vlong
symaddr(Sym *s)
{
- Adr a;
-
- a.type = D_ADDR;
- a.index = D_EXTERN;
- a.offset = 0;
- a.sym = s;
- return vaddr(&a);
+ if(!s->reachable)
+ diag("unreachable symbol in symaddr - %s", s->name);
+ return s->value;
}
-vlong
-vaddr(Adr *a)
+static vlong
+vaddr(Adr *a, Reloc *r)
{
int t;
vlong v;
Sym *s;
+
+ if(r != nil)
+ memset(r, 0, sizeof *r);
t = a->type;
v = a->offset;
@@ -783,34 +683,18 @@ vaddr(Adr *a)
case D_STATIC:
case D_EXTERN:
s = a->sym;
- if(s != nil) {
- if(dlm && curp != P)
- reloca = a;
- switch(s->type) {
- case SUNDEF:
- ckoff(s, v);
- case STEXT:
- case SCONST:
- if(!s->reachable)
- diag("unreachable symbol in vaddr - %s", s->name);
- if((uvlong)s->value < (uvlong)INITTEXT)
- v += INITTEXT; /* TO DO */
- v += s->value;
- break;
- case SFIXED:
- v += s->value;
- break;
- case SMACHO:
- if(!s->reachable)
- sysfatal("unreachable symbol in vaddr - %s", s->name);
- v += INITDAT + datsize + s->value;
- break;
- default:
- if(!s->reachable)
- diag("unreachable symbol in vaddr - %s", s->name);
- v += INITDAT + s->value;
- }
+ if(!s->reachable)
+ diag("unreachable symbol in vaddr - %s", s->name);
+ if(r == nil) {
+ diag("need reloc for %D", a);
+ errorexit();
}
+ r->type = D_ADDR;
+ r->siz = 4; // TODO: 8 for external symbols
+ r->off = -1; // caller must fill in
+ r->sym = s;
+ r->add = v;
+ v = 0;
}
return v;
}
@@ -819,55 +703,51 @@ static void
asmandsz(Adr *a, int r, int rex, int m64)
{
int32 v;
- int t;
- Adr aa;
+ int t, scale;
+ Reloc rel;
rex &= (0x40 | Rxr);
v = a->offset;
t = a->type;
+ rel.siz = 0;
if(a->index != D_NONE) {
- if(t >= D_INDIR) {
- t -= D_INDIR;
- rexflag |= (regrex[(int)a->index] & Rxx) | (regrex[t] & Rxb) | rex;
- if(t == D_NONE) {
- *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
- asmidx(a, t);
- put4(v);
- return;
- }
- if(v == 0 && t != D_BP && t != D_R13) {
- *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
- asmidx(a, t);
- return;
- }
- if(v >= -128 && v < 128) {
- *andptr++ = (1 << 6) | (4 << 0) | (r << 3);
- asmidx(a, t);
- *andptr++ = v;
- return;
+ if(t < D_INDIR) {
+ switch(t) {
+ default:
+ goto bad;
+ case D_STATIC:
+ case D_EXTERN:
+ t = D_NONE;
+ v = vaddr(a, &rel);
+ break;
+ case D_AUTO:
+ case D_PARAM:
+ t = D_SP;
+ break;
}
- *andptr++ = (2 << 6) | (4 << 0) | (r << 3);
- asmidx(a, t);
- put4(v);
+ } else
+ t -= D_INDIR;
+ rexflag |= (regrex[(int)a->index] & Rxx) | (regrex[t] & Rxb) | rex;
+ if(t == D_NONE) {
+ *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
+ asmidx(a->scale, a->index, t);
+ goto putrelv;
return;
}
- switch(t) {
- default:
- goto bad;
- case D_STATIC:
- case D_EXTERN:
- aa.type = D_NONE+D_INDIR;
- break;
- case D_AUTO:
- case D_PARAM:
- aa.type = D_SP+D_INDIR;
- break;
+ if(v == 0 && rel.siz == 0 && t != D_BP && t != D_R13) {
+ *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
+ asmidx(a->scale, a->index, t);
+ return;
}
- aa.offset = vaddr(a);
- aa.index = a->index;
- aa.scale = a->scale;
- asmandsz(&aa, r, rex, m64);
- return;
+ if(v >= -128 && v < 128 && rel.siz == 0) {
+ *andptr++ = (1 << 6) | (4 << 0) | (r << 3);
+ asmidx(a->scale, a->index, t);
+ *andptr++ = v;
+ return;
+ }
+ *andptr++ = (2 << 6) | (4 << 0) | (r << 3);
+ asmidx(a->scale, a->index, t);
+ goto putrelv;
}
if(t >= D_AL && t <= D_X0+15) {
if(v)
@@ -876,72 +756,84 @@ asmandsz(Adr *a, int r, int rex, int m64)
rexflag |= (regrex[t] & (0x40 | Rxb)) | rex;
return;
}
- if(t >= D_INDIR) {
+
+ scale = a->scale;
+ if(t < D_INDIR) {
+ switch(a->type) {
+ default:
+ goto bad;
+ case D_STATIC:
+ case D_EXTERN:
+ t = D_NONE;
+ v = vaddr(a, &rel);
+ break;
+ case D_AUTO:
+ case D_PARAM:
+ t = D_SP;
+ break;
+ }
+ scale = 1;
+ } else
t -= D_INDIR;
- rexflag |= (regrex[t] & Rxb) | rex;
- if(t == D_NONE) {
- if(asmode != 64){
- *andptr++ = (0 << 6) | (5 << 0) | (r << 3);
- put4(v);
- return;
- }
- /* temporary */
- *andptr++ = (0 << 6) | (4 << 0) | (r << 3); /* sib present */
- *andptr++ = (0 << 6) | (4 << 3) | (5 << 0); /* DS:d32 */
- put4(v);
+
+ rexflag |= (regrex[t] & Rxb) | rex;
+ if(t == D_NONE || (D_CS <= t && t <= D_GS)) {
+ if(asmode != 64){
+ *andptr++ = (0 << 6) | (5 << 0) | (r << 3);
+ goto putrelv;
+ }
+ /* temporary */
+ *andptr++ = (0 << 6) | (4 << 0) | (r << 3); /* sib present */
+ *andptr++ = (0 << 6) | (4 << 3) | (5 << 0); /* DS:d32 */
+ goto putrelv;
+ }
+ if(t == D_SP || t == D_R12) {
+ if(v == 0) {
+ *andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
+ asmidx(scale, D_NONE, t);
return;
}
- if(t == D_SP || t == D_R12) {
- if(v == 0) {
- *andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
- asmidx(a, t);
- return;
- }
- if(v >= -128 && v < 128) {
- *andptr++ = (1 << 6) | (reg[t] << 0) | (r << 3);
- asmidx(a, t);
- *andptr++ = v;
- return;
- }
- *andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
- asmidx(a, t);
- put4(v);
+ if(v >= -128 && v < 128) {
+ *andptr++ = (1 << 6) | (reg[t] << 0) | (r << 3);
+ asmidx(scale, D_NONE, t);
+ *andptr++ = v;
return;
}
- if(t >= D_AX && t <= D_R15) {
- if(v == 0 && t != D_BP && t != D_R13) {
- *andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
- return;
- }
- if(v >= -128 && v < 128) {
- andptr[0] = (1 << 6) | (reg[t] << 0) | (r << 3);
- andptr[1] = v;
- andptr += 2;
- return;
- }
- *andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
- put4(v);
+ *andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
+ asmidx(scale, D_NONE, t);
+ goto putrelv;
+ }
+ if(t >= D_AX && t <= D_R15) {
+ if(v == 0 && t != D_BP && t != D_R13) {
+ *andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
return;
}
- goto bad;
+ if(v >= -128 && v < 128) {
+ andptr[0] = (1 << 6) | (reg[t] << 0) | (r << 3);
+ andptr[1] = v;
+ andptr += 2;
+ return;
+ }
+ *andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
+ goto putrelv;
}
- switch(a->type) {
- default:
- goto bad;
- case D_STATIC:
- case D_EXTERN:
- aa.type = D_NONE+D_INDIR;
- break;
- case D_AUTO:
- case D_PARAM:
- aa.type = D_SP+D_INDIR;
- break;
+ goto bad;
+
+putrelv:
+ if(rel.siz != 0) {
+ Reloc *r;
+
+ if(rel.siz != 4) {
+ diag("bad rel");
+ goto bad;
+ }
+ r = addrel(cursym);
+ *r = rel;
+ r->off = curp->pc + andptr - and;
}
- aa.index = D_NONE;
- aa.scale = 1;
- aa.offset = vaddr(a);
- asmandsz(&aa, r, rex, m64);
+ put4(v);
return;
+
bad:
diag("asmand: bad address %D", a);
return;
@@ -1173,14 +1065,25 @@ doasm(Prog *p)
Prog *q, pp;
uchar *t;
Movtab *mo;
- int z, op, ft, tt, xo, l;
+ int z, op, ft, tt, xo, l, pre;
vlong v;
+ Reloc rel, *r;
+ Adr *a;
+
+ curp = p; // TODO
o = opindex[p->as];
if(o == nil) {
diag("asmins: missing op %P", p);
return;
}
+
+ pre = prefixof(&p->from);
+ if(pre)
+ *andptr++ = pre;
+ pre = prefixof(&p->to);
+ if(pre)
+ *andptr++ = pre;
if(p->ft == 0)
p->ft = oclass(&p->from);
@@ -1244,7 +1147,7 @@ found:
diag("asmins: illegal in %d-bit mode: %P", p->mode, p);
break;
}
- v = vaddr(&p->from);
+
op = o->op[z];
if(op == 0x0f) {
*andptr++ = op;
@@ -1350,64 +1253,74 @@ found:
break;
case Zm_ibo:
- v = vaddr(&p->to);
*andptr++ = op;
asmando(&p->from, o->op[z+1]);
- *andptr++ = v;
+ *andptr++ = vaddr(&p->to, nil);
break;
case Zibo_m:
*andptr++ = op;
asmando(&p->to, o->op[z+1]);
- *andptr++ = v;
+ *andptr++ = vaddr(&p->from, nil);
break;
case Zibo_m_xm:
z = mediaop(o, op, t[3], z);
asmando(&p->to, o->op[z+1]);
- *andptr++ = v;
+ *andptr++ = vaddr(&p->from, nil);
break;
case Z_ib:
- v = vaddr(&p->to);
case Zib_:
+ if(t[2] == Zib_)
+ a = &p->from;
+ else
+ a = &p->to;
*andptr++ = op;
- *andptr++ = v;
+ *andptr++ = vaddr(a, nil);
break;
case Zib_rp:
rexflag |= regrex[p->to.type] & (Rxb|0x40);
*andptr++ = op + reg[p->to.type];
- *andptr++ = v;
+ *andptr++ = vaddr(&p->from, nil);
break;
case Zil_rp:
rexflag |= regrex[p->to.type] & Rxb;
*andptr++ = op + reg[p->to.type];
if(o->prefix == Pe) {
+ v = vaddr(&p->from, nil);
*andptr++ = v;
*andptr++ = v>>8;
}
else
- put4(v);
+ relput4(p, &p->from);
break;
case Zo_iw:
*andptr++ = op;
if(p->from.type != D_NONE){
+ v = vaddr(&p->from, nil);
*andptr++ = v;
*andptr++ = v>>8;
}
break;
case Ziq_rp:
+ v = vaddr(&p->from, &rel);
l = v>>32;
- if(l == 0){
+ if(l == 0 && rel.siz != 8){
//p->mark |= 0100;
//print("zero: %llux %P\n", v, p);
rexflag &= ~(0x40|Rxw);
rexflag |= regrex[p->to.type] & Rxb;
*andptr++ = 0xb8 + reg[p->to.type];
+ if(rel.type != 0) {
+ r = addrel(cursym);
+ *r = rel;
+ r->off = p->pc + andptr - and;
+ }
put4(v);
}else if(l == -1 && (v&((uvlong)1<<31))!=0){ /* sign extend */
//p->mark |= 0100;
@@ -1419,6 +1332,11 @@ found:
//print("all: %llux %P\n", v, p);
rexflag |= regrex[p->to.type] & Rxb;
*andptr++ = op + reg[p->to.type];
+ if(rel.type != 0) {
+ r = addrel(cursym);
+ *r = rel;
+ r->off = p->pc + andptr - and;
+ }
put8(v);
}
break;
@@ -1426,53 +1344,54 @@ found:
case Zib_rr:
*andptr++ = op;
asmand(&p->to, &p->to);
- *andptr++ = v;
+ *andptr++ = vaddr(&p->from, nil);
break;
case Z_il:
- v = vaddr(&p->to);
case Zil_:
- *andptr++ = op;
- if(o->prefix == Pe) {
- *andptr++ = v;
- *andptr++ = v>>8;
- }
+ if(t[2] == Zil_)
+ a = &p->from;
else
- put4(v);
- break;
-
- case Zm_ilo:
- v = vaddr(&p->to);
+ a = &p->to;
*andptr++ = op;
- asmando(&p->from, o->op[z+1]);
if(o->prefix == Pe) {
+ v = vaddr(a, nil);
*andptr++ = v;
*andptr++ = v>>8;
}
else
- put4(v);
+ relput4(p, a);
break;
+ case Zm_ilo:
case Zilo_m:
*andptr++ = op;
- asmando(&p->to, o->op[z+1]);
+ if(t[2] == Zilo_m) {
+ a = &p->from;
+ asmando(&p->to, o->op[z+1]);
+ } else {
+ a = &p->to;
+ asmando(&p->from, o->op[z+1]);
+ }
if(o->prefix == Pe) {
+ v = vaddr(a, nil);
*andptr++ = v;
*andptr++ = v>>8;
}
else
- put4(v);
+ relput4(p, a);
break;
case Zil_rr:
*andptr++ = op;
asmand(&p->to, &p->to);
if(o->prefix == Pe) {
+ v = vaddr(&p->from, nil);
*andptr++ = v;
*andptr++ = v>>8;
}
else
- put4(v);
+ relput4(p, &p->from);
break;
case Z_rp:
@@ -1490,74 +1409,132 @@ found:
asmand(&p->to, &p->to);
break;
- case Zbr:
+ case Zcall:
q = p->pcond;
- if(q) {
- v = q->pc - p->pc - 2;
- if(v >= -128 && v <= 127) {
- *andptr++ = op;
- *andptr++ = v;
- } else {
- v -= 6-2;
- *andptr++ = 0x0f;
- *andptr++ = o->op[z+1];
- *andptr++ = v;
- *andptr++ = v>>8;
- *andptr++ = v>>16;
- *andptr++ = v>>24;
- }
+ if(q == nil) {
+ diag("call without target");
+ errorexit();
+ }
+ if(q->as != ATEXT) {
+ // Could handle this case by making D_PCREL
+ // record the Prog* instead of the Sym*, but let's
+ // wait until the need arises.
+ diag("call of non-TEXT %P", q);
+ errorexit();
}
+ *andptr++ = op;
+ r = addrel(cursym);
+ r->off = p->pc + andptr - and;
+ r->sym = q->from.sym;
+ r->type = D_PCREL;
+ r->siz = 4;
+ put4(0);
break;
- case Zcall:
+ case Zbr:
+ case Zjmp:
+ // TODO: jump across functions needs reloc
q = p->pcond;
- if(q) {
- v = q->pc - p->pc - 5;
- if(dlm && curp != P && p->to.sym->type == SUNDEF){
- /* v = 0 - p->pc - 5; */
- v = 0;
- ckoff(p->to.sym, v);
- v += p->to.sym->value;
- dynreloc(p->to.sym, p->pc+1, 0);
+ if(q == nil) {
+ diag("jmp/branch without target");
+ errorexit();
+ }
+ if(q->as == ATEXT) {
+ if(t[2] == Zbr) {
+ diag("branch to ATEXT");
+ errorexit();
}
- *andptr++ = op;
- *andptr++ = v;
- *andptr++ = v>>8;
- *andptr++ = v>>16;
- *andptr++ = v>>24;
+ *andptr++ = o->op[z+1];
+ r = addrel(cursym);
+ r->off = p->pc + andptr - and;
+ r->sym = q->from.sym;
+ r->type = D_PCREL;
+ r->siz = 4;
+ put4(0);
+ break;
}
- break;
+ // Assumes q is in this function.
+ // TODO: Check in input, preserve in brchain.
- case Zjmp:
- q = p->pcond;
- if(q) {
- v = q->pc - p->pc - 2;
- if(v >= -128 && v <= 127) {
+ // Fill in backward jump now.
+ if(p->back & 1) {
+ v = q->pc - (p->pc + 2);
+ if(v >= -128) {
*andptr++ = op;
*andptr++ = v;
} else {
v -= 5-2;
+ if(t[2] == Zbr) {
+ *andptr++ = 0x0f;
+ v--;
+ }
*andptr++ = o->op[z+1];
*andptr++ = v;
*andptr++ = v>>8;
*andptr++ = v>>16;
*andptr++ = v>>24;
}
+ break;
+ }
+
+ // Annotate target; will fill in later.
+ p->forwd = q->comefrom;
+ q->comefrom = p;
+ if(p->back & 2) { // short
+ *andptr++ = op;
+ *andptr++ = 0;
+ } else {
+ if(t[2] == Zbr)
+ *andptr++ = 0x0f;
+ *andptr++ = o->op[z+1];
+ *andptr++ = 0;
+ *andptr++ = 0;
+ *andptr++ = 0;
+ *andptr++ = 0;
}
break;
+
+/*
+ v = q->pc - p->pc - 2;
+ if((v >= -128 && v <= 127) || p->pc == -1 || q->pc == -1) {
+ *andptr++ = op;
+ *andptr++ = v;
+ } else {
+ v -= 5-2;
+ if(t[2] == Zbr) {
+ *andptr++ = 0x0f;
+ v--;
+ }
+ *andptr++ = o->op[z+1];
+ *andptr++ = v;
+ *andptr++ = v>>8;
+ *andptr++ = v>>16;
+ *andptr++ = v>>24;
+ }
+*/
+ break;
case Zloop:
q = p->pcond;
- if(q) {
- v = q->pc - p->pc - 2;
- if(v < -128 && v > 127)
- diag("loop too far: %P", p);
- *andptr++ = op;
- *andptr++ = v;
+ 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) {
+ rel.siz = op;
+ r = addrel(cursym);
+ *r = rel;
+ r->off = p->pc + andptr - and;
+ }
*andptr++ = v;
if(op > 1) {
*andptr++ = v>>8;
@@ -1730,6 +1707,7 @@ void
asmins(Prog *p)
{
int n, np, c;
+ Reloc *r;
rexflag = 0;
andptr = and;
@@ -1739,7 +1717,7 @@ asmins(Prog *p)
/*
* as befits the whole approach of the architecture,
* the rex prefix must appear before the first opcode byte
- * (and thus after any 66/67/f2/f3 prefix bytes, but
+ * (and thus after any 66/67/f2/f3/26/2e/3e prefix bytes, but
* before the 0f opcode escape!), or it might be ignored.
* note that the handbook often misleadingly shows 66/f2/f3 in `opcode'.
*/
@@ -1748,164 +1726,16 @@ asmins(Prog *p)
n = andptr - and;
for(np = 0; np < n; np++) {
c = and[np];
- if(c != 0x66 && c != 0xf2 && c != 0xf3 && c != 0x67)
+ if(c != 0xf2 && c != 0xf3 && (c < 0x64 || c > 0x67) && c != 0x2e && c != 0x3e && c != 0x26)
break;
}
+ for(r=cursym->r+cursym->nr; r-- > cursym->r; ) {
+ if(r->off < p->pc)
+ break;
+ r->off++;
+ }
memmove(and+np+1, and+np, n-np);
and[np] = 0x40 | rexflag;
andptr++;
}
}
-
-enum{
- ABSD = 0,
- ABSU = 1,
- RELD = 2,
- RELU = 3,
-};
-
-int modemap[4] = { 0, 1, -1, 2, };
-
-typedef struct Reloc Reloc;
-
-struct Reloc
-{
- int n;
- int t;
- uchar *m;
- uint32 *a;
-};
-
-Reloc rels;
-
-static void
-grow(Reloc *r)
-{
- int t;
- uchar *m, *nm;
- uint32 *a, *na;
-
- t = r->t;
- r->t += 64;
- m = r->m;
- a = r->a;
- r->m = nm = mal(r->t*sizeof(uchar));
- r->a = na = mal(r->t*sizeof(uint32));
- memmove(nm, m, t*sizeof(uchar));
- memmove(na, a, t*sizeof(uint32));
- free(m);
- free(a);
-}
-
-void
-dynreloc(Sym *s, uint32 v, int abs)
-{
- int i, k, n;
- uchar *m;
- uint32 *a;
- Reloc *r;
-
- if(s->type == SUNDEF)
- k = abs ? ABSU : RELU;
- else
- k = abs ? ABSD : RELD;
- /* Bprint(&bso, "R %s a=%ld(%lx) %d\n", s->name, v, v, k); */
- k = modemap[k];
- r = &rels;
- n = r->n;
- if(n >= r->t)
- grow(r);
- m = r->m;
- a = r->a;
- for(i = n; i > 0; i--){
- if(v < a[i-1]){ /* happens occasionally for data */
- m[i] = m[i-1];
- a[i] = a[i-1];
- }
- else
- break;
- }
- m[i] = k;
- a[i] = v;
- r->n++;
-}
-
-static int
-sput(char *s)
-{
- char *p;
-
- p = s;
- while(*s)
- cput(*s++);
- cput(0);
- return s-p+1;
-}
-
-void
-asmdyn()
-{
- int i, n, t, c;
- Sym *s;
- uint32 la, ra, *a;
- vlong off;
- uchar *m;
- Reloc *r;
-
- cflush();
- off = seek(cout, 0, 1);
- lputb(0);
- t = 0;
- lputb(imports);
- t += 4;
- for(i = 0; i < NHASH; i++)
- for(s = hash[i]; s != S; s = s->link)
- if(s->type == SUNDEF){
- lputb(s->sig);
- t += 4;
- t += sput(s->name);
- }
-
- la = 0;
- r = &rels;
- n = r->n;
- m = r->m;
- a = r->a;
- lputb(n);
- t += 4;
- for(i = 0; i < n; i++){
- ra = *a-la;
- if(*a < la)
- diag("bad relocation order");
- if(ra < 256)
- c = 0;
- else if(ra < 65536)
- c = 1;
- else
- c = 2;
- cput((c<<6)|*m++);
- t++;
- if(c == 0){
- cput(ra);
- t++;
- }
- else if(c == 1){
- wputb(ra);
- t += 2;
- }
- else{
- lputb(ra);
- t += 4;
- }
- la = *a++;
- }
-
- cflush();
- seek(cout, off, 0);
- lputb(t);
-
- if(debug['v']){
- Bprint(&bso, "import table entries = %d\n", imports);
- Bprint(&bso, "export table entries = %d\n", exports);
- }
-}
diff --git a/src/cmd/8a/Makefile b/src/cmd/8a/Makefile
index beb575544..78d361dbd 100644
--- a/src/cmd/8a/Makefile
+++ b/src/cmd/8a/Makefile
@@ -2,10 +2,10 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.conf
+include ../../Make.inc
+O:=$(HOST_O)
-TARG=\
- 8a\
+TARG=8a
HFILES=\
a.h\
@@ -20,21 +20,6 @@ OFILES=\
YFILES=\
a.y\
-$(TARG): $(OFILES)
- $(LD) -o $(TARG) -L"$(GOROOT)"/lib $(OFILES) -lbio -l9
-
-$(OFILES): $(HFILES)
+include ../../Make.ccmd
lex.$O: ../cc/macbody ../cc/lexbody
-
-y.tab.h: $(YFILES)
- bison -y $(YFLAGS) $(YFILES)
-
-y.tab.c: y.tab.h
- test -f y.tab.c && touch y.tab.c
-
-clean:
- rm -f *.$O $(TARG) *.6 enam.c 6.out a.out y.tab.h y.tab.c
-
-install: $(TARG)
- cp $(TARG) "$(GOBIN)"/$(TARG)
diff --git a/src/cmd/8a/a.h b/src/cmd/8a/a.h
index 035db2551..fe6b17280 100644
--- a/src/cmd/8a/a.h
+++ b/src/cmd/8a/a.h
@@ -1,7 +1,7 @@
// Inferno utils/8a/a.h
// http://code.google.com/p/inferno-os/source/browse/utils/8a/a.h
//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
@@ -50,7 +50,7 @@ typedef struct Ref Ref;
typedef struct Gen Gen;
typedef struct Io Io;
typedef struct Hist Hist;
-typedef struct Gen2 Gen2;
+typedef struct Gen2 Gen2;
#define MAXALIGN 7
#define FPCHIP 1
@@ -162,6 +162,7 @@ EXTERN int pass;
EXTERN char* pathname;
EXTERN int32 pc;
EXTERN int peekc;
+EXTERN int32 stmtline;
EXTERN int sym;
EXTERN char* symb;
EXTERN int thechar;
@@ -169,9 +170,9 @@ EXTERN char* thestring;
EXTERN int32 thunk;
EXTERN Biobuf obuf;
-void* alloc(int32);
+void* alloc(int32);
void* allocn(void*, int32, int32);
-void ensuresymb(int32);
+void ensuresymb(int32);
void errorexit(void);
void pushio(void);
void newio(void);
diff --git a/src/cmd/8a/a.y b/src/cmd/8a/a.y
index 8bc96cce5..04662f83d 100644
--- a/src/cmd/8a/a.y
+++ b/src/cmd/8a/a.y
@@ -1,7 +1,7 @@
// Inferno utils/8a/a.y
// http://code.google.com/p/inferno-os/source/browse/utils/8a/a.y
//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
@@ -64,7 +64,11 @@
%type <gen2> spec1 spec2 spec3 spec4 spec5 spec6 spec7 spec8
%%
prog:
-| prog line
+| prog
+ {
+ stmtline = lineno;
+ }
+ line
line:
LLAB ':'
diff --git a/src/cmd/8a/lex.c b/src/cmd/8a/lex.c
index c8127bde9..bf298b266 100644
--- a/src/cmd/8a/lex.c
+++ b/src/cmd/8a/lex.c
@@ -1,7 +1,7 @@
// Inferno utils/8a/lex.c
// http://code.google.com/p/inferno-os/source/browse/utils/8a/lex.c
//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
@@ -925,10 +925,10 @@ jackpot:
}
Bputc(&obuf, a);
Bputc(&obuf, a>>8);
- Bputc(&obuf, lineno);
- Bputc(&obuf, lineno>>8);
- Bputc(&obuf, lineno>>16);
- Bputc(&obuf, lineno>>24);
+ Bputc(&obuf, stmtline);
+ Bputc(&obuf, stmtline>>8);
+ Bputc(&obuf, stmtline>>16);
+ Bputc(&obuf, stmtline>>24);
zaddr(&g2->from, sf);
zaddr(&g2->to, st);
diff --git a/src/cmd/8c/Makefile b/src/cmd/8c/Makefile
index 85ea3013b..60f46d3c9 100644
--- a/src/cmd/8c/Makefile
+++ b/src/cmd/8c/Makefile
@@ -2,10 +2,10 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.conf
+include ../../Make.inc
+O:=$(HOST_O)
-TARG=\
- 8c\
+TARG=8c
HFILES=\
gc.h\
@@ -29,18 +29,9 @@ OFILES=\
../8l/enam.$O\
LIB=\
- ../cc/cc.a$O
+ ../cc/cc.a\
-$(TARG): $(OFILES) $(LIB)
- $(LD) -o $(TARG) -L"$(GOROOT)"/lib $(OFILES) $(LIB) -lm -lbio -l9
-
-$(OFILES): $(HFILES)
-
-clean:
- rm -f *.$O $(TARG) *.8 8.out a.out
-
-install: $(TARG)
- cp $(TARG) "$(GOBIN)"/$(TARG)
+include ../../Make.ccmd
%.$O: ../cc/%.c
- $(CC) $(CFLAGS) -c -I. -o $@ ../cc/$*.c
+ $(HOST_CC) $(HOST_CFLAGS) -c -I. -o $@ ../cc/$*.c
diff --git a/src/cmd/8c/cgen64.c b/src/cmd/8c/cgen64.c
index ce1512c51..3424f762c 100644
--- a/src/cmd/8c/cgen64.c
+++ b/src/cmd/8c/cgen64.c
@@ -57,7 +57,7 @@ vaddr(Node *n, int a)
int32
hi64v(Node *n)
{
- if(align(0, types[TCHAR], Aarg1)) /* isbigendian */
+ if(align(0, types[TCHAR], Aarg1, nil)) /* isbigendian */
return (int32)(n->vconst) & ~0L;
else
return (int32)((uvlong)n->vconst>>32) & ~0L;
@@ -66,7 +66,7 @@ hi64v(Node *n)
int32
lo64v(Node *n)
{
- if(align(0, types[TCHAR], Aarg1)) /* isbigendian */
+ if(align(0, types[TCHAR], Aarg1, nil)) /* isbigendian */
return (int32)((uvlong)n->vconst>>32) & ~0L;
else
return (int32)(n->vconst) & ~0L;
diff --git a/src/cmd/8c/div.c b/src/cmd/8c/div.c
index 538e3522c..14945052e 100644
--- a/src/cmd/8c/div.c
+++ b/src/cmd/8c/div.c
@@ -120,7 +120,7 @@ sdivgen(Node *l, Node *r, Node *ax, Node *dx)
if(c < 0)
c = -c;
a = sdiv(c, &m, &s);
-//print("a=%d i=%ld s=%d m=%lux\n", a, (int32)r->vconst, s, m);
+//print("a=%d i=%d s=%d m=%ux\n", a, (int32)r->vconst, s, m);
gins(AMOVL, nodconst(m), ax);
gins(AIMULL, l, Z);
gins(AMOVL, l, ax);
@@ -141,7 +141,7 @@ udivgen(Node *l, Node *r, Node *ax, Node *dx)
Node nod;
a = udiv(r->vconst, &m, &s, &t);
-//print("a=%ud i=%ld p=%d s=%d m=%lux\n", a, (int32)r->vconst, t, s, m);
+//print("a=%ud i=%d p=%d s=%d m=%ux\n", a, (int32)r->vconst, t, s, m);
if(t != 0) {
gins(AMOVL, l, ax);
gins(ASHRL, nodconst(t), ax);
diff --git a/src/cmd/8c/list.c b/src/cmd/8c/list.c
index 6caafd258..c422905cd 100644
--- a/src/cmd/8c/list.c
+++ b/src/cmd/8c/list.c
@@ -76,15 +76,27 @@ Pconv(Fmt *fp)
Prog *p;
p = va_arg(fp->args, Prog*);
- if(p->as == ADATA)
- sprint(str, " %A %D/%d,%D",
- p->as, &p->from, p->from.scale, &p->to);
- else if(p->as == ATEXT)
- sprint(str, " %A %D,%d,%D",
- p->as, &p->from, p->from.scale, &p->to);
- else
- sprint(str, " %A %D,%D",
- p->as, &p->from, &p->to);
+ switch(p->as) {
+ case ADATA:
+ sprint(str, "(%L) %A %D/%d,%D",
+ p->lineno, p->as, &p->from, p->from.scale, &p->to);
+ break;
+
+ case ATEXT:
+ if(p->from.scale) {
+ sprint(str, "(%L) %A %D,%d,%lD",
+ p->lineno, p->as, &p->from, p->from.scale, &p->to);
+ break;
+ }
+ sprint(str, "(%L) %A %D,%lD",
+ p->lineno, p->as, &p->from, &p->to);
+ break;
+
+ default:
+ sprint(str, "(%L) %A %D,%lD",
+ p->lineno, p->as, &p->from, &p->to);
+ break;
+ }
return fmtstrcpy(fp, str);
}
diff --git a/src/cmd/8c/mul.c b/src/cmd/8c/mul.c
index 2b7332d54..a0742807e 100644
--- a/src/cmd/8c/mul.c
+++ b/src/cmd/8c/mul.c
@@ -355,7 +355,7 @@ mulgen1(uint32 v, Node *n)
mulparam(v, p);
found:
-// print("v=%.lx a=%d n=%d s=%d g=%d o=%d \n", p->value, p->alg, p->neg, p->shift, p->arg, p->off);
+// print("v=%.x a=%d n=%d s=%d g=%d o=%d \n", p->value, p->alg, p->neg, p->shift, p->arg, p->off);
if(p->alg < 0)
return 0;
diff --git a/src/cmd/8c/reg.c b/src/cmd/8c/reg.c
index 837da2d04..6ba07bed2 100644
--- a/src/cmd/8c/reg.c
+++ b/src/cmd/8c/reg.c
@@ -382,7 +382,7 @@ regopt(Prog *p)
if(debug['R'] && debug['v']) {
print("\nlooping structure:\n");
for(r = firstr; r != R; r = r->link) {
- print("%ld:%P", r->loop, r->prog);
+ print("%d:%P", r->loop, r->prog);
for(z=0; z<BITS; z++)
bit.b[z] = r->use1.b[z] |
r->use2.b[z] |
@@ -1031,7 +1031,7 @@ paint1(Reg *r, int bn)
if(LOAD(r) & ~(r->set.b[z]&~(r->use1.b[z]|r->use2.b[z])) & bb) {
change -= CLOAD * r->loop;
if(debug['R'] && debug['v'])
- print("%ld%P\tld %B $%d\n", r->loop,
+ print("%d%P\td %B $%d\n", r->loop,
r->prog, blsh(bn), change);
}
for(;;) {
@@ -1044,7 +1044,7 @@ paint1(Reg *r, int bn)
if(BtoR(bb) != D_F0)
change = -CINF;
if(debug['R'] && debug['v'])
- print("%ld%P\tu1 %B $%d\n", r->loop,
+ print("%d%P\tu1 %B $%d\n", r->loop,
p, blsh(bn), change);
}
@@ -1054,7 +1054,7 @@ paint1(Reg *r, int bn)
if(BtoR(bb) != D_F0)
change = -CINF;
if(debug['R'] && debug['v'])
- print("%ld%P\tu2 %B $%d\n", r->loop,
+ print("%d%P\tu2 %B $%d\n", r->loop,
p, blsh(bn), change);
}
@@ -1064,7 +1064,7 @@ paint1(Reg *r, int bn)
if(BtoR(bb) != D_F0)
change = -CINF;
if(debug['R'] && debug['v'])
- print("%ld%P\tst %B $%d\n", r->loop,
+ print("%d%P\tst %B $%d\n", r->loop,
p, blsh(bn), change);
}
diff --git a/src/cmd/8c/swt.c b/src/cmd/8c/swt.c
index 1c502f5ff..be48885f8 100644
--- a/src/cmd/8c/swt.c
+++ b/src/cmd/8c/swt.c
@@ -40,7 +40,7 @@ swit1(C1 *q, int nc, int32 def, Node *n)
if(nc < 5) {
for(i=0; i<nc; i++) {
if(debug['W'])
- print("case = %.8lux\n", q->val);
+ print("case = %.8ux\n", q->val);
gopcode(OEQ, n->type, n, nodconst(q->val));
patch(p, q->label);
q++;
@@ -52,7 +52,7 @@ swit1(C1 *q, int nc, int32 def, Node *n)
i = nc / 2;
r = q+i;
if(debug['W'])
- print("case > %.8lux\n", r->val);
+ print("case > %.8ux\n", r->val);
gopcode(OGT, n->type, n, nodconst(r->val));
sp = p;
gbranch(OGOTO);
@@ -61,7 +61,7 @@ swit1(C1 *q, int nc, int32 def, Node *n)
swit1(q, i, def, n);
if(debug['W'])
- print("case < %.8lux\n", r->val);
+ print("case < %.8ux\n", r->val);
patch(sp, pc);
swit1(r+1, nc-i-1, def, n);
}
@@ -501,7 +501,7 @@ zaddr(Biobuf *b, Adr *a, int s)
}
int32
-align(int32 i, Type *t, int op)
+align(int32 i, Type *t, int op, int32 *maxalign)
{
int32 o;
Type *v;
@@ -515,7 +515,9 @@ align(int32 i, Type *t, int op)
break;
case Asu2: /* padding at end of a struct */
- w = SZ_LONG;
+ w = *maxalign;
+ if(w < 1)
+ w = 1;
if(packflg)
w = packflg;
break;
@@ -523,10 +525,16 @@ align(int32 i, Type *t, int op)
case Ael1: /* initial align of struct element */
for(v=t; v->etype==TARRAY; v=v->link)
;
- w = ewidth[v->etype];
- if(w <= 0 || w >= SZ_LONG)
- w = SZ_LONG;
- if(packflg)
+ if(v->etype == TSTRUCT || v->etype == TUNION)
+ w = v->align;
+ else {
+ w = ewidth[v->etype];
+ if(w == 8)
+ w = 4;
+ }
+ if(w < 1 || w > SZ_LONG)
+ fatal(Z, "align");
+ if(packflg)
w = packflg;
break;
@@ -536,8 +544,8 @@ align(int32 i, Type *t, int op)
case Aarg0: /* initial passbyptr argument in arg list */
if(typesuv[t->etype]) {
- o = align(o, types[TIND], Aarg1);
- o = align(o, types[TIND], Aarg2);
+ o = align(o, types[TIND], Aarg1, nil);
+ o = align(o, types[TIND], Aarg2, nil);
}
break;
@@ -558,13 +566,15 @@ align(int32 i, Type *t, int op)
break;
case Aaut3: /* total align of automatic */
- o = align(o, t, Ael1);
- o = align(o, t, Ael2);
+ o = align(o, t, Ael1, nil);
+ o = align(o, t, Ael2, nil);
break;
}
o = xround(o, w);
+ if(maxalign && *maxalign < w)
+ *maxalign = w;
if(debug['A'])
- print("align %s %ld %T = %ld\n", bnames[op], i, t, o);
+ print("align %s %d %T = %d\n", bnames[op], i, t, o);
return o;
}
diff --git a/src/cmd/8c/txt.c b/src/cmd/8c/txt.c
index 194599c3a..0dd387d11 100644
--- a/src/cmd/8c/txt.c
+++ b/src/cmd/8c/txt.c
@@ -385,7 +385,7 @@ err:
void
regsalloc(Node *n, Node *nn)
{
- cursafe = align(cursafe, nn->type, Aaut3);
+ cursafe = align(cursafe, nn->type, Aaut3, nil);
maxargsafe = maxround(maxargsafe, cursafe+curarg);
*n = *nodsafe;
n->xoffset = -(stkoff + cursafe);
@@ -399,22 +399,22 @@ regaalloc1(Node *n, Node *nn)
{
nodreg(n, nn, REGARG);
reg[REGARG]++;
- curarg = align(curarg, nn->type, Aarg1);
- curarg = align(curarg, nn->type, Aarg2);
+ curarg = align(curarg, nn->type, Aarg1, nil);
+ curarg = align(curarg, nn->type, Aarg2, nil);
maxargsafe = maxround(maxargsafe, cursafe+curarg);
}
void
regaalloc(Node *n, Node *nn)
{
- curarg = align(curarg, nn->type, Aarg1);
+ curarg = align(curarg, nn->type, Aarg1, nil);
*n = *nn;
n->op = OINDREG;
n->reg = REGSP;
n->xoffset = curarg;
n->complex = 0;
n->addable = 20;
- curarg = align(curarg, nn->type, Aarg2);
+ curarg = align(curarg, nn->type, Aarg2, nil);
maxargsafe = maxround(maxargsafe, cursafe+curarg);
}
@@ -1403,7 +1403,6 @@ exreg(Type *t)
return o+1; // +1 to avoid 0 == failure; naddr case OEXREG will -1.
}
- USED(t);
return 0;
}
diff --git a/src/cmd/8g/Makefile b/src/cmd/8g/Makefile
index d2431182f..09cf8d4e3 100644
--- a/src/cmd/8g/Makefile
+++ b/src/cmd/8g/Makefile
@@ -2,10 +2,10 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.conf
+include ../../Make.inc
+O:=$(HOST_O)
-TARG=\
- 8g
+TARG=8g
HFILES=\
../gc/go.h\
@@ -27,18 +27,9 @@ OFILES=\
reg.$O\
LIB=\
- ../gc/gc.a$O
+ ../gc/gc.a\
-$(TARG): $(OFILES) $(LIB)
- $(LD) -o $(TARG) -L"$(GOROOT)"/lib $(OFILES) $(LIB) -lbio -l9 -lm
-
-$(OFILES): $(HFILES)
-
-clean:
- rm -f *.$O $(TARG) *.8 enam.c 8.out a.out
-
-install: $(TARG)
- cp $(TARG) "$(GOBIN)"/$(TARG)
+include ../../Make.ccmd
%.$O: ../gc/%.c
- $(CC) $(CFLAGS) -c -I. -o $@ ../gc/$*.c
+ $(HOST_CC) $(HOST_CFLAGS) -c -I. -o $@ ../gc/$*.c
diff --git a/src/cmd/8g/cgen.c b/src/cmd/8g/cgen.c
index 8fbdc6ee7..875d434fa 100644
--- a/src/cmd/8g/cgen.c
+++ b/src/cmd/8g/cgen.c
@@ -175,7 +175,7 @@ cgen(Node *n, Node *res)
case OREAL:
case OIMAG:
case OCMPLX:
- // TODO compile complex
+ fatal("unexpected complex");
return;
// these call bgen to get a bool value
@@ -230,8 +230,8 @@ cgen(Node *n, Node *res)
cgen(nl, res);
break;
}
- mgen(nl, &n1, res);
tempname(&n2, n->type);
+ mgen(nl, &n1, res);
gmove(&n1, &n2);
gmove(&n2, res);
mfree(&n1);
@@ -392,23 +392,16 @@ uop: // unary
gmove(&n1, res);
return;
-flt: // floating-point. 387 (not SSE2) to interoperate with 6c
+flt: // floating-point. 387 (not SSE2) to interoperate with 8c
nodreg(&f0, nl->type, D_F0);
nodreg(&f1, n->type, D_F0+1);
if(nr != N)
goto flt2;
- if(n->op == OMINUS) {
- nr = nodintconst(-1);
- convlit(&nr, n->type);
- n->op = OMUL;
- goto flt2;
- }
-
// unary
cgen(nl, &f0);
if(n->op != OCONV && n->op != OPLUS)
- gins(foptoas(n->op, n->type, 0), &f0, &f0);
+ gins(foptoas(n->op, n->type, 0), N, N);
gmove(&f0, res);
return;
@@ -525,9 +518,11 @@ agen(Node *n, Node *res)
p2 = nil; // to be patched to panicindex.
w = n->type->width;
if(nr->addable) {
- agenr(nl, &n3, res);
- if(!isconst(nr, CTINT)) {
+ if(!isconst(nr, CTINT))
tempname(&tmp, types[TINT32]);
+ if(!isconst(nl, CTSTR))
+ agenr(nl, &n3, res);
+ if(!isconst(nr, CTINT)) {
p2 = cgenindex(nr, &tmp);
regalloc(&n1, tmp.type, N);
gmove(&tmp, &n1);
@@ -539,13 +534,16 @@ agen(Node *n, Node *res)
regalloc(&n1, tmp.type, N);
gmove(&tmp, &n1);
}
- regalloc(&n3, types[tptr], res);
- agen(nl, &n3);
+ if(!isconst(nl, CTSTR)) {
+ regalloc(&n3, types[tptr], res);
+ agen(nl, &n3);
+ }
} else {
tempname(&tmp, types[TINT32]);
p2 = cgenindex(nr, &tmp);
nr = &tmp;
- agenr(nl, &n3, res);
+ if(!isconst(nl, CTSTR))
+ agenr(nl, &n3, res);
regalloc(&n1, tmp.type, N);
gins(optoas(OAS, tmp.type), &tmp, &n1);
}
@@ -556,7 +554,7 @@ agen(Node *n, Node *res)
// explicit check for nil if array is large enough
// that we might derive too big a pointer.
- if(!isslice(nl->type) && nl->type->width >= unmappedzero) {
+ if(isfixedarray(nl->type) && nl->type->width >= unmappedzero) {
regalloc(&n4, types[tptr], &n3);
gmove(&n3, &n4);
n4.op = OINDREG;
@@ -571,9 +569,10 @@ agen(Node *n, Node *res)
// constant index
if(isconst(nr, CTINT)) {
+ if(isconst(nl, CTSTR))
+ fatal("constant string constant index");
v = mpgetfix(nr->val.u.xval);
- if(isslice(nl->type)) {
-
+ if(isslice(nl->type) || nl->type->etype == TSTRING) {
if(!debug['B'] && !n->etype) {
n1 = n3;
n1.op = OINDREG;
@@ -591,13 +590,6 @@ agen(Node *n, Node *res)
n1.type = types[tptr];
n1.xoffset = Array_array;
gmove(&n1, &n3);
- } else
- if(!debug['B'] && !n->etype) {
- if(v < 0)
- yyerror("out of bounds on array");
- else
- if(v >= nl->type->bound)
- yyerror("out of bounds on array");
}
nodconst(&n2, types[tptr], v*w);
@@ -614,7 +606,9 @@ agen(Node *n, Node *res)
if(!debug['B'] && !n->etype) {
// check bounds
- if(isslice(nl->type)) {
+ if(isconst(nl, CTSTR))
+ nodconst(&n1, types[TUINT32], nl->val.u.sval->len);
+ else if(isslice(nl->type) || nl->type->etype == TSTRING) {
n1 = n3;
n1.op = OINDREG;
n1.type = types[tptr];
@@ -628,8 +622,17 @@ agen(Node *n, Node *res)
ginscall(panicindex, 0);
patch(p1, pc);
}
+
+ if(isconst(nl, CTSTR)) {
+ regalloc(&n3, types[tptr], res);
+ p1 = gins(ALEAL, N, &n3);
+ datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from);
+ p1->from.scale = 1;
+ p1->from.index = n2.val.u.reg;
+ goto indexdone;
+ }
- if(isslice(nl->type)) {
+ if(isslice(nl->type) || nl->type->etype == TSTRING) {
n1 = n3;
n1.op = OINDREG;
n1.type = types[tptr];
@@ -649,6 +652,7 @@ agen(Node *n, Node *res)
gmove(&n3, res);
}
+ indexdone:
gmove(&n3, res);
regfree(&n2);
regfree(&n3);
@@ -724,8 +728,14 @@ igen(Node *n, Node *a, Node *res)
{
Node n1;
+ // release register for now, to avoid
+ // confusing tempname.
+ if(res != N && res->op == OREGISTER)
+ reg[res->val.u.reg]--;
tempname(&n1, types[tptr]);
agen(n, &n1);
+ if(res != N && res->op == OREGISTER)
+ reg[res->val.u.reg]++;
regalloc(a, types[tptr], res);
gmove(&n1, a);
a->op = OINDREG;
@@ -768,6 +778,9 @@ bgen(Node *n, int true, Prog *to)
if(n == N)
n = nodbool(1);
+ if(n->ninit != nil)
+ genlist(n->ninit);
+
nl = n->left;
nr = n->right;
diff --git a/src/cmd/8g/galign.c b/src/cmd/8g/galign.c
index 346647205..1c14dfe47 100644
--- a/src/cmd/8g/galign.c
+++ b/src/cmd/8g/galign.c
@@ -25,7 +25,6 @@ Typedef typedefs[] =
void
betypeinit(void)
{
- maxround = 4;
widthptr = 4;
zprog.link = P;
diff --git a/src/cmd/8g/ggen.c b/src/cmd/8g/ggen.c
index 8a55ffd59..4dcbd4489 100644
--- a/src/cmd/8g/ggen.c
+++ b/src/cmd/8g/ggen.c
@@ -8,7 +8,6 @@
#include "opt.h"
static Prog *pret;
-static Node *naclnop;
void
compile(Node *fn)
@@ -24,7 +23,6 @@ compile(Node *fn)
newproc = sysfunc("newproc");
deferproc = sysfunc("deferproc");
deferreturn = sysfunc("deferreturn");
- naclnop = sysfunc("naclnop");
panicindex = sysfunc("panicindex");
panicslice = sysfunc("panicslice");
throwreturn = sysfunc("throwreturn");
@@ -64,6 +62,8 @@ compile(Node *fn)
pl = newplist();
pl->name = curfn->nname;
+ setlineno(curfn);
+
nodconst(&nod1, types[TINT32], 0);
ptxt = gins(ATEXT, curfn->nname, &nod1);
afunclit(&ptxt->from);
@@ -85,6 +85,8 @@ compile(Node *fn)
checklabels();
if(nerrors != 0)
goto ret;
+ if(curfn->endlineno)
+ lineno = curfn->endlineno;
if(curfn->type->outtuple != 0)
ginscall(throwreturn, 0);
@@ -92,21 +94,13 @@ compile(Node *fn)
if(pret)
patch(pret, pc);
ginit();
+ if(hasdefer)
+ ginscall(deferreturn, 0);
if(curfn->exit)
genlist(curfn->exit);
gclean();
if(nerrors != 0)
goto ret;
- if(hasdefer) {
- // On Native client, insert call to no-op function
- // to force alignment immediately before call to deferreturn,
- // so that when jmpdefer subtracts 5 from the second CALL's
- // return address and then the return masks off the low bits,
- // we'll back up to the NOPs immediately after the dummy CALL.
- if(strcmp(getgoos(), "nacl") == 0)
- ginscall(naclnop, 0);
- ginscall(deferreturn, 0);
- }
pc->as = ARET; // overwrite AEND
pc->lineno = lineno;
@@ -114,12 +108,12 @@ compile(Node *fn)
regopt(ptxt);
}
// fill in argument size
- ptxt->to.offset2 = rnd(curfn->type->argwid, maxround);
+ ptxt->to.offset2 = rnd(curfn->type->argwid, widthptr);
// fill in final stack size
if(stksize > maxstksize)
maxstksize = stksize;
- ptxt->to.offset = rnd(maxstksize+maxarg, maxround);
+ ptxt->to.offset = rnd(maxstksize+maxarg, widthptr);
maxstksize = 0;
if(debug['f'])
@@ -789,25 +783,58 @@ regcmp(const void *va, const void *vb)
static Prog* throwpc;
+// We're only going to bother inlining if we can
+// convert all the arguments to 32 bits safely. Can we?
+static int
+fix64(NodeList *nn, int n)
+{
+ NodeList *l;
+ Node *r;
+ int i;
+
+ l = nn;
+ for(i=0; i<n; i++) {
+ r = l->n->right;
+ if(is64(r->type) && !smallintconst(r)) {
+ if(r->op == OCONV)
+ r = r->left;
+ if(is64(r->type))
+ return 0;
+ }
+ l = l->next;
+ }
+ return 1;
+}
+
void
getargs(NodeList *nn, Node *reg, int n)
{
NodeList *l;
+ Node *r;
int i;
throwpc = nil;
l = nn;
for(i=0; i<n; i++) {
- if(!smallintconst(l->n->right) && !isslice(l->n->right->type)) {
+ r = l->n->right;
+ if(is64(r->type)) {
+ if(r->op == OCONV)
+ r = r->left;
+ else if(smallintconst(r))
+ r->type = types[TUINT32];
+ if(is64(r->type))
+ fatal("getargs");
+ }
+ if(!smallintconst(r) && !isslice(r->type)) {
if(i < 3) // AX CX DX
- nodreg(reg+i, l->n->right->type, D_AX+i);
+ nodreg(reg+i, r->type, D_AX+i);
else
reg[i].op = OXXX;
- regalloc(reg+i, l->n->right->type, reg+i);
- cgen(l->n->right, reg+i);
+ regalloc(reg+i, r->type, reg+i);
+ cgen(r, reg+i);
} else
- reg[i] = *l->n->right;
+ reg[i] = *r;
if(reg[i].local != 0)
yyerror("local used");
reg[i].local = l->n->left->xoffset;
@@ -821,44 +848,53 @@ getargs(NodeList *nn, Node *reg, int n)
void
cmpandthrow(Node *nl, Node *nr)
{
- vlong cl, cr;
+ vlong cl;
Prog *p1;
int op;
- Node *c;
+ Node *c, n1;
+ Type *t;
op = OLE;
if(smallintconst(nl)) {
cl = mpgetfix(nl->val.u.xval);
if(cl == 0)
return;
- if(smallintconst(nr)) {
- cr = mpgetfix(nr->val.u.xval);
- if(cl > cr) {
- if(throwpc == nil) {
- throwpc = pc;
- ginscall(panicslice, 0);
- } else
- patch(gbranch(AJMP, T), throwpc);
- }
+ if(smallintconst(nr))
return;
- }
-
// put the constant on the right
op = brrev(op);
c = nl;
nl = nr;
nr = c;
}
-
- gins(optoas(OCMP, types[TUINT32]), nl, nr);
+
+ // Arguments are known not to be 64-bit,
+ // but they might be smaller than 32 bits.
+ // Check if we need to use a temporary.
+ // At least one of the arguments is 32 bits
+ // (the len or cap) so one temporary suffices.
+ n1.op = OXXX;
+ t = types[TUINT32];
+ if(nl->type->width != t->width) {
+ regalloc(&n1, t, nl);
+ gmove(nl, &n1);
+ nl = &n1;
+ } else if(nr->type->width != t->width) {
+ regalloc(&n1, t, nr);
+ gmove(nr, &n1);
+ nr = &n1;
+ }
+ gins(optoas(OCMP, t), nl, nr);
+ if(n1.op != OXXX)
+ regfree(&n1);
if(throwpc == nil) {
- p1 = gbranch(optoas(op, types[TUINT32]), T);
+ p1 = gbranch(optoas(op, t), T);
throwpc = pc;
ginscall(panicslice, 0);
patch(p1, pc);
} else {
op = brcom(op);
- p1 = gbranch(optoas(op, types[TUINT32]), T);
+ p1 = gbranch(optoas(op, t), T);
patch(p1, throwpc);
}
}
@@ -889,6 +925,8 @@ cgen_inline(Node *n, Node *res)
goto no;
if(!n->left->addable)
goto no;
+ if(n->left->sym == S)
+ goto no;
if(n->left->sym->pkg != runtimepkg)
goto no;
if(strcmp(n->left->sym->name, "slicearray") == 0)
@@ -906,6 +944,8 @@ cgen_inline(Node *n, Node *res)
slicearray:
if(!sleasy(res))
goto no;
+ if(!fix64(n->list, 5))
+ goto no;
getargs(n->list, nodes, 5);
// if(hb[3] > nel[1]) goto throw
@@ -988,6 +1028,8 @@ slicearray:
return 1;
sliceslice:
+ if(!fix64(n->list, narg))
+ goto no;
ntemp.op = OXXX;
if(!sleasy(n->list->n->right)) {
Node *n0;
@@ -1016,6 +1058,7 @@ sliceslice:
// if(lb[1] > old.nel[0]) goto throw;
n2 = nodes[0];
n2.xoffset += Array_nel;
+ n2.type = types[TUINT32];
cmpandthrow(&nodes[1], &n2);
// ret.nel = old.nel[0]-lb[1];
@@ -1035,6 +1078,7 @@ sliceslice:
// if(hb[2] > old.cap[0]) goto throw;
n2 = nodes[0];
n2.xoffset += Array_cap;
+ n2.type = types[TUINT32];
cmpandthrow(&nodes[2], &n2);
// if(lb[1] > hb[2]) goto throw;
diff --git a/src/cmd/8g/gobj.c b/src/cmd/8g/gobj.c
index 1f4b106f7..e48ad529b 100644
--- a/src/cmd/8g/gobj.c
+++ b/src/cmd/8g/gobj.c
@@ -642,7 +642,7 @@ dsymptr(Sym *s, int off, Sym *x, int xoff)
}
void
-genembedtramp(Type *rcvr, Type *method, Sym *newnam)
+genembedtramp(Type *rcvr, Type *method, Sym *newnam, int iface)
{
Sym *e;
int c, d, o, mov, add, loaded;
@@ -739,7 +739,7 @@ out:
p = pc;
gins(AJMP, N, N);
p->to.type = D_EXTERN;
- p->to.sym = methodsym(method->sym, ptrto(f->type));
+ p->to.sym = methodsym(method->sym, ptrto(f->type), 0);
//print("6. %P\n", p);
pc->as = ARET; // overwrite AEND
diff --git a/src/cmd/8g/gsubr.c b/src/cmd/8g/gsubr.c
index 6890c683e..8ed7e5564 100644
--- a/src/cmd/8g/gsubr.c
+++ b/src/cmd/8g/gsubr.c
@@ -149,6 +149,8 @@ ggloblnod(Node *nam, int32 width)
p->to.sym = S;
p->to.type = D_CONST;
p->to.offset = width;
+ if(nam->readonly)
+ p->from.scale = RODATA;
}
void
@@ -165,6 +167,7 @@ ggloblsym(Sym *s, int32 width, int dupok)
p->to.offset = width;
if(dupok)
p->from.scale = DUPOK;
+ p->from.scale |= RODATA;
}
int
@@ -661,6 +664,11 @@ foptoas(int op, Type *t, int flg)
return AFCOMDP;
case FCASE(OCMP, TFLOAT64, Fpop2):
return AFCOMDPP;
+
+ case FCASE(OMINUS, TFLOAT32, 0):
+ return AFCHS;
+ case FCASE(OMINUS, TFLOAT64, 0):
+ return AFCHS;
}
fatal("foptoas %O %T %#x", op, t, flg);
@@ -707,7 +715,7 @@ gclean(void)
for(i=D_AL; i<=D_DI; i++)
if(reg[i])
- yyerror("reg %R left allocated at %lux", i, regpc[i]);
+ yyerror("reg %R left allocated at %ux", i, regpc[i]);
}
int32
@@ -764,7 +772,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%#lux\n", i, regpc[i]);
+ fprint(2, "\t%R\t%#ux\n", i, regpc[i]);
yyerror("out of fixed registers");
goto err;
@@ -1651,7 +1659,7 @@ checkoffset(Addr *a, int canemitcode)
if(a->offset < unmappedzero)
return;
if(!canemitcode)
- fatal("checkoffset %#llx, cannot emit code", a->offset);
+ fatal("checkoffset %#x, cannot emit code", a->offset);
// cannot rely on unmapped nil page at 0 to catch
// reference with large offset. instead, emit explicit
diff --git a/src/cmd/8g/list.c b/src/cmd/8g/list.c
index 9b3622a6d..edb1ece84 100644
--- a/src/cmd/8g/list.c
+++ b/src/cmd/8g/list.c
@@ -47,24 +47,28 @@ Pconv(Fmt *fp)
{
char str[STRINGSZ];
Prog *p;
+ char scale[40];
p = va_arg(fp->args, Prog*);
sconsize = 8;
+ scale[0] = '\0';
+ if(p->from.scale != 0 && (p->as == AGLOBL || p->as == ATEXT))
+ snprint(scale, sizeof scale, "%d,", p->from.scale);
switch(p->as) {
default:
- snprint(str, sizeof(str), "%.4ld (%L) %-7A %D,%D",
- p->loc, p->lineno, p->as, &p->from, &p->to);
+ snprint(str, sizeof(str), "%.4d (%L) %-7A %D,%s%D",
+ p->loc, p->lineno, p->as, &p->from, scale, &p->to);
break;
case ADATA:
sconsize = p->from.scale;
- snprint(str, sizeof(str), "%.4ld (%L) %-7A %D/%d,%D",
+ snprint(str, sizeof(str), "%.4d (%L) %-7A %D/%d,%D",
p->loc, p->lineno, p->as, &p->from, sconsize, &p->to);
break;
case ATEXT:
- snprint(str, sizeof(str), "%.4ld (%L) %-7A %D,%lD",
- p->loc, p->lineno, p->as, &p->from, &p->to);
+ snprint(str, sizeof(str), "%.4d (%L) %-7A %D,%s%lD",
+ p->loc, p->lineno, p->as, &p->from, scale, &p->to);
break;
}
return fmtstrcpy(fp, str);
diff --git a/src/cmd/8g/reg.c b/src/cmd/8g/reg.c
index 3e57916c7..e1dacf55a 100644
--- a/src/cmd/8g/reg.c
+++ b/src/cmd/8g/reg.c
@@ -612,17 +612,17 @@ brk:
print("\nstats\n");
if(ostats.ncvtreg)
- print(" %4ld cvtreg\n", ostats.ncvtreg);
+ print(" %4d cvtreg\n", ostats.ncvtreg);
if(ostats.nspill)
- print(" %4ld spill\n", ostats.nspill);
+ print(" %4d spill\n", ostats.nspill);
if(ostats.nreload)
- print(" %4ld reload\n", ostats.nreload);
+ print(" %4d reload\n", ostats.nreload);
if(ostats.ndelmov)
- print(" %4ld delmov\n", ostats.ndelmov);
+ print(" %4d delmov\n", ostats.ndelmov);
if(ostats.nvar)
- print(" %4ld delmov\n", ostats.nvar);
+ print(" %4d delmov\n", ostats.nvar);
if(ostats.naddr)
- print(" %4ld delmov\n", ostats.naddr);
+ print(" %4d delmov\n", ostats.naddr);
memset(&ostats, 0, sizeof(ostats));
}
@@ -789,6 +789,8 @@ mkvar(Reg *r, Adr *a)
// if they overlaps, disable both
if(overlap(v->offset, v->width, o, w)) {
+ if(debug['R'])
+ print("disable %s\n", v->sym->name);
v->addr = 1;
flag = 1;
}
@@ -821,7 +823,7 @@ mkvar(Reg *r, Adr *a)
v->addr = flag; // funny punning
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 %S %D flag=%d\n", i, et, w, s, a, v->addr);
ostats.nvar++;
bit = blsh(i);
@@ -1378,7 +1380,7 @@ dumpone(Reg *r)
int z;
Bits bit;
- print("%ld:%P", r->loop, r->prog);
+ print("%d:%P", r->loop, r->prog);
for(z=0; z<BITS; z++)
bit.b[z] =
r->set.b[z] |
@@ -1427,14 +1429,14 @@ dumpit(char *str, Reg *r0)
if(r1 != R) {
print(" pred:");
for(; r1 != R; r1 = r1->p2link)
- print(" %.4lud", r1->prog->loc);
+ print(" %.4ud", r1->prog->loc);
print("\n");
}
// r1 = r->s1;
// if(r1 != R) {
// print(" succ:");
// for(; r1 != R; r1 = r1->s1)
-// print(" %.4lud", r1->prog->loc);
+// print(" %.4ud", r1->prog->loc);
// print("\n");
// }
}
diff --git a/src/cmd/8l/8.out.h b/src/cmd/8l/8.out.h
index c17f606e2..0866f05f0 100644
--- a/src/cmd/8l/8.out.h
+++ b/src/cmd/8l/8.out.h
@@ -33,6 +33,7 @@
#define NOPROF (1<<0)
#define DUPOK (1<<1)
#define NOSPLIT (1<<2)
+#define RODATA (1<<3)
enum as
{
@@ -383,8 +384,8 @@ enum as
AEND,
- ADYNT,
- AINIT,
+ ADYNT_,
+ AINIT_,
ASIGNAME,
@@ -498,6 +499,9 @@ enum
D_CONST2 = D_INDIR+D_INDIR,
D_SIZE, /* 8l internal */
+ D_PCREL,
+ D_GOTOFF,
+ D_GOTREL,
T_TYPE = 1<<0,
T_INDEX = 1<<1,
diff --git a/src/cmd/8l/Makefile b/src/cmd/8l/Makefile
index 88c7c512b..84976ba18 100644
--- a/src/cmd/8l/Makefile
+++ b/src/cmd/8l/Makefile
@@ -2,15 +2,20 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.conf
+include ../../Make.inc
+O:=$(HOST_O)
-TARG=\
- 8l\
+TARG=8l
OFILES=\
asm.$O\
+ data.$O\
+ dwarf.$O\
elf.$O\
enam.$O\
+ go.$O\
+ ldelf.$O\
+ ldmacho.$O\
lib.$O\
list.$O\
macho.$O\
@@ -18,30 +23,26 @@ OFILES=\
optab.$O\
pass.$O\
pe.$O\
+ prof.$O\
span.$O\
- go.$O\
+ symtab.$O\
+
HFILES=\
l.h\
../8l/8.out.h\
+ ../ld/dwarf.h\
../ld/elf.h\
../ld/macho.h\
../ld/pe.h\
-
-$(TARG): $(OFILES)
- $(LD) -o $(TARG) -L"$(GOROOT)"/lib $(OFILES) -lbio -l9
-
-$(OFILES): $(HFILES)
+include ../../Make.ccmd
enam.c: 8.out.h
sh mkenam
-clean:
- rm -f *.$O $(TARG) *.8 enam.c 8.out a.out
+CLEANFILES+=enam.c
-install: $(TARG)
- cp $(TARG) "$(GOBIN)"/$(TARG)
%.$O: ../ld/%.c
- $(CC) $(CFLAGS) -c -I. ../ld/$*.c
+ $(HOST_CC) $(HOST_CFLAGS) -c -I. ../ld/$*.c
diff --git a/src/cmd/8l/asm.c b/src/cmd/8l/asm.c
index a7f894aa2..cdb5a33e6 100644
--- a/src/cmd/8l/asm.c
+++ b/src/cmd/8l/asm.c
@@ -28,9 +28,12 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+// Writing object files.
+
#include "l.h"
#include "../ld/lib.h"
#include "../ld/elf.h"
+#include "../ld/dwarf.h"
#include "../ld/macho.h"
#include "../ld/pe.h"
@@ -38,7 +41,6 @@
char linuxdynld[] = "/lib/ld-linux.so.2";
char freebsddynld[] = "/usr/libexec/ld-elf.so.1";
-uint32 symdatva = SYMDATVA;
int32
entryvalue(void)
@@ -52,15 +54,8 @@ entryvalue(void)
s = lookup(a, 0);
if(s->type == 0)
return INITTEXT;
- switch(s->type) {
- case STEXT:
- break;
- case SDATA:
- if(dlm)
- return s->value+INITDAT;
- default:
+ if(s->type != STEXT)
diag("entry not text: %s", s->name);
- }
return s->value;
}
@@ -103,134 +98,13 @@ vputl(uvlong l)
lputl(l);
}
-void
-strnput(char *s, int n)
-{
- for(; *s && n > 0; s++) {
- cput(*s);
- n--;
- }
- while(n > 0) {
- cput(0);
- n--;
- }
-}
-
-vlong
-addstring(Sym *s, char *str)
-{
- int n, m;
- vlong r;
- Prog *p;
-
- if(s->type == 0)
- s->type = SDATA;
- s->reachable = 1;
- r = s->value;
- n = strlen(str)+1;
- while(n > 0) {
- m = n;
- if(m > sizeof(p->to.scon))
- m = sizeof(p->to.scon);
- p = newdata(s, s->value, m, D_EXTERN);
- p->to.type = D_SCONST;
- memmove(p->to.scon, str, m);
- s->value += m;
- str += m;
- n -= m;
- }
- return r;
-}
-
-vlong
-adduintxx(Sym *s, uint64 v, int wid)
-{
- vlong r;
- Prog *p;
-
- if(s->type == 0)
- s->type = SDATA;
- s->reachable = 1;
- r = s->value;
- p = newdata(s, s->value, wid, D_EXTERN);
- s->value += wid;
- p->to.type = D_CONST;
- p->to.offset = v;
- return r;
-}
-
-vlong
-adduint8(Sym *s, uint8 v)
-{
- return adduintxx(s, v, 1);
-}
-
-vlong
-adduint16(Sym *s, uint16 v)
-{
- return adduintxx(s, v, 2);
-}
-
-vlong
-adduint32(Sym *s, uint32 v)
-{
- return adduintxx(s, v, 4);
-}
-
-vlong
-adduint64(Sym *s, uint64 v)
-{
- return adduintxx(s, v, 8);
-}
-
-vlong
-addaddr(Sym *s, Sym *t)
-{
- vlong r;
- Prog *p;
- enum { Ptrsize = 4 };
-
- if(s->type == 0)
- s->type = SDATA;
- s->reachable = 1;
- r = s->value;
- p = newdata(s, s->value, Ptrsize, D_EXTERN);
- s->value += Ptrsize;
- p->to.type = D_ADDR;
- p->to.index = D_EXTERN;
- p->to.offset = 0;
- p->to.sym = t;
- return r;
-}
-
-vlong
-addsize(Sym *s, Sym *t)
-{
- vlong r;
- Prog *p;
- enum { Ptrsize = 4 };
-
- if(s->type == 0)
- s->type = SDATA;
- s->reachable = 1;
- r = s->value;
- p = newdata(s, s->value, Ptrsize, D_EXTERN);
- s->value += Ptrsize;
- p->to.type = D_SIZE;
- p->to.index = D_EXTERN;
- p->to.offset = 0;
- p->to.sym = t;
- return r;
-}
-
vlong
datoff(vlong addr)
{
- if(addr >= INITDAT) {
- if(HEADTYPE == 8)
- return addr - INITDAT + rnd(HEADR+textsize, 4096);
- return addr - INITDAT + rnd(HEADR+textsize, INITRND);
- }
+ if(addr >= segdata.vaddr)
+ return addr - segdata.vaddr + segdata.fileoff;
+ if(addr >= segtext.vaddr)
+ return addr - segtext.vaddr + segtext.fileoff;
diag("datoff %#llx", addr);
return 0;
}
@@ -252,6 +126,10 @@ enum {
ElfStrGosymtab,
ElfStrGopclntab,
ElfStrShstrtab,
+ ElfStrSymtab,
+ ElfStrStrtab,
+ ElfStrRelPlt,
+ ElfStrPlt,
NElfStr
};
@@ -273,26 +151,424 @@ needlib(char *name)
return 0;
}
+int nelfsym = 1;
+
+static void addpltsym(Sym*);
+static void addgotsym(Sym*);
+
+void
+adddynrel(Sym *s, Reloc *r)
+{
+ Sym *targ, *rel, *got;
+
+ targ = r->sym;
+ cursym = s;
+
+ switch(r->type) {
+ default:
+ if(r->type >= 256) {
+ diag("unexpected relocation type %d", r->type);
+ return;
+ }
+ break;
+
+ // Handle relocations found in ELF object files.
+ case 256 + R_386_PC32:
+ if(targ->dynimpname != nil && !targ->dynexport)
+ diag("unexpected R_386_PC32 relocation for dynamic symbol %s", targ->name);
+ if(targ->type == 0 || targ->type == SXREF)
+ diag("unknown symbol %s in pcrel", targ->name);
+ r->type = D_PCREL;
+ r->add += 4;
+ return;
+
+ case 256 + R_386_PLT32:
+ r->type = D_PCREL;
+ r->add += 4;
+ if(targ->dynimpname != nil && !targ->dynexport) {
+ addpltsym(targ);
+ r->sym = lookup(".plt", 0);
+ r->add += targ->plt;
+ }
+ return;
+
+ case 256 + R_386_GOT32:
+ if(targ->dynimpname == nil || targ->dynexport) {
+ // have symbol
+ // turn MOVL of GOT entry into LEAL of symbol itself
+ if(r->off < 2 || s->p[r->off-2] != 0x8b) {
+ diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name);
+ return;
+ }
+ s->p[r->off-2] = 0x8d;
+ r->type = D_GOTOFF;
+ return;
+ }
+ addgotsym(targ);
+ r->type = D_CONST; // write r->add during relocsym
+ r->sym = S;
+ r->add += targ->got;
+ return;
+
+ case 256 + R_386_GOTOFF:
+ r->type = D_GOTOFF;
+ return;
+
+ case 256 + R_386_GOTPC:
+ r->type = D_PCREL;
+ r->sym = lookup(".got", 0);
+ r->add += 4;
+ return;
+
+ case 256 + R_386_32:
+ if(targ->dynimpname != nil && !targ->dynexport)
+ diag("unexpected R_386_32 relocation for dynamic symbol %s", targ->name);
+ r->type = D_ADDR;
+ return;
+
+ case 512 + MACHO_GENERIC_RELOC_VANILLA*2 + 0:
+ r->type = D_ADDR;
+ if(targ->dynimpname != nil && !targ->dynexport)
+ diag("unexpected reloc for dynamic symbol %s", targ->name);
+ return;
+
+ case 512 + MACHO_GENERIC_RELOC_VANILLA*2 + 1:
+ if(targ->dynimpname != nil && !targ->dynexport) {
+ addpltsym(targ);
+ r->sym = lookup(".plt", 0);
+ r->add = targ->plt;
+ r->type = D_PCREL;
+ return;
+ }
+ r->type = D_PCREL;
+ return;
+
+ case 512 + MACHO_FAKE_GOTPCREL:
+ if(targ->dynimpname == nil || targ->dynexport) {
+ // have symbol
+ // turn MOVL of GOT entry into LEAL of symbol itself
+ if(r->off < 2 || s->p[r->off-2] != 0x8b) {
+ diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name);
+ return;
+ }
+ s->p[r->off-2] = 0x8d;
+ r->type = D_PCREL;
+ return;
+ }
+ addgotsym(targ);
+ r->sym = lookup(".got", 0);
+ r->add += targ->got;
+ r->type = D_PCREL;
+ return;
+ }
+
+ // Handle references to ELF symbols from our own object files.
+ if(targ->dynimpname == nil || targ->dynexport)
+ return;
+
+ switch(r->type) {
+ case D_PCREL:
+ addpltsym(targ);
+ r->sym = lookup(".plt", 0);
+ r->add = targ->plt;
+ return;
+
+ case D_ADDR:
+ if(s->type != SDATA)
+ break;
+ if(iself) {
+ adddynsym(targ);
+ rel = lookup(".rel", 0);
+ addaddrplus(rel, s, r->off);
+ adduint32(rel, ELF32_R_INFO(targ->dynid, R_386_32));
+ r->type = D_CONST; // write r->add during relocsym
+ r->sym = S;
+ return;
+ }
+ if(HEADTYPE == 6 && s->size == PtrSize && r->off == 0) {
+ // Mach-O relocations are a royal pain to lay out.
+ // They use a compact stateful bytecode representation
+ // that is too much bother to deal with.
+ // Instead, interpret the C declaration
+ // void *_Cvar_stderr = &stderr;
+ // as making _Cvar_stderr the name of a GOT entry
+ // for stderr. This is separate from the usual GOT entry,
+ // just in case the C code assigns to the variable,
+ // and of course it only works for single pointers,
+ // but we only need to support cgo and that's all it needs.
+ adddynsym(targ);
+ got = lookup(".got", 0);
+ s->type = got->type | SSUB;
+ s->outer = got;
+ s->sub = got->sub;
+ got->sub = s;
+ s->value = got->size;
+ adduint32(got, 0);
+ adduint32(lookup(".linkedit.got", 0), targ->dynid);
+ r->type = 256; // ignore during relocsym
+ return;
+ }
+ break;
+ }
+
+ cursym = s;
+ diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type);
+}
+
+static void
+elfsetupplt(void)
+{
+ Sym *plt, *got;
+
+ plt = lookup(".plt", 0);
+ got = lookup(".got.plt", 0);
+ if(plt->size == 0) {
+ // pushl got+4
+ adduint8(plt, 0xff);
+ adduint8(plt, 0x35);
+ addaddrplus(plt, got, 4);
+
+ // jmp *got+8
+ adduint8(plt, 0xff);
+ adduint8(plt, 0x25);
+ addaddrplus(plt, got, 8);
+
+ // zero pad
+ adduint32(plt, 0);
+
+ // assume got->size == 0 too
+ addaddrplus(got, lookup(".dynamic", 0), 0);
+ adduint32(got, 0);
+ adduint32(got, 0);
+ }
+}
+
+int
+archreloc(Reloc *r, Sym *s, vlong *val)
+{
+ switch(r->type) {
+ case D_CONST:
+ *val = r->add;
+ return 0;
+ case D_GOTOFF:
+ *val = symaddr(r->sym) + r->add - symaddr(lookup(".got", 0));
+ return 0;
+ }
+ return -1;
+}
+
+static void
+addpltsym(Sym *s)
+{
+ Sym *plt, *got, *rel;
+
+ if(s->plt >= 0)
+ return;
+
+ adddynsym(s);
+
+ if(iself) {
+ plt = lookup(".plt", 0);
+ got = lookup(".got.plt", 0);
+ rel = lookup(".rel.plt", 0);
+ if(plt->size == 0)
+ elfsetupplt();
+
+ // jmpq *got+size
+ adduint8(plt, 0xff);
+ adduint8(plt, 0x25);
+ addaddrplus(plt, got, got->size);
+
+ // add to got: pointer to current pos in plt
+ addaddrplus(got, plt, plt->size);
+
+ // pushl $x
+ adduint8(plt, 0x68);
+ adduint32(plt, rel->size);
+
+ // jmp .plt
+ adduint8(plt, 0xe9);
+ adduint32(plt, -(plt->size+4));
+
+ // rel
+ addaddrplus(rel, got, got->size-4);
+ adduint32(rel, ELF32_R_INFO(s->dynid, R_386_JMP_SLOT));
+
+ s->plt = plt->size - 16;
+ } else if(HEADTYPE == 6) { // Mach-O
+ // Same laziness as in 6l.
+
+ Sym *plt;
+
+ plt = lookup(".plt", 0);
+
+ addgotsym(s);
+
+ adduint32(lookup(".linkedit.plt", 0), s->dynid);
+
+ // jmpq *got+size(IP)
+ s->plt = plt->size;
+
+ adduint8(plt, 0xff);
+ adduint8(plt, 0x25);
+ addaddrplus(plt, lookup(".got", 0), s->got);
+ } else {
+ diag("addpltsym: unsupported binary format");
+ }
+}
+
+static void
+addgotsym(Sym *s)
+{
+ Sym *got, *rel;
+
+ if(s->got >= 0)
+ return;
+
+ adddynsym(s);
+ got = lookup(".got", 0);
+ s->got = got->size;
+ adduint32(got, 0);
+
+ if(iself) {
+ rel = lookup(".rel", 0);
+ addaddrplus(rel, got, s->got);
+ adduint32(rel, ELF32_R_INFO(s->dynid, R_386_GLOB_DAT));
+ } else if(HEADTYPE == 6) { // Mach-O
+ adduint32(lookup(".linkedit.got", 0), s->dynid);
+ } else {
+ diag("addgotsym: unsupported binary format");
+ }
+}
+
+void
+adddynsym(Sym *s)
+{
+ Sym *d, *str;
+ int t;
+ char *name;
+
+ if(s->dynid >= 0)
+ return;
+
+ if(s->dynimpname == nil)
+ diag("adddynsym: no dynamic name for %s", s->name, *(int32*)0);
+
+ if(iself) {
+ s->dynid = nelfsym++;
+
+ d = lookup(".dynsym", 0);
+
+ /* name */
+ name = s->dynimpname;
+ if(name == nil)
+ name = s->name;
+ adduint32(d, addstring(lookup(".dynstr", 0), name));
+
+ /* value */
+ if(s->type == SDYNIMPORT)
+ adduint32(d, 0);
+ else
+ addaddr(d, s);
+
+ /* size */
+ adduint32(d, 0);
+
+ /* type */
+ t = STB_GLOBAL << 4;
+ if(s->dynexport && s->type == STEXT)
+ t |= STT_FUNC;
+ else
+ t |= STT_OBJECT;
+ adduint8(d, t);
+ adduint8(d, 0);
+
+ /* shndx */
+ if(!s->dynexport && s->dynimpname != nil)
+ adduint16(d, SHN_UNDEF);
+ else {
+ switch(s->type) {
+ default:
+ case STEXT:
+ t = 11;
+ break;
+ case SRODATA:
+ t = 12;
+ break;
+ case SDATA:
+ t = 13;
+ break;
+ case SBSS:
+ t = 14;
+ break;
+ }
+ adduint16(d, t);
+ }
+ } else if(HEADTYPE == 6) {
+ // Mach-O symbol nlist32
+ d = lookup(".dynsym", 0);
+ name = s->dynimpname;
+ if(name == nil)
+ name = s->name;
+ s->dynid = d->size/12;
+ // darwin still puts _ prefixes on all C symbols
+ str = lookup(".dynstr", 0);
+ adduint32(d, str->size);
+ adduint8(str, '_');
+ addstring(str, name);
+ adduint8(d, 0x01); // type - N_EXT - external symbol
+ adduint8(d, 0); // section
+ adduint16(d, 0); // desc
+ adduint32(d, 0); // value
+ } else {
+ diag("adddynsym: unsupported binary format");
+ }
+}
+
+void
+adddynlib(char *lib)
+{
+ Sym *s;
+
+ if(!needlib(lib))
+ return;
+
+ if(iself) {
+ s = lookup(".dynstr", 0);
+ if(s->size == 0)
+ addstring(s, "");
+ elfwritedynent(lookup(".dynamic", 0), DT_NEEDED, addstring(s, lib));
+ } else if(HEADTYPE == 6) { // Mach-O
+ machoadddynlib(lib);
+ } else {
+ diag("adddynlib: unsupported binary format");
+ }
+}
+
void
doelf(void)
{
- Sym *s, *shstrtab, *dynamic, *dynstr, *d;
- int h, nsym, t;
+ Sym *s, *shstrtab, *dynstr;
if(!iself)
return;
/* predefine strings we need for section headers */
shstrtab = lookup(".shstrtab", 0);
+ shstrtab->type = SELFDATA;
shstrtab->reachable = 1;
+
elfstr[ElfStrEmpty] = addstring(shstrtab, "");
elfstr[ElfStrText] = addstring(shstrtab, ".text");
elfstr[ElfStrData] = addstring(shstrtab, ".data");
elfstr[ElfStrBss] = addstring(shstrtab, ".bss");
+ addstring(shstrtab, ".elfdata");
+ addstring(shstrtab, ".rodata");
if(!debug['s']) {
elfstr[ElfStrGosymcounts] = addstring(shstrtab, ".gosymcounts");
elfstr[ElfStrGosymtab] = addstring(shstrtab, ".gosymtab");
elfstr[ElfStrGopclntab] = addstring(shstrtab, ".gopclntab");
+ dwarfaddshstrings(shstrtab);
}
elfstr[ElfStrShstrtab] = addstring(shstrtab, ".shstrtab");
@@ -305,6 +581,8 @@ doelf(void)
elfstr[ElfStrDynsym] = addstring(shstrtab, ".dynsym");
elfstr[ElfStrDynstr] = addstring(shstrtab, ".dynstr");
elfstr[ElfStrRel] = addstring(shstrtab, ".rel");
+ elfstr[ElfStrRelPlt] = addstring(shstrtab, ".rel.plt");
+ elfstr[ElfStrPlt] = addstring(shstrtab, ".plt");
/* interpreter string */
s = lookup(".interp", 0);
@@ -315,13 +593,14 @@ doelf(void)
s = lookup(".dynsym", 0);
s->type = SELFDATA;
s->reachable = 1;
- s->value += ELF32SYMSIZE;
+ s->size += ELF32SYMSIZE;
/* dynamic string table */
s = lookup(".dynstr", 0);
s->reachable = 1;
s->type = SELFDATA;
- addstring(s, "");
+ if(s->size == 0)
+ addstring(s, "");
dynstr = s;
/* relocation table */
@@ -332,88 +611,36 @@ doelf(void)
/* global offset table */
s = lookup(".got", 0);
s->reachable = 1;
+ s->type = SDATA; // writable, so not SELFDATA
+
+ /* hash */
+ s = lookup(".hash", 0);
+ s->reachable = 1;
s->type = SELFDATA;
- /* got.plt - ??? */
+ /* got.plt */
s = lookup(".got.plt", 0);
s->reachable = 1;
+ s->type = SDATA; // writable, so not SELFDATA
+
+ s = lookup(".plt", 0);
+ s->reachable = 1;
s->type = SELFDATA;
- /* define dynamic elf table */
- s = lookup(".dynamic", 0);
+ s = lookup(".rel.plt", 0);
s->reachable = 1;
s->type = SELFDATA;
- dynamic = s;
- /*
- * relocation entries for dynimport symbols
- */
- nsym = 1; // sym 0 is reserved
- for(h=0; h<NHASH; h++) {
- for(s=hash[h]; s!=S; s=s->link) {
- if(!s->reachable || (s->type != STEXT && s->type != SDATA && s->type != SBSS) || s->dynimpname == nil)
- continue;
-
- if(!s->dynexport) {
- d = lookup(".rel", 0);
- addaddr(d, s);
- adduint32(d, ELF32_R_INFO(nsym, R_386_32));
- }
-
- nsym++;
-
- d = lookup(".dynsym", 0);
- adduint32(d, addstring(lookup(".dynstr", 0), s->dynimpname));
- /* value */
- if(!s->dynexport)
- adduint32(d, 0);
- else
- addaddr(d, s);
-
- /* size of object */
- adduint32(d, 0);
-
- /* type */
- t = STB_GLOBAL << 4;
- if(s->dynexport && s->type == STEXT)
- t |= STT_FUNC;
- else
- t |= STT_OBJECT;
- adduint8(d, t);
-
- /* reserved */
- adduint8(d, 0);
-
- /* section where symbol is defined */
- if(!s->dynexport)
- adduint16(d, SHN_UNDEF);
- else {
- switch(s->type) {
- default:
- case STEXT:
- t = 9;
- break;
- case SDATA:
- t = 10;
- break;
- case SBSS:
- t = 11;
- break;
- }
- adduint16(d, t);
- }
-
- if(!s->dynexport && needlib(s->dynimplib))
- elfwritedynent(dynamic, DT_NEEDED, addstring(dynstr, s->dynimplib));
- }
- }
+ elfsetupplt();
- elfdynhash(nsym);
+ /* define dynamic elf table */
+ s = lookup(".dynamic", 0);
+ s->reachable = 1;
+ s->type = SELFDATA;
/*
* .dynamic table
*/
- s = dynamic;
elfwritedynentsym(s, DT_HASH, lookup(".hash", 0));
elfwritedynentsym(s, DT_SYMTAB, lookup(".dynsym", 0));
elfwritedynent(s, DT_SYMENT, ELF32SYMSIZE);
@@ -424,6 +651,10 @@ doelf(void)
elfwritedynent(s, DT_RELENT, ELF32RELSIZE);
if(rpath)
elfwritedynent(s, DT_RUNPATH, addstring(dynstr, rpath));
+ elfwritedynentsym(s, DT_PLTGOT, lookup(".got.plt", 0));
+ 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_NULL, 0);
}
}
@@ -450,155 +681,52 @@ phsh(Elf64_Phdr *ph, Elf64_Shdr *sh)
void
asmb(void)
{
- Prog *p;
int32 v, magic;
int a, dynsym;
uint32 va, fo, w, symo, startva, machlink;
- uchar *op1;
- ulong expectpc;
ElfEhdr *eh;
ElfPhdr *ph, *pph;
ElfShdr *sh;
+ Section *sect;
if(debug['v'])
Bprint(&bso, "%5.2f asmb\n", cputime());
Bflush(&bso);
- seek(cout, HEADR, 0);
- pc = INITTEXT;
- curp = firstp;
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT)
- curtext = p;
- curp = p;
- if(HEADTYPE == 8) {
- // native client
- expectpc = p->pc;
- p->pc = pc;
- asmins(p);
- if(p->pc != expectpc) {
- Bflush(&bso);
- diag("phase error %lux sb %lux in %s", p->pc, expectpc, TNAME);
- }
- while(pc < p->pc) {
- cput(0x90); // nop
- pc++;
- }
- }
- if(p->pc != pc) {
- Bflush(&bso);
- if(!debug['a'])
- print("%P\n", curp);
- diag("phase error %lux sb %lux in %s", p->pc, pc, TNAME);
- pc = p->pc;
- }
- if(HEADTYPE != 8) {
- asmins(p);
- if(pc != p->pc) {
- Bflush(&bso);
- diag("asmins changed pc %lux sb %lux in %s", p->pc, pc, TNAME);
- }
- }
- if(cbc < sizeof(and))
- cflush();
- a = (andptr - and);
-
- if(debug['a']) {
- Bprint(&bso, pcstr, pc);
- for(op1 = and; op1 < andptr; op1++)
- Bprint(&bso, "%.2ux", *op1 & 0xff);
- Bprint(&bso, "\t%P\n", curp);
- }
- if(dlm) {
- if(p->as == ATEXT)
- reloca = nil;
- else if(reloca != nil)
- diag("reloc failure: %P", curp);
- }
- memmove(cbp, and, a);
- cbp += a;
- pc += a;
- cbc -= a;
- }
- if(HEADTYPE == 8) {
- while(pc < INITDAT) {
- cput(0xf4); // hlt
- pc++;
- }
- }
- cflush();
+ sect = segtext.sect;
+ seek(cout, sect->vaddr - segtext.vaddr + segtext.fileoff, 0);
+ codeblk(sect->vaddr, sect->len);
- switch(HEADTYPE) {
- default:
- if(iself)
- goto Elfseek;
- diag("unknown header type %d", HEADTYPE);
- case 0:
- seek(cout, rnd(HEADR+textsize, 8192), 0);
- break;
- case 1:
- textsize = rnd(HEADR+textsize, 4096)-HEADR;
- seek(cout, textsize+HEADR, 0);
- break;
- case 2:
- seek(cout, HEADR+textsize, 0);
- break;
- case 3:
- case 4:
- seek(cout, HEADR+rnd(textsize, INITRND), 0);
- break;
- case 6:
- v = HEADR+textsize;
- seek(cout, v, 0);
- v = rnd(v, 4096) - v;
- while(v > 0) {
- cput(0);
- v--;
- }
- cflush();
- break;
- case 8:
- // Native Client only needs to round
- // text segment file address to 4096 bytes,
- // but text segment memory address rounds
- // to INITRND (65536).
- v = rnd(HEADR+textsize, 4096);
- seek(cout, v, 0);
- break;
- Elfseek:
- case 10:
- v = rnd(HEADR+textsize, INITRND);
- seek(cout, v, 0);
- break;
- }
+ /* output read-only data in text segment */
+ sect = segtext.sect->next;
+ seek(cout, sect->vaddr - segtext.vaddr + segtext.fileoff, 0);
+ datblk(sect->vaddr, sect->len);
if(debug['v'])
Bprint(&bso, "%5.2f datblk\n", cputime());
Bflush(&bso);
- if(dlm){
- char buf[8];
-
- write(cout, buf, INITDAT-textsize);
- textsize = INITDAT;
- }
-
- for(v = 0; v < datsize; v += sizeof(buf)-Dbufslop) {
- if(datsize-v > sizeof(buf)-Dbufslop)
- datblk(v, sizeof(buf)-Dbufslop);
- else
- datblk(v, datsize-v);
- }
+ seek(cout, segdata.fileoff, 0);
+ datblk(segdata.vaddr, segdata.filelen);
machlink = 0;
if(HEADTYPE == 6)
machlink = domacholink();
+ if(iself) {
+ /* index of elf text section; needed by asmelfsym, double-checked below */
+ /* !debug['d'] causes extra sections before the .text section */
+ elftextsh = 1;
+ if(!debug['d'])
+ elftextsh += 10;
+ }
+
symsize = 0;
spsize = 0;
lcsize = 0;
symo = 0;
if(!debug['s']) {
+ // TODO: rationalize
if(debug['v'])
Bprint(&bso, "%5.2f sym\n", cputime());
Bflush(&bso);
@@ -607,53 +735,38 @@ asmb(void)
if(iself)
goto Elfsym;
case 0:
- seek(cout, rnd(HEADR+textsize, 8192)+datsize, 0);
+ seek(cout, rnd(HEADR+segtext.filelen, 8192)+segdata.filelen, 0);
break;
case 1:
- seek(cout, rnd(HEADR+textsize, INITRND)+datsize, 0);
+ seek(cout, rnd(HEADR+segtext.filelen, INITRND)+segdata.filelen, 0);
break;
case 2:
- seek(cout, HEADR+textsize+datsize, 0);
+ seek(cout, HEADR+segtext.filelen+segdata.filelen, 0);
break;
case 3:
case 4:
debug['s'] = 1;
- symo = HEADR+textsize+datsize;
+ symo = HEADR+segtext.filelen+segdata.filelen;
break;
case 6:
- symo = rnd(HEADR+textsize, INITRND)+rnd(datsize, INITRND)+machlink;
+ symo = rnd(HEADR+segtext.filelen, INITRND)+rnd(segdata.filelen, INITRND)+machlink;
break;
Elfsym:
- case 10:
- symo = rnd(HEADR+textsize, INITRND)+datsize;
+ symo = rnd(HEADR+segtext.filelen, INITRND)+segdata.filelen;
symo = rnd(symo, INITRND);
break;
+ case 10:
+ // TODO(brainman): not sure what symo meant to be, but it is not used for Windows PE for now anyway
+ symo = rnd(HEADR+segtext.filelen, PEFILEALIGN)+segdata.filelen;
+ symo = rnd(symo, PEFILEALIGN);
+ break;
+ }
+ if(HEADTYPE != 10 && !debug['s']) {
+ seek(cout, symo, 0);
+ if(debug['v'])
+ Bprint(&bso, "%5.2f dwarf\n", cputime());
+ dwarfemitdebugsections();
}
- seek(cout, symo+8, 0);
- if(!debug['s'])
- asmsym();
- if(debug['v'])
- Bprint(&bso, "%5.2f sp\n", cputime());
- Bflush(&bso);
- if(debug['v'])
- Bprint(&bso, "%5.2f pc\n", cputime());
- Bflush(&bso);
- if(!debug['s'])
- asmlc();
- if(dlm)
- asmdyn();
- if(HEADTYPE == 10 || (iself && !debug['s']))
- strnput("", INITRND-(8+symsize+lcsize)%INITRND);
- cflush();
- seek(cout, symo, 0);
- lputl(symsize);
- lputl(lcsize);
- cflush();
- }
- else if(dlm){
- seek(cout, HEADR+textsize+datsize, 0);
- asmdyn();
- cflush();
}
if(debug['v'])
Bprint(&bso, "%5.2f headr\n", cputime());
@@ -666,17 +779,17 @@ asmb(void)
case 0: /* garbage */
lput(0x160L<<16); /* magic and sections */
lput(0L); /* time and date */
- lput(rnd(HEADR+textsize, 4096)+datsize);
+ lput(rnd(HEADR+segtext.filelen, 4096)+segdata.filelen);
lput(symsize); /* nsyms */
lput((0x38L<<16)|7L); /* size of optional hdr and flags */
lput((0413<<16)|0437L); /* magic and version */
- lput(rnd(HEADR+textsize, 4096)); /* sizes */
- lput(datsize);
- lput(bsssize);
+ lput(rnd(HEADR+segtext.filelen, 4096)); /* sizes */
+ lput(segdata.filelen);
+ lput(segdata.len - segdata.filelen);
lput(entryvalue()); /* va of entry */
lput(INITTEXT-HEADR); /* va of base of text */
- lput(INITDAT); /* va of base of data */
- lput(INITDAT+datsize); /* va of base of bss */
+ lput(segdata.vaddr); /* va of base of data */
+ lput(segdata.vaddr+segdata.filelen); /* va of base of bss */
lput(~0L); /* gp reg mask */
lput(0L);
lput(0L);
@@ -698,19 +811,19 @@ asmb(void)
* a.out header
*/
lputl(0x10b); /* magic, version stamp */
- lputl(rnd(textsize, INITRND)); /* text sizes */
- lputl(datsize); /* data sizes */
- lputl(bsssize); /* bss sizes */
+ lputl(rnd(segtext.filelen, INITRND)); /* text sizes */
+ lputl(segdata.filelen); /* data sizes */
+ lputl(segdata.len - segdata.filelen); /* bss sizes */
lput(entryvalue()); /* va of entry */
lputl(INITTEXT); /* text start */
- lputl(INITDAT); /* data start */
+ lputl(segdata.vaddr); /* data start */
/*
* text section header
*/
s8put(".text");
lputl(HEADR); /* pa */
lputl(HEADR); /* va */
- lputl(textsize); /* text size */
+ lputl(segtext.filelen); /* text size */
lputl(HEADR); /* file offset */
lputl(0); /* relocation */
lputl(0); /* line numbers */
@@ -720,10 +833,10 @@ asmb(void)
* data section header
*/
s8put(".data");
- lputl(INITDAT); /* pa */
- lputl(INITDAT); /* va */
- lputl(datsize); /* data size */
- lputl(HEADR+textsize); /* file offset */
+ lputl(segdata.vaddr); /* pa */
+ lputl(segdata.vaddr); /* va */
+ lputl(segdata.filelen); /* data size */
+ lputl(HEADR+segtext.filelen); /* file offset */
lputl(0); /* relocation */
lputl(0); /* line numbers */
lputl(0); /* relocation, line numbers */
@@ -732,9 +845,9 @@ asmb(void)
* bss section header
*/
s8put(".bss");
- lputl(INITDAT+datsize); /* pa */
- lputl(INITDAT+datsize); /* va */
- lputl(bsssize); /* bss size */
+ lputl(segdata.vaddr+segdata.filelen); /* pa */
+ lputl(segdata.vaddr+segdata.filelen); /* va */
+ lputl(segdata.len - segdata.filelen); /* bss size */
lputl(0); /* file offset */
lputl(0); /* relocation */
lputl(0); /* line numbers */
@@ -747,20 +860,18 @@ asmb(void)
lputl(0); /* pa */
lputl(0); /* va */
lputl(symsize+lcsize); /* comment size */
- lputl(HEADR+textsize+datsize); /* file offset */
- lputl(HEADR+textsize+datsize); /* offset of syms */
- lputl(HEADR+textsize+datsize+symsize);/* offset of line numbers */
+ lputl(HEADR+segtext.filelen+segdata.filelen); /* file offset */
+ lputl(HEADR+segtext.filelen+segdata.filelen); /* offset of syms */
+ lputl(HEADR+segtext.filelen+segdata.filelen+symsize);/* offset of line numbers */
lputl(0); /* relocation, line numbers */
lputl(0x200); /* flags comment only */
break;
case 2: /* plan9 */
magic = 4*11*11+7;
- if(dlm)
- magic |= 0x80000000;
lput(magic); /* magic */
- lput(textsize); /* sizes */
- lput(datsize);
- lput(bsssize);
+ lput(segtext.filelen); /* sizes */
+ lput(segdata.filelen);
+ lput(segdata.len - segdata.filelen);
lput(symsize); /* nsyms */
lput(entryvalue()); /* va of entry */
lput(spsize); /* sp offsets */
@@ -771,7 +882,7 @@ asmb(void)
break;
case 4:
/* fake MS-DOS .EXE */
- v = rnd(HEADR+textsize, INITRND)+datsize;
+ v = rnd(HEADR+segtext.filelen, INITRND)+segdata.filelen;
wputl(0x5A4D); /* 'MZ' */
wputl(v % 512); /* bytes in last page */
wputl(rnd(v, 512)/512); /* total number of pages */
@@ -793,34 +904,31 @@ asmb(void)
break;
case 6:
- asmbmacho(symdatva, symo);
+ asmbmacho();
break;
Elfput:
/* elf 386 */
- if(HEADTYPE == 8 || HEADTYPE == 11)
+ if(HEADTYPE == 11)
debug['d'] = 1;
eh = getElfEhdr();
fo = HEADR;
startva = INITTEXT - HEADR;
va = startva + fo;
- w = textsize;
+ w = segtext.filelen;
/* This null SHdr must appear before all others */
sh = newElfShdr(elfstr[ElfStrEmpty]);
- /* program header info - but not on native client */
- pph = nil;
- if(HEADTYPE != 8) {
- pph = newElfPhdr();
- pph->type = PT_PHDR;
- pph->flags = PF_R + PF_X;
- pph->off = eh->ehsize;
- pph->vaddr = INITTEXT - HEADR + pph->off;
- pph->paddr = INITTEXT - HEADR + pph->off;
- pph->align = INITRND;
- }
+ /* program header info */
+ pph = newElfPhdr();
+ pph->type = PT_PHDR;
+ pph->flags = PF_R + PF_X;
+ pph->off = eh->ehsize;
+ pph->vaddr = INITTEXT - HEADR + pph->off;
+ pph->paddr = INITTEXT - HEADR + pph->off;
+ pph->align = INITRND;
if(!debug['d']) {
/* interpreter */
@@ -843,51 +951,8 @@ asmb(void)
phsh(ph, sh);
}
- ph = newElfPhdr();
- ph->type = PT_LOAD;
- ph->flags = PF_X+PF_R;
- if(HEADTYPE != 8) { // Include header, but not on Native Client.
- va -= fo;
- w += fo;
- fo = 0;
- }
- ph->vaddr = va;
- ph->paddr = va;
- ph->off = fo;
- ph->filesz = w;
- ph->memsz = INITDAT - va;
- ph->align = INITRND;
-
- // NaCl text segment file address rounds to 4096;
- // only memory address rounds to INITRND.
- if(HEADTYPE == 8)
- fo = rnd(fo+w, 4096);
- else
- fo = rnd(fo+w, INITRND);
- va = INITDAT;
- w = datsize;
-
- ph = newElfPhdr();
- ph->type = PT_LOAD;
- ph->flags = PF_W+PF_R;
- ph->off = fo;
- ph->vaddr = va;
- ph->paddr = va;
- ph->filesz = w;
- ph->memsz = w+bsssize;
- ph->align = INITRND;
-
- if(!debug['s'] && HEADTYPE != 8 && HEADTYPE != 11) {
- ph = newElfPhdr();
- ph->type = PT_LOAD;
- ph->flags = PF_R;
- ph->off = symo;
- ph->vaddr = symdatva;
- ph->paddr = symdatva;
- ph->filesz = rnd(8+symsize+lcsize, INITRND);
- ph->memsz = rnd(8+symsize+lcsize, INITRND);
- ph->align = INITRND;
- }
+ elfphload(&segtext);
+ elfphload(&segdata);
/* Dynamic linking sections */
if (!debug['d']) { /* -d suppresses dynamic loader format */
@@ -921,6 +986,22 @@ asmb(void)
sh->flags = SHF_ALLOC;
sh->addralign = 1;
shsym(sh, lookup(".dynstr", 0));
+
+ sh = newElfShdr(elfstr[ElfStrRelPlt]);
+ sh->type = SHT_REL;
+ sh->flags = SHF_ALLOC;
+ sh->entsize = ELF32RELSIZE;
+ sh->addralign = 4;
+ sh->link = dynsym;
+ sh->info = eh->shnum; // .plt
+ shsym(sh, lookup(".rel.plt", 0));
+
+ sh = newElfShdr(elfstr[ElfStrPlt]);
+ sh->type = SHT_PROGBITS;
+ sh->flags = SHF_ALLOC+SHF_EXECINSTR;
+ sh->entsize = 4;
+ sh->addralign = 4;
+ shsym(sh, lookup(".plt", 0));
sh = newElfShdr(elfstr[ElfStrHash]);
sh->type = SHT_HASH;
@@ -968,80 +1049,27 @@ asmb(void)
ph->flags = PF_W+PF_R;
ph->align = 4;
- fo = HEADR;
- va = startva + fo;
- w = textsize;
-
- sh = newElfShdr(elfstr[ElfStrText]);
- sh->type = SHT_PROGBITS;
- sh->flags = SHF_ALLOC+SHF_EXECINSTR;
- sh->addr = va;
- sh->off = fo;
- sh->size = w;
- sh->addralign = 4;
-
- // NaCl text segment file address rounds to 4096;
- // only memory address rounds to INITRND.
- if(HEADTYPE == 8)
- fo = rnd(fo+w, 4096);
- else
- fo = rnd(fo+w, INITRND);
- va = rnd(va+w, INITRND);
- w = datsize;
-
- sh = newElfShdr(elfstr[ElfStrData]);
- sh->type = SHT_PROGBITS;
- sh->flags = SHF_WRITE+SHF_ALLOC;
- sh->addr = va + elfdatsize;
- sh->off = fo + elfdatsize;
- sh->size = w - elfdatsize;
- sh->addralign = 4;
-
- fo += w;
- va += w;
- w = bsssize;
-
- sh = newElfShdr(elfstr[ElfStrBss]);
- sh->type = SHT_NOBITS;
- sh->flags = SHF_WRITE+SHF_ALLOC;
- sh->addr = va;
- sh->off = fo;
- sh->size = w;
- sh->addralign = 4;
+ if(elftextsh != eh->shnum)
+ diag("elftextsh = %d, want %d", elftextsh, eh->shnum);
+ for(sect=segtext.sect; sect!=nil; sect=sect->next)
+ elfshbits(sect);
+ for(sect=segdata.sect; sect!=nil; sect=sect->next)
+ elfshbits(sect);
if (!debug['s']) {
- fo = symo;
- w = 8;
-
- sh = newElfShdr(elfstr[ElfStrGosymcounts]);
- sh->type = SHT_PROGBITS;
- sh->flags = SHF_ALLOC;
- sh->off = fo;
- sh->size = w;
- sh->addralign = 1;
- sh->addr = symdatva;
-
- fo += w;
- w = symsize;
-
sh = newElfShdr(elfstr[ElfStrGosymtab]);
sh->type = SHT_PROGBITS;
sh->flags = SHF_ALLOC;
- sh->off = fo;
- sh->size = w;
sh->addralign = 1;
- sh->addr = symdatva + 8;
-
- fo += w;
- w = lcsize;
+ shsym(sh, lookup("symtab", 0));
sh = newElfShdr(elfstr[ElfStrGopclntab]);
sh->type = SHT_PROGBITS;
sh->flags = SHF_ALLOC;
- sh->off = fo;
- sh->size = w;
sh->addralign = 1;
- sh->addr = symdatva + 8 + symsize;
+ shsym(sh, lookup("pclntab", 0));
+
+ dwarfaddelfheaders();
}
sh = newElfShstrtab(elfstr[ElfStrShstrtab]);
@@ -1058,11 +1086,6 @@ asmb(void)
eh->ident[EI_DATA] = ELFDATA2LSB;
eh->ident[EI_VERSION] = EV_CURRENT;
switch(HEADTYPE) {
- case 8:
- eh->ident[EI_OSABI] = ELFOSABI_NACL;
- eh->ident[EI_ABIVERSION] = 7;
- eh->flags = 0x200000; // aligned mod 32
- break;
case 9:
eh->ident[EI_OSABI] = 9;
break;
@@ -1113,215 +1136,16 @@ cflush(void)
n = sizeof(buf.cbuf) - cbc;
if(n)
- write(cout, buf.cbuf, n);
+ ewrite(cout, buf.cbuf, n);
cbp = buf.cbuf;
cbc = sizeof(buf.cbuf);
}
-void
-datblk(int32 s, int32 n)
+/* Current position in file */
+vlong
+cpos(void)
{
- Prog *p;
- char *cast;
- int32 l, fl, j;
- int i, c;
- Adr *a;
-
- memset(buf.dbuf, 0, n+Dbufslop);
- for(p = datap; p != P; p = p->link) {
- a = &p->from;
-
- l = a->sym->value + a->offset - s;
- if(l >= n)
- continue;
-
- c = a->scale;
- i = 0;
- if(l < 0) {
- if(l+c <= 0)
- continue;
- i = -l;
- l = 0;
- }
-
- curp = p;
- if(!a->sym->reachable)
- diag("unreachable symbol in datblk - %s", a->sym->name);
- if(a->sym->type == SMACHO)
- continue;
-
- if(p->as != AINIT && p->as != ADYNT) {
- for(j=l+(c-i)-1; j>=l; j--)
- if(buf.dbuf[j]) {
- print("%P\n", p);
- diag("multiple initialization");
- break;
- }
- }
- switch(p->to.type) {
- case D_FCONST:
- switch(c) {
- default:
- case 4:
- fl = ieeedtof(&p->to.ieee);
- cast = (char*)&fl;
- for(; i<c; i++) {
- buf.dbuf[l] = cast[fnuxi4[i]];
- l++;
- }
- break;
- case 8:
- cast = (char*)&p->to.ieee;
- for(; i<c; i++) {
- buf.dbuf[l] = cast[fnuxi8[i]];
- l++;
- }
- break;
- }
- break;
-
- case D_SCONST:
- for(; i<c; i++) {
- buf.dbuf[l] = p->to.scon[i];
- l++;
- }
- break;
-
- default:
- fl = p->to.offset;
- if(p->to.type == D_SIZE)
- fl += p->to.sym->size;
- if(p->to.type == D_ADDR) {
- if(p->to.index != D_STATIC && p->to.index != D_EXTERN)
- diag("DADDR type%P", p);
- if(p->to.sym) {
- if(p->to.sym->type == SUNDEF)
- ckoff(p->to.sym, fl);
- fl += p->to.sym->value;
- if(p->to.sym->type != STEXT && p->to.sym->type != SUNDEF)
- fl += INITDAT;
- if(dlm)
- dynreloc(p->to.sym, l+s+INITDAT, 1);
- }
- }
- cast = (char*)&fl;
- switch(c) {
- default:
- diag("bad nuxi %d %d\n%P", c, i, curp);
- break;
- case 1:
- for(; i<c; i++) {
- buf.dbuf[l] = cast[inuxi1[i]];
- l++;
- }
- break;
- case 2:
- for(; i<c; i++) {
- buf.dbuf[l] = cast[inuxi2[i]];
- l++;
- }
- break;
- case 4:
- for(; i<c; i++) {
- buf.dbuf[l] = cast[inuxi4[i]];
- l++;
- }
- break;
- }
- break;
- }
- }
-
- write(cout, buf.dbuf, n);
- if(!debug['a'])
- return;
-
- /*
- * a second pass just to print the asm
- */
- for(p = datap; p != P; p = p->link) {
- a = &p->from;
-
- l = a->sym->value + a->offset - s;
- if(l < 0 || l >= n)
- continue;
-
- c = a->scale;
- i = 0;
-
- switch(p->to.type) {
- case D_FCONST:
- switch(c) {
- default:
- case 4:
- fl = ieeedtof(&p->to.ieee);
- cast = (char*)&fl;
- Bprint(&bso, pcstr, l+s+INITDAT);
- for(j=0; j<c; j++)
- Bprint(&bso, "%.2ux", cast[fnuxi4[j]] & 0xff);
- Bprint(&bso, "\t%P\n", curp);
- break;
- case 8:
- cast = (char*)&p->to.ieee;
- Bprint(&bso, pcstr, l+s+INITDAT);
- for(j=0; j<c; j++)
- Bprint(&bso, "%.2ux", cast[fnuxi8[j]] & 0xff);
- Bprint(&bso, "\t%P\n", curp);
- break;
- }
- break;
-
- case D_SCONST:
- Bprint(&bso, pcstr, l+s+INITDAT);
- for(j=0; j<c; j++)
- Bprint(&bso, "%.2ux", p->to.scon[j] & 0xff);
- Bprint(&bso, "\t%P\n", curp);
- break;
-
- default:
- fl = p->to.offset;
- if(p->to.type == D_SIZE)
- fl += p->to.sym->size;
- if(p->to.type == D_ADDR) {
- if(p->to.index != D_STATIC && p->to.index != D_EXTERN)
- diag("DADDR type%P", p);
- if(p->to.sym) {
- if(p->to.sym->type == SUNDEF)
- ckoff(p->to.sym, fl);
- fl += p->to.sym->value;
- if(p->to.sym->type != STEXT && p->to.sym->type != SUNDEF)
- fl += INITDAT;
- if(dlm)
- dynreloc(p->to.sym, l+s+INITDAT, 1);
- }
- }
- cast = (char*)&fl;
- switch(c) {
- default:
- diag("bad nuxi %d %d\n%P", c, i, curp);
- break;
- case 1:
- Bprint(&bso, pcstr, l+s+INITDAT);
- for(j=0; j<c; j++)
- Bprint(&bso, "%.2ux", cast[inuxi1[j]] & 0xff);
- Bprint(&bso, "\t%P\n", curp);
- break;
- case 2:
- Bprint(&bso, pcstr, l+s+INITDAT);
- for(j=0; j<c; j++)
- Bprint(&bso, "%.2ux", cast[inuxi2[j]] & 0xff);
- Bprint(&bso, "\t%P\n", curp);
- break;
- case 4:
- Bprint(&bso, pcstr, l+s+INITDAT);
- for(j=0; j<c; j++)
- Bprint(&bso, "%.2ux", cast[inuxi4[j]] & 0xff);
- Bprint(&bso, "\t%P\n", curp);
- break;
- }
- break;
- }
- }
+ return seek(cout, 0, 1) + sizeof(buf.cbuf) - cbc;
}
int32
@@ -1338,3 +1162,71 @@ rnd(int32 v, int32 r)
v -= c;
return v;
}
+
+void
+genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
+{
+ Auto *a;
+ Sym *s;
+ int h;
+
+ s = lookup("etext", 0);
+ if(s->type == STEXT)
+ put(s, s->name, 'T', s->value, s->size, s->version, 0);
+
+ for(h=0; h<NHASH; h++) {
+ for(s=hash[h]; s!=S; s=s->hash) {
+ switch(s->type&~SSUB) {
+ case SCONST:
+ case SRODATA:
+ case SDATA:
+ case SELFDATA:
+ case SMACHO:
+ case SMACHOGOT:
+ case SWINDOWS:
+ if(!s->reachable)
+ continue;
+ put(s, s->name, 'D', symaddr(s), s->size, s->version, s->gotype);
+ continue;
+
+ case SBSS:
+ if(!s->reachable)
+ continue;
+ put(s, s->name, 'B', symaddr(s), s->size, s->version, s->gotype);
+ continue;
+
+ case SFILE:
+ put(nil, s->name, 'f', s->value, 0, s->version, 0);
+ continue;
+ }
+ }
+ }
+
+ for(s = textp; s != nil; s = s->next) {
+ if(s->text == nil)
+ continue;
+
+ /* filenames first */
+ for(a=s->autom; a; a=a->link)
+ if(a->type == D_FILE)
+ put(nil, a->asym->name, 'z', a->aoffset, 0, 0, 0);
+ else
+ if(a->type == D_FILE1)
+ put(nil, a->asym->name, 'Z', a->aoffset, 0, 0, 0);
+
+ put(s, s->name, 'T', s->value, s->size, s->version, s->gotype);
+
+ /* frame, auto and param after */
+ put(nil, ".frame", 'm', s->text->to.offset+4, 0, 0, 0);
+
+ for(a=s->autom; a; a=a->link)
+ if(a->type == D_AUTO)
+ put(nil, a->asym->name, 'a', -a->aoffset, 0, 0, a->gotype);
+ else
+ if(a->type == D_PARAM)
+ put(nil, a->asym->name, 'p', a->aoffset, 0, 0, a->gotype);
+ }
+ if(debug['v'] || debug['n'])
+ Bprint(&bso, "symsize = %ud\n", symsize);
+ Bflush(&bso);
+}
diff --git a/src/cmd/8l/doc.go b/src/cmd/8l/doc.go
index c8c058684..0bf6f151f 100644
--- a/src/cmd/8l/doc.go
+++ b/src/cmd/8l/doc.go
@@ -29,8 +29,8 @@ Options new in this version:
Write Apple Mach-O binaries (default when $GOOS is darwin)
-H7
Write Linux ELF binaries (default when $GOOS is linux)
--L dir1,dir2,..
- Search for libraries (package files) in the comma-separated list of directories.
+-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.
diff --git a/src/cmd/8l/l.h b/src/cmd/8l/l.h
index 495c40d64..daede8879 100644
--- a/src/cmd/8l/l.h
+++ b/src/cmd/8l/l.h
@@ -44,7 +44,7 @@ enum
#define P ((Prog*)0)
#define S ((Sym*)0)
-#define TNAME (curtext?curtext->from.sym->name:noname)
+#define TNAME (cursym?cursym->name:noname)
#define cput(c)\
{ *cbp++ = c;\
if(--cbc <= 0)\
@@ -55,6 +55,7 @@ typedef struct Prog Prog;
typedef struct Sym Sym;
typedef struct Auto Auto;
typedef struct Optab Optab;
+typedef struct Reloc Reloc;
struct Adr
{
@@ -66,11 +67,7 @@ struct Adr
Ieee u0ieee;
char *u0sbig;
} u0;
- union
- {
- Auto* u1autom;
- Sym* u1sym;
- } u1;
+ Sym* sym;
short type;
uchar index;
char scale;
@@ -83,18 +80,25 @@ struct Adr
#define ieee u0.u0ieee
#define sbig u0.u0sbig
-#define autom u1.u1autom
-#define sym u1.u1sym
+struct Reloc
+{
+ int32 off;
+ uchar siz;
+ int32 type;
+ int32 add;
+ Sym* sym;
+};
struct Prog
{
Adr from;
Adr to;
- Prog *forwd;
+ Prog* forwd;
+ Prog* comefrom;
Prog* link;
- Prog* dlink;
Prog* pcond; /* work on this */
int32 pc;
+ int32 spadj;
int32 line;
short as;
char width; /* fake for DATA */
@@ -103,8 +107,10 @@ struct Prog
uchar mark; /* work on these */
uchar back;
uchar bigjmp;
-
};
+#define datasize from.scale
+#define textflag from.scale
+
struct Auto
{
Sym* asym;
@@ -115,25 +121,39 @@ struct Auto
};
struct Sym
{
- char *name;
+ char* name;
short type;
short version;
- short become;
- short frame;
- uchar subtype;
uchar dupok;
uchar reachable;
uchar dynexport;
+ uchar special;
int32 value;
int32 size;
int32 sig;
- Sym* link;
- Prog* text;
- Prog* data;
+ int32 dynid;
+ int32 plt;
+ int32 got;
+ Sym* hash; // in hash table
+ Sym* next; // in text or data list
+ Sym* sub; // in sub list
+ Sym* outer; // container of sub
Sym* gotype;
char* file;
char* dynimpname;
char* dynimplib;
+
+ // STEXT
+ Auto* autom;
+ Prog* text;
+
+ // SDATA, SBSS
+ uchar* p;
+ int32 np;
+ int32 maxp;
+ Reloc* r;
+ int32 nr;
+ int32 maxr;
};
struct Optab
{
@@ -146,23 +166,28 @@ struct Optab
enum
{
Sxxx,
-
+
+ /* order here is order in output file */
STEXT,
+ SELFDATA,
+ SMACHOPLT,
+ SRODATA,
SDATA,
+ SMACHO, /* Mach-O __nl_symbol_ptr */
+ SMACHOGOT,
+ SWINDOWS,
SBSS,
- SDATA1,
+
SXREF,
+ SMACHODYNSTR,
+ SMACHODYNSYM,
+ SMACHOINDIRECTPLT,
+ SMACHOINDIRECTGOT,
SFILE,
SCONST,
- SUNDEF,
-
- SIMPORT,
- SEXPORT,
+ SDYNIMPORT,
- SMACHO, /* pointer to mach-o imported symbol */
-
- SFIXED,
- SELFDATA,
+ SSUB = 1<<8, /* sub-symbol, linked from parent via ->sub list */
NHASH = 10007,
NHUNK = 100000,
@@ -240,9 +265,6 @@ enum
Pm = 0x0f, /* 2byte opcode escape */
Pq = 0xff, /* both escape */
Pb = 0xfe, /* byte operands */
-
- Roffset = 22, /* no. bits for offset in relocation address */
- Rindex = 10, /* no. bits for index in relocation address */
};
EXTERN union
@@ -266,12 +288,11 @@ EXTERN union
EXTERN int32 HEADR;
EXTERN int32 HEADTYPE;
-EXTERN int32 INITDAT;
EXTERN int32 INITRND;
EXTERN int32 INITTEXT;
+EXTERN int32 INITDAT;
EXTERN char* INITENTRY; /* entry point */
EXTERN Biobuf bso;
-EXTERN int32 bsssize;
EXTERN int32 casepc;
EXTERN int cbc;
EXTERN char* cbp;
@@ -279,22 +300,17 @@ EXTERN char* pcstr;
EXTERN Auto* curauto;
EXTERN Auto* curhist;
EXTERN Prog* curp;
-EXTERN Prog* curtext;
-EXTERN Prog* datap;
-EXTERN Prog* edatap;
-EXTERN int32 datsize;
+EXTERN Sym* cursym;
+EXTERN Sym* datap;
EXTERN int32 elfdatsize;
-EXTERN int32 dynptrsize;
EXTERN char debug[128];
EXTERN char literal[32];
-EXTERN Prog* etextp;
+EXTERN Sym* etextp;
EXTERN Prog* firstp;
-EXTERN int xrefresolv;
EXTERN uchar ycover[Ymax*Ymax];
EXTERN uchar* andptr;
EXTERN uchar and[100];
EXTERN char reg[D_NONE];
-EXTERN Prog* lastp;
EXTERN int32 lcsize;
EXTERN int maxop;
EXTERN int nerrors;
@@ -304,30 +320,22 @@ EXTERN char* rpath;
EXTERN int32 spsize;
EXTERN Sym* symlist;
EXTERN int32 symsize;
-EXTERN Prog* textp;
+EXTERN Sym* textp;
EXTERN int32 textsize;
-EXTERN int32 textpad;
EXTERN int version;
EXTERN Prog zprg;
EXTERN int dtype;
EXTERN int tlsoffset;
EXTERN Sym* adrgotype; // type symbol on last Adr read
EXTERN Sym* fromgotype; // type symbol on last p->from read
-
-EXTERN Adr* reloca;
-EXTERN int doexp, dlm;
-EXTERN int imports, nimports;
-EXTERN int exports, nexports;
-EXTERN char* EXPTAB;
-EXTERN Prog undefp;
-
-#define UP (&undefp)
+EXTERN int elftextsh;
extern Optab optab[];
extern char* anames[];
int Aconv(Fmt*);
int Dconv(Fmt*);
+int Iconv(Fmt*);
int Pconv(Fmt*);
int Rconv(Fmt*);
int Sconv(Fmt*);
@@ -336,29 +344,23 @@ Prog* appendp(Prog*);
void asmb(void);
void asmdyn(void);
void asmins(Prog*);
-void asmlc(void);
-void asmsp(void);
void asmsym(void);
int32 atolwhex(char*);
Prog* brchain(Prog*);
Prog* brloop(Prog*);
void cflush(void);
-void ckoff(Sym*, int32);
Prog* copyp(Prog*);
+vlong cpos(void);
double cputime(void);
-void datblk(int32, int32);
void diag(char*, ...);
void dodata(void);
void doelf(void);
-void doinit(void);
void doprof1(void);
void doprof2(void);
void dostkoff(void);
-void dynreloc(Sym*, uint32, int);
int32 entryvalue(void);
-void export(void);
void follow(void);
-void import(void);
+void instinit(void);
void listinit(void);
Sym* lookup(char*, int);
void lput(int32);
@@ -366,26 +368,20 @@ void lputl(int32);
void vputl(uvlong);
void strnput(char*, int);
void main(int, char*[]);
-void mkfwd(void);
void* mal(uint32);
-Prog* newdata(Sym*, int, int, int);
-Prog* newtext(Prog*, Sym*);
int opsize(Prog*);
void patch(void);
Prog* prg(void);
int relinv(int);
-int32 reuse(Prog*, Sym*);
int32 rnd(int32, int32);
void s8put(char*);
void span(void);
void undef(void);
-int32 vaddr(Adr*);
int32 symaddr(Sym*);
void wput(ushort);
void wputl(ushort);
void xdefine(char*, int, int32);
-void xfol(Prog*);
-void zaddr(Biobuf*, Adr*, Sym*[]);
+
uint32 machheadr(void);
vlong addaddr(Sym *s, Sym *t);
vlong addsize(Sym *s, Sym *t);
@@ -410,3 +406,9 @@ void deadcode(void);
#pragma varargck type "P" Prog*
#pragma varargck type "R" int
#pragma varargck type "A" int
+
+/* Used by ../ld/dwarf.c */
+enum
+{
+ DWARFREGSP = 4
+};
diff --git a/src/cmd/8l/list.c b/src/cmd/8l/list.c
index a5dbba7f8..4e199d767 100644
--- a/src/cmd/8l/list.c
+++ b/src/cmd/8l/list.c
@@ -28,6 +28,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+// Printing.
+
#include "l.h"
#include "../ld/lib.h"
@@ -40,6 +42,7 @@ listinit(void)
fmtinstall('D', Dconv);
fmtinstall('S', Sconv);
fmtinstall('P', Pconv);
+ fmtinstall('I', Iconv);
}
static Prog *bigP;
@@ -47,7 +50,6 @@ static Prog *bigP;
int
Pconv(Fmt *fp)
{
- char str[STRINGSZ];
Prog *p;
p = va_arg(fp->args, Prog*);
@@ -55,23 +57,23 @@ Pconv(Fmt *fp)
switch(p->as) {
case ATEXT:
if(p->from.scale) {
- sprint(str, "(%d) %A %D,%d,%D",
+ fmtprint(fp, "(%d) %A %D,%d,%D",
p->line, p->as, &p->from, p->from.scale, &p->to);
break;
}
default:
- sprint(str, "(%d) %A %D,%D",
+ fmtprint(fp, "(%d) %A %D,%D",
p->line, p->as, &p->from, &p->to);
break;
case ADATA:
- case AINIT:
- case ADYNT:
- sprint(str, "(%d) %A %D/%d,%D",
+ case AINIT_:
+ case ADYNT_:
+ fmtprint(fp, "(%d) %A %D/%d,%D",
p->line, p->as, &p->from, p->from.scale, &p->to);
break;
}
bigP = P;
- return fmtstrcpy(fp, str);
+ return 0;
}
int
@@ -102,15 +104,15 @@ Dconv(Fmt *fp)
i = a->type;
if(i >= D_INDIR && i < 2*D_INDIR) {
if(a->offset)
- sprint(str, "%ld(%R)", a->offset, i-D_INDIR);
+ snprint(str, sizeof str, "%d(%R)", a->offset, i-D_INDIR);
else
- sprint(str, "(%R)", i-D_INDIR);
+ snprint(str, sizeof str, "(%R)", i-D_INDIR);
goto brk;
}
switch(i) {
default:
- sprint(str, "%R", i);
+ snprint(str, sizeof str, "%R", i);
break;
case D_NONE:
@@ -120,54 +122,54 @@ Dconv(Fmt *fp)
case D_BRANCH:
if(bigP != P && bigP->pcond != P)
if(a->sym != S)
- sprint(str, "%lux+%s", bigP->pcond->pc,
+ snprint(str, sizeof str, "%ux+%s", bigP->pcond->pc,
a->sym->name);
else
- sprint(str, "%lux", bigP->pcond->pc);
+ snprint(str, sizeof str, "%ux", bigP->pcond->pc);
else
- sprint(str, "%ld(PC)", a->offset);
+ snprint(str, sizeof str, "%d(PC)", a->offset);
break;
case D_EXTERN:
- sprint(str, "%s+%ld(SB)", xsymname(a->sym), a->offset);
+ snprint(str, sizeof str, "%s+%d(SB)", xsymname(a->sym), a->offset);
break;
case D_STATIC:
- sprint(str, "%s<%d>+%ld(SB)", xsymname(a->sym),
+ snprint(str, sizeof str, "%s<%d>+%d(SB)", xsymname(a->sym),
a->sym->version, a->offset);
break;
case D_AUTO:
- sprint(str, "%s+%ld(SP)", xsymname(a->sym), a->offset);
+ snprint(str, sizeof str, "%s+%d(SP)", xsymname(a->sym), a->offset);
break;
case D_PARAM:
if(a->sym)
- sprint(str, "%s+%ld(FP)", a->sym->name, a->offset);
+ snprint(str, sizeof str, "%s+%d(FP)", a->sym->name, a->offset);
else
- sprint(str, "%ld(FP)", a->offset);
+ snprint(str, sizeof str, "%d(FP)", a->offset);
break;
case D_CONST:
- sprint(str, "$%ld", a->offset);
+ snprint(str, sizeof str, "$%d", a->offset);
break;
case D_CONST2:
- sprint(str, "$%ld-%ld", a->offset, a->offset2);
+ snprint(str, sizeof str, "$%d-%d", a->offset, a->offset2);
break;
case D_FCONST:
- sprint(str, "$(%.8lux,%.8lux)", a->ieee.h, a->ieee.l);
+ snprint(str, sizeof str, "$(%.8ux,%.8ux)", a->ieee.h, a->ieee.l);
break;
case D_SCONST:
- sprint(str, "$\"%S\"", a->scon);
+ snprint(str, sizeof str, "$\"%S\"", a->scon);
break;
case D_ADDR:
a->type = a->index;
a->index = D_NONE;
- sprint(str, "$%D", a);
+ snprint(str, sizeof str, "$%D", a);
a->index = a->type;
a->type = D_ADDR;
goto conv;
@@ -316,19 +318,48 @@ Sconv(Fmt *fp)
return fmtstrcpy(fp, str);
}
+int
+Iconv(Fmt *fp)
+{
+ int i, n;
+ uchar *p;
+ char *s;
+ Fmt fmt;
+
+ n = fp->prec;
+ fp->prec = 0;
+ if(!(fp->flags&FmtPrec) || n < 0)
+ return fmtstrcpy(fp, "%I");
+ fp->flags &= ~FmtPrec;
+ p = va_arg(fp->args, uchar*);
+
+ // format into temporary buffer and
+ // call fmtstrcpy to handle padding.
+ fmtstrinit(&fmt);
+ for(i=0; i<n; i++)
+ fmtprint(&fmt, "%.2ux", *p++);
+ s = fmtstrflush(&fmt);
+ fmtstrcpy(fp, s);
+ free(s);
+ return 0;
+}
+
void
diag(char *fmt, ...)
{
- char buf[STRINGSZ], *tn;
+ char buf[STRINGSZ], *tn, *sep;
va_list arg;
- tn = "??none??";
- if(curtext != P && curtext->from.sym != S)
- tn = curtext->from.sym->name;
+ tn = "";
+ sep = "";
+ if(cursym != S) {
+ tn = cursym->name;
+ sep = ": ";
+ }
va_start(arg, fmt);
vseprint(buf, buf+sizeof(buf), fmt, arg);
va_end(arg);
- print("%s: %s\n", tn, buf);
+ print("%s%s%s\n", tn, sep, buf);
nerrors++;
if(nerrors > 20) {
diff --git a/src/cmd/8l/obj.c b/src/cmd/8l/obj.c
index 1a3ecec1d..18b2112fe 100644
--- a/src/cmd/8l/obj.c
+++ b/src/cmd/8l/obj.c
@@ -28,11 +28,14 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+// Reading object files.
+
#define EXTERN
#include "l.h"
#include "../ld/lib.h"
#include "../ld/elf.h"
#include "../ld/macho.h"
+#include "../ld/dwarf.h"
#include "../ld/pe.h"
#include <ar.h>
@@ -52,32 +55,12 @@ char *thestring = "386";
* -H4 -Tx -Rx is fake MS-DOS .EXE
* -H6 -Tx -Rx is Apple Mach-O
* -H7 -Tx -Rx is Linux ELF32
- * -H8 -Tx -Rx is Google Native Client
+ * -H8 -Tx -Rx was Google Native Client
* -H9 -Tx -Rx is FreeBSD ELF32
+ * -H10 -Tx -Rx is MS Windows PE
+ * -H11 -Tx -Rx is tiny (os image)
*/
-static int
-isobjfile(char *f)
-{
- int n, v;
- Biobuf *b;
- char buf1[5], buf2[SARMAG];
-
- b = Bopen(f, OREAD);
- if(b == nil)
- return 0;
- n = Bread(b, buf1, 5);
- if(n == 5 && (buf1[2] == 1 && buf1[3] == '<' || buf1[3] == 1 && buf1[4] == '<'))
- v = 1; /* good enough for our purposes */
- else{
- Bseek(b, 0, 0);
- n = Bread(b, buf2, SARMAG);
- v = n == SARMAG && strncmp(buf2, ARMAG, SARMAG) == 0;
- }
- Bterm(b);
- return v;
-}
-
void
usage(void)
{
@@ -88,7 +71,7 @@ usage(void)
void
main(int argc, char *argv[])
{
- int i, c;
+ int c;
Binit(&bso, 1, OWRITE);
cout = -1;
@@ -152,9 +135,6 @@ main(int argc, char *argv[])
if(strcmp(goos, "darwin") == 0)
HEADTYPE = 6;
else
- if(strcmp(goos, "nacl") == 0)
- HEADTYPE = 8;
- else
if(strcmp(goos, "freebsd") == 0)
HEADTYPE = 9;
else
@@ -164,6 +144,9 @@ main(int argc, char *argv[])
if(strcmp(goos, "tiny") == 0)
HEADTYPE = 11;
else
+ if(strcmp(goos, "plan9") == 0)
+ HEADTYPE = 2;
+ else
print("goos is not known: %s\n", goos);
}
@@ -208,7 +191,7 @@ main(int argc, char *argv[])
if(INITDAT == -1)
INITDAT = 0;
if(INITRND == -1)
- INITRND = 4096;
+ INITRND = 1;
break;
case 3: /* MS-DOS .COM */
HEADR = 0;
@@ -229,7 +212,7 @@ main(int argc, char *argv[])
INITRND = 4;
HEADR += (INITTEXT & 0xFFFF);
if(debug['v'])
- Bprint(&bso, "HEADR = 0x%ld\n", HEADR);
+ Bprint(&bso, "HEADR = 0x%d\n", HEADR);
break;
case 6: /* apple MACH */
/*
@@ -249,7 +232,7 @@ main(int argc, char *argv[])
case 7: /* elf32 executable */
case 9:
/*
- * Linux ELF uses TLS offsets negative from %gs.
+ * 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.
@@ -264,30 +247,15 @@ main(int argc, char *argv[])
if(INITRND == -1)
INITRND = 4096;
break;
- case 8: /* native client elf32 executable */
- elfinit();
- HEADR = 4096;
- if(INITTEXT == -1)
- INITTEXT = 0x20000;
- if(INITDAT == -1)
- INITDAT = 0;
- if(INITRND == -1)
- INITRND = 65536;
-
- // 512 kB of address space for closures.
- // (Doesn't take any space in the binary file.)
- // Closures are 64 bytes each, so this is 8,192 closures.
- textpad = 512*1024;
- break;
case 10: /* PE executable */
peinit();
- HEADR = PERESERVE;
+ HEADR = PEFILEHEADR;
if(INITTEXT == -1)
- INITTEXT = PEBASE+0x1000;
+ INITTEXT = PEBASE+PESECTHEADR;
if(INITDAT == -1)
INITDAT = 0;
if(INITRND == -1)
- INITRND = PEALIGN;
+ INITRND = PESECTALIGN;
break;
case 11:
tlsoffset = 0;
@@ -302,68 +270,14 @@ main(int argc, char *argv[])
break;
}
if(INITDAT != 0 && INITRND != 0)
- print("warning: -D0x%lux is ignored because of -R0x%lux\n",
+ print("warning: -D0x%ux is ignored because of -R0x%ux\n",
INITDAT, INITRND);
if(debug['v'])
- Bprint(&bso, "HEADER = -H0x%ld -T0x%lux -D0x%lux -R0x%lux\n",
+ Bprint(&bso, "HEADER = -H0x%d -T0x%ux -D0x%ux -R0x%ux\n",
HEADTYPE, INITTEXT, INITDAT, INITRND);
Bflush(&bso);
- for(i=1; optab[i].as; i++)
- if(i != optab[i].as) {
- diag("phase error in optab: %d", i);
- errorexit();
- }
- maxop = i;
-
- for(i=0; i<Ymax; i++)
- ycover[i*Ymax + i] = 1;
-
- ycover[Yi0*Ymax + Yi8] = 1;
- ycover[Yi1*Ymax + Yi8] = 1;
-
- ycover[Yi0*Ymax + Yi32] = 1;
- ycover[Yi1*Ymax + Yi32] = 1;
- ycover[Yi8*Ymax + Yi32] = 1;
-
- ycover[Yal*Ymax + Yrb] = 1;
- ycover[Ycl*Ymax + Yrb] = 1;
- ycover[Yax*Ymax + Yrb] = 1;
- ycover[Ycx*Ymax + Yrb] = 1;
- ycover[Yrx*Ymax + Yrb] = 1;
-
- ycover[Yax*Ymax + Yrx] = 1;
- ycover[Ycx*Ymax + Yrx] = 1;
-
- ycover[Yax*Ymax + Yrl] = 1;
- ycover[Ycx*Ymax + Yrl] = 1;
- ycover[Yrx*Ymax + Yrl] = 1;
-
- ycover[Yf0*Ymax + Yrf] = 1;
-
- ycover[Yal*Ymax + Ymb] = 1;
- ycover[Ycl*Ymax + Ymb] = 1;
- ycover[Yax*Ymax + Ymb] = 1;
- ycover[Ycx*Ymax + Ymb] = 1;
- ycover[Yrx*Ymax + Ymb] = 1;
- ycover[Yrb*Ymax + Ymb] = 1;
- ycover[Ym*Ymax + Ymb] = 1;
-
- ycover[Yax*Ymax + Yml] = 1;
- ycover[Ycx*Ymax + Yml] = 1;
- ycover[Yrx*Ymax + Yml] = 1;
- ycover[Yrl*Ymax + Yml] = 1;
- ycover[Ym*Ymax + Yml] = 1;
-
- for(i=0; i<D_NONE; i++) {
- reg[i] = -1;
- if(i >= D_AL && i <= D_BH)
- reg[i] = (i-D_AL) & 7;
- if(i >= D_AX && i <= D_DI)
- reg[i] = (i-D_AX) & 7;
- if(i >= D_F0 && i <= D_F0+7)
- reg[i] = (i-D_F0) & 7;
- }
+ instinit();
zprg.link = P;
zprg.pcond = P;
zprg.back = 2;
@@ -373,49 +287,25 @@ main(int argc, char *argv[])
zprg.from.scale = 1;
zprg.to = zprg.from;
- pcstr = "%.6lux ";
+ pcstr = "%.6ux ";
nuxiinit();
histgen = 0;
- textp = P;
- datap = P;
- edatap = P;
pc = 0;
dtype = 4;
version = 0;
cbp = buf.cbuf;
cbc = sizeof(buf.cbuf);
- firstp = prg();
- lastp = firstp;
addlibpath("command line", "command line", argv[0], "main");
loadlib();
-
deadcode();
-
- firstp = firstp->link;
- if(firstp == P)
- errorexit();
- if(doexp || dlm){
- EXPTAB = "_exporttab";
- zerosig(EXPTAB);
- zerosig("etext");
- zerosig("edata");
- zerosig("end");
- if(dlm){
- import();
- HEADTYPE = 2;
- INITTEXT = INITDAT = 0;
- INITRND = 8;
- INITENTRY = EXPTAB;
- }
- export();
- }
patch();
follow();
doelf();
if(HEADTYPE == 6)
domacho();
- dodata();
+ if(HEADTYPE == 10)
+ dope();
dostkoff();
if(debug['p'])
if(debug['1'])
@@ -423,14 +313,18 @@ main(int argc, char *argv[])
else
doprof2();
span();
- doinit();
- if(HEADTYPE == 10)
- dope();
+ addexport();
+ textaddress();
+ pclntab();
+ symtab();
+ dodata();
+ address();
+ reloc();
asmb();
undef();
if(debug['v']) {
Bprint(&bso, "%5.2f cpu time\n", cputime());
- Bprint(&bso, "%ld symbols\n", nsymbol);
+ Bprint(&bso, "%d symbols\n", nsymbol);
Bprint(&bso, "%d sizeof adr\n", sizeof(Adr));
Bprint(&bso, "%d sizeof prog\n", sizeof(Prog));
}
@@ -439,8 +333,19 @@ main(int argc, char *argv[])
errorexit();
}
-void
-zaddr(Biobuf *f, Adr *a, Sym *h[])
+static Sym*
+zsym(char *pn, Biobuf *f, Sym *h[])
+{
+ int o;
+
+ o = Bgetc(f);
+ if(o < 0 || o >= NSYM || h[o] == nil)
+ mangle(pn);
+ return h[o];
+}
+
+static void
+zaddr(char *pn, Biobuf *f, Adr *a, Sym *h[])
{
int t;
int32 l;
@@ -465,7 +370,7 @@ zaddr(Biobuf *f, Adr *a, Sym *h[])
}
a->sym = S;
if(t & T_SYM)
- a->sym = h[Bgetc(f)];
+ a->sym = zsym(pn, f, h);
if(t & T_FCONST) {
a->ieee.l = Bget4(f);
a->ieee.h = Bget4(f);
@@ -479,7 +384,7 @@ zaddr(Biobuf *f, Adr *a, Sym *h[])
a->type = Bgetc(f);
adrgotype = S;
if(t & T_GOTYPE)
- adrgotype = h[Bgetc(f)];
+ adrgotype = zsym(pn, f, h);
t = a->type;
if(t == D_INDIR+D_GS)
@@ -526,7 +431,7 @@ void
ldobj1(Biobuf *f, char *pkg, int64 len, char *pn)
{
int32 ipc;
- Prog *p, *t;
+ Prog *p;
int v, o, r, skip;
Sym *h[NSYM], *s, *di;
uint32 sig;
@@ -534,7 +439,9 @@ ldobj1(Biobuf *f, char *pkg, int64 len, char *pn)
int32 eof;
char *name, *x;
char src[1024];
+ Prog *lastp;
+ lastp = nil;
ntext = 0;
eof = Boffset(f) + len;
di = S;
@@ -591,7 +498,7 @@ loop:
if(sig != 0){
if(s->sig != 0 && s->sig != sig)
diag("incompatible type signatures"
- "%lux(%s) and %lux(%s) for %s",
+ "%ux(%s) and %ux(%s) for %s",
s->sig, s->file, sig, pn, s->name);
s->sig = sig;
s->file = pn;
@@ -599,6 +506,8 @@ loop:
if(debug['W'])
print(" ANAME %s\n", s->name);
+ if(o < 0 || o >= nelem(h))
+ mangle(pn);
h[o] = s;
if((v == D_EXTERN || v == D_STATIC) && s->type == 0)
s->type = SXREF;
@@ -613,6 +522,7 @@ loop:
histfrogp++;
} else
collapsefrog(s);
+ dwarfaddfrag(s->value, s->name);
}
goto loop;
}
@@ -623,9 +533,9 @@ loop:
p->back = 2;
p->ft = 0;
p->tt = 0;
- zaddr(f, &p->from, h);
+ zaddr(pn, f, &p->from, h);
fromgotype = adrgotype;
- zaddr(f, &p->to, h);
+ zaddr(pn, f, &p->to, h);
if(debug['W'])
print("%P\n", p);
@@ -647,10 +557,10 @@ loop:
case AEND:
histtoauto();
- if(curtext != P)
- curtext->to.autom = curauto;
+ if(cursym != nil && cursym->text)
+ cursym->autom = curauto;
curauto = 0;
- curtext = P;
+ cursym = nil;
if(Boffset(f) == eof)
return;
goto newloop;
@@ -659,89 +569,41 @@ loop:
s = p->from.sym;
if(s->type == 0 || s->type == SXREF) {
s->type = SBSS;
- s->value = 0;
+ s->size = 0;
}
- if(s->type != SBSS) {
+ if(s->type != SBSS && !s->dupok) {
diag("%s: redefinition: %s in %s",
pn, s->name, TNAME);
s->type = SBSS;
- s->value = 0;
+ s->size = 0;
}
- if(p->to.offset > s->value)
- s->value = p->to.offset;
+ if(p->to.offset > s->size)
+ s->size = p->to.offset;
if(p->from.scale & DUPOK)
s->dupok = 1;
+ if(p->from.scale & RODATA)
+ s->type = SRODATA;
goto loop;
- case ADYNT:
- if(p->to.sym == S) {
- diag("DYNT without a sym\n%P", p);
- break;
- }
- di = p->to.sym;
- p->from.scale = 4;
- if(di->type == SXREF) {
- if(debug['z'])
- Bprint(&bso, "%P set to %d\n", p, dtype);
- di->type = SCONST;
- di->value = dtype;
- dtype += 4;
- }
- if(p->from.sym == S)
- break;
-
- p->from.offset = di->value;
- p->from.sym->type = SDATA;
- if(curtext == P) {
- diag("DYNT not in text: %P", p);
- break;
- }
- p->to.sym = curtext->from.sym;
- p->to.type = D_ADDR;
- p->to.index = D_EXTERN;
- goto data;
-
- case AINIT:
- if(p->from.sym == S) {
- diag("INIT without a sym\n%P", p);
- break;
- }
- if(di == S) {
- diag("INIT without previous DYNT\n%P", p);
- break;
- }
- p->from.offset = di->value;
- p->from.sym->type = SDATA;
- goto data;
-
case ADATA:
- data:
// Assume that AGLOBL comes after ADATA.
// If we've seen an AGLOBL that said this sym was DUPOK,
// ignore any more ADATA we see, which must be
// redefinitions.
s = p->from.sym;
- if(s != S && s->dupok) {
+ if(s->dupok) {
// if(debug['v'])
// Bprint(&bso, "skipping %s in %s: dupok\n", s->name, pn);
goto loop;
}
- if(s != S) {
- p->dlink = s->data;
- s->data = p;
- if(s->file == nil)
- s->file = pn;
- else if(s->file != pn) {
- diag("multiple initialization for %s: in both %s and %s", s->name, s->file, pn);
- errorexit();
- }
+ if(s->file == nil)
+ s->file = pn;
+ else if(s->file != pn) {
+ diag("multiple initialization for %s: in both %s and %s", s->name, s->file, pn);
+ errorexit();
}
- if(edatap == P)
- datap = p;
- else
- edatap->link = p;
- edatap = p;
- p->link = P;
+ savedata(s, p);
+ unmal(p, sizeof *p);
goto loop;
case AGOK:
@@ -751,9 +613,9 @@ loop:
case ATEXT:
s = p->from.sym;
- if(s == S) {
- diag("%s: no TEXT symbol: %P", pn, p);
- errorexit();
+ if(s->text != nil) {
+ diag("%s: %s: redefinition", pn, s->name);
+ return;
}
if(ntext++ == 0 && s->type != 0 && s->type != SXREF) {
/* redefinition, so file has probably been seen before */
@@ -761,13 +623,19 @@ loop:
diag("skipping: %s: redefinition: %s", pn, s->name);
return;
}
- if(curtext != P) {
+ if(cursym != nil && cursym->text) {
histtoauto();
- curtext->to.autom = curauto;
+ cursym->autom = curauto;
curauto = 0;
}
skip = 0;
- curtext = p;
+ if(etextp)
+ etextp->next = s;
+ else
+ textp = s;
+ etextp = s;
+ s->text = p;
+ cursym = s;
if(s->type != 0 && s->type != SXREF) {
if(p->from.scale & DUPOK) {
skip = 1;
@@ -775,7 +643,10 @@ loop:
}
diag("%s: redefinition: %s\n%P", pn, s->name, p);
}
- newtext(p, s);
+ s->type = STEXT;
+ s->value = pc;
+ lastp = p;
+ p->pc = pc++;
goto loop;
case AFMOVF:
@@ -791,24 +662,12 @@ loop:
goto casdef;
if(p->from.type == D_FCONST) {
/* size sb 9 max */
- sprint(literal, "$%lux", ieeedtof(&p->from.ieee));
+ sprint(literal, "$%ux", ieeedtof(&p->from.ieee));
s = lookup(literal, 0);
if(s->type == 0) {
- s->type = SBSS;
- s->value = 4;
- t = prg();
- t->as = ADATA;
- t->line = p->line;
- t->from.type = D_EXTERN;
- t->from.sym = s;
- t->from.scale = 4;
- t->to = p->from;
- if(edatap == P)
- datap = t;
- else
- edatap->link = t;
- edatap = t;
- t->link = P;
+ s->type = SDATA;
+ adduint32(s, ieeedtof(&p->from.ieee));
+ s->reachable = 0;
}
p->from.type = D_EXTERN;
p->from.sym = s;
@@ -829,25 +688,14 @@ loop:
goto casdef;
if(p->from.type == D_FCONST) {
/* size sb 18 max */
- sprint(literal, "$%lux.%lux",
+ sprint(literal, "$%ux.%ux",
p->from.ieee.l, p->from.ieee.h);
s = lookup(literal, 0);
if(s->type == 0) {
- s->type = SBSS;
- s->value = 8;
- t = prg();
- t->as = ADATA;
- t->line = p->line;
- t->from.type = D_EXTERN;
- t->from.sym = s;
- t->from.scale = 8;
- t->to = p->from;
- if(edatap == P)
- datap = t;
- else
- edatap->link = t;
- edatap = t;
- t->link = P;
+ s->type = SDATA;
+ adduint32(s, p->from.ieee.l);
+ adduint32(s, p->from.ieee.h);
+ s->reachable = 0;
}
p->from.type = D_EXTERN;
p->from.sym = s;
@@ -859,13 +707,18 @@ loop:
default:
if(skip)
nopout(p);
+ p->pc = pc;
+ pc++;
if(p->to.type == D_BRANCH)
p->to.offset += ipc;
+ if(lastp == nil) {
+ if(p->as != ANOP)
+ diag("unexpected instruction: %P", p);
+ goto loop;
+ }
lastp->link = p;
lastp = p;
- p->pc = pc;
- pc++;
goto loop;
}
goto loop;
@@ -905,153 +758,3 @@ appendp(Prog *q)
p->line = q->line;
return p;
}
-
-void
-doprof1(void)
-{
- Sym *s;
- int32 n;
- Prog *p, *q;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f profile 1\n", cputime());
- Bflush(&bso);
- s = lookup("__mcount", 0);
- n = 1;
- for(p = firstp->link; p != P; p = p->link) {
- if(p->as == ATEXT) {
- q = prg();
- q->line = p->line;
- q->link = datap;
- datap = q;
- q->as = ADATA;
- q->from.type = D_EXTERN;
- q->from.offset = n*4;
- q->from.sym = s;
- q->from.scale = 4;
- q->to = p->from;
- q->to.type = D_CONST;
-
- q = prg();
- q->line = p->line;
- q->pc = p->pc;
- q->link = p->link;
- p->link = q;
- p = q;
- p->as = AADDL;
- p->from.type = D_CONST;
- p->from.offset = 1;
- p->to.type = D_EXTERN;
- p->to.sym = s;
- p->to.offset = n*4 + 4;
-
- n += 2;
- continue;
- }
- }
- q = prg();
- q->line = 0;
- q->link = datap;
- datap = q;
-
- q->as = ADATA;
- q->from.type = D_EXTERN;
- q->from.sym = s;
- q->from.scale = 4;
- q->to.type = D_CONST;
- q->to.offset = n;
-
- s->type = SBSS;
- s->value = n*4;
-}
-
-void
-doprof2(void)
-{
- Sym *s2, *s4;
- Prog *p, *q, *ps2, *ps4;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f profile 2\n", cputime());
- Bflush(&bso);
-
- s2 = lookup("_profin", 0);
- s4 = lookup("_profout", 0);
- if(s2->type != STEXT || s4->type != STEXT) {
- diag("_profin/_profout not defined");
- return;
- }
-
- ps2 = P;
- ps4 = P;
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT) {
- if(p->from.sym == s2) {
- p->from.scale = 1;
- ps2 = p;
- }
- if(p->from.sym == s4) {
- p->from.scale = 1;
- ps4 = p;
- }
- }
- }
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT) {
- curtext = p;
-
- if(p->from.scale & NOPROF) { /* dont profile */
- for(;;) {
- q = p->link;
- if(q == P)
- break;
- if(q->as == ATEXT)
- break;
- p = q;
- }
- continue;
- }
-
- /*
- * JMPL profin
- */
- q = prg();
- q->line = p->line;
- q->pc = p->pc;
- q->link = p->link;
- p->link = q;
- p = q;
- p->as = ACALL;
- p->to.type = D_BRANCH;
- p->pcond = ps2;
- p->to.sym = s2;
-
- continue;
- }
- if(p->as == ARET) {
- /*
- * RET
- */
- q = prg();
- q->as = ARET;
- q->from = p->from;
- q->to = p->to;
- q->link = p->link;
- p->link = q;
-
- /*
- * JAL profout
- */
- p->as = ACALL;
- p->from = zprg.from;
- p->to = zprg.to;
- p->to.type = D_BRANCH;
- p->pcond = ps4;
- p->to.sym = s4;
-
- p = q;
-
- continue;
- }
- }
-}
diff --git a/src/cmd/8l/optab.c b/src/cmd/8l/optab.c
index 5b7be692e..fceab785d 100644
--- a/src/cmd/8l/optab.c
+++ b/src/cmd/8l/optab.c
@@ -696,8 +696,8 @@ Optab optab[] =
{ AFYL2X, ynone, Px, 0xd9, 0xf1 },
{ AFYL2XP1, ynone, Px, 0xd9, 0xf9 },
{ AEND },
- { ADYNT },
- { AINIT },
+ { ADYNT_ },
+ { AINIT_ },
{ ASIGNAME },
{ ACMPXCHGB, yrb_mb, Pm, 0xb0 },
{ ACMPXCHGL, yrl_ml, Pm, 0xb1 },
diff --git a/src/cmd/8l/pass.c b/src/cmd/8l/pass.c
index ace640d22..6e387b0b5 100644
--- a/src/cmd/8l/pass.c
+++ b/src/cmd/8l/pass.c
@@ -28,9 +28,13 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+// Code and data passes.
+
#include "l.h"
#include "../ld/lib.h"
+static void xfol(Prog*, Prog**);
+
// see ../../pkg/runtime/proc.c:/StackGuard
enum
{
@@ -38,138 +42,6 @@ enum
StackBig = 4096,
};
-void
-dodata(void)
-{
- int i;
- Sym *s;
- Prog *p;
- int32 t, u;
-
- if(debug['v'])
- Bprint(&bso, "%5.2f dodata\n", cputime());
- Bflush(&bso);
- for(p = datap; p != P; p = p->link) {
- s = p->from.sym;
- if(p->as == ADYNT || p->as == AINIT)
- s->value = dtype;
- if(s->type == SBSS)
- s->type = SDATA;
- if(s->type != SDATA && s->type != SELFDATA)
- diag("initialize non-data (%d): %s\n%P",
- s->type, s->name, p);
- t = p->from.offset + p->width;
- if(t > s->value)
- diag("initialize bounds (%ld): %s\n%P",
- s->value, s->name, p);
- }
-
- /* allocate elf guys - must be segregated from real data */
- datsize = 0;
- for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->link) {
- if(!s->reachable)
- continue;
- if(s->type != SELFDATA)
- continue;
- t = rnd(s->value, 4);
- s->size = t;
- s->value = datsize;
- datsize += t;
- }
- elfdatsize = datsize;
-
- /* allocate small guys */
- for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->link) {
- if(!s->reachable)
- continue;
- if(s->type != SDATA)
- if(s->type != SBSS)
- continue;
- t = s->value;
- if(t == 0 && s->name[0] != '.') {
- diag("%s: no size", s->name);
- t = 1;
- }
- t = rnd(t, 4);
- s->size = t;
- s->value = t;
- if(t > MINSIZ)
- continue;
- s->value = datsize;
- datsize += t;
- s->type = SDATA1;
- }
-
- /* allocate the rest of the data */
- for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->link) {
- if(s->type != SDATA) {
- if(s->type == SDATA1)
- s->type = SDATA;
- continue;
- }
- t = s->value;
- s->size = t;
- s->value = datsize;
- datsize += t;
- }
-
- if(debug['j']) {
- /*
- * pad data with bss that fits up to next
- * 8k boundary, then push data to 8k
- */
- u = rnd(datsize, 8192);
- u -= datsize;
- for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->link) {
- if(!s->reachable)
- continue;
- if(s->type != SBSS)
- continue;
- t = s->value;
- if(t > u)
- continue;
- u -= t;
- s->size = t;
- s->value = datsize;
- s->type = SDATA;
- datsize += t;
- }
- datsize += u;
- }
-
- if(dynptrsize > 0) {
- /* dynamic pointer section between data and bss */
- datsize = rnd(datsize, 4);
- }
-
- /* now the bss */
- bsssize = 0;
- for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->link) {
- if(!s->reachable)
- continue;
- if(s->type != SBSS)
- continue;
- t = s->value;
- s->size = t;
- s->value = bsssize + dynptrsize + datsize;
- bsssize += t;
- }
-
- xdefine("data", SBSS, 0);
- xdefine("edata", SBSS, datsize);
- xdefine("end", SBSS, dynptrsize + bsssize + datsize);
-
- if(debug['s'] || HEADTYPE == 8)
- xdefine("symdat", SFIXED, 0);
- else
- xdefine("symdat", SFIXED, SYMDATVA);
-}
-
Prog*
brchain(Prog *p)
{
@@ -186,19 +58,53 @@ brchain(Prog *p)
void
follow(void)
{
+ Prog *firstp, *lastp;
if(debug['v'])
Bprint(&bso, "%5.2f follow\n", cputime());
Bflush(&bso);
- firstp = prg();
- lastp = firstp;
- xfol(textp);
- lastp->link = P;
- firstp = firstp->link;
+
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ firstp = prg();
+ lastp = firstp;
+ xfol(cursym->text, &lastp);
+ lastp->link = nil;
+ cursym->text = firstp->link;
+ }
}
-void
-xfol(Prog *p)
+static int
+nofollow(int a)
+{
+ switch(a) {
+ case AJMP:
+ case ARET:
+ case AIRETL:
+ case AIRETW:
+ return 1;
+ }
+ return 0;
+}
+
+static int
+pushpop(int a)
+{
+ switch(a) {
+ case APUSHL:
+ case APUSHFL:
+ case APUSHW:
+ case APUSHFW:
+ case APOPL:
+ case APOPFL:
+ case APOPW:
+ case APOPFW:
+ return 1;
+ }
+ return 0;
+}
+
+static void
+xfol(Prog *p, Prog **last)
{
Prog *q;
int i;
@@ -207,46 +113,31 @@ xfol(Prog *p)
loop:
if(p == P)
return;
- if(p->as == ATEXT)
- curtext = p;
- if(!curtext->from.sym->reachable) {
- p = p->pcond;
- goto loop;
- }
if(p->as == AJMP)
if((q = p->pcond) != P && q->as != ATEXT) {
+ /* mark instruction as done and continue layout at target of jump */
p->mark = 1;
p = q;
if(p->mark == 0)
goto loop;
}
if(p->mark) {
- /* copy up to 4 instructions to avoid branch */
+ /*
+ * p goes here, but already used it elsewhere.
+ * copy up to 4 instructions or else branch to other copy.
+ */
for(i=0,q=p; i<4; i++,q=q->link) {
if(q == P)
break;
- if(q == lastp)
+ if(q == *last)
break;
a = q->as;
if(a == ANOP) {
i--;
continue;
}
- switch(a) {
- case AJMP:
- case ARET:
- case AIRETL:
-
- case APUSHL:
- case APUSHFL:
- case APUSHW:
- case APUSHFW:
- case APOPL:
- case APOPFL:
- case APOPW:
- case APOPFW:
- goto brk;
- }
+ if(nofollow(a) || pushpop(a))
+ break; // NOTE(rsc): arm does goto copy
if(q->pcond == P || q->pcond->mark)
continue;
if(a == ACALL || a == ALOOP)
@@ -259,8 +150,8 @@ loop:
q = copyp(p);
p = p->link;
q->mark = 1;
- lastp->link = q;
- lastp = q;
+ (*last)->link = q;
+ *last = q;
if(q->as != a || q->pcond == P || q->pcond->mark)
continue;
@@ -268,14 +159,13 @@ loop:
p = q->pcond;
q->pcond = q->link;
q->link = p;
- xfol(q->link);
+ xfol(q->link, last);
p = q->link;
if(p->mark)
return;
goto loop;
}
} /* */
- brk:;
q = prg();
q->as = AJMP;
q->line = p->line;
@@ -284,14 +174,22 @@ loop:
q->pcond = p;
p = q;
}
+
+ /* emit p */
p->mark = 1;
- lastp->link = p;
- lastp = p;
+ (*last)->link = p;
+ *last = p;
a = p->as;
- if(a == AJMP || a == ARET || a == AIRETL)
+
+ /* continue loop with what comes after p */
+ if(nofollow(a))
return;
- if(p->pcond != P)
- if(a != ACALL) {
+ if(p->pcond != P && a != ACALL) {
+ /*
+ * some kind of conditional branch.
+ * recurse to follow one path.
+ * continue loop on the other.
+ */
q = brchain(p->link);
if(q != P && q->mark)
if(a != ALOOP) {
@@ -299,7 +197,7 @@ loop:
p->link = p->pcond;
p->pcond = q;
}
- xfol(p->link);
+ xfol(p->link, last);
q = brchain(p->pcond);
if(q->mark) {
p->pcond = q;
@@ -339,28 +237,6 @@ relinv(int a)
}
void
-doinit(void)
-{
- Sym *s;
- Prog *p;
- int x;
-
- for(p = datap; p != P; p = p->link) {
- x = p->to.type;
- if(x != D_EXTERN && x != D_STATIC)
- continue;
- s = p->to.sym;
- if(s->type == 0 || s->type == SXREF)
- diag("undefined %s initializer of %s",
- s->name, p->from.sym->name);
- p->to.offset += s->value;
- p->to.type = D_CONST;
- if(s->type == SDATA || s->type == SBSS)
- p->to.offset += INITDAT;
- }
-}
-
-void
patch(void)
{
int32 c;
@@ -377,116 +253,106 @@ patch(void)
Bflush(&bso);
s = lookup("exit", 0);
vexit = s->value;
- for(p = firstp; p != P; p = p->link) {
- if(HEADTYPE == 10) {
- // Convert
- // op n(GS), reg
- // to
- // MOVL 0x2C(FS), reg
- // op n(reg), reg
- // The purpose of this patch is to fix some accesses
- // to extern register variables (TLS) on Windows, as
- // a different method is used to access them.
- if(p->from.type == D_INDIR+D_GS
- && p->to.type >= D_AX && p->to.type <= D_DI) {
- q = appendp(p);
- q->from = p->from;
- q->from.type += p->to.type-D_GS;
- q->to = p->to;
- q->as = p->as;
- p->as = AMOVL;
- p->from.type = D_INDIR+D_FS;
- p->from.offset = 0x2C;
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ for(p = cursym->text; p != P; p = p->link) {
+ if(HEADTYPE == 10) { // Windows
+ // Convert
+ // op n(GS), reg
+ // to
+ // MOVL 0x2C(FS), reg
+ // op n(reg), reg
+ // The purpose of this patch is to fix some accesses
+ // to extern register variables (TLS) on Windows, as
+ // a different method is used to access them.
+ if(p->from.type == D_INDIR+D_GS
+ && p->to.type >= D_AX && p->to.type <= D_DI) {
+ q = appendp(p);
+ q->from = p->from;
+ q->from.type = D_INDIR + p->to.type;
+ q->to = p->to;
+ q->as = p->as;
+ p->as = AMOVL;
+ p->from.type = D_INDIR+D_FS;
+ p->from.offset = 0x2C;
+ }
}
- }
- if(p->as == ATEXT)
- curtext = p;
- if(p->as == ACALL || (p->as == AJMP && p->to.type != D_BRANCH)) {
- s = p->to.sym;
- if(s) {
- if(debug['c'])
- Bprint(&bso, "%s calls %s\n", TNAME, s->name);
- switch(s->type) {
- default:
- /* diag prints TNAME first */
- diag("undefined: %s", s->name);
- s->type = STEXT;
- s->value = vexit;
- continue; // avoid more error messages
- case STEXT:
- p->to.offset = s->value;
- break;
- case SUNDEF:
- p->pcond = UP;
- p->to.offset = 0;
- break;
+ if(HEADTYPE == 7) { // Linux
+ // Running binaries under Xen requires using
+ // MOVL 0(GS), reg
+ // and then off(reg) instead of saying off(GS) directly
+ // when the offset is negative.
+ if(p->from.type == D_INDIR+D_GS && p->from.offset < 0
+ && p->to.type >= D_AX && p->to.type <= D_DI) {
+ q = appendp(p);
+ q->from = p->from;
+ q->from.type = D_INDIR + p->to.type;
+ q->to = p->to;
+ q->as = p->as;
+ p->as = AMOVL;
+ p->from.type = D_INDIR+D_GS;
+ p->from.offset = 0;
}
- p->to.type = D_BRANCH;
}
- }
- if(p->to.type != D_BRANCH || p->pcond == UP)
- continue;
- c = p->to.offset;
- for(q = firstp; q != P;) {
- if(q->forwd != P)
- if(c >= q->forwd->pc) {
- q = q->forwd;
+ if(HEADTYPE == 2) { // Plan 9
+ if(p->from.type == D_INDIR+D_GS
+ && p->to.type >= D_AX && p->to.type <= D_DI) {
+ p->as = AMOVL;
+ p->from.type = D_ADDR+D_STATIC;
+ p->from.offset += 0xdfffefc0;
+ }
+ }
+ if(p->as == ACALL || (p->as == AJMP && p->to.type != D_BRANCH)) {
+ s = p->to.sym;
+ if(s) {
+ if(debug['c'])
+ Bprint(&bso, "%s calls %s\n", TNAME, s->name);
+ if((s->type&~SSUB) != STEXT) {
+ /* diag prints TNAME first */
+ diag("undefined: %s", s->name);
+ s->type = STEXT;
+ s->value = vexit;
+ continue; // avoid more error messages
+ }
+ if(s->text == nil)
+ continue;
+ p->to.type = D_BRANCH;
+ p->to.offset = s->text->pc;
+ p->pcond = s->text;
+ continue;
+ }
+ }
+ if(p->to.type != D_BRANCH)
continue;
+ c = p->to.offset;
+ for(q = cursym->text; q != P;) {
+ if(c == q->pc)
+ break;
+ if(q->forwd != P && c >= q->forwd->pc)
+ q = q->forwd;
+ else
+ q = q->link;
}
- if(c == q->pc)
- break;
- q = q->link;
- }
- if(q == P) {
- diag("branch out of range in %s\n%P", TNAME, p);
- p->to.type = D_NONE;
+ if(q == P) {
+ diag("branch out of range in %s (%#ux)\n%P [%s]",
+ TNAME, c, p, p->to.sym ? p->to.sym->name : "<nil>");
+ p->to.type = D_NONE;
+ }
+ p->pcond = q;
}
- p->pcond = q;
}
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT)
- curtext = p;
- p->mark = 0; /* initialization for follow */
- if(p->pcond != P && p->pcond != UP) {
- p->pcond = brloop(p->pcond);
- if(p->pcond != P)
- if(p->to.type == D_BRANCH)
- p->to.offset = p->pcond->pc;
- }
- }
-}
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ if(cursym->text == nil || cursym->p != nil)
+ continue;
-#define LOG 5
-void
-mkfwd(void)
-{
- Prog *p;
- int i;
- int32 dwn[LOG], cnt[LOG];
- Prog *lst[LOG];
-
- for(i=0; i<LOG; i++) {
- if(i == 0)
- cnt[i] = 1; else
- cnt[i] = LOG * cnt[i-1];
- dwn[i] = 1;
- lst[i] = P;
- }
- i = 0;
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT)
- curtext = p;
- i--;
- if(i < 0)
- i = LOG-1;
- p->forwd = P;
- dwn[i]--;
- if(dwn[i] <= 0) {
- dwn[i] = cnt[i];
- if(lst[i] != P)
- lst[i]->forwd = p;
- lst[i] = p;
+ for(p = cursym->text; p != P; p = p->link) {
+ p->mark = 0; /* initialization for follow */
+ if(p->pcond != P) {
+ p->pcond = brloop(p->pcond);
+ if(p->pcond != P)
+ if(p->to.type == D_BRANCH)
+ p->to.offset = p->pcond->pc;
+ }
}
}
}
@@ -513,286 +379,221 @@ dostkoff(void)
{
Prog *p, *q, *q1;
int32 autoffset, deltasp;
- int a, f, curframe, curbecome, maxbecome;
+ int a;
Prog *pmorestack;
Sym *symmorestack;
pmorestack = P;
symmorestack = lookup("runtime.morestack", 0);
- if(symmorestack->type == STEXT)
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT) {
- if(p->from.sym == symmorestack) {
- pmorestack = p;
- p->from.scale |= NOSPLIT;
- break;
- }
- }
- }
- if(pmorestack == P)
+ if(symmorestack->type != STEXT)
diag("runtime.morestack not defined");
+ else {
+ pmorestack = symmorestack->text;
+ symmorestack->text->from.scale |= NOSPLIT;
+ }
- curframe = 0;
- curbecome = 0;
- maxbecome = 0;
- curtext = 0;
- for(p = firstp; p != P; p = p->link) {
-
- /* find out how much arg space is used in this TEXT */
- if(p->to.type == (D_INDIR+D_SP))
- if(p->to.offset > curframe)
- curframe = p->to.offset;
-
- switch(p->as) {
- case ATEXT:
- if(curtext && curtext->from.sym) {
- curtext->from.sym->frame = curframe;
- curtext->from.sym->become = curbecome;
- if(curbecome > maxbecome)
- maxbecome = curbecome;
- }
- curframe = 0;
- curbecome = 0;
-
- curtext = p;
- break;
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ if(cursym->text == nil || cursym->text->link == nil)
+ continue;
- case ARET:
- /* special form of RET is BECOME */
- if(p->from.type == D_CONST)
- if(p->from.offset > curbecome)
- curbecome = p->from.offset;
- break;
- }
- }
- if(curtext && curtext->from.sym) {
- curtext->from.sym->frame = curframe;
- curtext->from.sym->become = curbecome;
- if(curbecome > maxbecome)
- maxbecome = curbecome;
- }
+ p = cursym->text;
+ autoffset = p->to.offset;
+ if(autoffset < 0)
+ autoffset = 0;
+
+ q = P;
+ q1 = P;
+ if(pmorestack != P)
+ if(!(p->from.scale & NOSPLIT)) {
+ p = appendp(p); // load g into CX
+ switch(HEADTYPE) {
+ case 10: // Windows
+ p->as = AMOVL;
+ p->from.type = D_INDIR+D_FS;
+ p->from.offset = 0x2c;
+ p->to.type = D_CX;
- if(debug['b'])
- print("max become = %d\n", maxbecome);
- xdefine("ALEFbecome", STEXT, maxbecome);
+ p = appendp(p);
+ p->as = AMOVL;
+ p->from.type = D_INDIR+D_CX;
+ p->from.offset = 0;
+ p->to.type = D_CX;
+ break;
+
+ case 7: // Linux
+ p->as = AMOVL;
+ p->from.type = D_INDIR+D_GS;
+ p->from.offset = 0;
+ p->to.type = D_CX;
- curtext = 0;
- for(p = firstp; p != P; p = p->link) {
- switch(p->as) {
- case ATEXT:
- curtext = p;
- break;
- case ACALL:
- if(curtext != P && curtext->from.sym != S && curtext->to.offset >= 0) {
- f = maxbecome - curtext->from.sym->frame;
- if(f <= 0)
- break;
- /* calling a become or calling a variable */
- if(p->to.sym == S || p->to.sym->become) {
- curtext->to.offset += f;
- if(debug['b']) {
- curp = p;
- print("%D calling %D increase %d\n",
- &curtext->from, &p->to, f);
- }
- }
+ p = appendp(p);
+ p->as = AMOVL;
+ p->from.type = D_INDIR+D_CX;
+ p->from.offset = tlsoffset + 0;
+ p->to.type = D_CX;
+ break;
+
+ case 2: // Plan 9
+ p->as = AMOVL;
+ p->from.type = D_ADDR+D_STATIC;
+ p->from.offset = 0xdfffefc0;
+ p->to.type = D_CX;
+ break;
+
+ default:
+ p->as = AMOVL;
+ p->from.type = D_INDIR+D_GS;
+ p->from.offset = tlsoffset + 0;
+ p->to.type = D_CX;
}
- break;
- }
- }
- autoffset = 0;
- deltasp = 0;
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT) {
- curtext = p;
- autoffset = p->to.offset;
- if(autoffset < 0)
- autoffset = 0;
-
- q = P;
- q1 = P;
- if(pmorestack != P)
- if(!(p->from.scale & NOSPLIT)) {
- p = appendp(p); // load g into CX
- if(HEADTYPE == 10) {
- p->as = AMOVL;
- p->from.type = D_INDIR+D_FS;
- p->from.offset = 0x2c;
- p->to.type = D_CX;
+ if(debug['K']) {
+ // 8l -K means check not only for stack
+ // overflow but stack underflow.
+ // On underflow, INT 3 (breakpoint).
+ // Underflow itself is rare but this also
+ // catches out-of-sync stack guard info.
+ p = appendp(p);
+ p->as = ACMPL;
+ p->from.type = D_INDIR+D_CX;
+ p->from.offset = 4;
+ p->to.type = D_SP;
- p = appendp(p);
- p->as = AMOVL;
- p->from.type = D_INDIR+D_CX;
- p->from.offset = 0;
- p->to.type = D_CX;
- } else {
- p->as = AMOVL;
- p->from.type = D_INDIR+D_GS;
- p->from.offset = tlsoffset + 0;
- p->to.type = D_CX;
- }
+ p = appendp(p);
+ p->as = AJCC;
+ p->to.type = D_BRANCH;
+ p->to.offset = 4;
+ q1 = p;
- if(debug['K']) {
- // 8l -K means check not only for stack
- // overflow but stack underflow.
- // On underflow, INT 3 (breakpoint).
- // Underflow itself is rare but this also
- // catches out-of-sync stack guard info.
- p = appendp(p);
- p->as = ACMPL;
- p->from.type = D_INDIR+D_CX;
- p->from.offset = 4;
- p->to.type = D_SP;
+ p = appendp(p);
+ p->as = AINT;
+ p->from.type = D_CONST;
+ p->from.offset = 3;
+
+ p = appendp(p);
+ p->as = ANOP;
+ q1->pcond = p;
+ }
+ if(autoffset < StackBig) { // do we need to call morestack
+ if(autoffset <= StackSmall) {
+ // small stack
p = appendp(p);
- p->as = AJCC;
- p->to.type = D_BRANCH;
- p->to.offset = 4;
- q1 = p;
-
+ p->as = ACMPL;
+ p->from.type = D_SP;
+ p->to.type = D_INDIR+D_CX;
+ } else {
+ // large stack
p = appendp(p);
- p->as = AINT;
- p->from.type = D_CONST;
- p->from.offset = 3;
- }
-
- if(autoffset < StackBig) { // do we need to call morestack
- if(autoffset <= StackSmall) {
- // small stack
- p = appendp(p);
- p->as = ACMPL;
- p->from.type = D_SP;
- p->to.type = D_INDIR+D_CX;
- if(q1) {
- q1->pcond = p;
- q1 = P;
- }
- } else {
- // large stack
- p = appendp(p);
- p->as = ALEAL;
- p->from.type = D_INDIR+D_SP;
- p->from.offset = -(autoffset-StackSmall);
- p->to.type = D_AX;
- if(q1) {
- q1->pcond = p;
- q1 = P;
- }
-
- p = appendp(p);
- p->as = ACMPL;
- p->from.type = D_AX;
- p->to.type = D_INDIR+D_CX;
- }
+ p->as = ALEAL;
+ p->from.type = D_INDIR+D_SP;
+ p->from.offset = -(autoffset-StackSmall);
+ p->to.type = D_AX;
- // common
p = appendp(p);
- p->as = AJHI;
- p->to.type = D_BRANCH;
- p->to.offset = 4;
- q = p;
+ p->as = ACMPL;
+ p->from.type = D_AX;
+ p->to.type = D_INDIR+D_CX;
}
- 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 > 4096)
- p->from.offset = (autoffset+160) & ~7LL;
-
- p = appendp(p); // save arg size in AX
- p->as = AMOVL;
- p->to.type = D_AX;
- p->from.type = D_CONST;
- p->from.offset = curtext->to.offset2;
-
+ // common
p = appendp(p);
- p->as = ACALL;
+ p->as = AJHI;
p->to.type = D_BRANCH;
- p->pcond = pmorestack;
- p->to.sym = symmorestack;
-
+ p->to.offset = 4;
+ q = p;
}
- if(q != P)
- q->pcond = p->link;
+ 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 > 4096)
+ p->from.offset = (autoffset+160) & ~7LL;
+
+ p = appendp(p); // save arg size in AX
+ p->as = AMOVL;
+ p->to.type = D_AX;
+ p->from.type = D_CONST;
+ p->from.offset = cursym->text->to.offset2;
+
+ p = appendp(p);
+ p->as = ACALL;
+ p->to.type = D_BRANCH;
+ p->pcond = pmorestack;
+ p->to.sym = symmorestack;
- if(autoffset) {
- p = appendp(p);
- p->as = AADJSP;
- p->from.type = D_CONST;
- p->from.offset = autoffset;
- if(q != P)
- q->pcond = p;
- }
- deltasp = autoffset;
- }
- a = p->from.type;
- if(a == D_AUTO)
- p->from.offset += deltasp;
- if(a == D_PARAM)
- p->from.offset += deltasp + 4;
- a = p->to.type;
- if(a == D_AUTO)
- p->to.offset += deltasp;
- if(a == D_PARAM)
- p->to.offset += deltasp + 4;
-
- switch(p->as) {
- default:
- continue;
- case APUSHL:
- case APUSHFL:
- deltasp += 4;
- continue;
- case APUSHW:
- case APUSHFW:
- deltasp += 2;
- continue;
- case APOPL:
- case APOPFL:
- deltasp -= 4;
- continue;
- case APOPW:
- case APOPFW:
- deltasp -= 2;
- continue;
- case ARET:
- break;
}
- if(autoffset != deltasp)
- diag("unbalanced PUSH/POP");
- if(p->from.type == D_CONST)
- goto become;
+ if(q != P)
+ q->pcond = p->link;
if(autoffset) {
- q = p;
p = appendp(p);
- p->as = ARET;
-
- q->as = AADJSP;
- q->from.type = D_CONST;
- q->from.offset = -autoffset;
+ p->as = AADJSP;
+ p->from.type = D_CONST;
+ p->from.offset = autoffset;
+ p->spadj = autoffset;
+ if(q != P)
+ q->pcond = p;
+ }
+ deltasp = autoffset;
+
+ for(; p != P; p = p->link) {
+ a = p->from.type;
+ if(a == D_AUTO)
+ p->from.offset += deltasp;
+ if(a == D_PARAM)
+ p->from.offset += deltasp + 4;
+ a = p->to.type;
+ if(a == D_AUTO)
+ p->to.offset += deltasp;
+ if(a == D_PARAM)
+ p->to.offset += deltasp + 4;
+
+ switch(p->as) {
+ default:
+ continue;
+ case APUSHL:
+ case APUSHFL:
+ deltasp += 4;
+ p->spadj = 4;
+ continue;
+ case APUSHW:
+ case APUSHFW:
+ deltasp += 2;
+ p->spadj = 2;
+ continue;
+ case APOPL:
+ case APOPFL:
+ deltasp -= 4;
+ p->spadj = -4;
+ continue;
+ case APOPW:
+ case APOPFW:
+ deltasp -= 2;
+ p->spadj = -2;
+ continue;
+ case ARET:
+ break;
+ }
+
+ if(autoffset != deltasp)
+ diag("unbalanced PUSH/POP");
+
+ if(autoffset) {
+ q = p;
+ p = appendp(p);
+ p->as = ARET;
+
+ q->as = AADJSP;
+ q->from.type = D_CONST;
+ q->from.offset = -autoffset;
+ p->spadj = -autoffset;
+ }
}
- continue;
-
- become:
- q = p;
- p = appendp(p);
- p->as = AJMP;
- p->to = q->to;
- p->pcond = q->pcond;
-
- q->as = AADJSP;
- q->from = zprg.from;
- q->from.type = D_CONST;
- q->from.offset = -autoffset;
- q->to = zprg.to;
- continue;
}
}
@@ -843,176 +644,7 @@ undef(void)
Sym *s;
for(i=0; i<NHASH; i++)
- for(s = hash[i]; s != S; s = s->link)
+ for(s = hash[i]; s != S; s = s->hash)
if(s->type == SXREF)
- diag("%s: not defined", s->name);
-}
-
-void
-import(void)
-{
- int i;
- Sym *s;
-
- for(i = 0; i < NHASH; i++)
- for(s = hash[i]; s != S; s = s->link)
- if(s->sig != 0 && s->type == SXREF && (nimports == 0 || s->subtype == SIMPORT)){
- if(s->value != 0)
- diag("value != 0 on SXREF");
- undefsym(s);
- Bprint(&bso, "IMPORT: %s sig=%lux v=%ld\n", s->name, s->sig, s->value);
- if(debug['S'])
- s->sig = 0;
- }
-}
-
-void
-ckoff(Sym *s, int32 v)
-{
- if(v < 0 || v >= 1<<Roffset)
- diag("relocation offset %ld for %s out of range", v, s->name);
-}
-
-Prog*
-newdata(Sym *s, int o, int w, int t)
-{
- Prog *p;
-
- p = prg();
- if(edatap == P)
- datap = p;
- else
- edatap->link = p;
- edatap = p;
- p->as = ADATA;
- p->width = w;
- p->from.scale = w;
- p->from.type = t;
- p->from.sym = s;
- p->from.offset = o;
- p->to.type = D_CONST;
- p->dlink = s->data;
- s->data = p;
- return p;
-}
-
-Prog*
-newtext(Prog *p, Sym *s)
-{
- if(p == P) {
- p = prg();
- p->as = ATEXT;
- p->from.sym = s;
- }
- s->type = STEXT;
- s->text = p;
- s->value = pc;
- lastp->link = p;
- lastp = p;
- p->pc = pc++;
- if(textp == P)
- textp = p;
- else
- etextp->pcond = p;
- etextp = p;
- return p;
-}
-
-void
-export(void)
-{
- int i, j, n, off, nb, sv, ne;
- Sym *s, *et, *str, **esyms;
- Prog *p;
- char buf[NSNAME], *t;
-
- n = 0;
- for(i = 0; i < NHASH; i++)
- for(s = hash[i]; s != S; s = s->link)
- if(s->sig != 0 && s->type != SXREF && s->type != SUNDEF && (nexports == 0 || s->subtype == SEXPORT))
- n++;
- esyms = mal(n*sizeof(Sym*));
- ne = n;
- n = 0;
- for(i = 0; i < NHASH; i++)
- for(s = hash[i]; s != S; s = s->link)
- if(s->sig != 0 && s->type != SXREF && s->type != SUNDEF && (nexports == 0 || s->subtype == SEXPORT))
- esyms[n++] = s;
- for(i = 0; i < ne-1; i++)
- for(j = i+1; j < ne; j++)
- if(strcmp(esyms[i]->name, esyms[j]->name) > 0){
- s = esyms[i];
- esyms[i] = esyms[j];
- esyms[j] = s;
- }
-
- nb = 0;
- off = 0;
- et = lookup(EXPTAB, 0);
- if(et->type != 0 && et->type != SXREF)
- diag("%s already defined", EXPTAB);
- et->type = SDATA;
- str = lookup(".string", 0);
- if(str->type == 0)
- str->type = SDATA;
- sv = str->value;
- for(i = 0; i < ne; i++){
- s = esyms[i];
- if(debug['S'])
- s->sig = 0;
- /* Bprint(&bso, "EXPORT: %s sig=%lux t=%d\n", s->name, s->sig, s->type); */
-
- /* signature */
- p = newdata(et, off, sizeof(int32), D_EXTERN);
- off += sizeof(int32);
- p->to.offset = s->sig;
-
- /* address */
- p = newdata(et, off, sizeof(int32), D_EXTERN);
- off += sizeof(int32);
- p->to.type = D_ADDR;
- p->to.index = D_EXTERN;
- p->to.sym = s;
-
- /* string */
- t = s->name;
- n = strlen(t)+1;
- for(;;){
- buf[nb++] = *t;
- sv++;
- if(nb >= NSNAME){
- p = newdata(str, sv-NSNAME, NSNAME, D_STATIC);
- p->to.type = D_SCONST;
- memmove(p->to.scon, buf, NSNAME);
- nb = 0;
- }
- if(*t++ == 0)
- break;
- }
-
- /* name */
- p = newdata(et, off, sizeof(int32), D_EXTERN);
- off += sizeof(int32);
- p->to.type = D_ADDR;
- p->to.index = D_STATIC;
- p->to.sym = str;
- p->to.offset = sv-n;
- }
-
- if(nb > 0){
- p = newdata(str, sv-nb, nb, D_STATIC);
- p->to.type = D_SCONST;
- memmove(p->to.scon, buf, nb);
- }
-
- for(i = 0; i < 3; i++){
- newdata(et, off, sizeof(int32), D_EXTERN);
- off += sizeof(int32);
- }
- et->value = off;
- if(sv == 0)
- sv = 1;
- str->value = sv;
- exports = ne;
- free(esyms);
+ diag("%s(%d): not defined", s->name, s->version);
}
diff --git a/src/cmd/8l/prof.c b/src/cmd/8l/prof.c
new file mode 100644
index 000000000..4e95fad79
--- /dev/null
+++ b/src/cmd/8l/prof.c
@@ -0,0 +1,173 @@
+// Inferno utils/8l/obj.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8l/obj.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+// Profiling.
+
+#include "l.h"
+#include "../ld/lib.h"
+
+void
+doprof1(void)
+{
+#if 0 // TODO(rsc)
+ Sym *s;
+ int32 n;
+ Prog *p, *q;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f profile 1\n", cputime());
+ Bflush(&bso);
+ s = lookup("__mcount", 0);
+ n = 1;
+ for(p = firstp->link; p != P; p = p->link) {
+ if(p->as == ATEXT) {
+ q = prg();
+ q->line = p->line;
+ q->link = datap;
+ datap = q;
+ q->as = ADATA;
+ q->from.type = D_EXTERN;
+ q->from.offset = n*4;
+ q->from.sym = s;
+ q->from.scale = 4;
+ q->to = p->from;
+ q->to.type = D_CONST;
+
+ q = prg();
+ q->line = p->line;
+ q->pc = p->pc;
+ q->link = p->link;
+ p->link = q;
+ p = q;
+ p->as = AADDL;
+ p->from.type = D_CONST;
+ p->from.offset = 1;
+ p->to.type = D_EXTERN;
+ p->to.sym = s;
+ p->to.offset = n*4 + 4;
+
+ n += 2;
+ continue;
+ }
+ }
+ q = prg();
+ q->line = 0;
+ q->link = datap;
+ datap = q;
+
+ q->as = ADATA;
+ q->from.type = D_EXTERN;
+ q->from.sym = s;
+ q->from.scale = 4;
+ q->to.type = D_CONST;
+ q->to.offset = n;
+
+ s->type = SBSS;
+ s->size = n*4;
+#endif
+}
+
+void
+doprof2(void)
+{
+ Sym *s2, *s4;
+ Prog *p, *q, *ps2, *ps4;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f profile 2\n", cputime());
+ Bflush(&bso);
+
+ s2 = lookup("_profin", 0);
+ s4 = lookup("_profout", 0);
+ if(s2->type != STEXT || s4->type != STEXT) {
+ diag("_profin/_profout not defined");
+ return;
+ }
+
+ ps2 = P;
+ ps4 = P;
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ p = cursym->text;
+ if(p->from.sym == s2) {
+ p->from.scale = 1;
+ ps2 = p;
+ }
+ if(p->from.sym == s4) {
+ p->from.scale = 1;
+ ps4 = p;
+ }
+ }
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ p = cursym->text;
+
+ if(p->from.scale & NOPROF) /* dont profile */
+ continue;
+
+ /*
+ * JMPL profin
+ */
+ q = prg();
+ q->line = p->line;
+ q->pc = p->pc;
+ q->link = p->link;
+ p->link = q;
+ p = q;
+ p->as = ACALL;
+ p->to.type = D_BRANCH;
+ p->pcond = ps2;
+ p->to.sym = s2;
+
+ for(; p; p=p->link) {
+ if(p->as == ARET) {
+ /*
+ * RET
+ */
+ q = prg();
+ q->as = ARET;
+ q->from = p->from;
+ q->to = p->to;
+ q->link = p->link;
+ p->link = q;
+
+ /*
+ * JAL profout
+ */
+ p->as = ACALL;
+ p->from = zprg.from;
+ p->to = zprg.to;
+ p->to.type = D_BRANCH;
+ p->pcond = ps4;
+ p->to.sym = s4;
+
+ p = q;
+ }
+ }
+ }
+}
diff --git a/src/cmd/8l/span.c b/src/cmd/8l/span.c
index 99ba279da..66a843b23 100644
--- a/src/cmd/8l/span.c
+++ b/src/cmd/8l/span.c
@@ -28,29 +28,28 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+// Instruction layout.
+
#include "l.h"
#include "../ld/lib.h"
+static int32 vaddr(Adr*, Reloc*);
+
void
-span(void)
+span1(Sym *s)
{
Prog *p, *q;
- int32 v, c, idat;
- int m, n, again;
-
- xdefine("etext", STEXT, 0L);
- idat = INITDAT;
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT)
- curtext = p;
- n = 0;
- if(p->to.type == D_BRANCH)
- if(p->pcond == P)
- p->pcond = p;
- if((q = p->pcond) != P)
- if(q->back != 2)
- n = 1;
- p->back = n;
+ int32 c, v, loop;
+ uchar *bp;
+ int n, m, i;
+
+ cursym = s;
+
+ for(p = s->text; p != P; p = p->link) {
+ p->back = 2; // use short branches first time through
+ if((q = p->pcond) != P && (q->back & 2))
+ p->back |= 1; // backward jump
+
if(p->as == AADJSP) {
p->to.type = D_SP;
v = -p->from.offset;
@@ -65,293 +64,186 @@ span(void)
p->as = ANOP;
}
}
-
+
n = 0;
-start:
- do{
- again = 0;
- if(debug['v'])
- Bprint(&bso, "%5.2f span %d\n", cputime(), n);
- Bflush(&bso);
- if(n > 50) {
- print("span must be looping - %d\n", textsize);
+ do {
+ loop = 0;
+ memset(s->r, 0, s->nr*sizeof s->r[0]);
+ s->nr = 0;
+ s->np = 0;
+ c = 0;
+ for(p = s->text; p != P; p = p->link) {
+ p->pc = c;
+
+ // process forward jumps to p
+ for(q = p->comefrom; q != P; q = q->forwd) {
+ v = p->pc - (q->pc + q->mark);
+ if(q->back & 2) { // short
+ if(v > 127) {
+ loop++;
+ q->back ^= 2;
+ }
+ s->p[q->pc+1] = v;
+ } else {
+ bp = s->p + q->pc + q->mark - 4;
+ *bp++ = v;
+ *bp++ = v>>8;
+ *bp++ = v>>16;
+ *bp++ = v>>24;
+ }
+ }
+ p->comefrom = P;
+
+ asmins(p);
+ p->pc = c;
+ m = andptr-and;
+ symgrow(s, p->pc+m);
+ memmove(s->p+p->pc, and, m);
+ p->mark = m;
+ c += m;
+ }
+ if(++n > 20) {
+ diag("span must be looping");
errorexit();
}
- c = INITTEXT;
- for(p = firstp; p != P; p = p->link) {
- if(p->as == ATEXT) {
- curtext = p;
- if(HEADTYPE == 8)
- c = (c+31)&~31;
- }
- if(p->to.type == D_BRANCH)
- if(p->back)
- p->pc = c;
- if(n == 0 || HEADTYPE == 8 || p->to.type == D_BRANCH) {
- if(HEADTYPE == 8)
- p->pc = c;
- asmins(p);
- m = andptr-and;
- if(p->mark != m)
- again = 1;
- p->mark = m;
- }
- if(HEADTYPE == 8) {
- c = p->pc + p->mark;
- } else {
- p->pc = c;
- c += p->mark;
- }
+ } while(loop);
+ s->size = c;
+
+ if(debug['a'] > 1) {
+ print("span1 %s %d (%d tries)\n %.6ux", s->name, s->size, n, 0);
+ for(i=0; i<s->np; i++) {
+ print(" %.2ux", s->p[i]);
+ if(i%16 == 15)
+ print("\n %.6ux", i+1);
}
- textsize = c;
- n++;
- }while(again);
-
- if(INITRND) {
- INITDAT = rnd(c+textpad, INITRND);
- if(INITDAT != idat) {
- idat = INITDAT;
- goto start;
+ if(i%16)
+ print("\n");
+
+ for(i=0; i<s->nr; i++) {
+ Reloc *r;
+
+ r = &s->r[i];
+ print(" rel %#.4ux/%d %s%+d\n", r->off, r->siz, r->sym->name, r->add);
}
}
- xdefine("etext", STEXT, c);
- if(debug['v'])
- Bprint(&bso, "etext = %lux\n", c);
- Bflush(&bso);
- for(p = textp; p != P; p = p->pcond)
- p->from.sym->value = p->pc;
- textsize = c - INITTEXT;
}
void
-xdefine(char *p, int t, int32 v)
+span(void)
{
- Sym *s;
-
- s = lookup(p, 0);
- if(s->type == 0 || s->type == SXREF) {
- s->type = t;
- s->value = v;
- }
- if(s->type == STEXT && s->value == 0)
- s->value = v;
-}
+ Prog *p, *q;
+ int32 v;
+ int n;
-void
-putsymb(char *s, int t, int32 v, int ver, Sym *go)
-{
- int i, f;
- vlong gv;
-
- if(t == 'f')
- s++;
- lput(v);
- if(ver)
- t += 'a' - 'A';
- cput(t+0x80); /* 0x80 is variable length */
-
- if(t == 'Z' || t == 'z') {
- cput(s[0]);
- for(i=1; s[i] != 0 || s[i+1] != 0; i += 2) {
- cput(s[i]);
- cput(s[i+1]);
- }
- cput(0);
- cput(0);
- i++;
- }
- else {
- for(i=0; s[i]; i++)
- cput(s[i]);
- cput(0);
- }
- gv = 0;
- if(go) {
- if(!go->reachable)
- sysfatal("unreachable type %s", go->name);
- gv = go->value+INITDAT;
- }
- lput(gv);
+ if(debug['v'])
+ Bprint(&bso, "%5.2f span\n", cputime());
- symsize += 4 + 1 + i+1 + 4;
+ // NOTE(rsc): If we get rid of the globals we should
+ // be able to parallelize these iterations.
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ if(cursym->text == nil || cursym->text->link == nil)
+ continue;
- if(debug['n']) {
- if(t == 'z' || t == 'Z') {
- Bprint(&bso, "%c %.8lux ", t, v);
- for(i=1; s[i] != 0 || s[i+1] != 0; i+=2) {
- f = ((s[i]&0xff) << 8) | (s[i+1]&0xff);
- Bprint(&bso, "/%x", f);
+ // TODO: move into span1
+ for(p = cursym->text; p != P; p = p->link) {
+ n = 0;
+ if(p->to.type == D_BRANCH)
+ if(p->pcond == P)
+ p->pcond = p;
+ if((q = p->pcond) != P)
+ if(q->back != 2)
+ n = 1;
+ p->back = n;
+ if(p->as == AADJSP) {
+ p->to.type = D_SP;
+ v = -p->from.offset;
+ p->from.offset = v;
+ p->as = AADDL;
+ if(v < 0) {
+ p->as = ASUBL;
+ v = -v;
+ p->from.offset = v;
+ }
+ if(v == 0)
+ p->as = ANOP;
}
- Bprint(&bso, "\n");
- return;
}
- if(ver)
- Bprint(&bso, "%c %.8lux %s<%d> %s (%.8llux)\n", t, v, s, ver, go ? go->name : "", gv);
- else
- Bprint(&bso, "%c %.8lux %s\n", t, v, s, go ? go->name : "", gv);
+ span1(cursym);
}
}
void
-asmsym(void)
+xdefine(char *p, int t, int32 v)
{
- Prog *p;
- Auto *a;
Sym *s;
- int h;
-
- s = lookup("etext", 0);
- if(s->type == STEXT)
- putsymb(s->name, 'T', s->value, s->version, 0);
-
- for(h=0; h<NHASH; h++)
- for(s=hash[h]; s!=S; s=s->link)
- switch(s->type) {
- case SCONST:
- if(!s->reachable)
- continue;
- putsymb(s->name, 'D', s->value, s->version, s->gotype);
- continue;
-
- case SDATA:
- case SELFDATA:
- if(!s->reachable)
- continue;
- putsymb(s->name, 'D', s->value+INITDAT, s->version, s->gotype);
- continue;
-
- case SMACHO:
- if(!s->reachable)
- continue;
- putsymb(s->name, 'D', s->value+INITDAT+datsize+bsssize, s->version, s->gotype);
- continue;
-
- case SBSS:
- if(!s->reachable)
- continue;
- putsymb(s->name, 'B', s->value+INITDAT, s->version, s->gotype);
- continue;
-
- case SFIXED:
- putsymb(s->name, 'B', s->value, s->version, s->gotype);
- continue;
-
- case SFILE:
- putsymb(s->name, 'f', s->value, s->version, 0);
- continue;
- }
- for(p=textp; p!=P; p=p->pcond) {
- s = p->from.sym;
- if(s->type != STEXT)
- continue;
-
- /* filenames first */
- for(a=p->to.autom; a; a=a->link)
- if(a->type == D_FILE)
- putsymb(a->asym->name, 'z', a->aoffset, 0, 0);
- else
- if(a->type == D_FILE1)
- putsymb(a->asym->name, 'Z', a->aoffset, 0, 0);
-
- if(!s->reachable)
- continue;
-
- putsymb(s->name, 'T', s->value, s->version, s->gotype);
-
- /* frame, auto and param after */
- putsymb(".frame", 'm', p->to.offset+4, 0, 0);
-
- for(a=p->to.autom; a; a=a->link)
- if(a->type == D_AUTO)
- putsymb(a->asym->name, 'a', -a->aoffset, 0, a->gotype);
- else
- if(a->type == D_PARAM)
- putsymb(a->asym->name, 'p', a->aoffset, 0, a->gotype);
- }
- if(debug['v'] || debug['n'])
- Bprint(&bso, "symsize = %lud\n", symsize);
- Bflush(&bso);
+ s = lookup(p, 0);
+ s->type = t;
+ s->value = v;
+ s->reachable = 1;
+ s->special = 1;
}
void
-asmlc(void)
+instinit(void)
{
- int32 oldpc, oldlc;
- Prog *p;
- int32 v, s;
-
- oldpc = INITTEXT;
- oldlc = 0;
- for(p = firstp; p != P; p = p->link) {
- if(p->line == oldlc || p->as == ATEXT || p->as == ANOP) {
- if(p->as == ATEXT)
- curtext = p;
- if(debug['L'])
- Bprint(&bso, "%6lux %P\n",
- p->pc, p);
- continue;
- }
- if(debug['L'])
- Bprint(&bso, "\t\t%6ld", lcsize);
- v = (p->pc - oldpc) / MINLC;
- while(v) {
- s = 127;
- if(v < 127)
- s = v;
- cput(s+128); /* 129-255 +pc */
- if(debug['L'])
- Bprint(&bso, " pc+%ld*%d(%ld)", s, MINLC, s+128);
- v -= s;
- lcsize++;
- }
- s = p->line - oldlc;
- oldlc = p->line;
- oldpc = p->pc + MINLC;
- if(s > 64 || s < -64) {
- cput(0); /* 0 vv +lc */
- cput(s>>24);
- cput(s>>16);
- cput(s>>8);
- cput(s);
- if(debug['L']) {
- if(s > 0)
- Bprint(&bso, " lc+%ld(%d,%ld)\n",
- s, 0, s);
- else
- Bprint(&bso, " lc%ld(%d,%ld)\n",
- s, 0, s);
- Bprint(&bso, "%6lux %P\n",
- p->pc, p);
- }
- lcsize += 5;
- continue;
- }
- if(s > 0) {
- cput(0+s); /* 1-64 +lc */
- if(debug['L']) {
- Bprint(&bso, " lc+%ld(%ld)\n", s, 0+s);
- Bprint(&bso, "%6lux %P\n",
- p->pc, p);
- }
- } else {
- cput(64-s); /* 65-128 -lc */
- if(debug['L']) {
- Bprint(&bso, " lc%ld(%ld)\n", s, 64-s);
- Bprint(&bso, "%6lux %P\n",
- p->pc, p);
- }
+ int i;
+
+ for(i=1; optab[i].as; i++)
+ if(i != optab[i].as) {
+ diag("phase error in optab: %d", i);
+ errorexit();
}
- lcsize++;
- }
- while(lcsize & 1) {
- s = 129;
- cput(s);
- lcsize++;
+ maxop = i;
+
+ for(i=0; i<Ymax; i++)
+ ycover[i*Ymax + i] = 1;
+
+ ycover[Yi0*Ymax + Yi8] = 1;
+ ycover[Yi1*Ymax + Yi8] = 1;
+
+ ycover[Yi0*Ymax + Yi32] = 1;
+ ycover[Yi1*Ymax + Yi32] = 1;
+ ycover[Yi8*Ymax + Yi32] = 1;
+
+ ycover[Yal*Ymax + Yrb] = 1;
+ ycover[Ycl*Ymax + Yrb] = 1;
+ ycover[Yax*Ymax + Yrb] = 1;
+ ycover[Ycx*Ymax + Yrb] = 1;
+ ycover[Yrx*Ymax + Yrb] = 1;
+
+ ycover[Yax*Ymax + Yrx] = 1;
+ ycover[Ycx*Ymax + Yrx] = 1;
+
+ ycover[Yax*Ymax + Yrl] = 1;
+ ycover[Ycx*Ymax + Yrl] = 1;
+ ycover[Yrx*Ymax + Yrl] = 1;
+
+ ycover[Yf0*Ymax + Yrf] = 1;
+
+ ycover[Yal*Ymax + Ymb] = 1;
+ ycover[Ycl*Ymax + Ymb] = 1;
+ ycover[Yax*Ymax + Ymb] = 1;
+ ycover[Ycx*Ymax + Ymb] = 1;
+ ycover[Yrx*Ymax + Ymb] = 1;
+ ycover[Yrb*Ymax + Ymb] = 1;
+ ycover[Ym*Ymax + Ymb] = 1;
+
+ ycover[Yax*Ymax + Yml] = 1;
+ ycover[Ycx*Ymax + Yml] = 1;
+ ycover[Yrx*Ymax + Yml] = 1;
+ ycover[Yrl*Ymax + Yml] = 1;
+ ycover[Ym*Ymax + Yml] = 1;
+
+ for(i=0; i<D_NONE; i++) {
+ reg[i] = -1;
+ if(i >= D_AL && i <= D_BH)
+ reg[i] = (i-D_AL) & 7;
+ if(i >= D_AX && i <= D_DI)
+ reg[i] = (i-D_AX) & 7;
+ if(i >= D_F0 && i <= D_F0+7)
+ reg[i] = (i-D_F0) & 7;
}
- if(debug['v'] || debug['L'])
- Bprint(&bso, "lcsize = %ld\n", lcsize);
- Bflush(&bso);
}
int
@@ -506,11 +398,11 @@ oclass(Adr *a)
}
void
-asmidx(Adr *a, int base)
+asmidx(int scale, int index, int base)
{
int i;
- switch(a->index) {
+ switch(index) {
default:
goto bad;
@@ -525,10 +417,10 @@ asmidx(Adr *a, int base)
case D_BP:
case D_SI:
case D_DI:
- i = reg[a->index] << 3;
+ i = reg[index] << 3;
break;
}
- switch(a->scale) {
+ switch(scale) {
default:
goto bad;
case 1:
@@ -564,7 +456,7 @@ bas:
*andptr++ = i;
return;
bad:
- diag("asmidx: bad address %D", a);
+ diag("asmidx: bad address %d,%d,%d", scale, index, base);
*andptr++ = 0;
return;
}
@@ -572,10 +464,6 @@ bad:
static void
put4(int32 v)
{
- if(dlm && curp != P && reloca != nil){
- dynreloc(reloca->sym, curp->pc + andptr - &and[0], 1);
- reloca = nil;
- }
andptr[0] = v;
andptr[1] = v>>8;
andptr[2] = v>>16;
@@ -583,24 +471,40 @@ put4(int32 v)
andptr += 4;
}
+static void
+relput4(Prog *p, Adr *a)
+{
+ vlong v;
+ Reloc rel, *r;
+
+ v = vaddr(a, &rel);
+ if(rel.siz != 0) {
+ if(rel.siz != 4)
+ diag("bad reloc");
+ r = addrel(cursym);
+ *r = rel;
+ r->off = p->pc + andptr - and;
+ }
+ put4(v);
+}
+
int32
symaddr(Sym *s)
{
- Adr a;
-
- a.type = D_ADDR;
- a.index = D_EXTERN;
- a.offset = 0;
- a.sym = s;
- return vaddr(&a);
+ if(!s->reachable)
+ diag("unreachable symbol in symaddr - %s", s->name);
+ return s->value;
}
-int32
-vaddr(Adr *a)
+static int32
+vaddr(Adr *a, Reloc *r)
{
int t;
int32 v;
Sym *s;
+
+ if(r != nil)
+ memset(r, 0, sizeof *r);
t = a->type;
v = a->offset;
@@ -611,30 +515,18 @@ vaddr(Adr *a)
case D_EXTERN:
s = a->sym;
if(s != nil) {
- if(dlm && curp != P)
- reloca = a;
- switch(s->type) {
- case SUNDEF:
- ckoff(s, v);
- case STEXT:
- case SCONST:
- if(!s->reachable)
- sysfatal("unreachable symbol in vaddr - %s", s->name);
- v += s->value;
- break;
- case SMACHO:
- if(!s->reachable)
- sysfatal("unreachable symbol in vaddr - %s", s->name);
- v += INITDAT + datsize + s->value;
- break;
- case SFIXED:
- v += s->value;
- break;
- default:
- if(!s->reachable)
- sysfatal("unreachable symbol in vaddr - %s", s->name);
- v += INITDAT + s->value;
+ if(!s->reachable)
+ sysfatal("unreachable symbol in vaddr - %s", s->name);
+ if(r == nil) {
+ diag("need reloc for %D", a);
+ errorexit();
}
+ r->type = D_ADDR;
+ r->siz = 4;
+ r->off = -1;
+ r->sym = s;
+ r->add = v;
+ v = 0;
}
}
return v;
@@ -644,118 +536,127 @@ void
asmand(Adr *a, int r)
{
int32 v;
- int t;
- Adr aa;
+ int t, scale;
+ Reloc rel;
v = a->offset;
t = a->type;
+ rel.siz = 0;
if(a->index != D_NONE) {
- if(t >= D_INDIR && t < 2*D_INDIR) {
- t -= D_INDIR;
- if(t == D_NONE) {
- *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
- asmidx(a, t);
- put4(v);
- return;
- }
- if(v == 0 && t != D_BP) {
- *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
- asmidx(a, t);
- return;
- }
- if(v >= -128 && v < 128) {
- *andptr++ = (1 << 6) | (4 << 0) | (r << 3);
- asmidx(a, t);
- *andptr++ = v;
- return;
+ if(t < D_INDIR || t >= 2*D_INDIR) {
+ switch(t) {
+ default:
+ goto bad;
+ case D_STATIC:
+ case D_EXTERN:
+ t = D_NONE;
+ v = vaddr(a, &rel);
+ break;
+ case D_AUTO:
+ case D_PARAM:
+ t = D_SP;
+ break;
}
- *andptr++ = (2 << 6) | (4 << 0) | (r << 3);
- asmidx(a, t);
- put4(v);
+ } else
+ t -= D_INDIR;
+
+ if(t == D_NONE) {
+ *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
+ asmidx(a->scale, a->index, t);
+ goto putrelv;
+ }
+ if(v == 0 && rel.siz == 0 && t != D_BP) {
+ *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
+ asmidx(a->scale, a->index, t);
+ return;
+ }
+ if(v >= -128 && v < 128 && rel.siz == 0) {
+ *andptr++ = (1 << 6) | (4 << 0) | (r << 3);
+ asmidx(a->scale, a->index, t);
+ *andptr++ = v;
return;
}
- switch(t) {
+ *andptr++ = (2 << 6) | (4 << 0) | (r << 3);
+ asmidx(a->scale, a->index, t);
+ goto putrelv;
+ }
+ if(t >= D_AL && t <= D_F0+7) {
+ if(v)
+ goto bad;
+ *andptr++ = (3 << 6) | (reg[t] << 0) | (r << 3);
+ return;
+ }
+
+ scale = a->scale;
+ if(t < D_INDIR || t >= 2*D_INDIR) {
+ switch(a->type) {
default:
goto bad;
case D_STATIC:
case D_EXTERN:
- aa.type = D_NONE+D_INDIR;
+ t = D_NONE;
+ v = vaddr(a, &rel);
break;
case D_AUTO:
case D_PARAM:
- aa.type = D_SP+D_INDIR;
+ t = D_SP;
break;
}
- aa.offset = vaddr(a);
- aa.index = a->index;
- aa.scale = a->scale;
- asmand(&aa, r);
- return;
- }
- if(t >= D_AL && t <= D_F0+7) {
- if(v)
- goto bad;
- *andptr++ = (3 << 6) | (reg[t] << 0) | (r << 3);
- return;
- }
- if(t >= D_INDIR && t < 2*D_INDIR) {
+ scale = 1;
+ } else
t -= D_INDIR;
- if(t == D_NONE || (D_CS <= t && t <= D_GS)) {
- *andptr++ = (0 << 6) | (5 << 0) | (r << 3);
- put4(v);
+
+ if(t == D_NONE || (D_CS <= t && t <= D_GS)) {
+ *andptr++ = (0 << 6) | (5 << 0) | (r << 3);
+ goto putrelv;
+ }
+ if(t == D_SP) {
+ if(v == 0 && rel.siz == 0) {
+ *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
+ asmidx(scale, D_NONE, t);
return;
}
- if(t == D_SP) {
- if(v == 0) {
- *andptr++ = (0 << 6) | (4 << 0) | (r << 3);
- asmidx(a, D_SP);
- return;
- }
- if(v >= -128 && v < 128) {
- *andptr++ = (1 << 6) | (4 << 0) | (r << 3);
- asmidx(a, D_SP);
- *andptr++ = v;
- return;
- }
- *andptr++ = (2 << 6) | (4 << 0) | (r << 3);
- asmidx(a, D_SP);
- put4(v);
+ if(v >= -128 && v < 128 && rel.siz == 0) {
+ *andptr++ = (1 << 6) | (4 << 0) | (r << 3);
+ asmidx(scale, D_NONE, t);
+ *andptr++ = v;
return;
}
- if(t >= D_AX && t <= D_DI) {
- if(v == 0 && t != D_BP) {
- *andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
- return;
- }
- if(v >= -128 && v < 128) {
- andptr[0] = (1 << 6) | (reg[t] << 0) | (r << 3);
- andptr[1] = v;
- andptr += 2;
- return;
- }
- *andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
- put4(v);
+ *andptr++ = (2 << 6) | (4 << 0) | (r << 3);
+ asmidx(scale, D_NONE, t);
+ goto putrelv;
+ }
+ if(t >= D_AX && t <= D_DI) {
+ if(v == 0 && rel.siz == 0 && t != D_BP) {
+ *andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
return;
}
- goto bad;
+ if(v >= -128 && v < 128 && rel.siz == 0) {
+ andptr[0] = (1 << 6) | (reg[t] << 0) | (r << 3);
+ andptr[1] = v;
+ andptr += 2;
+ return;
+ }
+ *andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
+ goto putrelv;
}
- switch(a->type) {
- default:
- goto bad;
- case D_STATIC:
- case D_EXTERN:
- aa.type = D_NONE+D_INDIR;
- break;
- case D_AUTO:
- case D_PARAM:
- aa.type = D_SP+D_INDIR;
- break;
+ goto bad;
+
+putrelv:
+ if(rel.siz != 0) {
+ Reloc *r;
+
+ if(rel.siz != 4) {
+ diag("bad rel");
+ goto bad;
+ }
+ r = addrel(cursym);
+ *r = rel;
+ r->off = curp->pc + andptr - and;
}
- aa.index = D_NONE;
- aa.scale = 1;
- aa.offset = vaddr(a);
- asmand(&aa, r);
+ put4(v);
return;
+
bad:
diag("asmand: bad address %D", a);
return;
@@ -921,22 +822,6 @@ subreg(Prog *p, int from, int to)
print("%P\n", p);
}
-// nacl RET:
-// POPL BX
-// ANDL BX, $~31
-// JMP BX
-uchar naclret[] = { 0x5b, 0x83, 0xe3, ~31, 0xff, 0xe3 };
-
-// nacl JMP BX:
-// ANDL BX, $~31
-// JMP BX
-uchar nacljmpbx[] = { 0x83, 0xe3, ~31, 0xff, 0xe3 };
-
-// nacl CALL BX:
-// ANDL BX, $~31
-// CALL BX
-uchar naclcallbx[] = { 0x83, 0xe3, ~31, 0xff, 0xd3 };
-
void
doasm(Prog *p)
{
@@ -945,6 +830,10 @@ doasm(Prog *p)
uchar *t;
int z, op, ft, tt;
int32 v, pre;
+ Reloc rel, *r;
+ Adr *a;
+
+ curp = p; // TODO
pre = prefixof(&p->from);
if(pre)
@@ -990,7 +879,7 @@ found:
case Pb: /* botch */
break;
}
- v = vaddr(&p->from);
+
op = o->op[z];
switch(t[2]) {
default:
@@ -1001,12 +890,6 @@ found:
break;
case Zlit:
- if(HEADTYPE == 8 && p->as == ARET) {
- // native client return.
- for(z=0; z<sizeof(naclret); z++)
- *andptr++ = naclret[z];
- break;
- }
for(; op = o->op[z]; z++)
*andptr++ = op;
break;
@@ -1040,137 +923,100 @@ found:
break;
case Zo_m:
- if(HEADTYPE == 8) {
- Adr a;
-
- switch(p->as) {
- case AJMP:
- if(p->to.type < D_AX || p->to.type > D_DI)
- diag("indirect jmp must use register in native client");
- // ANDL $~31, REG
- *andptr++ = 0x83;
- asmand(&p->to, 04);
- *andptr++ = ~31;
- // JMP REG
- *andptr++ = 0xFF;
- asmand(&p->to, 04);
- return;
-
- case ACALL:
- a = p->to;
- // native client indirect call
- if(a.type < D_AX || a.type > D_DI) {
- // MOVL target into BX
- *andptr++ = 0x8b;
- asmand(&p->to, reg[D_BX]);
- memset(&a, 0, sizeof a);
- a.type = D_BX;
- }
- // ANDL $~31, REG
- *andptr++ = 0x83;
- asmand(&a, 04);
- *andptr++ = ~31;
- // CALL REG
- *andptr++ = 0xFF;
- asmand(&a, 02);
- return;
- }
- }
*andptr++ = op;
asmand(&p->to, o->op[z+1]);
break;
case Zm_ibo:
- v = vaddr(&p->to);
*andptr++ = op;
asmand(&p->from, o->op[z+1]);
- *andptr++ = v;
+ *andptr++ = vaddr(&p->to, nil);
break;
case Zibo_m:
*andptr++ = op;
asmand(&p->to, o->op[z+1]);
- *andptr++ = v;
+ *andptr++ = vaddr(&p->from, nil);
break;
case Z_ib:
- v = vaddr(&p->to);
case Zib_:
- if(HEADTYPE == 8 && p->as == AINT && v == 3) {
- // native client disallows all INT instructions.
- // translate INT $3 to HLT.
- *andptr++ = 0xf4;
- break;
- }
+ if(t[2] == Zib_)
+ a = &p->from;
+ else
+ a = &p->to;
+ v = vaddr(a, nil);
*andptr++ = op;
*andptr++ = v;
break;
case Zib_rp:
*andptr++ = op + reg[p->to.type];
- *andptr++ = v;
+ *andptr++ = vaddr(&p->from, nil);
break;
case Zil_rp:
*andptr++ = op + reg[p->to.type];
if(o->prefix == Pe) {
+ v = vaddr(&p->from, nil);
*andptr++ = v;
*andptr++ = v>>8;
}
else
- put4(v);
+ relput4(p, &p->from);
break;
case Zib_rr:
*andptr++ = op;
asmand(&p->to, reg[p->to.type]);
- *andptr++ = v;
+ *andptr++ = vaddr(&p->from, nil);
break;
case Z_il:
- v = vaddr(&p->to);
case Zil_:
- *andptr++ = op;
- if(o->prefix == Pe) {
- *andptr++ = v;
- *andptr++ = v>>8;
- }
+ if(t[2] == Zil_)
+ a = &p->from;
else
- put4(v);
- break;
-
- case Zm_ilo:
- v = vaddr(&p->to);
+ a = &p->to;
*andptr++ = op;
- asmand(&p->from, o->op[z+1]);
if(o->prefix == Pe) {
+ v = vaddr(a, nil);
*andptr++ = v;
*andptr++ = v>>8;
}
else
- put4(v);
+ relput4(p, a);
break;
+ case Zm_ilo:
case Zilo_m:
*andptr++ = op;
- asmand(&p->to, o->op[z+1]);
+ if(t[2] == Zilo_m) {
+ a = &p->from;
+ asmand(&p->to, o->op[z+1]);
+ } else {
+ a = &p->to;
+ asmand(&p->from, o->op[z+1]);
+ }
if(o->prefix == Pe) {
+ v = vaddr(a, nil);
*andptr++ = v;
*andptr++ = v>>8;
}
else
- put4(v);
+ relput4(p, a);
break;
case Zil_rr:
*andptr++ = op;
asmand(&p->to, reg[p->to.type]);
if(o->prefix == Pe) {
+ v = vaddr(&p->from, nil);
*andptr++ = v;
*andptr++ = v>>8;
}
else
- put4(v);
+ relput4(p, &p->from);
break;
case Z_rp:
@@ -1185,99 +1031,128 @@ found:
*andptr++ = op;
asmand(&p->to, reg[p->to.type]);
break;
-
- case Zbr:
- q = p->pcond;
- if(q) {
- v = q->pc - p->pc - 2;
- if(q->pc == 0)
- v = 0;
- if(v >= -128 && v <= 127 && !p->bigjmp) {
- *andptr++ = op;
- *andptr++ = v;
- } else {
- p->bigjmp = 1;
- v -= 6-2;
- *andptr++ = 0x0f;
- *andptr++ = o->op[z+1];
- *andptr++ = v;
- *andptr++ = v>>8;
- *andptr++ = v>>16;
- *andptr++ = v>>24;
- }
- }
- break;
-
+
case Zcall:
q = p->pcond;
- if(q) {
- v = q->pc - p->pc - 5;
- if(dlm && curp != P && p->to.sym->type == SUNDEF){
- /* v = 0 - p->pc - 5; */
- v = 0;
- ckoff(p->to.sym, v);
- v += p->to.sym->value;
- dynreloc(p->to.sym, p->pc+1, 0);
- }
- *andptr++ = op;
- *andptr++ = v;
- *andptr++ = v>>8;
- *andptr++ = v>>16;
- *andptr++ = v>>24;
+ if(q == nil) {
+ diag("call without target");
+ errorexit();
+ }
+ if(q->as != ATEXT) {
+ // Could handle this case by making D_PCREL
+ // record the Prog* instead of the Sym*, but let's
+ // wait until the need arises.
+ diag("call of non-TEXT %P", q);
+ errorexit();
}
- break;
-
- case Zcallcon:
- v = p->to.offset - p->pc - 5;
*andptr++ = op;
- *andptr++ = v;
- *andptr++ = v>>8;
- *andptr++ = v>>16;
- *andptr++ = v>>24;
+ r = addrel(cursym);
+ r->off = p->pc + andptr - and;
+ r->type = D_PCREL;
+ r->siz = 4;
+ r->sym = q->from.sym;
+ put4(0);
break;
+ case Zbr:
case Zjmp:
q = p->pcond;
- if(q) {
- v = q->pc - p->pc - 2;
- if(q->pc == 0)
- v = 0;
- if(v >= -128 && v <= 127 && !p->bigjmp) {
+ if(q == nil) {
+ diag("jmp/branch without target");
+ errorexit();
+ }
+ if(q->as == ATEXT) {
+ // jump out of function
+ if(t[2] == Zbr) {
+ diag("branch to ATEXT");
+ errorexit();
+ }
+ *andptr++ = o->op[z+1];
+ r = addrel(cursym);
+ r->off = p->pc + andptr - and;
+ r->sym = q->from.sym;
+ r->type = D_PCREL;
+ r->siz = 4;
+ put4(0);
+ break;
+ }
+
+ // Assumes q is in this function.
+ // TODO: Check in input, preserve in brchain.
+
+ // Fill in backward jump now.
+ if(p->back & 1) {
+ v = q->pc - (p->pc + 2);
+ if(v >= -128) {
*andptr++ = op;
*andptr++ = v;
} else {
- p->bigjmp = 1;
v -= 5-2;
+ if(t[2] == Zbr) {
+ *andptr++ = 0x0f;
+ v--;
+ }
*andptr++ = o->op[z+1];
*andptr++ = v;
*andptr++ = v>>8;
*andptr++ = v>>16;
*andptr++ = v>>24;
}
+ break;
+ }
+
+ // Annotate target; will fill in later.
+ p->forwd = q->comefrom;
+ q->comefrom = p;
+ if(p->back & 2) { // short
+ *andptr++ = op;
+ *andptr++ = 0;
+ } else {
+ if(t[2] == Zbr)
+ *andptr++ = 0x0f;
+ *andptr++ = o->op[z+1];
+ *andptr++ = 0;
+ *andptr++ = 0;
+ *andptr++ = 0;
+ *andptr++ = 0;
}
break;
+ case Zcallcon:
case Zjmpcon:
- v = p->to.offset - p->pc - 5;
- *andptr++ = o->op[z+1];
- *andptr++ = v;
- *andptr++ = v>>8;
- *andptr++ = v>>16;
- *andptr++ = v>>24;
+ if(t[2] == Zcallcon)
+ *andptr++ = op;
+ else
+ *andptr++ = o->op[z+1];
+ r = addrel(cursym);
+ r->off = p->pc + andptr - and;
+ r->type = D_PCREL;
+ r->siz = 4;
+ r->add = p->to.offset;
+ put4(0);
break;
case Zloop:
q = p->pcond;
- if(q) {
- v = q->pc - p->pc - 2;
- if(v < -128 && v > 127)
- diag("loop too far: %P", p);
- *andptr++ = op;
- *andptr++ = v;
+ 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) {
+ rel.siz = op;
+ r = addrel(cursym);
+ *r = rel;
+ r->off = p->pc + andptr - and;
+ }
*andptr++ = v;
if(op > 1) {
*andptr++ = v>>8;
@@ -1342,7 +1217,7 @@ bad:
}
return;
}
- diag("doasm: notfound t2=%lux from=%lux to=%lux %P", t[2], p->from.type, p->to.type, p);
+ diag("doasm: notfound t2=%ux from=%ux to=%ux %P", t[2], p->from.type, p->to.type, p);
return;
mfound:
@@ -1441,204 +1316,10 @@ mfound:
void
asmins(Prog *p)
{
- if(HEADTYPE == 8) {
- ulong npc;
- static Prog *prefix;
-
- // native client
- // - pad indirect jump targets (aka ATEXT) to 32-byte boundary
- // - instructions cannot cross 32-byte boundary
- // - end of call (return address) must be on 32-byte boundary
- if(p->as == ATEXT)
- p->pc += 31 & -p->pc;
- if(p->as == ACALL) {
- // must end on 32-byte boundary.
- // doasm to find out how long the CALL encoding is.
- andptr = and;
- doasm(p);
- npc = p->pc + (andptr - and);
- p->pc += 31 & -npc;
- }
- if(p->as == AREP || p->as == AREPN) {
- // save prefix for next instruction,
- // so that inserted NOPs do not split (e.g.) REP / MOVSL sequence.
- prefix = p;
- andptr = and;
- return;
- }
- andptr = and;
- if(prefix)
- doasm(prefix);
- doasm(p);
- npc = p->pc + (andptr - and);
- if(andptr > and && (p->pc&~31) != ((npc-1)&~31)) {
- // crossed 32-byte boundary; pad to boundary and try again
- p->pc += 31 & -p->pc;
- andptr = and;
- if(prefix)
- doasm(prefix);
- doasm(p);
- }
- prefix = nil;
- } else {
- andptr = and;
- doasm(p);
- }
+ andptr = and;
+ doasm(p);
if(andptr > and+sizeof and) {
print("and[] is too short - %d byte instruction\n", andptr - and);
errorexit();
}
}
-
-enum{
- ABSD = 0,
- ABSU = 1,
- RELD = 2,
- RELU = 3,
-};
-
-int modemap[4] = { 0, 1, -1, 2, };
-
-typedef struct Reloc Reloc;
-
-struct Reloc
-{
- int n;
- int t;
- uchar *m;
- uint32 *a;
-};
-
-Reloc rels;
-
-static void
-grow(Reloc *r)
-{
- int t;
- uchar *m, *nm;
- uint32 *a, *na;
-
- t = r->t;
- r->t += 64;
- m = r->m;
- a = r->a;
- r->m = nm = mal(r->t*sizeof(uchar));
- r->a = na = mal(r->t*sizeof(uint32));
- memmove(nm, m, t*sizeof(uchar));
- memmove(na, a, t*sizeof(uint32));
- free(m);
- free(a);
-}
-
-void
-dynreloc(Sym *s, uint32 v, int abs)
-{
- int i, k, n;
- uchar *m;
- uint32 *a;
- Reloc *r;
-
- if(s->type == SUNDEF)
- k = abs ? ABSU : RELU;
- else
- k = abs ? ABSD : RELD;
- /* Bprint(&bso, "R %s a=%ld(%lx) %d\n", s->name, v, v, k); */
- k = modemap[k];
- r = &rels;
- n = r->n;
- if(n >= r->t)
- grow(r);
- m = r->m;
- a = r->a;
- for(i = n; i > 0; i--){
- if(v < a[i-1]){ /* happens occasionally for data */
- m[i] = m[i-1];
- a[i] = a[i-1];
- }
- else
- break;
- }
- m[i] = k;
- a[i] = v;
- r->n++;
-}
-
-static int
-sput(char *s)
-{
- char *p;
-
- p = s;
- while(*s)
- cput(*s++);
- cput(0);
- return s-p+1;
-}
-
-void
-asmdyn()
-{
- int i, n, t, c;
- Sym *s;
- uint32 la, ra, *a;
- vlong off;
- uchar *m;
- Reloc *r;
-
- cflush();
- off = seek(cout, 0, 1);
- lput(0);
- t = 0;
- lput(imports);
- t += 4;
- for(i = 0; i < NHASH; i++)
- for(s = hash[i]; s != S; s = s->link)
- if(s->type == SUNDEF){
- lput(s->sig);
- t += 4;
- t += sput(s->name);
- }
-
- la = 0;
- r = &rels;
- n = r->n;
- m = r->m;
- a = r->a;
- lput(n);
- t += 4;
- for(i = 0; i < n; i++){
- ra = *a-la;
- if(*a < la)
- diag("bad relocation order");
- if(ra < 256)
- c = 0;
- else if(ra < 65536)
- c = 1;
- else
- c = 2;
- cput((c<<6)|*m++);
- t++;
- if(c == 0){
- cput(ra);
- t++;
- }
- else if(c == 1){
- wput(ra);
- t += 2;
- }
- else{
- lput(ra);
- t += 4;
- }
- la = *a++;
- }
-
- cflush();
- seek(cout, off, 0);
- lput(t);
-
- if(debug['v']){
- Bprint(&bso, "import table entries = %d\n", imports);
- Bprint(&bso, "export table entries = %d\n", exports);
- }
-}
diff --git a/src/cmd/cc/Makefile b/src/cmd/cc/Makefile
index 98b89f0a2..71f23383d 100644
--- a/src/cmd/cc/Makefile
+++ b/src/cmd/cc/Makefile
@@ -2,10 +2,10 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.conf
+include ../../Make.inc
+O:=$(HOST_O)
-LIB=\
- cc.a$O\
+LIB=cc.a
HFILES=\
cc.h\
@@ -30,18 +30,7 @@ OFILES=\
dpchk.$O\
omachcap.$O\
-$(LIB): $(OFILES)
- ar rsc $(LIB) $(OFILES)
-
-$(OFILES): $(HFILES)
-
-y.tab.h: $(YFILES)
- bison -y $(YFLAGS) $(YFILES)
-
-y.tab.c: y.tab.h
- test -f y.tab.c && touch y.tab.c
-
-clean:
- rm -f *.$O *.6 enam.c 6.out a.out y.tab.h y.tab.c $(LIB)
+NOINSTALL=1
+include ../../Make.clib
install: $(LIB)
diff --git a/src/cmd/cc/acid.c b/src/cmd/cc/acid.c
index eb7968c4f..c6a6722bd 100644
--- a/src/cmd/cc/acid.c
+++ b/src/cmd/cc/acid.c
@@ -150,7 +150,7 @@ acidmember(Type *t, int32 off, int flag)
if(typesu[l->etype]) {
s1 = acidsue(l->link);
if(s1 != S) {
- Bprint(&outbuf, " 'A' %s %ld %s;\n",
+ Bprint(&outbuf, " 'A' %s %d %s;\n",
amap(s1->name),
t->offset+off, amap(s->name));
break;
@@ -189,7 +189,7 @@ acidmember(Type *t, int32 off, int flag)
if(s == S)
break;
if(flag) {
- Bprint(&outbuf, " '%c' %ld %s;\n",
+ Bprint(&outbuf, " '%c' %d %s;\n",
acidchar[t->etype], t->offset+off, amap(s->name));
} else {
Bprint(&outbuf, "\tprint(indent, \"%s\t\", addr.%s, \"\\n\");\n",
@@ -209,7 +209,7 @@ acidmember(Type *t, int32 off, int flag)
acidmember(l, t->offset+off, flag);
Bprint(&outbuf, " };\n");
} else {
- Bprint(&outbuf, " %s %ld %s;\n",
+ Bprint(&outbuf, " %s %d %s;\n",
amap(s1->name),
t->offset+off, amap(s->name));
}
@@ -223,7 +223,7 @@ acidmember(Type *t, int32 off, int flag)
} else {
Bprint(&outbuf, "\tprint(indent, \"%s {\\n\");\n",
amap(s1->name));
- Bprint(&outbuf, "\tindent_%s(addr+%ld, indent+\"\\t\");\n",
+ Bprint(&outbuf, "\tindent_%s(addr+%d, indent+\"\\t\");\n",
amap(s1->name), t->offset+off);
Bprint(&outbuf, "\tprint(indent, \"}\\n\");\n");
}
@@ -263,7 +263,7 @@ acidtype(Type *t)
if(debug['s'])
goto asmstr;
an = amap(s->name);
- Bprint(&outbuf, "sizeof%s = %ld;\n", an, t->width);
+ Bprint(&outbuf, "sizeof%s = %d;\n", an, t->width);
Bprint(&outbuf, "aggr %s\n{\n", an);
for(l = t->link; l != T; l = l->down)
acidmember(l, 0, 1);
@@ -280,7 +280,7 @@ acidtype(Type *t)
break;
for(l = t->link; l != T; l = l->down)
if(l->sym != S)
- Bprint(&outbuf, "#define\t%s.%s\t%ld\n",
+ Bprint(&outbuf, "#define\t%s.%s\t%d\n",
s->name,
l->sym->name,
l->offset);
diff --git a/src/cmd/cc/cc.h b/src/cmd/cc/cc.h
index 69adcccb0..3649bf5f6 100644
--- a/src/cmd/cc/cc.h
+++ b/src/cmd/cc/cc.h
@@ -166,6 +166,7 @@ struct Type
uchar nbits;
uchar etype;
uchar garb;
+ uchar align;
};
#define T ((Type*)0)
@@ -785,7 +786,7 @@ int32 outlstring(ushort*, int32);
void sextern(Sym*, Node*, int32, int32);
void xcom(Node*);
int32 exreg(Type*);
-int32 align(int32, Type*, int);
+int32 align(int32, Type*, int, int32*);
int32 maxround(int32, int32);
extern schar ewidth[];
diff --git a/src/cmd/cc/com.c b/src/cmd/cc/com.c
index 5cbe8b77c..b1a8a4704 100644
--- a/src/cmd/cc/com.c
+++ b/src/cmd/cc/com.c
@@ -638,10 +638,10 @@ tcomo(Node *n, int f)
n->addable = 1;
if(n->class == CEXREG) {
n->op = OREGISTER;
- // on 386, "extern register" generates
+ // on 386 or amd64, "extern register" generates
// memory references relative to the
- // fs segment.
- if(thechar == '8') // [sic]
+ // gs or fs segment.
+ if(thechar == '8' || thechar == '6') // [sic]
n->op = OEXREG;
n->reg = n->sym->offset;
n->xoffset = 0;
diff --git a/src/cmd/cc/dcl.c b/src/cmd/cc/dcl.c
index b4d8c4d14..f629925d1 100644
--- a/src/cmd/cc/dcl.c
+++ b/src/cmd/cc/dcl.c
@@ -195,7 +195,7 @@ doinit(Sym *s, Type *t, int32 o, Node *a)
dbgdecl(s);
}
if(debug['i']) {
- print("t = %T; o = %ld; n = %s\n", t, o, s->name);
+ print("t = %T; o = %d; n = %s\n", t, o, s->name);
prtree(a, "doinit value");
}
@@ -323,7 +323,7 @@ init1(Sym *s, Type *t, int32 o, int exflag)
return Z;
if(debug['i']) {
- print("t = %T; o = %ld; n = %s\n", t, o, s->name);
+ print("t = %T; o = %d; n = %s\n", t, o, s->name);
prtree(a, "init1 value");
}
@@ -479,7 +479,7 @@ init1(Sym *s, Type *t, int32 o, int exflag)
e = r->vconst;
if(t->width != 0)
if(e < 0 || e*w >= t->width) {
- diag(a, "initialization index out of range: %ld", e);
+ diag(a, "initialization index out of range: %d", e);
continue;
}
}
@@ -552,9 +552,10 @@ void
sualign(Type *t)
{
Type *l;
- int32 o, w;
+ int32 o, w, maxal;
o = 0;
+ maxal = 0;
switch(t->etype) {
case TSTRUCT:
@@ -577,13 +578,14 @@ sualign(Type *t)
l->sym->name);
else
diag(Z, "incomplete structure element");
- w = align(w, l, Ael1);
+ w = align(w, l, Ael1, &maxal);
l->offset = w;
- w = align(w, l, Ael2);
+ w = align(w, l, Ael2, &maxal);
}
}
- w = align(w, t, Asu2);
+ w = align(w, t, Asu2, &maxal);
t->width = w;
+ t->align = maxal;
acidtype(t);
pickletype(t);
return;
@@ -600,12 +602,13 @@ sualign(Type *t)
diag(Z, "incomplete union element");
l->offset = 0;
l->shift = 0;
- o = align(align(0, l, Ael1), l, Ael2);
+ o = align(align(0, l, Ael1, &maxal), l, Ael2, &maxal);
if(o > w)
w = o;
}
- w = align(w, t, Asu2);
+ w = align(w, t, Asu2, &maxal);
t->width = w;
+ t->align = maxal;
acidtype(t);
pickletype(t);
return;
@@ -663,7 +666,7 @@ argmark(Node *n, int pass)
{
Type *t;
- autoffset = align(0, thisfn->link, Aarg0);
+ autoffset = align(0, thisfn->link, Aarg0, nil);
stkoff = 0;
for(; n->left != Z; n = n->left) {
if(n->op != OFUNC || n->left->op != ONAME)
@@ -745,9 +748,9 @@ loop:
firstarg = s;
firstargtype = s->type;
}
- autoffset = align(autoffset, s->type, Aarg1);
+ autoffset = align(autoffset, s->type, Aarg1, nil);
s->offset = autoffset;
- autoffset = align(autoffset, s->type, Aarg2);
+ autoffset = align(autoffset, s->type, Aarg2, nil);
} else
dodecl(pdecl, CXXX, types[TINT], n);
break;
@@ -916,7 +919,7 @@ fnproto1(Node *n)
void
dbgdecl(Sym *s)
{
- print("decl \"%s\": C=%s [B=%d:O=%ld] T=%T\n",
+ print("decl \"%s\": C=%s [B=%d:O=%d] T=%T\n",
s->name, cnames[s->class], s->block, s->offset, s->type);
}
@@ -1275,7 +1278,7 @@ adecl(int c, Type *t, Sym *s)
}
switch(c) {
case CAUTO:
- autoffset = align(autoffset, t, Aaut3);
+ autoffset = align(autoffset, t, Aaut3, nil);
stkoff = maxround(stkoff, autoffset);
s->offset = -autoffset;
break;
@@ -1285,10 +1288,10 @@ adecl(int c, Type *t, Sym *s)
firstarg = s;
firstargtype = t;
}
- autoffset = align(autoffset, t, Aarg1);
+ autoffset = align(autoffset, t, Aarg1, nil);
if(s)
s->offset = autoffset;
- autoffset = align(autoffset, t, Aarg2);
+ autoffset = align(autoffset, t, Aarg2, nil);
break;
}
}
@@ -1571,7 +1574,7 @@ contig(Sym *s, Node *n, int32 v)
Type *zt;
if(debug['i']) {
- print("contig v = %ld; s = %s\n", v, s->name);
+ print("contig v = %d; s = %s\n", v, s->name);
prtree(n, "doinit value");
}
@@ -1587,7 +1590,7 @@ contig(Sym *s, Node *n, int32 v)
if(v != 0)
diag(n, "automatic adjustable array: %s", s->name);
v = s->offset;
- autoffset = align(autoffset, s->type, Aaut3);
+ autoffset = align(autoffset, s->type, Aaut3, nil);
s->offset = -autoffset;
stkoff = maxround(stkoff, autoffset);
symadjust(s, n, v - s->offset);
diff --git a/src/cmd/cc/dpchk.c b/src/cmd/cc/dpchk.c
index 046c0e4da..6eb5fb409 100644
--- a/src/cmd/cc/dpchk.c
+++ b/src/cmd/cc/dpchk.c
@@ -369,7 +369,7 @@ checkargs(Node *nn, char *s, int pos)
continue;
for(l=tprot; l; l=l->link)
if(sametype(a->type, l->type)) {
-/*print("checking %T/%ulx %T/%ulx\n", a->type, flag.b[0], l->type, l->flag.b[0]);*/
+/*print("checking %T/%ux %T/%ux\n", a->type, flag.b[0], l->type, l->flag.b[0]);*/
if(beq(flag, l->flag))
goto loop;
}
@@ -400,6 +400,7 @@ dpcheck(Node *n)
i = l->param;
b = n->right;
+ a = Z;
while(i > 0) {
b = nextarg(b, &a);
i--;
@@ -437,9 +438,9 @@ pragpack(void)
;
if(debug['f'])
if(packflg)
- print("%4ld: pack %d\n", lineno, packflg);
+ print("%4d: pack %d\n", lineno, packflg);
else
- print("%4ld: pack off\n", lineno);
+ print("%4d: pack off\n", lineno);
}
void
@@ -459,9 +460,9 @@ pragfpround(void)
;
if(debug['f'])
if(fproundflg)
- print("%4ld: fproundflg %d\n", lineno, fproundflg);
+ print("%4d: fproundflg %d\n", lineno, fproundflg);
else
- print("%4ld: fproundflg off\n", lineno);
+ print("%4d: fproundflg off\n", lineno);
}
void
@@ -477,7 +478,7 @@ pragtextflag(void)
while(getnsc() != '\n')
;
if(debug['f'])
- print("%4ld: textflag %d\n", lineno, textflag);
+ print("%4d: textflag %d\n", lineno, textflag);
}
void
diff --git a/src/cmd/cc/lex.c b/src/cmd/cc/lex.c
index c9facc667..3b413c246 100644
--- a/src/cmd/cc/lex.c
+++ b/src/cmd/cc/lex.c
@@ -38,7 +38,7 @@
int
systemtype(int sys)
{
-#ifdef __MINGW32__
+#ifdef _WIN32
return sys&Windows;
#else
return sys&Plan9;
@@ -630,7 +630,7 @@ l1:
vv = c;
yylval.vval = convvtox(vv, TUCHAR);
if(yylval.vval != vv)
- yyerror("overflow in character constant: 0x%lx", c);
+ yyerror("overflow in character constant: 0x%x", c);
else
if(c & 0x80){
nearln = lineno;
@@ -1410,11 +1410,11 @@ Lconv(Fmt *fp)
strcat(str, " ");
}
if(a[i].line)
- snprint(s, STRINGSZ, "%s:%ld[%s:%ld]",
+ snprint(s, STRINGSZ, "%s:%d[%s:%d]",
a[i].line->name, l-a[i].ldel+1,
a[i].incl->name, l-a[i].idel+1);
else
- snprint(s, STRINGSZ, "%s:%ld",
+ snprint(s, STRINGSZ, "%s:%d",
a[i].incl->name, l-a[i].idel+1);
if(strlen(s)+strlen(str) >= STRINGSZ-10)
break;
@@ -1463,7 +1463,7 @@ Tconv(Fmt *fp)
n = t->width;
if(t->link && t->link->width)
n /= t->link->width;
- sprint(s, "[%ld]", n);
+ sprint(s, "[%d]", n);
if(strlen(str) + strlen(s) < STRINGSZ)
strcat(str, s);
}
diff --git a/src/cmd/cc/macbody b/src/cmd/cc/macbody
index ca8a54c0b..35740e985 100644
--- a/src/cmd/cc/macbody
+++ b/src/cmd/cc/macbody
@@ -63,7 +63,7 @@ getsym(void)
if(cp <= symb+NSYMB-4)
*cp++ = c;
c = getc();
- if(isalnum(c) || c == '_' || c >= 0x80)
+ if(isalnum(c) || c == '_' || c >= 0x80 || c == '$')
continue;
unget(c);
break;
diff --git a/src/cmd/cc/pgen.c b/src/cmd/cc/pgen.c
index cd6fffc57..a9d7f1ef4 100644
--- a/src/cmd/cc/pgen.c
+++ b/src/cmd/cc/pgen.c
@@ -37,7 +37,7 @@ argsize(void)
int32 s;
//print("t=%T\n", thisfn);
- s = align(0, thisfn->link, Aarg0);
+ s = align(0, thisfn->link, Aarg0, nil);
for(t=thisfn->down; t!=T; t=t->down) {
switch(t->etype) {
case TVOID:
@@ -47,8 +47,8 @@ argsize(void)
s += 64;
break;
default:
- s = align(s, t, Aarg1);
- s = align(s, t, Aarg2);
+ s = align(s, t, Aarg1, nil);
+ s = align(s, t, Aarg2, nil);
break;
}
//print(" %d %T\n", s, t);
@@ -99,7 +99,7 @@ codgen(Node *n, Node *nn)
nod1 = *nodret->left;
nod1.sym = firstarg;
nod1.type = firstargtype;
- nod1.xoffset = align(0, firstargtype, Aarg1);
+ nod1.xoffset = align(0, firstargtype, Aarg1, nil);
nod1.etype = firstargtype->etype;
nodreg(&nod, &nod1, REGARG);
gmove(&nod, &nod1);
diff --git a/src/cmd/cc/pickle.c b/src/cmd/cc/pickle.c
index fb7ec585b..82cf5eb05 100644
--- a/src/cmd/cc/pickle.c
+++ b/src/cmd/cc/pickle.c
@@ -143,7 +143,7 @@ picklemember(Type *t, int32 off)
case TIND:
if(s == S)
Bprint(&outbuf,
- "%s\"p\", (char*)addr+%ld+_i*%ld);\n",
+ "%s\"p\", (char*)addr+%d+_i*%d);\n",
picklestr, t->offset+off, t->width);
else
Bprint(&outbuf,
@@ -164,14 +164,14 @@ picklemember(Type *t, int32 off)
case TFLOAT:
case TDOUBLE:
if(s == S)
- Bprint(&outbuf, "%s\"%c\", (char*)addr+%ld+_i*%ld);\n",
+ Bprint(&outbuf, "%s\"%c\", (char*)addr+%d+_i*%d);\n",
picklestr, picklechar[t->etype], t->offset+off, t->width);
else
Bprint(&outbuf, "%s\"%c\", &addr->%s);\n",
picklestr, picklechar[t->etype], pmap(s->name));
break;
case TARRAY:
- Bprint(&outbuf, "\tfor(_i = 0; _i < %ld; _i++) {\n\t",
+ Bprint(&outbuf, "\tfor(_i = 0; _i < %d; _i++) {\n\t",
t->width/t->link->width);
picklemember(t->link, t->offset+off);
Bprint(&outbuf, "\t}\n\t_i = 0;\n\tUSED(_i);\n");
@@ -183,7 +183,7 @@ picklemember(Type *t, int32 off)
if(s1 == S)
break;
if(s == S) {
- Bprint(&outbuf, "\tbp = pickle_%s(bp, ep, un, (%s*)((char*)addr+%ld+_i*%ld));\n",
+ Bprint(&outbuf, "\tbp = pickle_%s(bp, ep, un, (%s*)((char*)addr+%d+_i*%d));\n",
pmap(s1->name), pmap(s1->name), t->offset+off, t->width);
} else {
Bprint(&outbuf, "\tbp = pickle_%s(bp, ep, un, &addr->%s);\n",
@@ -235,7 +235,7 @@ pickletype(Type *t)
break;
for(l = t->link; l != T; l = l->down)
if(l->sym != S)
- Bprint(&outbuf, "#define\t%s.%s\t%ld\n",
+ Bprint(&outbuf, "#define\t%s.%s\t%d\n",
s->name,
l->sym->name,
l->offset);
diff --git a/src/cmd/cc/pswt.c b/src/cmd/cc/pswt.c
index 02d4e64a0..0e402dea7 100644
--- a/src/cmd/cc/pswt.c
+++ b/src/cmd/cc/pswt.c
@@ -80,7 +80,7 @@ doswit(Node *n)
qsort(iq, nc, sizeof(C1), swcmp);
if(debug['W'])
for(i=0; i<nc; i++)
- print("case %2ld: = %.8llux\n", i, (vlong)iq[i].val);
+ print("case %2d: = %.8llux\n", i, (vlong)iq[i].val);
for(i=0; i<nc-1; i++)
if(iq[i].val == iq[i+1].val)
diag(n, "duplicate cases in switch %lld", (vlong)iq[i].val);
@@ -115,7 +115,7 @@ outlstring(ushort *s, int32 n)
r = nstring;
while(n > 0) {
c = *s++;
- if(align(0, types[TCHAR], Aarg1)) {
+ if(align(0, types[TCHAR], Aarg1, nil)) {
buf[0] = c>>8;
buf[1] = c;
} else {
diff --git a/src/cmd/cc/sub.c b/src/cmd/cc/sub.c
index 335d30bfb..e0d5df719 100644
--- a/src/cmd/cc/sub.c
+++ b/src/cmd/cc/sub.c
@@ -92,18 +92,18 @@ prtree1(Node *n, int d, int f)
{
case ONAME:
print(" \"%F\"", n);
- print(" %ld", n->xoffset);
+ print(" %d", n->xoffset);
i = 0;
break;
case OINDREG:
- print(" %ld(R%d)", n->xoffset, n->reg);
+ print(" %d(R%d)", n->xoffset, n->reg);
i = 0;
break;
case OREGISTER:
if(n->xoffset)
- print(" %ld+R%d", n->xoffset, n->reg);
+ print(" %d+R%d", n->xoffset, n->reg);
else
print(" R%d", n->reg);
i = 0;
@@ -845,7 +845,7 @@ simplifyshift(Node *n)
/*
if(debug['h'])
- print("%.3o %ld %ld %d #%.lux\n",
+ print("%.3o %d %d %d #%.ux\n",
(s1<<3)|s2, c1, c2, topbit(c3), c3);
*/
diff --git a/src/cmd/cgo/Makefile b/src/cmd/cgo/Makefile
index 34ca3dd46..5458c3e4f 100644
--- a/src/cmd/cgo/Makefile
+++ b/src/cmd/cgo/Makefile
@@ -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 ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=cgo
GOFILES=\
diff --git a/src/cmd/cgo/ast.go b/src/cmd/cgo/ast.go
index 580a72a95..8689ac3da 100644
--- a/src/cmd/cgo/ast.go
+++ b/src/cmd/cgo/ast.go
@@ -12,63 +12,13 @@ import (
"go/doc"
"go/parser"
"go/scanner"
+ "go/token"
"os"
"strings"
)
-// A Cref refers to an expression of the form C.xxx in the AST.
-type Cref struct {
- Name string
- Expr *ast.Expr
- Context string // "type", "expr", "const", or "call"
- TypeName bool // whether xxx is a C type name
- Type *Type // the type of xxx
- FuncType *FuncType
-}
-
-// A ExpFunc is an exported function, callable from C.
-type ExpFunc struct {
- Func *ast.FuncDecl
- ExpName string // name to use from C
-}
-
-// A Prog collects information about a cgo program.
-type Prog struct {
- AST *ast.File // parsed AST
- Preamble string // C preamble (doc comment on import "C")
- PackagePath string
- Package string
- Crefs []*Cref
- Typedef map[string]ast.Expr
- Vardef map[string]*Type
- Funcdef map[string]*FuncType
- Enumdef map[string]int64
- Constdef map[string]string
- ExpFuncs []*ExpFunc
- PtrSize int64
- GccOptions []string
- OutDefs map[string]bool
-}
-
-// A Type collects information about a type in both the C and Go worlds.
-type Type struct {
- Size int64
- Align int64
- C string
- Go ast.Expr
- EnumValues map[string]int64
-}
-
-// A FuncType collects information about a function type in both the C and Go worlds.
-type FuncType struct {
- Params []*Type
- Result *Type
- Go *ast.FuncType
-}
-
-func openProg(name string, p *Prog) {
- var err os.Error
- p.AST, err = parser.ParseFile(name, nil, nil, parser.ParseComments)
+func parse(name string, flags uint) *ast.File {
+ ast1, err := parser.ParseFile(fset, name, nil, flags)
if err != nil {
if list, ok := err.(scanner.ErrorList); ok {
// If err is a scanner.ErrorList, its String will print just
@@ -82,25 +32,37 @@ func openProg(name string, p *Prog) {
}
fatal("parsing %s: %s", name, err)
}
- p.Package = p.AST.Name.Name()
+ return ast1
+}
- // Find the import "C" line and get any extra C preamble.
- // Delete the import "C" line along the way.
+// ReadGo populates f with information learned from reading the
+// Go source file with the given file name. It gathers the C preamble
+// attached to the import "C" comment, a list of references to C.xxx,
+// a list of exported functions, and the actual AST, to be rewritten and
+// printed.
+func (f *File) ReadGo(name string) {
+ // Two different parses: once with comments, once without.
+ // The printer is not good enough at printing comments in the
+ // right place when we start editing the AST behind its back,
+ // so we use ast1 to look for the doc comments on import "C"
+ // and on exported functions, and we use ast2 for translating
+ // and reprinting.
+ ast1 := parse(name, parser.ParseComments)
+ ast2 := parse(name, 0)
+
+ f.Package = ast1.Name.Name
+ f.Name = make(map[string]*Name)
+
+ // In ast1, find the import "C" line and get any extra C preamble.
sawC := false
- w := 0
- for _, decl := range p.AST.Decls {
+ for _, decl := range ast1.Decls {
d, ok := decl.(*ast.GenDecl)
if !ok {
- p.AST.Decls[w] = decl
- w++
continue
}
- ws := 0
for _, spec := range d.Specs {
s, ok := spec.(*ast.ImportSpec)
if !ok || string(s.Path.Value) != `"C"` {
- d.Specs[ws] = spec
- ws++
continue
}
sawC = true
@@ -108,269 +70,330 @@ func openProg(name string, p *Prog) {
error(s.Path.Pos(), `cannot rename import "C"`)
}
if s.Doc != nil {
- p.Preamble += doc.CommentText(s.Doc) + "\n"
+ f.Preamble += doc.CommentText(s.Doc) + "\n"
} else if len(d.Specs) == 1 && d.Doc != nil {
- p.Preamble += doc.CommentText(d.Doc) + "\n"
+ f.Preamble += doc.CommentText(d.Doc) + "\n"
+ }
+ }
+ }
+ if !sawC {
+ error(token.NoPos, `cannot find import "C"`)
+ }
+
+ // In ast2, strip the import "C" line.
+ w := 0
+ for _, decl := range ast2.Decls {
+ d, ok := decl.(*ast.GenDecl)
+ if !ok {
+ ast2.Decls[w] = decl
+ w++
+ continue
+ }
+ ws := 0
+ for _, spec := range d.Specs {
+ s, ok := spec.(*ast.ImportSpec)
+ if !ok || string(s.Path.Value) != `"C"` {
+ d.Specs[ws] = spec
+ ws++
}
}
if ws == 0 {
continue
}
d.Specs = d.Specs[0:ws]
- p.AST.Decls[w] = d
+ ast2.Decls[w] = d
w++
}
- p.AST.Decls = p.AST.Decls[0:w]
-
- if !sawC {
- error(noPos, `cannot find import "C"`)
- }
+ ast2.Decls = ast2.Decls[0:w]
// Accumulate pointers to uses of C.x.
- if p.Crefs == nil {
- p.Crefs = make([]*Cref, 0, 8)
+ if f.Ref == nil {
+ f.Ref = make([]*Ref, 0, 8)
}
- walk(p.AST, p, "prog")
+ f.walk(ast2, "prog", (*File).saveRef)
+
+ // Accumulate exported functions.
+ // The comments are only on ast1 but we need to
+ // save the function bodies from ast2.
+ // The first walk fills in ExpFunc, and the
+ // second walk changes the entries to
+ // refer to ast2 instead.
+ f.walk(ast1, "prog", (*File).saveExport)
+ f.walk(ast2, "prog", (*File).saveExport2)
+
+ f.AST = ast2
}
-func walk(x interface{}, p *Prog, context string) {
- switch n := x.(type) {
- case *ast.Expr:
- if sel, ok := (*n).(*ast.SelectorExpr); ok {
- // For now, assume that the only instance of capital C is
- // when used as the imported package identifier.
- // The parser should take care of scoping in the future,
- // so that we will be able to distinguish a "top-level C"
- // from a local C.
- if l, ok := sel.X.(*ast.Ident); ok && l.Name() == "C" {
- i := len(p.Crefs)
- if i >= cap(p.Crefs) {
- new := make([]*Cref, 2*i)
- for j, v := range p.Crefs {
- new[j] = v
- }
- p.Crefs = new
- }
- p.Crefs = p.Crefs[0 : i+1]
- p.Crefs[i] = &Cref{
- Name: sel.Sel.Name(),
- Expr: n,
- Context: context,
+// Save references to C.xxx for later processing.
+func (f *File) saveRef(x interface{}, context string) {
+ n, ok := x.(*ast.Expr)
+ if !ok {
+ return
+ }
+ if sel, ok := (*n).(*ast.SelectorExpr); ok {
+ // For now, assume that the only instance of capital C is
+ // when used as the imported package identifier.
+ // The parser should take care of scoping in the future,
+ // so that we will be able to distinguish a "top-level C"
+ // from a local C.
+ if l, ok := sel.X.(*ast.Ident); ok && l.Name == "C" {
+ if context == "as2" {
+ context = "expr"
+ }
+ goname := sel.Sel.Name
+ if goname == "errno" {
+ error(sel.Pos(), "cannot refer to errno directly; see documentation")
+ return
+ }
+ name := f.Name[goname]
+ if name == nil {
+ name = &Name{
+ Go: goname,
}
- break
+ f.Name[goname] = name
}
+ f.Ref = append(f.Ref, &Ref{
+ Name: name,
+ Expr: n,
+ Context: context,
+ })
+ return
}
- walk(*n, p, context)
+ }
+}
+
+// If a function should be exported add it to ExpFunc.
+func (f *File) saveExport(x interface{}, context string) {
+ n, ok := x.(*ast.FuncDecl)
+ if !ok {
+ return
+ }
+
+ if n.Doc == nil {
+ return
+ }
+ for _, c := range n.Doc.List {
+ if string(c.Text[0:9]) != "//export " {
+ continue
+ }
+
+ name := strings.TrimSpace(string(c.Text[9:]))
+ if name == "" {
+ error(c.Pos(), "export missing name")
+ }
+
+ f.ExpFunc = append(f.ExpFunc, &ExpFunc{
+ Func: n,
+ ExpName: name,
+ })
+ break
+ }
+}
+
+// Make f.ExpFunc[i] point at the Func from this AST instead of the other one.
+func (f *File) saveExport2(x interface{}, context string) {
+ n, ok := x.(*ast.FuncDecl)
+ if !ok {
+ return
+ }
+
+ for _, exp := range f.ExpFunc {
+ if exp.Func.Name.Name == n.Name.Name {
+ exp.Func = n
+ break
+ }
+ }
+}
+
+// walk walks the AST x, calling visit(f, x, context) for each node.
+func (f *File) walk(x interface{}, context string, visit func(*File, interface{}, string)) {
+ visit(f, x, context)
+ switch n := x.(type) {
+ case *ast.Expr:
+ f.walk(*n, context, visit)
// everything else just recurs
default:
- error(noPos, "unexpected type %T in walk", x)
+ 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:
- walk(&n.Type, p, "type")
+ f.walk(&n.Type, "type", visit)
case *ast.FieldList:
- for _, f := range n.List {
- walk(f, p, context)
+ for _, field := range n.List {
+ f.walk(field, context, visit)
}
case *ast.BadExpr:
case *ast.Ident:
case *ast.Ellipsis:
case *ast.BasicLit:
case *ast.FuncLit:
- walk(n.Type, p, "type")
- walk(n.Body, p, "stmt")
+ f.walk(n.Type, "type", visit)
+ f.walk(n.Body, "stmt", visit)
case *ast.CompositeLit:
- walk(&n.Type, p, "type")
- walk(n.Elts, p, "expr")
+ f.walk(&n.Type, "type", visit)
+ f.walk(n.Elts, "expr", visit)
case *ast.ParenExpr:
- walk(&n.X, p, context)
+ f.walk(&n.X, context, visit)
case *ast.SelectorExpr:
- walk(&n.X, p, "selector")
+ f.walk(&n.X, "selector", visit)
case *ast.IndexExpr:
- walk(&n.X, p, "expr")
- walk(&n.Index, p, "expr")
+ f.walk(&n.X, "expr", visit)
+ f.walk(&n.Index, "expr", visit)
case *ast.SliceExpr:
- walk(&n.X, p, "expr")
- walk(&n.Index, p, "expr")
- if n.End != nil {
- walk(&n.End, p, "expr")
+ f.walk(&n.X, "expr", visit)
+ if n.Low != nil {
+ f.walk(&n.Low, "expr", visit)
+ }
+ if n.High != nil {
+ f.walk(&n.High, "expr", visit)
}
case *ast.TypeAssertExpr:
- walk(&n.X, p, "expr")
- walk(&n.Type, p, "type")
+ f.walk(&n.X, "expr", visit)
+ f.walk(&n.Type, "type", visit)
case *ast.CallExpr:
- walk(&n.Fun, p, "call")
- walk(n.Args, p, "expr")
+ if context == "as2" {
+ f.walk(&n.Fun, "call2", visit)
+ } else {
+ f.walk(&n.Fun, "call", visit)
+ }
+ f.walk(n.Args, "expr", visit)
case *ast.StarExpr:
- walk(&n.X, p, context)
+ f.walk(&n.X, context, visit)
case *ast.UnaryExpr:
- walk(&n.X, p, "expr")
+ f.walk(&n.X, "expr", visit)
case *ast.BinaryExpr:
- walk(&n.X, p, "expr")
- walk(&n.Y, p, "expr")
+ f.walk(&n.X, "expr", visit)
+ f.walk(&n.Y, "expr", visit)
case *ast.KeyValueExpr:
- walk(&n.Key, p, "expr")
- walk(&n.Value, p, "expr")
+ f.walk(&n.Key, "expr", visit)
+ f.walk(&n.Value, "expr", visit)
case *ast.ArrayType:
- walk(&n.Len, p, "expr")
- walk(&n.Elt, p, "type")
+ f.walk(&n.Len, "expr", visit)
+ f.walk(&n.Elt, "type", visit)
case *ast.StructType:
- walk(n.Fields, p, "field")
+ f.walk(n.Fields, "field", visit)
case *ast.FuncType:
- walk(n.Params, p, "field")
+ f.walk(n.Params, "field", visit)
if n.Results != nil {
- walk(n.Results, p, "field")
+ f.walk(n.Results, "field", visit)
}
case *ast.InterfaceType:
- walk(n.Methods, p, "field")
+ f.walk(n.Methods, "field", visit)
case *ast.MapType:
- walk(&n.Key, p, "type")
- walk(&n.Value, p, "type")
+ f.walk(&n.Key, "type", visit)
+ f.walk(&n.Value, "type", visit)
case *ast.ChanType:
- walk(&n.Value, p, "type")
+ f.walk(&n.Value, "type", visit)
case *ast.BadStmt:
case *ast.DeclStmt:
- walk(n.Decl, p, "decl")
+ f.walk(n.Decl, "decl", visit)
case *ast.EmptyStmt:
case *ast.LabeledStmt:
- walk(n.Stmt, p, "stmt")
+ f.walk(n.Stmt, "stmt", visit)
case *ast.ExprStmt:
- walk(&n.X, p, "expr")
+ f.walk(&n.X, "expr", visit)
case *ast.IncDecStmt:
- walk(&n.X, p, "expr")
+ f.walk(&n.X, "expr", visit)
case *ast.AssignStmt:
- walk(n.Lhs, p, "expr")
- walk(n.Rhs, p, "expr")
+ f.walk(n.Lhs, "expr", visit)
+ if len(n.Lhs) == 2 && len(n.Rhs) == 1 {
+ f.walk(n.Rhs, "as2", visit)
+ } else {
+ f.walk(n.Rhs, "expr", visit)
+ }
case *ast.GoStmt:
- walk(n.Call, p, "expr")
+ f.walk(n.Call, "expr", visit)
case *ast.DeferStmt:
- walk(n.Call, p, "expr")
+ f.walk(n.Call, "expr", visit)
case *ast.ReturnStmt:
- walk(n.Results, p, "expr")
+ f.walk(n.Results, "expr", visit)
case *ast.BranchStmt:
case *ast.BlockStmt:
- walk(n.List, p, "stmt")
+ f.walk(n.List, "stmt", visit)
case *ast.IfStmt:
- walk(n.Init, p, "stmt")
- walk(&n.Cond, p, "expr")
- walk(n.Body, p, "stmt")
- walk(n.Else, p, "stmt")
+ f.walk(n.Init, "stmt", visit)
+ f.walk(&n.Cond, "expr", visit)
+ f.walk(n.Body, "stmt", visit)
+ f.walk(n.Else, "stmt", visit)
case *ast.CaseClause:
- walk(n.Values, p, "expr")
- walk(n.Body, p, "stmt")
+ f.walk(n.Values, "expr", visit)
+ f.walk(n.Body, "stmt", visit)
case *ast.SwitchStmt:
- walk(n.Init, p, "stmt")
- walk(&n.Tag, p, "expr")
- walk(n.Body, p, "stmt")
+ f.walk(n.Init, "stmt", visit)
+ f.walk(&n.Tag, "expr", visit)
+ f.walk(n.Body, "stmt", visit)
case *ast.TypeCaseClause:
- walk(n.Types, p, "type")
- walk(n.Body, p, "stmt")
+ f.walk(n.Types, "type", visit)
+ f.walk(n.Body, "stmt", visit)
case *ast.TypeSwitchStmt:
- walk(n.Init, p, "stmt")
- walk(n.Assign, p, "stmt")
- walk(n.Body, p, "stmt")
+ f.walk(n.Init, "stmt", visit)
+ f.walk(n.Assign, "stmt", visit)
+ f.walk(n.Body, "stmt", visit)
case *ast.CommClause:
- walk(n.Lhs, p, "expr")
- walk(n.Rhs, p, "expr")
- walk(n.Body, p, "stmt")
+ f.walk(n.Lhs, "expr", visit)
+ f.walk(n.Rhs, "expr", visit)
+ f.walk(n.Body, "stmt", visit)
case *ast.SelectStmt:
- walk(n.Body, p, "stmt")
+ f.walk(n.Body, "stmt", visit)
case *ast.ForStmt:
- walk(n.Init, p, "stmt")
- walk(&n.Cond, p, "expr")
- walk(n.Post, p, "stmt")
- walk(n.Body, p, "stmt")
+ f.walk(n.Init, "stmt", visit)
+ f.walk(&n.Cond, "expr", visit)
+ f.walk(n.Post, "stmt", visit)
+ f.walk(n.Body, "stmt", visit)
case *ast.RangeStmt:
- walk(&n.Key, p, "expr")
- walk(&n.Value, p, "expr")
- walk(&n.X, p, "expr")
- walk(n.Body, p, "stmt")
+ f.walk(&n.Key, "expr", visit)
+ f.walk(&n.Value, "expr", visit)
+ f.walk(&n.X, "expr", visit)
+ f.walk(n.Body, "stmt", visit)
case *ast.ImportSpec:
case *ast.ValueSpec:
- walk(&n.Type, p, "type")
- walk(n.Values, p, "expr")
+ f.walk(&n.Type, "type", visit)
+ f.walk(n.Values, "expr", visit)
case *ast.TypeSpec:
- walk(&n.Type, p, "type")
+ f.walk(&n.Type, "type", visit)
case *ast.BadDecl:
case *ast.GenDecl:
- walk(n.Specs, p, "spec")
+ f.walk(n.Specs, "spec", visit)
case *ast.FuncDecl:
if n.Recv != nil {
- walk(n.Recv, p, "field")
+ f.walk(n.Recv, "field", visit)
}
- walk(n.Type, p, "type")
+ f.walk(n.Type, "type", visit)
if n.Body != nil {
- walk(n.Body, p, "stmt")
+ f.walk(n.Body, "stmt", visit)
}
- checkExpFunc(n, p)
-
case *ast.File:
- walk(n.Decls, p, "decl")
+ f.walk(n.Decls, "decl", visit)
case *ast.Package:
- for _, f := range n.Files {
- walk(f, p, "file")
+ for _, file := range n.Files {
+ f.walk(file, "file", visit)
}
case []ast.Decl:
for _, d := range n {
- walk(d, p, context)
+ f.walk(d, context, visit)
}
case []ast.Expr:
for i := range n {
- walk(&n[i], p, context)
+ f.walk(&n[i], context, visit)
}
case []ast.Stmt:
for _, s := range n {
- walk(s, p, context)
+ f.walk(s, context, visit)
}
case []ast.Spec:
for _, s := range n {
- walk(s, p, context)
- }
- }
-}
-
-// If a function should be exported add it to ExpFuncs.
-func checkExpFunc(n *ast.FuncDecl, p *Prog) {
- if n.Doc == nil {
- return
- }
- for _, c := range n.Doc.List {
- if string(c.Text[0:9]) != "//export " {
- continue
- }
-
- name := strings.TrimSpace(string(c.Text[9:]))
- if name == "" {
- error(c.Position, "export missing name")
- }
-
- if p.ExpFuncs == nil {
- p.ExpFuncs = make([]*ExpFunc, 0, 8)
+ f.walk(s, context, visit)
}
- i := len(p.ExpFuncs)
- if i >= cap(p.ExpFuncs) {
- new := make([]*ExpFunc, 2*i)
- for j, v := range p.ExpFuncs {
- new[j] = v
- }
- p.ExpFuncs = new
- }
- p.ExpFuncs = p.ExpFuncs[0 : i+1]
- p.ExpFuncs[i] = &ExpFunc{
- Func: n,
- ExpName: name,
- }
- break
}
}
diff --git a/src/cmd/cgo/doc.go b/src/cmd/cgo/doc.go
index 022a87c15..0f9204d7f 100644
--- a/src/cmd/cgo/doc.go
+++ b/src/cmd/cgo/doc.go
@@ -23,6 +23,31 @@ the package. For example:
// #include <errno.h>
import "C"
+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.
+
+The standard C numeric types are available under the names
+C.char, C.schar (signed char), C.uchar (unsigned char),
+C.short, C.ushort (unsigned short), C.int, C.uint (unsigned int),
+C.long, C.ulong (unsigned long), C.longlong (long long),
+C.ulonglong (unsigned long long), C.float, C.double.
+
+To access a struct, union, or enum type directly, prefix it with
+struct_, union_, or enum_, as in C.struct_stat.
+
+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:
+
+ n, err := C.atoi("abc")
+
+In C, a function argument written as a fixed size array
+actually requires a pointer to the first element of the array.
+C compilers are aware of this calling convention and adjust
+the call accordingly, but Go cannot. In Go, you must pass
+the pointer to the first element explicitly: C.f(&x[0]).
+
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.
diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go
index 5e12a6687..be3b8fe64 100644
--- a/src/cmd/cgo/gcc.go
+++ b/src/cmd/cgo/gcc.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.
-// Annotate Crefs in Prog with C types by parsing gcc debug output.
+// Annotate Ref in Prog with C types by parsing gcc debug output.
// Conversion of debug output to Go types.
package main
@@ -12,6 +12,8 @@ import (
"debug/dwarf"
"debug/elf"
"debug/macho"
+ "debug/pe"
+ "flag"
"fmt"
"go/ast"
"go/parser"
@@ -21,12 +23,64 @@ import (
"strings"
)
-func (p *Prog) loadDebugInfo() {
+var debugDefine = flag.Bool("debug-define", false, "print relevant #defines")
+var debugGcc = flag.Bool("debug-gcc", false, "print gcc invocations")
+
+var nameToC = map[string]string{
+ "schar": "signed char",
+ "uchar": "unsigned char",
+ "ushort": "unsigned short",
+ "uint": "unsigned int",
+ "ulong": "unsigned long",
+ "longlong": "long long",
+ "ulonglong": "unsigned long long",
+}
+
+// cname returns the C name to use for C.s.
+// The expansions are listed in nameToC and also
+// struct_foo becomes "struct foo", and similarly for
+// union and enum.
+func cname(s string) string {
+ if t, ok := nameToC[s]; ok {
+ return t
+ }
+
+ if strings.HasPrefix(s, "struct_") {
+ return "struct " + s[len("struct_"):]
+ }
+ if strings.HasPrefix(s, "union_") {
+ return "union " + s[len("union_"):]
+ }
+ if strings.HasPrefix(s, "enum_") {
+ return "enum " + s[len("enum_"):]
+ }
+ return s
+}
+
+// Translate rewrites f.AST, the original Go input, to remove
+// references to the imported package C, replacing them with
+// references to the equivalent Go types, functions, and variables.
+func (p *Package) Translate(f *File) {
+ for _, cref := range f.Ref {
+ // Convert C.ulong to C.unsigned long, etc.
+ cref.Name.C = cname(cref.Name.Go)
+ }
+ p.loadDefines(f)
+ needType := p.guessKinds(f)
+ if len(needType) > 0 {
+ p.loadDWARF(f, needType)
+ }
+ p.rewriteRef(f)
+}
+
+// loadDefines coerces gcc into spitting out the #defines in use
+// in the file f and saves relevant renamings in f.Name[name].Define.
+func (p *Package) loadDefines(f *File) {
var b bytes.Buffer
+ b.WriteString(builtinProlog)
+ b.WriteString(f.Preamble)
+ stdout := p.gccDefines(b.Bytes())
- b.WriteString(p.Preamble)
- stdout := p.gccPostProc(b.Bytes())
- defines := make(map[string]string)
for _, line := range strings.Split(stdout, "\n", -1) {
if len(line) < 9 || line[0:7] != "#define" {
continue
@@ -48,70 +102,112 @@ func (p *Prog) loadDebugInfo() {
val = strings.TrimSpace(line[tabIndex:])
}
- // Only allow string, character, and numeric constants. Ignoring #defines for
- // symbols allows those symbols to be referenced in Go, as they will be
- // translated by gcc later.
- _, err := strconv.Atoi(string(val[0]))
- if err == nil || val[0] == '\'' || val[0] == '"' {
- defines[key] = val
- }
- }
-
- // Construct a slice of unique names from p.Crefs.
- m := make(map[string]int)
- for _, c := range p.Crefs {
- // If we've already found this name as a define, it is not a Cref.
- if val, ok := defines[c.Name]; ok {
- _, err := parser.ParseExpr("", val, nil)
- if err != nil {
- fmt.Fprintf(os.Stderr, "The value in C.%s does not parse as a Go expression; cannot use.\n", c.Name)
- os.Exit(2)
+ if n := f.Name[key]; n != nil {
+ if *debugDefine {
+ fmt.Fprintf(os.Stderr, "#define %s %s\n", key, val)
}
-
- c.Context = "const"
- c.TypeName = false
- p.Constdef[c.Name] = val
- continue
+ n.Define = val
}
- m[c.Name] = -1
- }
- names := make([]string, 0, len(m))
- for name, _ := range m {
- i := len(names)
- names = names[0 : i+1]
- names[i] = name
- m[name] = i
}
+}
+// guessKinds tricks gcc into revealing the kind of each
+// name xxx for the references C.xxx in the Go input.
+// The kind is either a constant, type, or variable.
+func (p *Package) guessKinds(f *File) []*Name {
// Coerce gcc into telling us whether each name is
// a type, a value, or undeclared. We compile a function
// containing the line:
// name;
// If name is a type, gcc will print:
- // x.c:2: warning: useless type name in empty declaration
+ // cgo-test:2: warning: useless type name in empty declaration
// If name is a value, gcc will print
- // x.c:2: warning: statement with no effect
+ // cgo-test:2: warning: statement with no effect
// If name is undeclared, gcc will print
- // x.c:2: error: 'name' undeclared (first use in this function)
+ // cgo-test:2: error: 'name' undeclared (first use in this function)
// A line number directive causes the line number to
// correspond to the index in the names array.
- b.Reset()
- b.WriteString(p.Preamble)
+ //
+ // The line also has an enum declaration:
+ // name; enum { _cgo_enum_1 = name };
+ // If name is not a constant, gcc will print:
+ // cgo-test:4: error: enumerator value for '_cgo_enum_4' is not an integer constant
+ // we assume lines without that error are constants.
+
+ // Make list of names that need sniffing, type lookup.
+ toSniff := make([]*Name, 0, len(f.Name))
+ needType := make([]*Name, 0, len(f.Name))
+
+ for _, n := range f.Name {
+ // If we've already found this name as a #define
+ // and we can translate it as a constant value, do so.
+ if n.Define != "" {
+ ok := false
+ 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 {
+ ok = true
+ }
+ }
+ if ok {
+ n.Kind = "const"
+ n.Const = n.Define
+ continue
+ }
+
+ if isName(n.Define) {
+ n.C = n.Define
+ }
+ }
+
+ // If this is a struct, union, or enum type name,
+ // record the kind but also that we need type information.
+ if strings.HasPrefix(n.C, "struct ") || strings.HasPrefix(n.C, "union ") || strings.HasPrefix(n.C, "enum ") {
+ n.Kind = "type"
+ i := len(needType)
+ needType = needType[0 : i+1]
+ needType[i] = n
+ continue
+ }
+
+ i := len(toSniff)
+ toSniff = toSniff[0 : i+1]
+ toSniff[i] = n
+ }
+
+ if len(toSniff) == 0 {
+ return needType
+ }
+
+ var b bytes.Buffer
+ b.WriteString(builtinProlog)
+ b.WriteString(f.Preamble)
b.WriteString("void f(void) {\n")
b.WriteString("#line 0 \"cgo-test\"\n")
- for _, n := range names {
- b.WriteString(n)
- b.WriteString(";\n")
+ for i, n := range toSniff {
+ fmt.Fprintf(&b, "%s; enum { _cgo_enum_%d = %s }; /* cgo-test:%d */\n", n.C, i, n.C, i)
}
b.WriteString("}\n")
-
- kind := make(map[string]string)
- _, stderr := p.gccDebug(b.Bytes())
+ stderr := p.gccErrors(b.Bytes())
if stderr == "" {
- fatal("gcc produced no output")
+ fatal("gcc produced no output\non input:\n%s", b.Bytes())
}
+
+ names := make([]*Name, len(toSniff))
+ copy(names, toSniff)
+
+ isConst := make([]bool, len(toSniff))
+ for i := range isConst {
+ isConst[i] = true // until proven otherwise
+ }
+
for _, line := range strings.Split(stderr, "\n", -1) {
if len(line) < 9 || line[0:9] != "cgo-test:" {
+ if len(line) > 8 && line[0:8] == "<stdin>:" {
+ fatal("gcc produced unexpected output:\n%s\non input:\n%s", line, b.Bytes())
+ }
continue
}
line = line[9:]
@@ -127,28 +223,52 @@ func (p *Prog) loadDebugInfo() {
switch {
default:
continue
- case strings.Index(line, ": useless type name in empty declaration") >= 0:
+ case strings.Contains(line, ": useless type name in empty declaration"):
what = "type"
- case strings.Index(line, ": statement with no effect") >= 0:
- what = "value"
- case strings.Index(line, "undeclared") >= 0:
- what = "error"
+ isConst[i] = false
+ 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:]))
+ case strings.Contains(line, "is not an integer constant"):
+ isConst[i] = false
+ continue
}
- if old, ok := kind[names[i]]; ok && old != what {
- error(noPos, "inconsistent gcc output about C.%s", names[i])
+ n := toSniff[i]
+ if n == nil {
+ continue
}
- kind[names[i]] = what
+ toSniff[i] = nil
+ n.Kind = what
+
+ j := len(needType)
+ needType = needType[0 : j+1]
+ needType[j] = n
}
- for _, n := range names {
- if _, ok := kind[n]; !ok {
- error(noPos, "could not determine kind of name for C.%s", n)
+ for i, b := range isConst {
+ if b {
+ names[i].Kind = "const"
}
}
-
+ for _, n := range toSniff {
+ if n == nil {
+ continue
+ }
+ if n.Kind != "" {
+ continue
+ }
+ error(token.NoPos, "could not determine kind of name for C.%s", n.Go)
+ }
if nerrors > 0 {
- fatal("failed to interpret gcc output:\n%s", stderr)
+ fatal("unresolved names")
}
+ return needType
+}
+// loadDWARF parses the DWARF debug information generated
+// by gcc to learn the details of the constants, variables, and types
+// being referred to as C.xxx.
+func (p *Package) loadDWARF(f *File, names []*Name) {
// Extract the types from the DWARF section of an object
// from a well-formed C program. Gcc only generates DWARF info
// for symbols in the object file, so it is not enough to print the
@@ -157,19 +277,24 @@ func (p *Prog) loadDebugInfo() {
// typeof(names[i]) *__cgo__i;
// for each entry in names and then dereference the type we
// learn for __cgo__i.
- b.Reset()
- b.WriteString(p.Preamble)
+ var b bytes.Buffer
+ b.WriteString(builtinProlog)
+ b.WriteString(f.Preamble)
for i, n := range names {
- fmt.Fprintf(&b, "typeof(%s) *__cgo__%d;\n", n, i)
- }
- d, stderr := p.gccDebug(b.Bytes())
- if d == nil {
- fatal("gcc failed:\n%s\non input:\n%s", stderr, b.Bytes())
+ fmt.Fprintf(&b, "typeof(%s) *__cgo__%d;\n", n.C, i)
+ if n.Kind == "const" {
+ fmt.Fprintf(&b, "enum { __cgo_enum__%d = %s };\n", i, n.C)
+ }
}
+ d := p.gccDebug(b.Bytes())
// Scan DWARF info for top-level TagVariable entries with AttrName __cgo__i.
types := make([]dwarf.Type, len(names))
enums := make([]dwarf.Offset, len(names))
+ nameToIndex := make(map[*Name]int)
+ for i, n := range names {
+ nameToIndex[n] = i
+ }
r := d.Reader()
for {
e, err := r.Next()
@@ -192,9 +317,11 @@ func (p *Prog) loadDebugInfo() {
}
if e.Tag == dwarf.TagEnumerator {
entryName := e.Val(dwarf.AttrName).(string)
- i, ok := m[entryName]
- if ok {
- enums[i] = offset
+ if strings.HasPrefix(entryName, "__cgo_enum__") {
+ n, _ := strconv.Atoi(entryName[len("__cgo_enum__"):])
+ if 0 <= n && n < len(names) {
+ enums[n] = offset
+ }
}
}
}
@@ -234,97 +361,221 @@ func (p *Prog) loadDebugInfo() {
}
}
- // Record types and typedef information in Crefs.
+ // Record types and typedef information.
var conv typeConv
conv.Init(p.PtrSize)
- for _, c := range p.Crefs {
- i, ok := m[c.Name]
- if !ok {
- if _, ok := p.Constdef[c.Name]; !ok {
- fatal("Cref %s is no longer around", c.Name)
- }
- continue
- }
- c.TypeName = kind[c.Name] == "type"
+ for i, n := range names {
f, fok := types[i].(*dwarf.FuncType)
- if c.Context == "call" && !c.TypeName && fok {
- c.FuncType = conv.FuncType(f)
+ if n.Kind != "type" && fok {
+ n.Kind = "func"
+ n.FuncType = conv.FuncType(f)
} else {
- c.Type = conv.Type(types[i])
+ n.Type = conv.Type(types[i])
+ 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])
+ // Remove injected enum to ensure the value will deep-compare
+ // equally in future loads of the same constant.
+ n.Type.EnumValues[k] = 0, false
+ }
}
}
- p.Typedef = conv.typedef
}
-func concat(a, b []string) []string {
- c := make([]string, len(a)+len(b))
- for i, s := range a {
- c[i] = s
+// 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.
+func (p *Package) rewriteRef(f *File) {
+ // Assign mangled names.
+ for _, n := range f.Name {
+ if n.Kind == "not-type" {
+ n.Kind = "var"
+ }
+ if n.Mangle == "" {
+ n.Mangle = "_C" + n.Kind + "_" + n.Go
+ }
}
- for i, s := range b {
- c[i+len(a)] = s
+
+ // Now that we have all the name types filled in,
+ // scan through the Refs to identify the ones that
+ // are trying to do a ,err call. Also check that
+ // functions are only used in calls.
+ for _, r := range f.Ref {
+ var expr ast.Expr = ast.NewIdent(r.Name.Mangle) // default
+ switch r.Context {
+ case "call", "call2":
+ if r.Name.Kind != "func" {
+ if r.Name.Kind == "type" {
+ r.Context = "type"
+ expr = r.Name.Type.Go
+ break
+ }
+ 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")
+ }
+ // Invent new Name for the two-result function.
+ n := f.Name["2"+r.Name.Go]
+ if n == nil {
+ n = new(Name)
+ *n = *r.Name
+ n.AddError = true
+ n.Mangle = "_C2func_" + n.Go
+ f.Name["2"+r.Name.Go] = n
+ }
+ expr = ast.NewIdent(n.Mangle)
+ r.Name = n
+ break
+ }
+ case "expr":
+ if r.Name.Kind == "func" {
+ error(r.Pos(), "must call C.%s", r.Name.Go)
+ }
+ if r.Name.Kind == "type" {
+ // Okay - might be new(T)
+ expr = r.Name.Type.Go
+ }
+ if r.Name.Kind == "var" {
+ expr = &ast.StarExpr{X: expr}
+ }
+
+ case "type":
+ if r.Name.Kind != "type" {
+ error(r.Pos(), "expression C.%s used as type", r.Name.Go)
+ } else {
+ expr = r.Name.Type.Go
+ }
+ default:
+ if r.Name.Kind == "func" {
+ error(r.Pos(), "must call C.%s", r.Name.Go)
+ }
+ }
+ *r.Expr = expr
}
- return c
}
-// gccDebug runs gcc -gdwarf-2 over the C program stdin and
-// returns the corresponding DWARF data and any messages
-// printed to standard error.
-func (p *Prog) gccDebug(stdin []byte) (*dwarf.Data, string) {
- machine := "-m32"
+// gccName returns the name of the compiler to run. Use $GCC if set in
+// the environment, otherwise just "gcc".
+
+func (p *Package) gccName() (ret string) {
+ if ret = os.Getenv("GCC"); ret == "" {
+ ret = "gcc"
+ }
+ return
+}
+
+// gccMachine returns the gcc -m flag to use, either "-m32" or "-m64".
+func (p *Package) gccMachine() string {
if p.PtrSize == 8 {
- machine = "-m64"
+ return "-m64"
}
+ return "-m32"
+}
- tmp := "_cgo_.o"
- base := []string{
- "gcc",
- machine,
+const gccTmp = "_cgo_.o"
+
+// gccCmd returns the gcc command line to use for compiling
+// the input.
+func (p *Package) gccCmd() []string {
+ return []string{
+ p.gccName(),
+ p.gccMachine(),
"-Wall", // many warnings
"-Werror", // warnings are errors
- "-o" + tmp, // 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
"-xc", // input language is C
"-", // read input from standard input
}
- _, stderr, ok := run(stdin, concat(base, p.GccOptions))
- if !ok {
- return nil, string(stderr)
- }
+}
+
+// gccDebug runs gcc -gdwarf-2 over the C program stdin and
+// returns the corresponding DWARF data and any messages
+// printed to standard error.
+func (p *Package) gccDebug(stdin []byte) *dwarf.Data {
+ runGcc(stdin, append(p.gccCmd(), p.GccOptions...))
// Try to parse f as ELF and Mach-O and hope one works.
var f interface {
DWARF() (*dwarf.Data, os.Error)
}
var err os.Error
- if f, err = elf.Open(tmp); err != nil {
- if f, err = macho.Open(tmp); err != nil {
- fatal("cannot parse gcc output %s as ELF or Mach-O object", tmp)
+ if f, err = elf.Open(gccTmp); err != nil {
+ if f, err = macho.Open(gccTmp); err != nil {
+ if f, err = pe.Open(gccTmp); err != nil {
+ fatal("cannot parse gcc output %s as ELF or Mach-O or PE object", gccTmp)
+ }
}
}
d, err := f.DWARF()
if err != nil {
- fatal("cannot load DWARF debug information from %s: %s", tmp, err)
+ fatal("cannot load DWARF debug information from %s: %s", gccTmp, err)
}
- return d, ""
+ return d
}
-func (p *Prog) gccPostProc(stdin []byte) string {
- machine := "-m32"
- if p.PtrSize == 8 {
- machine = "-m64"
+// gccDefines runs gcc -E -dM -xc - over the C program stdin
+// and returns the corresponding standard output, which is the
+// #defines that gcc encountered while processing the input
+// and its included files.
+func (p *Package) gccDefines(stdin []byte) string {
+ base := []string{p.gccName(), p.gccMachine(), "-E", "-dM", "-xc", "-"}
+ stdout, _ := runGcc(stdin, append(base, p.GccOptions...))
+ return stdout
+}
+
+// gccErrors runs gcc over the C program stdin and returns
+// the errors that gcc prints. That is, this function expects
+// gcc to fail.
+func (p *Package) gccErrors(stdin []byte) string {
+ // TODO(rsc): require failure
+ args := append(p.gccCmd(), p.GccOptions...)
+ if *debugGcc {
+ fmt.Fprintf(os.Stderr, "$ %s <<EOF\n", strings.Join(args, " "))
+ os.Stderr.Write(stdin)
+ fmt.Fprint(os.Stderr, "EOF\n")
+ }
+ stdout, stderr, _ := run(stdin, args)
+ if *debugGcc {
+ os.Stderr.Write(stdout)
+ os.Stderr.Write(stderr)
}
+ return string(stderr)
+}
- base := []string{"gcc", machine, "-E", "-dM", "-xc", "-"}
- stdout, stderr, ok := run(stdin, concat(base, p.GccOptions))
+// runGcc runs the gcc command line args with stdin on standard input.
+// If the command exits with a non-zero exit status, runGcc prints
+// details about what was run and exits.
+// Otherwise runGcc returns the data written to standard output and standard error.
+// Note that for some of the uses we expect useful data back
+// on standard error, but for those uses gcc must still exit 0.
+func runGcc(stdin []byte, args []string) (string, string) {
+ if *debugGcc {
+ fmt.Fprintf(os.Stderr, "$ %s <<EOF\n", strings.Join(args, " "))
+ os.Stderr.Write(stdin)
+ fmt.Fprint(os.Stderr, "EOF\n")
+ }
+ stdout, stderr, ok := run(stdin, args)
+ if *debugGcc {
+ os.Stderr.Write(stdout)
+ os.Stderr.Write(stderr)
+ }
if !ok {
- return string(stderr)
+ fmt.Fprint(os.Stderr, "Error running gcc:\n")
+ fmt.Fprintf(os.Stderr, "$ %s <<EOF\n", strings.Join(args, " "))
+ os.Stderr.Write(stdin)
+ fmt.Fprint(os.Stderr, "EOF\n")
+ os.Stderr.Write(stderr)
+ os.Exit(2)
}
-
- return string(stdout)
+ return string(stdout), string(stderr)
}
// A typeConv is a translator from dwarf types to Go types
@@ -345,14 +596,14 @@ type typeConv struct {
string ast.Expr
ptrSize int64
-
- tagGen int
}
+var tagGen int
+var typedef = make(map[string]ast.Expr)
+
func (c *typeConv) Init(ptrSize int64) {
c.ptrSize = ptrSize
c.m = make(map[dwarf.Type]*Type)
- c.typedef = make(map[string]ast.Expr)
c.bool = c.Ident("bool")
c.byte = c.Ident("byte")
c.int8 = c.Ident("int8")
@@ -388,7 +639,7 @@ func base(dt dwarf.Type) dwarf.Type {
}
// Map from dwarf text names to aliases we use in package "C".
-var cnameMap = map[string]string{
+var dwarfToName = map[string]string{
"long int": "long",
"long unsigned int": "ulong",
"unsigned int": "uint",
@@ -415,6 +666,7 @@ func (c *typeConv) Type(dtype dwarf.Type) *Type {
t.C = dtype.Common().Name
t.EnumValues = nil
c.m[dtype] = t
+
if t.Size < 0 {
// Unsized types are [0]byte
t.Size = 0
@@ -550,16 +802,16 @@ func (c *typeConv) Type(dtype dwarf.Type) *Type {
// Have to give it a name to simulate C "struct foo" references.
tag := dt.StructName
if tag == "" {
- tag = "__" + strconv.Itoa(c.tagGen)
- c.tagGen++
+ tag = "__" + strconv.Itoa(tagGen)
+ tagGen++
} else if t.C == "" {
t.C = dt.Kind + " " + tag
}
- name := c.Ident("_C" + dt.Kind + "_" + tag)
+ name := c.Ident("_Ctype_" + dt.Kind + "_" + tag)
t.Go = name // publish before recursive calls
switch dt.Kind {
case "union", "class":
- c.typedef[name.Name()] = c.Opaque(t.Size)
+ typedef[name.Name] = c.Opaque(t.Size)
if t.C == "" {
t.C = fmt.Sprintf("typeof(unsigned char[%d])", t.Size)
}
@@ -569,7 +821,7 @@ func (c *typeConv) Type(dtype dwarf.Type) *Type {
t.C = csyntax
}
t.Align = align
- c.typedef[name.Name()] = g
+ typedef[name.Name] = g
}
case *dwarf.TypedefType:
@@ -583,13 +835,13 @@ func (c *typeConv) Type(dtype dwarf.Type) *Type {
t.Align = c.ptrSize
break
}
- name := c.Ident("_C_" + dt.Name)
+ name := c.Ident("_Ctypedef_" + dt.Name)
t.Go = name // publish before recursive call
sub := c.Type(dt.Type)
t.Size = sub.Size
t.Align = sub.Align
- if _, ok := c.typedef[name.Name()]; !ok {
- c.typedef[name.Name()] = sub.Go
+ if _, ok := typedef[name.Name]; !ok {
+ typedef[name.Name] = sub.Go
}
case *dwarf.UcharType:
@@ -628,12 +880,12 @@ func (c *typeConv) Type(dtype dwarf.Type) *Type {
case *dwarf.AddrType, *dwarf.BoolType, *dwarf.CharType, *dwarf.IntType, *dwarf.FloatType, *dwarf.UcharType, *dwarf.UintType:
s := dtype.Common().Name
if s != "" {
- if ss, ok := cnameMap[s]; ok {
+ if ss, ok := dwarfToName[s]; ok {
s = ss
}
s = strings.Join(strings.Split(s, " ", -1), "") // strip spaces
- name := c.Ident("_C_" + s)
- c.typedef[name.Name()] = t.Go
+ name := c.Ident("_Ctype_" + s)
+ typedef[name.Name] = t.Go
t.Go = name
}
}
@@ -710,7 +962,9 @@ func (c *typeConv) FuncType(dtype *dwarf.FuncType) *FuncType {
}
// Identifier
-func (c *typeConv) Ident(s string) *ast.Ident { return ast.NewIdent(s) }
+func (c *typeConv) Ident(s string) *ast.Ident {
+ return ast.NewIdent(s)
+}
// Opaque type of n bytes.
func (c *typeConv) Opaque(n int64) ast.Expr {
@@ -736,13 +990,14 @@ func (c *typeConv) pad(fld []*ast.Field, size int64) []*ast.Field {
return fld
}
-// Struct conversion
+// Struct conversion: return Go and (6g) C syntax for type.
func (c *typeConv) Struct(dt *dwarf.StructType) (expr *ast.StructType, csyntax string, align int64) {
- csyntax = "struct { "
+ var buf bytes.Buffer
+ buf.WriteString("struct {")
fld := make([]*ast.Field, 0, 2*len(dt.Field)+1) // enough for padding around every field
off := int64(0)
- // Mangle struct fields that happen to be named Go keywords into
+ // Rename struct fields that happen to be named Go keywords into
// _{keyword}. Create a map from C ident -> Go ident. The Go ident will
// be mangled. Any existing identifier that already has the same name on
// the C-side will cause the Go-mangled version to be prefixed with _.
@@ -783,7 +1038,10 @@ func (c *typeConv) Struct(dt *dwarf.StructType) (expr *ast.StructType, csyntax s
fld[n] = &ast.Field{Names: []*ast.Ident{c.Ident(ident[f.Name])}, Type: t.Go}
off += t.Size
- csyntax += t.C + " " + f.Name + "; "
+ buf.WriteString(t.C)
+ buf.WriteString(" ")
+ buf.WriteString(f.Name)
+ buf.WriteString("; ")
if t.Align > align {
align = t.Align
}
@@ -795,7 +1053,8 @@ func (c *typeConv) Struct(dt *dwarf.StructType) (expr *ast.StructType, csyntax s
if off != dt.ByteSize {
fatal("struct size calculation error")
}
- csyntax += "}"
+ buf.WriteString("}")
+ csyntax = buf.String()
expr = &ast.StructType{Fields: &ast.FieldList{List: fld}}
return
}
diff --git a/src/cmd/cgo/main.go b/src/cmd/cgo/main.go
index 070146c9a..942bda5f4 100644
--- a/src/cmd/cgo/main.go
+++ b/src/cmd/cgo/main.go
@@ -11,13 +11,95 @@
package main
import (
+ "crypto/md5"
+ "flag"
"fmt"
"go/ast"
+ "go/token"
+ "io"
"os"
+ "reflect"
"strings"
)
-func usage() { fmt.Fprint(os.Stderr, "usage: cgo [compiler options] file.go ...\n") }
+// A Package collects information about the package we're going to write.
+type Package struct {
+ PackageName string // name of package
+ PackagePath string
+ PtrSize int64
+ GccOptions []string
+ Written map[string]bool
+ Name map[string]*Name // accumulated Name from Files
+ Typedef map[string]ast.Expr // accumulated Typedef from Files
+ ExpFunc []*ExpFunc // accumulated ExpFunc from Files
+ Decl []ast.Decl
+ GoFiles []string // list of Go files
+ GccFiles []string // list of gcc output files
+}
+
+// A File collects information about a single Go input file.
+type File struct {
+ AST *ast.File // parsed AST
+ Package string // Package name
+ Preamble string // C preamble (doc comment on import "C")
+ Ref []*Ref // all references to C.xxx in AST
+ ExpFunc []*ExpFunc // exported functions for this file
+ Name map[string]*Name // map from Go name to Name
+ Typedef map[string]ast.Expr // translations of all necessary types from C
+}
+
+// A Ref refers to an expression of the form C.xxx in the AST.
+type Ref struct {
+ Name *Name
+ Expr *ast.Expr
+ Context string // "type", "expr", "call", or "call2"
+}
+
+func (r *Ref) Pos() token.Pos {
+ return (*r.Expr).Pos()
+}
+
+// A Name collects information about C.xxx.
+type Name struct {
+ Go string // name used in Go referring to package C
+ Mangle string // name used in generated Go
+ C string // name used in C
+ Define string // #define expansion
+ Kind string // "const", "type", "var", "func", "not-type"
+ Type *Type // the type of xxx
+ FuncType *FuncType
+ AddError bool
+ Const string // constant definition
+}
+
+// A ExpFunc is an exported function, callable from C.
+// Such functions are identified in the Go input file
+// by doc comments containing the line //export ExpName
+type ExpFunc struct {
+ Func *ast.FuncDecl
+ ExpName string // name to use from C
+}
+
+// A Type collects information about a type in both the C and Go worlds.
+type Type struct {
+ Size int64
+ Align int64
+ C string
+ Go ast.Expr
+ EnumValues map[string]int64
+}
+
+// A FuncType collects information about a function type in both the C and Go worlds.
+type FuncType struct {
+ Params []*Type
+ Result *Type
+ Go *ast.FuncType
+}
+
+func usage() {
+ fmt.Fprint(os.Stderr, "usage: cgo [compiler options] file.go ...\n")
+ os.Exit(2)
+}
var ptrSizeMap = map[string]int64{
"386": 4,
@@ -25,43 +107,60 @@ var ptrSizeMap = map[string]int64{
"arm": 4,
}
-var expandName = map[string]string{
- "schar": "signed char",
- "uchar": "unsigned char",
- "ushort": "unsigned short",
- "uint": "unsigned int",
- "ulong": "unsigned long",
- "longlong": "long long",
- "ulonglong": "unsigned long long",
-}
+var cPrefix string
+
+var fset = token.NewFileSet()
+
+var dynobj = flag.String("dynimport", "", "if non-empty, print dynamic import data for that file")
func main() {
- args := os.Args
- if len(args) < 2 {
+ flag.Usage = usage
+ flag.Parse()
+
+ if *dynobj != "" {
+ // 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
+ // 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
+ // symbols and which ones to use.
+ syms, imports := dynimport(*dynobj)
+ for _, sym := range syms {
+ fmt.Printf("#pragma dynimport %s %s %q\n", sym, sym, "")
+ }
+ for _, p := range imports {
+ fmt.Printf("#pragma dynimport %s %s %q\n", "_", "_", p)
+ }
+ return
+ }
+
+ args := flag.Args()
+ if len(args) < 1 {
usage()
- os.Exit(2)
}
// Find first arg that looks like a go file and assume everything before
// that are options to pass to gcc.
var i int
- for i = len(args) - 1; i > 0; i-- {
- if !strings.HasSuffix(args[i], ".go") {
+ for i = len(args); i > 0; i-- {
+ if !strings.HasSuffix(args[i-1], ".go") {
break
}
}
-
- i += 1
-
- gccOptions, goFiles := args[1:i], args[i:]
+ if i == len(args) {
+ usage()
+ }
+ gccOptions, goFiles := args[0:i], args[i:]
arch := os.Getenv("GOARCH")
if arch == "" {
fatal("$GOARCH is not set")
}
- ptrSize, ok := ptrSizeMap[arch]
- if !ok {
- fatal("unknown architecture %s", arch)
+ ptrSize := ptrSizeMap[arch]
+ if ptrSize == 0 {
+ fatal("unknown $GOARCH %q", arch)
}
// Clear locale variables so gcc emits English errors [sic].
@@ -69,75 +168,82 @@ func main() {
os.Setenv("LC_ALL", "C")
os.Setenv("LC_CTYPE", "C")
- p := new(Prog)
-
- p.PtrSize = ptrSize
- p.GccOptions = gccOptions
- p.Vardef = make(map[string]*Type)
- p.Funcdef = make(map[string]*FuncType)
- p.Enumdef = make(map[string]int64)
- p.Constdef = make(map[string]string)
- p.OutDefs = make(map[string]bool)
+ p := &Package{
+ PtrSize: ptrSize,
+ GccOptions: gccOptions,
+ Written: make(map[string]bool),
+ }
+ // Need a unique prefix for the global C symbols that
+ // we use to coordinate between gcc and ourselves.
+ // We already put _cgo_ at the beginning, so the main
+ // concern is other cgo wrappers for the same functions.
+ // Use the beginning of the md5 of the input to disambiguate.
+ h := md5.New()
for _, input := range goFiles {
- // Reset p.Preamble so that we don't end up with conflicting headers / defines
- p.Preamble = builtinProlog
- openProg(input, p)
- for _, cref := range p.Crefs {
- // Convert C.ulong to C.unsigned long, etc.
- if expand, ok := expandName[cref.Name]; ok {
- cref.Name = expand
- }
+ f, err := os.Open(input, os.O_RDONLY, 0)
+ if err != nil {
+ fatal("%s", err)
}
- p.loadDebugInfo()
- for _, cref := range p.Crefs {
+ io.Copy(h, f)
+ f.Close()
+ }
+ cPrefix = fmt.Sprintf("_%x", h.Sum()[0:6])
+
+ for _, input := range goFiles {
+ f := new(File)
+ // Reset f.Preamble so that we don't end up with conflicting headers / defines
+ f.Preamble = ""
+ f.ReadGo(input)
+ p.Translate(f)
+ for _, cref := range f.Ref {
switch cref.Context {
- case "const":
- // This came from a #define and we'll output it later.
- *cref.Expr = ast.NewIdent(cref.Name)
- break
- case "call":
- if !cref.TypeName {
- // Is an actual function call.
- pos := (*cref.Expr).Pos()
- *cref.Expr = &ast.Ident{Position: pos, Obj: ast.NewObj(ast.Err, pos, "_C_"+cref.Name)}
- p.Funcdef[cref.Name] = cref.FuncType
- break
- }
- *cref.Expr = cref.Type.Go
- case "expr":
- if cref.TypeName {
- error((*cref.Expr).Pos(), "type C.%s used as expression", cref.Name)
- }
- // If the expression refers to an enumerated value, then
- // place the identifier for the value and add it to Enumdef so
- // it will be declared as a constant in the later stage.
- if cref.Type.EnumValues != nil {
- *cref.Expr = ast.NewIdent(cref.Name)
- p.Enumdef[cref.Name] = cref.Type.EnumValues[cref.Name]
+ case "call", "call2":
+ if cref.Name.Kind != "type" {
break
}
- // Reference to C variable.
- // We declare a pointer and arrange to have it filled in.
- *cref.Expr = &ast.StarExpr{X: ast.NewIdent("_C_" + cref.Name)}
- p.Vardef[cref.Name] = cref.Type
- case "type":
- if !cref.TypeName {
- error((*cref.Expr).Pos(), "expression C.%s used as type", cref.Name)
- }
- *cref.Expr = cref.Type.Go
+ *cref.Expr = cref.Name.Type.Go
}
}
if nerrors > 0 {
os.Exit(2)
}
- pkg := p.Package
+ pkg := f.Package
if dir := os.Getenv("CGOPKGPATH"); dir != "" {
pkg = dir + "/" + pkg
}
p.PackagePath = pkg
- p.writeOutput(input)
+ p.writeOutput(f, input)
+
+ p.Record(f)
}
p.writeDefs()
+ if nerrors > 0 {
+ os.Exit(2)
+ }
+}
+
+// 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)
+ }
+
+ if p.Name == nil {
+ p.Name = f.Name
+ } else {
+ for k, v := range f.Name {
+ 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)
+ }
+ }
+ }
+
+ p.ExpFunc = append(p.ExpFunc, f.ExpFunc...)
+ p.Decl = append(p.Decl, f.AST.Decls...)
}
diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go
index 7cdf483f0..c3f9ae60b 100644
--- a/src/cmd/cgo/out.go
+++ b/src/cmd/cgo/out.go
@@ -5,6 +5,9 @@
package main
import (
+ "bytes"
+ "debug/elf"
+ "debug/macho"
"fmt"
"go/ast"
"go/printer"
@@ -13,30 +16,9 @@ import (
"strings"
)
-func creat(name string) *os.File {
- f, err := os.Open(name, os.O_WRONLY|os.O_CREAT|os.O_TRUNC, 0666)
- if err != nil {
- fatal("%s", err)
- }
- return f
-}
-
-func slashToUnderscore(c int) int {
- if c == '/' {
- c = '_'
- }
- return c
-}
-
// 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 *Prog) writeDefs() {
- pkgroot := os.Getenv("GOROOT") + "/pkg/" + os.Getenv("GOOS") + "_" + os.Getenv("GOARCH")
- path := p.PackagePath
- if !strings.HasPrefix(path, "/") {
- path = pkgroot + "/" + path
- }
-
+func (p *Package) writeDefs() {
// The path for the shared object is slash-free so that ELF loaders
// will treat it as a relative path. We rewrite slashes to underscores.
sopath := "cgo_" + strings.Map(slashToUnderscore, p.PackagePath)
@@ -48,229 +30,305 @@ func (p *Prog) writeDefs() {
fgo2 := creat("_cgo_gotypes.go")
fc := creat("_cgo_defun.c")
+ fm := creat("_cgo_main.c")
+
+ // Write C main file for using gcc to resolve imports.
+ fmt.Fprintf(fm, "int main() { return 0; }\n")
+ fmt.Fprintf(fm, "int crosscall2;\n\n")
// Write second Go output: definitions of _C_xxx.
// In a separate file so that the import of "unsafe" does not
// pollute the original file.
- fmt.Fprintf(fgo2, "// Created by cgo - DO NOT EDIT\n")
- fmt.Fprintf(fgo2, "package %s\n\n", p.Package)
+ 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, "type _ unsafe.Pointer\n\n")
+ fmt.Fprintf(fgo2, "func _Cerrno(dst *os.Error, x int) { *dst = os.Errno(x) }\n")
- for name, def := range p.Typedef {
+ for name, def := range typedef {
fmt.Fprintf(fgo2, "type %s ", name)
- printer.Fprint(fgo2, def)
+ printer.Fprint(fgo2, fset, def)
fmt.Fprintf(fgo2, "\n")
}
- fmt.Fprintf(fgo2, "type _C_void [0]byte\n")
+ fmt.Fprintf(fgo2, "type _Ctype_void [0]byte\n")
+
+ fmt.Fprintf(fc, cProlog)
+
+ var cVars []string
+ for _, n := range p.Name {
+ if n.Kind != "var" {
+ continue
+ }
+ cVars = append(cVars, n.C)
- fmt.Fprintf(fc, cProlog, soprefix, soprefix, soprefix, soprefix, soprefix)
+ fmt.Fprintf(fm, "extern char %s[];\n", n.C)
+ fmt.Fprintf(fm, "void *_cgohack_%s = %s;\n\n", n.C, n.C)
+
+ fmt.Fprintf(fc, "extern byte *%s;\n", n.C)
+ fmt.Fprintf(fc, "void *·%s = &%s;\n", n.Mangle, n.C)
+ fmt.Fprintf(fc, "\n")
- for name, def := range p.Vardef {
- fmt.Fprintf(fc, "#pragma dynimport ·_C_%s %s \"%s%s.so\"\n", name, name, soprefix, sopath)
- fmt.Fprintf(fgo2, "var _C_%s ", name)
- printer.Fprint(fgo2, &ast.StarExpr{X: def.Go})
+ fmt.Fprintf(fgo2, "var %s ", n.Mangle)
+ printer.Fprint(fgo2, fset, &ast.StarExpr{X: n.Type.Go})
fmt.Fprintf(fgo2, "\n")
}
fmt.Fprintf(fc, "\n")
- for name, value := range p.Constdef {
- fmt.Fprintf(fgo2, "const %s = %s\n", name, value)
- }
-
- for name, value := range p.Enumdef {
- fmt.Fprintf(fgo2, "const %s = %d\n", name, value)
+ for _, n := range p.Name {
+ if n.Const != "" {
+ fmt.Fprintf(fgo2, "const _Cconst_%s = %s\n", n.Go, n.Const)
+ }
}
fmt.Fprintf(fgo2, "\n")
- for name, def := range p.Funcdef {
- // Go func declaration.
- d := &ast.FuncDecl{
- Name: ast.NewIdent("_C_" + name),
- Type: def.Go,
+ for _, n := range p.Name {
+ if n.FuncType != nil {
+ p.writeDefsFunc(fc, fgo2, n, soprefix, sopath)
}
- printer.Fprint(fgo2, d)
- fmt.Fprintf(fgo2, "\n")
+ }
- if name == "CString" || name == "GoString" {
- // The builtins are already defined in the C prolog.
- continue
+ p.writeExports(fgo2, fc, fm)
+
+ fgo2.Close()
+ fc.Close()
+}
+
+func dynimport(obj string) (syms, imports []string) {
+ var f interface {
+ ImportedLibraries() ([]string, os.Error)
+ ImportedSymbols() ([]string, os.Error)
+ }
+ var isMacho bool
+ var err1, err2 os.Error
+ if f, err1 = elf.Open(obj); err1 != nil {
+ if f, err2 = macho.Open(obj); err2 != nil {
+ fatal("cannot parse %s as ELF (%v) or Mach-O (%v)", obj, err1, err2)
}
+ isMacho = true
+ }
- // Construct a gcc struct matching the 6c argument frame.
- // Assumes that in gcc, char is 1 byte, short 2 bytes, int 4 bytes, long long 8 bytes.
- // These assumptions are checked by the gccProlog.
- // Also assumes that 6c convention is to word-align the
- // input and output parameters.
- structType := "struct {\n"
- off := int64(0)
- npad := 0
- for i, t := range def.Params {
- if off%t.Align != 0 {
- pad := t.Align - off%t.Align
- structType += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
- off += pad
- npad++
+ var err os.Error
+ syms, err = f.ImportedSymbols()
+ if err != nil {
+ fatal("cannot load dynamic symbols: %v", err)
+ }
+ if isMacho {
+ // remove leading _ that OS X insists on
+ for i, s := range syms {
+ if len(s) >= 2 && s[0] == '_' {
+ syms[i] = s[1:]
}
- structType += fmt.Sprintf("\t\t%s p%d;\n", t.C, i)
- off += t.Size
}
- if off%p.PtrSize != 0 {
- pad := p.PtrSize - off%p.PtrSize
- structType += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
+ }
+
+ imports, err = f.ImportedLibraries()
+ if err != nil {
+ fatal("cannot load dynamic imports: %v", err)
+ }
+
+ return
+}
+
+// Construct a gcc struct matching the 6c argument frame.
+// Assumes that in gcc, char is 1 byte, short 2 bytes, int 4 bytes, long long 8 bytes.
+// These assumptions are checked by the gccProlog.
+// Also assumes that 6c convention is to word-align the
+// input and output parameters.
+func (p *Package) structType(n *Name) (string, int64) {
+ var buf bytes.Buffer
+ fmt.Fprint(&buf, "struct {\n")
+ off := int64(0)
+ for i, t := range n.FuncType.Params {
+ if off%t.Align != 0 {
+ pad := t.Align - off%t.Align
+ fmt.Fprintf(&buf, "\t\tchar __pad%d[%d];\n", off, pad)
off += pad
- npad++
- }
- if t := def.Result; t != nil {
- if off%t.Align != 0 {
- pad := t.Align - off%t.Align
- structType += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
- off += pad
- npad++
- }
- structType += fmt.Sprintf("\t\t%s r;\n", t.C)
- off += t.Size
}
- if off%p.PtrSize != 0 {
- pad := p.PtrSize - off%p.PtrSize
- structType += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
+ fmt.Fprintf(&buf, "\t\t%s p%d;\n", t.C, i)
+ off += t.Size
+ }
+ if off%p.PtrSize != 0 {
+ pad := p.PtrSize - off%p.PtrSize
+ fmt.Fprintf(&buf, "\t\tchar __pad%d[%d];\n", off, pad)
+ off += pad
+ }
+ if t := n.FuncType.Result; t != nil {
+ if off%t.Align != 0 {
+ pad := t.Align - off%t.Align
+ fmt.Fprintf(&buf, "\t\tchar __pad%d[%d];\n", off, pad)
off += pad
- npad++
}
- if len(def.Params) == 0 && def.Result == nil {
- structType += "\t\tchar unused;\n" // avoid empty struct
- off++
+ qual := ""
+ if t.C[len(t.C)-1] == '*' {
+ qual = "const "
}
- structType += "\t}"
- argSize := off
+ fmt.Fprintf(&buf, "\t\t%s%s r;\n", qual, t.C)
+ off += t.Size
+ }
+ if off%p.PtrSize != 0 {
+ pad := p.PtrSize - off%p.PtrSize
+ fmt.Fprintf(&buf, "\t\tchar __pad%d[%d];\n", off, pad)
+ off += pad
+ }
+ if n.AddError {
+ fmt.Fprint(&buf, "\t\tvoid *e[2]; /* os.Error */\n")
+ off += 2 * p.PtrSize
+ }
+ if off == 0 {
+ fmt.Fprintf(&buf, "\t\tchar unused;\n") // avoid empty struct
+ off++
+ }
+ fmt.Fprintf(&buf, "\t}")
+ return buf.String(), off
+}
- // C wrapper calls into gcc, passing a pointer to the argument frame.
- // Also emit #pragma to get a pointer to the gcc wrapper.
- fmt.Fprintf(fc, "#pragma dynimport _cgo_%s _cgo_%s \"%s%s.so\"\n", name, name, soprefix, sopath)
- fmt.Fprintf(fc, "void (*_cgo_%s)(void*);\n", name)
- fmt.Fprintf(fc, "\n")
- fmt.Fprintf(fc, "void\n")
- fmt.Fprintf(fc, "·_C_%s(struct{uint8 x[%d];}p)\n", name, argSize)
- fmt.Fprintf(fc, "{\n")
- fmt.Fprintf(fc, "\tcgocall(_cgo_%s, &p);\n", name)
- fmt.Fprintf(fc, "}\n")
- fmt.Fprintf(fc, "\n")
+func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name, soprefix, sopath string) {
+ name := n.Go
+ gtype := n.FuncType.Go
+ if n.AddError {
+ // Add "os.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")}
+ l := gtype.Results.List
+ if len(l) == 0 {
+ l = []*ast.Field{err}
+ } else {
+ l = []*ast.Field{l[0], err}
+ }
+ t := new(ast.FuncType)
+ *t = *gtype
+ t.Results = &ast.FieldList{List: l}
+ gtype = t
}
- p.writeExports(fgo2, fc)
+ // Go func declaration.
+ d := &ast.FuncDecl{
+ Name: ast.NewIdent(n.Mangle),
+ Type: gtype,
+ }
+ printer.Fprint(fgo2, fset, d)
+ fmt.Fprintf(fgo2, "\n")
- fgo2.Close()
- fc.Close()
+ if name == "CString" || name == "GoString" || name == "GoStringN" {
+ // The builtins are already defined in the C prolog.
+ return
+ }
+
+ var argSize int64
+ _, argSize = p.structType(n)
+
+ // C wrapper calls into gcc, passing a pointer to the argument frame.
+ fmt.Fprintf(fc, "void _cgo%s%s(void*);\n", cPrefix, n.Mangle)
+ fmt.Fprintf(fc, "\n")
+ fmt.Fprintf(fc, "void\n")
+ fmt.Fprintf(fc, "·%s(struct{uint8 x[%d];}p)\n", n.Mangle, argSize)
+ fmt.Fprintf(fc, "{\n")
+ fmt.Fprintf(fc, "\truntime·cgocall(_cgo%s%s, &p);\n", cPrefix, n.Mangle)
+ if n.AddError {
+ // gcc leaves errno in first word of interface at end of p.
+ // check whether it is zero; if so, turn interface into nil.
+ // if not, turn interface into errno.
+ // Go init function initializes ·_Cerrno with an os.Errno
+ // for us to copy.
+ fmt.Fprintln(fc, ` {
+ int32 e;
+ void **v;
+ v = (void**)(&p+1) - 2; /* v = final two void* of p */
+ e = *(int32*)v;
+ v[0] = (void*)0xdeadbeef;
+ v[1] = (void*)0xdeadbeef;
+ if(e == 0) {
+ /* nil interface */
+ v[0] = 0;
+ v[1] = 0;
+ } else {
+ ·_Cerrno(v, e); /* fill in v as os.Error for errno e */
+ }
+ }`)
+ }
+ fmt.Fprintf(fc, "}\n")
+ fmt.Fprintf(fc, "\n")
}
// writeOutput creates stubs for a specific source file to be compiled by 6g
// (The comments here say 6g and 6c but the code applies to the 8 and 5 tools too.)
-func (p *Prog) writeOutput(srcfile string) {
+func (p *Package) writeOutput(f *File, srcfile string) {
base := srcfile
if strings.HasSuffix(base, ".go") {
base = base[0 : len(base)-3]
}
+ base = strings.Map(slashToUnderscore, base)
fgo1 := creat(base + ".cgo1.go")
fgcc := creat(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")
+ fmt.Fprintf(fgo1, "// Created by cgo - DO NOT EDIT\n\n")
fmt.Fprintf(fgo1, "//line %s:1\n", srcfile)
- printer.Fprint(fgo1, p.AST)
+ printer.Fprint(fgo1, fset, f.AST)
// While we process the vars and funcs, also write 6c and gcc output.
// Gcc output starts with the preamble.
- fmt.Fprintf(fgcc, "%s\n", p.Preamble)
+ fmt.Fprintf(fgcc, "%s\n", f.Preamble)
fmt.Fprintf(fgcc, "%s\n", gccProlog)
- for name, def := range p.Funcdef {
- _, ok := p.OutDefs[name]
- if name == "CString" || name == "GoString" || ok {
- // The builtins are already defined in the C prolog, and we don't
- // want to duplicate function definitions we've already done.
- continue
- }
- p.OutDefs[name] = true
-
- // Construct a gcc struct matching the 6c argument frame.
- // Assumes that in gcc, char is 1 byte, short 2 bytes, int 4 bytes, long long 8 bytes.
- // These assumptions are checked by the gccProlog.
- // Also assumes that 6c convention is to word-align the
- // input and output parameters.
- structType := "struct {\n"
- off := int64(0)
- npad := 0
- for i, t := range def.Params {
- if off%t.Align != 0 {
- pad := t.Align - off%t.Align
- structType += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
- off += pad
- npad++
- }
- structType += fmt.Sprintf("\t\t%s p%d;\n", t.C, i)
- off += t.Size
+ for _, n := range f.Name {
+ if n.FuncType != nil {
+ p.writeOutputFunc(fgcc, n)
}
- if off%p.PtrSize != 0 {
- pad := p.PtrSize - off%p.PtrSize
- structType += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
- off += pad
- npad++
- }
- if t := def.Result; t != nil {
- if off%t.Align != 0 {
- pad := t.Align - off%t.Align
- structType += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
- off += pad
- npad++
- }
- structType += fmt.Sprintf("\t\t%s r;\n", t.C)
- off += t.Size
- }
- if off%p.PtrSize != 0 {
- pad := p.PtrSize - off%p.PtrSize
- structType += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
- off += pad
- npad++
- }
- if len(def.Params) == 0 && def.Result == nil {
- structType += "\t\tchar unused;\n" // avoid empty struct
- off++
- }
- structType += "\t}"
-
- // Gcc wrapper unpacks the C argument struct
- // and calls the actual C function.
- fmt.Fprintf(fgcc, "void\n")
- fmt.Fprintf(fgcc, "_cgo_%s(void *v)\n", name)
- fmt.Fprintf(fgcc, "{\n")
- fmt.Fprintf(fgcc, "\t%s *a = v;\n", structType)
- fmt.Fprintf(fgcc, "\t")
- if def.Result != nil {
- fmt.Fprintf(fgcc, "a->r = ")
- }
- fmt.Fprintf(fgcc, "%s(", name)
- for i := range def.Params {
- if i > 0 {
- fmt.Fprintf(fgcc, ", ")
- }
- fmt.Fprintf(fgcc, "a->p%d", i)
- }
- fmt.Fprintf(fgcc, ");\n")
- fmt.Fprintf(fgcc, "}\n")
- fmt.Fprintf(fgcc, "\n")
}
fgo1.Close()
fgcc.Close()
}
-// Write out the various stubs we need to support functions exported
-// from Go so that they are callable from C.
-func (p *Prog) writeExports(fgo2, fc *os.File) {
- if len(p.ExpFuncs) == 0 {
+func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
+ name := n.Mangle
+ if name == "_Cfunc_CString" || name == "_Cfunc_GoString" || name == "_Cfunc_GoStringN" || p.Written[name] {
+ // The builtins are already defined in the C prolog, and we don't
+ // want to duplicate function definitions we've already done.
return
}
+ p.Written[name] = true
+
+ ctype, _ := p.structType(n)
+
+ // Gcc wrapper unpacks the C argument struct
+ // and calls the actual C function.
+ fmt.Fprintf(fgcc, "void\n")
+ fmt.Fprintf(fgcc, "_cgo%s%s(void *v)\n", cPrefix, n.Mangle)
+ fmt.Fprintf(fgcc, "{\n")
+ if n.AddError {
+ fmt.Fprintf(fgcc, "\tint e;\n") // assuming 32 bit (see comment above structType)
+ fmt.Fprintf(fgcc, "\terrno = 0;\n")
+ }
+ fmt.Fprintf(fgcc, "\t%s *a = v;\n", ctype)
+ fmt.Fprintf(fgcc, "\t")
+ if n.FuncType.Result != nil {
+ fmt.Fprintf(fgcc, "a->r = ")
+ }
+ fmt.Fprintf(fgcc, "%s(", n.C)
+ for i := range n.FuncType.Params {
+ if i > 0 {
+ fmt.Fprintf(fgcc, ", ")
+ }
+ fmt.Fprintf(fgcc, "a->p%d", i)
+ }
+ fmt.Fprintf(fgcc, ");\n")
+ if n.AddError {
+ fmt.Fprintf(fgcc, "\t*(int*)(a->e) = errno;\n")
+ }
+ fmt.Fprintf(fgcc, "}\n")
+ fmt.Fprintf(fgcc, "\n")
+}
+// 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("_cgo_export.c")
fgcch := creat("_cgo_export.h")
@@ -280,17 +338,17 @@ func (p *Prog) writeExports(fgo2, fc *os.File) {
fmt.Fprintf(fgcc, "/* Created by cgo - DO NOT EDIT. */\n")
fmt.Fprintf(fgcc, "#include \"_cgo_export.h\"\n")
- for _, exp := range p.ExpFuncs {
+ for _, exp := range p.ExpFunc {
fn := exp.Func
// Construct a gcc struct matching the 6c argument and
// result frame.
- structType := "struct {\n"
+ ctype := "struct {\n"
off := int64(0)
npad := 0
if fn.Recv != nil {
t := p.cgoType(fn.Recv.List[0].Type)
- structType += fmt.Sprintf("\t\t%s recv;\n", t.C)
+ ctype += fmt.Sprintf("\t\t%s recv;\n", t.C)
off += t.Size
}
fntype := fn.Type
@@ -299,16 +357,16 @@ func (p *Prog) writeExports(fgo2, fc *os.File) {
t := p.cgoType(atype)
if off%t.Align != 0 {
pad := t.Align - off%t.Align
- structType += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
+ ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
off += pad
npad++
}
- structType += fmt.Sprintf("\t\t%s p%d;\n", t.C, i)
+ ctype += fmt.Sprintf("\t\t%s p%d;\n", t.C, i)
off += t.Size
})
if off%p.PtrSize != 0 {
pad := p.PtrSize - off%p.PtrSize
- structType += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
+ ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
off += pad
npad++
}
@@ -317,24 +375,24 @@ func (p *Prog) writeExports(fgo2, fc *os.File) {
t := p.cgoType(atype)
if off%t.Align != 0 {
pad := t.Align - off%t.Align
- structType += fmt.Sprintf("\t\tchar __pad%d[%d]\n", npad, pad)
+ ctype += fmt.Sprintf("\t\tchar __pad%d[%d]\n", npad, pad)
off += pad
npad++
}
- structType += fmt.Sprintf("\t\t%s r%d;\n", t.C, i)
+ ctype += fmt.Sprintf("\t\t%s r%d;\n", t.C, i)
off += t.Size
})
if off%p.PtrSize != 0 {
pad := p.PtrSize - off%p.PtrSize
- structType += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
+ ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
off += pad
npad++
}
- if structType == "struct {\n" {
- structType += "\t\tchar unused;\n" // avoid empty struct
+ if ctype == "struct {\n" {
+ ctype += "\t\tchar unused;\n" // avoid empty struct
off++
}
- structType += "\t}"
+ ctype += "\t}"
// Get the return type of the wrapper function
// compiled by gcc.
@@ -370,10 +428,10 @@ func (p *Prog) writeExports(fgo2, fc *os.File) {
s += ")"
fmt.Fprintf(fgcch, "\nextern %s;\n", s)
- fmt.Fprintf(fgcc, "extern _cgoexp_%s(void *, int);\n", exp.ExpName)
+ fmt.Fprintf(fgcc, "extern _cgoexp%s_%s(void *, int);\n", cPrefix, exp.ExpName)
fmt.Fprintf(fgcc, "\n%s\n", s)
fmt.Fprintf(fgcc, "{\n")
- fmt.Fprintf(fgcc, "\t%s a;\n", structType)
+ fmt.Fprintf(fgcc, "\t%s a;\n", ctype)
if gccResult != "void" && (len(fntype.Results.List) > 1 || len(fntype.Results.List[0].Names) > 1) {
fmt.Fprintf(fgcc, "\t%s r;\n", gccResult)
}
@@ -384,7 +442,7 @@ func (p *Prog) writeExports(fgo2, fc *os.File) {
func(i int, atype ast.Expr) {
fmt.Fprintf(fgcc, "\ta.p%d = p%d;\n", i, i)
})
- fmt.Fprintf(fgcc, "\tcrosscall2(_cgoexp_%s, &a, (int) sizeof a);\n", exp.ExpName)
+ fmt.Fprintf(fgcc, "\tcrosscall2(_cgoexp%s_%s, &a, (int) sizeof a);\n", cPrefix, exp.ExpName)
if gccResult != "void" {
if len(fntype.Results.List) == 1 && len(fntype.Results.List[0].Names) <= 1 {
fmt.Fprintf(fgcc, "\treturn a.r0;\n")
@@ -399,27 +457,28 @@ func (p *Prog) writeExports(fgo2, fc *os.File) {
fmt.Fprintf(fgcc, "}\n")
// Build the wrapper function compiled by 6c/8c
- goname := exp.Func.Name.Name()
+ goname := exp.Func.Name.Name
if fn.Recv != nil {
- goname = "_cgoexpwrap_" + fn.Recv.List[0].Names[0].Name() + "_" + goname
+ goname = "_cgoexpwrap" + cPrefix + "_" + fn.Recv.List[0].Names[0].Name + "_" + goname
}
- fmt.Fprintf(fc, "#pragma dynexport _cgoexp_%s _cgoexp_%s\n", exp.ExpName, exp.ExpName)
fmt.Fprintf(fc, "extern void ·%s();\n", goname)
fmt.Fprintf(fc, "\nvoid\n")
- fmt.Fprintf(fc, "_cgoexp_%s(void *a, int32 n)\n", exp.ExpName)
+ fmt.Fprintf(fc, "_cgoexp%s_%s(void *a, int32 n)\n", cPrefix, exp.ExpName)
fmt.Fprintf(fc, "{\n")
- fmt.Fprintf(fc, "\tcgocallback(·%s, a, n);\n", goname)
+ fmt.Fprintf(fc, "\truntime·cgocallback(·%s, a, n);\n", goname)
fmt.Fprintf(fc, "}\n")
+ fmt.Fprintf(fm, "int _cgoexp%s_%s;\n", cPrefix, exp.ExpName)
+
// Calling a function with a receiver from C requires
// a Go wrapper function.
if fn.Recv != nil {
fmt.Fprintf(fgo2, "func %s(recv ", goname)
- printer.Fprint(fgo2, fn.Recv.List[0].Type)
+ printer.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, atype)
+ fmt.Fprintf(fgo2, ", p%d ", i)
+ printer.Fprint(fgo2, fset, atype)
})
fmt.Fprintf(fgo2, ")")
if gccResult != "void" {
@@ -429,7 +488,7 @@ func (p *Prog) writeExports(fgo2, fc *os.File) {
if i > 0 {
fmt.Fprint(fgo2, ", ")
}
- printer.Fprint(fgo2, atype)
+ printer.Fprint(fgo2, fset, atype)
})
fmt.Fprint(fgo2, ")")
}
@@ -493,7 +552,7 @@ var goTypes = map[string]*Type{
}
// Map an ast type to a Type.
-func (p *Prog) cgoType(e ast.Expr) *Type {
+func (p *Package) cgoType(e ast.Expr) *Type {
switch t := e.(type) {
case *ast.StarExpr:
x := p.cgoType(t.X)
@@ -515,7 +574,7 @@ func (p *Prog) cgoType(e ast.Expr) *Type {
case *ast.Ident:
// Look up the type in the top level declarations.
// TODO: Handle types defined within a function.
- for _, d := range p.AST.Decls {
+ for _, d := range p.Decl {
gd, ok := d.(*ast.GenDecl)
if !ok || gd.Tok != token.TYPE {
continue
@@ -525,30 +584,35 @@ func (p *Prog) cgoType(e ast.Expr) *Type {
if !ok {
continue
}
- if ts.Name.Name() == t.Name() {
+ if ts.Name.Name == t.Name {
return p.cgoType(ts.Type)
}
}
}
- for name, def := range p.Typedef {
- if name == t.Name() {
+ for name, def := range typedef {
+ if name == t.Name {
return p.cgoType(def)
}
}
- if t.Name() == "uintptr" {
+ if t.Name == "uintptr" {
return &Type{Size: p.PtrSize, Align: p.PtrSize, C: "uintptr"}
}
- if t.Name() == "string" {
+ if t.Name == "string" {
return &Type{Size: p.PtrSize + 4, Align: p.PtrSize, C: "GoString"}
}
- if r, ok := goTypes[t.Name()]; ok {
+ if r, ok := goTypes[t.Name]; ok {
if r.Align > p.PtrSize {
r.Align = p.PtrSize
}
return r
}
+ case *ast.SelectorExpr:
+ id, ok := t.X.(*ast.Ident)
+ if ok && id.Name == "unsafe" && t.Sel.Name == "Pointer" {
+ return &Type{Size: p.PtrSize, Align: p.PtrSize, C: "void*"}
+ }
}
- error(e.Pos(), "unrecognized Go type %v", e)
+ error(e.Pos(), "unrecognized Go type %T", e)
return &Type{Size: 4, Align: 4, C: "int"}
}
@@ -568,11 +632,15 @@ typedef long long __cgo_long_long;
__cgo_size_assert(__cgo_long_long, 8)
__cgo_size_assert(float, 4)
__cgo_size_assert(double, 8)
+
+#include <errno.h>
+#include <string.h>
`
const builtinProlog = `
typedef struct { char *p; int n; } _GoString_;
_GoString_ GoString(char *p);
+_GoString_ GoStringN(char *p, int l);
char *CString(_GoString_);
`
@@ -580,24 +648,27 @@ const cProlog = `
#include "runtime.h"
#include "cgocall.h"
-#pragma dynimport initcgo initcgo "%slibcgo.so"
-#pragma dynimport libcgo_thread_start libcgo_thread_start "%slibcgo.so"
-#pragma dynimport libcgo_set_scheduler libcgo_set_scheduler "%slibcgo.so"
-#pragma dynimport _cgo_malloc _cgo_malloc "%slibcgo.so"
-#pragma dynimport _cgo_free _cgo_free "%slibcgo.so"
+void ·_Cerrno(void*, int32);
+
+void
+·_Cfunc_GoString(int8 *p, String s)
+{
+ s = runtime·gostring((byte*)p);
+ FLUSH(&s);
+}
void
-·_C_GoString(int8 *p, String s)
+·_Cfunc_GoStringN(int8 *p, int32 l, String s)
{
- s = gostring((byte*)p);
+ s = runtime·gostringn((byte*)p, l);
FLUSH(&s);
}
void
-·_C_CString(String s, int8 *p)
+·_Cfunc_CString(String s, int8 *p)
{
- p = cmalloc(s.len+1);
- mcpy((byte*)p, s.str, s.len);
+ p = runtime·cmalloc(s.len+1);
+ runtime·mcpy((byte*)p, s.str, s.len);
p[s.len] = 0;
FLUSH(&p);
}
@@ -610,6 +681,7 @@ typedef unsigned char uchar;
typedef unsigned short ushort;
typedef long long int64;
typedef unsigned long long uint64;
+typedef __SIZE_TYPE__ uintptr;
typedef struct { char *p; int n; } GoString;
typedef void *GoMap;
diff --git a/src/cmd/cgo/util.go b/src/cmd/cgo/util.go
index 95067039c..a6f509dc4 100644
--- a/src/cmd/cgo/util.go
+++ b/src/cmd/cgo/util.go
@@ -12,16 +12,6 @@ import (
"os"
)
-// A ByteReaderAt implements io.ReadAt using a slice of bytes.
-type ByteReaderAt []byte
-
-func (r ByteReaderAt) ReadAt(p []byte, off int64) (n int, err os.Error) {
- if off >= int64(len(r)) || off < 0 {
- return 0, os.EOF
- }
- return copy(p, r[off:]), nil
-}
-
// run runs the command argv, feeding in stdin on standard input.
// It returns the output to standard output and standard error.
// ok indicates whether the command exited successfully.
@@ -55,9 +45,8 @@ func run(stdin []byte, argv []string) (stdout, stderr []byte, ok bool) {
w0.Close()
c <- true
}()
- var xstdout []byte // TODO(rsc): delete after 6g can take address of out parameter
go func() {
- xstdout, _ = ioutil.ReadAll(r1)
+ stdout, _ = ioutil.ReadAll(r1)
r1.Close()
c <- true
}()
@@ -65,7 +54,6 @@ func run(stdin []byte, argv []string) (stdout, stderr []byte, ok bool) {
r2.Close()
<-c
<-c
- stdout = xstdout
w, err := os.Wait(pid, 0)
if err != nil {
@@ -77,18 +65,45 @@ func run(stdin []byte, argv []string) (stdout, stderr []byte, ok bool) {
// Die with an error message.
func fatal(msg string, args ...interface{}) {
- fmt.Fprintf(os.Stderr, msg+"\n", args)
+ fmt.Fprintf(os.Stderr, msg+"\n", args...)
os.Exit(2)
}
var nerrors int
-var noPos token.Position
-func error(pos token.Position, msg string, args ...interface{}) {
+func error(pos token.Pos, msg string, args ...interface{}) {
nerrors++
if pos.IsValid() {
- fmt.Fprintf(os.Stderr, "%s: ", pos)
+ fmt.Fprintf(os.Stderr, "%s: ", fset.Position(pos).String())
}
- fmt.Fprintf(os.Stderr, msg, args)
+ fmt.Fprintf(os.Stderr, msg, args...)
fmt.Fprintf(os.Stderr, "\n")
}
+
+// isName returns true if s is a valid C identifier
+func isName(s string) bool {
+ for i, v := range s {
+ if v != '_' && (v < 'A' || v > 'Z') && (v < 'a' || v > 'z') && (v < '0' || v > '9') {
+ return false
+ }
+ if i == 0 && '0' <= v && v <= '9' {
+ return false
+ }
+ }
+ return s != ""
+}
+
+func creat(name string) *os.File {
+ f, err := os.Open(name, os.O_WRONLY|os.O_CREAT|os.O_TRUNC, 0666)
+ if err != nil {
+ fatal("%s", err)
+ }
+ return f
+}
+
+func slashToUnderscore(c int) int {
+ if c == '/' {
+ c = '_'
+ }
+ return c
+}
diff --git a/src/cmd/clean.bash b/src/cmd/clean.bash
index 9317b8ae5..6349919a8 100644
--- a/src/cmd/clean.bash
+++ b/src/cmd/clean.bash
@@ -3,11 +3,9 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-GOBIN="${GOBIN:-$HOME/bin}"
-
for i in cc 6l 6a 6c 8l 8a 8c 8g 5l 5a 5c 5g gc 6g gopack nm cgo cov ebnflint godefs godoc gofmt goinstall gotest goyacc hgpatch prof
do
cd $i
- "$GOBIN"/gomake clean
+ gomake clean
cd ..
done
diff --git a/src/cmd/cov/Makefile b/src/cmd/cov/Makefile
index 58cb2302c..fdeb14636 100644
--- a/src/cmd/cov/Makefile
+++ b/src/cmd/cov/Makefile
@@ -2,7 +2,8 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.conf
+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
@@ -16,15 +17,22 @@ OFILES=\
HFILES=\
tree.h\
-$(TARG): $(OFILES)
- $(LD) -o $(TARG) -L"$(GOROOT)"/lib $(OFILES) -lmach -lbio -l9
+LIB=\
+ ../../../lib/libmach.a\
-clean:
- rm -f *.$O $(TARG)
+NOINSTALL=1
+include ../../Make.ccmd
-install: install-$(shell uname | tr A-Z a-z)
+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)
@@ -32,5 +40,3 @@ install-darwin: $(TARG)
install-default: $(TARG)
cp $(TARG) "$(GOBIN)"/$(TARG)
-
-$(OFILES): $(HFILES)
diff --git a/src/cmd/cov/main.c b/src/cmd/cov/main.c
index 1b3138a7f..5ff22c00a 100644
--- a/src/cmd/cov/main.c
+++ b/src/cmd/cov/main.c
@@ -81,7 +81,7 @@ ran(uvlong pc, uvlong epc)
key.epc = pc+1;
r = treeget(&breakpoints, &key);
if(r == nil)
- sysfatal("unchecked breakpoint at %#lux+%d", pc, (int)(epc-pc));
+ 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.
diff --git a/src/cmd/ebnflint/Makefile b/src/cmd/ebnflint/Makefile
index 8cb9fd821..8f030aaef 100644
--- a/src/cmd/ebnflint/Makefile
+++ b/src/cmd/ebnflint/Makefile
@@ -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 ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=ebnflint
GOFILES=\
@@ -11,5 +11,5 @@ GOFILES=\
include ../../Make.cmd
test: $(TARG)
- $(QUOTED_GOBIN)/$(TARG) -start="SourceFile" "$(GOROOT)"/doc/go_spec.html
+ $(TARG) -start="SourceFile" "$(GOROOT)"/doc/go_spec.html
diff --git a/src/cmd/ebnflint/ebnflint.go b/src/cmd/ebnflint/ebnflint.go
index 3dfa71f07..10cb5b387 100644
--- a/src/cmd/ebnflint/ebnflint.go
+++ b/src/cmd/ebnflint/ebnflint.go
@@ -10,12 +10,14 @@ import (
"flag"
"fmt"
"go/scanner"
+ "go/token"
"io/ioutil"
"os"
"path"
)
+var fset = token.NewFileSet()
var start = flag.String("start", "Start", "name of start production")
@@ -92,12 +94,12 @@ func main() {
src = extractEBNF(src)
}
- grammar, err := ebnf.Parse(filename, src)
+ grammar, err := ebnf.Parse(fset, filename, src)
if err != nil {
scanner.PrintError(os.Stderr, err)
}
- if err = ebnf.Verify(grammar, *start); err != nil {
+ if err = ebnf.Verify(fset, grammar, *start); err != nil {
scanner.PrintError(os.Stderr, err)
}
}
diff --git a/src/cmd/gc/Makefile b/src/cmd/gc/Makefile
index 46dc6dfbc..dbfd86474 100644
--- a/src/cmd/gc/Makefile
+++ b/src/cmd/gc/Makefile
@@ -2,10 +2,10 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.conf
+include ../../Make.inc
+O:=$(HOST_O)
-LIB=\
- gc.a$O\
+LIB=gc.a
HFILES=\
go.h\
@@ -43,16 +43,10 @@ OFILES=\
walk.$O\
y1.tab.$O\
-$(LIB): $(OFILES)
- ar rsc $(LIB) $(OFILES)
+NOINSTALL=1
+include ../../Make.clib
-$(OFILES): $(HFILES)
-
-y.tab.h: $(YFILES)
- LANG=C LANGUAGE="en_US.UTF8" bison -v -y $(YFLAGS) $(YFILES)
-
-y.tab.c: y.tab.h
- test -f y.tab.c && touch y.tab.c
+install: $(LIB)
y1.tab.c: y.tab.c # 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/' >y1.tab.c
@@ -70,7 +64,4 @@ subr.$O: opnames.h
opnames.h: mkopnames go.h
./mkopnames go.h >opnames.h
-clean:
- rm -f *.[568o] enam.c [568].out a.out y.tab.h y.tab.c y1.tab.c y.output yerr.h $(LIB) mkbuiltin1 builtin.c _builtin.c opnames.h
-
-install: $(LIB)
+CLEANFILES+=*.[568] [568].out y1.tab.c yerr.h mkbuiltin1 builtin.c _builtin.c opnames.h
diff --git a/src/cmd/gc/align.c b/src/cmd/gc/align.c
index 1b9112d69..a3785e871 100644
--- a/src/cmd/gc/align.c
+++ b/src/cmd/gc/align.c
@@ -7,8 +7,8 @@
/*
* machine size and rounding
* alignment is dictated around
- * the size of a pointer, set in belexinit
- * (see ../6g/align.c).
+ * the size of a pointer, set in betypeinit
+ * (see ../6g/galign.c).
*/
static int defercalc;
@@ -16,15 +16,9 @@ static int defercalc;
uint32
rnd(uint32 o, uint32 r)
{
- if(maxround == 0)
+ if(r < 1 || r > 8 || (r&(r-1)) != 0)
fatal("rnd");
-
- if(r > maxround)
- r = maxround;
- if(r != 0)
- while(o%r != 0)
- o++;
- return o;
+ return (o+r-1)&~(r-1);
}
static void
@@ -43,29 +37,24 @@ offmod(Type *t)
}
static uint32
-arrayelemwidth(Type *t)
-{
-
- while(t->etype == TARRAY && t->bound >= 0)
- t = t->type;
- return t->width;
-}
-
-static uint32
widstruct(Type *t, uint32 o, int flag)
{
Type *f;
- int32 w, m;
-
+ int32 w, maxalign;
+
+ maxalign = flag;
+ if(maxalign < 1)
+ maxalign = 1;
for(f=t->type; f!=T; f=f->down) {
if(f->etype != TFIELD)
fatal("widstruct: not TFIELD: %lT", f);
dowidth(f->type);
+ if(f->type->align > maxalign)
+ maxalign = f->type->align;
if(f->type->width < 0)
fatal("invalid width %lld", f->type->width);
w = f->type->width;
- m = arrayelemwidth(f->type);
- o = rnd(o, m);
+ o = rnd(o, f->type->align);
f->width = o; // really offset for TFIELD
if(f->nname != N) {
// this same stackparam logic is in addrescapes
@@ -82,7 +71,8 @@ widstruct(Type *t, uint32 o, int flag)
}
// final width is rounded
if(flag)
- o = rnd(o, maxround);
+ o = rnd(o, maxalign);
+ t->align = maxalign;
// type width only includes back to first field's offset
if(t->type == T)
@@ -100,7 +90,7 @@ dowidth(Type *t)
int lno;
Type *t1;
- if(maxround == 0 || widthptr == 0)
+ if(widthptr == 0)
fatal("dowidth without betypeinit");
if(t == T)
@@ -124,6 +114,7 @@ dowidth(Type *t)
lno = lineno;
lineno = t->lineno;
t->width = -2;
+ t->align = 0;
et = t->etype;
switch(et) {
@@ -166,9 +157,11 @@ dowidth(Type *t)
case TFLOAT64:
case TCOMPLEX64:
w = 8;
+ t->align = widthptr;
break;
case TCOMPLEX128:
w = 16;
+ t->align = widthptr;
break;
case TPTR32:
w = 4;
@@ -180,6 +173,7 @@ dowidth(Type *t)
break;
case TINTER: // implemented as 2 pointers
w = 2*widthptr;
+ t->align = widthptr;
offmod(t);
break;
case TCHAN: // implemented as pointer
@@ -197,6 +191,7 @@ dowidth(Type *t)
dowidth(t->type); // just in case
if(t1->type->width >= (1<<16))
yyerror("channel element type too large (>64kB)");
+ t->width = 1;
break;
case TMAP: // implemented as pointer
w = widthptr;
@@ -217,6 +212,7 @@ dowidth(Type *t)
if(sizeof_String == 0)
fatal("early dowidth string");
w = sizeof_String;
+ t->align = widthptr;
break;
case TARRAY:
if(t->type == T)
@@ -235,11 +231,13 @@ dowidth(Type *t)
yyerror("type %lT larger than address space", t);
w = t->bound * t->type->width;
if(w == 0)
- w = maxround;
+ w = 1;
+ t->align = t->type->align;
}
else if(t->bound == -1) {
w = sizeof_Array;
checkwidth(t->type);
+ t->align = widthptr;
}
else if(t->bound == -100)
yyerror("use of [...] array outside of array literal");
@@ -252,7 +250,9 @@ dowidth(Type *t)
fatal("dowidth fn struct %T", t);
w = widstruct(t, 0, 1);
if(w == 0)
- w = maxround;
+ w = 1;
+ //if(t->align < widthptr)
+ // warn("align %d: %T\n", t->align, t);
break;
case TFUNC:
@@ -271,16 +271,24 @@ dowidth(Type *t)
// compute their widths as side-effect.
t1 = t->type;
w = widstruct(*getthis(t1), 0, 0);
- w = widstruct(*getinarg(t1), w, 1);
- w = widstruct(*getoutarg(t1), w, 1);
+ w = widstruct(*getinarg(t1), w, widthptr);
+ w = widstruct(*getoutarg(t1), w, widthptr);
t1->argwid = w;
+ if(w%widthptr)
+ warn("bad type %T %d\n", t1, w);
+ t->align = 1;
break;
}
// catch all for error cases; avoid divide by zero later
if(w == 0)
- w = maxround;
+ w = 1;
t->width = w;
+ if(t->align == 0) {
+ if(w > 8 || (w&(w-1)) != 0)
+ fatal("invalid alignment for %T", t);
+ t->align = w;
+ }
lineno = lno;
if(defercalc == 1)
@@ -351,8 +359,8 @@ void
defercheckwidth(void)
{
// we get out of sync on syntax errors, so don't be pedantic.
- // if(defercalc)
- // fatal("defercheckwidth");
+ if(defercalc && nerrors == 0)
+ fatal("defercheckwidth");
defercalc = 1;
}
@@ -596,10 +604,10 @@ typeinit(void)
Array_array = rnd(0, widthptr);
Array_nel = rnd(Array_array+widthptr, types[TUINT32]->width);
Array_cap = rnd(Array_nel+types[TUINT32]->width, types[TUINT32]->width);
- sizeof_Array = rnd(Array_cap+types[TUINT32]->width, maxround);
+ sizeof_Array = rnd(Array_cap+types[TUINT32]->width, widthptr);
// string is same as slice wo the cap
- sizeof_String = rnd(Array_nel+types[TUINT32]->width, maxround);
+ sizeof_String = rnd(Array_nel+types[TUINT32]->width, widthptr);
dowidth(types[TSTRING]);
dowidth(idealstring);
diff --git a/src/cmd/gc/builtin.c.boot b/src/cmd/gc/builtin.c.boot
index 3e2d98872..380abc642 100644
--- a/src/cmd/gc/builtin.c.boot
+++ b/src/cmd/gc/builtin.c.boot
@@ -1,6 +1,6 @@
char *runtimeimport =
"package runtime\n"
- "func \"\".mal (? int32) *any\n"
+ "func \"\".new (? int32) *any\n"
"func \"\".panicindex ()\n"
"func \"\".panicslice ()\n"
"func \"\".throwreturn ()\n"
@@ -19,12 +19,13 @@ char *runtimeimport =
"func \"\".printslice (? any)\n"
"func \"\".printnl ()\n"
"func \"\".printsp ()\n"
- "func \"\".printf ()\n"
- "func \"\".catstring (? string, ? string) string\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 \"\".indexstring (? string, ? int) uint8\n"
"func \"\".intstring (? int64) string\n"
"func \"\".slicebytetostring (? []uint8) string\n"
"func \"\".sliceinttostring (? []int) string\n"
@@ -33,6 +34,7 @@ char *runtimeimport =
"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"
@@ -75,16 +77,18 @@ char *runtimeimport =
"func \"\".selectdefault (sel *uint8) bool\n"
"func \"\".selectgo (sel *uint8)\n"
"func \"\".makeslice (typ *uint8, nel int64, cap int64) []any\n"
- "func \"\".sliceslice1 (old []any, lb int, width int) []any\n"
- "func \"\".sliceslice (old []any, lb int, hb int, width int) []any\n"
- "func \"\".slicearray (old *any, nel int, lb int, hb int, width int) []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";
diff --git a/src/cmd/gc/closure.c b/src/cmd/gc/closure.c
index a24a03a49..eb7014366 100644
--- a/src/cmd/gc/closure.c
+++ b/src/cmd/gc/closure.c
@@ -158,7 +158,7 @@ walkclosure(Node *func, NodeList **init)
// create the function
xfunc = nod(ODCLFUNC, N, N);
- snprint(namebuf, sizeof namebuf, "_func_%.3ld", ++closgen);
+ snprint(namebuf, sizeof namebuf, "_func_%.3d", ++closgen);
xfunc->nname = newname(lookup(namebuf));
xfunc->nname->ntype = xtype;
xfunc->nname->defn = xfunc;
diff --git a/src/cmd/gc/const.c b/src/cmd/gc/const.c
index cec95359a..72e67a634 100644
--- a/src/cmd/gc/const.c
+++ b/src/cmd/gc/const.c
@@ -101,7 +101,7 @@ convlit1(Node **np, Type *t, int explicit)
break;
case OLSH:
case ORSH:
- convlit1(&n->left, t, explicit);
+ convlit1(&n->left, t, explicit && isideal(n->left->type));
t = n->left->type;
if(t != T && !isint[t->etype]) {
yyerror("invalid operation: %#N (shift of type %T)", n, t);
@@ -202,8 +202,6 @@ convlit1(Node **np, Type *t, int explicit)
goto bad;
case CTFLT:
case CTINT:
- if(explicit)
- goto bad;
n->val = tocplx(n->val);
break;
case CTCPLX:
@@ -300,7 +298,7 @@ toflt(Val v)
f = mal(sizeof(*f));
mpmovefltflt(f, &v.u.cval->real);
if(mpcmpfltc(&v.u.cval->imag, 0) != 0)
- yyerror("constant %#F truncated to real", v.u.fval);
+ yyerror("constant %#F%+#Fi truncated to real", &v.u.cval->real, &v.u.cval->imag);
v.ctype = CTFLT;
v.u.fval = f;
break;
@@ -324,9 +322,9 @@ toint(Val v)
case CTCPLX:
i = mal(sizeof(*i));
if(mpmovefltfix(i, &v.u.cval->real) < 0)
- yyerror("constant %#F truncated to integer", v.u.fval);
+ yyerror("constant %#F%+#Fi truncated to integer", &v.u.cval->real, &v.u.cval->imag);
if(mpcmpfltc(&v.u.cval->imag, 0) != 0)
- yyerror("constant %#F truncated to real", v.u.fval);
+ yyerror("constant %#F%+#Fi truncated to real", &v.u.cval->real, &v.u.cval->imag);
v.ctype = CTINT;
v.u.xval = i;
break;
@@ -536,6 +534,12 @@ evconst(Node *n)
v = toflt(v);
rv = toflt(rv);
}
+ if(v.ctype != rv.ctype) {
+ // Use of undefined name as constant?
+ if((v.ctype == 0 || rv.ctype == 0) && nerrors > 0)
+ return;
+ fatal("constant type mismatch %T(%d) %T(%d)", nl->type, v.ctype, nr->type, rv.ctype);
+ }
// run op
switch(TUP(n->op, v.ctype)) {
@@ -1086,6 +1090,12 @@ smallintconst(Node *n)
case TBOOL:
case TPTR32:
return 1;
+ case TINT64:
+ case TUINT64:
+ if(mpcmpfixfix(n->val.u.xval, minintval[TINT32]) < 0
+ || mpcmpfixfix(n->val.u.xval, maxintval[TINT32]) > 0)
+ break;
+ return 1;
}
return 0;
}
diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c
index adb1531c3..a71272aa2 100644
--- a/src/cmd/gc/dcl.c
+++ b/src/cmd/gc/dcl.c
@@ -729,8 +729,11 @@ stotype(NodeList *l, int et, Type **t)
n->right = N;
if(n->embedded && n->type != T) {
t1 = n->type;
- if(t1->sym == S && isptr[t1->etype])
+ 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)
@@ -841,6 +844,8 @@ dostruct(NodeList *l, int et)
t->broke = 1;
return t;
}
+ if(et == TINTER)
+ t = sortinter(t);
if(!funarg)
checkwidth(t);
return t;
@@ -1017,11 +1022,12 @@ functype(Node *this, NodeList *in, NodeList *out)
}
Sym*
-methodsym(Sym *nsym, Type *t0)
+methodsym(Sym *nsym, Type *t0, int iface)
{
Sym *s;
char *p;
Type *t;
+ char *suffix;
t = t0;
if(t == T)
@@ -1043,7 +1049,13 @@ methodsym(Sym *nsym, Type *t0)
if(t != t0 && t0->sym)
t0 = ptrto(t);
- p = smprint("%#hT·%s", t0, nsym->name);
+ suffix = "";
+ if(iface) {
+ dowidth(t0);
+ if(t0->width < types[tptr]->width)
+ suffix = "·i";
+ }
+ p = smprint("%#hT·%s%s", t0, nsym->name, suffix);
s = pkglookup(p, s->pkg);
free(p);
return s;
@@ -1058,7 +1070,7 @@ methodname(Node *n, Type *t)
{
Sym *s;
- s = methodsym(n->sym, t);
+ s = methodsym(n->sym, t, 0);
if(s == S)
return n;
return newname(s);
diff --git a/src/cmd/gc/doc.go b/src/cmd/gc/doc.go
index 108a091b2..21e1b103b 100644
--- a/src/cmd/gc/doc.go
+++ b/src/cmd/gc/doc.go
@@ -25,13 +25,18 @@ other packages. It is therefore not necessary when compiling client C of
package P to read the files of P's dependencies, only the compiled output
of P.
-Usage: 6g [flags] *.go (or 8g or 5g)
+Usage:
+ 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.
Flags:
-o file
- output file, default 6.out for 6g, etc.
+ output file, default file.6 for 6g, etc.
-e
normally the compiler quits after 10 errors; -e prints all errors
+ -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
diff --git a/src/cmd/gc/export.c b/src/cmd/gc/export.c
index 52853c454..594509915 100644
--- a/src/cmd/gc/export.c
+++ b/src/cmd/gc/export.c
@@ -176,7 +176,8 @@ dumpexporttype(Sym *s)
yyerror("export of incomplete type %T", t);
return;
}
- Bprint(bout, "type %#T %l#T\n", t, t);
+ if(Bprint(bout, "type %#T %l#T\n", t, t) < 0)
+ fatal("Bprint failed for %T", t);
}
static int
diff --git a/src/cmd/gc/gen.c b/src/cmd/gc/gen.c
index fd8a7f39b..04af5a7bb 100644
--- a/src/cmd/gc/gen.c
+++ b/src/cmd/gc/gen.c
@@ -58,7 +58,7 @@ allocparams(void)
if(w >= MAXWIDTH)
fatal("bad width");
stksize += w;
- stksize = rnd(stksize, w);
+ stksize = rnd(stksize, n->type->align);
n->xoffset = -stksize;
}
lineno = lno;
@@ -139,8 +139,10 @@ gen(Node *n)
Prog *scontin, *sbreak;
Prog *p1, *p2, *p3;
Label *lab;
+ int32 wasregalloc;
lno = setlineno(n);
+ wasregalloc = anyregalloc();
if(n == N)
goto ret;
@@ -246,9 +248,6 @@ gen(Node *n)
gen(n->nincr); // contin: incr
patch(p1, pc); // test:
- if(n->ntest != N)
- if(n->ntest->ninit != nil)
- genlist(n->ntest->ninit);
bgen(n->ntest, 0, breakpc); // if(!test) goto break
genlist(n->nbody); // body
gjmp(continpc);
@@ -261,9 +260,6 @@ gen(Node *n)
p1 = gjmp(P); // goto test
p2 = gjmp(P); // p2: goto else
patch(p1, pc); // test:
- if(n->ntest != N)
- if(n->ntest->ninit != nil)
- genlist(n->ntest->ninit);
bgen(n->ntest, 0, p2); // if(!test) goto p2
genlist(n->nbody); // then
p3 = gjmp(P); // goto done
@@ -342,6 +338,11 @@ gen(Node *n)
}
ret:
+ if(anyregalloc() != wasregalloc) {
+ dump("node", n);
+ fatal("registers left allocated");
+ }
+
lineno = lno;
}
@@ -432,7 +433,7 @@ cgen_discard(Node *nr)
switch(nr->op) {
case ONAME:
- if(!(nr->class & PHEAP) && nr->class != PEXTERN && nr->class != PFUNC)
+ if(!(nr->class & PHEAP) && nr->class != PEXTERN && nr->class != PFUNC && nr->class != PPARAMREF)
gused(nr);
break;
@@ -651,7 +652,6 @@ tempname(Node *n, Type *t)
snprint(namebuf, sizeof(namebuf), "autotmp_%.4d", statuniqgen);
statuniqgen++;
s = lookup(namebuf);
-
memset(n, 0, sizeof(*n));
n->op = ONAME;
n->sym = s;
@@ -664,7 +664,7 @@ tempname(Node *n, Type *t)
dowidth(t);
w = t->width;
stksize += w;
- stksize = rnd(stksize, w);
+ stksize = rnd(stksize, t->align);
n->xoffset = -stksize;
n->pun = anyregalloc();
}
diff --git a/src/cmd/gc/go.errors b/src/cmd/gc/go.errors
index cdd7578d4..b5af4678c 100644
--- a/src/cmd/gc/go.errors
+++ b/src/cmd/gc/go.errors
@@ -35,6 +35,15 @@ static struct {
% loadsys package imports LTYPE LNAME ';'
"unexpected semicolon or newline in type declaration",
+ % loadsys package imports LCHAN '}'
+ "unexpected } in channel type",
+
+ % loadsys package imports LCHAN ')'
+ "unexpected ) in channel type",
+
+ % loadsys package imports LCHAN ','
+ "unexpected comma in channel type",
+
% loadsys package imports LFUNC LNAME '(' ')' '{' if_stmt ';' LELSE
"unexpected semicolon or newline before else",
diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h
index 99e369eca..73ea5b976 100644
--- a/src/cmd/gc/go.h
+++ b/src/cmd/gc/go.h
@@ -6,6 +6,8 @@
#include <libc.h>
#include <bio.h>
+#undef OAPPEND
+
// avoid <ctype.h>
#undef isblank
#define isblank goisblank
@@ -38,9 +40,10 @@ enum
ASTRING,
AINTER,
ANILINTER,
+ AMEMWORD,
BADWIDTH = -1000000000,
- MAXWIDTH = 1<<30
+ MAXWIDTH = 1<<30
};
/*
@@ -151,6 +154,7 @@ struct Type
uchar deferwidth;
uchar broke;
uchar isddd; // TFIELD is ... argument
+ uchar align;
Node* nod; // canonical OTYPE node
Type* orig; // original type (type literal or predefined type)
@@ -209,12 +213,15 @@ struct Node
uchar dodata; // compile literal assignment as data statement
uchar used;
uchar isddd;
- uchar pun; // dont registerize variable ONAME
+ uchar pun; // don't registerize variable ONAME
+ uchar readonly;
+ uchar implicit; // don't show in printout
// most nodes
Node* left;
Node* right;
Type* type;
+ Type* realtype; // as determined by typecheck
NodeList* list;
NodeList* rlist;
@@ -261,6 +268,7 @@ struct Node
Sym* sym; // various
int32 vargen; // unique name for OTYPE/ONAME
int32 lineno;
+ int32 endlineno;
vlong xoffset;
int32 ostk;
int32 iota;
@@ -344,6 +352,7 @@ enum
OADD, OSUB, OOR, OXOR, OADDSTR,
OADDR,
OANDAND,
+ OAPPEND,
OARRAY,
OARRAYBYTESTR, OARRAYRUNESTR,
OSTRARRAYBYTE, OSTRARRAYRUNE,
@@ -356,7 +365,7 @@ enum
OCLOSURE,
OCMPIFACE, OCMPSTR,
OCOMPLIT, OMAPLIT, OSTRUCTLIT, OARRAYLIT,
- OCONV, OCONVIFACE, OCONVNOP, OCONVSLICE,
+ OCONV, OCONVIFACE, OCONVNOP,
OCOPY,
ODCL, ODCLFUNC, ODCLFIELD, ODCLCONST, ODCLTYPE,
ODOT, ODOTPTR, ODOTMETH, ODOTINTER, OXDOT,
@@ -364,7 +373,7 @@ enum
ODOTTYPE2,
OEQ, ONE, OLT, OLE, OGE, OGT,
OIND,
- OINDEX, OINDEXSTR, OINDEXMAP,
+ OINDEX, OINDEXMAP,
OKEY, OPARAM,
OLEN,
OMAKE, OMAKECHAN, OMAKEMAP, OMAKESLICE,
@@ -400,7 +409,6 @@ enum
ORETURN,
OSELECT,
OSWITCH,
- OTYPECASE,
OTYPESW, // l = r.(type)
// types
@@ -410,6 +418,7 @@ enum
OTINTER,
OTFUNC,
OTARRAY,
+ OTPAREN,
// misc
ODDD,
@@ -632,9 +641,9 @@ EXTERN Label* labellist;
*
* typedef struct
* { // must not move anything
- * uchar array[8]; // pointer to data
- * uchar nel[4]; // number of elements
- * uchar cap[4]; // allocated number of elements
+ * uchar array[8]; // pointer to data
+ * uchar nel[4]; // number of elements
+ * uchar cap[4]; // allocated number of elements
* } Array;
*/
EXTERN int Array_array; // runtime offsetof(Array,array) - same for String
@@ -649,8 +658,8 @@ EXTERN int sizeof_Array; // runtime sizeof(Array)
*
* typedef struct
* { // must not move anything
- * uchar array[8]; // pointer to data
- * uchar nel[4]; // number of elements
+ * uchar array[8]; // pointer to data
+ * uchar nel[4]; // number of elements
* } String;
*/
EXTERN int sizeof_String; // runtime sizeof(String)
@@ -743,7 +752,6 @@ EXTERN int hasdefer; // flag that curfn has defer statetment
EXTERN Node* curfn;
-EXTERN int maxround;
EXTERN int widthptr;
EXTERN Node* typesw;
@@ -858,7 +866,7 @@ int isifacemethod(Type *f);
void markdcl(void);
Node* methodname(Node *n, Type *t);
Node* methodname1(Node *n, Node *t);
-Sym* methodsym(Sym *nsym, Type *t0);
+Sym* methodsym(Sym *nsym, Type *t0, int iface);
Node* newname(Sym *s);
Type* newtype(Sym *s);
Node* oldname(Sym *s);
@@ -914,6 +922,9 @@ char* lexname(int lex);
void mkpackage(char* pkgname);
void unimportfile(void);
int32 yylex(void);
+extern int windows;
+extern int yylast;
+extern int yyprev;
/*
* mparith1.c
@@ -1003,7 +1014,7 @@ void walkrange(Node *n);
* reflect.c
*/
void dumptypestructs(void);
-Type* methodfunc(Type *f, int use_receiver);
+Type* methodfunc(Type *f, Type*);
Node* typename(Type *t);
Sym* typesym(Type *t);
@@ -1016,7 +1027,7 @@ void walkselect(Node *sel);
/*
* sinit.c
*/
-void anylit(int ctxt, Node *n, Node *var, NodeList **init);
+void anylit(int, Node *n, Node *var, NodeList **init);
int gen_as_init(Node *n);
NodeList* initfix(NodeList *l);
int oaslit(Node *n, NodeList **init);
@@ -1059,7 +1070,7 @@ 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);
+void genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface);
Type** getinarg(Type *t);
Type* getinargx(Type *t);
Type** getoutarg(Type *t);
@@ -1095,6 +1106,7 @@ Node* nod(int op, Node *nleft, Node *nright);
Node* nodbool(int b);
void nodconst(Node *n, Type *t, int64 v);
Node* nodintconst(int64 v);
+Node* nodfltconst(Mpflt *v);
Node* nodnil(void);
int parserline(void);
Sym* pkglookup(char *name, Pkg *pkg);
@@ -1103,13 +1115,13 @@ Type* ptrto(Type *t);
void* remal(void *p, int32 on, int32 n);
Sym* restrictlookup(char *name, Pkg *pkg);
Node* safeexpr(Node *n, NodeList **init);
+Node* cheapexpr(Node *n, NodeList **init);
int32 setlineno(Node *n);
void setmaxarg(Type *t);
Type* shallow(Type *t);
int simsimtype(Type *t);
void smagic(Magic *m);
Type* sortinter(Type *t);
-Node* staticname(Type *t);
uint32 stringhash(char *p);
Strlit* strlit(char *s);
int structcount(Type *t);
@@ -1143,7 +1155,7 @@ void typechecklist(NodeList *l, int top);
/*
* unsafe.c
*/
-Node* unsafenmagic(Node *fn, NodeList *args);
+Node* unsafenmagic(Node *n);
/*
* walk.c
@@ -1206,7 +1218,7 @@ void dumpfuncs(void);
void gdata(Node*, Node*, int);
void gdatacomplex(Node*, Mpcplx*);
void gdatastring(Node*, Strlit*);
-void genembedtramp(Type*, Type*, Sym*);
+void genembedtramp(Type*, Type*, Sym*, int iface);
void ggloblnod(Node *nam, int32 width);
void ggloblsym(Sym *s, int32 width, int dupok);
Prog* gjmp(Prog*);
diff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y
index c46abaa56..917265758 100644
--- a/src/cmd/gc/go.y
+++ b/src/cmd/gc/go.y
@@ -20,6 +20,8 @@
%{
#include <stdio.h> /* if we don't, bison will, and go.h re-#defines getc */
#include "go.h"
+
+static void fixlbrace(int);
%}
%union {
Node* node;
@@ -50,7 +52,7 @@
%type <node> stmt ntype
%type <node> arg_type
%type <node> case caseblock
-%type <node> compound_stmt dotname embed expr
+%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
@@ -58,7 +60,7 @@
%type <node> name_or_type non_expr_type
%type <node> new_name dcl_name oexpr typedclname
%type <node> onew_name
-%type <node> osimple_stmt pexpr
+%type <node> osimple_stmt pexpr pexpr_no_paren
%type <node> pseudocall range_stmt select_stmt
%type <node> simple_stmt
%type <node> switch_stmt uexpr
@@ -66,7 +68,7 @@
%type <list> xdcl fnbody fnres switch_body loop_body dcl_name_list
%type <list> new_name_list expr_list keyval_list braced_keyval_list expr_or_type_list xdcl_list
-%type <list> oexpr_list oexpr_or_type_list_ocomma caseblock_list stmt_list oarg_type_list_ocomma arg_type_list
+%type <list> oexpr_list caseblock_list stmt_list oarg_type_list_ocomma arg_type_list
%type <list> interfacedcl_list vardcl vardcl_list structdcl structdcl_list
%type <list> common_dcl constdcl constdcl1 constdcl_list typedcl_list
@@ -459,7 +461,7 @@ case:
}
break;
}
-| LCASE name '=' expr ':'
+| LCASE expr '=' expr ':'
{
// will be converted to OCASE
// right will point to next case
@@ -515,10 +517,33 @@ switch_body:
}
caseblock:
- case stmt_list
+ case
+ {
+ // 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;
+ }
+ stmt_list
{
+ 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");
$$ = $1;
- $$->nbody = $2;
+ $$->nbody = $3;
}
caseblock_list:
@@ -648,11 +673,13 @@ select_stmt:
LSELECT
{
markdcl();
+ typesw = nod(OXXX, typesw, N);
}
switch_body
{
$$ = nod(OSELECT, N, N);
$$->list = $3;
+ typesw = typesw->left;
popdcl();
}
@@ -783,13 +810,23 @@ uexpr:
* can be preceded by 'defer' and 'go'
*/
pseudocall:
- pexpr '(' oexpr_or_type_list_ocomma ')'
+ pexpr '(' ')'
+ {
+ $$ = nod(OCALL, $1, N);
+ }
+| pexpr '(' expr_or_type_list ocomma ')'
{
$$ = nod(OCALL, $1, N);
$$->list = $3;
}
+| pexpr '(' expr_or_type_list LDDD ocomma ')'
+ {
+ $$ = nod(OCALL, $1, N);
+ $$->list = $3;
+ $$->isddd = 1;
+ }
-pexpr:
+pexpr_no_paren:
LLITERAL
{
$$ = nodlit($1);
@@ -806,10 +843,6 @@ pexpr:
}
$$ = nod(OXDOT, $1, newname($3));
}
-| '(' expr_or_type ')'
- {
- $$ = $2;
- }
| pexpr '.' '(' expr_or_type ')'
{
$$ = nod(ODOTTYPE, $1, $4);
@@ -824,10 +857,6 @@ pexpr:
}
| pexpr '[' oexpr ':' oexpr ']'
{
- if($3 == N) {
- yyerror("missing lower bound in slice expression");
- $3 = nodintconst(0);
- }
$$ = nod(OSLICE, $1, nod(OKEY, $3, $5));
}
| pseudocall
@@ -842,21 +871,45 @@ pexpr:
// composite expression
$$ = nod(OCOMPLIT, N, $1);
$$->list = $3;
-
- // 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($2 == LBODY)
- loophack = 1;
+
+ fixlbrace($2);
}
-| pexpr '{' braced_keyval_list '}'
+| pexpr_no_paren '{' braced_keyval_list '}'
{
// composite expression
$$ = nod(OCOMPLIT, N, $1);
$$->list = $3;
}
+| '(' expr_or_type ')' '{' braced_keyval_list '}'
+ {
+ yyerror("cannot parenthesize type in composite literal");
+ // composite expression
+ $$ = nod(OCOMPLIT, N, $2);
+ $$->list = $5;
+ }
| fnliteral
+keyval:
+ expr ':' complitexpr
+ {
+ $$ = nod(OKEY, $1, $3);
+ }
+
+complitexpr:
+ expr
+| '{' braced_keyval_list '}'
+ {
+ $$ = nod(OCOMPLIT, N, N);
+ $$->list = $2;
+ }
+
+pexpr:
+ pexpr_no_paren
+| '(' expr_or_type ')'
+ {
+ $$ = $2;
+ }
+
expr_or_type:
expr
| non_expr_type %prec PreferToRightParen
@@ -939,7 +992,7 @@ ntype:
| dotname
| '(' ntype ')'
{
- $$ = $2;
+ $$ = nod(OTPAREN, $2, N);
}
non_expr_type:
@@ -958,7 +1011,7 @@ non_recvchantype:
| dotname
| '(' ntype ')'
{
- $$ = $2;
+ $$ = nod(OTPAREN, $2, N);
}
convtype:
@@ -1030,34 +1083,31 @@ recvchantype:
}
structtype:
- LSTRUCT '{' structdcl_list osemi '}'
+ LSTRUCT lbrace structdcl_list osemi '}'
{
$$ = nod(OTSTRUCT, N, N);
$$->list = $3;
+ fixlbrace($2);
}
-| LSTRUCT '{' '}'
+| LSTRUCT lbrace '}'
{
$$ = nod(OTSTRUCT, N, N);
+ fixlbrace($2);
}
interfacetype:
- LINTERFACE '{' interfacedcl_list osemi '}'
+ LINTERFACE lbrace interfacedcl_list osemi '}'
{
$$ = nod(OTINTER, N, N);
$$->list = $3;
+ fixlbrace($2);
}
-| LINTERFACE '{' '}'
+| LINTERFACE lbrace '}'
{
$$ = nod(OTINTER, N, N);
+ fixlbrace($2);
}
-keyval:
- expr ':' expr
- {
- $$ = nod(OKEY, $1, $3);
- }
-
-
/*
* function stuff
* all in one place to show how crappy it all is
@@ -1069,6 +1119,7 @@ xfndcl:
if($$ == N)
break;
$$->nbody = $3;
+ $$->endlineno = lineno;
funcbody($$);
}
@@ -1118,6 +1169,8 @@ fndcl:
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");
$$ = nod(ODCLFUNC, N, N);
$$->nname = methodname1(name, rcvr->right);
@@ -1250,12 +1303,32 @@ structdcl:
$1->val = $2;
$$ = list1($1);
}
+| '(' embed ')' oliteral
+ {
+ $2->val = $4;
+ $$ = list1($2);
+ yyerror("cannot parenthesize embedded type");
+ }
| '*' embed oliteral
{
$2->right = nod(OIND, $2->right, N);
$2->val = $3;
$$ = list1($2);
}
+| '(' '*' embed ')' oliteral
+ {
+ $3->right = nod(OIND, $3->right, N);
+ $3->val = $5;
+ $$ = list1($3);
+ yyerror("cannot parenthesize embedded type");
+ }
+| '*' '(' embed ')' oliteral
+ {
+ $3->right = nod(OIND, $3->right, N);
+ $3->val = $5;
+ $$ = list1($3);
+ yyerror("cannot parenthesize embedded type");
+ }
packname:
LNAME
@@ -1296,6 +1369,11 @@ interfacedcl:
{
$$ = nod(ODCLFIELD, N, oldname($1));
}
+| '(' packname ')'
+ {
+ $$ = nod(ODCLFIELD, N, oldname($2));
+ yyerror("cannot parenthesize embedded type");
+ }
indcl:
'(' oarg_type_list_ocomma ')' fnres
@@ -1481,7 +1559,7 @@ keyval_list:
{
$$ = list1($1);
}
-| expr
+| complitexpr
{
$$ = list1($1);
}
@@ -1489,7 +1567,7 @@ keyval_list:
{
$$ = list($1, $3);
}
-| keyval_list ',' expr
+| keyval_list ',' complitexpr
{
$$ = list($1, $3);
}
@@ -1524,12 +1602,6 @@ oexpr_list:
}
| expr_list
-oexpr_or_type_list_ocomma:
- {
- $$ = nil;
- }
-| expr_or_type_list ocomma
-
osimple_stmt:
{
$$ = N;
@@ -1654,7 +1726,6 @@ hidden_type_misc:
| LINTERFACE '{' ohidden_interfacedcl_list '}'
{
$$ = dostruct($3, TINTER);
- $$ = sortinter($$);
}
| '*' hidden_type
{
@@ -1867,3 +1938,16 @@ hidden_interfacedcl_list:
{
$$ = list($1, $3);
}
+
+%%
+
+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/lex.c b/src/cmd/gc/lex.c
index 452acfc76..0f1acd2fc 100644
--- a/src/cmd/gc/lex.c
+++ b/src/cmd/gc/lex.c
@@ -14,6 +14,8 @@
extern int yychar;
int windows;
+int yyprev;
+int yylast;
static void lexinit(void);
static void lexfini(void);
@@ -23,9 +25,45 @@ static void ungetc(int);
static int32 getr(void);
static int escchar(int, int*, vlong*);
static void addidir(char*);
-
+static int getlinepragma(void);
static char *goos, *goarch, *goroot;
+// Our own isdigit, isspace, isalpha, isalnum that take care
+// of EOF and other out of range arguments.
+static int
+yy_isdigit(int c)
+{
+ return c >= 0 && c <= 0xFF && isdigit(c);
+}
+
+static int
+yy_isspace(int c)
+{
+ return c >= 0 && c <= 0xFF && isspace(c);
+}
+
+static int
+yy_isalpha(int c)
+{
+ return c >= 0 && c <= 0xFF && isalpha(c);
+}
+
+static int
+yy_isalnum(int c)
+{
+ return c >= 0 && c <= 0xFF && isalnum(c);
+}
+
+// Disallow use of isdigit etc.
+#undef isdigit
+#undef isspace
+#undef isalpha
+#undef isalnum
+#define isdigit use_yy_isdigit_instead_of_isdigit
+#define isspace use_yy_isspace_instead_of_isspace
+#define isalpha use_yy_isalpha_instead_of_isalpha
+#define isalnum use_yy_isalnum_instead_of_isalnum
+
#define DBG if(!debug['x']);else print
enum
{
@@ -35,7 +73,7 @@ enum
void
usage(void)
{
- print("usage: %cg [flags] file.go...\n");
+ print("gc: usage: %cg [flags] file.go...\n", thechar);
print("flags:\n");
// -A is allow use of "any" type, for bootstrapping
print(" -I DIR search for packages in DIR\n");
@@ -52,12 +90,27 @@ usage(void)
exit(0);
}
+void
+fault(int 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
+ // the code and try again.
+ if(nerrors > 0)
+ errorexit();
+ fatal("fault");
+}
+
int
main(int argc, char *argv[])
{
int i, c;
NodeList *l;
char *p;
+
+ signal(SIGBUS, fault);
+ signal(SIGSEGV, fault);
localpkg = mkpkg(strlit(""));
localpkg->prefix = "\"\"";
@@ -119,7 +172,7 @@ main(int argc, char *argv[])
if(getwd(pathname, 999) == 0)
strcpy(pathname, "/???");
- if(isalpha(pathname[0]) && pathname[1] == ':') {
+ if(yy_isalpha(pathname[0]) && pathname[1] == ':') {
// On Windows.
windows = 1;
@@ -141,7 +194,7 @@ main(int argc, char *argv[])
fmtinstall('F', Fconv); // big float numbers
betypeinit();
- if(maxround == 0 || widthptr == 0)
+ if(widthptr == 0)
fatal("betypeinit failed");
lexinit();
@@ -287,7 +340,7 @@ islocalname(Strlit *name)
if(!windows && name->len >= 1 && name->s[0] == '/')
return 1;
if(windows && name->len >= 3 &&
- isalpha(name->s[0]) && name->s[1] == ':' && name->s[2] == '/')
+ yy_isalpha(name->s[0]) && name->s[1] == ':' && name->s[2] == '/')
return 1;
if(name->len >= 2 && strncmp(name->s, "./", 2) == 0)
return 1;
@@ -300,8 +353,11 @@ static int
findpkg(Strlit *name)
{
Idir *p;
+ char *q;
if(islocalname(name)) {
+ if(safemode)
+ return 0;
// try .a before .6. important for building libraries:
// if there is an array.6 in the array.a library,
// want to find all of array.a, not just array.6.
@@ -314,6 +370,18 @@ findpkg(Strlit *name)
return 0;
}
+ // local imports should be canonicalized already.
+ // don't want to see "container/../container/vector"
+ // as different from "container/vector".
+ q = mal(name->len+1);
+ memmove(q, name->s, name->len);
+ q[name->len] = '\0';
+ cleanname(q);
+ if(strlen(q) != name->len || memcmp(q, name->s, name->len) != 0) {
+ yyerror("non-canonical import path %Z (should be %s)", name, q);
+ return 0;
+ }
+
for(p = idirs; p != nil; p = p->link) {
snprint(namebuf, sizeof(namebuf), "%s/%Z.a", p->dir, name);
if(access(namebuf, 0) >= 0)
@@ -368,7 +436,9 @@ importfile(Val *f, int line)
path = f->u.sval;
if(islocalname(path)) {
cleanbuf = mal(strlen(pathname) + strlen(path->s) + 2);
- sprint(cleanbuf, "%s/%s", pathname, path->s);
+ strcpy(cleanbuf, pathname);
+ strcat(cleanbuf, "/");
+ strcat(cleanbuf, path->s);
cleanname(cleanbuf);
path = strlit(cleanbuf);
}
@@ -381,7 +451,7 @@ importfile(Val *f, int line)
imp = Bopen(namebuf, OREAD);
if(imp == nil) {
- yyerror("can't open import: %Z", f->u.sval);
+ yyerror("can't open import: %Z: %r", f->u.sval);
errorexit();
}
file = strdup(namebuf);
@@ -470,7 +540,7 @@ isfrog(int c)
return 0;
return 1;
}
- if(0x80 <= c && c <= 0xa0) // unicode block including unbreakable space.
+ if(0x7f <= c && c <= 0xa0) // DEL, unicode block including unbreakable space.
return 1;
return 0;
}
@@ -496,7 +566,7 @@ _yylex(void)
l0:
c = getc();
- if(isspace(c)) {
+ if(yy_isspace(c)) {
if(c == '\n' && curio.nlsemi) {
ungetc(c);
DBG("lex: implicit semi\n");
@@ -514,13 +584,13 @@ l0:
goto talph;
}
- if(isalpha(c)) {
+ if(yy_isalpha(c)) {
cp = lexbuf;
ep = lexbuf+sizeof lexbuf;
goto talph;
}
- if(isdigit(c))
+ if(yy_isdigit(c))
goto tnum;
switch(c) {
@@ -536,7 +606,7 @@ l0:
case '.':
c1 = getc();
- if(isdigit(c1)) {
+ if(yy_isdigit(c1)) {
cp = lexbuf;
ep = lexbuf+sizeof lexbuf;
*cp++ = c;
@@ -656,16 +726,13 @@ l0:
}
}
if(c1 == '/') {
+ c = getlinepragma();
for(;;) {
- c = getr();
- if(c == '\n') {
+ if(c == '\n' || c == EOF) {
ungetc(c);
goto l0;
}
- if(c == EOF) {
- yyerror("eof in comment");
- errorexit();
- }
+ c = getr();
}
}
if(c1 == '=') {
@@ -878,6 +945,10 @@ lx:
yyerror("illegal character 0x%ux", c);
goto l0;
}
+ if(importpkg == nil && (c == '#' || c == '$' || c == '?' || c == '@' || c == '\\')) {
+ yyerror("%s: unexpected %c", "syntax error", c);
+ goto l0;
+ }
return c;
asop:
@@ -902,7 +973,7 @@ talph:
if(!isalpharune(rune) && !isdigitrune(rune) && (importpkg == nil || rune != 0xb7))
yyerror("invalid identifier character 0x%ux", rune);
cp += runetochar(cp, &rune);
- } else if(!isalnum(c) && c != '_')
+ } else if(!yy_isalnum(c) && c != '_')
break;
else
*cp++ = c;
@@ -940,7 +1011,7 @@ tnum:
}
*cp++ = c;
c = getc();
- if(isdigit(c))
+ if(yy_isdigit(c))
continue;
goto dc;
}
@@ -955,7 +1026,7 @@ tnum:
}
*cp++ = c;
c = getc();
- if(isdigit(c))
+ if(yy_isdigit(c))
continue;
if(c >= 'a' && c <= 'f')
continue;
@@ -976,7 +1047,7 @@ tnum:
yyerror("identifier too long");
errorexit();
}
- if(!isdigit(c))
+ if(!yy_isdigit(c))
break;
if(c < '0' || c > '7')
c1 = 1; // not octal
@@ -1025,7 +1096,7 @@ casedot:
}
*cp++ = c;
c = getc();
- if(!isdigit(c))
+ if(!yy_isdigit(c))
break;
}
if(c == 'i')
@@ -1040,9 +1111,9 @@ casee:
*cp++ = c;
c = getc();
}
- if(!isdigit(c))
+ if(!yy_isdigit(c))
yyerror("malformed fp constant exponent");
- while(isdigit(c)) {
+ while(yy_isdigit(c)) {
if(cp+10 >= ep) {
yyerror("identifier too long");
errorexit();
@@ -1061,9 +1132,9 @@ casep:
*cp++ = c;
c = getc();
}
- if(!isdigit(c))
+ if(!yy_isdigit(c))
yyerror("malformed fp constant exponent");
- while(isdigit(c)) {
+ while(yy_isdigit(c)) {
if(cp+10 >= ep) {
yyerror("identifier too long");
errorexit();
@@ -1104,6 +1175,68 @@ caseout:
return LLITERAL;
}
+/*
+ * read and interpret syntax that looks like
+ * //line parse.y:15
+ * as a discontinuity in sequential line numbers.
+ * the next line of input comes from parse.y:15
+ */
+static int
+getlinepragma(void)
+{
+ int i, c, n;
+ char *cp, *ep;
+ Hist *h;
+
+ for(i=0; i<5; i++) {
+ c = getr();
+ if(c != "line "[i])
+ goto out;
+ }
+
+ cp = lexbuf;
+ ep = lexbuf+sizeof(lexbuf)-5;
+ for(;;) {
+ c = getr();
+ if(c == '\n' || c == EOF)
+ goto out;
+ if(c == ' ')
+ continue;
+ if(c == ':')
+ break;
+ if(cp < ep)
+ *cp++ = c;
+ }
+ *cp = 0;
+
+ n = 0;
+ for(;;) {
+ c = getr();
+ if(!yy_isdigit(c))
+ break;
+ n = n*10 + (c-'0');
+ if(n > 1e8) {
+ yyerror("line number out of range");
+ errorexit();
+ }
+ }
+
+ if(c != '\n' || n <= 0)
+ goto out;
+
+ // try to avoid allocating file name over and over
+ for(h=hist; h!=H; h=h->link) {
+ if(h->name != nil && strcmp(h->name, lexbuf) == 0) {
+ linehist(h->name, n, 0);
+ goto out;
+ }
+ }
+ linehist(strdup(lexbuf), n, 0);
+
+out:
+ return c;
+}
+
int32
yylex(void)
{
@@ -1112,13 +1245,8 @@ yylex(void)
lx = _yylex();
if(curio.nlsemi && lx == EOF) {
- // if the nlsemi bit is set, we'd be willing to
- // insert a ; if we saw a \n, but we didn't.
- // that means the final \n is missing.
- // complain here, because we can give a
- // good message. the syntax error we'd get
- // otherwise is inscrutable.
- yyerror("missing newline at end of file");
+ // Treat EOF as "end of line" for the purposes
+ // of inserting a semicolon.
lx = ';';
}
@@ -1140,7 +1268,11 @@ yylex(void)
curio.nlsemi = 0;
break;
}
- return lx;
+
+ // Track last two tokens returned by yylex.
+ yyprev = yylast;
+ yylast = lx;
+ return lx;
}
static int
@@ -1395,6 +1527,7 @@ static struct
"type", LTYPE, Txxx, OXXX,
"var", LVAR, Txxx, OXXX,
+ "append", LNAME, Txxx, OAPPEND,
"cap", LNAME, Txxx, OCAP,
"close", LNAME, Txxx, OCLOSE,
"closed", LNAME, Txxx, OCLOSED,
diff --git a/src/cmd/gc/mkbuiltin b/src/cmd/gc/mkbuiltin
index 13309ec32..4dfff1caa 100755
--- a/src/cmd/gc/mkbuiltin
+++ b/src/cmd/gc/mkbuiltin
@@ -10,11 +10,9 @@
set -e
-GOBIN="${GOBIN:-$HOME/bin}"
-
-. "$GOROOT"/src/Make.$GOARCH
+eval $(gomake --no-print-directory -f ../../Make.inc go-env)
if [ -z "$GC" ]; then
- echo 'missing $GC - maybe no Make.$GOARCH?' 1>&2
+ echo 'missing $GC - gomake failed?' 1>&2
exit 1
fi
@@ -22,7 +20,7 @@ gcc -o mkbuiltin1 mkbuiltin1.c
rm -f _builtin.c
for i in runtime unsafe
do
- "$GOBIN"/$GC -A $i.go
+ $GC -A $i.go
O=$O ./mkbuiltin1 $i >>_builtin.c
done
diff --git a/src/cmd/gc/mparith1.c b/src/cmd/gc/mparith1.c
index 8110e77b9..6cd4e2500 100644
--- a/src/cmd/gc/mparith1.c
+++ b/src/cmd/gc/mparith1.c
@@ -156,10 +156,11 @@ mpmovefixflt(Mpflt *a, Mpint *b)
// convert (truncate) b to a.
// return -1 (but still convert) if b was non-integer.
-int
-mpmovefltfix(Mpint *a, Mpflt *b)
+static int
+mpexactfltfix(Mpint *a, Mpflt *b)
{
Mpflt f;
+
*a = b->val;
mpshiftfix(a, b->exp);
if(b->exp < 0) {
@@ -172,6 +173,35 @@ mpmovefltfix(Mpint *a, Mpflt *b)
return 0;
}
+int
+mpmovefltfix(Mpint *a, Mpflt *b)
+{
+ Mpflt f;
+ int i;
+
+ if(mpexactfltfix(a, b) == 0)
+ return 0;
+
+ // try rounding down a little
+ f = *b;
+ f.val.a[0] = 0;
+ if(mpexactfltfix(a, &f) == 0)
+ return 0;
+
+ // try rounding up a little
+ for(i=1; i<Mpprec; i++) {
+ f.val.a[i]++;
+ if(f.val.a[i] != Mpbase)
+ break;
+ f.val.a[i] = 0;
+ }
+ mpnorm(&f);
+ if(mpexactfltfix(a, &f) == 0)
+ return 0;
+
+ return -1;
+}
+
void
mpmovefixfix(Mpint *a, Mpint *b)
{
@@ -188,6 +218,8 @@ static double tab[] = { 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7 };
static void
mppow10flt(Mpflt *a, int p)
{
+ if(p < 0)
+ abort();
if(p < nelem(tab)) {
mpmovecflt(a, tab[p]);
return;
@@ -267,6 +299,10 @@ mpatoflt(Mpflt *a, char *as)
}
if(c >= '0' && c <= '9') {
ex = ex*10 + (c-'0');
+ if(ex > 1e8) {
+ yyerror("exponent out of range");
+ errorexit();
+ }
continue;
}
break;
@@ -439,6 +475,8 @@ Fconv(Fmt *fp)
// for well in range, convert to double and use print's %g
if(-900 < fvp->exp && fvp->exp < 900) {
d = mpgetflt(fvp);
+ if(d >= 0 && (fp->flags & FmtSign))
+ fmtprint(fp, "+");
return fmtprint(fp, "%g", d);
}
// TODO(rsc): for well out of range, print
diff --git a/src/cmd/gc/mparith2.c b/src/cmd/gc/mparith2.c
index b025917fa..403255005 100644
--- a/src/cmd/gc/mparith2.c
+++ b/src/cmd/gc/mparith2.c
@@ -319,7 +319,11 @@ mpmulfract(Mpint *a, Mpint *b)
s.neg = 0;
mpmovecfix(&q, 0);
- for(i=0; i<Mpprec; i++) {
+ x = *--a1;
+ if(x != 0)
+ yyerror("mpmulfract not normal");
+
+ for(i=0; i<Mpprec-1; i++) {
x = *--a1;
if(x == 0) {
mprshw(&s);
@@ -532,7 +536,7 @@ mpgetfix(Mpint *a)
vlong v;
if(a->ovf) {
- yyerror("ovf in mpgetfix");
+ yyerror("constant overflow");
return 0;
}
diff --git a/src/cmd/gc/mparith3.c b/src/cmd/gc/mparith3.c
index b9cd4ea84..7b7e66668 100644
--- a/src/cmd/gc/mparith3.c
+++ b/src/cmd/gc/mparith3.c
@@ -27,16 +27,36 @@ sigfig(Mpflt *a)
void
mpnorm(Mpflt *a)
{
- int s;
+ int s, os;
+ long x;
- s = sigfig(a);
- if(s == 0) {
+ os = sigfig(a);
+ if(os == 0) {
// zero
a->exp = 0;
a->val.neg = 0;
return;
}
- s = (Mpnorm-s) * Mpscale;
+
+ // this will normalize to the nearest word
+ x = a->val.a[os-1];
+ s = (Mpnorm-os) * Mpscale;
+
+ // further normalize to the nearest bit
+ for(;;) {
+ x <<= 1;
+ if(x & Mpbase)
+ break;
+ s++;
+ if(x == 0) {
+ // this error comes from trying to
+ // convert an Inf or something
+ // where the initial x=0x80000000
+ s = (Mpnorm-os) * Mpscale;
+ break;
+ }
+ }
+
mpshiftfix(&a->val, s);
a->exp -= s;
}
@@ -109,7 +129,7 @@ mpmulfltflt(Mpflt *a, Mpflt *b)
}
mpmulfract(&a->val, &b->val);
- a->exp = (a->exp + b->exp) + Mpscale*Mpprec - 1;
+ a->exp = (a->exp + b->exp) + Mpscale*Mpprec - Mpscale - 1;
mpnorm(a);
if(Mpdebug)
diff --git a/src/cmd/gc/obj.c b/src/cmd/gc/obj.c
index ae16f2725..0d0d70ac9 100644
--- a/src/cmd/gc/obj.c
+++ b/src/cmd/gc/obj.c
@@ -74,41 +74,96 @@ Bputname(Biobuf *b, Sym *s)
}
static void
+outzfile(Biobuf *b, char *p)
+{
+ char *q, *q2;
+
+ while(p) {
+ q = utfrune(p, '/');
+ if(windows) {
+ q2 = utfrune(p, '\\');
+ if(q2 && (!q || q2 < q))
+ q = q2;
+ }
+ if(!q) {
+ zfile(b, p, strlen(p));
+ return;
+ }
+ if(q > p)
+ zfile(b, p, q-p);
+ p = q + 1;
+ }
+}
+
+#define isdelim(c) (c == '/' || c == '\\')
+
+static void
+outwinname(Biobuf *b, Hist *h, char *ds, char *p)
+{
+ if(isdelim(p[0])) {
+ // full rooted name
+ zfile(b, ds, 3); // leading "c:/"
+ outzfile(b, p+1);
+ } else {
+ // relative name
+ if(h->offset == 0 && pathname && pathname[1] == ':') {
+ if(tolowerrune(ds[0]) == tolowerrune(pathname[0])) {
+ // using current drive
+ zfile(b, pathname, 3); // leading "c:/"
+ outzfile(b, pathname+3);
+ } else {
+ // using drive other then current,
+ // we don't have any simple way to
+ // determine current working directory
+ // there, therefore will output name as is
+ zfile(b, ds, 2); // leading "c:"
+ }
+ }
+ outzfile(b, p);
+ }
+}
+
+static void
outhist(Biobuf *b)
{
Hist *h;
- char *p, *q, *op;
- int n;
+ char *p, ds[] = {'c', ':', '/', 0};
for(h = hist; h != H; h = h->link) {
p = h->name;
- op = 0;
-
- if(p && p[0] != '/' && h->offset == 0 && pathname && pathname[0] == '/') {
- op = p;
- p = pathname;
- }
-
- while(p) {
- q = utfrune(p, '/');
- if(q) {
- n = q-p;
- if(n == 0)
- n = 1; // leading "/"
- q++;
+ if(p) {
+ if(windows) {
+ // if windows variable is set, then, we know already,
+ // pathname is started with windows drive specifier
+ // and all '\' were replaced with '/' (see lex.c)
+ if(isdelim(p[0]) && isdelim(p[1])) {
+ // file name has network name in it,
+ // like \\server\share\dir\file.go
+ zfile(b, "//", 2); // leading "//"
+ outzfile(b, p+2);
+ } else if(p[1] == ':') {
+ // file name has drive letter in it
+ ds[0] = p[0];
+ outwinname(b, h, ds, p+2);
+ } else {
+ // no drive letter in file name
+ outwinname(b, h, pathname, p);
+ }
} else {
- n = strlen(p);
- q = 0;
- }
- if(n)
- zfile(b, p, n);
- p = q;
- if(p == 0 && op) {
- p = op;
- op = 0;
+ if(p[0] == '/') {
+ // full rooted name, like /home/rsc/dir/file.go
+ zfile(b, "/", 1); // leading "/"
+ outzfile(b, p+1);
+ } else {
+ // relative name, like dir/file.go
+ if(h->offset == 0 && pathname && pathname[0] == '/') {
+ zfile(b, "/", 1); // leading "/"
+ outzfile(b, pathname+1);
+ }
+ outzfile(b, p);
+ }
}
}
-
zhist(b, h->line, h->offset);
}
}
diff --git a/src/cmd/gc/print.c b/src/cmd/gc/print.c
index 8738eb41b..6bb1f026b 100644
--- a/src/cmd/gc/print.c
+++ b/src/cmd/gc/print.c
@@ -23,14 +23,21 @@ 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:
@@ -53,9 +60,11 @@ exprfmt(Fmt *f, Node *n, int prec)
case OPRINT:
case OPRINTN:
case OCALL:
+ case OCALLMETH:
+ case OCALLINTER:
+ case OCALLFUNC:
case OCONV:
case OCONVNOP:
- case OCONVSLICE:
case OMAKESLICE:
case ORUNESTR:
case OADDR:
@@ -66,6 +75,9 @@ exprfmt(Fmt *f, Node *n, int prec)
case OPLUS:
case ORECV:
case OCONVIFACE:
+ case OTPAREN:
+ case OINDEX:
+ case OINDEXMAP:
nprec = 7;
break;
@@ -106,6 +118,11 @@ exprfmt(Fmt *f, Node *n, int prec)
case OOROR:
nprec = 1;
break;
+
+ case OTYPE:
+ if(n->sym != S)
+ nprec = 7;
+ break;
}
if(prec > nprec)
@@ -118,6 +135,10 @@ exprfmt(Fmt *f, Node *n, int prec)
break;
case OLITERAL:
+ if(n->sym != S) {
+ fmtprint(f, "%S", n->sym);
+ break;
+ }
switch(n->val.ctype) {
default:
goto bad;
@@ -154,6 +175,10 @@ exprfmt(Fmt *f, Node *n, int prec)
break;
case OTYPE:
+ if(n->type == T && n->sym != S) {
+ fmtprint(f, "%S", n->sym);
+ break;
+ }
fmtprint(f, "%T", n->type);
break;
@@ -161,6 +186,12 @@ exprfmt(Fmt *f, Node *n, int prec)
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[");
@@ -178,7 +209,7 @@ exprfmt(Fmt *f, Node *n, int prec)
exprfmt(f, n->left, 0);
} else {
fmtprint(f, " ");
- if(n->left->op == OTCHAN && n->left->etype == Crecv) {
+ if(n->left->op == OTCHAN && n->left->sym == S && n->left->etype == Crecv) {
fmtprint(f, "(");
exprfmt(f, n->left, 0);
fmtprint(f, ")");
@@ -248,6 +279,10 @@ exprfmt(Fmt *f, Node *n, int prec)
exprfmt(f, n->left, 0);
break;
+ case OCLOSURE:
+ fmtprint(f, "func literal");
+ break;
+
case OCOMPLIT:
fmtprint(f, "composite literal");
break;
@@ -267,6 +302,7 @@ exprfmt(Fmt *f, Node *n, int prec)
fmtprint(f, "struct literal");
break;
+ case OXDOT:
case ODOT:
case ODOTPTR:
case ODOTINTER:
@@ -274,8 +310,15 @@ exprfmt(Fmt *f, Node *n, int prec)
exprfmt(f, n->left, 7);
if(n->right == N || n->right->sym == S)
fmtprint(f, ".<nil>");
- else
- fmtprint(f, ".%s", n->right->sym->name);
+ 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:
@@ -291,7 +334,6 @@ exprfmt(Fmt *f, Node *n, int prec)
case OINDEX:
case OINDEXMAP:
- case OINDEXSTR:
exprfmt(f, n->left, 7);
fmtprint(f, "[");
exprfmt(f, n->right, 0);
@@ -299,9 +341,12 @@ exprfmt(Fmt *f, Node *n, int prec)
break;
case OSLICE:
+ case OSLICESTR:
+ case OSLICEARR:
exprfmt(f, n->left, 7);
fmtprint(f, "[");
- exprfmt(f, n->right->left, 0);
+ if(n->right->left != N)
+ exprfmt(f, n->right->left, 0);
fmtprint(f, ":");
if(n->right->right != N)
exprfmt(f, n->right->right, 0);
@@ -315,6 +360,8 @@ exprfmt(Fmt *f, Node *n, int prec)
exprfmt(f, n->left, 7);
fmtprint(f, "(");
exprlistfmt(f, n->list);
+ if(n->isddd)
+ fmtprint(f, "...");
fmtprint(f, ")");
break;
@@ -341,7 +388,6 @@ exprfmt(Fmt *f, Node *n, int prec)
case OCONV:
case OCONVIFACE:
case OCONVNOP:
- case OCONVSLICE:
case OARRAYBYTESTR:
case ORUNESTR:
if(n->type == T || n->type->sym == S)
@@ -355,6 +401,7 @@ exprfmt(Fmt *f, Node *n, int prec)
fmtprint(f, ")");
break;
+ case OAPPEND:
case OCAP:
case OCLOSE:
case OCLOSED:
diff --git a/src/cmd/gc/range.c b/src/cmd/gc/range.c
index 09d54b3ee..dca3a5454 100644
--- a/src/cmd/gc/range.c
+++ b/src/cmd/gc/range.c
@@ -24,6 +24,8 @@ typecheckrange(Node *n)
typecheck(&n->right, Erv);
if((t = n->right->type) == T)
goto out;
+ if(isptr[t->etype] && isfixedarray(t->type))
+ t = t->type;
n->type = t;
switch(t->etype) {
@@ -104,9 +106,6 @@ walkrange(Node *n)
a = nod(OCONV, n->right, N);
a->type = types[TSTRING];
}
- ha = nod(OXXX, N, N);
- tempname(ha, a->type);
- init = list(init, nod(OAS, ha, a));
v1 = n->list->n;
hv1 = N;
@@ -116,6 +115,16 @@ walkrange(Node *n)
v2 = n->list->next->n;
hv2 = N;
+ if(v2 == N && t->etype == TARRAY) {
+ // will have just one reference to argument.
+ // no need to make a potentially expensive copy.
+ ha = a;
+ } else {
+ ha = nod(OXXX, N, N);
+ tempname(ha, a->type);
+ init = list(init, nod(OAS, ha, a));
+ }
+
switch(t->etype) {
default:
fatal("walkrange");
@@ -131,7 +140,7 @@ walkrange(Node *n)
init = list(init, nod(OAS, hn, nod(OLEN, ha, N)));
if(v2) {
hp = nod(OXXX, N, N);
- tempname(hp, ptrto(a->type->type));
+ tempname(hp, 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)));
diff --git a/src/cmd/gc/reflect.c b/src/cmd/gc/reflect.c
index 467f3615b..b31eb5154 100644
--- a/src/cmd/gc/reflect.c
+++ b/src/cmd/gc/reflect.c
@@ -100,16 +100,16 @@ lsort(Sig *l, int(*f)(Sig*, Sig*))
* return function type, receiver as first argument (or not).
*/
Type*
-methodfunc(Type *f, int use_receiver)
+methodfunc(Type *f, Type *receiver)
{
NodeList *in, *out;
Node *d;
Type *t;
in = nil;
- if(use_receiver) {
+ if(receiver) {
d = nod(ODCLFIELD, N, N);
- d->type = getthisx(f)->type->type;
+ d->type = receiver;
in = list(in, d);
}
for(t=getinargx(f)->type; t; t=t->down) {
@@ -183,14 +183,14 @@ methods(Type *t)
a = b;
a->name = method->name;
- a->isym = methodsym(method, it);
- a->tsym = methodsym(method, t);
- a->type = methodfunc(f->type, 1);
- a->mtype = methodfunc(f->type, 0);
+ a->isym = methodsym(method, it, 1);
+ a->tsym = methodsym(method, t, 0);
+ a->type = methodfunc(f->type, t);
+ a->mtype = methodfunc(f->type, nil);
if(!(a->isym->flags & SymSiggen)) {
a->isym->flags |= SymSiggen;
- if(!eqtype(this, it)) {
+ if(!eqtype(this, it) || this->width < types[tptr]->width) {
if(oldlist == nil)
oldlist = pc;
// Is okay to call genwrapper here always,
@@ -199,9 +199,9 @@ methods(Type *t)
// is a pointer adjustment and a JMP.
if(isptr[it->etype] && isptr[this->etype]
&& f->embedded && !isifacemethod(f->type))
- genembedtramp(it, f, a->isym);
+ genembedtramp(it, f, a->isym, 1);
else
- genwrapper(it, f, a->isym);
+ genwrapper(it, f, a->isym, 1);
}
}
@@ -212,9 +212,9 @@ methods(Type *t)
oldlist = pc;
if(isptr[t->etype] && isptr[this->etype]
&& f->embedded && !isifacemethod(f->type))
- genembedtramp(t, f, a->tsym);
+ genembedtramp(t, f, a->tsym, 0);
else
- genwrapper(t, f, a->tsym);
+ genwrapper(t, f, a->tsym, 0);
}
}
}
@@ -241,22 +241,27 @@ imethods(Type *t)
Sig *a, *all, *last;
int o;
Type *f;
+ Sym *method, *isym;
+ Prog *oldlist;
all = nil;
last = nil;
o = 0;
+ oldlist = nil;
for(f=t->type; f; f=f->down) {
if(f->etype != TFIELD)
fatal("imethods: not field");
if(f->type->etype != TFUNC || f->sym == nil)
continue;
+ method = f->sym;
a = mal(sizeof(*a));
- a->name = f->sym->name;
- if(!exportname(f->sym->name))
- a->pkg = f->sym->pkg;
+ a->name = method->name;
+ if(!exportname(method->name))
+ a->pkg = method->pkg;
a->mtype = f->type;
a->offset = 0;
- a->type = methodfunc(f->type, 0);
+ a->type = methodfunc(f->type, nil);
+
if(last && sigcmp(last, a) >= 0)
fatal("sigcmp vs sortinter %s %s", last->name, a->name);
if(last == nil)
@@ -264,7 +269,34 @@ imethods(Type *t)
else
last->link = a;
last = a;
+
+ // Compiler can only refer to wrappers for
+ // named interface types.
+ if(t->sym == S)
+ continue;
+
+ // NOTE(rsc): Perhaps an oversight that
+ // IfaceType.Method is not in the reflect data.
+ // Generate the method body, so that compiled
+ // code can refer to it.
+ 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;
}
@@ -545,7 +577,6 @@ dcommontype(Sym *s, int ot, Type *t)
{
int i;
Sym *s1;
- Type *elem;
char *p;
dowidth(t);
@@ -566,26 +597,23 @@ dcommontype(Sym *s, int ot, Type *t)
// alg uint8;
// align uint8;
// fieldAlign uint8;
+ // kind uint8;
// string *string;
// *nameInfo;
// }
ot = duintptr(s, ot, t->width);
ot = duint32(s, ot, typehash(t));
ot = duint8(s, ot, algtype(t));
- elem = t;
- while(elem->etype == TARRAY && elem->bound >= 0)
- elem = elem->type;
- i = elem->width;
- if(i > maxround)
- i = maxround;
- ot = duint8(s, ot, i); // align
- ot = duint8(s, ot, i); // fieldAlign
+ ot = duint8(s, ot, t->align); // align
+ ot = duint8(s, ot, t->align); // fieldAlign
i = kinds[t->etype];
if(t->etype == TARRAY && t->bound < 0)
i = KindSlice;
+ if(isptr[t->etype] && t->type->etype == TANY)
+ i = KindUnsafePointer;
if(!haspointers(t))
i |= KindNoPointers;
- ot = duint8(s, ot, i);
+ ot = duint8(s, ot, i); // kind
longsymnames = 1;
p = smprint("%-T", t);
longsymnames = 0;
@@ -643,11 +671,10 @@ typename(Type *t)
static Sym*
dtypesym(Type *t)
{
- int ot, n, isddd;
+ int ot, n, isddd, dupok;
Sym *s, *s1, *s2;
Sig *a, *m;
- Type *t1;
- Sym *tsym;
+ Type *t1, *tbase;
if(isideal(t))
fatal("dtypesym %T", t);
@@ -660,30 +687,22 @@ dtypesym(Type *t)
// special case (look for runtime below):
// when compiling package runtime,
// emit the type structures for int, float, etc.
- t1 = T;
- if(isptr[t->etype])
- t1 = t->type;
- tsym = S;
- if(t1)
- tsym = t1->sym;
- else
- tsym = t->sym;
+ tbase = t;
+ if(isptr[t->etype] && t->sym == S && t->type->sym != S)
+ tbase = t->type;
+ dupok = tbase->sym == S;
if(compiling_runtime) {
- if(t == types[t->etype])
+ if(tbase == types[tbase->etype]) // int, float, etc
goto ok;
- if(t1 && t1 == types[t1->etype])
- goto ok;
- if(t1 && t1->etype == tptr && t1->type->etype == TANY)
+ if(tbase->etype == tptr && tbase->type->etype == TANY) // unsafe.Pointer
goto ok;
}
- // named types from other files are defined in those files
- if(t->sym && !t->local)
- return s;
- if(!t->sym && t1 && t1->sym && !t1->local)
+ // named types from other files are defined only by those files
+ if(tbase->sym && !tbase->local)
return s;
- if(isforw[t->etype] || (t1 && isforw[t1->etype]))
+ if(isforw[tbase->etype])
return s;
ok:
@@ -778,6 +797,7 @@ ok:
case TPTR32:
case TPTR64:
if(t->type->etype == TANY) {
+ // ../../pkg/runtime/type.go:/UnsafePointerType
ot = dcommontype(s, ot, t);
break;
}
@@ -818,7 +838,7 @@ ok:
break;
}
- ggloblsym(s, ot, tsym == nil);
+ ggloblsym(s, ot, dupok);
return s;
}
@@ -846,7 +866,7 @@ dumptypestructs(void)
continue;
t = n->type;
dtypesym(t);
- if(t->sym && !isptr[t->etype])
+ if(t->sym)
dtypesym(ptrto(t));
}
diff --git a/src/cmd/gc/runtime.go b/src/cmd/gc/runtime.go
index 5783faafd..174bc050e 100644
--- a/src/cmd/gc/runtime.go
+++ b/src/cmd/gc/runtime.go
@@ -10,7 +10,7 @@ package PACKAGE
// emitted by compiler, not referred to by go programs
-func mal(int32) *any
+func new(int32) *any
func panicindex()
func panicslice()
func throwreturn()
@@ -31,13 +31,18 @@ func printeface(any)
func printslice(any)
func printnl()
func printsp()
-func printf()
+func goprintf()
+
+// filled in by compiler: int n, string, string, ...
+func concatstring()
+
+// filled in by compiler: Type*, int n, Slice, ...
+func append()
+func appendslice(typ *byte, x any, y []any) any
-func catstring(string, string) string
func cmpstring(string, string) int
func slicestring(string, int, int) string
func slicestring1(string, int) string
-func indexstring(string, int) byte
func intstring(int64) string
func slicebytetostring([]byte) string
func sliceinttostring([]int) string
@@ -46,6 +51,7 @@ func stringtosliceint(string) []int
func stringiter(string, int) int
func stringiter2(string, int) (retk int, retv int)
func slicecopy(to any, fr any, wid uint32) int
+func slicestringcopy(to any, fr any) int
// interface conversions
func convI2E(elem any) (ret any)
@@ -99,9 +105,9 @@ func selectdefault(sel *byte) (selected bool)
func selectgo(sel *byte)
func makeslice(typ *byte, nel int64, cap int64) (ary []any)
-func sliceslice1(old []any, lb int, width int) (ary []any)
-func sliceslice(old []any, lb int, hb int, width int) (ary []any)
-func slicearray(old *any, nel int, lb int, hb int, width int) (ary []any)
+func sliceslice1(old []any, lb uint64, width uint64) (ary []any)
+func sliceslice(old []any, lb uint64, hb uint64, width uint64) (ary []any)
+func slicearray(old *any, nel uint64, lb uint64, hb uint64, width uint64) (ary []any)
func closure() // has args, but compiler fills in
@@ -111,6 +117,8 @@ func uint64div(uint64, uint64) uint64
func int64mod(int64, int64) int64
func uint64mod(uint64, uint64) uint64
func float64toint64(float64) int64
+func float64touint64(float64) uint64
func int64tofloat64(int64) float64
+func uint64tofloat64(uint64) float64
func complex128div(num complex128, den complex128) (quo complex128)
diff --git a/src/cmd/gc/select.c b/src/cmd/gc/select.c
index 9cba01fa5..1a3771311 100644
--- a/src/cmd/gc/select.c
+++ b/src/cmd/gc/select.c
@@ -41,11 +41,18 @@ typecheckselect(Node *sel)
setlineno(n);
switch(n->op) {
default:
- yyerror("select case must be receive, send or assign recv");;
+ yyerror("select case must be receive, send or assign recv");
break;
case OAS:
// convert x = <-c into OSELRECV(x, c)
+ // assignment might have introduced a
+ // conversion. throw it away.
+ // it will come back when the select code
+ // gets generated, because it always assigns
+ // through a temporary.
+ if((n->right->op == OCONVNOP || n->right->op == OCONVIFACE) && n->right->implicit)
+ n->right = n->right->left;
if(n->right->op != ORECV) {
yyerror("select assignment must have receive on right hand side");
break;
@@ -68,8 +75,6 @@ typecheckselect(Node *sel)
typechecklist(ncase->nbody, Etop);
}
sel->xoffset = count;
- if(count == 0)
- yyerror("empty select");
lineno = lno;
}
@@ -91,7 +96,7 @@ walkselect(Node *sel)
typecheck(&r, Etop);
init = list(init, r);
- if(sel->list == nil)
+ if(sel->list == nil && sel->xoffset != 0)
fatal("double walkselect"); // already rewrote
// register cases
diff --git a/src/cmd/gc/sinit.c b/src/cmd/gc/sinit.c
index 5ac14a537..19ee3327b 100644
--- a/src/cmd/gc/sinit.c
+++ b/src/cmd/gc/sinit.c
@@ -92,15 +92,9 @@ init1(Node *n, NodeList **out)
break;
case OAS2FUNC:
- if(n->defn->initorder)
- break;
- n->defn->initorder = 1;
- for(l=n->defn->rlist; l; l=l->next)
- init1(l->n, out);
- *out = list(*out, n->defn);
- break;
-
case OAS2MAPR:
+ case OAS2DOTTYPE:
+ case OAS2RECV:
if(n->defn->initorder)
break;
n->defn->initorder = 1;
@@ -190,6 +184,20 @@ static void arraylit(int ctxt, int pass, Node *n, Node *var, NodeList **init);
static void slicelit(int ctxt, Node *n, Node *var, NodeList **init);
static void maplit(int ctxt, Node *n, Node *var, NodeList **init);
+static Node*
+staticname(Type *t, int ctxt)
+{
+ Node *n;
+
+ snprint(namebuf, sizeof(namebuf), "statictmp_%.4d", statuniqgen);
+ statuniqgen++;
+ n = newname(lookup(namebuf));
+ if(!ctxt)
+ n->readonly = 1;
+ addvar(n, t, PEXTERN);
+ return n;
+}
+
static int
isliteral(Node *n)
{
@@ -402,12 +410,12 @@ slicelit(int ctxt, Node *n, Node *var, NodeList **init)
if(ctxt != 0) {
// put everything into static array
- vstat = staticname(t);
+ vstat = staticname(t, ctxt);
arraylit(ctxt, 1, n, vstat, init);
arraylit(ctxt, 2, n, vstat, init);
// copy static to slice
- a = nod(OADDR, vstat, N);
+ a = nod(OSLICE, vstat, nod(OKEY, N, N));
a = nod(OAS, var, a);
typecheck(&a, Etop);
a->dodata = 2;
@@ -439,7 +447,7 @@ slicelit(int ctxt, Node *n, Node *var, NodeList **init)
vstat = N;
mode = getdyn(n, 1);
if(mode & MODECONST) {
- vstat = staticname(t);
+ vstat = staticname(t, ctxt);
arraylit(ctxt, 1, n, vstat, init);
}
@@ -465,7 +473,7 @@ slicelit(int ctxt, Node *n, Node *var, NodeList **init)
}
// make slice out of heap (5)
- a = nod(OAS, var, vauto);
+ a = nod(OAS, var, nod(OSLICE, vauto, nod(OKEY, N, N)));
typecheck(&a, Etop);
walkexpr(&a, init);
*init = list(*init, a);
@@ -514,6 +522,8 @@ maplit(int ctxt, Node *n, Node *var, NodeList **init)
Node *vstat, *index, *value;
Sym *syma, *symb;
+ctxt = 0;
+
// make the map var
nerr = nerrors;
@@ -566,7 +576,7 @@ maplit(int ctxt, Node *n, Node *var, NodeList **init)
dowidth(t);
// make and initialize static array
- vstat = staticname(t);
+ vstat = staticname(t, ctxt);
b = 0;
for(l=n->list; l; l=l->next) {
r = l->n;
@@ -675,7 +685,7 @@ anylit(int ctxt, Node *n, Node *var, NodeList **init)
if(ctxt == 0) {
// lay out static data
- vstat = staticname(t);
+ vstat = staticname(t, ctxt);
structlit(1, 1, n, vstat, init);
// copy static to var
@@ -715,7 +725,7 @@ anylit(int ctxt, Node *n, Node *var, NodeList **init)
if(ctxt == 0) {
// lay out static data
- vstat = staticname(t);
+ vstat = staticname(t, ctxt);
arraylit(1, 1, n, vstat, init);
// copy static to automatic
@@ -769,8 +779,8 @@ oaslit(Node *n, NodeList **init)
// implies generated data executed
// exactly once and not subject to races.
ctxt = 0;
- if(n->dodata == 1)
- ctxt = 1;
+// if(n->dodata == 1)
+// ctxt = 1;
switch(n->right->op) {
default:
@@ -870,8 +880,18 @@ gen_as_init(Node *n)
default:
goto no;
- case OCONVSLICE:
- goto slice;
+ case OCONVNOP:
+ nr = nr->left;
+ if(nr == N || nr->op != OSLICEARR)
+ goto no;
+ // fall through
+
+ case OSLICEARR:
+ if(nr->right->op == OKEY && nr->right->left == N && nr->right->right == N) {
+ nr = nr->left;
+ goto slice;
+ }
+ goto no;
case OLITERAL:
break;
@@ -920,7 +940,7 @@ yes:
slice:
gused(N); // in case the data is the dest of a goto
- nr = n->right->left;
+ nl = nr;
if(nr == N || nr->op != OADDR)
goto no;
nr = nr->left;
@@ -932,7 +952,7 @@ slice:
goto no;
nam.xoffset += Array_array;
- gdata(&nam, n->right->left, types[tptr]->width);
+ gdata(&nam, nl, types[tptr]->width);
nam.xoffset += Array_nel-Array_array;
nodconst(&nod1, types[TINT32], nr->type->bound);
diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c
index 65b56dee6..3c4501096 100644
--- a/src/cmd/gc/subr.c
+++ b/src/cmd/gc/subr.c
@@ -228,11 +228,15 @@ linehist(char *file, int32 off, int relative)
if(debug['i']) {
if(file != nil) {
if(off < 0)
- print("pragma %s at line %L\n", file, lineno);
+ print("pragma %s", file);
else
- print("import %s at line %L\n", file, lineno);
+ if(off > 0)
+ print("line %s", file);
+ else
+ print("import %s", file);
} else
- print("end of import at line %L\n", lineno);
+ print("end of import");
+ print(" at line %L\n", lexlineno);
}
if(off < 0 && file[0] != '/' && !relative) {
@@ -267,7 +271,6 @@ setlineno(Node *n)
case OTYPE:
case OPACK:
case OLITERAL:
- case ONONAME:
break;
default:
lineno = n->lineno;
@@ -360,6 +363,8 @@ importdot(Pkg *opkg, Node *pack)
for(s = hash[h]; s != S; s = s->link) {
if(s->pkg != opkg)
continue;
+ if(s->def == N)
+ continue;
if(!exportname(s->name) || utfrune(s->name, 0xb7)) // 0xb7 = center dot
continue;
s1 = lookup(s->name);
@@ -473,9 +478,12 @@ algtype(Type *t)
int a;
if(issimple[t->etype] || isptr[t->etype] || iscomplex[t->etype] ||
- t->etype == TCHAN || t->etype == TFUNC || t->etype == TMAP)
- a = AMEM; // just bytes (int, ptr, etc)
- else if(t->etype == TSTRING)
+ t->etype == TCHAN || t->etype == TFUNC || t->etype == TMAP) {
+ if(t->width == widthptr)
+ a = AMEMWORD;
+ else
+ a = AMEM; // just bytes (int, ptr, etc)
+ } else if(t->etype == TSTRING)
a = ASTRING; // string
else if(isnilinter(t))
a = ANILINTER; // nil interface
@@ -584,6 +592,21 @@ nodintconst(int64 v)
return c;
}
+Node*
+nodfltconst(Mpflt* v)
+{
+ Node *c;
+
+ c = nod(OLITERAL, N, N);
+ c->addable = 1;
+ c->val.u.fval = mal(sizeof(*c->val.u.fval));
+ mpmovefltflt(c->val.u.fval, v);
+ c->val.ctype = CTFLT;
+ c->type = types[TIDEAL];
+ ullmancalc(c);
+ return c;
+}
+
void
nodconst(Node *n, Type *t, int64 v)
{
@@ -804,6 +827,7 @@ goopnames[] =
[OANDAND] = "&&",
[OANDNOT] = "&^",
[OAND] = "&",
+ [OAPPEND] = "append",
[OAS] = "=",
[OAS2] = "=",
[OBREAK] = "break",
@@ -894,12 +918,21 @@ Lconv(Fmt *fp)
if(lno < h->line)
break;
if(h->name) {
- if(n < HISTSZ) { /* beginning of file */
- a[n].incl = h;
- a[n].idel = h->line;
- a[n].line = 0;
+ 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++;
}
- n++;
continue;
}
n--;
@@ -919,14 +952,16 @@ Lconv(Fmt *fp)
break;
fmtprint(fp, " ");
}
+ if(debug['L'])
+ fmtprint(fp, "%s/", pathname);
if(a[i].line)
- fmtprint(fp, "%s:%ld[%s:%ld]",
+ 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:%ld",
+ 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 */
+ lno = a[i].incl->line - 1; // now print out start of this file
}
if(n == 0)
fmtprint(fp, "<epoch>");
@@ -1003,10 +1038,10 @@ Jconv(Fmt *fp)
fmtprint(fp, " a(%d)", n->addable);
if(n->vargen != 0)
- fmtprint(fp, " g(%ld)", n->vargen);
+ fmtprint(fp, " g(%d)", n->vargen);
if(n->lineno != 0)
- fmtprint(fp, " l(%ld)", n->lineno);
+ fmtprint(fp, " l(%d)", n->lineno);
if(n->xoffset != 0)
fmtprint(fp, " x(%lld)", n->xoffset);
@@ -1029,6 +1064,9 @@ Jconv(Fmt *fp)
if(n->isddd != 0)
fmtprint(fp, " isddd(%d)", n->isddd);
+ if(n->implicit != 0)
+ fmtprint(fp, " implicit(%d)", n->implicit);
+
return 0;
}
@@ -1146,7 +1184,7 @@ Tpretty(Fmt *fp, Type *t)
case Csend:
return fmtprint(fp, "chan<- %T", t->type);
}
- if(t->type != T && t->type->etype == TCHAN && t->type->chan == Crecv)
+ 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);
@@ -1256,7 +1294,7 @@ Tpretty(Fmt *fp, Type *t)
fmtprint(fp, "...%T", t->type->type);
else
fmtprint(fp, "%T", t->type);
- if(t->note) {
+ if(t->note) {
fmtprint(fp, " ");
if(exporting)
fmtprint(fp, ":");
@@ -1360,7 +1398,7 @@ Tconv(Fmt *fp)
case TARRAY:
if(t->bound >= 0)
- fmtprint(fp, "[%ld]%T", t->bound, t->type);
+ fmtprint(fp, "[%d]%T", t->bound, t->type);
else
fmtprint(fp, "[]%T", t->type);
break;
@@ -1414,7 +1452,7 @@ Nconv(Fmt *fp)
fmtprint(fp, "%O%J", n->op, n);
break;
}
- fmtprint(fp, "%O-%S G%ld%J", n->op,
+ fmtprint(fp, "%O-%S G%d%J", n->op,
n->sym, n->vargen, n);
goto ptyp;
@@ -1460,7 +1498,7 @@ Nconv(Fmt *fp)
break;
}
if(n->sym != S)
- fmtprint(fp, " %S G%ld", n->sym, n->vargen);
+ fmtprint(fp, " %S G%d", n->sym, n->vargen);
ptyp:
if(n->type != T)
@@ -1909,13 +1947,6 @@ assignop(Type *src, Type *dst, char **why)
// 7. Any typed value can be assigned to the blank identifier.
if(dst->etype == TBLANK)
return OCONVNOP;
-
- // 8. Array to slice.
- // TODO(rsc): Not for long.
- if(!src->sym || !dst->sym)
- if(isptr[src->etype] && isfixedarray(src->type) && isslice(dst))
- if(eqtype(src->type->type, dst->type))
- return OCONVSLICE;
return 0;
}
@@ -2037,6 +2068,7 @@ assignconv(Node *n, Type *t, char *context)
r = nod(op, n, N);
r->type = t;
r->typecheck = 1;
+ r->implicit = 1;
return r;
}
@@ -2292,7 +2324,8 @@ ptrto(Type *t)
fatal("ptrto: nil");
t1 = typ(tptr);
t1->type = t;
- t1->width = types[tptr]->width;
+ t1->width = widthptr;
+ t1->align = widthptr;
return t1;
}
@@ -2320,7 +2353,7 @@ frame(int context)
case ONAME:
if(flag)
print("--- %s frame ---\n", p);
- print("%O %S G%ld %T\n", n->op, n->sym, n->vargen, n->type);
+ print("%O %S G%d %T\n", n->op, n->sym, n->vargen, n->type);
flag = 0;
break;
@@ -2584,20 +2617,8 @@ brrev(int a)
return a;
}
-Node*
-staticname(Type *t)
-{
- Node *n;
-
- snprint(namebuf, sizeof(namebuf), "statictmp_%.4d", statuniqgen);
- statuniqgen++;
- n = newname(lookup(namebuf));
- addvar(n, t, PEXTERN);
- return n;
-}
-
/*
- * return side effect-free appending side effects to init.
+ * return side effect-free n, appending side effects to init.
* result is assignable if n is.
*/
Node*
@@ -2654,6 +2675,24 @@ safeexpr(Node *n, NodeList **init)
// make a copy; must not be used as an lvalue
if(islvalue(n))
fatal("missing lvalue case in safeexpr: %N", n);
+ return cheapexpr(n, init);
+}
+
+/*
+ * return side-effect free and cheap n, appending side effects to init.
+ * result may not be assignable.
+ */
+Node*
+cheapexpr(Node *n, NodeList **init)
+{
+ Node *a, *l;
+
+ switch(n->op) {
+ case ONAME:
+ case OLITERAL:
+ return n;
+ }
+
l = nod(OXXX, N, N);
tempname(l, n->type);
a = nod(OAS, l, n);
@@ -2939,6 +2978,11 @@ expandmeth(Sym *s, Type *t)
if(t == T || t->xmethod != nil)
return;
+ // mark top-level method symbols
+ // so that expand1 doesn't consider them.
+ for(f=t->method; f != nil; f=f->down)
+ f->sym->flags |= SymUniq;
+
// generate all reachable methods
slist = nil;
expand1(t, nelem(dotlist)-1, 0);
@@ -2958,6 +3002,9 @@ expandmeth(Sym *s, Type *t)
}
}
+ for(f=t->method; f != nil; f=f->down)
+ f->sym->flags &= ~SymUniq;
+
t->xmethod = t->method;
for(sl=slist; sl!=nil; sl=sl->link) {
if(sl->good) {
@@ -2969,7 +3016,6 @@ expandmeth(Sym *s, Type *t)
f->embedded = 2;
f->down = t->xmethod;
t->xmethod = f;
-
}
}
}
@@ -3031,15 +3077,19 @@ structargs(Type **tl, int mustname)
* newnam - the eventual mangled name of this function
*/
void
-genwrapper(Type *rcvr, Type *method, Sym *newnam)
+genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface)
{
- Node *this, *fn, *call, *n, *t;
+ Node *this, *fn, *call, *n, *t, *pad;
NodeList *l, *args, *in, *out;
+ Type *tpad;
+ int isddd;
if(debug['r'])
print("genwrapper rcvrtype=%T method=%T newnam=%S\n",
rcvr, method, newnam);
+ lineno = 1; // less confusing than end of input
+
dclcontext = PEXTERN;
markdcl();
@@ -3050,20 +3100,37 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam)
fn = nod(ODCLFUNC, N, N);
fn->nname = newname(newnam);
- t = nod(OTFUNC, this, N);
- t->list = in;
+ t = nod(OTFUNC, N, N);
+ l = list1(this);
+ if(iface && rcvr->width < types[tptr]->width) {
+ // Building method for interface table and receiver
+ // is smaller than the single pointer-sized word
+ // that the interface call will pass in.
+ // Add a dummy padding argument after the
+ // receiver to make up the difference.
+ tpad = typ(TARRAY);
+ tpad->type = types[TUINT8];
+ tpad->bound = types[tptr]->width - rcvr->width;
+ pad = nod(ODCLFIELD, newname(lookup(".pad")), typenod(tpad));
+ l = list(l, pad);
+ }
+ t->list = concat(l, in);
t->rlist = out;
fn->nname->ntype = t;
funchdr(fn);
// arg list
args = nil;
- for(l=in; l; l=l->next)
+ isddd = 0;
+ for(l=in; l; l=l->next) {
args = list(args, l->n->left);
+ isddd = l->n->left->isddd;
+ }
// generate call
call = nod(OCALL, adddot(nod(OXDOT, this->left, newname(method->sym))), N);
call->list = args;
+ call->isddd = isddd;
fn->nbody = list1(call);
if(method->type->outtuple > 0) {
n = nod(ORETURN, N, N);
@@ -3563,10 +3630,11 @@ umagic(Magic *m)
Sym*
ngotype(Node *n)
{
- if(n->sym != S && strncmp(n->sym->name, "autotmp_", 8) != 0)
- if(n->type->etype != TFUNC || n->type->thistuple == 0)
- if(n->type->etype != TSTRUCT || n->type->funarg == 0)
- return typename(n->type)->left->sym;
+ if(n->sym != S && n->realtype != T)
+ if(strncmp(n->sym->name, "autotmp_", 8) != 0)
+ if(strncmp(n->sym->name, "statictmp_", 8) != 0)
+ return typename(n->realtype)->left->sym;
+
return S;
}
@@ -3640,4 +3708,3 @@ strlit(char *s)
t->len = strlen(s);
return t;
}
-
diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c
index 457b82b4c..ca114d47c 100644
--- a/src/cmd/gc/typecheck.c
+++ b/src/cmd/gc/typecheck.c
@@ -17,7 +17,8 @@ static void implicitstar(Node**);
static int onearg(Node*, char*, ...);
static int twoarg(Node*);
static int lookdot(Node*, Type*, int);
-static void typecheckaste(int, Type*, NodeList*, char*);
+static int looktypedot(Node*, Type*, int);
+static void typecheckaste(int, int, Type*, NodeList*, char*);
static Type* lookdot1(Sym *s, Type *t, Type *f, int);
static int nokeys(NodeList*);
static void typecheckcomplit(Node**);
@@ -63,7 +64,7 @@ typechecklist(NodeList *l, int top)
Node*
typecheck(Node **np, int top)
{
- int et, op, ptr;
+ int et, aop, op, ptr;
Node *n, *l, *r;
NodeList *args;
int lno, ok, ntop;
@@ -79,7 +80,7 @@ typecheck(Node **np, int top)
n = *np;
if(n == N)
return N;
-
+
// Resolve definition of name and value of iota lazily.
n = resolve(n);
*np = n;
@@ -111,6 +112,7 @@ typecheck(Node **np, int top)
goto error;
}
walkdef(n);
+ n->realtype = n->type;
if(n->op == ONONAME)
goto error;
}
@@ -169,6 +171,16 @@ reswitch:
goto error;
break;
+ case OTPAREN:
+ ok |= Etype;
+ l = typecheck(&n->left, Etype);
+ if(l->type == T)
+ goto error;
+ n->op = OTYPE;
+ n->type = l->type;
+ n->left = N;
+ break;
+
case OTARRAY:
ok |= Etype;
t = typ(TARRAY);
@@ -251,7 +263,6 @@ reswitch:
n->type = dostruct(n->list, TINTER);
if(n->type == T)
goto error;
- n->type = sortinter(n->type);
break;
case OTFUNC:
@@ -340,6 +351,26 @@ reswitch:
et = t->etype;
if(et == TIDEAL)
et = TINT;
+ 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.)
+ if(r->type->etype != TBLANK && (aop = assignop(l->type, r->type, nil)) != 0) {
+ 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) {
+ r = nod(aop, r, N);
+ r->type = l->type;
+ r->typecheck = 1;
+ n->right = r;
+ t = r->type;
+ }
+ et = t->etype;
+ }
if(t->etype != TIDEAL && !eqtype(l->type, r->type)) {
badbinary:
defaultlit2(&l, &r, 1);
@@ -393,7 +424,7 @@ reswitch:
n->right = r;
t = r->type;
if(!isint[t->etype] || issigned[t->etype]) {
- yyerror("invalid operation: %#N (shift count type %T)", n, r->type);
+ yyerror("invalid operation: %#N (shift count type %T, must be unsigned integer)", n, r->type);
goto error;
}
t = l->type;
@@ -467,41 +498,42 @@ reswitch:
yyerror("rhs of . must be a name"); // impossible
goto error;
}
- if(isptr[t->etype]) {
- t = t->type;
- if(t == T)
- goto error;
- n->op = ODOTPTR;
- checkwidth(t);
- }
sym = n->right->sym;
- if(!lookdot(n, t, 0)) {
- if(lookdot(n, t, 1))
- yyerror("%#N undefined (cannot refer to unexported field %S)", n, n->right->sym);
- else
- yyerror("%#N undefined (type %T has no field %S)", n, t, n->right->sym);
- goto error;
- }
if(l->op == OTYPE) {
- if(n->type->etype != TFUNC || n->type->thistuple != 1) {
- yyerror("type %T has no method %hS", n->left->type, sym);
- n->type = T;
+ if(!looktypedot(n, t, 0)) {
+ if(looktypedot(n, t, 1))
+ 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);
goto error;
}
- if(t->etype == TINTER) {
- yyerror("method expression on interface not implemented");
+ if(n->type->etype != TFUNC || n->type->thistuple != 1) {
+ yyerror("type %T has no method %hS", n->left->type, sym);
n->type = T;
goto error;
}
n->op = ONAME;
- n->sym = methodsym(sym, l->type);
- n->type = methodfunc(n->type, 1);
+ n->sym = methodsym(sym, l->type, 0);
+ n->type = methodfunc(n->type, l->type);
n->xoffset = 0;
- getinargx(n->type)->type->type = l->type; // fix up receiver
n->class = PFUNC;
ok = Erv;
goto ret;
}
+ if(isptr[t->etype] && t->type->etype != TINTER) {
+ t = t->type;
+ if(t == T)
+ goto error;
+ n->op = ODOTPTR;
+ checkwidth(t);
+ }
+ 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);
+ else
+ yyerror("%#N undefined (type %T has no field or method %S)", n, t, n->right->sym);
+ goto error;
+ }
switch(n->op) {
case ODOTINTER:
case ODOTMETH:
@@ -561,7 +593,7 @@ reswitch:
goto error;
case TARRAY:
- defaultlit(&n->right, types[TUINT]);
+ defaultlit(&n->right, T);
if(n->right->type != T && !isint[n->right->type->etype])
yyerror("non-integer array index %#N", n->right);
n->type = t->type;
@@ -581,7 +613,6 @@ reswitch:
if(n->right->type != T && !isint[n->right->type->etype])
yyerror("non-integer string index %#N", n->right);
n->type = types[TUINT8];
- n->op = OINDEXSTR;
break;
}
goto ret;
@@ -612,6 +643,10 @@ reswitch:
l = n->left;
if((t = l->type) == T)
goto error;
+ if(t->etype != TCHAN) {
+ 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);
goto error;
@@ -620,6 +655,7 @@ reswitch:
r = n->right;
if((t = r->type) == T)
goto error;
+ r = assignconv(r, l->type->type, "send");
// TODO: more aggressive
n->etype = 0;
n->type = T;
@@ -635,24 +671,19 @@ reswitch:
typecheck(&n->right->left, Erv);
typecheck(&n->right->right, Erv);
defaultlit(&n->left, T);
- defaultlit(&n->right->left, types[TUINT]);
- defaultlit(&n->right->right, types[TUINT]);
+ defaultlit(&n->right->left, T);
+ defaultlit(&n->right->right, T);
if(isfixedarray(n->left->type)) {
- // Insert explicit & before fixed array
- // so that back end knows to move to heap.
n->left = nod(OADDR, n->left, N);
typecheck(&n->left, top);
}
- implicitstar(&n->left);
- if(n->right->left == N) {
- yyerror("missing slice bounds?");
- goto error;
- }
- if((t = n->right->left->type) == T)
- goto error;
- if(!isint[t->etype]) {
- yyerror("invalid slice index %#N (type %T)", n->right->left, t);
- goto error;
+ 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);
+ goto error;
+ }
}
if(n->right->right != N) {
if((t = n->right->right->type) == T)
@@ -670,9 +701,9 @@ reswitch:
n->op = OSLICESTR;
goto ret;
}
- if(isfixedarray(t)) {
+ if(isptr[t->etype] && isfixedarray(t->type)) {
n->type = typ(TARRAY);
- n->type->type = t->type;
+ n->type->type = t->type->type;
n->type->bound = -1;
dowidth(n->type);
n->op = OSLICEARR;
@@ -690,13 +721,17 @@ reswitch:
*/
case OCALL:
l = n->left;
- if(l->op == ONAME && (r = unsafenmagic(l, n->list)) != N) {
+ if(l->op == ONAME && (r = unsafenmagic(n)) != N) {
+ if(n->isddd)
+ yyerror("invalid use of ... with builtin %#N", l);
n = r;
goto reswitch;
}
typecheck(&n->left, Erv | Etype | Ecall);
l = n->left;
if(l->op == ONAME && l->etype != 0) {
+ if(n->isddd && l->etype != OAPPEND)
+ yyerror("invalid use of ... with builtin %#N", l);
// builtin: OLEN, OCAP, etc.
n->op = l->etype;
n->left = n->right;
@@ -706,6 +741,8 @@ reswitch:
defaultlit(&n->left, T);
l = n->left;
if(l->op == OTYPE) {
+ if(n->isddd)
+ yyerror("invalid use of ... in type conversion", l);
// pick off before type-checking arguments
ok |= Erv;
// turn CALL(type, arg) into CONV(arg) w/ type
@@ -732,7 +769,7 @@ reswitch:
case ODOTMETH:
n->op = OCALLMETH;
- typecheckaste(OCALL, getthisx(t), list1(l->left), "method receiver");
+ typecheckaste(OCALL, 0, getthisx(t), list1(l->left), "method receiver");
break;
default:
@@ -743,7 +780,7 @@ reswitch:
}
break;
}
- typecheckaste(OCALL, getinargx(t), n->list, "function argument");
+ typecheckaste(OCALL, n->isddd, getinargx(t), n->list, "function argument");
ok |= Etop;
if(t->outtuple == 0)
goto ret;
@@ -792,6 +829,12 @@ reswitch:
case OIMAG:
if(!iscomplex[t->etype])
goto badcall1;
+ if(isconst(l, CTCPLX)){
+ if(n->op == OREAL)
+ n = nodfltconst(&l->val.u.cval->real);
+ else
+ n = nodfltconst(&l->val.u.cval->imag);
+ }
n->type = types[cplxsubtype(t->etype)];
goto ret;
}
@@ -802,7 +845,7 @@ reswitch:
nodconst(n, types[TINT], l->val.u.sval->len);
break;
case TARRAY:
- if(t->bound >= 0)
+ if(t->bound >= 0 && l->op == ONAME)
nodconst(n, types[TINT], t->bound);
break;
}
@@ -868,6 +911,40 @@ reswitch:
ok |= Etop;
goto ret;
+ case OAPPEND:
+ ok |= Erv;
+ args = n->list;
+ if(args == nil) {
+ yyerror("missing arguments to append");
+ goto error;
+ }
+ typechecklist(args, Erv);
+ if((t = args->n->type) == T)
+ goto error;
+ n->type = t;
+ if(!isslice(t)) {
+ 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");
+ goto error;
+ }
+ if(args->next->next != nil) {
+ yyerror("too many arguments to append");
+ goto error;
+ }
+ args->next->n = assignconv(args->next->n, t->orig, "append");
+ goto ret;
+ }
+ for(args=args->next; args != nil; args=args->next) {
+ if(args->n->type == T)
+ continue;
+ args->n = assignconv(args->n, t->type, "append");
+ }
+ goto ret;
+
case OCOPY:
ok |= Etop|Erv;
args = n->list;
@@ -888,13 +965,18 @@ reswitch:
goto error;
defaultlit(&n->left, T);
defaultlit(&n->right, T);
+
+ // copy([]byte, string)
+ if(isslice(n->left->type) && n->left->type->type == types[TUINT8] && n->right->type->etype == TSTRING)
+ goto ret;
+
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);
else if(!isslice(n->left->type))
yyerror("first argument to copy should be slice; have %lT", n->left->type);
else
- yyerror("second argument to copy should be slice; have %lT", n->right->type);
+ yyerror("second argument to copy should be slice or string; have %lT", n->right->type);
goto error;
}
if(!eqtype(n->left->type->type, n->right->type->type)) {
@@ -1048,7 +1130,7 @@ reswitch:
case OPRINT:
case OPRINTN:
ok |= Etop;
- typechecklist(n->list, Erv);
+ typechecklist(n->list, Erv | Eindir); // Eindir: address does not escape
goto ret;
case OPANIC:
@@ -1056,7 +1138,7 @@ reswitch:
if(onearg(n, "panic") < 0)
goto error;
typecheck(&n->left, Erv);
- defaultlit(&n->left, T);
+ defaultlit(&n->left, types[TINTER]);
if(n->left->type == T)
goto error;
goto ret;
@@ -1129,9 +1211,13 @@ reswitch:
case ORETURN:
ok |= Etop;
typechecklist(n->list, Erv | Efnstruct);
+ if(curfn == N) {
+ yyerror("return outside function");
+ goto error;
+ }
if(curfn->type->outnamed && n->list == nil)
goto ret;
- typecheckaste(ORETURN, getoutargx(curfn->type), n->list, "return argument");
+ typecheckaste(ORETURN, 0, getoutargx(curfn->type), n->list, "return argument");
goto ret;
case OSELECT:
@@ -1149,11 +1235,6 @@ reswitch:
typecheckrange(n);
goto ret;
- case OTYPECASE:
- ok |= Etop | Erv;
- typecheck(&n->left, Erv);
- goto ret;
-
case OTYPESW:
yyerror("use of .(type) outside type switch");
goto error;
@@ -1218,7 +1299,7 @@ ret:
goto error;
}
if((ok & Ecall) && !(top & Ecall)) {
- yyerror("must call %#N", n);
+ yyerror("method %#N is not an expression, must be called", n);
goto error;
}
// TODO(rsc): simplify
@@ -1257,7 +1338,7 @@ implicitstar(Node **nn)
Type *t;
Node *n;
- // insert implicit * if needed
+ // insert implicit * if needed for fixed array
n = *nn;
t = n->type;
if(t == T || !isptr[t->etype])
@@ -1347,6 +1428,57 @@ lookdot1(Sym *s, Type *t, Type *f, int dostrcmp)
}
static int
+looktypedot(Node *n, Type *t, int dostrcmp)
+{
+ Type *f1, *f2, *tt;
+ Sym *s;
+
+ s = n->right->sym;
+
+ if(t->etype == TINTER) {
+ f1 = lookdot1(s, t, t->type, dostrcmp);
+ if(f1 == T)
+ return 0;
+
+ if(f1->width == BADWIDTH)
+ fatal("lookdot badwidth %T %p", f1, f1);
+ n->right = methodname(n->right, t);
+ n->xoffset = f1->width;
+ n->type = f1->type;
+ n->op = ODOTINTER;
+ return 1;
+ }
+
+ tt = t;
+ if(t->sym == S && isptr[t->etype])
+ tt = t->type;
+
+ f2 = methtype(tt);
+ if(f2 == T)
+ return 0;
+
+ expandmeth(f2->sym, f2);
+ f2 = lookdot1(s, f2, f2->xmethod, dostrcmp);
+ if(f2 == T)
+ return 0;
+
+ // disallow T.m if m requires *T receiver
+ if(isptr[getthisx(f2->type)->type->type->etype]
+ && !isptr[t->etype]
+ && f2->embedded != 2
+ && !isifacemethod(f2->type)) {
+ yyerror("invalid method expression %#N (needs pointer receiver: (*%T).%s)", n, t, f2->sym->name);
+ return 0;
+ }
+
+ n->right = methodname(n->right, t);
+ n->xoffset = f2->width;
+ n->type = f2->type;
+ n->op = ODOTMETH;
+ return 1;
+}
+
+static int
lookdot(Node *n, Type *t, int dostrcmp)
{
Type *f1, *f2, *tt, *rcvr;
@@ -1359,9 +1491,15 @@ lookdot(Node *n, Type *t, int dostrcmp)
if(t->etype == TSTRUCT || t->etype == TINTER)
f1 = lookdot1(s, t, t->type, dostrcmp);
- f2 = methtype(n->left->type);
- if(f2 != T)
- f2 = lookdot1(s, f2, f2->method, dostrcmp);
+ f2 = T;
+ if(n->left->type == t || n->left->type->sym == S) {
+ f2 = methtype(t);
+ 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);
+ }
+ }
if(f1 != T) {
if(f2 != T)
@@ -1385,14 +1523,16 @@ lookdot(Node *n, Type *t, int dostrcmp)
tt = n->left->type;
dowidth(tt);
rcvr = getthisx(f2->type)->type->type;
- if(n->left->op != OTYPE && !eqtype(rcvr, tt)) {
+ if(!eqtype(rcvr, tt)) {
if(rcvr->etype == tptr && eqtype(rcvr->type, tt)) {
checklvalue(n->left, "call pointer method on");
addrescapes(n->left);
n->left = nod(OADDR, n->left, N);
+ n->left->implicit = 1;
typecheck(&n->left, Etype|Erv);
} else if(tt->etype == tptr && eqtype(tt->type, rcvr)) {
n->left = nod(OIND, n->left, N);
+ n->left->implicit = 1;
typecheck(&n->left, Etype|Erv);
} else {
// method is attached to wrong type?
@@ -1422,7 +1562,7 @@ nokeys(NodeList *l)
* typecheck assignment: type list = expression list
*/
static void
-typecheckaste(int op, Type *tstruct, NodeList *nl, char *desc)
+typecheckaste(int op, int isddd, Type *tstruct, NodeList *nl, char *desc)
{
Type *t, *tl, *tn;
Node *n;
@@ -1436,63 +1576,79 @@ typecheckaste(int op, Type *tstruct, NodeList *nl, char *desc)
if(nl != nil && nl->next == nil && (n = nl->n)->type != T)
if(n->type->etype == TSTRUCT && n->type->funarg) {
- setlineno(n);
tn = n->type->type;
for(tl=tstruct->type; tl; tl=tl->down) {
if(tl->isddd) {
- for(; tn; tn=tn->down)
+ for(; tn; tn=tn->down) {
+ exportassignok(tn->type, desc);
if(assignop(tn->type, tl->type->type, &why) == 0)
yyerror("cannot use %T as type %T in %s%s", tn->type, tl->type->type, desc, why);
+ }
goto out;
}
- if(tn == T) {
- yyerror("not enough arguments to %#O", op);
- goto out;
- }
+ if(tn == T)
+ goto notenough;
+ exportassignok(tn->type, desc);
if(assignop(tn->type, tl->type, &why) == 0)
yyerror("cannot use %T as type %T in %s%s", tn->type, tl->type, desc, why);
tn = tn->down;
}
if(tn != T)
- yyerror("too many arguments to %#O", op);
+ goto toomany;
goto out;
}
for(tl=tstruct->type; tl; tl=tl->down) {
t = tl->type;
if(tl->isddd) {
- if(nl != nil && nl->n->isddd && !eqtype(nl->n->type, t)) {
- // TODO(rsc): This is not actually illegal but will
- // help catch bugs.
- yyerror("cannot pass %+N as %T (... mismatch)", nl->n, tl);
+ if(nl != nil && nl->n->op == ONAME && nl->n->isddd && !isddd) {
+ // TODO(rsc): This is not actually illegal, but it will help catch bugs.
+ yyerror("to pass '%#N' as ...%T, use '%#N...'", nl->n, t->type, nl->n);
+ isddd = 1;
}
- if(nl != nil && nl->next == nil && nl->n->isddd && eqtype(nl->n->type, t))
+ if(isddd) {
+ if(nl == nil)
+ goto notenough;
+ if(nl->next != nil)
+ goto toomany;
+ n = nl->n;
+ setlineno(n);
+ if(n->type != T)
+ nl->n = assignconv(n, t, desc);
goto out;
+ }
for(; nl; nl=nl->next) {
+ n = nl->n;
setlineno(nl->n);
- defaultlit(&nl->n, t->type);
- if(assignop(nl->n->type, t->type, &why) == 0)
- yyerror("cannot use %+N as type %T in %s%s", nl->n, t->type, desc, why);
+ if(n->type != T)
+ nl->n = assignconv(n, t->type, desc);
}
goto out;
}
- if(nl == nil) {
- yyerror("not enough arguments to %#O", op);
- goto out;
- }
+ if(nl == nil)
+ goto notenough;
n = nl->n;
- setlineno(nl->n);
+ setlineno(n);
if(n->type != T)
nl->n = assignconv(n, t, desc);
nl = nl->next;
}
- if(nl != nil) {
- yyerror("too many arguments to %#O", op);
- goto out;
- }
+ if(nl != nil)
+ goto toomany;
+ if(isddd)
+ yyerror("invalid use of ... in %#O", op);
out:
lineno = lno;
+ return;
+
+notenough:
+ yyerror("not enough arguments to %#O", op);
+ goto out;
+
+toomany:
+ yyerror("too many arguments to %#O", op);
+ goto out;
}
/*
@@ -1658,23 +1814,103 @@ indexdup(Node *n, Node *hash[], ulong nhash)
hash[h] = n;
}
+static int
+prime(ulong h, ulong sr)
+{
+ ulong n;
+
+ for(n=3; n<=sr; n+=2)
+ if(h%n == 0)
+ return 0;
+ return 1;
+}
+
+static ulong
+inithash(Node *n, Node ***hash, Node **autohash, ulong nautohash)
+{
+ ulong h, sr;
+ NodeList *ll;
+ int i;
+
+ // count the number of entries
+ h = 0;
+ for(ll=n->list; ll; ll=ll->next)
+ h++;
+
+ // if the auto hash table is
+ // large enough use it.
+ if(h <= nautohash) {
+ *hash = autohash;
+ memset(*hash, 0, nautohash * sizeof(**hash));
+ return nautohash;
+ }
+
+ // make hash size odd and 12% larger than entries
+ h += h/8;
+ h |= 1;
+
+ // calculate sqrt of h
+ sr = h/2;
+ for(i=0; i<5; i++)
+ sr = (sr + h/sr)/2;
+
+ // check for primeality
+ while(!prime(h, sr))
+ h += 2;
+
+ // build and return a throw-away hash table
+ *hash = mal(h * sizeof(**hash));
+ memset(*hash, 0, h * sizeof(**hash));
+ return h;
+}
+
static void
typecheckcomplit(Node **np)
{
int bad, i, len, nerr;
- Node *l, *n, *hash[101];
+ Node *l, *n, **hash;
NodeList *ll;
- Type *t, *f;
+ Type *t, *f, *pushtype;
Sym *s;
+ int32 lno;
+ ulong nhash;
+ Node *autohash[101];
n = *np;
+ lno = lineno;
- memset(hash, 0, sizeof hash);
+ if(n->right == N) {
+ if(n->list != nil)
+ setlineno(n->list->n);
+ yyerror("missing type in composite literal");
+ goto error;
+ }
+ setlineno(n->right);
l = typecheck(&n->right /* sic */, Etype);
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;
+ }
+ }
+ }
+
switch(t->etype) {
default:
yyerror("invalid type for composite literal: %T", t);
@@ -1682,31 +1918,29 @@ typecheckcomplit(Node **np)
break;
case TARRAY:
+ nhash = inithash(n, &hash, autohash, nelem(autohash));
+
len = 0;
i = 0;
for(ll=n->list; ll; ll=ll->next) {
l = ll->n;
- if(l->op == OKEY) {
- typecheck(&l->left, Erv);
- evconst(l->left);
- i = nonnegconst(l->left);
- if(i < 0) {
- yyerror("array index must be non-negative integer constant");
- i = -(1<<30); // stay negative for a while
- }
- typecheck(&l->right, Erv);
- defaultlit(&l->right, t->type);
- l->right = assignconv(l->right, t->type, "array index");
- } else {
- typecheck(&ll->n, Erv);
- defaultlit(&ll->n, t->type);
- ll->n = assignconv(ll->n, t->type, "array index");
- ll->n = nod(OKEY, nodintconst(i), ll->n);
- ll->n->left->type = types[TINT];
- ll->n->left->typecheck = 1;
+ setlineno(l);
+ if(l->op != OKEY) {
+ l = nod(OKEY, nodintconst(i), l);
+ l->left->type = types[TINT];
+ l->left->typecheck = 1;
+ ll->n = l;
+ }
+
+ typecheck(&l->left, Erv);
+ evconst(l->left);
+ i = nonnegconst(l->left);
+ if(i < 0) {
+ yyerror("array index must be non-negative integer constant");
+ i = -(1<<30); // stay negative for a while
}
if(i >= 0)
- indexdup(ll->n->left, hash, nelem(hash));
+ indexdup(l->left, hash, nhash);
i++;
if(i > len) {
len = i;
@@ -1716,6 +1950,12 @@ typecheckcomplit(Node **np)
t->bound = -1; // no more errors
}
}
+
+ 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 index");
}
if(t->bound == -100)
t->bound = len;
@@ -1725,20 +1965,27 @@ typecheckcomplit(Node **np)
break;
case TMAP:
+ nhash = inithash(n, &hash, autohash, nelem(autohash));
+
for(ll=n->list; ll; ll=ll->next) {
l = ll->n;
+ setlineno(l);
if(l->op != OKEY) {
typecheck(&ll->n, Erv);
yyerror("missing key in map literal");
continue;
}
+
typecheck(&l->left, Erv);
- typecheck(&l->right, Erv);
defaultlit(&l->left, t->down);
- defaultlit(&l->right, t->type);
l->left = assignconv(l->left, t->down, "map key");
+ 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");
- keydup(l->left, hash, nelem(hash));
}
n->op = OMAPLIT;
break;
@@ -1749,6 +1996,7 @@ typecheckcomplit(Node **np)
// simple list of variables
f = t->type;
for(ll=n->list; ll; ll=ll->next) {
+ setlineno(ll->n);
typecheck(&ll->n, Erv);
if(f == nil) {
if(!bad++)
@@ -1766,9 +2014,12 @@ typecheckcomplit(Node **np)
if(f != nil)
yyerror("too few values in struct initializer");
} else {
+ nhash = inithash(n, &hash, autohash, nelem(autohash));
+
// keyed list
for(ll=n->list; ll; ll=ll->next) {
l = ll->n;
+ setlineno(l);
if(l->op != OKEY) {
if(!bad++)
yyerror("mixture of field:value and value initializers");
@@ -1781,6 +2032,11 @@ typecheckcomplit(Node **np)
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)
+ s = lookup(s->name);
l->left = newname(s);
l->left->typecheck = 1;
f = lookdot1(s, t, t->type, 0);
@@ -1790,7 +2046,7 @@ typecheckcomplit(Node **np)
continue;
}
s = f->sym;
- fielddup(newname(s), hash, nelem(hash));
+ fielddup(newname(s), hash, nhash);
l->right = assignconv(l->right, f->type, "field value");
}
}
@@ -1802,11 +2058,13 @@ typecheckcomplit(Node **np)
n->type = t;
*np = n;
+ lineno = lno;
return;
error:
n->type = T;
*np = n;
+ lineno = lno;
}
/*
@@ -1890,6 +2148,8 @@ islvalue(Node *n)
case OINDEX:
if(isfixedarray(n->left->type))
return islvalue(n->left);
+ if(n->left->type != T && n->left->type->etype == TSTRING)
+ return 0;
// fall through
case OIND:
case ODOTPTR:
diff --git a/src/cmd/gc/unsafe.c b/src/cmd/gc/unsafe.c
index dbf6f708a..33f375631 100644
--- a/src/cmd/gc/unsafe.c
+++ b/src/cmd/gc/unsafe.c
@@ -11,13 +11,18 @@
* rewrite with a constant
*/
Node*
-unsafenmagic(Node *fn, NodeList *args)
+unsafenmagic(Node *nn)
{
Node *r, *n;
Sym *s;
Type *t, *tr;
long v;
Val val;
+ Node *fn;
+ NodeList *args;
+
+ fn = nn->left;
+ args = nn->list;
if(safemode || fn == N || fn->op != ONAME || (s = fn->sym) == S)
goto no;
@@ -35,13 +40,14 @@ unsafenmagic(Node *fn, NodeList *args)
defaultlit(&r, T);
tr = r->type;
if(tr == T)
- goto no;
+ goto bad;
v = tr->width;
goto yes;
}
if(strcmp(s->name, "Offsetof") == 0) {
+ typecheck(&r, Erv);
if(r->op != ODOT && r->op != ODOTPTR)
- goto no;
+ goto bad;
typecheck(&r, Erv);
v = r->xoffset;
goto yes;
@@ -51,7 +57,7 @@ unsafenmagic(Node *fn, NodeList *args)
defaultlit(&r, T);
tr = r->type;
if(tr == T)
- goto no;
+ goto bad;
// make struct { byte; T; }
t = typ(TSTRUCT);
@@ -70,9 +76,15 @@ unsafenmagic(Node *fn, NodeList *args)
no:
return N;
+bad:
+ yyerror("invalid expression %#N", nn);
+ v = 0;
+ goto ret;
+
yes:
if(args->next != nil)
yyerror("extra arguments for %S", s);
+ret:
// any side effects disappear; ignore init
val.ctype = CTINT;
val.u.xval = mal(sizeof(*n->val.u.xval));
diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c
index 4f59d5598..fa3e5d5e4 100644
--- a/src/cmd/gc/walk.c
+++ b/src/cmd/gc/walk.c
@@ -11,12 +11,14 @@ static Node* makenewvar(Type*, NodeList**, Node**);
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, Type**, NodeList*, int, NodeList**);
+static NodeList* ascompatte(int, int, Type**, NodeList*, int, NodeList**);
static Node* convas(Node*, NodeList**);
static void heapmoves(void);
static NodeList* paramstoheap(Type **argin, int out);
static NodeList* reorder1(NodeList*);
static NodeList* reorder3(NodeList*);
+static Node* addstr(Node*, NodeList**);
+static Node* append(Node*, NodeList**);
static NodeList* walkdefstack;
@@ -134,6 +136,10 @@ walkdeftype(Node *n)
n->diag = 1;
goto ret;
}
+ if(n->type == T) {
+ n->diag = 1;
+ goto ret;
+ }
// copy new type and clear fields
// that don't come along
@@ -257,6 +263,10 @@ walkdef(Node *n)
yyerror("const initializer must be constant");
goto ret;
}
+ if(isconst(e, CTNIL)) {
+ yyerror("const initializer cannot be nil");
+ goto ret;
+ }
t = n->type;
if(t != T) {
convlit(&e, t);
@@ -281,6 +291,13 @@ walkdef(Node *n)
if(n->defn == N) {
if(n->etype != 0) // like OPRINTN
break;
+ if(nerrors > 0) {
+ // Can have undefined variables in x := foo
+ // that make x have an n->ndefn == nil.
+ // If there are other errors anyway, don't
+ // bother adding to the noise.
+ break;
+ }
fatal("var without type, init: %S", n->sym);
}
if(n->defn->op == ONAME) {
@@ -292,10 +309,14 @@ walkdef(Node *n)
break;
case OTYPE:
+ if(curfn)
+ defercheckwidth();
n->walkdef = 1;
n->type = typ(TFORW);
n->type->sym = n->sym;
walkdeftype(n);
+ if(curfn)
+ resumecheckwidth();
break;
case OPACK:
@@ -354,7 +375,7 @@ walkstmt(Node **np)
NodeList *init;
NodeList *ll, *rl;
int cl, lno;
- Node *n;
+ Node *n, *f;
n = *np;
if(n == N)
@@ -481,11 +502,19 @@ walkstmt(Node **np)
n->list = nil;
break;
}
+ if(count(n->list) == 1 && count(rl) > 1) {
+ // 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);
+ n->list = concat(list1(f), ascompatet(n->op, rl, &f->type, 0, &n->ninit));
+ break;
+ }
ll = ascompatee(n->op, rl, n->list, &n->ninit);
n->list = reorder3(ll);
break;
}
- ll = ascompatte(n->op, getoutarg(curfn->type), n->list, 1, &n->ninit);
+ ll = ascompatte(n->op, 0, getoutarg(curfn->type), n->list, 1, &n->ninit);
n->list = ll;
break;
@@ -542,6 +571,7 @@ walkexpr(Node **np, NodeList **init)
NodeList *ll, *lr, *lpost;
Type *t;
int et;
+ int64 v, v1, v2, len;
int32 lno;
Node *n, *fn;
char buf[100], *p;
@@ -594,8 +624,6 @@ walkexpr(Node **np, NodeList **init)
case OMINUS:
case OPLUS:
case OCOM:
- case OLEN:
- case OCAP:
case OREAL:
case OIMAG:
case ODOT:
@@ -606,13 +634,27 @@ walkexpr(Node **np, NodeList **init)
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;
+ if(isptr[t->etype])
+ t = t->type;
+ if(isfixedarray(t)) {
+ safeexpr(n->left, init);
+ nodconst(n, n->type, t->bound);
+ n->typecheck = 1;
+ }
+ goto ret;
+
case OLSH:
case ORSH:
case OAND:
case OOR:
case OXOR:
- case OANDAND:
- case OOROR:
case OSUB:
case OMUL:
case OEQ:
@@ -626,6 +668,17 @@ walkexpr(Node **np, NodeList **init)
walkexpr(&n->left, init);
walkexpr(&n->right, init);
goto ret;
+
+ case OANDAND:
+ case OOROR:
+ walkexpr(&n->left, init);
+ // cannot put side effects from n->right on init,
+ // because they cannot run before n->left is checked.
+ // save elsewhere and store on the eventual n->right.
+ ll = nil;
+ walkexpr(&n->right, &ll);
+ n->right->ninit = concat(n->right->ninit, ll);
+ goto ret;
case OPRINT:
case OPRINTN:
@@ -656,7 +709,7 @@ walkexpr(Node **np, NodeList **init)
goto ret;
walkexpr(&n->left, init);
walkexprlist(n->list, init);
- ll = ascompatte(n->op, getinarg(t), n->list, 0, init);
+ ll = ascompatte(n->op, n->isddd, getinarg(t), n->list, 0, init);
n->list = reorder1(ll);
goto ret;
@@ -666,7 +719,7 @@ walkexpr(Node **np, NodeList **init)
goto ret;
walkexpr(&n->left, init);
walkexprlist(n->list, init);
- ll = ascompatte(n->op, getinarg(t), n->list, 0, init);
+ ll = ascompatte(n->op, n->isddd, getinarg(t), n->list, 0, init);
n->list = reorder1(ll);
if(isselect(n)) {
// special prob with selectsend and selectrecv:
@@ -676,7 +729,7 @@ walkexpr(Node **np, NodeList **init)
Node *b;
b = nodbool(0);
typecheck(&b, Erv);
- lr = ascompatte(n->op, getoutarg(t), list1(b), 0, init);
+ lr = ascompatte(n->op, 0, getoutarg(t), list1(b), 0, init);
n->list = concat(n->list, lr);
}
goto ret;
@@ -687,8 +740,8 @@ walkexpr(Node **np, NodeList **init)
goto ret;
walkexpr(&n->left, init);
walkexprlist(n->list, init);
- ll = ascompatte(n->op, getinarg(t), n->list, 0, init);
- lr = ascompatte(n->op, getthis(t), list1(n->left->left), 0, 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 = concat(ll, lr);
n->left->left = N;
ullmancalc(n->left);
@@ -882,43 +935,55 @@ walkexpr(Node **np, NodeList **init)
case OCONV:
case OCONVNOP:
if(thechar == '5') {
- if(isfloat[n->left->type->etype] &&
- (n->type->etype == TINT64 || n->type->etype == TUINT64)) {
- n = mkcall("float64toint64", n->type, init, conv(n->left, types[TFLOAT64]));
- goto ret;
+ if(isfloat[n->left->type->etype]) {
+ if(n->type->etype == TINT64) {
+ n = mkcall("float64toint64", n->type, init, conv(n->left, types[TFLOAT64]));
+ goto ret;
+ }
+ if(n->type->etype == TUINT64) {
+ n = mkcall("float64touint64", n->type, init, conv(n->left, types[TFLOAT64]));
+ goto ret;
+ }
}
- if((n->left->type->etype == TINT64 || n->left->type->etype == TUINT64) &&
- isfloat[n->type->etype]) {
- n = mkcall("int64tofloat64", n->type, init, conv(n->left, types[TINT64]));
- goto ret;
+ if(isfloat[n->type->etype]) {
+ if(n->left->type->etype == TINT64) {
+ n = mkcall("int64tofloat64", n->type, init, conv(n->left, types[TINT64]));
+ goto ret;
+ }
+ if(n->left->type->etype == TUINT64) {
+ n = mkcall("uint64tofloat64", n->type, init, conv(n->left, types[TUINT64]));
+ goto ret;
+ }
}
}
walkexpr(&n->left, init);
goto ret;
case OASOP:
- n->left = safeexpr(n->left, init);
- walkexpr(&n->left, init);
- l = n->left;
- walkexpr(&n->right, init);
if(n->etype == OANDNOT) {
n->etype = OAND;
n->right = nod(OCOM, n->right, N);
typecheck(&n->right, Erv);
}
+ n->left = safeexpr(n->left, init);
+ walkexpr(&n->left, init);
+ l = n->left;
+ walkexpr(&n->right, init);
/*
* on 32-bit arch, rewrite 64-bit ops into l = l op r.
* on 386, rewrite float ops into l = l op r.
* everywhere, rewrite map ops into l = l op r.
* everywhere, rewrite string += into l = l op r.
+ * everywhere, rewrite complex /= into l = l op r.
* TODO(rsc): Maybe this rewrite should be done always?
*/
et = n->left->type->etype;
if((widthptr == 4 && (et == TUINT64 || et == TINT64)) ||
(thechar == '8' && isfloat[et]) ||
l->op == OINDEXMAP ||
- et == TSTRING) {
+ et == TSTRING ||
+ (iscomplex[et] && n->etype == ODIV)) {
l = safeexpr(n->left, init);
a = l;
if(a->op == OINDEXMAP) {
@@ -952,9 +1017,11 @@ walkexpr(Node **np, NodeList **init)
*/
et = n->left->type->etype;
if(iscomplex[et] && n->op == ODIV) {
- n = mkcall("complex128div", n->type, init,
+ t = n->type;
+ n = mkcall("complex128div", types[TCOMPLEX128], init,
conv(n->left, types[TCOMPLEX128]),
conv(n->right, types[TCOMPLEX128]));
+ n = conv(n, t);
goto ret;
}
/*
@@ -981,11 +1048,36 @@ walkexpr(Node **np, NodeList **init)
// if range of type cannot exceed static array bound,
// disable bounds check
- if(!isslice(n->left->type))
+ if(isfixedarray(n->left->type))
if(n->right->type->width < 4)
if((1<<(8*n->right->type->width)) <= n->left->type->bound)
n->etype = 1;
+ if(isconst(n->left, CTSTR))
+ if(n->right->type->width < 4)
+ if((1<<(8*n->right->type->width)) <= n->left->val.u.sval->len)
+ n->etype = 1;
+
+ // check for static out of bounds
+ if(isconst(n->right, CTINT) && !n->etype) {
+ v = mpgetfix(n->right->val.u.xval);
+ len = 1LL<<60;
+ t = n->left->type;
+ if(isconst(n->left, CTSTR))
+ len = n->left->val.u.sval->len;
+ if(t != T && isptr[t->etype])
+ t = t->type;
+ if(isfixedarray(t))
+ len = t->bound;
+ if(v < 0 || v >= (1LL<<31) || v >= len)
+ yyerror("index out of bounds");
+ else if(isconst(n->left, CTSTR)) {
+ // replace "abc"[2] with 'b'.
+ // delayed until now because "abc"[2] is not
+ // an ideal constant.
+ nodconst(n, n->type, n->left->val.u.sval->s[v]);
+ }
+ }
goto ret;
case OINDEXMAP:
@@ -1002,24 +1094,61 @@ walkexpr(Node **np, NodeList **init)
goto ret;
case OSLICE:
+ case OSLICEARR:
walkexpr(&n->left, init);
n->left = safeexpr(n->left, init);
walkexpr(&n->right->left, init);
n->right->left = safeexpr(n->right->left, init);
walkexpr(&n->right->right, init);
n->right->right = safeexpr(n->right->right, init);
+
+ len = 1LL<<60;
+ t = n->left->type;
+ if(t != T && isptr[t->etype])
+ t = t->type;
+ if(isfixedarray(t))
+ len = t->bound;
+
+ // check for static out of bounds
+ // NOTE: v > len not v >= len.
+ v1 = -1;
+ v2 = -1;
+ if(isconst(n->right->left, CTINT)) {
+ v1 = mpgetfix(n->right->left->val.u.xval);
+ if(v1 < 0 || v1 >= (1LL<<31) || v1 > len) {
+ yyerror("slice index out of bounds");
+ v1 = -1;
+ }
+ }
+ if(isconst(n->right->right, CTINT)) {
+ v2 = mpgetfix(n->right->right->val.u.xval);
+ if(v2 < 0 || v2 >= (1LL<<31) || v2 > len) {
+ yyerror("slice index out of bounds");
+ v2 = -1;
+ }
+ }
+ if(v1 >= 0 && v2 >= 0 && v1 > v2)
+ yyerror("inverted slice range");
+
+ if(n->op == OSLICEARR)
+ goto slicearray;
+
// dynamic slice
- // sliceslice(old []any, lb int, hb int, width int) (ary []any)
- // sliceslice1(old []any, lb int, width int) (ary []any)
+ // sliceslice(old []any, lb uint64, hb uint64, width uint64) (ary []any)
+ // sliceslice1(old []any, lb uint64, width uint64) (ary []any)
t = n->type;
+ if(n->right->left == N)
+ l = nodintconst(0);
+ else
+ l = conv(n->right->left, types[TUINT64]);
if(n->right->right != N) {
fn = syslook("sliceslice", 1);
argtype(fn, t->type); // any-1
argtype(fn, t->type); // any-2
n = mkcall1(fn, t, init,
n->left,
- conv(n->right->left, types[TINT]),
- conv(n->right->right, types[TINT]),
+ l,
+ conv(n->right->right, types[TUINT64]),
nodintconst(t->type->width));
} else {
fn = syslook("sliceslice1", 1);
@@ -1027,47 +1156,33 @@ walkexpr(Node **np, NodeList **init)
argtype(fn, t->type); // any-2
n = mkcall1(fn, t, init,
n->left,
- conv(n->right->left, types[TINT]),
+ l,
nodintconst(t->type->width));
}
goto ret;
- case OSLICEARR:
- walkexpr(&n->left, init);
- n->left = safeexpr(n->left, init);
- walkexpr(&n->right->left, init);
- n->right->left = safeexpr(n->right->left, init);
- walkexpr(&n->right->right, init);
- n->right->right = safeexpr(n->right->right, init);
+ slicearray:
// static slice
- // slicearray(old *any, nel int, lb int, hb int, width int) (ary []any)
+ // slicearray(old *any, uint64 nel, lb uint64, hb uint64, width uint64) (ary []any)
t = n->type;
fn = syslook("slicearray", 1);
- argtype(fn, n->left->type); // any-1
+ argtype(fn, n->left->type->type); // any-1
argtype(fn, t->type); // any-2
+ if(n->right->left == N)
+ l = nodintconst(0);
+ else
+ l = conv(n->right->left, types[TUINT64]);
if(n->right->right == N)
- r = nodintconst(n->left->type->bound);
+ r = nodintconst(n->left->type->type->bound);
else
- r = conv(n->right->right, types[TINT]);
+ r = conv(n->right->right, types[TUINT64]);
n = mkcall1(fn, t, init,
- nod(OADDR, n->left, N), nodintconst(n->left->type->bound),
- conv(n->right->left, types[TINT]),
+ n->left, nodintconst(n->left->type->type->bound),
+ l,
r,
nodintconst(t->type->width));
goto ret;
- case OCONVSLICE:
- // slicearray(old *any, nel int, lb int, hb int, width int) (ary []any)
- fn = syslook("slicearray", 1);
- argtype(fn, n->left->type->type); // any-1
- argtype(fn, n->type->type); // any-2
- n = mkcall1(fn, n->type, init, n->left,
- nodintconst(n->left->type->type->bound),
- nodintconst(0),
- nodintconst(n->left->type->type->bound),
- nodintconst(n->type->type->width));
- goto ret;
-
case OADDR:;
Node *nvar, *nstar;
@@ -1118,46 +1233,62 @@ walkexpr(Node **np, NodeList **init)
goto ret;
}
+ // prepare for rewrite below
+ if(n->etype == OEQ || n->etype == ONE) {
+ n->left = cheapexpr(n->left, init);
+ n->right = cheapexpr(n->right, init);
+ }
+
// sys_cmpstring(s1, s2) :: 0
r = mkcall("cmpstring", types[TINT], init,
conv(n->left, types[TSTRING]),
conv(n->right, types[TSTRING]));
r = nod(n->etype, r, nodintconst(0));
+
+ // quick check of len before full compare for == or !=
+ if(n->etype == OEQ || n->etype == ONE) {
+ if(n->etype == OEQ)
+ r = nod(OANDAND, nod(OEQ, nod(OLEN, n->left, N), nod(OLEN, n->right, N)), r);
+ else
+ r = nod(OOROR, nod(ONE, nod(OLEN, n->left, N), nod(OLEN, n->right, N)), r);
+ typecheck(&r, Erv);
+ walkexpr(&r, nil);
+ }
typecheck(&r, Erv);
n = r;
goto ret;
case OADDSTR:
- // sys_catstring(s1, s2)
- n = mkcall("catstring", n->type, init,
- conv(n->left, types[TSTRING]),
- conv(n->right, types[TSTRING]));
+ n = addstr(n, init);
goto ret;
case OSLICESTR:
// sys_slicestring(s, lb, hb)
+ if(n->right->left == N)
+ l = nodintconst(0);
+ else
+ l = conv(n->right->left, types[TINT]);
if(n->right->right) {
n = mkcall("slicestring", n->type, init,
conv(n->left, types[TSTRING]),
- conv(n->right->left, types[TINT]),
+ l,
conv(n->right->right, types[TINT]));
} else {
n = mkcall("slicestring1", n->type, init,
conv(n->left, types[TSTRING]),
- conv(n->right->left, types[TINT]));
+ l);
}
goto ret;
-
- case OINDEXSTR:
- // TODO(rsc): should be done in back end
- // sys_indexstring(s, i)
- n = mkcall("indexstring", n->type, init,
- conv(n->left, types[TSTRING]),
- conv(n->right, types[TINT]));
+
+ case OAPPEND:
+ n = append(n, init);
goto ret;
case OCOPY:
- fn = syslook("slicecopy", 1);
+ if(n->right->type->etype == TSTRING)
+ fn = syslook("slicestringcopy", 1);
+ else
+ fn = syslook("slicecopy", 1);
argtype(fn, n->left->type);
argtype(fn, n->right->type);
n = mkcall1(fn, n->type, init,
@@ -1441,47 +1572,51 @@ mkdotargslice(NodeList *lr0, NodeList *nn, Type *l, int fp, NodeList **init)
/*
* helpers for shape errors
*/
-static void
+static char*
dumptypes(Type **nl, char *what)
{
int first;
Type *l;
Iter savel;
+ Fmt fmt;
+ fmtstrinit(&fmt);
+ fmtprint(&fmt, "\t");
l = structfirst(&savel, nl);
- print("\t");
first = 1;
for(l = structfirst(&savel, nl); l != T; l = structnext(&savel)) {
if(first)
first = 0;
else
- print(", ");
- print("%T", l);
+ fmtprint(&fmt, ", ");
+ fmtprint(&fmt, "%T", l);
}
if(first)
- print("[no arguments %s]", what);
- print("\n");
+ fmtprint(&fmt, "[no arguments %s]", what);
+ return fmtstrflush(&fmt);
}
-static void
+static char*
dumpnodetypes(NodeList *l, char *what)
{
int first;
Node *r;
+ Fmt fmt;
- print("\t");
+ fmtstrinit(&fmt);
+ fmtprint(&fmt, "\t");
first = 1;
for(; l; l=l->next) {
r = l->n;
if(first)
first = 0;
else
- print(", ");
- print("%T", r->type);
+ fmtprint(&fmt, ", ");
+ fmtprint(&fmt, "%T", r->type);
}
if(first)
- print("[no arguments %s]", what);
- print("\n");
+ fmtprint(&fmt, "[no arguments %s]", what);
+ return fmtstrflush(&fmt);
}
/*
@@ -1491,12 +1626,13 @@ dumpnodetypes(NodeList *l, char *what)
* func(expr-list)
*/
static NodeList*
-ascompatte(int op, Type **nl, NodeList *lr, int fp, NodeList **init)
+ascompatte(int op, int isddd, Type **nl, NodeList *lr, int fp, NodeList **init)
{
Type *l, *ll;
Node *r, *a;
NodeList *nn, *lr0, *alist;
Iter savel;
+ char *l1, *l2;
lr0 = lr;
l = structfirst(&savel, nl);
@@ -1545,7 +1681,7 @@ loop:
// only if we are assigning a single ddd
// argument to a ddd parameter then it is
// passed thru unencapsulated
- if(r != N && lr->next == nil && r->isddd && eqtype(l->type, r->type)) {
+ if(r != N && lr->next == nil && isddd && eqtype(l->type, r->type)) {
a = nod(OAS, nodarg(l, fp), r);
a = convas(a, init);
nn = list(nn, a);
@@ -1561,12 +1697,12 @@ loop:
if(l == T || r == N) {
if(l != T || r != N) {
+ l1 = dumptypes(nl, "expected");
+ l2 = dumpnodetypes(lr0, "given");
if(l != T)
- yyerror("not enough arguments to %O", op);
+ yyerror("not enough arguments to %O\n%s\n%s", op, l1, l2);
else
- yyerror("too many arguments to %O", op);
- dumptypes(nl, "expected");
- dumpnodetypes(lr0, "given");
+ yyerror("too many arguments to %O\n%s\n%s", op, l1, l2);
}
goto ret;
}
@@ -1740,7 +1876,7 @@ walkprint(Node *nn, NodeList **init, int defer)
if(defer) {
if(op == OPRINTN)
fmtprint(&fmt, "\n");
- on = syslook("printf", 1);
+ on = syslook("goprintf", 1);
on->type = functype(nil, intypes, nil);
args->n = nod(OLITERAL, N, N);
args->n->val.ctype = CTSTR;
@@ -1769,7 +1905,7 @@ callnew(Type *t)
Node *fn;
dowidth(t);
- fn = syslook("mal", 1);
+ fn = syslook("new", 1);
argtype(fn, t);
return mkcall1(fn, ptrto(t), nil, nodintconst(t->width));
}
@@ -2046,12 +2182,17 @@ static void
heapmoves(void)
{
NodeList *nn;
-
+ int32 lno;
+
+ lno = lineno;
+ lineno = curfn->lineno;
nn = paramstoheap(getthis(curfn->type), 0);
nn = concat(nn, paramstoheap(getinarg(curfn->type), 0));
nn = concat(nn, paramstoheap(getoutarg(curfn->type), 1));
curfn->enter = concat(curfn->enter, nn);
+ lineno = curfn->endlineno;
curfn->exit = returnsfromheap(getoutarg(curfn->type));
+ lineno = lno;
}
static Node*
@@ -2143,3 +2284,83 @@ mapfn(char *name, Type *t)
argtype(fn, t->type);
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
+ count++; // r
+
+ // prepare call of runtime.catstring of type int, string, string, string
+ // with as many strings as we have.
+ cat = syslook("concatstring", 1);
+ cat->type = T;
+ cat->ntype = nod(OTFUNC, N, N);
+ in = list1(nod(ODCLFIELD, N, typenod(types[TINT]))); // count
+ typstr = typenod(types[TSTRING]);
+ for(i=0; i<count; i++)
+ in = list(in, nod(ODCLFIELD, N, typstr));
+ cat->ntype->list = in;
+ cat->ntype->rlist = list1(nod(ODCLFIELD, N, typstr));
+
+ args = nil;
+ for(r=n; r->op == OADDSTR; r=r->left)
+ args = concat(list1(conv(r->right, types[TSTRING])), args);
+ args = concat(list1(conv(r, types[TSTRING])), args);
+ args = concat(list1(nodintconst(count)), args);
+
+ r = nod(OCALL, cat, N);
+ r->list = args;
+ typecheck(&r, Erv);
+ walkexpr(&r, init);
+ r->type = n->type;
+
+ return r;
+}
+
+static Node*
+append(Node *n, NodeList **init)
+{
+ int i, j;
+ Node *f, *r;
+ NodeList *in, *args;
+
+ if(n->isddd) {
+ f = syslook("appendslice", 1);
+ argtype(f, n->type);
+ argtype(f, n->type->type);
+ argtype(f, n->type);
+ r = mkcall1(f, n->type, init, typename(n->type), n->list->n, n->list->next->n);
+ return r;
+ }
+
+ j = count(n->list) - 1;
+ f = syslook("append", 1);
+ f->type = T;
+ f->ntype = nod(OTFUNC, N, N);
+ in = list1(nod(ODCLFIELD, N, typenod(ptrto(types[TUINT8])))); // type
+ in = list(in, nod(ODCLFIELD, N, typenod(types[TINT]))); // count
+ in = list(in, nod(ODCLFIELD, N, typenod(n->type))); // slice
+ for(i=0; i<j; i++)
+ in = list(in, nod(ODCLFIELD, N, typenod(n->type->type)));
+ f->ntype->list = in;
+ f->ntype->rlist = list1(nod(ODCLFIELD, N, typenod(n->type)));
+
+ args = list1(typename(n->type));
+ args = list(args, nodintconst(j));
+ args = concat(args, n->list);
+
+ r = nod(OCALL, f, N);
+ r->list = args;
+ typecheck(&r, Erv);
+ walkexpr(&r, init);
+ r->type = n->type;
+
+ return r;
+}
diff --git a/src/cmd/godefs/Makefile b/src/cmd/godefs/Makefile
index 49244f152..b5c76fb0f 100644
--- a/src/cmd/godefs/Makefile
+++ b/src/cmd/godefs/Makefile
@@ -2,7 +2,8 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.conf
+include ../../Make.inc
+O:=$(HOST_O)
TARG=godefs
OFILES=\
@@ -12,13 +13,4 @@ OFILES=\
HFILES=a.h
-$(TARG): $(OFILES)
- $(LD) -o $(TARG) -L"$(GOROOT)"/lib $(OFILES) -lbio -l9
-
-clean:
- rm -f *.$O $(TARG)
-
-install: $(TARG)
- cp $(TARG) "$(GOBIN)"/$(TARG)
-
-$(OFILES): $(HFILES)
+include ../../Make.ccmd
diff --git a/src/cmd/godefs/main.c b/src/cmd/godefs/main.c
index 6ff542f48..69ee1be5d 100644
--- a/src/cmd/godefs/main.c
+++ b/src/cmd/godefs/main.c
@@ -82,7 +82,7 @@
#include "a.h"
-#ifdef __MINGW32__
+#ifdef _WIN32
int
spawn(char *prog, char **argv)
{
@@ -133,7 +133,7 @@ Lang go =
"type %s struct {\n",
"type %s struct {\n",
- "\tPad%d [%d]byte;\n",
+ "\tPad_godefs_%d [%d]byte;\n",
"}\n",
gotypefmt,
@@ -150,7 +150,7 @@ Lang c =
"typedef struct %s %s;\nstruct %s {\n",
"typedef union %s %s;\nunion %s {\n",
- "\tbyte pad%d[%d];\n",
+ "\tbyte pad_godefs_%d[%d];\n",
"};\n",
ctypefmt,
@@ -373,6 +373,8 @@ Continue:
prefix = prefixlen(t);
for(j=0; j<t->nf; j++) {
f = &t->f[j];
+ if(f->type->kind == 0)
+ continue;
// padding
if(t->kind == Struct || lang == &go) {
if(f->offset%8 != 0 || f->size%8 != 0) {
@@ -391,7 +393,7 @@ Continue:
if(cutprefix(name))
name += prefix;
if(strcmp(name, "") == 0) {
- snprint(nambuf, sizeof nambuf, "Pad%d", npad++);
+ snprint(nambuf, sizeof nambuf, "Pad_godefs_%d", npad++);
name = nambuf;
}
Bprint(bout, "\t%#lT;\n", name, f->type);
diff --git a/src/cmd/godefs/stabs.c b/src/cmd/godefs/stabs.c
index 8d3be1913..1bc96d4c8 100644
--- a/src/cmd/godefs/stabs.c
+++ b/src/cmd/godefs/stabs.c
@@ -363,13 +363,22 @@ parsedef(char **pp, char *name)
return nil;
}
+ while(f->type->kind == Typedef)
+ f->type = f->type->type;
+ 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;
+ }
+
// rewrite
// uint32 x : 8;
// into
// uint8 x;
// hooray for bitfields.
- while(f->type->kind == Typedef)
- f->type = f->type->type;
while(Int16 <= f->type->kind && f->type->kind <= Uint64 && kindsize[f->type->kind] > f->size) {
tt = emalloc(sizeof *tt);
*tt = *f->type;
diff --git a/src/cmd/godoc/Makefile b/src/cmd/godoc/Makefile
index d799219dd..c4e0fd9f9 100644
--- a/src/cmd/godoc/Makefile
+++ b/src/cmd/godoc/Makefile
@@ -2,16 +2,19 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=godoc
GOFILES=\
codewalk.go\
+ dirtrees.go\
+ format.go\
godoc.go\
index.go\
main.go\
mapping.go\
snippet.go\
spec.go\
+ utils.go\
include ../../Make.cmd
diff --git a/src/cmd/godoc/codewalk.go b/src/cmd/godoc/codewalk.go
index 806849c00..bda63a9f6 100644
--- a/src/cmd/godoc/codewalk.go
+++ b/src/cmd/godoc/codewalk.go
@@ -31,26 +31,26 @@ import (
// Handler for /doc/codewalk/ and below.
-func codewalk(c *http.Conn, r *http.Request) {
+func codewalk(w http.ResponseWriter, r *http.Request) {
relpath := r.URL.Path[len("/doc/codewalk/"):]
abspath := absolutePath(r.URL.Path[1:], *goroot)
r.ParseForm()
if f := r.FormValue("fileprint"); f != "" {
- codewalkFileprint(c, r, f)
+ codewalkFileprint(w, r, f)
return
}
// If directory exists, serve list of code walks.
dir, err := os.Lstat(abspath)
if err == nil && dir.IsDirectory() {
- codewalkDir(c, r, relpath, abspath)
+ codewalkDir(w, r, relpath, abspath)
return
}
// If file exists, serve using standard file server.
if err == nil {
- serveFile(c, r)
+ serveFile(w, r)
return
}
@@ -58,18 +58,18 @@ func codewalk(c *http.Conn, r *http.Request) {
// a codewalk description.
cw, err := loadCodewalk(abspath + ".xml")
if err != nil {
- log.Stderr(err)
- serveError(c, r, relpath, err)
+ log.Print(err)
+ serveError(w, r, relpath, err)
return
}
// Canonicalize the path and redirect if changed
- if redirect(c, r) {
+ if redirect(w, r) {
return
}
b := applyTemplate(codewalkHTML, "codewalk", cw)
- servePage(c, "Codewalk: "+cw.Title, "", "", b)
+ servePage(w, "Codewalk: "+cw.Title, "", "", b)
}
@@ -178,7 +178,7 @@ func loadCodewalk(file string) (*Codewalk, os.Error) {
// codewalkDir serves the codewalk directory listing.
// It scans the directory for subdirectories or files named *.xml
// and prepares a table.
-func codewalkDir(c *http.Conn, r *http.Request, relpath, abspath string) {
+func codewalkDir(w http.ResponseWriter, r *http.Request, relpath, abspath string) {
type elem struct {
Name string
Title string
@@ -186,8 +186,8 @@ func codewalkDir(c *http.Conn, r *http.Request, relpath, abspath string) {
dir, err := ioutil.ReadDir(abspath)
if err != nil {
- log.Stderr(err)
- serveError(c, r, relpath, err)
+ log.Print(err)
+ serveError(w, r, relpath, err)
return
}
var v vector.Vector
@@ -204,7 +204,7 @@ func codewalkDir(c *http.Conn, r *http.Request, relpath, abspath string) {
}
b := applyTemplate(codewalkdirHTML, "codewalkdir", v)
- servePage(c, "Codewalks", "", "", b)
+ servePage(w, "Codewalks", "", "", b)
}
@@ -214,11 +214,12 @@ func codewalkDir(c *http.Conn, r *http.Request, relpath, abspath string) {
// in the response. This format is used for the middle window pane
// of the codewalk pages. It is a separate iframe and does not get
// the usual godoc HTML wrapper.
-func codewalkFileprint(c *http.Conn, r *http.Request, f string) {
+func codewalkFileprint(w http.ResponseWriter, r *http.Request, f string) {
abspath := absolutePath(f, *goroot)
data, err := ioutil.ReadFile(abspath)
if err != nil {
- serveError(c, r, f, err)
+ log.Print(err)
+ serveError(w, r, f, err)
return
}
lo, _ := strconv.Atoi(r.FormValue("lo"))
@@ -242,17 +243,17 @@ func codewalkFileprint(c *http.Conn, r *http.Request, f string) {
}
}
- io.WriteString(c, `<style type="text/css">@import "/doc/codewalk/codewalk.css";</style><pre>`)
- template.HTMLEscape(c, data[0:mark])
- io.WriteString(c, "<a name='mark'></a>")
- template.HTMLEscape(c, data[mark:lo])
+ io.WriteString(w, `<style type="text/css">@import "/doc/codewalk/codewalk.css";</style><pre>`)
+ template.HTMLEscape(w, data[0:mark])
+ io.WriteString(w, "<a name='mark'></a>")
+ template.HTMLEscape(w, data[mark:lo])
if lo < hi {
- io.WriteString(c, "<div class='codewalkhighlight'>")
- template.HTMLEscape(c, data[lo:hi])
- io.WriteString(c, "</div>")
+ io.WriteString(w, "<div class='codewalkhighlight'>")
+ template.HTMLEscape(w, data[lo:hi])
+ io.WriteString(w, "</div>")
}
- template.HTMLEscape(c, data[hi:])
- io.WriteString(c, "</pre>")
+ template.HTMLEscape(w, data[hi:])
+ io.WriteString(w, "</pre>")
}
@@ -450,13 +451,13 @@ func addrRegexp(data []byte, lo, hi int, dir byte, pattern string) (int, int, os
// through file, but that seems like overkill.
return 0, 0, os.NewError("reverse search not implemented")
}
- m := re.Execute(data[hi:])
+ m := re.FindIndex(data[hi:])
if len(m) > 0 {
m[0] += hi
m[1] += hi
} else if hi > 0 {
// No match. Wrap to beginning of data.
- m = re.Execute(data)
+ m = re.FindIndex(data)
}
if len(m) == 0 {
return 0, 0, os.NewError("no match for " + pattern)
diff --git a/src/cmd/godoc/dirtrees.go b/src/cmd/godoc/dirtrees.go
new file mode 100644
index 000000000..edb4a169d
--- /dev/null
+++ b/src/cmd/godoc/dirtrees.go
@@ -0,0 +1,341 @@
+// Copyright 2010 The Go 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 dealing with package directory trees.
+
+package main
+
+import (
+ "bytes"
+ "go/doc"
+ "go/parser"
+ "go/token"
+ "io/ioutil"
+ "os"
+ pathutil "path"
+ "strings"
+ "unicode"
+)
+
+
+type Directory struct {
+ Depth int
+ Path string // includes Name
+ Name string
+ Text string // package documentation, if any
+ Dirs []*Directory // subdirectories
+}
+
+
+func isGoFile(f *os.FileInfo) bool {
+ return f.IsRegular() &&
+ !strings.HasPrefix(f.Name, ".") && // ignore .files
+ pathutil.Ext(f.Name) == ".go"
+}
+
+
+func isPkgFile(f *os.FileInfo) bool {
+ return isGoFile(f) &&
+ !strings.HasSuffix(f.Name, "_test.go") // ignore test files
+}
+
+
+func isPkgDir(f *os.FileInfo) bool {
+ return f.IsDirectory() && len(f.Name) > 0 && f.Name[0] != '_'
+}
+
+
+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
+}
+
+
+func (b *treeBuilder) newDirTree(fset *token.FileSet, path, name string, depth int) *Directory {
+ if b.pathFilter != nil && !b.pathFilter(path) {
+ return nil
+ }
+
+ if depth >= b.maxDepth {
+ // 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}
+ }
+
+ list, _ := ioutil.ReadDir(path) // ignore errors
+
+ // determine number of subdirectories and if there are package files
+ ndirs := 0
+ hasPkgFiles := false
+ var synopses [4]string // prioritized package documentation (0 == highest priority)
+ for _, d := range list {
+ switch {
+ case isPkgDir(d):
+ ndirs++
+ case isPkgFile(d):
+ // looks like a package file, but may just be a file ending in ".go";
+ // don't just count it yet (otherwise we may end up with hasPkgFiles even
+ // 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, pathutil.Join(path, d.Name), nil,
+ parser.ParseComments|parser.PackageClauseOnly)
+ if err == nil {
+ hasPkgFiles = true
+ if file.Doc != nil {
+ // prioritize documentation
+ i := -1
+ switch file.Name.Name {
+ case name:
+ i = 0 // normal case: directory name matches package name
+ case fakePkgName:
+ i = 1 // synopses for commands
+ case "main":
+ i = 2 // directory contains a main package
+ default:
+ i = 3 // none of the above
+ }
+ if 0 <= i && i < len(synopses) && synopses[i] == "" {
+ synopses[i] = firstSentence(doc.CommentText(file.Doc))
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // create subdirectory tree
+ var dirs []*Directory
+ if ndirs > 0 {
+ dirs = make([]*Directory, ndirs)
+ i := 0
+ for _, d := range list {
+ if isPkgDir(d) {
+ dd := b.newDirTree(fset, pathutil.Join(path, d.Name), d.Name, depth+1)
+ if dd != nil {
+ dirs[i] = dd
+ i++
+ }
+ }
+ }
+ dirs = dirs[0:i]
+ }
+
+ // if there are no package files and no subdirectories
+ // containing package files, ignore the directory
+ if !hasPkgFiles && len(dirs) == 0 {
+ return nil
+ }
+
+ // select the highest-priority synopsis for the directory entry, if any
+ synopsis := ""
+ for _, synopsis = range synopses {
+ if synopsis != "" {
+ break
+ }
+ }
+
+ return &Directory{depth, path, name, synopsis, dirs}
+}
+
+
+// newDirectory creates a new package directory tree with at most maxDepth
+// levels, anchored at root. The result tree is pruned such that it only
+// contains directories that contain package files or that contain
+// subdirectories containing package files (transitively). If a non-nil
+// pathFilter is provided, directory paths additionally must be accepted
+// by the filter (i.e., pathFilter(path) must be true). If a value >= 0 is
+// provided for maxDepth, nodes at larger depths are pruned as well; they
+// 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 {
+ d, err := os.Lstat(root)
+ if err != nil || !isPkgDir(d) {
+ return nil
+ }
+ if maxDepth < 0 {
+ maxDepth = 1e6 // "infinity"
+ }
+ b := treeBuilder{pathFilter, maxDepth}
+ // the file set provided is only for local parsing, no position
+ // information escapes and thus we don't need to save the set
+ return b.newDirTree(token.NewFileSet(), root, d.Name, 0)
+}
+
+
+func (dir *Directory) writeLeafs(buf *bytes.Buffer) {
+ if dir != nil {
+ if len(dir.Dirs) == 0 {
+ buf.WriteString(dir.Path)
+ buf.WriteByte('\n')
+ return
+ }
+
+ for _, d := range dir.Dirs {
+ d.writeLeafs(buf)
+ }
+ }
+}
+
+
+func (dir *Directory) walk(c chan<- *Directory, skipRoot bool) {
+ if dir != nil {
+ if !skipRoot {
+ c <- dir
+ }
+ for _, d := range dir.Dirs {
+ d.walk(c, false)
+ }
+ }
+}
+
+
+func (dir *Directory) iter(skipRoot bool) <-chan *Directory {
+ c := make(chan *Directory)
+ go func() {
+ dir.walk(c, skipRoot)
+ close(c)
+ }()
+ return c
+}
+
+
+func (dir *Directory) lookupLocal(name string) *Directory {
+ for _, d := range dir.Dirs {
+ if d.Name == name {
+ return d
+ }
+ }
+ return nil
+}
+
+
+// lookup looks for the *Directory for a given path, relative to dir.
+func (dir *Directory) lookup(path string) *Directory {
+ d := strings.Split(dir.Path, "/", -1)
+ p := strings.Split(path, "/", -1)
+ i := 0
+ for i < len(d) {
+ if i >= len(p) || d[i] != p[i] {
+ return nil
+ }
+ i++
+ }
+ for dir != nil && i < len(p) {
+ dir = dir.lookupLocal(p[i])
+ i++
+ }
+ return dir
+}
+
+
+// DirEntry describes a directory entry. The Depth and Height values
+// are useful for presenting an entry in an indented fashion.
+//
+type DirEntry struct {
+ Depth int // >= 0
+ Height int // = DirList.MaxHeight - Depth, > 0
+ Path string // includes Name, relative to DirList root
+ Name string
+ Synopsis string
+}
+
+
+type DirList struct {
+ MaxHeight int // directory tree height, > 0
+ List []DirEntry
+}
+
+
+// listing creates a (linear) directory listing from a directory tree.
+// If skipRoot is set, the root directory itself is excluded from the list.
+//
+func (root *Directory) listing(skipRoot bool) *DirList {
+ if root == nil {
+ return nil
+ }
+
+ // determine number of entries n and maximum height
+ n := 0
+ minDepth := 1 << 30 // infinity
+ maxDepth := 0
+ for d := range root.iter(skipRoot) {
+ n++
+ if minDepth > d.Depth {
+ minDepth = d.Depth
+ }
+ if maxDepth < d.Depth {
+ maxDepth = d.Depth
+ }
+ }
+ maxHeight := maxDepth - minDepth + 1
+
+ if n == 0 {
+ return nil
+ }
+
+ // create list
+ list := make([]DirEntry, n)
+ i := 0
+ for d := range root.iter(skipRoot) {
+ p := &list[i]
+ p.Depth = d.Depth - minDepth
+ p.Height = maxHeight - p.Depth
+ // the path is relative to root.Path - remove the root.Path
+ // prefix (the prefix should always be present but avoid
+ // crashes and check)
+ path := d.Path
+ if strings.HasPrefix(d.Path, root.Path) {
+ path = d.Path[len(root.Path):]
+ }
+ // remove trailing '/' 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
+ i++
+ }
+
+ return &DirList{maxHeight, list}
+}
diff --git a/src/cmd/godoc/doc.go b/src/cmd/godoc/doc.go
index 955ed35bf..02779384c 100644
--- a/src/cmd/godoc/doc.go
+++ b/src/cmd/godoc/doc.go
@@ -24,7 +24,7 @@ godoc first tries localhost:6060 and then http://golang.org.
godoc -q Reader Writer
godoc -q math.Sin
- godoc -server=:6666 -q sin
+ godoc -server=:6060 -q sin
With the -http flag, it runs as a web server and presents the documentation as a
web page.
@@ -45,6 +45,10 @@ The flags are:
print (exported) source in command-line mode
-tabwidth=4
width of tabs in units of spaces
+ -timestamps=true
+ show timestamps with directory listings
+ -fulltext=false
+ build full text index for regular expression queries
-path=""
additional package directories (colon-separated)
-html
@@ -61,6 +65,10 @@ The flags are:
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
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
@@ -76,6 +84,13 @@ 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, it creates a search index from all .go files
under -goroot (excluding files starting with .). The index is created at startup
and is automatically updated every time the -sync command terminates with exit
diff --git a/src/cmd/godoc/format.go b/src/cmd/godoc/format.go
new file mode 100644
index 000000000..f68c67b24
--- /dev/null
+++ b/src/cmd/godoc/format.go
@@ -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.
+
+// This file implements FormatSelections and FormatText.
+// FormatText is used to HTML-format Go and non-Go source
+// text with line numbers and highlighted sections. It is
+// built on top of FormatSelections, a generic formatter
+// for "selected" text.
+
+package main
+
+import (
+ "bytes"
+ "fmt"
+ "go/scanner"
+ "go/token"
+ "io"
+ "regexp"
+ "strconv"
+ "template"
+)
+
+
+// ----------------------------------------------------------------------------
+// Implementation of FormatSelections
+
+// A Selection is a function returning offset pairs []int{a, b}
+// describing consecutive non-overlapping text segments [a, b).
+// If there are no more segments, a Selection must return nil.
+//
+// TODO It's more efficient to return a pair (a, b int) instead
+// of creating lots of slices. Need to determine how to
+// indicate the end of a Selection.
+//
+type Selection func() []int
+
+
+// A LinkWriter writes some start or end "tag" to w for the text offset offs.
+// It is called by FormatSelections at the start or end of each link segment.
+//
+type LinkWriter func(w io.Writer, offs int, start bool)
+
+
+// A SegmentWriter formats a text according to selections and writes it to w.
+// The selections parameter is a bit set indicating which selections provided
+// to FormatSelections overlap with the text segment: If the n'th bit is set
+// in selections, the n'th selection provided to FormatSelections is overlapping
+// with the text.
+//
+type SegmentWriter func(w io.Writer, text []byte, selections int)
+
+
+// FormatSelections takes a text and writes it to w using link and segment
+// writers lw and sw as follows: lw is invoked for consecutive segment starts
+// and ends as specified through the links selection, and sw is invoked for
+// consecutive segments of text overlapped by the same selections as specified
+// by selections. The link writer lw may be nil, in which case the links
+// Selection is ignored.
+//
+func FormatSelections(w io.Writer, text []byte, lw LinkWriter, links Selection, sw SegmentWriter, selections ...Selection) {
+ if lw != nil {
+ selections = append(selections, links)
+ }
+ // compute the sequence of consecutive segment changes
+ changes := newMerger(selections)
+ // The i'th bit in bitset indicates that the text
+ // at the current offset is covered by selections[i].
+ bitset := 0
+ lastOffs := 0
+ for {
+ // get the next segment change
+ index, offs, start := changes.next()
+ if index < 0 || offs > len(text) {
+ // no more segment changes or the next change
+ // is past the end of the text - we're done
+ break
+ }
+ // determine the kind of segment change
+ if index == len(selections)-1 {
+ // we have a link segment change:
+ // format the previous selection segment, write the
+ // link tag and start a new selection segment
+ sw(w, text[lastOffs:offs], bitset)
+ lastOffs = offs
+ lw(w, offs, start)
+ } else {
+ // we have a selection change:
+ // format the previous selection segment, determine
+ // the new selection bitset and start a new segment
+ sw(w, text[lastOffs:offs], bitset)
+ lastOffs = offs
+ mask := 1 << uint(index)
+ if start {
+ bitset |= mask
+ } else {
+ bitset &^= mask
+ }
+ }
+ }
+ sw(w, text[lastOffs:], bitset)
+}
+
+
+// A merger merges a slice of Selections and produces a sequence of
+// consecutive segment change events through repeated next() calls.
+//
+type merger struct {
+ selections []Selection
+ segments [][]int // segments[i] is the next segment of selections[i]
+}
+
+
+const infinity int = 2e9
+
+func newMerger(selections []Selection) *merger {
+ segments := make([][]int, len(selections))
+ for i, sel := range selections {
+ segments[i] = []int{infinity, infinity}
+ if sel != nil {
+ if seg := sel(); seg != nil {
+ segments[i] = seg
+ }
+ }
+ }
+ return &merger{selections, segments}
+}
+
+
+// next returns the next segment change: index specifies the Selection
+// to which the segment belongs, offs is the segment start or end offset
+// as determined by the start value. If there are no more segment changes,
+// next returns an index value < 0.
+//
+func (m *merger) next() (index, offs int, start bool) {
+ // find the next smallest offset where a segment starts or ends
+ offs = infinity
+ index = -1
+ for i, seg := range m.segments {
+ switch {
+ case seg[0] < offs:
+ offs = seg[0]
+ index = i
+ start = true
+ case seg[1] < offs:
+ offs = seg[1]
+ index = i
+ start = false
+ }
+ }
+ if index < 0 {
+ // no offset found => all selections merged
+ return
+ }
+ // offset found - it's either the start or end offset but
+ // either way it is ok to consume the start offset: set it
+ // to infinity so it won't be considered in the following
+ // next call
+ m.segments[index][0] = infinity
+ if start {
+ return
+ }
+ // end offset found - consume it
+ m.segments[index][1] = infinity
+ // advance to the next segment for that selection
+ seg := m.selections[index]()
+ if seg == nil {
+ return
+ }
+ m.segments[index] = seg
+ return
+}
+
+
+// ----------------------------------------------------------------------------
+// Implementation of FormatText
+
+// lineSelection returns the line segments for text as a Selection.
+func lineSelection(text []byte) Selection {
+ i, j := 0, 0
+ return func() (seg []int) {
+ // find next newline, if any
+ for j < len(text) {
+ j++
+ if text[j-1] == '\n' {
+ break
+ }
+ }
+ if i < j {
+ // text[i:j] constitutes a line
+ seg = []int{i, j}
+ i = j
+ }
+ return
+ }
+}
+
+
+// commentSelection returns the sequence of consecutive comments
+// in the Go src text as a Selection.
+//
+func commentSelection(src []byte) Selection {
+ var s scanner.Scanner
+ file := s.Init(token.NewFileSet(), "", src, nil, scanner.ScanComments+scanner.InsertSemis)
+ return func() (seg []int) {
+ for {
+ pos, tok, lit := s.Scan()
+ if tok == token.EOF {
+ break
+ }
+ offs := file.Offset(pos)
+ if tok == token.COMMENT {
+ seg = []int{offs, offs + len(lit)}
+ break
+ }
+ }
+ return
+ }
+}
+
+
+// makeSelection is a helper function to make a Selection from a slice of pairs.
+func makeSelection(matches [][]int) Selection {
+ return func() (seg []int) {
+ if len(matches) > 0 {
+ seg = matches[0]
+ matches = matches[1:]
+ }
+ return
+ }
+}
+
+
+// regexpSelection computes the Selection for the regular expression expr in text.
+func regexpSelection(text []byte, expr string) Selection {
+ var matches [][]int
+ if rx, err := regexp.Compile(expr); err == nil {
+ matches = rx.FindAllIndex(text, -1)
+ }
+ return makeSelection(matches)
+}
+
+
+var selRx = regexp.MustCompile(`^([0-9]+):([0-9]+)`)
+
+// rangeSelection computes the Selection for a text range described
+// by the argument str; the range description must match the selRx
+// regular expression.
+//
+func rangeSelection(str string) Selection {
+ m := selRx.FindStringSubmatch(str)
+ if len(m) >= 2 {
+ from, _ := strconv.Atoi(m[1])
+ to, _ := strconv.Atoi(m[2])
+ if from < to {
+ return makeSelection([][]int{[]int{from, to}})
+ }
+ }
+ return nil
+}
+
+
+// Span tags for all the possible selection combinations that may
+// be generated by FormatText. Selections are indicated by a bitset,
+// and the value of the bitset specifies the tag to be used.
+//
+// bit 0: comments
+// bit 1: highlights
+// bit 2: selections
+//
+var startTags = [][]byte{
+ /* 000 */ []byte(``),
+ /* 001 */ []byte(`<span class ="comment">`),
+ /* 010 */ []byte(`<span class="highlight">`),
+ /* 011 */ []byte(`<span class="highlight-comment">`),
+ /* 100 */ []byte(`<span class="selection">`),
+ /* 101 */ []byte(`<span class="selection-comment">`),
+ /* 110 */ []byte(`<span class="selection-highlight">`),
+ /* 111 */ []byte(`<span class="selection-highlight-comment">`),
+}
+
+var endTag = []byte(`</span>`)
+
+
+func selectionTag(w io.Writer, text []byte, selections int) {
+ if len(text) > 0 {
+ if selections < len(startTags) {
+ if tag := startTags[selections]; len(tag) > 0 {
+ w.Write(tag)
+ template.HTMLEscape(w, text)
+ w.Write(endTag)
+ return
+ }
+ }
+ template.HTMLEscape(w, text)
+ }
+}
+
+
+// FormatText HTML-escapes text and returns it wrapped in <pre> tags.
+// Conscutive text segments are wrapped in HTML spans (with tags as
+// defined by startTags and endTag) as follows:
+//
+// - if line >= 0, line numbers are printed before each line, starting
+// with the value of line
+// - if the text is Go source, comments get the "comment" span class
+// - each occurrence of the regular expression pattern gets the "highlight"
+// span class
+// - text segments covered by selection get the "selection" span class
+//
+// Comments, highlights, and selections may overlap arbitrarily; the respective
+// HTML span classes are specified in the startTags variable.
+//
+func FormatText(text []byte, line int, goSource bool, pattern string, selection Selection) []byte {
+ var buf bytes.Buffer
+ buf.WriteString("<pre>\n")
+
+ var comments, highlights Selection
+ if goSource {
+ comments = commentSelection(text)
+ }
+ if pattern != "" {
+ highlights = regexpSelection(text, pattern)
+ }
+ if comments != nil || highlights != nil || selection != nil {
+ var lineTag LinkWriter
+ if line >= 0 {
+ lineTag = func(w io.Writer, _ int, start bool) {
+ if start {
+ fmt.Fprintf(w, "<a id=\"L%d\"></a>%5d\t", line, line)
+ line++
+ }
+ }
+ }
+ FormatSelections(&buf, text, lineTag, lineSelection(text), selectionTag, comments, highlights, selection)
+ } else {
+ template.HTMLEscape(&buf, text)
+ }
+
+ buf.WriteString("</pre>\n")
+ return buf.Bytes()
+}
diff --git a/src/cmd/godoc/godoc.go b/src/cmd/godoc/godoc.go
index 61c53e2c3..d6054ab9d 100644
--- a/src/cmd/godoc/godoc.go
+++ b/src/cmd/godoc/godoc.go
@@ -21,43 +21,15 @@ import (
pathutil "path"
"regexp"
"runtime"
+ "sort"
"strings"
- "sync"
"template"
"time"
- "unicode"
"utf8"
)
// ----------------------------------------------------------------------------
-// Support types
-
-// An RWValue wraps a value and permits mutually exclusive
-// access to it and records the time the value was last set.
-type RWValue struct {
- mutex sync.RWMutex
- value interface{}
- timestamp int64 // time of last set(), in seconds since epoch
-}
-
-
-func (v *RWValue) set(value interface{}) {
- v.mutex.Lock()
- v.value = value
- v.timestamp = time.Seconds()
- v.mutex.Unlock()
-}
-
-
-func (v *RWValue) get() (interface{}, int64) {
- v.mutex.RLock()
- defer v.mutex.RUnlock()
- return v.value, v.timestamp
-}
-
-
-// ----------------------------------------------------------------------------
// Globals
type delayTime struct {
@@ -72,6 +44,7 @@ func (dt *delayTime) backoff(max int) {
v = max
}
dt.value = v
+ // don't change dt.timestamp - calling backoff indicates an error condition
dt.mutex.Unlock()
}
@@ -80,15 +53,24 @@ var (
verbose = flag.Bool("v", false, "verbose mode")
// file system roots
- goroot = flag.String("goroot", runtime.GOROOT(), "Go root directory")
- path = flag.String("path", "", "additional package directories (colon-separated)")
+ // 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)")
+ path = 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
// layout control
- tabwidth = flag.Int("tabwidth", 4, "tab width")
+ tabwidth = flag.Int("tabwidth", 4, "tab width")
+ showTimestamps = flag.Bool("timestamps", true, "show timestamps with directory listings")
+ fulltextIndex = flag.Bool("fulltext", false, "build full text index for regular expression queries")
// file system mapping
- fsMap Mapping // user-defined mapping
- fsTree RWValue // *Directory tree of packages, updated with each sync
+ fsMap Mapping // user-defined mapping
+ fsTree RWValue // *Directory tree of packages, updated with each sync
+ pathFilter RWValue // filter used when building fsMap directory trees
+ fsModified RWValue // timestamp of last call to invalidateIndex
// http handlers
fileServer http.Handler // default file server
@@ -114,410 +96,179 @@ func registerPublicHandlers(mux *http.ServeMux) {
}
-// ----------------------------------------------------------------------------
-// Predicates and small utility functions
-
-func isGoFile(f *os.FileInfo) bool {
- return f.IsRegular() &&
- !strings.HasPrefix(f.Name, ".") && // ignore .files
- pathutil.Ext(f.Name) == ".go"
-}
-
-
-func isPkgFile(f *os.FileInfo) bool {
- return isGoFile(f) &&
- !strings.HasSuffix(f.Name, "_test.go") // ignore test files
+func initFSTree() {
+ fsTree.set(newDirectory(pathutil.Join(*goroot, *testDir), nil, -1))
+ invalidateIndex()
}
-func isPkgDir(f *os.FileInfo) bool {
- return f.IsDirectory() && len(f.Name) > 0 && f.Name[0] != '_'
-}
-
-
-func pkgName(filename string) string {
- file, err := parser.ParseFile(filename, nil, nil, parser.PackageClauseOnly)
- if err != nil || file == nil {
- return ""
- }
- return file.Name.Name()
-}
-
+// ----------------------------------------------------------------------------
+// Directory filters
-func htmlEscape(s string) string {
- var buf bytes.Buffer
- template.HTMLEscape(&buf, []byte(s))
- return buf.String()
+// 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 firstSentence(s string) string {
- i := -1 // index+1 of first period
- j := -1 // index+1 of first period that is followed by white space
- prev := 'A'
- for k, ch := range s {
- k1 := k + 1
- if ch == '.' {
- if i < 0 {
- i = k1 // first period
- }
- if k1 < len(s) && s[k1] <= ' ' {
- if j < 0 {
- j = k1 // first period followed by white space
- }
- if !unicode.IsUpper(prev) {
- j = k1
- break
- }
- }
- }
- prev = ch
- }
-
- if j < 0 {
- // use the next best period
- j = i
- if j < 0 {
- // no period at all, use the entire string
- j = len(s)
- }
+func setPathFilter(list []string) {
+ if len(list) == 0 {
+ pathFilter.set(nil)
+ return
}
- return s[0:j]
+ // 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 absolutePath(path, defaultRoot string) string {
- abspath := fsMap.ToAbsolute(path)
- if abspath == "" {
- // no user-defined mapping found; use default mapping
- abspath = pathutil.Join(defaultRoot, path)
+func getPathFilter() func(string) bool {
+ f, _ := pathFilter.get()
+ if f != nil {
+ return f.(func(string) bool)
}
- return abspath
+ return nil
}
-func relativePath(path string) string {
- relpath := fsMap.ToRelative(path)
- if relpath == "" && strings.HasPrefix(path, *goroot+"/") {
- // no user-defined mapping found; use default mapping
- relpath = path[len(*goroot)+1:]
+// readDirList reads a file containing a newline-separated list
+// of directory paths and returns the list of paths.
+func readDirList(filename string) ([]string, os.Error) {
+ contents, err := ioutil.ReadFile(filename)
+ if err != nil {
+ return nil, err
}
- // 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
-}
-
-
-// ----------------------------------------------------------------------------
-// Package directories
-
-type Directory struct {
- Depth int
- Path string // includes Name
- Name string
- Text string // package documentation, if any
- Dirs []*Directory // subdirectories
-}
-
-
-func newDirTree(path, name string, depth, maxDepth int) *Directory {
- if depth >= maxDepth {
- // 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}
+ // create a sorted list of valid directory names
+ filter := func(path string) bool {
+ d, err := os.Lstat(path)
+ return err == nil && isPkgDir(d)
}
-
- list, _ := ioutil.ReadDir(path) // ignore errors
-
- // determine number of subdirectories and package files
- ndirs := 0
- nfiles := 0
- text := ""
- for _, d := range list {
- switch {
- case isPkgDir(d):
- ndirs++
- case isPkgFile(d):
- nfiles++
- if text == "" {
- // no package documentation yet; take the first found
- file, err := parser.ParseFile(pathutil.Join(path, d.Name), nil, nil,
- parser.ParseComments|parser.PackageClauseOnly)
- if err == nil &&
- // Also accept fakePkgName, so we get synopses for commmands.
- // Note: This may lead to incorrect results if there is a
- // (left-over) "documentation" package somewhere in a package
- // directory of different name, but this is very unlikely and
- // against current conventions.
- (file.Name.Name() == name || file.Name.Name() == fakePkgName) &&
- file.Doc != nil {
- // found documentation; extract a synopsys
- text = firstSentence(doc.CommentText(file.Doc))
- }
- }
- }
- }
-
- // create subdirectory tree
- var dirs []*Directory
- if ndirs > 0 {
- dirs = make([]*Directory, ndirs)
- i := 0
- for _, d := range list {
- if isPkgDir(d) {
- dd := newDirTree(pathutil.Join(path, d.Name), d.Name, depth+1, maxDepth)
- if dd != nil {
- dirs[i] = dd
- i++
- }
- }
+ list := canonicalizePaths(strings.Split(string(contents), "\n", -1), filter)
+ // for each parent path, remove all it's 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++
}
- dirs = dirs[0:i]
}
-
- // if there are no package files and no subdirectories
- // (with package files), ignore the directory
- if nfiles == 0 && len(dirs) == 0 {
- return nil
- }
-
- return &Directory{depth, path, name, text, dirs}
+ return list[0:i], nil
}
-// newDirectory creates a new package directory tree with at most maxDepth
-// levels, anchored at root which is relative to goroot. The result tree
-// only contains directories that contain package files or that contain
-// subdirectories containing package files (transitively).
+// updateMappedDirs computes the directory tree for
+// each user-defined file system mapping. If a filter
+// is provided, it is used to filter directories.
//
-func newDirectory(root string, maxDepth int) *Directory {
- d, err := os.Lstat(root)
- if err != nil || !isPkgDir(d) {
- return nil
- }
- return newDirTree(root, d.Name, 0, maxDepth)
-}
-
-
-func (dir *Directory) walk(c chan<- *Directory, skipRoot bool) {
- if dir != nil {
- if !skipRoot {
- c <- dir
- }
- for _, d := range dir.Dirs {
- d.walk(c, false)
- }
+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 (dir *Directory) iter(skipRoot bool) <-chan *Directory {
- c := make(chan *Directory)
- go func() {
- dir.walk(c, skipRoot)
- close(c)
- }()
- return c
-}
-
+func updateFilterFile() {
+ updateMappedDirs(nil) // no filter for accuracy
-func (dir *Directory) lookupLocal(name string) *Directory {
- for _, d := range dir.Dirs {
- if d.Name == name {
- return d
+ // 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 nil
-}
+ return true
+ })
-
-// lookup looks for the *Directory for a given path, relative to dir.
-func (dir *Directory) lookup(path string) *Directory {
- d := strings.Split(dir.Path, "/", -1)
- p := strings.Split(path, "/", -1)
- i := 0
- for i < len(d) {
- if i >= len(p) || d[i] != p[i] {
- return nil
- }
- i++
- }
- for dir != nil && i < len(p) {
- dir = dir.lookupLocal(p[i])
- i++
+ // 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
}
- return dir
-}
-
-
-// DirEntry describes a directory entry. The Depth and Height values
-// are useful for presenting an entry in an indented fashion.
-//
-type DirEntry struct {
- Depth int // >= 0
- Height int // = DirList.MaxHeight - Depth, > 0
- Path string // includes Name, relative to DirList root
- Name string
- Synopsis string
}
-type DirList struct {
- MaxHeight int // directory tree height, > 0
- List []DirEntry
-}
-
-
-// listing creates a (linear) directory listing from a directory tree.
-// If skipRoot is set, the root directory itself is excluded from the list.
-//
-func (root *Directory) listing(skipRoot bool) *DirList {
- if root == nil {
- return nil
- }
-
- // determine number of entries n and maximum height
- n := 0
- minDepth := 1 << 30 // infinity
- maxDepth := 0
- for d := range root.iter(skipRoot) {
- n++
- if minDepth > d.Depth {
- minDepth = d.Depth
- }
- if maxDepth < d.Depth {
- maxDepth = d.Depth
+func initDirTrees() {
+ // setup initial path filter
+ if *filter != "" {
+ list, err := readDirList(*filter)
+ if err != nil {
+ log.Printf("%s", err)
+ } else if len(list) == 0 {
+ log.Printf("no directory paths in file %s", *filter)
}
+ setPathFilter(list)
}
- maxHeight := maxDepth - minDepth + 1
- if n == 0 {
- return nil
- }
+ go updateMappedDirs(getPathFilter()) // use filter for speed
- // create list
- list := make([]DirEntry, n)
- i := 0
- for d := range root.iter(skipRoot) {
- p := &list[i]
- p.Depth = d.Depth - minDepth
- p.Height = maxHeight - p.Depth
- // the path is relative to root.Path - remove the root.Path
- // prefix (the prefix should always be present but avoid
- // crashes and check)
- path := d.Path
- if strings.HasPrefix(d.Path, root.Path) {
- path = d.Path[len(root.Path):]
- }
- // remove trailing '/' 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
- i++
+ // 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)
+ }
+ }()
}
-
- return &DirList{maxHeight, list}
}
// ----------------------------------------------------------------------------
-// HTML formatting support
-
-// Styler implements a printer.Styler.
-type Styler struct {
- linetags bool
- highlight string
- objmap map[*ast.Object]int
- count int
-}
-
-
-func newStyler(highlight string) *Styler {
- return &Styler{true, highlight, make(map[*ast.Object]int), 0}
-}
+// Path mapping
-
-func (s *Styler) id(obj *ast.Object) int {
- n, found := s.objmap[obj]
- if !found {
- n = s.count
- s.objmap[obj] = n
- s.count++
- }
- return n
-}
-
-
-func (s *Styler) mapping() []*ast.Object {
- if s.objmap == nil {
- return nil
- }
- m := make([]*ast.Object, s.count)
- for obj, i := range s.objmap {
- m[i] = obj
- }
- return m
-}
-
-
-// Use the defaultStyler when there is no specific styler.
-// The defaultStyler does not emit line tags since they may
-// interfere with tags emitted by templates.
-// TODO(gri): Should emit line tags at the beginning of a line;
-// never in the middle of code.
-var defaultStyler Styler
-
-
-func (s *Styler) LineTag(line int) (text []byte, tag printer.HTMLTag) {
- if s.linetags {
- tag = printer.HTMLTag{fmt.Sprintf(`<a id="L%d">`, line), "</a>"}
+func absolutePath(path, defaultRoot string) string {
+ abspath := fsMap.ToAbsolute(path)
+ if abspath == "" {
+ // no user-defined mapping found; use default mapping
+ abspath = pathutil.Join(defaultRoot, path)
}
- return
-}
-
-
-func (s *Styler) Comment(c *ast.Comment, line []byte) (text []byte, tag printer.HTMLTag) {
- text = line
- // minimal syntax-coloring of comments for now - people will want more
- // (don't do anything more until there's a button to turn it on/off)
- tag = printer.HTMLTag{`<span class="comment">`, "</span>"}
- return
-}
-
-
-func (s *Styler) BasicLit(x *ast.BasicLit) (text []byte, tag printer.HTMLTag) {
- text = x.Value
- return
+ return abspath
}
-func (s *Styler) Ident(id *ast.Ident) (text []byte, tag printer.HTMLTag) {
- text = []byte(id.Name())
- var str string
- if s.objmap != nil {
- str = fmt.Sprintf(` id="%d"`, s.id(id.Obj))
- }
- if s.highlight == id.Name() {
- str += ` class="highlight"`
- }
- if str != "" {
- tag = printer.HTMLTag{"<span" + str + ">", "</span>"}
+func relativePath(path string) string {
+ relpath := fsMap.ToRelative(path)
+ if relpath == "" {
+ // prefix must end in '/'
+ prefix := *goroot
+ if len(prefix) > 0 && prefix[len(prefix)-1] != '/' {
+ prefix += "/"
+ }
+ if strings.HasPrefix(path, prefix) {
+ // no user-defined mapping found; use default mapping
+ relpath = path[len(prefix):]
+ }
}
- return
-}
-
-
-func (s *Styler) Token(tok token.Token) (text []byte, tag printer.HTMLTag) {
- text = []byte(tok.String())
- return
+ // 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
}
@@ -597,7 +348,7 @@ func (p *tconv) Write(data []byte) (n int, err os.Error) {
// Templates
// Write an AST-node to w; optionally html-escaped.
-func writeNode(w io.Writer, node interface{}, html bool, styler printer.Styler) {
+func writeNode(w io.Writer, fset *token.FileSet, node interface{}, html bool) {
mode := printer.TabIndent | printer.UseSpaces
if html {
mode |= printer.GenHTML
@@ -606,7 +357,7 @@ func writeNode(w io.Writer, node interface{}, html bool, styler printer.Styler)
// to ensure a good outcome in most browsers (there may still
// be tabs in comments and strings, but converting those into
// the right number of spaces is much harder)
- (&printer.Config{mode, *tabwidth, styler}).Fprint(&tconv{output: w}, node)
+ (&printer.Config{mode, *tabwidth, nil}).Fprint(&tconv{output: w}, fset, node)
}
@@ -621,14 +372,14 @@ func writeText(w io.Writer, text []byte, html bool) {
// Write anything to w; optionally html-escaped.
-func writeAny(w io.Writer, x interface{}, html bool) {
+func writeAny(w io.Writer, fset *token.FileSet, html bool, x interface{}) {
switch v := x.(type) {
case []byte:
writeText(w, v, html)
case string:
writeText(w, []byte(v), html)
case ast.Decl, ast.Expr, ast.Stmt, *ast.File:
- writeNode(w, x, html, &defaultStyler)
+ writeNode(w, fset, x, html)
default:
if html {
var buf bytes.Buffer
@@ -641,24 +392,34 @@ func writeAny(w io.Writer, x interface{}, html bool) {
}
+func fileset(x []interface{}) *token.FileSet {
+ if len(x) > 1 {
+ if fset, ok := x[1].(*token.FileSet); ok {
+ return fset
+ }
+ }
+ return nil
+}
+
+
// Template formatter for "html" format.
-func htmlFmt(w io.Writer, x interface{}, format string) {
- writeAny(w, x, true)
+func htmlFmt(w io.Writer, format string, x ...interface{}) {
+ writeAny(w, fileset(x), true, x[0])
}
// Template formatter for "html-esc" format.
-func htmlEscFmt(w io.Writer, x interface{}, format string) {
+func htmlEscFmt(w io.Writer, format string, x ...interface{}) {
var buf bytes.Buffer
- writeAny(&buf, x, false)
+ writeAny(&buf, fileset(x), false, x[0])
template.HTMLEscape(w, buf.Bytes())
}
// Template formatter for "html-comment" format.
-func htmlCommentFmt(w io.Writer, x interface{}, format string) {
+func htmlCommentFmt(w io.Writer, format string, x ...interface{}) {
var buf bytes.Buffer
- writeAny(&buf, x, false)
+ writeAny(&buf, fileset(x), false, x[0])
// TODO(gri) Provide list of words (e.g. function parameters)
// to be emphasized by ToHTML.
doc.ToHTML(w, buf.Bytes(), nil) // does html-escaping
@@ -666,29 +427,49 @@ func htmlCommentFmt(w io.Writer, x interface{}, format string) {
// Template formatter for "" (default) format.
-func textFmt(w io.Writer, x interface{}, format string) {
- writeAny(w, x, false)
+func textFmt(w io.Writer, format string, x ...interface{}) {
+ writeAny(w, fileset(x), false, x[0])
+}
+
+
+// Template formatter for "urlquery-esc" format.
+func urlQueryEscFmt(w io.Writer, format string, x ...interface{}) {
+ var buf bytes.Buffer
+ writeAny(&buf, fileset(x), false, x[0])
+ template.HTMLEscape(w, []byte(http.URLEscape(string(buf.Bytes()))))
}
-// Template formatter for the various "url-xxx" formats.
-func urlFmt(w io.Writer, x interface{}, format string) {
+// Template formatter for the various "url-xxx" formats excluding url-esc.
+func urlFmt(w io.Writer, format string, x ...interface{}) {
var path string
var line int
+ var low, high int // selection
// determine path and position info, if any
type positioner interface {
- Pos() token.Position
+ Pos() token.Pos
+ End() token.Pos
}
- switch t := x.(type) {
+ switch t := x[0].(type) {
case string:
path = t
case positioner:
- pos := t.Pos()
- if pos.IsValid() {
+ fset := fileset(x)
+ if p := t.Pos(); p.IsValid() {
+ pos := fset.Position(p)
path = pos.Filename
line = pos.Line
+ low = pos.Offset
}
+ if p := t.End(); p.IsValid() {
+ high = fset.Position(p).Offset
+ }
+ default:
+ // we should never reach here, but be resilient
+ // and assume the position is invalid (empty path,
+ // and line 0)
+ log.Printf("INTERNAL ERROR: urlFmt(%s) without a string or positioner", format)
}
// map path
@@ -700,7 +481,7 @@ func urlFmt(w io.Writer, x interface{}, format string) {
default:
// we should never reach here, but be resilient
// and assume the url-pkg format instead
- log.Stderrf("INTERNAL ERROR: urlFmt(%s)", format)
+ log.Printf("INTERNAL ERROR: urlFmt(%s)", format)
fallthrough
case "url-pkg":
// because of the irregular mapping under goroot
@@ -712,10 +493,22 @@ func urlFmt(w io.Writer, x interface{}, format string) {
case "url-src":
template.HTMLEscape(w, []byte(relpath))
case "url-pos":
+ template.HTMLEscape(w, []byte(relpath))
+ // selection ranges are of form "s=low:high"
+ if low < high {
+ fmt.Fprintf(w, "?s=%d:%d", low, high)
+ // if we have a selection, position the page
+ // such that the selection is a bit below the top
+ line -= 10
+ if line < 1 {
+ line = 1
+ }
+ }
// line id's in html-printed source are of the
// form "L%d" where %d stands for the line number
- template.HTMLEscape(w, []byte(relpath))
- fmt.Fprintf(w, "#L%d", line)
+ if line > 0 {
+ fmt.Fprintf(w, "#L%d", line)
+ }
}
}
@@ -734,14 +527,14 @@ var infoKinds = [nKinds]string{
// Template formatter for "infoKind" format.
-func infoKindFmt(w io.Writer, x interface{}, format string) {
- fmt.Fprintf(w, infoKinds[x.(SpotKind)]) // infoKind entries are html-escaped
+func infoKindFmt(w io.Writer, format string, x ...interface{}) {
+ fmt.Fprintf(w, infoKinds[x[0].(SpotKind)]) // infoKind entries are html-escaped
}
// Template formatter for "infoLine" format.
-func infoLineFmt(w io.Writer, x interface{}, format string) {
- info := x.(SpotInfo)
+func infoLineFmt(w io.Writer, format string, x ...interface{}) {
+ info := x[0].(SpotInfo)
line := info.Lori()
if info.IsIndex() {
index, _ := searchIndex.get()
@@ -760,58 +553,52 @@ func infoLineFmt(w io.Writer, x interface{}, format string) {
// Template formatter for "infoSnippet" format.
-func infoSnippetFmt(w io.Writer, x interface{}, format string) {
- info := x.(SpotInfo)
- text := `<span class="alert">no snippet text available</span>`
+func infoSnippetFmt(w io.Writer, format string, x ...interface{}) {
+ info := x[0].(SpotInfo)
+ text := []byte(`<span class="alert">no snippet text available</span>`)
if info.IsIndex() {
index, _ := searchIndex.get()
// no escaping of snippet text needed;
// snippet text is escaped when generated
text = index.(*Index).Snippet(info.Lori()).Text
}
- fmt.Fprint(w, text)
+ w.Write(text)
}
// Template formatter for "padding" format.
-func paddingFmt(w io.Writer, x interface{}, format string) {
- for i := x.(int); i > 0; i-- {
+func paddingFmt(w io.Writer, format string, x ...interface{}) {
+ for i := x[0].(int); i > 0; i-- {
fmt.Fprint(w, `<td width="25"></td>`)
}
}
// Template formatter for "time" format.
-func timeFmt(w io.Writer, x interface{}, format string) {
- template.HTMLEscape(w, []byte(time.SecondsToLocalTime(x.(int64)/1e9).String()))
+func timeFmt(w io.Writer, format string, x ...interface{}) {
+ template.HTMLEscape(w, []byte(time.SecondsToLocalTime(x[0].(int64)/1e9).String()))
}
// Template formatter for "dir/" format.
-func dirslashFmt(w io.Writer, x interface{}, format string) {
- if x.(*os.FileInfo).IsDirectory() {
+func dirslashFmt(w io.Writer, format string, x ...interface{}) {
+ if x[0].(*os.FileInfo).IsDirectory() {
w.Write([]byte{'/'})
}
}
// Template formatter for "localname" format.
-func localnameFmt(w io.Writer, x interface{}, format string) {
- _, localname := pathutil.Split(x.(string))
+func localnameFmt(w io.Writer, format string, x ...interface{}) {
+ _, localname := pathutil.Split(x[0].(string))
template.HTMLEscape(w, []byte(localname))
}
-// Template formatter for "popupInfo" format.
-func popupInfoFmt(w io.Writer, x interface{}, format string) {
- obj := x.(*ast.Object)
- // for now, show object kind and name; eventually
- // do something more interesting (show declaration,
- // for instance)
- if obj.Kind != ast.Err {
- fmt.Fprintf(w, "%s ", obj.Kind)
- }
- template.HTMLEscape(w, []byte(obj.Name))
+// Template formatter for "numlines" format.
+func numlinesFmt(w io.Writer, format string, x ...interface{}) {
+ list := x[0].([]int)
+ fmt.Fprintf(w, "%d", len(list))
}
@@ -820,6 +607,7 @@ var fmap = template.FormatterMap{
"html": htmlFmt,
"html-esc": htmlEscFmt,
"html-comment": htmlCommentFmt,
+ "urlquery-esc": urlQueryEscFmt,
"url-pkg": urlFmt,
"url-src": urlFmt,
"url-pos": urlFmt,
@@ -830,7 +618,7 @@ var fmap = template.FormatterMap{
"time": timeFmt,
"dir/": dirslashFmt,
"localname": localnameFmt,
- "popupInfo": popupInfoFmt,
+ "numlines": numlinesFmt,
}
@@ -857,8 +645,7 @@ var (
packageHTML,
packageText,
searchHTML,
- searchText,
- sourceHTML *template.Template
+ searchText *template.Template
)
func readTemplates() {
@@ -872,46 +659,40 @@ func readTemplates() {
packageText = readTemplate("package.txt")
searchHTML = readTemplate("search.html")
searchText = readTemplate("search.txt")
- sourceHTML = readTemplate("source.html")
}
// ----------------------------------------------------------------------------
// Generic HTML wrapper
-func servePage(c *http.Conn, title, subtitle, query string, content []byte) {
- type Data struct {
- Title string
- Subtitle string
- PkgRoots []string
- Timestamp int64
- Query string
- Version string
- Menu []byte
- Content []byte
- }
-
- _, ts := fsTree.get()
- d := Data{
- Title: title,
- Subtitle: subtitle,
- PkgRoots: fsMap.PrefixList(),
- Timestamp: ts * 1e9, // timestamp in ns
- Query: query,
- Version: runtime.Version(),
- Menu: nil,
- Content: content,
- }
-
- if err := godocHTML.Execute(&d, c); err != nil {
- log.Stderrf("godocHTML.Execute: %s", err)
+func servePage(w http.ResponseWriter, title, subtitle, query string, content []byte) {
+ d := struct {
+ Title string
+ Subtitle string
+ PkgRoots []string
+ Query string
+ Version string
+ Menu []byte
+ Content []byte
+ }{
+ title,
+ subtitle,
+ fsMap.PrefixList(),
+ query,
+ runtime.Version(),
+ nil,
+ content,
+ }
+
+ if err := godocHTML.Execute(&d, w); err != nil {
+ log.Printf("godocHTML.Execute: %s", err)
}
}
-func serveText(c *http.Conn, text []byte) {
- c.SetHeader("Content-Type", "text/plain; charset=utf-8")
- c.Write(text)
+func serveText(w http.ResponseWriter, text []byte) {
+ w.SetHeader("Content-Type", "text/plain; charset=utf-8")
+ w.Write(text)
}
@@ -926,27 +707,27 @@ var (
func extractString(src []byte, rx *regexp.Regexp) (s string) {
- m := rx.Execute(src)
- if len(m) >= 4 {
- s = strings.TrimSpace(string(src[m[2]:m[3]]))
+ m := rx.FindSubmatch(src)
+ if m != nil {
+ s = strings.TrimSpace(string(m[1]))
}
return
}
-func serveHTMLDoc(c *http.Conn, r *http.Request, abspath, relpath string) {
+func serveHTMLDoc(w http.ResponseWriter, r *http.Request, abspath, relpath string) {
// get HTML body contents
src, err := ioutil.ReadFile(abspath)
if err != nil {
- log.Stderrf("ioutil.ReadFile: %s", err)
- serveError(c, r, relpath, err)
+ log.Printf("ioutil.ReadFile: %s", err)
+ serveError(w, r, relpath, err)
return
}
// if it begins with "<!DOCTYPE " assume it is standalone
// html that doesn't need the template wrapping.
if bytes.HasPrefix(src, []byte("<!DOCTYPE ")) {
- c.Write(src)
+ w.Write(src)
return
}
@@ -965,45 +746,22 @@ func serveHTMLDoc(c *http.Conn, r *http.Request, abspath, relpath string) {
}
subtitle := extractString(src, subtitleRx)
- servePage(c, title, subtitle, "", src)
+ servePage(w, title, subtitle, "", src)
}
func applyTemplate(t *template.Template, name string, data interface{}) []byte {
var buf bytes.Buffer
if err := t.Execute(data, &buf); err != nil {
- log.Stderrf("%s.Execute: %s", name, err)
+ log.Printf("%s.Execute: %s", name, err)
}
return buf.Bytes()
}
-func serveGoSource(c *http.Conn, r *http.Request, abspath, relpath string) {
- file, err := parser.ParseFile(abspath, nil, nil, parser.ParseComments)
- if err != nil {
- log.Stderrf("parser.ParseFile: %s", err)
- serveError(c, r, relpath, err)
- return
- }
-
- var buf bytes.Buffer
- styler := newStyler(r.FormValue("h"))
- writeNode(&buf, file, true, styler)
-
- type SourceInfo struct {
- Source []byte
- Data []*ast.Object
- }
- info := &SourceInfo{buf.Bytes(), styler.mapping()}
-
- contents := applyTemplate(sourceHTML, "sourceHTML", info)
- servePage(c, "Source file "+relpath, "", "", contents)
-}
-
-
-func redirect(c *http.Conn, r *http.Request) (redirected bool) {
+func redirect(w http.ResponseWriter, r *http.Request) (redirected bool) {
if canonical := pathutil.Clean(r.URL.Path) + "/"; r.URL.Path != canonical {
- http.Redirect(c, canonical, http.StatusMovedPermanently)
+ http.Redirect(w, r, canonical, http.StatusMovedPermanently)
redirected = true
}
return
@@ -1057,32 +815,28 @@ func isTextFile(path string) bool {
}
-func serveTextFile(c *http.Conn, r *http.Request, abspath, relpath string) {
+func serveTextFile(w http.ResponseWriter, r *http.Request, abspath, relpath, title string) {
src, err := ioutil.ReadFile(abspath)
if err != nil {
- log.Stderrf("ioutil.ReadFile: %s", err)
- serveError(c, r, relpath, err)
+ log.Printf("ioutil.ReadFile: %s", err)
+ serveError(w, r, relpath, err)
return
}
- var buf bytes.Buffer
- fmt.Fprintln(&buf, "<pre>")
- template.HTMLEscape(&buf, src)
- fmt.Fprintln(&buf, "</pre>")
-
- servePage(c, "Text file "+relpath, "", "", buf.Bytes())
+ contents := FormatText(src, 1, pathutil.Ext(abspath) == ".go", r.FormValue("h"), rangeSelection(r.FormValue("s")))
+ servePage(w, title+" "+relpath, "", "", contents)
}
-func serveDirectory(c *http.Conn, r *http.Request, abspath, relpath string) {
- if redirect(c, r) {
+func serveDirectory(w http.ResponseWriter, r *http.Request, abspath, relpath string) {
+ if redirect(w, r) {
return
}
list, err := ioutil.ReadDir(abspath)
if err != nil {
- log.Stderrf("ioutil.ReadDir: %s", err)
- serveError(c, r, relpath, err)
+ log.Printf("ioutil.ReadDir: %s", err)
+ serveError(w, r, relpath, err)
return
}
@@ -1093,23 +847,23 @@ func serveDirectory(c *http.Conn, r *http.Request, abspath, relpath string) {
}
contents := applyTemplate(dirlistHTML, "dirlistHTML", list)
- servePage(c, "Directory "+relpath, "", "", contents)
+ servePage(w, "Directory "+relpath, "", "", contents)
}
-func serveFile(c *http.Conn, r *http.Request) {
+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(c, r, pathutil.Join(*goroot, "doc/root.html"), "doc/root.html")
+ serveHTMLDoc(w, r, pathutil.Join(*goroot, "doc/root.html"), "doc/root.html")
return
case "/doc/root.html":
// hide landing page from its real name
- http.Redirect(c, "/", http.StatusMovedPermanently)
+ http.Redirect(w, r, "/", http.StatusMovedPermanently)
return
}
@@ -1118,42 +872,42 @@ func serveFile(c *http.Conn, r *http.Request) {
if strings.HasSuffix(abspath, "/index.html") {
// We'll show index.html for the directory.
// Use the dir/ version as canonical instead of dir/index.html.
- http.Redirect(c, r.URL.Path[0:len(r.URL.Path)-len("index.html")], http.StatusMovedPermanently)
+ http.Redirect(w, r, r.URL.Path[0:len(r.URL.Path)-len("index.html")], http.StatusMovedPermanently)
return
}
- serveHTMLDoc(c, r, abspath, relpath)
+ serveHTMLDoc(w, r, abspath, relpath)
return
case ".go":
- serveGoSource(c, r, abspath, relpath)
+ serveTextFile(w, r, abspath, relpath, "Source file")
return
}
dir, err := os.Lstat(abspath)
if err != nil {
- log.Stderr(err)
- serveError(c, r, relpath, err)
+ log.Print(err)
+ serveError(w, r, relpath, err)
return
}
if dir != nil && dir.IsDirectory() {
- if redirect(c, r) {
+ if redirect(w, r) {
return
}
if index := abspath + "/index.html"; isTextFile(index) {
- serveHTMLDoc(c, r, index, relativePath(index))
+ serveHTMLDoc(w, r, index, relativePath(index))
return
}
- serveDirectory(c, r, abspath, relpath)
+ serveDirectory(w, r, abspath, relpath)
return
}
if isTextFile(abspath) {
- serveTextFile(c, r, abspath, relpath)
+ serveTextFile(w, r, abspath, relpath, "Text file")
return
}
- fileServer.ServeHTTP(c, r)
+ fileServer.ServeHTTP(w, r)
}
@@ -1169,17 +923,19 @@ type PageInfoMode uint
const (
exportsOnly PageInfoMode = 1 << iota // only keep exported stuff
genDoc // generate documentation
- tryMode // don't log errors
)
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
}
@@ -1193,10 +949,10 @@ type httpHandler struct {
// 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)
-// is extracted from the AST. If the parameter try is set, no errors are
-// logged if getPageInfo fails. If there is no corresponding package in the
-// directory, PageInfo.PDoc and PageInfo.PExp are nil. If there are no sub-
-// directories, PageInfo.Dirs is nil.
+// is extracted from the AST. If there is no corresponding package in the
+// directory, PageInfo.PAst and PageInfo.PDoc are nil. If there are no sub-
+// 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 {
// filter function to select the desired .go files
@@ -1207,10 +963,12 @@ func (h *httpHandler) getPageInfo(abspath, relpath, pkgname string, mode PageInf
}
// get package ASTs
- pkgs, err := parser.ParseDir(abspath, filter, parser.ParseComments)
- if err != nil && mode&tryMode != 0 {
- // TODO: errors should be shown instead of an empty directory
- log.Stderrf("parser.parseDir: %s", err)
+ fset := token.NewFileSet()
+ pkgs, err := parser.ParseDir(fset, abspath, filter, parser.ParseComments)
+ if err != nil && pkgs == nil {
+ // only report directory read errors, ignore parse errors
+ // (may be able to extract partial package information)
+ return PageInfo{Dirname: abspath, Err: err}
}
// select package
@@ -1258,7 +1016,7 @@ func (h *httpHandler) getPageInfo(abspath, relpath, pkgname string, mode PageInf
// (excluding the selected package, if any).
plist = make([]string, len(pkgs))
i := 0
- for name, _ := range pkgs {
+ for name := range pkgs {
if pkg == nil || name != pkg.Name {
plist[i] = name
i++
@@ -1283,26 +1041,52 @@ func (h *httpHandler) getPageInfo(abspath, relpath, pkgname string, mode PageInf
// get directory information
var dir *Directory
- if tree, _ := fsTree.get(); tree != nil && tree.(*Directory) != nil {
+ var timestamp int64
+ 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
// new directory tree has not yet been computed)
- // TODO(gri) Need to build directory tree for fsMap entries
dir = tree.(*Directory).lookup(abspath)
+ 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 (either early after startup
- // or command-line mode, or we don't build a tree for the
- // directory; e.g. google3); compute one level for this page
- dir = newDirectory(abspath, 1)
+ // 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()
}
- return PageInfo{abspath, plist, past, pdoc, dir.listing(true), h.isPkg}
+ return PageInfo{abspath, plist, fset, past, pdoc, dir.listing(true), timestamp, h.isPkg, nil}
}
-func (h *httpHandler) ServeHTTP(c *http.Conn, r *http.Request) {
- if redirect(c, r) {
+func (h *httpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+ if redirect(w, r) {
return
}
@@ -1313,17 +1097,22 @@ func (h *httpHandler) ServeHTTP(c *http.Conn, r *http.Request) {
mode |= genDoc
}
info := h.getPageInfo(abspath, relpath, r.FormValue("p"), mode)
+ if info.Err != nil {
+ log.Print(info.Err)
+ serveError(w, r, relpath, info.Err)
+ return
+ }
if r.FormValue("f") == "text" {
contents := applyTemplate(packageText, "packageText", info)
- serveText(c, contents)
+ serveText(w, contents)
return
}
- var title string
+ var title, subtitle string
switch {
case info.PAst != nil:
- title = "Package " + info.PAst.Name.Name()
+ title = "Package " + info.PAst.Name.Name
case info.PDoc != nil:
switch {
case h.isPkg:
@@ -1337,10 +1126,13 @@ func (h *httpHandler) ServeHTTP(c *http.Conn, r *http.Request) {
}
default:
title = "Directory " + relativePath(info.Dirname)
+ if *showTimestamps {
+ subtitle = "Last update: " + time.SecondsToLocalTime(info.DirTime).String()
+ }
}
contents := applyTemplate(packageHTML, "packageHTML", info)
- servePage(c, title, "", "", contents)
+ servePage(w, title, subtitle, "", contents)
}
@@ -1350,71 +1142,160 @@ func (h *httpHandler) ServeHTTP(c *http.Conn, r *http.Request) {
var searchIndex RWValue
type SearchResult struct {
- Query string
- Hit *LookupResult
- Alt *AltWords
- Illegal bool
- Accurate bool
+ Query string
+ Alert string // error or warning message
+
+ // identifier matches
+ Hit *LookupResult // identifier matches of Query
+ Alt *AltWords // alternative identifiers to look for
+
+ // textual matches
+ Found int // number of textual occurrences found
+ Textual []FileLines // textual matches of Query
+ Complete bool // true if all textual occurrences of Query are reported
}
func lookup(query string) (result SearchResult) {
result.Query = query
+
+ // determine identifier lookup string and full text regexp
+ lookupStr := ""
+ lookupRx, err := regexp.Compile(query)
+ if err != nil {
+ result.Alert = "Error in query regular expression: " + err.String()
+ return
+ }
+ if prefix, complete := lookupRx.LiteralPrefix(); complete {
+ // otherwise we lookup "" (with no result) because
+ // identifier lookup doesn't support regexp search
+ lookupStr = prefix
+ }
+
if index, timestamp := searchIndex.get(); index != nil {
- result.Hit, result.Alt, result.Illegal = index.(*Index).Lookup(query)
- _, ts := fsTree.get()
- result.Accurate = timestamp >= ts
+ // identifier search
+ index := index.(*Index)
+ result.Hit, result.Alt, err = index.Lookup(lookupStr)
+ if err != nil && !*fulltextIndex {
+ // ignore the error if there is full text search
+ // since it accepts that query regular expression
+ result.Alert = "Error in query string: " + err.String()
+ return
+ }
+
+ // textual search
+ // TODO(gri) should max be a flag?
+ const max = 10000 // show at most this many fulltext results
+ result.Found, result.Textual = index.LookupRegexp(lookupRx, max+1)
+ result.Complete = result.Found <= max
+
+ // is the result accurate?
+ if _, ts := fsModified.get(); timestamp < ts {
+ result.Alert = "Indexing in progress: result may be inaccurate"
+ }
}
return
}
-func search(c *http.Conn, r *http.Request) {
+func search(w http.ResponseWriter, r *http.Request) {
query := strings.TrimSpace(r.FormValue("q"))
result := lookup(query)
if r.FormValue("f") == "text" {
contents := applyTemplate(searchText, "searchText", result)
- serveText(c, contents)
+ serveText(w, contents)
return
}
var title string
- if result.Hit != nil {
+ if result.Hit != nil || len(result.Textual) > 0 {
title = fmt.Sprintf(`Results for query %q`, query)
} else {
title = fmt.Sprintf(`No results found for query %q`, query)
}
contents := applyTemplate(searchHTML, "searchHTML", result)
- servePage(c, title, "", query, contents)
+ servePage(w, title, "", query, contents)
}
// ----------------------------------------------------------------------------
// Indexer
+// invalidateIndex should be called whenever any of the file systems
+// under godoc's observation change so that the indexer is kicked on.
+//
+func invalidateIndex() {
+ fsModified.set(nil)
+}
+
+
+// indexUpToDate() returns true if the search index is not older
+// than any of the file systems under godoc's observation.
+//
+func indexUpToDate() bool {
+ _, fsTime := fsModified.get()
+ _, siTime := searchIndex.get()
+ return fsTime <= siTime
+}
+
+
+// feedDirnames feeds the directory names of all directories
+// under the file system given by root to channel c.
+//
+func feedDirnames(root *RWValue, c chan<- string) {
+ if dir, _ := root.get(); dir != nil {
+ for d := range dir.(*Directory).iter(false) {
+ c <- d.Path
+ }
+ }
+}
+
+
+// fsDirnames() returns a channel sending all directory names
+// of all the file systems under godoc's observation.
+//
+func fsDirnames() <-chan string {
+ c := make(chan string, 256) // asynchronous 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 indexer() {
for {
- _, ts := fsTree.get()
- if _, timestamp := searchIndex.get(); timestamp < ts {
+ if !indexUpToDate() {
// index possibly out of date - make a new one
- // (could use a channel to send an explicit signal
- // from the sync goroutine, but this solution is
- // more decoupled, trivial, and works well enough)
+ if *verbose {
+ log.Printf("updating index...")
+ }
start := time.Nanoseconds()
- index := NewIndex(*goroot)
+ index := NewIndex(fsDirnames(), *fulltextIndex)
stop := time.Nanoseconds()
searchIndex.set(index)
if *verbose {
secs := float64((stop-start)/1e6) / 1e3
- nwords, nspots := index.Size()
- log.Stderrf("index updated (%gs, %d unique words, %d spots)", secs, nwords, nspots)
+ 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.Stderrf("bytes=%d footprint=%d\n", runtime.MemStats.HeapAlloc, runtime.MemStats.Sys)
+ log.Printf("before GC: bytes = %d footprint = %d", runtime.MemStats.HeapAlloc, runtime.MemStats.Sys)
runtime.GC()
- log.Stderrf("bytes=%d footprint=%d\n", runtime.MemStats.HeapAlloc, runtime.MemStats.Sys)
+ log.Printf("after GC: bytes = %d footprint = %d", runtime.MemStats.HeapAlloc, runtime.MemStats.Sys)
+ }
+ var delay int64 = 60 * 1e9 // by default, try every 60s
+ if *testDir != "" {
+ // in test mode, try once a second for fast startup
+ delay = 1 * 1e9
}
- time.Sleep(1 * 60e9) // try once a minute
+ time.Sleep(delay)
}
}
diff --git a/src/cmd/godoc/index.go b/src/cmd/godoc/index.go
index 8745b8b0a..ba6fe9acd 100644
--- a/src/cmd/godoc/index.go
+++ b/src/cmd/godoc/index.go
@@ -3,11 +3,11 @@
// license that can be found in the LICENSE file.
// This file contains the infrastructure to create an
-// (identifier) index for a set of Go files.
+// identifier and full-text index for a set of Go files.
//
-// Basic indexing algorithm:
+// Algorithm for identifier index:
// - traverse all .go files of the file tree specified by root
-// - for each word (identifier) encountered, collect all occurences (spots)
+// - for each word (identifier) 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
@@ -21,17 +21,34 @@
// (the line number for spots with snippets is stored in the snippet)
// - at the end, create lists of alternative spellings for a given
// word
+//
+// Algorithm for full text index:
+// - concatenate all source code in a byte buffer (in memory)
+// - add the files to a file set in lockstep as they are added to the byte
+// buffer such that a byte buffer offset corresponds to the Pos value for
+// that file location
+// - create a suffix array from the concatenated sources
+//
+// String lookup in full text index:
+// - use the suffix array to lookup a string's offsets - the offsets
+// correspond to the Pos values relative to the file set
+// - translate the Pos values back into file and line information and
+// sort the result
package main
import (
+ "bytes"
"container/vector"
"go/ast"
"go/parser"
"go/token"
"go/scanner"
+ "index/suffixarray"
+ "io/ioutil"
"os"
pathutil "path"
+ "regexp"
"sort"
"strings"
)
@@ -231,7 +248,7 @@ type File struct {
}
-// A Spot describes a single occurence of a word.
+// A Spot describes a single occurrence of a word.
type Spot struct {
File *File
Info SpotInfo
@@ -419,7 +436,17 @@ const excludeTestFiles = false
type IndexResult struct {
Decls RunList // package-level declarations (with snippets)
- Others RunList // all other occurences
+ Others RunList // all other occurrences
+}
+
+
+// Statistics provides statistics information for an index.
+type Statistics struct {
+ Bytes int // total size of indexed source files
+ Files int // number of indexed source files
+ Lines int // number of lines (all files)
+ Words int // number of different identifiers
+ Spots int // number of identifier occurrences
}
@@ -428,11 +455,14 @@ type IndexResult struct {
// interface for walking file trees, and the ast.Visitor interface for
// walking Go ASTs.
type Indexer struct {
+ fset *token.FileSet // file set for all indexed files
+ sources bytes.Buffer // concatenated sources
words map[string]*IndexResult // RunLists of Spots
snippets vector.Vector // vector of *Snippets, indexed by snippet indices
- file *File // current file
- decl ast.Decl // current decl
- nspots int // number of spots encountered
+ current *token.File // last file added to file set
+ file *File // AST for current file
+ decl ast.Decl // AST for current decl
+ stats Statistics
}
@@ -452,24 +482,24 @@ func (x *Indexer) visitComment(c *ast.CommentGroup) {
func (x *Indexer) visitIdent(kind SpotKind, id *ast.Ident) {
if id != nil {
- lists, found := x.words[id.Name()]
+ lists, found := x.words[id.Name]
if !found {
lists = new(IndexResult)
- x.words[id.Name()] = lists
+ x.words[id.Name] = lists
}
if kind == Use || x.decl == nil {
// not a declaration or no snippet required
- info := makeSpotInfo(kind, id.Pos().Line, false)
+ info := makeSpotInfo(kind, x.current.Line(id.Pos()), false)
lists.Others.Push(Spot{x.file, info})
} else {
// a declaration with snippet
- index := x.addSnippet(NewSnippet(x.decl, id))
+ index := x.addSnippet(NewSnippet(x.fset, x.decl, id))
info := makeSpotInfo(kind, index, true)
lists.Decls.Push(Spot{x.file, info})
}
- x.nspots++
+ x.stats.Spots++
}
}
@@ -506,7 +536,7 @@ func (x *Indexer) visitSpec(spec ast.Spec, isVarDecl bool) {
}
-func (x *Indexer) Visit(node interface{}) ast.Visitor {
+func (x *Indexer) Visit(node ast.Node) ast.Visitor {
// TODO(gri): methods in interface types are categorized as VarDecl
switch n := node.(type) {
case nil:
@@ -578,16 +608,69 @@ func (x *Indexer) Visit(node interface{}) ast.Visitor {
}
-func (x *Indexer) VisitDir(path string, f *os.FileInfo) bool {
- return true
+func pkgName(filename string) string {
+ // use a new file set each time in order to not pollute the indexer's
+ // file set (which must stay in sync with the concatenated source code)
+ file, err := parser.ParseFile(token.NewFileSet(), filename, nil, parser.PackageClauseOnly)
+ if err != nil || file == nil {
+ return ""
+ }
+ return file.Name.Name
+}
+
+
+func (x *Indexer) addFile(filename string) *ast.File {
+ // open file
+ f, err := os.Open(filename, os.O_RDONLY, 0)
+ if err != nil {
+ return nil
+ }
+ defer f.Close()
+
+ // The file set's base offset and x.sources size must be in lock-step;
+ // this permits the direct mapping of suffix array lookup results to
+ // to corresponding Pos values.
+ //
+ // When a file is added to the file set, it's offset base increases by
+ // the size of the file + 1; and the initial base offset is 1. Add an
+ // extra byte to the sources here.
+ x.sources.WriteByte(0)
+
+ // If the sources length doesn't match the file set base at this point
+ // the file set implementation changed or we have another error.
+ base := x.fset.Base()
+ if x.sources.Len() != base {
+ panic("internal error - file base incorrect")
+ }
+
+ // append file contents to x.sources
+ if _, err := x.sources.ReadFrom(f); err != nil {
+ x.sources.Truncate(base) // discard possibly added data
+ return nil // ignore files with I/O errors
+ }
+
+ // parse the file and in the process add it to the file set
+ src := x.sources.Bytes()[base:] // no need to reread the file
+ file, err := parser.ParseFile(x.fset, filename, src, parser.ParseComments)
+ if err != nil {
+ // do not discard the added source code in this case
+ // because the file has been added to the file set and
+ // the source size must match the file set base
+ // TODO(gri): given a FileSet.RemoveFile() one might be
+ // able to discard the data here (worthwhile?)
+ return nil // ignore files with (parse) errors
+ }
+
+ return file
}
-func (x *Indexer) VisitFile(path string, f *os.FileInfo) {
+func (x *Indexer) visitFile(dirname string, f *os.FileInfo) {
if !isGoFile(f) {
return
}
+ path := pathutil.Join(dirname, f.Name)
if excludeTestFiles && (!isPkgFile(f) || strings.HasPrefix(path, "test/")) {
return
}
@@ -596,15 +679,23 @@ func (x *Indexer) VisitFile(path string, f *os.FileInfo) {
return
}
- file, err := parser.ParseFile(path, nil, nil, parser.ParseComments)
- if err != nil {
- return // ignore files with (parse) errors
+ file := x.addFile(path)
+ if file == nil {
+ return
}
+ // we've got a file to index
+ x.current = x.fset.File(file.Pos()) // file.Pos is in the current file
dir, _ := pathutil.Split(path)
- pak := Pak{dir, file.Name.Name()}
+ pak := Pak{dir, file.Name.Name}
x.file = &File{path, pak}
ast.Walk(x, file)
+
+ // update statistics
+ // (count real file size as opposed to using the padded x.sources.Len())
+ x.stats.Bytes += x.current.Size()
+ x.stats.Files++
+ x.stats.Lines += x.current.LineCount()
}
@@ -613,30 +704,54 @@ func (x *Indexer) VisitFile(path string, f *os.FileInfo) {
type LookupResult struct {
Decls HitList // package-level declarations (with snippets)
- Others HitList // all other occurences
+ Others HitList // all other occurrences
}
type Index struct {
+ fset *token.FileSet // file set used during indexing; nil if no textindex
+ suffixes *suffixarray.Index // suffixes for concatenated sources; nil if no textindex
words map[string]*LookupResult // maps words to hit lists
alts map[string]*AltWords // maps canonical(words) to lists of alternative spellings
snippets []*Snippet // all snippets, indexed by snippet index
- nspots int // number of spots indexed (a measure of the index size)
+ stats Statistics
}
func canonical(w string) string { return strings.ToLower(w) }
-// NewIndex creates a new index for the file tree rooted at root.
-func NewIndex(root string) *Index {
+// NewIndex creates a new index for the .go files
+// in the directories given by dirnames.
+//
+func NewIndex(dirnames <-chan string, fulltextIndex bool) *Index {
var x Indexer
// initialize Indexer
+ x.fset = token.NewFileSet()
x.words = make(map[string]*IndexResult)
- // collect all Spots
- pathutil.Walk(root, &x, nil)
+ // index all files in the directories given by dirnames
+ for dirname := range dirnames {
+ list, err := ioutil.ReadDir(dirname)
+ if err != nil {
+ continue // ignore this directory
+ }
+ for _, f := range list {
+ if !f.IsDirectory() {
+ x.visitFile(dirname, f)
+ }
+ }
+ }
+
+ if !fulltextIndex {
+ // the file set, the current file, and the sources are
+ // not needed after indexing if no text index is built -
+ // help GC and clear them
+ x.fset = nil
+ x.sources.Reset()
+ x.current = nil // contains reference to fset!
+ }
// for each word, reduce the RunLists into a LookupResult;
// also collect the word with its canonical spelling in a
@@ -652,6 +767,7 @@ func NewIndex(root string) *Index {
}
wlist.Push(&wordPair{canonical(w), w})
}
+ x.stats.Words = len(words)
// reduce the word list {canonical(w), w} into
// a list of AltWords runs {canonical(w), {w}}
@@ -670,14 +786,19 @@ func NewIndex(root string) *Index {
snippets[i] = x.snippets.At(i).(*Snippet)
}
- return &Index{words, alts, snippets, x.nspots}
+ // 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}
}
-// Size returns the number of different words and
-// spots indexed as a measure for the index size.
-func (x *Index) Size() (nwords int, nspots int) {
- return len(x.words), x.nspots
+// Stats() returns index statistics.
+func (x *Index) Stats() Statistics {
+ return x.stats
}
@@ -696,7 +817,7 @@ func (x *Index) LookupWord(w string) (match *LookupResult, alt *AltWords) {
func isIdentifier(s string) bool {
var S scanner.Scanner
- S.Init("", []byte(s), nil, 0)
+ S.Init(token.NewFileSet(), "", []byte(s), nil, 0)
if _, tok, _ := S.Scan(); tok == token.IDENT {
_, tok, _ := S.Scan()
return tok == token.EOF
@@ -707,14 +828,14 @@ func isIdentifier(s string) bool {
// 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, illegal is set.
-func (x *Index) Lookup(query string) (match *LookupResult, alt *AltWords, illegal bool) {
+// 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) {
ss := strings.Split(query, ".", -1)
// check query syntax
for _, s := range ss {
if !isIdentifier(s) {
- illegal = true
+ err = os.NewError("all query parts must be identifiers")
return
}
}
@@ -734,7 +855,7 @@ func (x *Index) Lookup(query string) (match *LookupResult, alt *AltWords, illega
}
default:
- illegal = true
+ err = os.NewError("query is not a (qualified) identifier")
}
return
@@ -748,3 +869,103 @@ func (x *Index) Snippet(i int) *Snippet {
}
return nil
}
+
+
+type positionList []struct {
+ filename string
+ line int
+}
+
+func (list positionList) Len() int { return len(list) }
+func (list positionList) Less(i, j int) bool { return list[i].filename < list[j].filename }
+func (list positionList) Swap(i, j int) { list[i], list[j] = list[j], list[i] }
+
+
+// unique returns the list sorted and with duplicate entries removed
+func unique(list []int) []int {
+ sort.SortInts(list)
+ var last int
+ i := 0
+ for _, x := range list {
+ if i == 0 || x != last {
+ last = x
+ list[i] = x
+ i++
+ }
+ }
+ return list[0:i]
+}
+
+
+// A FileLines value specifies a file and line numbers within that file.
+type FileLines struct {
+ Filename string
+ Lines []int
+}
+
+
+// LookupRegexp returns the number of matches and the matches where a regular
+// expression r is found in the full text index. At most n matches are
+// returned (thus found <= n).
+//
+func (x *Index) LookupRegexp(r *regexp.Regexp, n int) (found int, result []FileLines) {
+ if x.suffixes == nil || n <= 0 {
+ return
+ }
+ // n > 0
+
+ var list positionList
+ // FindAllIndex may returns matches that span across file boundaries.
+ // Such matches are unlikely, buf after eliminating them we may end up
+ // with fewer than n matches. If we don't have enough at the end, redo
+ // the search with an increased value n1, but only if FindAllIndex
+ // returned all the requested matches in the first place (if it
+ // returned fewer than that there cannot be more).
+ for n1 := n; found < n; n1 += n - found {
+ found = 0
+ matches := x.suffixes.FindAllIndex(r, n1)
+ // compute files, exclude matches that span file boundaries,
+ // and map offsets to file-local offsets
+ list = make(positionList, len(matches))
+ for _, m := range matches {
+ // by construction, an offset corresponds to the Pos value
+ // for the file set - use it to get the file and line
+ p := token.Pos(m[0])
+ if file := x.fset.File(p); file != nil {
+ if base := file.Base(); base <= m[1] && m[1] <= base+file.Size() {
+ // match [m[0], m[1]) is within the file boundaries
+ list[found].filename = file.Name()
+ list[found].line = file.Line(p)
+ found++
+ }
+ }
+ }
+ if found == n || len(matches) < n1 {
+ // found all matches or there's no chance to find more
+ break
+ }
+ }
+ list = list[0:found]
+ sort.Sort(list) // sort by filename
+
+ // collect matches belonging to the same file
+ var last string
+ var lines []int
+ addLines := func() {
+ if len(lines) > 0 {
+ // remove duplicate lines
+ result = append(result, FileLines{last, unique(lines)})
+ lines = nil
+ }
+ }
+ for _, m := range list {
+ if m.filename != last {
+ addLines()
+ last = m.filename
+ }
+ lines = append(lines, m.line)
+ }
+ addLines()
+
+ return
+}
diff --git a/src/cmd/godoc/main.go b/src/cmd/godoc/main.go
index 7a9279a2f..fe3d22fb9 100644
--- a/src/cmd/godoc/main.go
+++ b/src/cmd/godoc/main.go
@@ -49,7 +49,7 @@ var (
// 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 delay in minutes; usually syncDelay == syncMin, but delay may back off exponentially
+ syncDelay delayTime // actual sync interval in minutes; usually syncDelay == syncMin, but syncDelay may back off exponentially
// network
httpAddr = flag.String("http", "", "HTTP service address (e.g., '"+defaultAddr+"')")
@@ -64,29 +64,30 @@ var (
)
-func serveError(c *http.Conn, r *http.Request, relpath string, err os.Error) {
+func serveError(w http.ResponseWriter, r *http.Request, relpath string, err os.Error) {
contents := applyTemplate(errorHTML, "errorHTML", err) // err may contain an absolute path!
- servePage(c, "File "+relpath, "", "", contents)
+ w.WriteHeader(http.StatusNotFound)
+ servePage(w, "File "+relpath, "", "", contents)
}
-func exec(c *http.Conn, args []string) (status int) {
+func exec(rw http.ResponseWriter, args []string) (status int) {
r, w, err := os.Pipe()
if err != nil {
- log.Stderrf("os.Pipe(): %v\n", err)
+ log.Printf("os.Pipe(): %v", err)
return 2
}
bin := args[0]
fds := []*os.File{nil, w, w}
if *verbose {
- log.Stderrf("executing %v", args)
+ log.Printf("executing %v", args)
}
pid, err := os.ForkExec(bin, args, os.Environ(), *goroot, fds)
defer r.Close()
w.Close()
if err != nil {
- log.Stderrf("os.ForkExec(%q): %v\n", bin, err)
+ log.Printf("os.ForkExec(%q): %v", bin, err)
return 2
}
@@ -95,41 +96,38 @@ func exec(c *http.Conn, args []string) (status int) {
wait, err := os.Wait(pid, 0)
if err != nil {
os.Stderr.Write(buf.Bytes())
- log.Stderrf("os.Wait(%d, 0): %v\n", pid, err)
+ log.Printf("os.Wait(%d, 0): %v", pid, err)
return 2
}
status = wait.ExitStatus()
if !wait.Exited() || status > 1 {
os.Stderr.Write(buf.Bytes())
- log.Stderrf("executing %v failed (exit status = %d)", args, status)
+ log.Printf("executing %v failed (exit status = %d)", args, status)
return
}
if *verbose {
os.Stderr.Write(buf.Bytes())
}
- if c != nil {
- c.SetHeader("content-type", "text/plain; charset=utf-8")
- c.Write(buf.Bytes())
+ if rw != nil {
+ rw.SetHeader("content-type", "text/plain; charset=utf-8")
+ rw.Write(buf.Bytes())
}
return
}
-// Maximum directory depth, adjust as needed.
-const maxDirDepth = 24
-
-func dosync(c *http.Conn, r *http.Request) {
+func dosync(w http.ResponseWriter, r *http.Request) {
args := []string{"/bin/sh", "-c", *syncCmd}
- switch exec(c, args) {
+ 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.
- fsTree.set(newDirectory(*goroot, maxDirDepth))
+ initFSTree()
fallthrough
case 1:
// sync failed because no files changed;
@@ -152,9 +150,9 @@ func usage() {
func loggingHandler(h http.Handler) http.Handler {
- return http.HandlerFunc(func(c *http.Conn, req *http.Request) {
- log.Stderrf("%s\t%s", c.RemoteAddr, req.URL)
- h.ServeHTTP(c, req)
+ return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
+ log.Printf("%s\t%s", w.RemoteAddr(), req.URL)
+ h.ServeHTTP(w, req)
})
}
@@ -239,13 +237,16 @@ func main() {
// HTTP server mode.
var handler http.Handler = http.DefaultServeMux
if *verbose {
- log.Stderrf("Go Documentation Server\n")
- log.Stderrf("version = %s\n", runtime.Version())
- log.Stderrf("address = %s\n", *httpAddr)
- log.Stderrf("goroot = %s\n", *goroot)
- log.Stderrf("tabwidth = %d\n", *tabwidth)
+ log.Printf("Go Documentation Server")
+ log.Printf("version = %s", runtime.Version())
+ log.Printf("address = %s", *httpAddr)
+ log.Printf("goroot = %s", *goroot)
+ log.Printf("tabwidth = %d", *tabwidth)
+ if *fulltextIndex {
+ log.Print("full text index enabled")
+ }
if !fsMap.IsEmpty() {
- log.Stderr("user-defined mapping:")
+ log.Print("user-defined mapping:")
fsMap.Fprint(os.Stderr)
}
handler = loggingHandler(handler)
@@ -256,12 +257,12 @@ func main() {
http.Handle("/debug/sync", http.HandlerFunc(dosync))
}
- // Initialize directory tree with corresponding timestamp.
- // Do it in two steps:
- // 1) set timestamp right away so that the indexer is kicked on
- fsTree.set(nil)
- // 2) compute initial directory tree in a goroutine so that launch is quick
- go func() { fsTree.set(newDirectory(*goroot, maxDirDepth)) }()
+ // 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 {
@@ -271,7 +272,7 @@ func main() {
dosync(nil, nil)
delay, _ := syncDelay.get()
if *verbose {
- log.Stderrf("next sync in %dmin", delay.(int))
+ log.Printf("next sync in %dmin", delay.(int))
}
time.Sleep(int64(delay.(int)) * 60e9)
}
@@ -333,15 +334,18 @@ func main() {
}
// TODO(gri): Provide a mechanism (flag?) to select a package
// if there are multiple packages in a directory.
- info := pkgHandler.getPageInfo(abspath, relpath, "", mode|tryMode)
+ info := pkgHandler.getPageInfo(abspath, relpath, "", mode)
- if info.PAst == nil && info.PDoc == nil && info.Dirs == nil {
+ if info.Err != nil || info.PAst == nil && info.PDoc == nil && info.Dirs == nil {
// try again, this time assume it's a command
if len(path) > 0 && path[0] != '/' {
abspath = absolutePath(path, cmdHandler.fsRoot)
}
info = cmdHandler.getPageInfo(abspath, relpath, "", mode)
}
+ if info.Err != nil {
+ log.Exitf("%v", info.Err)
+ }
// If we have more than one argument, use the remaining arguments for filtering
if flag.NArg() > 1 {
@@ -362,7 +366,7 @@ func main() {
if i > 0 {
fmt.Println()
}
- writeAny(os.Stdout, d, *html)
+ writeAny(os.Stdout, info.FSet, *html, d)
fmt.Println()
}
return
@@ -373,6 +377,6 @@ func main() {
}
if err := packageText.Execute(info, os.Stdout); err != nil {
- log.Stderrf("packageText.Execute: %s", err)
+ log.Printf("packageText.Execute: %s", err)
}
}
diff --git a/src/cmd/godoc/mapping.go b/src/cmd/godoc/mapping.go
index 400f97e1f..1d87bbc76 100644
--- a/src/cmd/godoc/mapping.go
+++ b/src/cmd/godoc/mapping.go
@@ -11,6 +11,7 @@ import (
"io"
"os"
pathutil "path"
+ "sort"
"strings"
)
@@ -42,14 +43,19 @@ import (
//
// (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
+ prefixes []string // lazily computed from list
}
type mapping struct {
prefix, path string
+ value *RWValue
}
@@ -75,43 +81,16 @@ type mapping struct {
// public -> /home/build/public
//
func (m *Mapping) Init(paths string) {
- cwd, _ := os.Getwd() // ignore errors
-
- pathlist := strings.Split(paths, ":", -1)
-
+ pathlist := canonicalizePaths(strings.Split(paths, ":", -1), nil)
list := make([]mapping, len(pathlist))
- n := 0 // number of mappings
- for _, path := range pathlist {
- if len(path) == 0 {
- // ignore empty paths (don't assume ".")
- continue
- }
-
- // len(path) > 0: normalize path
- if path[0] != '/' {
- path = pathutil.Join(cwd, path)
- } else {
- path = pathutil.Clean(path)
- }
-
- // check if mapping exists already
- var i int
- for i = 0; i < n; i++ {
- if path == list[i].path {
- break
- }
- }
-
- // add mapping if it is new
- if i >= n {
- _, prefix := pathutil.Split(path)
- list[n] = mapping{prefix, path}
- n++
- }
+ // create mapping list
+ for i, path := range pathlist {
+ _, prefix := pathutil.Split(path)
+ list[i] = mapping{prefix, path, new(RWValue)}
}
- m.list = list[0:n]
+ m.list = list
}
@@ -134,24 +113,25 @@ func (m *Mapping) PrefixList() []string {
// compute the list lazily
if m.prefixes == nil {
list := make([]string, len(m.list))
- n := 0 // nuber of prefixes
-
- for _, e := range m.list {
- // check if prefix exists already
- var i int
- for i = 0; i < n; i++ {
- if e.prefix == list[i] {
- break
- }
- }
- // add prefix if it is new
- if i >= n {
- list[n] = e.prefix
- n++
+ // populate list
+ for i, e := range m.list {
+ list[i] = e.prefix
+ }
+
+ // sort the list and remove duplicate entries
+ sort.SortStrings(list)
+ i := 0
+ prev := ""
+ for _, path := range list {
+ if path != prev {
+ list[i] = path
+ i++
+ prev = path
}
}
- m.prefixes = list[0:n]
+
+ m.prefixes = list[0:i]
}
return m.prefixes
@@ -166,7 +146,7 @@ func (m *Mapping) Fprint(w io.Writer) {
}
-func split(path string) (head, tail string) {
+func splitFirst(path string) (head, tail string) {
i := strings.Index(path, "/")
if i > 0 {
// 0 < i < len(path)
@@ -181,7 +161,7 @@ func split(path string) (head, tail string) {
// string is returned.
//
func (m *Mapping) ToAbsolute(path string) string {
- prefix, tail := split(path)
+ prefix, tail := splitFirst(path)
for _, e := range m.list {
switch {
case e.prefix == prefix:
@@ -214,3 +194,15 @@ func (m *Mapping) ToRelative(path string) string {
}
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/snippet.go b/src/cmd/godoc/snippet.go
index d8fb19533..6a12febe1 100755
--- a/src/cmd/godoc/snippet.go
+++ b/src/cmd/godoc/snippet.go
@@ -12,41 +12,22 @@ package main
import (
"bytes"
"go/ast"
- "go/printer"
+ "go/token"
"fmt"
)
type Snippet struct {
Line int
- Text string
+ Text []byte
}
-type snippetStyler struct {
- Styler // defined in godoc.go
- highlight *ast.Ident // identifier to highlight
-}
-
-
-func (s *snippetStyler) LineTag(line int) (text []uint8, tag printer.HTMLTag) {
- return // no LineTag for snippets
-}
-
-
-func (s *snippetStyler) Ident(id *ast.Ident) (text []byte, tag printer.HTMLTag) {
- text = []byte(id.Name())
- if s.highlight == id {
- tag = printer.HTMLTag{"<span class=highlight>", "</span>"}
- }
- return
-}
-
-
-func newSnippet(decl ast.Decl, id *ast.Ident) *Snippet {
+func newSnippet(fset *token.FileSet, decl ast.Decl, id *ast.Ident) *Snippet {
+ // TODO instead of pretty-printing the node, should use the original source instead
var buf bytes.Buffer
- writeNode(&buf, decl, true, &snippetStyler{highlight: id})
- return &Snippet{id.Pos().Line, buf.String()}
+ writeNode(&buf, fset, decl, true)
+ return &Snippet{fset.Position(id.Pos()).Line, FormatText(buf.Bytes(), -1, true, id.Name, nil)}
}
@@ -73,20 +54,20 @@ func findSpec(list []ast.Spec, id *ast.Ident) ast.Spec {
}
-func genSnippet(d *ast.GenDecl, id *ast.Ident) *Snippet {
+func genSnippet(fset *token.FileSet, d *ast.GenDecl, id *ast.Ident) *Snippet {
s := findSpec(d.Specs, id)
if s == nil {
return nil // declaration doesn't contain id - exit gracefully
}
// only use the spec containing the id for the snippet
- dd := &ast.GenDecl{d.Doc, d.Position, d.Tok, d.Lparen, []ast.Spec{s}, d.Rparen}
+ dd := &ast.GenDecl{d.Doc, d.Pos(), d.Tok, d.Lparen, []ast.Spec{s}, d.Rparen}
- return newSnippet(dd, id)
+ return newSnippet(fset, dd, id)
}
-func funcSnippet(d *ast.FuncDecl, id *ast.Ident) *Snippet {
+func funcSnippet(fset *token.FileSet, d *ast.FuncDecl, id *ast.Ident) *Snippet {
if d.Name != id {
return nil // declaration doesn't contain id - exit gracefully
}
@@ -94,7 +75,7 @@ func funcSnippet(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}
- return newSnippet(dd, id)
+ return newSnippet(fset, dd, id)
}
@@ -102,19 +83,21 @@ func funcSnippet(d *ast.FuncDecl, id *ast.Ident) *Snippet {
// identifier id. Parts of the declaration not containing the identifier
// may be removed for a more compact snippet.
//
-func NewSnippet(decl ast.Decl, id *ast.Ident) (s *Snippet) {
+func NewSnippet(fset *token.FileSet, decl ast.Decl, id *ast.Ident) (s *Snippet) {
switch d := decl.(type) {
case *ast.GenDecl:
- s = genSnippet(d, id)
+ s = genSnippet(fset, d, id)
case *ast.FuncDecl:
- s = funcSnippet(d, id)
+ s = funcSnippet(fset, d, id)
}
// handle failure gracefully
if s == nil {
+ var buf bytes.Buffer
+ fmt.Fprintf(&buf, `<span class="alert">could not generate a snippet for <span class="highlight">%s</span></span>`, id.Name)
s = &Snippet{
- id.Pos().Line,
- fmt.Sprintf(`could not generate a snippet for <span class="highlight">%s</span>`, id.Name()),
+ fset.Position(id.Pos()).Line,
+ buf.Bytes(),
}
}
return
diff --git a/src/cmd/godoc/spec.go b/src/cmd/godoc/spec.go
index 2298fae2c..b1c1a883f 100644
--- a/src/cmd/godoc/spec.go
+++ b/src/cmd/godoc/spec.go
@@ -20,24 +20,28 @@ import (
type ebnfParser struct {
- out io.Writer // parser output
- src []byte // parser source
+ out io.Writer // parser output
+ src []byte // parser source
+ file *token.File // for position information
scanner scanner.Scanner
- prev int // offset of previous token
- pos token.Position // token position
- tok token.Token // one token look-ahead
- lit []byte // token literal
+ prev int // offset of previous token
+ pos token.Pos // token position
+ tok token.Token // one token look-ahead
+ lit []byte // token literal
}
func (p *ebnfParser) flush() {
- p.out.Write(p.src[p.prev:p.pos.Offset])
- p.prev = p.pos.Offset
+ offs := p.file.Offset(p.pos)
+ p.out.Write(p.src[p.prev:offs])
+ p.prev = offs
}
func (p *ebnfParser) next() {
- p.flush()
+ 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?
@@ -52,9 +56,9 @@ func (p *ebnfParser) Error(pos token.Position, msg string) {
}
-func (p *ebnfParser) errorExpected(pos token.Position, msg string) {
+func (p *ebnfParser) errorExpected(pos token.Pos, msg string) {
msg = "expected " + msg
- if pos.Offset == p.pos.Offset {
+ if pos == p.pos {
// the error happened at the current position;
// make the error message more specific
msg += ", found '" + p.tok.String() + "'"
@@ -62,11 +66,11 @@ func (p *ebnfParser) errorExpected(pos token.Position, msg string) {
msg += " " + string(p.lit)
}
}
- p.Error(pos, msg)
+ p.Error(p.file.Position(pos), msg)
}
-func (p *ebnfParser) expect(tok token.Token) token.Position {
+func (p *ebnfParser) expect(tok token.Token) token.Pos {
pos := p.pos
if p.tok != tok {
p.errorExpected(pos, "'"+tok.String()+"'")
@@ -148,11 +152,11 @@ func (p *ebnfParser) parseProduction() {
}
-func (p *ebnfParser) parse(out io.Writer, src []byte) {
+func (p *ebnfParser) parse(fset *token.FileSet, out io.Writer, src []byte) {
// initialize ebnfParser
p.out = out
p.src = src
- p.scanner.Init("", src, p, 0)
+ p.file = p.scanner.Init(fset, "", src, p, 0)
p.next() // initializes pos, tok, lit
// process source
@@ -171,6 +175,7 @@ var (
func linkify(out io.Writer, src []byte) {
+ fset := token.NewFileSet()
for len(src) > 0 {
n := len(src)
@@ -192,7 +197,7 @@ func linkify(out io.Writer, src []byte) {
out.Write(src[0:i])
// parse and write EBNF
var p ebnfParser
- p.parse(out, src[i:j])
+ p.parse(fset, out, src[i:j])
// advance
src = src[j:n]
diff --git a/src/cmd/godoc/utils.go b/src/cmd/godoc/utils.go
new file mode 100644
index 000000000..55cf87841
--- /dev/null
+++ b/src/cmd/godoc/utils.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.
+
+// This file contains support functionality for godoc.
+
+package main
+
+import (
+ "io"
+ "io/ioutil"
+ "os"
+ pathutil "path"
+ "sort"
+ "strings"
+ "sync"
+ "time"
+)
+
+
+// An RWValue wraps a value and permits mutually exclusive
+// access to it and records the time the value was last set.
+type RWValue struct {
+ mutex sync.RWMutex
+ value interface{}
+ timestamp int64 // time of last set(), in seconds since epoch
+}
+
+
+func (v *RWValue) set(value interface{}) {
+ v.mutex.Lock()
+ v.value = value
+ v.timestamp = time.Seconds()
+ v.mutex.Unlock()
+}
+
+
+func (v *RWValue) get() (interface{}, int64) {
+ v.mutex.RLock()
+ defer v.mutex.RUnlock()
+ return v.value, v.timestamp
+}
+
+
+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 path[0] != '/' {
+ path = pathutil.Join(cwd, path)
+ } else {
+ path = pathutil.Clean(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.SortStrings(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 {
+ f, err := ioutil.TempFile(cwd, 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)
+}
diff --git a/src/cmd/gofmt/Makefile b/src/cmd/gofmt/Makefile
index 2294fd1db..5f2f454e8 100644
--- a/src/cmd/gofmt/Makefile
+++ b/src/cmd/gofmt/Makefile
@@ -2,12 +2,13 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=gofmt
GOFILES=\
gofmt.go\
rewrite.go\
+ simplify.go\
include ../../Make.cmd
@@ -15,5 +16,4 @@ test: $(TARG)
./test.sh
smoketest: $(TARG)
- ./test.sh "$(GOROOT)"/src/pkg/go/parser/parser.go
-
+ (cd testdata; ./test.sh)
diff --git a/src/cmd/gofmt/doc.go b/src/cmd/gofmt/doc.go
index 2e4c40c21..2d2c9ae61 100644
--- a/src/cmd/gofmt/doc.go
+++ b/src/cmd/gofmt/doc.go
@@ -20,6 +20,8 @@ The flags are:
unless -w is also set.
-r rule
apply the rewrite rule to the source before reformatting.
+ -s
+ try to simplify code (after applying the rewrite rule, if any).
-w
if set, overwrite each input file with its output.
-spaces
@@ -33,6 +35,8 @@ Debugging flags:
-trace
print parse trace.
+ -ast
+ print AST (before rewrites).
-comments=true
print comments; if false, all comments are elided from the output.
diff --git a/src/cmd/gofmt/gofmt.go b/src/cmd/gofmt/gofmt.go
index ffec0325f..d7b70c461 100644
--- a/src/cmd/gofmt/gofmt.go
+++ b/src/cmd/gofmt/gofmt.go
@@ -12,6 +12,7 @@ import (
"go/parser"
"go/printer"
"go/scanner"
+ "go/token"
"io/ioutil"
"os"
pathutil "path"
@@ -24,11 +25,12 @@ var (
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(α)] -> α[β:]')")
+ simplifyAST = flag.Bool("s", false, "simplify code")
// debugging support
comments = flag.Bool("comments", true, "print comments")
- debug = flag.Bool("debug", false, "print debugging information")
trace = flag.Bool("trace", false, "print parse trace")
+ printAST = flag.Bool("ast", false, "print AST (before rewrites)")
// layout control
tabWidth = flag.Int("tabwidth", 8, "tab width")
@@ -38,6 +40,7 @@ var (
var (
+ fset = token.NewFileSet()
exitCode = 0
rewrite func(*ast.File) *ast.File
parserMode uint
@@ -92,22 +95,26 @@ func processFile(f *os.File) os.Error {
return err
}
- var scope *ast.Scope
- if *debug {
- scope = ast.NewScope(nil)
- }
- file, err := parser.ParseFile(f.Name(), src, scope, parserMode)
+ file, err := parser.ParseFile(fset, f.Name(), src, parserMode)
if err != nil {
return err
}
+ if *printAST {
+ ast.Print(file)
+ }
+
if rewrite != nil {
file = rewrite(file)
}
+ if *simplifyAST {
+ simplify(file)
+ }
+
var res bytes.Buffer
- _, err = (&printer.Config{printerMode, *tabWidth, nil}).Fprint(&res, file)
+ _, err = (&printer.Config{printerMode, *tabWidth, nil}).Fprint(&res, fset, file)
if err != nil {
return err
}
@@ -133,10 +140,10 @@ func processFile(f *os.File) os.Error {
}
-func processFileByName(filename string) (err os.Error) {
+func processFileByName(filename string) os.Error {
file, err := os.Open(filename, os.O_RDONLY, 0)
if err != nil {
- return
+ return err
}
defer file.Close()
return processFile(file)
diff --git a/src/cmd/gofmt/rewrite.go b/src/cmd/gofmt/rewrite.go
index a89146ca0..8ea5334e9 100644
--- a/src/cmd/gofmt/rewrite.go
+++ b/src/cmd/gofmt/rewrite.go
@@ -37,7 +37,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("input", s, nil)
+ x, err := parser.ParseExpr(fset, "input", s)
if err != nil {
fmt.Fprintf(os.Stderr, "parsing %s %s: %s\n", what, s, err)
os.Exit(2)
@@ -66,13 +66,19 @@ func rewriteFile(pattern, replace ast.Expr, p *ast.File) *ast.File {
}
-var positionType = reflect.Typeof(token.Position{})
-var identType = reflect.Typeof((*ast.Ident)(nil))
-
-
-func isWildcard(s string) bool {
- rune, size := utf8.DecodeRuneInString(s)
- return size == len(s) && unicode.IsLower(rune)
+// setValue is a wrapper for x.SetValue(y); it protects
+// the caller from panics if x cannot be changed to y.
+func setValue(x, y reflect.Value) {
+ defer func() {
+ if x := recover(); x != nil {
+ if s, ok := x.(string); ok && strings.HasPrefix(s, "type mismatch") {
+ // x cannot be set to y - ignore this rewrite
+ return
+ }
+ panic(x)
+ }
+ }()
+ x.SetValue(y)
}
@@ -86,21 +92,31 @@ func apply(f func(reflect.Value) reflect.Value, val reflect.Value) reflect.Value
case *reflect.SliceValue:
for i := 0; i < v.Len(); i++ {
e := v.Elem(i)
- e.SetValue(f(e))
+ setValue(e, f(e))
}
case *reflect.StructValue:
for i := 0; i < v.NumField(); i++ {
e := v.Field(i)
- e.SetValue(f(e))
+ setValue(e, f(e))
}
case *reflect.InterfaceValue:
e := v.Elem()
- v.SetValue(f(e))
+ setValue(v, f(e))
}
return val
}
+var positionType = reflect.Typeof(token.NoPos)
+var identType = reflect.Typeof((*ast.Ident)(nil))
+
+
+func isWildcard(s string) bool {
+ rune, size := utf8.DecodeRuneInString(s)
+ return size == len(s) && unicode.IsLower(rune)
+}
+
+
// match returns true if pattern matches val,
// recording wildcard submatches in m.
// If m == nil, match checks whether pattern == val.
@@ -109,17 +125,20 @@ func match(m map[string]reflect.Value, pattern, val reflect.Value) bool {
// times in the pattern, it must match the same expression
// each time.
if m != nil && pattern.Type() == identType {
- name := pattern.Interface().(*ast.Ident).Name()
+ name := pattern.Interface().(*ast.Ident).Name
if isWildcard(name) {
- if old, ok := m[name]; ok {
- return match(nil, old, val)
+ // wildcards only match expressions
+ if _, ok := val.Interface().(ast.Expr); ok {
+ if old, ok := m[name]; ok {
+ return match(nil, old, val)
+ }
+ m[name] = val
+ return true
}
- m[name] = val
- return true
}
}
- // Otherwise, the expressions must match recursively.
+ // Otherwise, pattern and val must match recursively.
if pattern == nil || val == nil {
return pattern == nil && val == nil
}
@@ -139,7 +158,7 @@ func match(m map[string]reflect.Value, pattern, val reflect.Value) bool {
// of recursing down any further via reflection.
p := pattern.Interface().(*ast.Ident)
v := val.Interface().(*ast.Ident)
- return p == nil && v == nil || p != nil && v != nil && p.Name() == v.Name()
+ return p == nil && v == nil || p != nil && v != nil && p.Name == v.Name
}
p := reflect.Indirect(pattern)
@@ -194,7 +213,7 @@ func subst(m map[string]reflect.Value, pattern reflect.Value, pos reflect.Value)
// Wildcard gets replaced with map value.
if m != nil && pattern.Type() == identType {
- name := pattern.Interface().(*ast.Ident).Name()
+ name := pattern.Interface().(*ast.Ident).Name
if isWildcard(name) {
if old, ok := m[name]; ok {
return subst(nil, old, nil)
@@ -203,6 +222,10 @@ func subst(m map[string]reflect.Value, pattern reflect.Value, pos reflect.Value)
}
if pos != nil && pattern.Type() == positionType {
+ // use new position only if old position was valid in the first place
+ if old := pattern.Interface().(token.Pos); !old.IsValid() {
+ return pattern
+ }
return pos
}
diff --git a/src/cmd/gofmt/simplify.go b/src/cmd/gofmt/simplify.go
new file mode 100644
index 000000000..bcc67c4a6
--- /dev/null
+++ b/src/cmd/gofmt/simplify.go
@@ -0,0 +1,67 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "go/ast"
+ "reflect"
+)
+
+
+type simplifier struct{}
+
+func (s *simplifier) Visit(node ast.Node) ast.Visitor {
+ switch n := node.(type) {
+ case *ast.CompositeLit:
+ // array, slice, and map composite literals may be simplified
+ outer := n
+ var eltType ast.Expr
+ switch typ := outer.Type.(type) {
+ case *ast.ArrayType:
+ eltType = typ.Elt
+ case *ast.MapType:
+ eltType = typ.Value
+ }
+
+ if eltType != nil {
+ typ := reflect.NewValue(eltType)
+ for _, x := range outer.Elts {
+ // look at value of indexed/named elements
+ if t, ok := x.(*ast.KeyValueExpr); ok {
+ x = t.Value
+ }
+ simplify(x)
+ // if the element is a composite literal and its literal type
+ // matches the outer literal's element type exactly, the inner
+ // literal type may be omitted
+ if inner, ok := x.(*ast.CompositeLit); ok {
+ if match(nil, typ, reflect.NewValue(inner.Type)) {
+ inner.Type = nil
+ }
+ }
+ }
+
+ // node was simplified - stop walk (there are no subnodes to simplify)
+ return nil
+ }
+
+ case *ast.RangeStmt:
+ // range of the form: for x, _ = range v {...}
+ // can be simplified to: for x = range v {...}
+ if n.Value != nil {
+ if ident, ok := n.Value.(*ast.Ident); ok && ident.Name == "_" {
+ n.Value = nil
+ }
+ }
+ }
+
+ return s
+}
+
+
+func simplify(node ast.Node) {
+ var s simplifier
+ ast.Walk(&s, node)
+}
diff --git a/src/cmd/gofmt/test.sh b/src/cmd/gofmt/test.sh
index bed46532b..b5f4de1e2 100755
--- a/src/cmd/gofmt/test.sh
+++ b/src/cmd/gofmt/test.sh
@@ -3,7 +3,7 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-. "$GOROOT"/src/Make.$GOARCH
+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
@@ -41,7 +41,8 @@ apply1() {
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 ) return ;;
+ bug282.go | bug287.go | bug298.go | bug299.go | bug300.go | \
+ bug302.go | bug306.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:
diff --git a/src/cmd/gofmt/testdata/composites.golden b/src/cmd/gofmt/testdata/composites.golden
new file mode 100644
index 000000000..1fd5847c1
--- /dev/null
+++ b/src/cmd/gofmt/testdata/composites.golden
@@ -0,0 +1,104 @@
+package P
+
+type T struct {
+ x, y int
+}
+
+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},
+}
+
+// from exp/4s/data.go
+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
new file mode 100644
index 000000000..15afd9e5c
--- /dev/null
+++ b/src/cmd/gofmt/testdata/composites.input
@@ -0,0 +1,104 @@
+package P
+
+type T struct {
+ x, y int
+}
+
+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},
+}
+
+// from exp/4s/data.go
+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/test.sh b/src/cmd/gofmt/testdata/test.sh
new file mode 100755
index 000000000..a1d5d823e
--- /dev/null
+++ b/src/cmd/gofmt/testdata/test.sh
@@ -0,0 +1,65 @@
+#!/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.
+
+CMD="../gofmt"
+TMP=test_tmp.go
+COUNT=0
+
+
+cleanup() {
+ rm -f $TMP
+}
+
+
+error() {
+ echo $1
+ exit 1
+}
+
+
+count() {
+ #echo $1
+ let COUNT=$COUNT+1
+ let M=$COUNT%10
+ if [ $M == 0 ]; then
+ echo -n "."
+ fi
+}
+
+
+test() {
+ count $1
+
+ # compare against .golden file
+ cleanup
+ $CMD -s $1 > $TMP
+ cmp -s $TMP $2
+ if [ $? != 0 ]; then
+ diff $TMP $2
+ error "Error: simplified $1 does not match $2"
+ fi
+
+ # make sure .golden is idempotent
+ cleanup
+ $CMD -s $2 > $TMP
+ cmp -s $TMP $2
+ if [ $? != 0 ]; then
+ diff $TMP $2
+ error "Error: $2 is not idempotent"
+ fi
+}
+
+
+runtests() {
+ smoketest=../../../pkg/go/parser/parser.go
+ test $smoketest $smoketest
+ test composites.input composites.golden
+ # add more test cases here
+}
+
+
+runtests
+cleanup
+echo "PASSED ($COUNT tests)"
diff --git a/src/cmd/goinstall/Makefile b/src/cmd/goinstall/Makefile
index cf4728401..6ddb32be7 100644
--- a/src/cmd/goinstall/Makefile
+++ b/src/cmd/goinstall/Makefile
@@ -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 ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=goinstall
GOFILES=\
diff --git a/src/cmd/goinstall/doc.go b/src/cmd/goinstall/doc.go
index 80b30d5ac..17cc06969 100644
--- a/src/cmd/goinstall/doc.go
+++ b/src/cmd/goinstall/doc.go
@@ -10,14 +10,33 @@ It maintains a list of public Go packages at http://godashboard.appspot.com/pack
Usage:
goinstall [flags] importpath...
+ goinstall [flags] -a
Flags and default settings:
+ -a=false install all previously installed packages
-dashboard=true tally public packages on godashboard.appspot.com
- -update=false update already-downloaded packages
+ -log=true log installed packages to $GOROOT/goinstall.log for use by -a
+ -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.
+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/. If the import
@@ -31,8 +50,8 @@ if necessary. The recognized code hosting sites are:
GitHub (Git)
- import "github.com/user/project.git"
- import "github.com/user/project.git/sub/directory"
+ import "github.com/user/project"
+ import "github.com/user/project/sub/directory"
Google Code Project Hosting (Mercurial, Subversion)
@@ -44,17 +63,17 @@ if necessary. The recognized code hosting sites are:
Launchpad
- import "launchpad.net/project
- import "launchpad.net/project/series
- import "launchpad.net/project/series/sub/directory
+ 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
+ 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 -update flag changes this behavior,
+attempt to fetch updates. The -u flag changes this behavior,
causing goinstall to update all remote packages encountered during
the installation.
diff --git a/src/cmd/goinstall/download.go b/src/cmd/goinstall/download.go
index 3422e8186..889f9d857 100644
--- a/src/cmd/goinstall/download.go
+++ b/src/cmd/goinstall/download.go
@@ -38,16 +38,16 @@ var launchpad = regexp.MustCompile(`^(launchpad\.net/([a-z0-9A-Z_.\-]+(/[a-z0-9A
// download checks out or updates pkg from the remote server.
func download(pkg string) (string, os.Error) {
- if strings.Index(pkg, "..") >= 0 {
+ if strings.Contains(pkg, "..") {
return "", os.ErrorString("invalid path (contains ..)")
}
- if m := bitbucket.MatchStrings(pkg); m != nil {
+ if m := bitbucket.FindStringSubmatch(pkg); m != nil {
if err := vcsCheckout(&hg, root+m[1], "http://"+m[1], m[1]); err != nil {
return "", err
}
return root + pkg, nil
}
- if m := googlecode.MatchStrings(pkg); m != nil {
+ if m := googlecode.FindStringSubmatch(pkg); m != nil {
var v *vcs
switch m[2] {
case "hg":
@@ -58,12 +58,12 @@ func download(pkg string) (string, os.Error) {
// regexp only allows hg, svn to get through
panic("missing case in download: " + pkg)
}
- if err := vcsCheckout(v, root+m[1], "http://"+m[1], m[1]); err != nil {
+ if err := vcsCheckout(v, root+m[1], "https://"+m[1], m[1]); err != nil {
return "", err
}
return root + pkg, nil
}
- if m := github.MatchStrings(pkg); m != nil {
+ if m := github.FindStringSubmatch(pkg); m != nil {
if strings.HasSuffix(m[1], ".git") {
return "", os.ErrorString("repository " + pkg + " should not have .git suffix")
}
@@ -72,7 +72,7 @@ func download(pkg string) (string, os.Error) {
}
return root + pkg, nil
}
- if m := launchpad.MatchStrings(pkg); m != nil {
+ if m := launchpad.FindStringSubmatch(pkg); m != nil {
// Either lp.net/<project>[/<series>[/<path>]]
// or lp.net/~<user or team>/<project>/<branch>[/<path>]
if err := vcsCheckout(&bzr, root+m[1], "https://"+m[1], m[1]); err != nil {
@@ -88,6 +88,7 @@ func download(pkg string) (string, os.Error) {
type vcs struct {
cmd string
metadir string
+ checkout string
clone string
update string
updateReleaseFlag string
@@ -101,6 +102,7 @@ type vcs struct {
var hg = vcs{
cmd: "hg",
metadir: ".hg",
+ checkout: "checkout",
clone: "clone",
update: "update",
updateReleaseFlag: "release",
@@ -113,18 +115,20 @@ var hg = vcs{
var git = vcs{
cmd: "git",
metadir: ".git",
+ checkout: "checkout",
clone: "clone",
update: "pull",
updateReleaseFlag: "release",
pull: "fetch",
- log: "log",
- logLimitFlag: "-n1",
+ log: "show-ref",
+ logLimitFlag: "",
logReleaseFlag: "release",
}
var svn = vcs{
cmd: "svn",
metadir: ".svn",
+ checkout: "checkout",
clone: "checkout",
update: "update",
updateReleaseFlag: "release",
@@ -136,6 +140,7 @@ var svn = vcs{
var bzr = vcs{
cmd: "bzr",
metadir: ".bzr",
+ checkout: "update",
clone: "branch",
update: "update",
updateReleaseFlag: "-rrelease",
@@ -146,6 +151,22 @@ var bzr = vcs{
logReleaseFlag: "-rrelease",
}
+// Try to detect if a "release" tag exists. If it does, update
+// to the tagged version, otherwise just update the current branch.
+// NOTE(_nil): svn will always fail because it is trying to get
+// the revision history of a file named "release" instead of
+// looking for a commit with a release tag
+func (v *vcs) updateRepo(dst string) os.Error {
+ if err := quietRun(dst, nil, v.cmd, v.log, v.logLimitFlag, v.logReleaseFlag); err == nil {
+ if err := run(dst, nil, v.cmd, v.checkout, v.updateReleaseFlag); err != nil {
+ return err
+ }
+ } else if err := run(dst, nil, v.cmd, v.update); err != nil {
+ return err
+ }
+ return nil
+}
+
// vcsCheckout 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)
@@ -164,8 +185,9 @@ func vcsCheckout(vcs *vcs, dst, repo, dashpath string) os.Error {
if err := run("/", nil, vcs.cmd, vcs.clone, repo, dst); err != nil {
return err
}
- quietRun(dst, nil, vcs.cmd, vcs.update, vcs.updateReleaseFlag)
-
+ if err := vcs.updateRepo(dst); err != nil {
+ return err
+ }
// success on first installation - report
maybeReportToDashboard(dashpath)
} else if *update {
@@ -181,19 +203,8 @@ func vcsCheckout(vcs *vcs, dst, repo, dashpath string) os.Error {
}
}
- // Try to detect if a "release" tag exists. If it does, update
- // to the tagged version. If no tag is found, then update to the
- // tip afterwards.
- // NOTE(gustavo@niemeyer.net): What is the expected behavior with
- // svn here? "svn log -l1 release" doesn't make sense in this
- // context and will probably fail.
- if err := quietRun(dst, nil, vcs.cmd, vcs.log, vcs.logLimitFlag, vcs.logReleaseFlag); err == nil {
- if err := run(dst, nil, vcs.cmd, vcs.update, vcs.updateReleaseFlag); err != nil {
- // The VCS supports tagging, has the "release" tag, but
- // something else went wrong. Report.
- return err
- }
- } else if err := run(dst, nil, vcs.cmd, vcs.update); err != nil {
+ // Update to release or latest revision
+ if err := vcs.updateRepo(dst); err != nil {
return err
}
}
diff --git a/src/cmd/goinstall/main.go b/src/cmd/goinstall/main.go
index 60efdf082..b0f08efdf 100644
--- a/src/cmd/goinstall/main.go
+++ b/src/cmd/goinstall/main.go
@@ -11,28 +11,37 @@ import (
"exec"
"flag"
"fmt"
+ "go/token"
"io"
+ "io/ioutil"
"os"
"path"
+ "runtime"
"strings"
)
func usage() {
fmt.Fprint(os.Stderr, "usage: goinstall importpath...\n")
+ fmt.Fprintf(os.Stderr, "\tgoinstall -a\n")
flag.PrintDefaults()
os.Exit(2)
}
var (
- argv0 = os.Args[0]
- errors = false
- gobin = os.Getenv("GOBIN")
- parents = make(map[string]string)
- root = os.Getenv("GOROOT")
- visit = make(map[string]status)
+ fset = token.NewFileSet()
+ argv0 = os.Args[0]
+ errors = false
+ parents = make(map[string]string)
+ root = runtime.GOROOT()
+ visit = make(map[string]status)
+ logfile = path.Join(root, "goinstall.log")
+ installedPkgs = make(map[string]bool)
+ allpkg = flag.Bool("a", false, "install all previously installed packages")
reportToDashboard = flag.Bool("dashboard", true, "report public packages at "+dashboardURL)
+ logPkgs = flag.Bool("log", true, "log installed packages to $GOROOT/goinstall.log for use by -a")
update = flag.Bool("u", false, "update already-downloaded packages")
+ clean = flag.Bool("clean", false, "clean the package directory before installing")
verbose = flag.Bool("v", false, "verbose")
)
@@ -51,15 +60,30 @@ func main() {
os.Exit(1)
}
root += "/src/pkg/"
- if gobin == "" {
- gobin = os.Getenv("HOME") + "/bin"
- }
// special case - "unsafe" is already installed
visit["unsafe"] = done
- // install command line arguments
args := flag.Args()
+ if *allpkg || *logPkgs {
+ readPackageList()
+ }
+ if *allpkg {
+ if len(args) != 0 {
+ usage() // -a and package list both provided
+ }
+ // install all packages that were ever installed
+ if len(installedPkgs) == 0 {
+ fmt.Fprintf(os.Stderr, "%s: no installed packages\n", argv0)
+ os.Exit(1)
+ }
+ args = make([]string, len(installedPkgs), len(installedPkgs))
+ i := 0
+ for pkg := range installedPkgs {
+ args[i] = pkg
+ i++
+ }
+ }
if len(args) == 0 {
usage()
}
@@ -82,6 +106,29 @@ func printDeps(pkg string) {
fmt.Fprintf(os.Stderr, "\t%s ->\n", pkg)
}
+// readPackageList reads the list of installed packages from goinstall.log
+func readPackageList() {
+ pkglistdata, _ := ioutil.ReadFile(logfile)
+ pkglist := strings.Fields(string(pkglistdata))
+ for _, pkg := range pkglist {
+ installedPkgs[pkg] = true
+ }
+}
+
+// logPackage logs the named package as installed in goinstall.log, if the package is not found in there
+func logPackage(pkg string) {
+ if installedPkgs[pkg] {
+ return
+ }
+ fout, err := os.Open(logfile, os.O_WRONLY|os.O_APPEND|os.O_CREAT, 0644)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "%s: %s\n", argv0, err)
+ return
+ }
+ fmt.Fprintf(fout, "%s\n", pkg)
+ fout.Close()
+}
+
// 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.
@@ -104,6 +151,11 @@ func install(pkg, parent string) {
// If remote, download or update it.
var dir string
local := false
+ if strings.HasPrefix(pkg, "http://") {
+ fmt.Fprintf(os.Stderr, "%s: %s: 'http://' used in remote path, try '%s'\n", argv0, pkg, pkg[7:])
+ errors = true
+ return
+ }
if isLocalPath(pkg) {
dir = pkg
local = true
@@ -122,23 +174,25 @@ func install(pkg, parent string) {
}
// Install prerequisites.
- files, m, pkgname, err := goFiles(dir, parent == "")
+ dirInfo, err := scanDir(dir, parent == "")
if err != nil {
fmt.Fprintf(os.Stderr, "%s: %s: %s\n", argv0, pkg, err)
errors = true
visit[pkg] = done
return
}
- if len(files) == 0 {
+ if len(dirInfo.goFiles) == 0 {
fmt.Fprintf(os.Stderr, "%s: %s: package has no files\n", argv0, pkg)
errors = true
visit[pkg] = done
return
}
- for p := range m {
- install(p, pkg)
+ for _, p := range dirInfo.imports {
+ if p != "C" {
+ install(p, pkg)
+ }
}
- if pkgname == "main" {
+ if dirInfo.pkgName == "main" {
if !errors {
fmt.Fprintf(os.Stderr, "%s: %s's dependencies are installed.\n", argv0, pkg)
}
@@ -152,9 +206,11 @@ func install(pkg, parent string) {
if err := domake(dir, pkg, local); err != nil {
fmt.Fprintf(os.Stderr, "%s: installing %s: %s\n", argv0, pkg, err)
errors = true
+ } else if !local && *logPkgs {
+ // mark this package as installed in $GOROOT/goinstall.log
+ logPackage(pkg)
}
}
-
visit[pkg] = done
}
@@ -207,6 +263,9 @@ func genRun(dir string, stdin []byte, cmd []string, quiet bool) os.Error {
io.Copy(&buf, p.Stdout)
w, err := p.Wait(0)
p.Close()
+ if err != nil {
+ return err
+ }
if !w.Exited() || w.ExitStatus() != 0 {
if !quiet || *verbose {
if dir != "" {
diff --git a/src/cmd/goinstall/make.go b/src/cmd/goinstall/make.go
index c15709b31..93a648b2b 100644
--- a/src/cmd/goinstall/make.go
+++ b/src/cmd/goinstall/make.go
@@ -17,30 +17,65 @@ import (
// For non-local packages or packages without Makefiles,
// domake generates a standard Makefile and passes it
// to make on standard input.
-func domake(dir, pkg string, local bool) os.Error {
+func domake(dir, pkg string, local bool) (err os.Error) {
+ needMakefile := true
if local {
_, err := os.Stat(dir + "/Makefile")
if err == nil {
- return run(dir, nil, gobin+"/gomake", "install")
+ needMakefile = false
}
}
- makefile, err := makeMakefile(dir, pkg)
- if err != nil {
- return err
+ cmd := []string{"gomake"}
+ var makefile []byte
+ if needMakefile {
+ if makefile, err = makeMakefile(dir, pkg); err != nil {
+ return err
+ }
+ cmd = append(cmd, "-f-")
+ }
+ if *clean {
+ cmd = append(cmd, "clean")
}
- return run(dir, makefile, gobin+"/gomake", "-f-", "install")
+ 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) ([]byte, os.Error) {
- files, _, _, err := goFiles(dir, false)
+ dirInfo, err := scanDir(dir, false)
if err != nil {
return nil, err
}
+
+ if len(dirInfo.cgoFiles) == 0 && len(dirInfo.cFiles) > 0 {
+ // When using cgo, .c files are compiled with gcc. Without cgo,
+ // they may be intended for 6c. Just error out for now.
+ return nil, os.ErrorString("C files found in non-cgo package")
+ }
+
+ cgoFiles := dirInfo.cgoFiles
+ isCgo := make(map[string]bool, len(cgoFiles))
+ for _, file := range cgoFiles {
+ isCgo[file] = true
+ }
+
+ oFiles := make([]string, 0, len(dirInfo.cFiles))
+ for _, file := range dirInfo.cFiles {
+ oFiles = append(oFiles, file[:len(file)-2]+".o")
+ }
+
+ goFiles := make([]string, 0, len(dirInfo.goFiles))
+ for _, file := range dirInfo.goFiles {
+ if !isCgo[file] {
+ goFiles = append(goFiles, file)
+ }
+ }
+
var buf bytes.Buffer
- if err := makefileTemplate.Execute(&makedata{pkg, files}, &buf); err != nil {
+ md := makedata{pkg, goFiles, cgoFiles, oFiles}
+ if err := makefileTemplate.Execute(&md, &buf); err != nil {
return nil, err
}
return buf.Bytes(), nil
@@ -48,19 +83,38 @@ func makeMakefile(dir, pkg string) ([]byte, os.Error) {
// makedata is the data type for the makefileTemplate.
type makedata struct {
- pkg string // package import path
- files []string // list of .go files
+ Pkg string // package import path
+ GoFiles []string // list of non-cgo .go files
+ CgoFiles []string // list of cgo .go files
+ OFiles []string // list of ofiles for cgo
}
var makefileTemplate = template.MustParse(`
-include $(GOROOT)/src/Make.$(GOARCH)
+include $(GOROOT)/src/Make.inc
+
+TARG={Pkg}
-TARG={pkg}
+{.section GoFiles}
GOFILES=\
-{.repeated section files}
+{.repeated section GoFiles}
+ {@}\
+{.end}
+
+{.end}
+{.section CgoFiles}
+CGOFILES=\
+{.repeated section CgoFiles}
{@}\
{.end}
+{.end}
+{.section OFiles}
+CGO_OFILES=\
+{.repeated section OFiles}
+ {@}\
+{.end}
+
+{.end}
include $(GOROOT)/src/Make.pkg
`,
nil)
diff --git a/src/cmd/goinstall/parse.go b/src/cmd/goinstall/parse.go
index ae391ed9a..679edfabc 100644
--- a/src/cmd/goinstall/parse.go
+++ b/src/cmd/goinstall/parse.go
@@ -16,36 +16,60 @@ import (
"go/parser"
)
-// goFiles returns a list of the *.go source files in dir, excluding
-// those in package main (unless allowMain is true) or ending in
-// _test.go. It also returns a map giving the packages imported by
-// those files, and the package name.
-// The map keys are the imported paths. The key's value
-// is one file that imports that path.
-func goFiles(dir string, allowMain bool) (files []string, imports map[string]string, pkgName string, err os.Error) {
+
+type dirInfo struct {
+ goFiles []string // .go files within dir (including cgoFiles)
+ cgoFiles []string // .go files that import "C"
+ cFiles []string // .c files within dir
+ imports []string // All packages imported by goFiles
+ pkgName string // Name of package within dir
+}
+
+// scanDir returns a structure with details about the Go content found
+// in the given directory. The list of files will NOT contain the
+// following entries:
+//
+// - Files in package main (unless allowMain is true)
+// - Files ending in _test.go
+// - Files starting with _ (temporary)
+// - Files containing .cgo in their names
+//
+// The imports map keys are package paths imported by listed Go files,
+// and the values are the Go files importing the respective package paths.
+func scanDir(dir string, allowMain bool) (info *dirInfo, err os.Error) {
f, err := os.Open(dir, os.O_RDONLY, 0)
if err != nil {
- return nil, nil, "", err
+ return nil, err
}
dirs, err := f.Readdir(-1)
f.Close()
if err != nil {
- return nil, nil, "", err
+ return nil, err
}
- files = make([]string, 0, len(dirs))
- imports = make(map[string]string)
+ goFiles := make([]string, 0, len(dirs))
+ cgoFiles := make([]string, 0, len(dirs))
+ cFiles := make([]string, 0, len(dirs))
+ importsm := make(map[string]bool)
+ pkgName := ""
for i := range dirs {
d := &dirs[i]
+ if strings.HasPrefix(d.Name, "_") || strings.Index(d.Name, ".cgo") != -1 {
+ continue
+ }
+ if strings.HasSuffix(d.Name, ".c") {
+ cFiles = append(cFiles, d.Name)
+ continue
+ }
if !strings.HasSuffix(d.Name, ".go") || strings.HasSuffix(d.Name, "_test.go") {
continue
}
filename := path.Join(dir, d.Name)
- pf, err := parser.ParseFile(filename, nil, nil, parser.ImportsOnly)
+ pf, err := parser.ParseFile(fset, filename, nil, parser.ImportsOnly)
if err != nil {
- return nil, nil, "", err
+ return nil, err
}
- s := string(pf.Name.Name())
+ s := string(pf.Name.Name)
if s == "main" && !allowMain {
continue
}
@@ -56,24 +80,31 @@ func goFiles(dir string, allowMain bool) (files []string, imports map[string]str
// do we return pkgName=="main".
// A mix of main and another package reverts
// to the original (allowMain=false) behaviour.
- if allowMain && pkgName == "main" {
- return goFiles(dir, false)
+ if s == "main" || pkgName == "main" {
+ return scanDir(dir, false)
}
- return nil, nil, "", os.ErrorString("multiple package names in " + dir)
+ return nil, os.ErrorString("multiple package names in " + dir)
}
- n := len(files)
- files = files[0 : n+1]
- files[n] = filename
+ goFiles = append(goFiles, d.Name)
for _, decl := range pf.Decls {
for _, spec := range decl.(*ast.GenDecl).Specs {
quoted := string(spec.(*ast.ImportSpec).Path.Value)
unquoted, err := strconv.Unquote(quoted)
if err != nil {
- log.Crashf("%s: parser returned invalid quoted string: <%s>", filename, quoted)
+ log.Panicf("%s: parser returned invalid quoted string: <%s>", filename, quoted)
+ }
+ importsm[unquoted] = true
+ if unquoted == "C" {
+ cgoFiles = append(cgoFiles, d.Name)
}
- imports[unquoted] = filename
}
}
}
- return files, imports, pkgName, nil
+ imports := make([]string, len(importsm))
+ i := 0
+ for p := range importsm {
+ imports[i] = p
+ i++
+ }
+ return &dirInfo{goFiles, cgoFiles, cFiles, imports, pkgName}, nil
}
diff --git a/src/cmd/gomake/doc.go b/src/cmd/gomake/doc.go
new file mode 100644
index 000000000..2f35fd9dd
--- /dev/null
+++ b/src/cmd/gomake/doc.go
@@ -0,0 +1,36 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+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
index c3c136f42..859809562 100644
--- a/src/cmd/gopack/Makefile
+++ b/src/cmd/gopack/Makefile
@@ -2,17 +2,14 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.conf
+include ../../Make.inc
+O:=$(HOST_O)
TARG=gopack
OFILES=\
ar.$O\
-$(TARG): $(OFILES)
- $(LD) -o $(TARG) -L"$(GOROOT)"/lib $(OFILES) -lmach -lbio -l9
+LIB=\
+ ../../../lib/libmach.a\
-clean:
- rm -f *.$O $(TARG)
-
-install: $(TARG)
- cp $(TARG) "$(GOBIN)"/$(TARG)
+include ../../Make.ccmd
diff --git a/src/cmd/gopack/ar.c b/src/cmd/gopack/ar.c
index 377366ec4..063967bd7 100644
--- a/src/cmd/gopack/ar.c
+++ b/src/cmd/gopack/ar.c
@@ -593,25 +593,43 @@ scanobj(Biobuf *b, Arfile *ap, long size)
vlong offset;
Dir *d;
static int lastobj = -1;
+ uchar buf[4];
if (!allobj) /* non-object file encountered */
return;
offset = Boffset(b);
obj = objtype(b, 0);
if (obj < 0) { /* not an object file */
+ /* maybe a foreign object file */
+ Bseek(b, offset, 0);
+ memset(buf, 0, sizeof buf);
+ Bread(b, buf, 4);
+
+ /* maybe a foreign object file? that's okay */
+ if((buf[0] == 0x7F && buf[1] == 'E' && buf[2] == 'L' && buf[3] == 'F') || // ELF
+ (buf[0] == 0xFE && buf[1] == 0xED && buf[2] == 0xFA && (buf[3]&~1) == 0xCE) || // Mach-O big-endian
+ (buf[3] == 0xFE && buf[2] == 0xED && buf[1] == 0xFA && (buf[0]&~1) == 0xCE)) { // Mach-O little-endian
+ Bseek(b, offset, 0);
+ return;
+ }
+
if (!gflag || strcmp(file, pkgdef) != 0) { /* don't clear allobj if it's pkg defs */
fprint(2, "gopack: non-object file %s\n", file);
+ errors++;
allobj = 0;
}
d = dirfstat(Bfildes(b));
- if (d != nil && d->length == 0)
+ if (d != nil && d->length == 0) {
fprint(2, "gopack: zero length file %s\n", file);
+ errors++;
+ }
free(d);
Bseek(b, offset, 0);
return;
}
if (lastobj >= 0 && obj != lastobj) {
fprint(2, "gopack: inconsistent object file %s\n", file);
+ errors++;
allobj = 0;
Bseek(b, offset, 0);
return;
@@ -619,6 +637,7 @@ scanobj(Biobuf *b, Arfile *ap, long size)
lastobj = obj;
if (!readar(b, obj, offset+size, 0)) {
fprint(2, "gopack: invalid symbol reference in file %s\n", file);
+ errors++;
allobj = 0;
Bseek(b, offset, 0);
return;
@@ -718,8 +737,8 @@ foundstart:
first = 1;
start = end = 0;
for (n=0; n<size; n+=Blinelen(b)) {
- line = Brdline(b, '\n');
- if (line == 0)
+ line = Brdstr(b, '\n', 0);
+ if (line == nil)
goto bad;
if (first && strstrn(line, Blinelen(b), "package ")) {
if (Blinelen(b) > sizeof(pkgbuf)-1)
@@ -742,14 +761,19 @@ foundstart:
safe = 0;
start = Boffset(b); // after package statement
first = 0;
+ free(line);
continue;
}
- if(line[0] == '$' && line[1] == '$')
+ if(line[0] == '$' && line[1] == '$') {
+ free(line);
goto foundend;
+ }
end = Boffset(b); // before closing $$
+ free(line);
}
bad:
fprint(2, "gopack: bad package import section in %s\n", file);
+ errors++;
return;
foundend:
@@ -795,6 +819,7 @@ objsym(Sym *s, void *p)
if(s->type == 'T' && duplicate(as->name, &ofile)) {
dupfound = 1;
fprint(2, "duplicate text symbol: %s and %s: %s\n", as->file, ofile, as->name);
+ errors++;
free(as->name);
free(as);
return;
diff --git a/src/cmd/gopack/doc.go b/src/cmd/gopack/doc.go
index 0d5ccdb6c..74c272fd2 100644
--- a/src/cmd/gopack/doc.go
+++ b/src/cmd/gopack/doc.go
@@ -4,7 +4,7 @@
/*
-Gopack program is a variant of the Plan 9 ar tool. The original is documented at
+Gopack is a variant of the Plan 9 ar tool. The original is documented at
http://plan9.bell-labs.com/magic/man2html/1/ar
diff --git a/src/cmd/gotest/Makefile b/src/cmd/gotest/Makefile
index b20b1daff..74054e974 100644
--- a/src/cmd/gotest/Makefile
+++ b/src/cmd/gotest/Makefile
@@ -1,14 +1,18 @@
-# Copyright 2009 The Go Authors. All rights reserved.
+# Copyright 2010 The Go Authors. 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.conf
+include ../../Make.inc
-TARG=gotest
+TARG=install
clean:
@true
-install: $(TARG)
- ! test -f "$(GOBIN)"/$(TARG) || chmod u+w "$(GOBIN)"/$(TARG)
- cp $(TARG) "$(GOBIN)"/$(TARG)
+install: install-gotest install-gotry
+
+install-%: %
+ ! test -f "$(GOBIN)"/$* || chmod u+w "$(GOBIN)"/$*
+ sed 's`@@GOROOT@@`$(GOROOT_FINAL)`' $* >"$(GOBIN)"/$*
+ chmod +x "$(GOBIN)"/$*
+
diff --git a/src/cmd/gotest/gotest b/src/cmd/gotest/gotest
index fec2b4a4a..7572610d2 100755
--- a/src/cmd/gotest/gotest
+++ b/src/cmd/gotest/gotest
@@ -3,10 +3,10 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-# Using all the test*.go files in the current directory, write out a file
+# Using all the *_test.go files in the current directory, write out a file
# _testmain.go that runs all its tests. Compile everything and run the
# tests.
-# If files are named on the command line, use them instead of test*.go.
+# If files are named on the command line, use them instead of *_test.go.
# Makes egrep,grep work better in general if we put them
# in ordinary C mode instead of what the current language is.
@@ -14,16 +14,15 @@ unset LANG
export LC_ALL=C
export LC_CTYPE=C
-GOBIN="${GOBIN:-$HOME/bin}"
-
-_GC=$GC # Make.$GOARCH will overwrite this
+_GC=$GC # Make.inc will overwrite this
if [ ! -f [Mm]akefile ]; then
echo 'please create a Makefile for gotest; see http://golang.org/doc/code.html for details' 1>&2
exit 2
fi
-. "$GOROOT"/src/Make.$GOARCH
+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
@@ -31,18 +30,12 @@ fi
E="$GORUN"
-# TODO(kaib): proper emulator strategy
-case x"$GOARCH" in
-xarm)
- export E=${GORUN:-qemu-arm -cpu cortex-a8}
-esac
-
# Allow overrides
-GC="$GOBIN/${_GC:-$GC} -I _test"
-GL="$GOBIN/${GL:-$LD} -L _test"
-AS="$GOBIN/$AS"
-CC="$GOBIN/$CC"
-LD="$GOBIN/$LD"
+GC="${_GC:-$GC} -I _test"
+GL="${GL:-$LD} -L _test"
+AS="$AS"
+CC="$CC"
+LD="$LD"
export GC GL O AS CC LD
gofiles=""
@@ -93,14 +86,13 @@ fi
set -e
-"$GOBIN"/gomake testpackage-clean
-"$GOBIN"/gomake testpackage "GOTESTFILES=$gofiles"
+gomake testpackage-clean
+gomake testpackage "GOTESTFILES=$gofiles"
if $havex; then
$GC -o $xofile $xgofiles
fi
# They all compile; now generate the code to call them.
-trap "rm -f _testmain.go _testmain.$O" 0 1 2 3 14 15
# Suppress output to stdout on Linux
MAKEFLAGS=
@@ -116,18 +108,18 @@ nmgrep() {
# Figure out pkg.
case "$i" in
*.a)
- pkg=$("$GOBIN"/gopack p $i __.PKGDEF | sed -n 's/^package //p' | sed 's/ .*//' | sed 1q)
+ pkg=$(gopack p $i __.PKGDEF | sed -n 's/^package //p' | sed 's/ .*//' | sed 1q)
;;
*)
pkg=$(sed -n 's/^ .* in package "\(.*\)".*/\1/p' $i | sed 1q)
;;
esac
- "$GOBIN"/6nm -s "$i" | egrep ' T .*\.'"$pat"'$' |
+ 6nm -s "$i" | egrep ' T .*\.'"$pat"'$' |
sed 's/.* //; /\..*\./d; s/""\./'"$pkg"'./g'
done
}
-importpath=$("$GOBIN"/gomake -s importpath)
+importpath=$(gomake -s importpath)
{
# test functions are named TestFoo
# the grep -v eliminates methods and other special names
@@ -155,30 +147,43 @@ importpath=$("$GOBIN"/gomake -s importpath)
echo 'import "./_xtest_"'
fi
echo 'import "testing"'
+ echo 'import __regexp__ "regexp"' # rename in case tested package is called regexp
# test array
echo
- echo 'var tests = []testing.Test {'
+ echo 'var tests = []testing.InternalTest{'
for i in $tests
do
- echo ' testing.Test{ "'$i'", '$i' },'
+ echo ' {"'$i'", '$i'},'
done
echo '}'
# benchmark array
- echo 'var benchmarks = []testing.Benchmark {'
- for i in $benchmarks
- do
- echo ' testing.Benchmark{ "'$i'", '$i' },'
- done
- echo '}'
-
+ if [ "$benchmarks" = "" ]
+ then
+ # keep the empty array gofmt-safe.
+ # (not an issue for the test array, which is never empty.)
+ echo 'var benchmarks = []testing.InternalBenchmark{}'
+ else
+ echo 'var benchmarks = []testing.InternalBenchmark{'
+ for i in $benchmarks
+ do
+ echo ' {"'$i'", '$i'},'
+ done
+ echo '}'
+ fi
# body
echo
echo 'func main() {'
- echo ' testing.Main(tests);'
- echo ' testing.RunBenchmarks(benchmarks)'
+ echo ' testing.Main(__regexp__.MatchString, tests)'
+ echo ' testing.RunBenchmarks(__regexp__.MatchString, benchmarks)'
echo '}'
}>_testmain.go
$GC _testmain.go
$GL _testmain.$O
+
+# Set dynamic linker library path, no matter what it's called,
+# to include the current directory while running $O.out,
+# so that cgo libraries can be tested without installation.
+LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH \
+DYLD_LIBRARY_PATH=.:$DYLD_LIBRARY_PATH \
$E ./$O.out "$@"
diff --git a/src/cmd/gotest/gotry b/src/cmd/gotest/gotry
new file mode 100755
index 000000000..52c5d2d58
--- /dev/null
+++ b/src/cmd/gotest/gotry
@@ -0,0 +1,167 @@
+#!/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
+rm -f /tmp/$USER.try.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 }
+!
+
+)>/tmp/$USER.try.go
+
+$GC -o /tmp/$USER.try.$O /tmp/$USER.try.go &&
+$GL -o /tmp/$USER.try /tmp/$USER.try.$O &&
+/tmp/$USER.try "_$@"
+rm -f /tmp/$USER.try /tmp/$USER.try.go /tmp/$USER.try.$O
diff --git a/src/cmd/govet/Makefile b/src/cmd/govet/Makefile
new file mode 100644
index 000000000..291b27197
--- /dev/null
+++ b/src/cmd/govet/Makefile
@@ -0,0 +1,11 @@
+# Copyright 2010 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+
+TARG=govet
+GOFILES=\
+ govet.go\
+
+include ../../Make.cmd
diff --git a/src/cmd/govet/doc.go b/src/cmd/govet/doc.go
new file mode 100644
index 000000000..5a2489fca
--- /dev/null
+++ b/src/cmd/govet/doc.go
@@ -0,0 +1,38 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+
+Govet does simple checking of Go source code.
+
+It checks for simple errors in calls to functions named
+ Print Printf Println
+ Fprint Fprintf Fprintln
+ Sprint Sprintf Sprintln
+ Error Errorf
+ Fatal Fatalf
+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
+complains about arguments that look like format descriptor strings.
+
+Usage:
+
+ govet [flag] [file.go ...]
+ govet [flag] [directory ...] # Scan all .go files under directory, recursively
+
+The flags are:
+ -v
+ Verbose mode
+ -printfuncs
+ A comma-separated list of print-like functions to supplement
+ the standard list. Each entry is in the form Name:N where N
+ is the zero-based argument position of the first argument
+ involved in the print: either the format or the first print
+ argument for non-formatted prints. For example,
+ if you have Warn and Warnf functions that take an
+ io.Writer as their first argument, like Fprintf,
+ -printfuncs=Warn:1,Warnf:1
+
+*/
+package documentation
diff --git a/src/cmd/govet/govet.go b/src/cmd/govet/govet.go
new file mode 100644
index 000000000..2981891eb
--- /dev/null
+++ b/src/cmd/govet/govet.go
@@ -0,0 +1,325 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Govet is a simple checker for static errors in Go source code.
+// See doc.go for more information.
+package main
+
+import (
+ "bytes"
+ "flag"
+ "fmt"
+ "io"
+ "go/ast"
+ "go/parser"
+ "go/token"
+ "os"
+ "path"
+ "strconv"
+ "strings"
+)
+
+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, ",", -1) {
+ 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 {
+ error(`illegal format for "Func:N" argument %q; %s`, name, err)
+ }
+ name = name[:colon]
+ }
+ 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 {
+ error("%s: %s", name, err)
+ return
+ }
+ file := &File{fs.File(parsedFile.Pos())}
+ file.checkFile(name, parsedFile)
+}
+
+// Visitor for path.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 {
+ error("walk error: %s", e)
+ }
+ done <- true
+ }()
+ path.Walk(root, V{}, errors)
+ close(errors)
+ <-done
+}
+
+// error formats the error to standard error, adding program
+// identification and a newline
+func error(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 {
+ // TODO: could return nil for nodes that cannot contain a CallExpr -
+ // will shortcut traversal. Worthwhile?
+ switch n := node.(type) {
+ case *ast.CallExpr:
+ f.checkCallExpr(n)
+ }
+ return f
+}
+
+
+// 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.
+var printfList = map[string]int{
+ "Errorf": 0,
+ "Fatalf": 0,
+ "Fprintf": 1,
+ "Printf": 0,
+ "Sprintf": 0,
+}
+
+// printList records the unformatted-print functions. The value is the location
+// of the first parameter to be printed.
+var printList = map[string]int{
+ "Error": 0,
+ "Fatal": 0,
+ "Fprint": 1, "Fprintln": 1,
+ "Print": 0, "Println": 0,
+ "Sprint": 0, "Sprintln": 0,
+}
+
+// checkCall triggers the print-specific checks if the call invokes a print function.
+func (f *File) checkCall(call *ast.CallExpr, name string) {
+ if skip, ok := printfList[name]; ok {
+ f.checkPrintf(call, name, skip)
+ return
+ }
+ if skip, ok := printList[name]; ok {
+ f.checkPrint(call, name, skip)
+ return
+ }
+}
+
+// checkPrintf checks a call to a formatted print routine such as Printf.
+// The skip argument records how many arguments to ignore; that is,
+// call.Args[skip] is (well, should be) the format argument.
+func (f *File) checkPrintf(call *ast.CallExpr, name string, skip int) {
+ if len(call.Args) <= skip {
+ return
+ }
+ // Common case: literal is first argument.
+ arg := call.Args[skip]
+ lit, ok := arg.(*ast.BasicLit)
+ if !ok {
+ // Too hard to check.
+ if *verbose {
+ f.Warn(call.Pos(), "can't check args for call to", name)
+ }
+ return
+ }
+ if lit.Kind == token.STRING {
+ if bytes.IndexByte(lit.Value, '%') < 0 {
+ if len(call.Args) > skip+1 {
+ f.Badf(call.Pos(), "no formatting directive in %s call", name)
+ }
+ return
+ }
+ }
+ // Hard part: check formats against args.
+ // Trivial but useful test: count.
+ numPercent := 0
+ for i := 0; i < len(lit.Value); i++ {
+ if lit.Value[i] == '%' {
+ if i+1 < len(lit.Value) && lit.Value[i+1] == '%' {
+ // %% doesn't count.
+ i++
+ } else {
+ numPercent++
+ }
+ }
+ }
+ expect := len(call.Args) - (skip + 1)
+ if numPercent != expect {
+ f.Badf(call.Pos(), "wrong number of formatting directives in %s call: %d percent(s) for %d args", name, numPercent, expect)
+ }
+}
+
+var terminalNewline = []byte(`\n"`) // \n at end of interpreted string
+
+// 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")
+ args := call.Args
+ if len(args) <= skip {
+ if *verbose && !isLn {
+ f.Badf(call.Pos(), "no args in %s call", name)
+ }
+ return
+ }
+ arg := args[skip]
+ if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING {
+ if bytes.IndexByte(lit.Value, '%') >= 0 {
+ f.Badf(call.Pos(), "possible formatting directive in %s call", name)
+ }
+ }
+ if isLn {
+ // The last item, if a string, should not have a newline.
+ arg = args[len(call.Args)-1]
+ if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING {
+ if bytes.HasSuffix(lit.Value, terminalNewline) {
+ f.Badf(call.Pos(), "%s call ends with newline", name)
+ }
+ }
+ }
+}
+
+// This function never executes, but it serves as a simple test for the program.
+// Test with govet -printfuncs="Bad:1,Badf:1,Warn:1,Warnf:1" govet.go
+func BadFunctionUsedInTests() {
+ fmt.Println() // niladic call
+ fmt.Println("%s", "hi") // % in call to Println
+ fmt.Printf("%s", "hi", 3) // wrong # percents
+ fmt.Printf("%s%%%d", "hi", 3) // right # percents
+ Printf("now is the time", "buddy") // no %s
+ f := new(File)
+ f.Warn(0, "%s", "hello", 3) // % in call to added function
+ f.Warnf(0, "%s", "hello", 3) // wrong # %s in call to added function
+}
diff --git a/src/cmd/goyacc/Makefile b/src/cmd/goyacc/Makefile
index 77ac918bc..54b8f3360 100644
--- a/src/cmd/goyacc/Makefile
+++ b/src/cmd/goyacc/Makefile
@@ -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 ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=goyacc
GOFILES=\
diff --git a/src/cmd/goyacc/goyacc.go b/src/cmd/goyacc/goyacc.go
index a5da5f0a1..c9fa6bfb9 100644
--- a/src/cmd/goyacc/goyacc.go
+++ b/src/cmd/goyacc/goyacc.go
@@ -299,17 +299,17 @@ type Resrv struct {
}
var resrv = []Resrv{
- Resrv{"binary", BINARY},
- Resrv{"left", LEFT},
- Resrv{"nonassoc", BINARY},
- Resrv{"prec", PREC},
- Resrv{"right", RIGHT},
- Resrv{"start", START},
- Resrv{"term", TERM},
- Resrv{"token", TERM},
- Resrv{"type", TYPEDEF},
- Resrv{"union", UNION},
- Resrv{"struct", UNION},
+ {"binary", BINARY},
+ {"left", LEFT},
+ {"nonassoc", BINARY},
+ {"prec", PREC},
+ {"right", RIGHT},
+ {"start", START},
+ {"term", TERM},
+ {"token", TERM},
+ {"type", TYPEDEF},
+ {"union", UNION},
+ {"struct", UNION},
}
var zznewstate = 0
@@ -1032,7 +1032,7 @@ func chfind(t int, s string) int {
func cpyunion() {
if !lflag {
- fmt.Fprintf(ftable, "\n//line %v %v\n", lineno, infile)
+ fmt.Fprintf(ftable, "\n//line %v:%v\n", infile, lineno)
}
fmt.Fprintf(ftable, "type\tyySymType\tstruct")
@@ -1075,7 +1075,7 @@ func cpycode() {
lineno++
}
if !lflag {
- fmt.Fprintf(ftable, "\n//line %v %v\n", lineno, infile)
+ fmt.Fprintf(ftable, "\n//line %v:%v\n", infile, lineno)
}
for c != EOF {
if c == '%' {
@@ -1158,7 +1158,7 @@ func dumpprod(curprod []int, max int) {
func cpyact(curprod []int, max int) {
if !lflag {
- fmt.Fprintf(fcode, "\n//line %v %v\n", lineno, infile)
+ fmt.Fprintf(fcode, "\n//line %v:%v\n", infile, lineno)
}
lno := lineno
@@ -2066,6 +2066,7 @@ nextk:
func output() {
var c, u, v int
+ fmt.Fprintf(ftable, "\n//line yacctab:1\n")
fmt.Fprintf(ftable, "var\tyyExca = []int {\n")
noset := mkset()
@@ -2825,8 +2826,10 @@ func others() {
c = getrune(finput)
}
- parts := strings.Split(yaccpar, "yyrun()", 2)
// copy yaccpar
+ fmt.Fprintf(ftable, "\n//line yaccpar:1\n")
+
+ parts := strings.Split(yaccpar, "yyrun()", 2)
fmt.Fprintf(ftable, "%v", parts[0])
ftable.Write(fcode.Bytes())
fmt.Fprintf(ftable, "%v", parts[1])
@@ -3035,7 +3038,7 @@ func open(s string) *bufio.Reader {
return bufio.NewReader(fi)
}
-func create(s string, m int) *bufio.Writer {
+func create(s string, m uint32) *bufio.Writer {
fo, err := os.Open(s, os.O_WRONLY|os.O_CREAT|os.O_TRUNC, m)
if err != nil {
error("error opening %v: %v", s, err)
@@ -3049,7 +3052,7 @@ func create(s string, m int) *bufio.Writer {
//
func error(s string, v ...interface{}) {
nerrors++
- fmt.Fprintf(stderr, s, v)
+ fmt.Fprintf(stderr, s, v...)
fmt.Fprintf(stderr, ": %v:%v\n", infile, lineno)
if fatfl != 0 {
summary()
@@ -3136,7 +3139,7 @@ out:
c = yyTok2[1] /* unknown char */
}
if yyDebug >= 3 {
- fmt.Printf("lex %.4x %s\n", uint(yychar), yyTokname(c))
+ fmt.Printf("lex %U %s\n", uint(yychar), yyTokname(c))
}
return c
}
@@ -3241,7 +3244,7 @@ yydefault:
Errflag = 3
/* find a state where "error" is a legal shift action */
- for yyp >= len(YYS) {
+ for yyp >= 0 {
yyn = yyPact[YYS[yyp].yys] + yyErrCode
if yyn >= 0 && yyn < yyLast {
yystate = yyAct[yyn] /* simulate a shift of "error" */
diff --git a/src/cmd/goyacc/units.y b/src/cmd/goyacc/units.y
index bd5517e8b..a7d472fc6 100644
--- a/src/cmd/goyacc/units.y
+++ b/src/cmd/goyacc/units.y
@@ -215,7 +215,7 @@ expr0:
type UnitsLex int
-func (_ UnitsLex) Lex(yylval *yySymType) int {
+func (UnitsLex) Lex(yylval *yySymType) int {
var c, i int
c = peekrune
@@ -280,7 +280,7 @@ numb:
return VAL
}
-func (_ UnitsLex) Error(s string) {
+func (UnitsLex) Error(s string) {
Error("syntax error, last name: %v", sym)
}
@@ -298,7 +298,7 @@ func main() {
f, err := os.Open(file, os.O_RDONLY, 0)
if err != nil {
- fmt.Printf("error opening %v: %v\n", file, err)
+ fmt.Fprintf(os.Stderr, "error opening %v: %v\n", file, err)
os.Exit(1)
}
fi = bufio.NewReader(f)
@@ -390,7 +390,7 @@ func rdigit(c int) bool {
func Error(s string, v ...interface{}) {
fmt.Printf("%v: %v\n\t", lineno, line)
- fmt.Printf(s, v)
+ fmt.Printf(s, v...)
fmt.Printf("\n")
nerrors++
diff --git a/src/cmd/hgpatch/Makefile b/src/cmd/hgpatch/Makefile
index f7d64bc12..1ef98d7f9 100644
--- a/src/cmd/hgpatch/Makefile
+++ b/src/cmd/hgpatch/Makefile
@@ -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 ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=hgpatch
GOFILES=\
diff --git a/src/cmd/hgpatch/main.go b/src/cmd/hgpatch/main.go
index f6ea36da8..bd4b563f9 100644
--- a/src/cmd/hgpatch/main.go
+++ b/src/cmd/hgpatch/main.go
@@ -153,7 +153,7 @@ func main() {
changed[o.Dst] = 1
}
if o.Mode != 0 {
- chk(os.Chmod(o.Dst, o.Mode&0755))
+ chk(os.Chmod(o.Dst, uint32(o.Mode&0755)))
undoRevert(o.Dst)
changed[o.Dst] = 1
}
@@ -192,7 +192,7 @@ func makeParent(name string) {
// Copy of os.MkdirAll but adds to undo log after
// creating a directory.
-func mkdirAll(path string, perm int) os.Error {
+func mkdirAll(path string, perm uint32) os.Error {
dir, err := os.Lstat(path)
if err == nil {
if dir.IsDirectory() {
@@ -318,11 +318,9 @@ func hgRename(dst, src string) os.Error {
return err
}
-func copy(a []string) []string {
+func dup(a []string) []string {
b := make([]string, len(a))
- for i, s := range a {
- b[i] = s
- }
+ copy(b, a)
return b
}
@@ -379,7 +377,7 @@ func run(argv []string, input []byte) (out string, err os.Error) {
return
Error:
- err = &runError{copy(argv), err}
+ err = &runError{dup(argv), err}
return
}
diff --git a/src/cmd/ld/data.c b/src/cmd/ld/data.c
new file mode 100644
index 000000000..210f10ab5
--- /dev/null
+++ b/src/cmd/ld/data.c
@@ -0,0 +1,914 @@
+// Inferno utils/8l/asm.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8l/asm.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+// Data layout and relocation.
+
+#include "l.h"
+#include "../ld/lib.h"
+#include "../ld/elf.h"
+#include "../ld/pe.h"
+
+void dynreloc(void);
+
+/*
+ * divide-and-conquer list-link
+ * sort of Sym* structures.
+ * Used for the data block.
+ */
+int
+datcmp(Sym *s1, Sym *s2)
+{
+ if(s1->type != s2->type)
+ return (int)s1->type - (int)s2->type;
+ if(s1->size != s2->size) {
+ if(s1->size < s2->size)
+ return -1;
+ return +1;
+ }
+ return strcmp(s1->name, s2->name);
+}
+
+Sym*
+datsort(Sym *l)
+{
+ Sym *l1, *l2, *le;
+
+ if(l == 0 || l->next == 0)
+ return l;
+
+ l1 = l;
+ l2 = l;
+ for(;;) {
+ l2 = l2->next;
+ if(l2 == 0)
+ break;
+ l2 = l2->next;
+ if(l2 == 0)
+ break;
+ l1 = l1->next;
+ }
+
+ l2 = l1->next;
+ l1->next = 0;
+ l1 = datsort(l);
+ l2 = datsort(l2);
+
+ /* set up lead element */
+ if(datcmp(l1, l2) < 0) {
+ l = l1;
+ l1 = l1->next;
+ } else {
+ l = l2;
+ l2 = l2->next;
+ }
+ le = l;
+
+ for(;;) {
+ if(l1 == 0) {
+ while(l2) {
+ le->next = l2;
+ le = l2;
+ l2 = l2->next;
+ }
+ le->next = 0;
+ break;
+ }
+ if(l2 == 0) {
+ while(l1) {
+ le->next = l1;
+ le = l1;
+ l1 = l1->next;
+ }
+ break;
+ }
+ if(datcmp(l1, l2) < 0) {
+ le->next = l1;
+ le = l1;
+ l1 = l1->next;
+ } else {
+ le->next = l2;
+ le = l2;
+ l2 = l2->next;
+ }
+ }
+ le->next = 0;
+ return l;
+}
+
+Reloc*
+addrel(Sym *s)
+{
+ if(s->nr >= s->maxr) {
+ if(s->maxr == 0)
+ s->maxr = 4;
+ else
+ s->maxr <<= 1;
+ s->r = realloc(s->r, s->maxr*sizeof s->r[0]);
+ if(s->r == 0) {
+ diag("out of memory");
+ errorexit();
+ }
+ memset(s->r+s->nr, 0, (s->maxr-s->nr)*sizeof s->r[0]);
+ }
+ return &s->r[s->nr++];
+}
+
+void
+relocsym(Sym *s)
+{
+ Reloc *r;
+ Prog p;
+ int32 i, off, siz, fl;
+ vlong o;
+ uchar *cast;
+
+ cursym = s;
+ memset(&p, 0, sizeof p);
+ for(r=s->r; r<s->r+s->nr; r++) {
+ off = r->off;
+ siz = r->siz;
+ if(off < 0 || off+(siz&~Rbig) > s->np) {
+ diag("%s: invalid relocation %d+%d not in [%d,%d)", s->name, off, siz&~Rbig, 0, s->np);
+ continue;
+ }
+ if(r->sym != S && (r->sym->type == 0 || r->sym->type == SXREF)) {
+ diag("%s: not defined", r->sym->name);
+ continue;
+ }
+ if(r->type >= 256)
+ continue;
+
+ if(r->sym != S && r->sym->type == SDYNIMPORT)
+ diag("unhandled relocation for %s (type %d rtype %d)", r->sym->name, r->sym->type, r->type);
+
+ if(r->sym != S && !r->sym->reachable)
+ diag("unreachable sym in relocation: %s %s", s->name, r->sym->name);
+
+ switch(r->type) {
+ default:
+ o = 0;
+ if(archreloc(r, s, &o) < 0)
+ diag("unknown reloc %d", r->type);
+ break;
+ case D_ADDR:
+ o = symaddr(r->sym) + r->add;
+ break;
+ case D_PCREL:
+ o = symaddr(r->sym) + r->add - (s->value + r->off + r->siz);
+ break;
+ case D_SIZE:
+ o = r->sym->size + r->add;
+ break;
+ }
+//print("relocate %s %p %s => %p %p %p %p [%p]\n", s->name, s->value+off, r->sym ? r->sym->name : "<nil>", (void*)symaddr(r->sym), (void*)s->value, (void*)r->off, (void*)r->siz, (void*)o);
+ switch(siz) {
+ default:
+ cursym = s;
+ diag("bad reloc size %#ux for %s", siz, r->sym->name);
+ case 4 + Rbig:
+ fl = o;
+ s->p[off] = fl>>24;
+ s->p[off+1] = fl>>16;
+ s->p[off+2] = fl>>8;
+ s->p[off+3] = fl;
+ break;
+ case 4 + Rlittle:
+ fl = o;
+ s->p[off] = fl;
+ s->p[off+1] = fl>>8;
+ s->p[off+2] = fl>>16;
+ s->p[off+3] = fl>>24;
+ break;
+ case 4:
+ fl = o;
+ cast = (uchar*)&fl;
+ for(i=0; i<4; i++)
+ s->p[off+i] = cast[inuxi4[i]];
+ break;
+ case 8:
+ cast = (uchar*)&o;
+ for(i=0; i<8; i++)
+ s->p[off+i] = cast[inuxi8[i]];
+ break;
+ }
+ }
+}
+
+void
+reloc(void)
+{
+ Sym *s;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f reloc\n", cputime());
+ Bflush(&bso);
+
+ for(s=textp; s!=S; s=s->next)
+ relocsym(s);
+ for(s=datap; s!=S; s=s->next)
+ relocsym(s);
+}
+
+void
+dynrelocsym(Sym *s)
+{
+ Reloc *r;
+
+ for(r=s->r; r<s->r+s->nr; r++)
+ if(r->sym->type == SDYNIMPORT || r->type >= 256)
+ adddynrel(s, r);
+}
+
+void
+dynreloc(void)
+{
+ Sym *s;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f reloc\n", cputime());
+ Bflush(&bso);
+
+ for(s=textp; s!=S; s=s->next)
+ dynrelocsym(s);
+ for(s=datap; s!=S; s=s->next)
+ dynrelocsym(s);
+ if(iself)
+ elfdynhash();
+}
+
+void
+symgrow(Sym *s, int32 siz)
+{
+ if(s->np >= siz)
+ return;
+
+ if(s->maxp < siz) {
+ if(s->maxp == 0)
+ s->maxp = 8;
+ while(s->maxp < siz)
+ s->maxp <<= 1;
+ s->p = realloc(s->p, s->maxp);
+ if(s->p == nil) {
+ diag("out of memory");
+ errorexit();
+ }
+ memset(s->p+s->np, 0, s->maxp-s->np);
+ }
+ s->np = siz;
+}
+
+void
+savedata(Sym *s, Prog *p)
+{
+ int32 off, siz, i, fl;
+ uchar *cast;
+ vlong o;
+ Reloc *r;
+
+ off = p->from.offset;
+ siz = p->datasize;
+ symgrow(s, off+siz);
+
+ switch(p->to.type) {
+ default:
+ diag("bad data: %P", p);
+ break;
+
+ case D_FCONST:
+ switch(siz) {
+ default:
+ case 4:
+ fl = ieeedtof(&p->to.ieee);
+ cast = (uchar*)&fl;
+ for(i=0; i<4; i++)
+ s->p[off+i] = cast[fnuxi4[i]];
+ break;
+ case 8:
+ cast = (uchar*)&p->to.ieee;
+ for(i=0; i<8; i++)
+ s->p[off+i] = cast[fnuxi8[i]];
+ break;
+ }
+ break;
+
+ case D_SCONST:
+ for(i=0; i<siz; i++)
+ s->p[off+i] = p->to.scon[i];
+ break;
+
+ case D_CONST:
+ if(p->to.sym)
+ goto Addr;
+ o = p->to.offset;
+ fl = o;
+ cast = (uchar*)&fl;
+ switch(siz) {
+ default:
+ diag("bad nuxi %d\n%P", siz, p);
+ break;
+ case 1:
+ s->p[off] = cast[inuxi1[0]];
+ break;
+ case 2:
+ for(i=0; i<2; i++)
+ s->p[off+i] = cast[inuxi2[i]];
+ break;
+ case 4:
+ for(i=0; i<4; i++)
+ s->p[off+i] = cast[inuxi4[i]];
+ break;
+ case 8:
+ cast = (uchar*)&o;
+ for(i=0; i<8; i++)
+ s->p[off+i] = cast[inuxi8[i]];
+ break;
+ }
+ break;
+
+ case D_ADDR:
+ case D_SIZE:
+ Addr:
+ r = addrel(s);
+ r->off = off;
+ r->siz = siz;
+ r->sym = p->to.sym;
+ r->type = p->to.type;
+ if(r->type != D_SIZE)
+ r->type = D_ADDR;
+ r->add = p->to.offset;
+ break;
+ }
+}
+
+static void
+blk(Sym *allsym, int32 addr, int32 size)
+{
+ Sym *sym;
+ int32 eaddr;
+ uchar *p, *ep;
+
+ for(sym = allsym; sym != nil; sym = sym->next)
+ if(!(sym->type&SSUB) && sym->value >= addr)
+ break;
+
+ eaddr = addr+size;
+ for(; sym != nil; sym = sym->next) {
+ if(sym->type&SSUB)
+ continue;
+ if(sym->value >= eaddr)
+ break;
+ if(sym->value < addr) {
+ diag("phase error: addr=%#llx but sym=%#llx type=%d", (vlong)addr, (vlong)sym->value, sym->type);
+ errorexit();
+ }
+ cursym = sym;
+ for(; addr < sym->value; addr++)
+ cput(0);
+ p = sym->p;
+ ep = p + sym->np;
+ while(p < ep)
+ cput(*p++);
+ addr += sym->np;
+ for(; addr < sym->value+sym->size; addr++)
+ cput(0);
+ if(addr != sym->value+sym->size) {
+ diag("phase error: addr=%#llx value+size=%#llx", (vlong)addr, (vlong)sym->value+sym->size);
+ errorexit();
+ }
+ }
+
+ for(; addr < eaddr; addr++)
+ cput(0);
+ cflush();
+}
+
+void
+codeblk(int32 addr, int32 size)
+{
+ Sym *sym;
+ int32 eaddr, n, epc;
+ Prog *p;
+ uchar *q;
+
+ if(debug['a'])
+ Bprint(&bso, "codeblk [%#x,%#x) at offset %#llx\n", addr, addr+size, seek(cout, 0, 1));
+
+ blk(textp, addr, size);
+
+ /* again for printing */
+ if(!debug['a'])
+ return;
+
+ for(sym = textp; sym != nil; sym = sym->next) {
+ if(!sym->reachable)
+ continue;
+ if(sym->value >= addr)
+ break;
+ }
+
+ eaddr = addr + size;
+ for(; sym != nil; sym = sym->next) {
+ if(!sym->reachable)
+ continue;
+ if(sym->value >= eaddr)
+ break;
+
+ if(addr < sym->value) {
+ Bprint(&bso, "%-20s %.8llux|", "_", (vlong)addr);
+ for(; addr < sym->value; addr++)
+ Bprint(&bso, " %.2ux", 0);
+ Bprint(&bso, "\n");
+ }
+ p = sym->text;
+ if(p == nil) {
+ Bprint(&bso, "%.6llux\t%-20s | foreign text\n", (vlong)addr, sym->name);
+ n = sym->size;
+ q = sym->p;
+
+ while(n >= 16) {
+ Bprint(&bso, "%.6ux\t%-20.16I\n", addr, q);
+ addr += 16;
+ q += 16;
+ n -= 16;
+ }
+ if(n > 0)
+ Bprint(&bso, "%.6ux\t%-20.*I\n", addr, n, q);
+ addr += n;
+ continue;
+ }
+
+ Bprint(&bso, "%.6llux\t%-20s | %P\n", (vlong)sym->value, sym->name, p);
+ for(p = p->link; p != P; p = p->link) {
+ if(p->link != P)
+ epc = p->link->pc;
+ else
+ epc = sym->value + sym->size;
+ Bprint(&bso, "%.6ux\t", p->pc);
+ q = sym->p + p->pc - sym->value;
+ n = epc - p->pc;
+ Bprint(&bso, "%-20.*I | %P\n", n, q, p);
+ addr += n;
+ }
+ }
+
+ if(addr < eaddr) {
+ Bprint(&bso, "%-20s %.8llux|", "_", (vlong)addr);
+ for(; addr < eaddr; addr++)
+ Bprint(&bso, " %.2ux", 0);
+ }
+ Bflush(&bso);
+}
+
+void
+datblk(int32 addr, int32 size)
+{
+ Sym *sym;
+ int32 eaddr;
+ uchar *p, *ep;
+
+ if(debug['a'])
+ Bprint(&bso, "datblk [%#x,%#x) at offset %#llx\n", addr, addr+size, seek(cout, 0, 1));
+
+ blk(datap, addr, size);
+
+ /* again for printing */
+ if(!debug['a'])
+ return;
+
+ for(sym = datap; sym != nil; sym = sym->next)
+ if(sym->value >= addr)
+ break;
+
+ eaddr = addr + size;
+ for(; sym != nil; sym = sym->next) {
+ if(sym->value >= eaddr)
+ break;
+ if(addr < sym->value) {
+ Bprint(&bso, "%-20s %.8ux| 00 ...\n", "(pre-pad)", addr);
+ addr = sym->value;
+ }
+ Bprint(&bso, "%-20s %.8ux|", sym->name, addr);
+ p = sym->p;
+ ep = p + sym->np;
+ while(p < ep)
+ Bprint(&bso, " %.2ux", *p++);
+ addr += sym->np;
+ for(; addr < sym->value+sym->size; addr++)
+ Bprint(&bso, " %.2ux", 0);
+ Bprint(&bso, "\n");
+ }
+
+ if(addr < eaddr)
+ Bprint(&bso, "%-20s %.8ux| 00 ...\n", "(post-pad)", addr);
+ Bprint(&bso, "%-20s %.8ux|\n", "", eaddr);
+}
+
+void
+strnput(char *s, int n)
+{
+ for(; *s && n > 0; s++) {
+ cput(*s);
+ n--;
+ }
+ while(n > 0) {
+ cput(0);
+ n--;
+ }
+}
+
+vlong
+addstring(Sym *s, char *str)
+{
+ int n;
+ int32 r;
+
+ if(s->type == 0)
+ s->type = SDATA;
+ s->reachable = 1;
+ r = s->size;
+ n = strlen(str)+1;
+ if(strcmp(s->name, ".shstrtab") == 0)
+ elfsetstring(str, r);
+ symgrow(s, r+n);
+ memmove(s->p+r, str, n);
+ s->size += n;
+ return r;
+}
+
+vlong
+adduintxx(Sym *s, uint64 v, int wid)
+{
+ int32 i, r, fl;
+ vlong o;
+ uchar *cast;
+
+ if(s->type == 0)
+ s->type = SDATA;
+ s->reachable = 1;
+ r = s->size;
+ s->size += wid;
+ symgrow(s, s->size);
+ assert(r+wid <= s->size);
+ fl = v;
+ cast = (uchar*)&fl;
+ switch(wid) {
+ case 1:
+ s->p[r] = cast[inuxi1[0]];
+ break;
+ case 2:
+ for(i=0; i<2; i++)
+ s->p[r+i] = cast[inuxi2[i]];
+ break;
+ case 4:
+ for(i=0; i<4; i++)
+ s->p[r+i] = cast[inuxi4[i]];
+ break;
+ case 8:
+ o = v;
+ cast = (uchar*)&o;
+ for(i=0; i<8; i++)
+ s->p[r+i] = cast[inuxi8[i]];
+ break;
+ }
+ return r;
+}
+
+vlong
+adduint8(Sym *s, uint8 v)
+{
+ return adduintxx(s, v, 1);
+}
+
+vlong
+adduint16(Sym *s, uint16 v)
+{
+ return adduintxx(s, v, 2);
+}
+
+vlong
+adduint32(Sym *s, uint32 v)
+{
+ return adduintxx(s, v, 4);
+}
+
+vlong
+adduint64(Sym *s, uint64 v)
+{
+ return adduintxx(s, v, 8);
+}
+
+vlong
+addaddrplus(Sym *s, Sym *t, int32 add)
+{
+ vlong i;
+ Reloc *r;
+
+ if(s->type == 0)
+ s->type = SDATA;
+ s->reachable = 1;
+ i = s->size;
+ s->size += PtrSize;
+ symgrow(s, s->size);
+ r = addrel(s);
+ r->sym = t;
+ r->off = i;
+ r->siz = PtrSize;
+ r->type = D_ADDR;
+ r->add = add;
+ return i;
+}
+
+vlong
+addpcrelplus(Sym *s, Sym *t, int32 add)
+{
+ vlong i;
+ Reloc *r;
+
+ if(s->type == 0)
+ s->type = SDATA;
+ s->reachable = 1;
+ i = s->size;
+ s->size += 4;
+ symgrow(s, s->size);
+ r = addrel(s);
+ r->sym = t;
+ r->off = i;
+ r->add = add;
+ r->type = D_PCREL;
+ r->siz = 4;
+ return i;
+}
+
+vlong
+addaddr(Sym *s, Sym *t)
+{
+ return addaddrplus(s, t, 0);
+}
+
+vlong
+addsize(Sym *s, Sym *t)
+{
+ vlong i;
+ Reloc *r;
+
+ if(s->type == 0)
+ s->type = SDATA;
+ s->reachable = 1;
+ i = s->size;
+ s->size += PtrSize;
+ symgrow(s, s->size);
+ r = addrel(s);
+ r->sym = t;
+ r->off = i;
+ r->siz = PtrSize;
+ r->type = D_SIZE;
+ return i;
+}
+
+void
+dodata(void)
+{
+ int32 h, t, datsize;
+ Section *sect;
+ Sym *s, *last, **l;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f dodata\n", cputime());
+ Bflush(&bso);
+
+ last = nil;
+ datap = nil;
+ for(h=0; h<NHASH; h++) {
+ for(s=hash[h]; s!=S; s=s->hash){
+ if(!s->reachable || s->special)
+ continue;
+ if(STEXT < s->type && s->type < SXREF) {
+ if(last == nil)
+ datap = s;
+ else
+ last->next = s;
+ s->next = nil;
+ last = s;
+ }
+ }
+ }
+
+ for(s = datap; s != nil; s = s->next) {
+ if(s->np > 0 && s->type == SBSS) // TODO: necessary?
+ 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
+ * dynamic relocations. these will grow the relocation
+ * symbol, which is itself data.
+ */
+ dynreloc();
+
+ /* some symbols may no longer belong in datap (Mach-O) */
+ for(l=&datap; (s=*l) != nil; ) {
+ if(s->type <= STEXT || SXREF <= s->type)
+ *l = s->next;
+ else
+ l = &s->next;
+ }
+ *l = nil;
+
+ datap = datsort(datap);
+
+ /*
+ * allocate data sections. list is sorted by type,
+ * so we can just walk it for each piece we want to emit.
+ */
+
+ /* read-only data */
+ sect = addsection(&segtext, ".rodata", 06);
+ sect->vaddr = 0;
+ datsize = 0;
+ s = datap;
+ for(; s != nil && s->type < SDATA; s = s->next) {
+ s->type = SRODATA;
+ t = rnd(s->size, 4);
+ s->size = t;
+ s->value = datsize;
+ datsize += t;
+ }
+ sect->len = datsize - sect->vaddr;
+
+ /* data */
+ datsize = 0;
+ sect = addsection(&segdata, ".data", 06);
+ sect->vaddr = 0;
+ for(; s != nil && s->type < SBSS; s = s->next) {
+ s->type = SDATA;
+ t = s->size;
+ if(t == 0 && s->name[0] != '.') {
+ diag("%s: no size", s->name);
+ t = 1;
+ }
+ if(t & 1)
+ ;
+ else if(t & 2)
+ datsize = rnd(datsize, 2);
+ else if(t & 4)
+ datsize = rnd(datsize, 4);
+ else
+ datsize = rnd(datsize, 8);
+ s->value = datsize;
+ datsize += t;
+ }
+ sect->len = datsize - sect->vaddr;
+
+ /* bss */
+ sect = addsection(&segdata, ".bss", 06);
+ sect->vaddr = datsize;
+ for(; s != nil; s = s->next) {
+ if(s->type != SBSS) {
+ cursym = s;
+ diag("unexpected symbol type %d", s->type);
+ }
+ t = s->size;
+ if(t & 1)
+ ;
+ else if(t & 2)
+ datsize = rnd(datsize, 2);
+ else if(t & 4)
+ datsize = rnd(datsize, 4);
+ else
+ datsize = rnd(datsize, 8);
+ s->size = t;
+ s->value = datsize;
+ datsize += t;
+ }
+ sect->len = datsize - sect->vaddr;
+}
+
+// assign addresses to text
+void
+textaddress(void)
+{
+ uvlong va;
+ Prog *p;
+ Section *sect;
+ Sym *sym, *sub;
+
+ addsection(&segtext, ".text", 05);
+
+ // Assign PCs in text segment.
+ // Could parallelize, by assigning to text
+ // and then letting threads copy down, but probably not worth it.
+ sect = segtext.sect;
+ va = INITTEXT;
+ sect->vaddr = va;
+ for(sym = textp; sym != nil; sym = sym->next) {
+ if(sym->type & SSUB)
+ continue;
+ sym->value = 0;
+ for(sub = sym; sub != S; sub = sub->sub) {
+ sub->value += va;
+ for(p = sub->text; p != P; p = p->link)
+ p->pc += sub->value;
+ }
+ if(sym->size == 0 && sym->sub != S) {
+ cursym = sym;
+ }
+ va += sym->size;
+ }
+ sect->len = va - sect->vaddr;
+}
+
+// assign addresses
+void
+address(void)
+{
+ Section *s, *text, *data, *rodata, *bss;
+ Sym *sym, *sub;
+ uvlong va;
+
+ va = INITTEXT;
+ segtext.rwx = 05;
+ segtext.vaddr = va;
+ segtext.fileoff = HEADR;
+ for(s=segtext.sect; s != nil; s=s->next) {
+ s->vaddr = va;
+ va += s->len;
+ segtext.len = va - INITTEXT;
+ va = rnd(va, INITRND);
+ }
+ segtext.filelen = segtext.len;
+
+ segdata.rwx = 06;
+ segdata.vaddr = va;
+ segdata.fileoff = va - segtext.vaddr + segtext.fileoff;
+ if(thechar == '8' && HEADTYPE == 10) // Windows PE
+ segdata.fileoff = segtext.fileoff + rnd(segtext.len, PEFILEALIGN);
+ if(thechar == '8' && HEADTYPE == 2) { // Plan 9
+ segdata.vaddr = va = rnd(va, 4096);
+ segdata.fileoff = segtext.fileoff + segtext.filelen;
+ }
+ for(s=segdata.sect; s != nil; s=s->next) {
+ s->vaddr = va;
+ va += s->len;
+ segdata.len = va - segdata.vaddr;
+ }
+ segdata.filelen = segdata.sect->len; // assume .data is first
+
+ text = segtext.sect;
+ rodata = segtext.sect->next;
+ data = segdata.sect;
+ bss = segdata.sect->next;
+
+ for(sym = datap; sym != nil; sym = sym->next) {
+ cursym = sym;
+ if(sym->type < SDATA)
+ sym->value += rodata->vaddr;
+ else
+ sym->value += data->vaddr;
+ for(sub = sym->sub; sub != nil; sub = sub->sub)
+ sub->value += sym->value;
+ }
+
+ xdefine("text", STEXT, text->vaddr);
+ xdefine("etext", STEXT, text->vaddr + text->len);
+ xdefine("rodata", SRODATA, rodata->vaddr);
+ xdefine("erodata", SRODATA, rodata->vaddr + rodata->len);
+ xdefine("data", SBSS, data->vaddr);
+ xdefine("edata", SBSS, data->vaddr + data->len);
+ xdefine("end", SBSS, segdata.vaddr + segdata.len);
+
+ sym = lookup("pclntab", 0);
+ xdefine("epclntab", SRODATA, sym->value + sym->size);
+ sym = lookup("symtab", 0);
+ xdefine("esymtab", SRODATA, sym->value + sym->size);
+}
diff --git a/src/cmd/ld/dwarf.c b/src/cmd/ld/dwarf.c
new file mode 100644
index 000000000..506c6e5db
--- /dev/null
+++ b/src/cmd/ld/dwarf.c
@@ -0,0 +1,2547 @@
+// Copyright 2010 The Go 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/NICETOHAVE:
+// - eliminate DW_CLS_ if not used
+// - package info in compilation units
+// - assign global variables and types to their packages
+// - (upstream) type info for C parts of runtime
+// - gdb uses c syntax, meaning clumsy quoting is needed for go identifiers. eg
+// ptype struct '[]uint8' and qualifiers need to be quoted away
+// - lexical scoping is lost, so gdb gets confused as to which 'main.i' you mean.
+// - file:line info for variables
+// - make strings a typedef so prettyprinters can see the underlying string type
+//
+#include "l.h"
+#include "lib.h"
+#include "../ld/dwarf.h"
+#include "../ld/dwarf_defs.h"
+#include "../ld/elf.h"
+#include "../ld/macho.h"
+
+/*
+ * Offsets and sizes of the debug_* sections in the cout file.
+ */
+
+static vlong abbrevo;
+static vlong abbrevsize;
+static vlong lineo;
+static vlong linesize;
+static vlong infoo; // also the base for DWDie->offs and reference attributes.
+static vlong infosize;
+static vlong frameo;
+static vlong framesize;
+static vlong pubnameso;
+static vlong pubnamessize;
+static vlong pubtypeso;
+static vlong pubtypessize;
+static vlong arangeso;
+static vlong arangessize;
+static vlong gdbscripto;
+static vlong gdbscriptsize;
+
+static char gdbscript[1024];
+
+/*
+ * Basic I/O
+ */
+
+static void
+addrput(vlong addr)
+{
+ switch(PtrSize) {
+ case 4:
+ LPUT(addr);
+ break;
+ case 8:
+ VPUT(addr);
+ break;
+ }
+}
+
+static int
+uleb128enc(uvlong v, char* dst)
+{
+ uint8 c, len;
+
+ len = 0;
+ do {
+ c = v & 0x7f;
+ v >>= 7;
+ if (v)
+ c |= 0x80;
+ if (dst)
+ *dst++ = c;
+ len++;
+ } while (c & 0x80);
+ return len;
+};
+
+static int
+sleb128enc(vlong v, char *dst)
+{
+ uint8 c, s, len;
+
+ len = 0;
+ do {
+ c = v & 0x7f;
+ s = v & 0x40;
+ v >>= 7;
+ if ((v != -1 || !s) && (v != 0 || s))
+ c |= 0x80;
+ if (dst)
+ *dst++ = c;
+ len++;
+ } while(c & 0x80);
+ return len;
+}
+
+static void
+uleb128put(vlong v)
+{
+ char buf[10];
+ strnput(buf, uleb128enc(v, buf));
+}
+
+static void
+sleb128put(vlong v)
+{
+ char buf[10];
+ strnput(buf, sleb128enc(v, buf));
+}
+
+/*
+ * Defining Abbrevs. This is hardcoded, and there will be
+ * only a handful of them. The DWARF spec places no restriction on
+ * the ordering of atributes in the Abbrevs and DIEs, and we will
+ * always write them out in the order of declaration in the abbrev.
+ * This implementation relies on tag, attr < 127, so they serialize as
+ * a char. Higher numbered user-defined tags or attributes can be used
+ * for storing internal data but won't be serialized.
+ */
+typedef struct DWAttrForm DWAttrForm;
+struct DWAttrForm {
+ uint8 attr;
+ uint8 form;
+};
+
+// Index into the abbrevs table below.
+// Keep in sync with ispubname() and ispubtype() below.
+// ispubtype considers >= NULLTYPE public
+enum
+{
+ DW_ABRV_NULL,
+ DW_ABRV_COMPUNIT,
+ DW_ABRV_FUNCTION,
+ DW_ABRV_VARIABLE,
+ DW_ABRV_AUTO,
+ DW_ABRV_PARAM,
+ DW_ABRV_STRUCTFIELD,
+ DW_ABRV_FUNCTYPEPARAM,
+ DW_ABRV_DOTDOTDOT,
+ DW_ABRV_ARRAYRANGE,
+ DW_ABRV_NULLTYPE,
+ DW_ABRV_BASETYPE,
+ DW_ABRV_ARRAYTYPE,
+ DW_ABRV_CHANTYPE,
+ DW_ABRV_FUNCTYPE,
+ DW_ABRV_IFACETYPE,
+ DW_ABRV_MAPTYPE,
+ DW_ABRV_PTRTYPE,
+ DW_ABRV_SLICETYPE,
+ DW_ABRV_STRINGTYPE,
+ DW_ABRV_STRUCTTYPE,
+ DW_ABRV_TYPEDECL,
+ DW_NABRV
+};
+
+typedef struct DWAbbrev DWAbbrev;
+static struct DWAbbrev {
+ uint8 tag;
+ uint8 children;
+ DWAttrForm attr[30];
+} abbrevs[DW_NABRV] = {
+ /* The mandatory DW_ABRV_NULL entry. */
+ { 0 },
+ /* COMPUNIT */
+ {
+ DW_TAG_compile_unit, DW_CHILDREN_yes,
+ DW_AT_name, DW_FORM_string,
+ DW_AT_language, DW_FORM_data1,
+ DW_AT_low_pc, DW_FORM_addr,
+ DW_AT_high_pc, DW_FORM_addr,
+ DW_AT_stmt_list, DW_FORM_data4,
+ 0, 0
+ },
+ /* FUNCTION */
+ {
+ DW_TAG_subprogram, DW_CHILDREN_yes,
+ DW_AT_name, DW_FORM_string,
+ DW_AT_low_pc, DW_FORM_addr,
+ DW_AT_high_pc, DW_FORM_addr,
+ DW_AT_external, DW_FORM_flag,
+ 0, 0
+ },
+ /* VARIABLE */
+ {
+ DW_TAG_variable, DW_CHILDREN_no,
+ DW_AT_name, DW_FORM_string,
+ DW_AT_location, DW_FORM_block1,
+ DW_AT_type, DW_FORM_ref_addr,
+ DW_AT_external, DW_FORM_flag,
+ 0, 0
+ },
+ /* AUTO */
+ {
+ DW_TAG_variable, DW_CHILDREN_no,
+ DW_AT_name, DW_FORM_string,
+ DW_AT_location, DW_FORM_block1,
+ DW_AT_type, DW_FORM_ref_addr,
+ 0, 0
+ },
+ /* PARAM */
+ {
+ DW_TAG_formal_parameter, DW_CHILDREN_no,
+ DW_AT_name, DW_FORM_string,
+ DW_AT_location, DW_FORM_block1,
+ DW_AT_type, DW_FORM_ref_addr,
+ 0, 0
+ },
+ /* STRUCTFIELD */
+ {
+ DW_TAG_member, DW_CHILDREN_no,
+ DW_AT_name, DW_FORM_string,
+ DW_AT_data_member_location, DW_FORM_block1,
+ DW_AT_type, DW_FORM_ref_addr,
+ 0, 0
+ },
+ /* FUNCTYPEPARAM */
+ {
+ DW_TAG_formal_parameter, DW_CHILDREN_no,
+ // No name!
+ DW_AT_type, DW_FORM_ref_addr,
+ 0, 0
+ },
+
+ /* DOTDOTDOT */
+ {
+ DW_TAG_unspecified_parameters, DW_CHILDREN_no,
+ 0, 0
+ },
+ /* ARRAYRANGE */
+ {
+ DW_TAG_subrange_type, DW_CHILDREN_no,
+ // No name!
+ DW_AT_type, DW_FORM_ref_addr,
+ DW_AT_upper_bound, DW_FORM_data1,
+ 0, 0
+ },
+
+ // Below here are the types considered public by ispubtype
+ /* NULLTYPE */
+ {
+ DW_TAG_unspecified_type, DW_CHILDREN_no,
+ DW_AT_name, DW_FORM_string,
+ 0, 0
+ },
+ /* BASETYPE */
+ {
+ DW_TAG_base_type, DW_CHILDREN_no,
+ DW_AT_name, DW_FORM_string,
+ DW_AT_encoding, DW_FORM_data1,
+ DW_AT_byte_size, DW_FORM_data1,
+ 0, 0
+ },
+ /* ARRAYTYPE */
+ // child is subrange with upper bound
+ {
+ DW_TAG_array_type, DW_CHILDREN_yes,
+ DW_AT_name, DW_FORM_string,
+ DW_AT_type, DW_FORM_ref_addr,
+ DW_AT_byte_size, DW_FORM_udata,
+ 0, 0
+ },
+
+ /* CHANTYPE */
+ {
+ DW_TAG_typedef, DW_CHILDREN_no,
+ DW_AT_name, DW_FORM_string,
+ DW_AT_type, DW_FORM_ref_addr,
+ 0, 0
+ },
+
+ /* FUNCTYPE */
+ {
+ DW_TAG_subroutine_type, DW_CHILDREN_yes,
+ DW_AT_name, DW_FORM_string,
+// DW_AT_type, DW_FORM_ref_addr,
+ 0, 0
+ },
+
+ /* IFACETYPE */
+ {
+ DW_TAG_typedef, DW_CHILDREN_yes,
+ DW_AT_name, DW_FORM_string,
+ DW_AT_type, DW_FORM_ref_addr,
+ 0, 0
+ },
+
+ /* MAPTYPE */
+ {
+ DW_TAG_typedef, DW_CHILDREN_no,
+ DW_AT_name, DW_FORM_string,
+ DW_AT_type, DW_FORM_ref_addr,
+ 0, 0
+ },
+
+ /* PTRTYPE */
+ {
+ DW_TAG_pointer_type, DW_CHILDREN_no,
+ DW_AT_name, DW_FORM_string,
+ DW_AT_type, DW_FORM_ref_addr,
+ 0, 0
+ },
+
+ /* SLICETYPE */
+ {
+ DW_TAG_structure_type, DW_CHILDREN_yes,
+ DW_AT_name, DW_FORM_string,
+ DW_AT_byte_size, DW_FORM_udata,
+ 0, 0
+ },
+
+ /* STRINGTYPE */
+ {
+ DW_TAG_structure_type, DW_CHILDREN_yes,
+ DW_AT_name, DW_FORM_string,
+ DW_AT_byte_size, DW_FORM_udata,
+ 0, 0
+ },
+
+ /* STRUCTTYPE */
+ {
+ DW_TAG_structure_type, DW_CHILDREN_yes,
+ DW_AT_name, DW_FORM_string,
+ DW_AT_byte_size, DW_FORM_udata,
+ 0, 0
+ },
+
+ /* TYPEDECL */
+ {
+ DW_TAG_typedef, DW_CHILDREN_no,
+ DW_AT_name, DW_FORM_string,
+ DW_AT_type, DW_FORM_ref_addr,
+ 0, 0
+ },
+};
+
+static void
+writeabbrev(void)
+{
+ int i, n;
+
+ abbrevo = cpos();
+ for (i = 1; i < DW_NABRV; i++) {
+ // See section 7.5.3
+ uleb128put(i);
+ uleb128put(abbrevs[i].tag);
+ cput(abbrevs[i].children);
+ // 0 is not a valid attr or form, and DWAbbrev.attr is
+ // 0-terminated, so we can treat it as a string
+ n = strlen((char*)abbrevs[i].attr) / 2;
+ strnput((char*)abbrevs[i].attr,
+ (n+1) * sizeof(DWAttrForm));
+ }
+ cput(0);
+ abbrevsize = cpos() - abbrevo;
+}
+
+/*
+ * Debugging Information Entries and their attributes.
+ */
+
+enum
+{
+ HASHSIZE = 107
+};
+
+static uint32
+hashstr(char* s)
+{
+ uint32 h;
+
+ h = 0;
+ while (*s)
+ h = h+h+h + *s++;
+ return h % HASHSIZE;
+}
+
+// For DW_CLS_string and _block, value should contain the length, and
+// data the data, for _reference, value is 0 and data is a DWDie* to
+// the referenced instance, for all others, value is the whole thing
+// and data is null.
+
+typedef struct DWAttr DWAttr;
+struct DWAttr {
+ DWAttr *link;
+ uint8 atr; // DW_AT_
+ uint8 cls; // DW_CLS_
+ vlong value;
+ char *data;
+};
+
+typedef struct DWDie DWDie;
+struct DWDie {
+ int abbrev;
+ DWDie *link;
+ DWDie *child;
+ DWAttr *attr;
+ // offset into .debug_info section, i.e relative to
+ // infoo. only valid after call to putdie()
+ vlong offs;
+ DWDie **hash; // optional index of children by name, enabled by mkindex()
+ DWDie *hlink; // bucket chain in parent's index
+};
+
+/*
+ * Root DIEs for compilation units, types and global variables.
+ */
+
+static DWDie dwroot;
+static DWDie dwtypes;
+static DWDie dwglobals;
+
+static DWAttr*
+newattr(DWDie *die, uint8 attr, int cls, vlong value, char *data)
+{
+ DWAttr *a;
+
+ a = mal(sizeof *a);
+ a->link = die->attr;
+ die->attr = a;
+ a->atr = attr;
+ a->cls = cls;
+ a->value = value;
+ a->data = data;
+ return a;
+}
+
+// Each DIE (except the root ones) has at least 1 attribute: its
+// name. getattr moves the desired one to the front so
+// frequently searched ones are found faster.
+static DWAttr*
+getattr(DWDie *die, uint8 attr)
+{
+ DWAttr *a, *b;
+
+ if (die->attr->atr == attr)
+ return die->attr;
+
+ a = die->attr;
+ b = a->link;
+ while (b != nil) {
+ if (b->atr == attr) {
+ a->link = b->link;
+ b->link = die->attr;
+ die->attr = b;
+ return b;
+ }
+ a = b;
+ b = b->link;
+ }
+ return nil;
+}
+
+static void
+delattr(DWDie *die, uint8 attr)
+{
+ DWAttr **a;
+
+ a = &die->attr;
+ while (*a != nil)
+ if ((*a)->atr == attr)
+ *a = (*a)->link;
+ else
+ a = &((*a)->link);
+}
+
+// Every DIE has at least a DW_AT_name attribute (but it will only be
+// written out if it is listed in the abbrev). If its parent is
+// keeping an index, the new DIE will be inserted there.
+static DWDie*
+newdie(DWDie *parent, int abbrev, char *name)
+{
+ DWDie *die;
+ int h;
+
+ die = mal(sizeof *die);
+ die->abbrev = abbrev;
+ die->link = parent->child;
+ parent->child = die;
+
+ newattr(die, DW_AT_name, DW_CLS_STRING, strlen(name), name);
+
+ if (parent->hash) {
+ h = hashstr(name);
+ die->hlink = parent->hash[h];
+ parent->hash[h] = die;
+ }
+
+ return die;
+}
+
+static void
+mkindex(DWDie *die)
+{
+ die->hash = mal(HASHSIZE * sizeof(DWDie*));
+}
+
+// Find child by AT_name using hashtable if available or linear scan
+// if not.
+static DWDie*
+find(DWDie *die, char* name)
+{
+ DWDie *a, *b;
+ int h;
+
+ if (die->hash == nil) {
+ for (a = die->child; a != nil; a = a->link)
+ if (strcmp(name, getattr(a, DW_AT_name)->data) == 0)
+ return a;
+ return nil;
+ }
+
+ h = hashstr(name);
+ a = die->hash[h];
+
+ if (a == nil)
+ return nil;
+
+
+ if (strcmp(name, getattr(a, DW_AT_name)->data) == 0)
+ return a;
+
+ // Move found ones to head of the list.
+ b = a->hlink;
+ while (b != nil) {
+ if (strcmp(name, getattr(b, DW_AT_name)->data) == 0) {
+ a->hlink = b->hlink;
+ b->hlink = die->hash[h];
+ die->hash[h] = b;
+ return b;
+ }
+ a = b;
+ b = b->hlink;
+ }
+ return nil;
+}
+
+static DWDie*
+find_or_diag(DWDie *die, char* name)
+{
+ DWDie *r;
+ r = find(die, name);
+ if (r == nil)
+ diag("dwarf find: %s has no %s", getattr(die, DW_AT_name)->data, name);
+ return r;
+}
+
+static DWAttr*
+newrefattr(DWDie *die, uint8 attr, DWDie* ref)
+{
+ if (ref == nil)
+ return nil;
+ return newattr(die, attr, DW_CLS_REFERENCE, 0, (char*)ref);
+}
+
+static int fwdcount;
+
+static void
+putattr(int form, int cls, vlong value, char *data)
+{
+ switch(form) {
+ case DW_FORM_addr: // address
+ addrput(value);
+ break;
+
+ case DW_FORM_block1: // block
+ value &= 0xff;
+ cput(value);
+ while(value--)
+ cput(*data++);
+ break;
+
+ case DW_FORM_block2: // block
+ value &= 0xffff;
+ WPUT(value);
+ while(value--)
+ cput(*data++);
+ break;
+
+ case DW_FORM_block4: // block
+ value &= 0xffffffff;
+ LPUT(value);
+ while(value--)
+ cput(*data++);
+ break;
+
+ case DW_FORM_block: // block
+ uleb128put(value);
+ while(value--)
+ cput(*data++);
+ break;
+
+ case DW_FORM_data1: // constant
+ cput(value);
+ break;
+
+ case DW_FORM_data2: // constant
+ WPUT(value);
+ break;
+
+ case DW_FORM_data4: // constant, {line,loclist,mac,rangelist}ptr
+ LPUT(value);
+ break;
+
+ case DW_FORM_data8: // constant, {line,loclist,mac,rangelist}ptr
+ VPUT(value);
+ break;
+
+ case DW_FORM_sdata: // constant
+ sleb128put(value);
+ break;
+
+ case DW_FORM_udata: // constant
+ uleb128put(value);
+ break;
+
+ case DW_FORM_string: // string
+ strnput(data, value+1);
+ break;
+
+ case DW_FORM_flag: // flag
+ cput(value?1:0);
+ break;
+
+ case DW_FORM_ref_addr: // reference to a DIE in the .info section
+ if (data == nil) {
+ diag("null dwarf reference");
+ LPUT(0); // invalid dwarf, gdb will complain.
+ } else {
+ if (((DWDie*)data)->offs == 0)
+ fwdcount++;
+ LPUT(((DWDie*)data)->offs);
+ }
+ break;
+
+ case DW_FORM_ref1: // reference within the compilation unit
+ case DW_FORM_ref2: // reference
+ case DW_FORM_ref4: // reference
+ case DW_FORM_ref8: // reference
+ case DW_FORM_ref_udata: // reference
+
+ case DW_FORM_strp: // string
+ case DW_FORM_indirect: // (see Section 7.5.3)
+ default:
+ diag("Unsupported atribute form %d / class %d", form, cls);
+ errorexit();
+ }
+}
+
+// Note that we can (and do) add arbitrary attributes to a DIE, but
+// only the ones actually listed in the Abbrev will be written out.
+static void
+putattrs(int abbrev, DWAttr* attr)
+{
+ DWAttr *attrs[DW_AT_recursive + 1];
+ DWAttrForm* af;
+
+ memset(attrs, 0, sizeof attrs);
+ for( ; attr; attr = attr->link)
+ if (attr->atr < nelem(attrs))
+ attrs[attr->atr] = attr;
+
+ for(af = abbrevs[abbrev].attr; af->attr; af++)
+ if (attrs[af->attr])
+ putattr(af->form,
+ attrs[af->attr]->cls,
+ attrs[af->attr]->value,
+ attrs[af->attr]->data);
+ else
+ putattr(af->form, 0, 0, 0);
+}
+
+static void putdie(DWDie* die);
+
+static void
+putdies(DWDie* die)
+{
+ for(; die; die = die->link)
+ putdie(die);
+}
+
+static void
+putdie(DWDie* die)
+{
+ die->offs = cpos() - infoo;
+ uleb128put(die->abbrev);
+ putattrs(die->abbrev, die->attr);
+ if (abbrevs[die->abbrev].children) {
+ putdies(die->child);
+ cput(0);
+ }
+}
+
+static void
+reverselist(DWDie** list)
+{
+ DWDie *curr, *prev;
+
+ curr = *list;
+ prev = nil;
+ while(curr != nil) {
+ DWDie* next = curr->link;
+ curr->link = prev;
+ prev = curr;
+ curr = next;
+ }
+ *list = prev;
+}
+
+static void
+reversetree(DWDie** list)
+{
+ DWDie *die;
+
+ reverselist(list);
+ for (die = *list; die != nil; die = die->link)
+ if (abbrevs[die->abbrev].children)
+ reversetree(&die->child);
+}
+
+static void
+newmemberoffsetattr(DWDie *die, int32 offs)
+{
+ char block[10];
+ int i;
+
+ i = 0;
+ if (offs != 0) {
+ block[i++] = DW_OP_consts;
+ i += sleb128enc(offs, block+i);
+ block[i++] = DW_OP_plus;
+ }
+ newattr(die, DW_AT_data_member_location, DW_CLS_BLOCK, i, mal(i));
+ memmove(die->attr->data, block, i);
+}
+
+// GDB doesn't like DW_FORM_addr for DW_AT_location, so emit a
+// location expression that evals to a const.
+static void
+newabslocexprattr(DWDie *die, vlong addr)
+{
+ char block[10];
+ int i;
+
+ i = 0;
+ block[i++] = DW_OP_constu;
+ i += uleb128enc(addr, block+i);
+ newattr(die, DW_AT_location, DW_CLS_BLOCK, i, mal(i));
+ memmove(die->attr->data, block, i);
+}
+
+// Decoding the type.* symbols. This has to be in sync with
+// ../../pkg/runtime/type.go, or more specificaly, with what
+// ../gc/reflect.c stuffs in these.
+
+enum {
+ KindBool = 1,
+ KindInt,
+ KindInt8,
+ KindInt16,
+ KindInt32,
+ KindInt64,
+ KindUint,
+ KindUint8,
+ KindUint16,
+ KindUint32,
+ KindUint64,
+ KindUintptr,
+ KindFloat,
+ KindFloat32,
+ KindFloat64,
+ KindComplex,
+ KindComplex64,
+ KindComplex128,
+ KindArray,
+ KindChan,
+ KindFunc,
+ KindInterface,
+ KindMap,
+ KindPtr,
+ KindSlice,
+ KindString,
+ KindStruct,
+ KindUnsafePointer,
+
+ KindNoPointers = 1<<7,
+};
+
+static Reloc*
+decode_reloc(Sym *s, int32 off)
+{
+ int i;
+
+ for (i = 0; i < s->nr; i++)
+ if (s->r[i].off == off)
+ return s->r + i;
+ return nil;
+}
+
+static uvlong
+decode_inuxi(uchar* p, int sz)
+{
+ uint64 v;
+ uint32 l;
+ uchar *cast, *inuxi;
+ int i;
+
+ v = l = 0;
+ cast = nil;
+ inuxi = nil;
+ switch (sz) {
+ case 2:
+ cast = (uchar*)&l;
+ inuxi = inuxi2;
+ break;
+ case 4:
+ cast = (uchar*)&l;
+ inuxi = inuxi4;
+ break;
+ case 8:
+ cast = (uchar*)&v;
+ inuxi = inuxi8;
+ break;
+ default:
+ diag("decode inuxi %d", sz);
+ errorexit();
+ }
+ for (i = 0; i < sz; i++)
+ cast[inuxi[i]] = p[i];
+ if (sz == 8)
+ return v;
+ return l;
+}
+
+// Type.commonType.kind
+static uint8
+decodetype_kind(Sym *s)
+{
+ return s->p[3*PtrSize + 7] & ~KindNoPointers; // 0x13 / 0x1f
+}
+
+// Type.commonType.size
+static vlong
+decodetype_size(Sym *s)
+{
+ return decode_inuxi(s->p + 2*PtrSize, PtrSize); // 0x8 / 0x10
+}
+
+// Type.ArrayType.elem and Type.SliceType.Elem
+static Sym*
+decodetype_arrayelem(Sym *s)
+{
+ return decode_reloc(s, 5*PtrSize + 8)->sym; // 0x1c / 0x30
+}
+
+static vlong
+decodetype_arraylen(Sym *s)
+{
+ return decode_inuxi(s->p + 6*PtrSize + 8, PtrSize);
+}
+
+// Type.PtrType.elem
+static Sym*
+decodetype_ptrelem(Sym *s)
+{
+ return decode_reloc(s, 5*PtrSize + 8)->sym; // 0x1c / 0x30
+}
+
+// Type.MapType.key, elem
+static Sym*
+decodetype_mapkey(Sym *s)
+{
+ return decode_reloc(s, 5*PtrSize + 8)->sym; // 0x1c / 0x30
+}
+static Sym*
+decodetype_mapvalue(Sym *s)
+{
+ return decode_reloc(s, 6*PtrSize + 8)->sym; // 0x20 / 0x38
+}
+
+// Type.ChanType.elem
+static Sym*
+decodetype_chanelem(Sym *s)
+{
+ return decode_reloc(s, 5*PtrSize + 8)->sym; // 0x1c / 0x30
+}
+
+// Type.FuncType.dotdotdot
+static int
+decodetype_funcdotdotdot(Sym *s)
+{
+ return s->p[5*PtrSize + 8];
+}
+
+// Type.FuncType.in.len
+static int
+decodetype_funcincount(Sym *s)
+{
+ return decode_inuxi(s->p + 7*PtrSize + 8, 4);
+}
+
+static int
+decodetype_funcoutcount(Sym *s)
+{
+ return decode_inuxi(s->p + 8*PtrSize + 16, 4);
+}
+
+static Sym*
+decodetype_funcintype(Sym *s, int i)
+{
+ Reloc *r;
+
+ r = decode_reloc(s, 6*PtrSize + 8);
+ return decode_reloc(r->sym, r->add + i * PtrSize)->sym;
+}
+
+static Sym*
+decodetype_funcouttype(Sym *s, int i)
+{
+ Reloc *r;
+
+ r = decode_reloc(s, 7*PtrSize + 16);
+ return decode_reloc(r->sym, r->add + i * PtrSize)->sym;
+}
+
+// Type.StructType.fields.Slice::len
+static int
+decodetype_structfieldcount(Sym *s)
+{
+ return decode_inuxi(s->p + 6*PtrSize + 8, 4); // 0x20 / 0x38
+}
+
+// Type.StructType.fields[]-> name, typ and offset. sizeof(structField) = 5*PtrSize
+static char*
+decodetype_structfieldname(Sym *s, int i)
+{
+ Reloc* r;
+
+ r = decode_reloc(s, 6*PtrSize + 0x10 + i*5*PtrSize); // go.string."foo" 0x28 / 0x40
+ if (r == nil) // embedded structs have a nil name.
+ return nil;
+ r = decode_reloc(r->sym, 0); // string."foo"
+ if (r == nil) // shouldn't happen.
+ return nil;
+ return (char*)r->sym->p; // the c-string
+}
+
+static Sym*
+decodetype_structfieldtype(Sym *s, int i)
+{
+ return decode_reloc(s, 8*PtrSize + 0x10 + i*5*PtrSize)->sym; // 0x30 / 0x50
+}
+
+static vlong
+decodetype_structfieldoffs(Sym *s, int i)
+{
+ return decode_inuxi(s->p + 10*PtrSize + 0x10 + i*5*PtrSize, 4); // 0x38 / 0x60
+}
+
+// InterfaceTYpe.methods.len
+static vlong
+decodetype_ifacemethodcount(Sym *s)
+{
+ return decode_inuxi(s->p + 6*PtrSize + 8, 4);
+}
+
+
+// Fake attributes for slices, maps and channel
+enum {
+ DW_AT_internal_elem_type = 250, // channels and slices
+ DW_AT_internal_key_type = 251, // maps
+ DW_AT_internal_val_type = 252, // maps
+ DW_AT_internal_location = 253, // params and locals
+};
+
+static DWDie* defptrto(DWDie *dwtype); // below
+
+// Define gotype, for composite ones recurse into constituents.
+static DWDie*
+defgotype(Sym *gotype)
+{
+ DWDie *die, *fld;
+ Sym *s;
+ char *name, *f;
+ uint8 kind;
+ vlong bytesize;
+ int i, nfields;
+
+ if (gotype == nil)
+ return find_or_diag(&dwtypes, "<unspecified>");
+
+ if (strncmp("type.", gotype->name, 5) != 0) {
+ diag("Type name doesn't start with \".type\": %s", gotype->name);
+ return find_or_diag(&dwtypes, "<unspecified>");
+ }
+ name = gotype->name + 5; // Altenatively decode from Type.string
+
+ die = find(&dwtypes, name);
+ if (die != nil)
+ return die;
+
+ if (0 && debug['v'] > 2) {
+ print("new type: %s @0x%08x [%d]", gotype->name, gotype->value, gotype->size);
+ for (i = 0; i < gotype->size; i++) {
+ if (!(i%8)) print("\n\t%04x ", i);
+ print("%02x ", gotype->p[i]);
+ }
+ print("\n");
+ for (i = 0; i < gotype->nr; i++) {
+ print("\t0x%02x[%x] %d %s[%llx]\n",
+ gotype->r[i].off,
+ gotype->r[i].siz,
+ gotype->r[i].type,
+ gotype->r[i].sym->name,
+ (vlong)gotype->r[i].add);
+ }
+ }
+
+ kind = decodetype_kind(gotype);
+ bytesize = decodetype_size(gotype);
+
+ switch (kind) {
+ case KindBool:
+ die = newdie(&dwtypes, DW_ABRV_BASETYPE, name);
+ newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_boolean, 0);
+ newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
+ break;
+
+ case KindInt:
+ case KindInt8:
+ case KindInt16:
+ case KindInt32:
+ case KindInt64:
+ die = newdie(&dwtypes, DW_ABRV_BASETYPE, name);
+ newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_signed, 0);
+ newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
+ break;
+
+ case KindUint:
+ case KindUint8:
+ case KindUint16:
+ case KindUint32:
+ case KindUint64:
+ case KindUintptr:
+ die = newdie(&dwtypes, DW_ABRV_BASETYPE, name);
+ newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_unsigned, 0);
+ newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
+ break;
+
+ case KindFloat:
+ case KindFloat32:
+ case KindFloat64:
+ die = newdie(&dwtypes, DW_ABRV_BASETYPE, name);
+ newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_float, 0);
+ newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
+ break;
+
+ case KindComplex:
+ case KindComplex64:
+ case KindComplex128:
+ die = newdie(&dwtypes, DW_ABRV_BASETYPE, name);
+ newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_complex_float, 0);
+ newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
+ break;
+
+ case KindArray:
+ die = newdie(&dwtypes, DW_ABRV_ARRAYTYPE, name);
+ newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
+ s = decodetype_arrayelem(gotype);
+ newrefattr(die, DW_AT_type, defgotype(s));
+ fld = newdie(die, DW_ABRV_ARRAYRANGE, "range");
+ newattr(fld, DW_AT_upper_bound, DW_CLS_CONSTANT, decodetype_arraylen(gotype), 0);
+ newrefattr(fld, DW_AT_type, find_or_diag(&dwtypes, "uintptr"));
+ break;
+
+ case KindChan:
+ die = newdie(&dwtypes, DW_ABRV_CHANTYPE, name);
+ newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
+ s = decodetype_chanelem(gotype);
+ newrefattr(die, DW_AT_internal_elem_type, defgotype(s));
+ break;
+
+ case KindFunc:
+ die = newdie(&dwtypes, DW_ABRV_FUNCTYPE, name);
+ newrefattr(die, DW_AT_type, find_or_diag(&dwtypes, "void"));
+ nfields = decodetype_funcincount(gotype);
+ for (i = 0; i < nfields; i++) {
+ s = decodetype_funcintype(gotype, i);
+ fld = newdie(die, DW_ABRV_FUNCTYPEPARAM, s->name+5);
+ newrefattr(fld, DW_AT_type, defgotype(s));
+ }
+ if (decodetype_funcdotdotdot(gotype))
+ newdie(die, DW_ABRV_DOTDOTDOT, "...");
+ nfields = decodetype_funcoutcount(gotype);
+ for (i = 0; i < nfields; i++) {
+ s = decodetype_funcouttype(gotype, i);
+ fld = newdie(die, DW_ABRV_FUNCTYPEPARAM, s->name+5);
+ newrefattr(fld, DW_AT_type, defptrto(defgotype(s)));
+ }
+ die = defptrto(die);
+ break;
+
+ case KindInterface:
+ die = newdie(&dwtypes, DW_ABRV_IFACETYPE, name);
+ newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
+ nfields = decodetype_ifacemethodcount(gotype);
+ if (nfields == 0)
+ s = lookup("type.runtime.eface", 0);
+ else
+ s = lookup("type.runtime.iface", 0);
+ newrefattr(die, DW_AT_type, defgotype(s));
+ break;
+
+ case KindMap:
+ die = newdie(&dwtypes, DW_ABRV_MAPTYPE, name);
+ s = decodetype_mapkey(gotype);
+ newrefattr(die, DW_AT_internal_key_type, defgotype(s));
+ s = decodetype_mapvalue(gotype);
+ newrefattr(die, DW_AT_internal_val_type, defgotype(s));
+ break;
+
+ case KindPtr:
+ die = newdie(&dwtypes, DW_ABRV_PTRTYPE, name);
+ s = decodetype_ptrelem(gotype);
+ newrefattr(die, DW_AT_type, defgotype(s));
+ break;
+
+ case KindSlice:
+ die = newdie(&dwtypes, DW_ABRV_SLICETYPE, name);
+ newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
+ s = decodetype_arrayelem(gotype);
+ newrefattr(die, DW_AT_internal_elem_type, defgotype(s));
+ break;
+
+ case KindString:
+ die = newdie(&dwtypes, DW_ABRV_STRINGTYPE, name);
+ newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
+ break;
+
+ case KindStruct:
+ die = newdie(&dwtypes, DW_ABRV_STRUCTTYPE, name);
+ newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
+ nfields = decodetype_structfieldcount(gotype);
+ for (i = 0; i < nfields; i++) {
+ f = decodetype_structfieldname(gotype, i);
+ s = decodetype_structfieldtype(gotype, i);
+ if (f == nil)
+ f = s->name + 5; // skip "type."
+ fld = newdie(die, DW_ABRV_STRUCTFIELD, f);
+ newrefattr(fld, DW_AT_type, defgotype(s));
+ newmemberoffsetattr(fld, decodetype_structfieldoffs(gotype, i));
+ }
+ break;
+
+ case KindUnsafePointer:
+ die = newdie(&dwtypes, DW_ABRV_PTRTYPE, name);
+ newrefattr(die, DW_AT_type, find(&dwtypes, "void"));
+ break;
+
+ default:
+ diag("definition of unknown kind %d: %s", kind, gotype->name);
+ die = newdie(&dwtypes, DW_ABRV_TYPEDECL, name);
+ newrefattr(die, DW_AT_type, find_or_diag(&dwtypes, "<unspecified>"));
+ }
+
+ return die;
+}
+
+// Find or construct *T given T.
+static DWDie*
+defptrto(DWDie *dwtype)
+{
+ char ptrname[1024];
+ DWDie *die;
+
+ snprint(ptrname, sizeof ptrname, "*%s", getattr(dwtype, DW_AT_name)->data);
+ die = find(&dwtypes, ptrname);
+ if (die == nil) {
+ die = newdie(&dwtypes, DW_ABRV_PTRTYPE,
+ strcpy(mal(strlen(ptrname)+1), ptrname));
+ newrefattr(die, DW_AT_type, dwtype);
+ }
+ return die;
+}
+
+// Copies src's children into dst. Copies attributes by value.
+// DWAttr.data is copied as pointer only.
+static void
+copychildren(DWDie *dst, DWDie *src)
+{
+ DWDie *c;
+ DWAttr *a;
+
+ for (src = src->child; src != nil; src = src->link) {
+ c = newdie(dst, src->abbrev, getattr(src, DW_AT_name)->data);
+ for (a = src->attr; a != nil; a = a->link)
+ newattr(c, a->atr, a->cls, a->value, a->data);
+ copychildren(c, src);
+ }
+ reverselist(&dst->child);
+}
+
+// Search children (assumed to have DW_TAG_member) for the one named
+// field and set it's DW_AT_type to dwtype
+static void
+substitutetype(DWDie *structdie, char *field, DWDie* dwtype)
+{
+ DWDie *child;
+ DWAttr *a;
+
+ child = find_or_diag(structdie, field);
+ if (child == nil)
+ return;
+
+ a = getattr(child, DW_AT_type);
+ if (a != nil)
+ a->data = (char*) dwtype;
+ else
+ newrefattr(child, DW_AT_type, dwtype);
+}
+
+static void
+synthesizestringtypes(DWDie* die)
+{
+ DWDie *prototype;
+
+ prototype = defgotype(lookup("type.runtime.string_", 0));
+ if (prototype == nil)
+ return;
+
+ for (; die != nil; die = die->link) {
+ if (die->abbrev != DW_ABRV_STRINGTYPE)
+ continue;
+ copychildren(die, prototype);
+ }
+}
+
+static void
+synthesizeslicetypes(DWDie *die)
+{
+ DWDie *prototype, *elem;
+
+ prototype = defgotype(lookup("type.runtime.slice",0));
+ if (prototype == nil)
+ return;
+
+ for (; die != nil; die = die->link) {
+ if (die->abbrev != DW_ABRV_SLICETYPE)
+ continue;
+ copychildren(die, prototype);
+ elem = (DWDie*) getattr(die, DW_AT_internal_elem_type)->data;
+ substitutetype(die, "array", defptrto(elem));
+ }
+}
+
+static char*
+mkinternaltypename(char *base, char *arg1, char *arg2)
+{
+ char buf[1024];
+ char *n;
+
+ if (arg2 == nil)
+ snprint(buf, sizeof buf, "%s<%s>", base, arg1);
+ else
+ snprint(buf, sizeof buf, "%s<%s,%s>", base, arg1, arg2);
+ n = mal(strlen(buf) + 1);
+ memmove(n, buf, strlen(buf));
+ return n;
+}
+
+
+// synthesizemaptypes is way too closely married to runtime/hashmap.c
+enum {
+ MaxValsize = 256 - 64
+};
+
+static void
+synthesizemaptypes(DWDie *die)
+{
+
+ DWDie *hash, *hash_subtable, *hash_entry,
+ *dwh, *dwhs, *dwhe, *keytype, *valtype, *fld;
+ int hashsize, keysize, valsize, datsize, valsize_in_hash, datavo;
+ DWAttr *a;
+
+ hash = defgotype(lookup("type.runtime.hash",0));
+ hash_subtable = defgotype(lookup("type.runtime.hash_subtable",0));
+ hash_entry = defgotype(lookup("type.runtime.hash_entry",0));
+
+ if (hash == nil || hash_subtable == nil || hash_entry == nil)
+ return;
+
+ dwh = (DWDie*)getattr(find_or_diag(hash_entry, "hash"), DW_AT_type)->data;
+ if (dwh == nil)
+ return;
+
+ hashsize = getattr(dwh, DW_AT_byte_size)->value;
+
+ for (; die != nil; die = die->link) {
+ if (die->abbrev != DW_ABRV_MAPTYPE)
+ continue;
+
+ keytype = (DWDie*) getattr(die, DW_AT_internal_key_type)->data;
+ valtype = (DWDie*) getattr(die, DW_AT_internal_val_type)->data;
+
+ a = getattr(keytype, DW_AT_byte_size);
+ keysize = a ? a->value : PtrSize; // We don't store size with Pointers
+
+ a = getattr(valtype, DW_AT_byte_size);
+ valsize = a ? a->value : PtrSize;
+
+ // This is what happens in hash_init and makemap_c
+ valsize_in_hash = valsize;
+ if (valsize > MaxValsize)
+ valsize_in_hash = PtrSize;
+ datavo = keysize;
+ if (valsize_in_hash >= PtrSize)
+ datavo = rnd(keysize, PtrSize);
+ datsize = datavo + valsize_in_hash;
+ if (datsize < PtrSize)
+ datsize = PtrSize;
+ datsize = rnd(datsize, PtrSize);
+
+ // Construct struct hash_entry<K,V>
+ dwhe = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
+ mkinternaltypename("hash_entry",
+ getattr(keytype, DW_AT_name)->data,
+ getattr(valtype, DW_AT_name)->data));
+ copychildren(dwhe, hash_entry);
+ substitutetype(dwhe, "key", keytype);
+ if (valsize > MaxValsize)
+ valtype = defptrto(valtype);
+ substitutetype(dwhe, "val", valtype);
+ fld = find_or_diag(dwhe, "val");
+ delattr(fld, DW_AT_data_member_location);
+ newmemberoffsetattr(fld, hashsize + datavo);
+ newattr(dwhe, DW_AT_byte_size, DW_CLS_CONSTANT, hashsize + datsize, NULL);
+
+ // Construct hash_subtable<hash_entry<K,V>>
+ dwhs = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
+ mkinternaltypename("hash_subtable",
+ getattr(keytype, DW_AT_name)->data,
+ getattr(valtype, DW_AT_name)->data));
+ copychildren(dwhs, hash_subtable);
+ substitutetype(dwhs, "end", defptrto(dwhe));
+ substitutetype(dwhs, "entry", dwhe); // todo: []hash_entry with dynamic size
+ newattr(dwhs, DW_AT_byte_size, DW_CLS_CONSTANT,
+ getattr(hash_subtable, DW_AT_byte_size)->value, NULL);
+
+ // Construct hash<K,V>
+ dwh = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
+ mkinternaltypename("hash",
+ getattr(keytype, DW_AT_name)->data,
+ getattr(valtype, DW_AT_name)->data));
+ copychildren(dwh, hash);
+ substitutetype(dwh, "st", defptrto(dwhs));
+ newattr(dwh, DW_AT_byte_size, DW_CLS_CONSTANT,
+ getattr(hash, DW_AT_byte_size)->value, NULL);
+
+ newrefattr(die, DW_AT_type, defptrto(dwh));
+ }
+}
+
+static void
+synthesizechantypes(DWDie *die)
+{
+ DWDie *sudog, *waitq, *link, *hchan,
+ *dws, *dww, *dwl, *dwh, *elemtype;
+ DWAttr *a;
+ int elemsize, linksize, sudogsize;
+
+ sudog = defgotype(lookup("type.runtime.sudoG",0));
+ waitq = defgotype(lookup("type.runtime.waitQ",0));
+ link = defgotype(lookup("type.runtime.link",0));
+ hchan = defgotype(lookup("type.runtime.hChan",0));
+ if (sudog == nil || waitq == nil || link == nil || hchan == nil)
+ return;
+
+ sudogsize = getattr(sudog, DW_AT_byte_size)->value;
+ linksize = getattr(link, DW_AT_byte_size)->value;
+
+ for (; die != nil; die = die->link) {
+ if (die->abbrev != DW_ABRV_CHANTYPE)
+ continue;
+ elemtype = (DWDie*) getattr(die, DW_AT_internal_elem_type)->data;
+ a = getattr(elemtype, DW_AT_byte_size);
+ elemsize = a ? a->value : PtrSize;
+
+ // sudog<T>
+ dws = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
+ mkinternaltypename("sudog",
+ getattr(elemtype, DW_AT_name)->data, NULL));
+ copychildren(dws, sudog);
+ substitutetype(dws, "elem", elemtype);
+ newattr(dws, DW_AT_byte_size, DW_CLS_CONSTANT,
+ sudogsize + (elemsize > 8 ? elemsize - 8 : 0), NULL);
+
+ // waitq<T>
+ dww = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
+ mkinternaltypename("waitq", getattr(elemtype, DW_AT_name)->data, NULL));
+ copychildren(dww, waitq);
+ substitutetype(dww, "first", defptrto(dws));
+ substitutetype(dww, "last", defptrto(dws));
+ newattr(dww, DW_AT_byte_size, DW_CLS_CONSTANT,
+ getattr(waitq, DW_AT_byte_size)->value, NULL);
+
+ // link<T>
+ dwl = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
+ mkinternaltypename("link", getattr(elemtype, DW_AT_name)->data, NULL));
+ copychildren(dwl, link);
+ substitutetype(dwl, "link", defptrto(dwl));
+ substitutetype(dwl, "elem", elemtype);
+ newattr(dwl, DW_AT_byte_size, DW_CLS_CONSTANT,
+ linksize + (elemsize > 8 ? elemsize - 8 : 0), NULL);
+
+ // hchan<T>
+ dwh = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
+ mkinternaltypename("hchan", getattr(elemtype, DW_AT_name)->data, NULL));
+ copychildren(dwh, hchan);
+ substitutetype(dwh, "senddataq", defptrto(dwl));
+ substitutetype(dwh, "recvdataq", defptrto(dwl));
+ substitutetype(dwh, "recvq", dww);
+ substitutetype(dwh, "sendq", dww);
+ substitutetype(dwh, "free", dws);
+ newattr(dwh, DW_AT_byte_size, DW_CLS_CONSTANT,
+ getattr(hchan, DW_AT_byte_size)->value, NULL);
+
+ newrefattr(die, DW_AT_type, defptrto(dwh));
+ }
+}
+
+// For use with pass.c::genasmsym
+static void
+defdwsymb(Sym* sym, char *s, int t, vlong v, vlong size, int ver, Sym *gotype)
+{
+ DWDie *dv, *dt;
+
+ if (strncmp(s, "go.string.", 10) == 0)
+ return;
+ if (strncmp(s, "string.", 7) == 0)
+ return;
+ if (strncmp(s, "type._.", 7) == 0)
+ return;
+
+ if (strncmp(s, "type.", 5) == 0) {
+ defgotype(sym);
+ return;
+ }
+
+ dv = nil;
+
+ switch (t) {
+ default:
+ return;
+ case 'd':
+ case 'b':
+ case 'D':
+ case 'B':
+ dv = newdie(&dwglobals, DW_ABRV_VARIABLE, s);
+ newabslocexprattr(dv, v);
+ if (ver == 0)
+ newattr(dv, DW_AT_external, DW_CLS_FLAG, 1, 0);
+ // fallthrough
+ case 'a':
+ case 'p':
+ dt = defgotype(gotype);
+ }
+
+ if (dv != nil)
+ newrefattr(dv, DW_AT_type, dt);
+}
+
+// TODO(lvd) For now, just append them all to the first compilation
+// unit (that should be main), in the future distribute them to the
+// appropriate compilation units.
+static void
+movetomodule(DWDie *parent)
+{
+ DWDie *die;
+
+ for (die = dwroot.child->child; die->link != nil; die = die->link) /* nix */;
+ die->link = parent->child;
+}
+
+/*
+ * Filename fragments for the line history stack.
+ */
+
+static char **ftab;
+static int ftabsize;
+
+void
+dwarfaddfrag(int n, char *frag)
+{
+ int s;
+
+ if (n >= ftabsize) {
+ s = ftabsize;
+ ftabsize = 1 + n + (n >> 2);
+ ftab = realloc(ftab, ftabsize * sizeof(ftab[0]));
+ memset(ftab + s, 0, (ftabsize - s) * sizeof(ftab[0]));
+ }
+
+ if (*frag == '<')
+ frag++;
+ ftab[n] = frag;
+}
+
+// Returns a malloc'ed string, piecewise copied from the ftab.
+static char *
+decodez(char *s)
+{
+ int len, o;
+ char *ss, *f;
+ char *r, *rb, *re;
+
+ len = 0;
+ ss = s + 1; // first is 0
+ while((o = ((uint8)ss[0] << 8) | (uint8)ss[1]) != 0) {
+ if (o < 0 || o >= ftabsize) {
+ diag("corrupt z entry");
+ return 0;
+ }
+ f = ftab[o];
+ if (f == nil) {
+ diag("corrupt z entry");
+ return 0;
+ }
+ len += strlen(f) + 1; // for the '/'
+ ss += 2;
+ }
+
+ if (len == 0)
+ return 0;
+
+ r = malloc(len + 1);
+ rb = r;
+ re = rb + len + 1;
+
+ s++;
+ while((o = ((uint8)s[0] << 8) | (uint8)s[1]) != 0) {
+ f = ftab[o];
+ if (rb == r || rb[-1] == '/')
+ rb = seprint(rb, re, "%s", f);
+ else
+ rb = seprint(rb, re, "/%s", f);
+ s += 2;
+ }
+ return r;
+}
+
+/*
+ * The line history itself
+ */
+
+static char **histfile; // [0] holds "<eof>", DW_LNS_set_file arguments must be > 0.
+static int histfilesize;
+static int histfilecap;
+
+static void
+clearhistfile(void)
+{
+ int i;
+
+ // [0] holds "<eof>"
+ for (i = 1; i < histfilesize; i++)
+ free(histfile[i]);
+ histfilesize = 0;
+}
+
+static int
+addhistfile(char *zentry)
+{
+ char *fname;
+
+ if (histfilesize == histfilecap) {
+ histfilecap = 2 * histfilecap + 2;
+ histfile = realloc(histfile, histfilecap * sizeof(char*));
+ }
+ if (histfilesize == 0)
+ histfile[histfilesize++] = "<eof>";
+
+ fname = decodez(zentry);
+ if (fname == 0)
+ return -1;
+ // Don't fill with duplicates (check only top one).
+ if (strcmp(fname, histfile[histfilesize-1]) == 0) {
+ free(fname);
+ return histfilesize - 1;
+ }
+ histfile[histfilesize++] = fname;
+ return histfilesize - 1;
+}
+
+// if the histfile stack contains ..../runtime/runtime_defs.go
+// use that to set gdbscript
+static void
+finddebugruntimepath()
+{
+ int i, l;
+ char *c;
+
+ for (i = 1; i < histfilesize; i++) {
+ if ((c = strstr(histfile[i], "runtime/runtime_defs.go")) != nil) {
+ l = c - histfile[i];
+ memmove(gdbscript, histfile[i], l);
+ memmove(gdbscript + l, "runtime/runtime-gdb.py", strlen("runtime/runtime-gdb.py") + 1);
+ break;
+ }
+ }
+}
+
+// Go's runtime C sources are sane, and Go sources nest only 1 level,
+// so 16 should be plenty.
+static struct {
+ int file;
+ vlong line;
+} includestack[16];
+static int includetop;
+static vlong absline;
+
+typedef struct Linehist Linehist;
+struct Linehist {
+ Linehist *link;
+ vlong absline;
+ vlong line;
+ int file;
+};
+
+static Linehist *linehist;
+
+static void
+checknesting(void)
+{
+ int i;
+
+ if (includetop < 0) {
+ diag("corrupt z stack");
+ errorexit();
+ }
+ if (includetop >= nelem(includestack)) {
+ diag("nesting too deep");
+ for (i = 0; i < nelem(includestack); i++)
+ diag("\t%s", histfile[includestack[i].file]);
+ errorexit();
+ }
+}
+
+/*
+ * Return false if the a->link chain contains no history, otherwise
+ * returns true and finds z and Z entries in the Auto list (of a
+ * Prog), and resets the history stack
+ */
+static int
+inithist(Auto *a)
+{
+ Linehist *lh;
+
+ for (; a; a = a->link)
+ if (a->type == D_FILE)
+ break;
+ if (a==nil)
+ return 0;
+
+ // We have a new history. They are guaranteed to come completely
+ // at the beginning of the compilation unit.
+ if (a->aoffset != 1) {
+ diag("stray 'z' with offset %d", a->aoffset);
+ return 0;
+ }
+
+ // Clear the history.
+ clearhistfile();
+ includetop = 0;
+ includestack[includetop].file = 0;
+ includestack[includetop].line = -1;
+ absline = 0;
+ while (linehist != nil) {
+ lh = linehist->link;
+ free(linehist);
+ linehist = lh;
+ }
+
+ // Construct the new one.
+ for (; a; a = a->link) {
+ if (a->type == D_FILE) { // 'z'
+ int f = addhistfile(a->asym->name);
+ if (f < 0) { // pop file
+ includetop--;
+ checknesting();
+ } else if(f != includestack[includetop].file) { // pushed a new file
+ includestack[includetop].line += a->aoffset - absline;
+ includetop++;
+ checknesting();
+ includestack[includetop].file = f;
+ includestack[includetop].line = 1;
+ }
+ absline = a->aoffset;
+ } else if (a->type == D_FILE1) { // 'Z'
+ // We could just fixup the current
+ // linehist->line, but there doesn't appear to
+ // be a guarantee that every 'Z' is preceded
+ // by it's own 'z', so do the safe thing and
+ // update the stack and push a new Linehist
+ // entry
+ includestack[includetop].line = a->aoffset;
+ } else
+ continue;
+ if (linehist == 0 || linehist->absline != absline) {
+ Linehist* lh = malloc(sizeof *lh);
+ lh->link = linehist;
+ lh->absline = absline;
+ linehist = lh;
+ }
+ linehist->file = includestack[includetop].file;
+ linehist->line = includestack[includetop].line;
+ }
+ return 1;
+}
+
+static Linehist *
+searchhist(vlong absline)
+{
+ Linehist *lh;
+
+ for (lh = linehist; lh; lh = lh->link)
+ if (lh->absline <= absline)
+ break;
+ return lh;
+}
+
+static int
+guesslang(char *s)
+{
+ if(strlen(s) >= 3 && strcmp(s+strlen(s)-3, ".go") == 0)
+ return DW_LANG_Go;
+
+ return DW_LANG_C;
+}
+
+/*
+ * Generate short opcodes when possible, long ones when neccesary.
+ * See section 6.2.5
+ */
+
+enum {
+ LINE_BASE = -1,
+ LINE_RANGE = 4,
+ OPCODE_BASE = 5
+};
+
+static void
+putpclcdelta(vlong delta_pc, vlong delta_lc)
+{
+ if (LINE_BASE <= delta_lc && delta_lc < LINE_BASE+LINE_RANGE) {
+ vlong opcode = OPCODE_BASE + (delta_lc - LINE_BASE) + (LINE_RANGE * delta_pc);
+ if (OPCODE_BASE <= opcode && opcode < 256) {
+ cput(opcode);
+ return;
+ }
+ }
+
+ if (delta_pc) {
+ cput(DW_LNS_advance_pc);
+ sleb128put(delta_pc);
+ }
+
+ cput(DW_LNS_advance_line);
+ sleb128put(delta_lc);
+ cput(DW_LNS_copy);
+}
+
+static void
+newcfaoffsetattr(DWDie *die, int32 offs)
+{
+ char block[10];
+ int i;
+
+ i = 0;
+
+ block[i++] = DW_OP_call_frame_cfa;
+ if (offs != 0) {
+ block[i++] = DW_OP_consts;
+ i += sleb128enc(offs, block+i);
+ block[i++] = DW_OP_plus;
+ }
+ newattr(die, DW_AT_location, DW_CLS_BLOCK, i, mal(i));
+ memmove(die->attr->data, block, i);
+}
+
+static char*
+mkvarname(char* name, int da)
+{
+ char buf[1024];
+ char *n;
+
+ snprint(buf, sizeof buf, "%s#%d", name, da);
+ n = mal(strlen(buf) + 1);
+ memmove(n, buf, strlen(buf));
+ return n;
+}
+
+/*
+ * Walk prog table, emit line program and build DIE tree.
+ */
+
+// flush previous compilation unit.
+static void
+flushunit(DWDie *dwinfo, vlong pc, vlong unitstart)
+{
+ vlong here;
+
+ if (dwinfo != nil && pc != 0) {
+ newattr(dwinfo, DW_AT_high_pc, DW_CLS_ADDRESS, pc+1, 0);
+ }
+
+ if (unitstart >= 0) {
+ cput(0); // start extended opcode
+ uleb128put(1);
+ cput(DW_LNE_end_sequence);
+ cflush();
+
+ here = cpos();
+ seek(cout, unitstart, 0);
+ LPUT(here - unitstart - sizeof(int32));
+ cflush();
+ seek(cout, here, 0);
+ }
+}
+
+static void
+writelines(void)
+{
+ Prog *q;
+ Sym *s;
+ Auto *a;
+ vlong unitstart, offs;
+ vlong pc, epc, lc, llc, lline;
+ int currfile;
+ int i, lang, da, dt;
+ Linehist *lh;
+ DWDie *dwinfo, *dwfunc, *dwvar, **dws;
+ DWDie *varhash[HASHSIZE];
+ char *n, *nn;
+
+ unitstart = -1;
+ epc = pc = 0;
+ lc = 1;
+ llc = 1;
+ currfile = -1;
+ lineo = cpos();
+ dwinfo = nil;
+
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ s = cursym;
+ if(s->text == P)
+ continue;
+
+ // Look for history stack. If we find one,
+ // we're entering a new compilation unit
+
+ if (inithist(s->autom)) {
+ flushunit(dwinfo, epc, unitstart);
+ unitstart = cpos();
+
+ if(debug['v'] > 1) {
+ print("dwarf writelines found %s\n", histfile[1]);
+ Linehist* lh;
+ for (lh = linehist; lh; lh = lh->link)
+ print("\t%8lld: [%4lld]%s\n",
+ lh->absline, lh->line, histfile[lh->file]);
+ }
+
+ lang = guesslang(histfile[1]);
+ finddebugruntimepath();
+
+ dwinfo = newdie(&dwroot, DW_ABRV_COMPUNIT, strdup(histfile[1]));
+ newattr(dwinfo, DW_AT_language, DW_CLS_CONSTANT,lang, 0);
+ newattr(dwinfo, DW_AT_stmt_list, DW_CLS_PTR, unitstart - lineo, 0);
+ newattr(dwinfo, DW_AT_low_pc, DW_CLS_ADDRESS, s->text->pc, 0);
+
+ // Write .debug_line Line Number Program Header (sec 6.2.4)
+ // Fields marked with (*) must be changed for 64-bit dwarf
+ LPUT(0); // unit_length (*), will be filled in later.
+ WPUT(3); // dwarf version (appendix F)
+ LPUT(11); // header_length (*), starting here.
+
+ cput(1); // minimum_instruction_length
+ cput(1); // default_is_stmt
+ cput(LINE_BASE); // line_base
+ cput(LINE_RANGE); // line_range
+ cput(OPCODE_BASE); // opcode_base (we only use 1..4)
+ cput(0); // standard_opcode_lengths[1]
+ cput(1); // standard_opcode_lengths[2]
+ cput(1); // standard_opcode_lengths[3]
+ cput(1); // standard_opcode_lengths[4]
+ cput(0); // include_directories (empty)
+ cput(0); // file_names (empty) (emitted by DW_LNE's below)
+ // header_length ends here.
+
+ for (i=1; i < histfilesize; i++) {
+ cput(0); // start extended opcode
+ uleb128put(1 + strlen(histfile[i]) + 4);
+ cput(DW_LNE_define_file);
+ strnput(histfile[i], strlen(histfile[i]) + 4);
+ // 4 zeros: the string termination + 3 fields.
+ }
+
+ epc = pc = s->text->pc;
+ currfile = 1;
+ lc = 1;
+ llc = 1;
+
+ cput(0); // start extended opcode
+ uleb128put(1 + PtrSize);
+ cput(DW_LNE_set_address);
+ addrput(pc);
+ }
+ if(s->text == nil)
+ continue;
+
+ if (unitstart < 0) {
+ diag("reachable code before seeing any history: %P", s->text);
+ continue;
+ }
+
+ dwfunc = newdie(dwinfo, DW_ABRV_FUNCTION, s->name);
+ newattr(dwfunc, DW_AT_low_pc, DW_CLS_ADDRESS, s->value, 0);
+ epc = s->value + s->size;
+ newattr(dwfunc, DW_AT_high_pc, DW_CLS_ADDRESS, epc, 0);
+ if (s->version == 0)
+ newattr(dwfunc, DW_AT_external, DW_CLS_FLAG, 1, 0);
+
+ if(s->text->link == nil)
+ continue;
+
+ for(q = s->text; q != P; q = q->link) {
+ lh = searchhist(q->line);
+ if (lh == nil) {
+ diag("corrupt history or bad absolute line: %P", q);
+ continue;
+ }
+
+ if (lh->file < 1) { // 0 is the past-EOF entry.
+ // diag("instruction with line number past EOF in %s: %P", histfile[1], q);
+ continue;
+ }
+
+ lline = lh->line + q->line - lh->absline;
+ if (debug['v'] > 1)
+ print("%6llux %s[%lld] %P\n", (vlong)q->pc, histfile[lh->file], lline, q);
+
+ if (q->line == lc)
+ continue;
+ if (currfile != lh->file) {
+ currfile = lh->file;
+ cput(DW_LNS_set_file);
+ uleb128put(currfile);
+ }
+ putpclcdelta(q->pc - pc, lline - llc);
+ pc = q->pc;
+ lc = q->line;
+ llc = lline;
+ }
+
+ da = 0;
+ dwfunc->hash = varhash; // enable indexing of children by name
+ memset(varhash, 0, sizeof varhash);
+ for(a = s->autom; a; a = a->link) {
+ switch (a->type) {
+ case D_AUTO:
+ dt = DW_ABRV_AUTO;
+ offs = a->aoffset - PtrSize;
+ break;
+ case D_PARAM:
+ dt = DW_ABRV_PARAM;
+ offs = a->aoffset;
+ break;
+ default:
+ continue;
+ }
+ if (strstr(a->asym->name, ".autotmp_"))
+ continue;
+ if (find(dwfunc, a->asym->name) != nil)
+ n = mkvarname(a->asym->name, da);
+ else
+ n = a->asym->name;
+ // Drop the package prefix from locals and arguments.
+ nn = strrchr(n, '.');
+ if (nn)
+ n = nn + 1;
+
+ dwvar = newdie(dwfunc, dt, n);
+ newcfaoffsetattr(dwvar, offs);
+ newrefattr(dwvar, DW_AT_type, defgotype(a->gotype));
+
+ // push dwvar down dwfunc->child to preserve order
+ newattr(dwvar, DW_AT_internal_location, DW_CLS_CONSTANT, offs, NULL);
+ dwfunc->child = dwvar->link; // take dwvar out from the top of the list
+ for (dws = &dwfunc->child; *dws != nil; dws = &(*dws)->link)
+ if (offs > getattr(*dws, DW_AT_internal_location)->value)
+ break;
+ dwvar->link = *dws;
+ *dws = dwvar;
+
+ da++;
+ }
+
+ dwfunc->hash = nil;
+ }
+
+ flushunit(dwinfo, epc, unitstart);
+ linesize = cpos() - lineo;
+}
+
+/*
+ * Emit .debug_frame
+ */
+enum
+{
+ CIERESERVE = 16,
+ DATAALIGNMENTFACTOR = -4, // TODO -PtrSize?
+ FAKERETURNCOLUMN = 16 // TODO gdb6 doesnt like > 15?
+};
+
+static void
+putpccfadelta(vlong deltapc, vlong cfa)
+{
+ if (deltapc < 0x40) {
+ cput(DW_CFA_advance_loc + deltapc);
+ } else if (deltapc < 0x100) {
+ cput(DW_CFA_advance_loc1);
+ cput(deltapc);
+ } else if (deltapc < 0x10000) {
+ cput(DW_CFA_advance_loc2);
+ WPUT(deltapc);
+ } else {
+ cput(DW_CFA_advance_loc4);
+ LPUT(deltapc);
+ }
+
+ cput(DW_CFA_def_cfa_offset_sf);
+ sleb128put(cfa / DATAALIGNMENTFACTOR);
+}
+
+static void
+writeframes(void)
+{
+ Prog *p, *q;
+ Sym *s;
+ vlong fdeo, fdesize, pad, cfa, pc;
+
+ frameo = cpos();
+
+ // Emit the CIE, Section 6.4.1
+ LPUT(CIERESERVE); // initial length, must be multiple of PtrSize
+ LPUT(0xffffffff); // cid.
+ cput(3); // dwarf version (appendix F)
+ cput(0); // augmentation ""
+ uleb128put(1); // code_alignment_factor
+ sleb128put(DATAALIGNMENTFACTOR); // guess
+ uleb128put(FAKERETURNCOLUMN); // return_address_register
+
+ cput(DW_CFA_def_cfa);
+ uleb128put(DWARFREGSP); // register SP (**ABI-dependent, defined in l.h)
+ uleb128put(PtrSize); // offset
+
+ cput(DW_CFA_offset + FAKERETURNCOLUMN); // return address
+ uleb128put(-PtrSize / DATAALIGNMENTFACTOR); // at cfa - x*4
+
+ // 4 is to exclude the length field.
+ pad = CIERESERVE + frameo + 4 - cpos();
+ if (pad < 0) {
+ diag("CIERESERVE too small by %lld bytes.", -pad);
+ errorexit();
+ }
+ strnput("", pad);
+
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ s = cursym;
+ if(s->text == nil)
+ continue;
+
+ fdeo = cpos();
+ // Emit a FDE, Section 6.4.1, starting wit a placeholder.
+ LPUT(0); // length, must be multiple of PtrSize
+ LPUT(0); // Pointer to the CIE above, at offset 0
+ addrput(0); // initial location
+ addrput(0); // address range
+
+ cfa = PtrSize; // CFA starts at sp+PtrSize
+ p = s->text;
+ pc = p->pc;
+
+ for(q = p; q->link != P; q = q->link) {
+ if (q->spadj == 0)
+ continue;
+ cfa += q->spadj;
+ putpccfadelta(q->link->pc - pc, cfa);
+ pc = q->link->pc;
+ }
+
+ fdesize = cpos() - fdeo - 4; // exclude the length field.
+ pad = rnd(fdesize, PtrSize) - fdesize;
+ strnput("", pad);
+ fdesize += pad;
+ cflush();
+
+ // Emit the FDE header for real, Section 6.4.1.
+ seek(cout, fdeo, 0);
+ LPUT(fdesize);
+ LPUT(0);
+ addrput(p->pc);
+ addrput(s->size);
+
+ cflush();
+ seek(cout, fdeo + 4 + fdesize, 0);
+ }
+
+ cflush();
+ framesize = cpos() - frameo;
+}
+
+/*
+ * Walk DWarfDebugInfoEntries, and emit .debug_info
+ */
+enum
+{
+ COMPUNITHEADERSIZE = 4+2+4+1
+};
+
+static void
+writeinfo(void)
+{
+ DWDie *compunit;
+ vlong unitstart, here;
+
+ fwdcount = 0;
+
+ for (compunit = dwroot.child; compunit; compunit = compunit->link) {
+ unitstart = cpos();
+
+ // Write .debug_info Compilation Unit Header (sec 7.5.1)
+ // Fields marked with (*) must be changed for 64-bit dwarf
+ // This must match COMPUNITHEADERSIZE above.
+ LPUT(0); // unit_length (*), will be filled in later.
+ WPUT(3); // dwarf version (appendix F)
+ LPUT(0); // debug_abbrev_offset (*)
+ cput(PtrSize); // address_size
+
+ putdie(compunit);
+
+ cflush();
+ here = cpos();
+ seek(cout, unitstart, 0);
+ LPUT(here - unitstart - 4); // exclude the length field.
+ cflush();
+ seek(cout, here, 0);
+ }
+
+}
+
+/*
+ * Emit .debug_pubnames/_types. _info must have been written before,
+ * because we need die->offs and infoo/infosize;
+ */
+static int
+ispubname(DWDie *die) {
+ DWAttr *a;
+
+ switch(die->abbrev) {
+ case DW_ABRV_FUNCTION:
+ case DW_ABRV_VARIABLE:
+ a = getattr(die, DW_AT_external);
+ return a && a->value;
+ }
+ return 0;
+}
+
+static int
+ispubtype(DWDie *die) {
+ return die->abbrev >= DW_ABRV_NULLTYPE;
+}
+
+static vlong
+writepub(int (*ispub)(DWDie*))
+{
+ DWDie *compunit, *die;
+ DWAttr *dwa;
+ vlong unitstart, unitend, sectionstart, here;
+
+ sectionstart = cpos();
+
+ for (compunit = dwroot.child; compunit != nil; compunit = compunit->link) {
+ unitstart = compunit->offs - COMPUNITHEADERSIZE;
+ if (compunit->link != nil)
+ unitend = compunit->link->offs - COMPUNITHEADERSIZE;
+ else
+ unitend = infoo + infosize;
+
+ // Write .debug_pubnames/types Header (sec 6.1.1)
+ LPUT(0); // unit_length (*), will be filled in later.
+ WPUT(2); // dwarf version (appendix F)
+ LPUT(unitstart); // debug_info_offset (of the Comp unit Header)
+ LPUT(unitend - unitstart); // debug_info_length
+
+ for (die = compunit->child; die != nil; die = die->link) {
+ if (!ispub(die)) continue;
+ LPUT(die->offs - unitstart);
+ dwa = getattr(die, DW_AT_name);
+ strnput(dwa->data, dwa->value + 1);
+ }
+ LPUT(0);
+
+ cflush();
+ here = cpos();
+ seek(cout, sectionstart, 0);
+ LPUT(here - sectionstart - 4); // exclude the length field.
+ cflush();
+ seek(cout, here, 0);
+
+ }
+
+ return sectionstart;
+}
+
+/*
+ * emit .debug_aranges. _info must have been written before,
+ * because we need die->offs of dw_globals.
+ */
+static vlong
+writearanges(void)
+{
+ DWDie *compunit;
+ DWAttr *b, *e;
+ int headersize;
+ vlong sectionstart;
+
+ sectionstart = cpos();
+ headersize = rnd(4+2+4+1+1, PtrSize); // don't count unit_length field itself
+
+ for (compunit = dwroot.child; compunit != nil; compunit = compunit->link) {
+ b = getattr(compunit, DW_AT_low_pc);
+ if (b == nil)
+ continue;
+ e = getattr(compunit, DW_AT_high_pc);
+ if (e == nil)
+ continue;
+
+ // Write .debug_aranges Header + entry (sec 6.1.2)
+ LPUT(headersize + 4*PtrSize - 4); // unit_length (*)
+ WPUT(2); // dwarf version (appendix F)
+ LPUT(compunit->offs - COMPUNITHEADERSIZE); // debug_info_offset
+ cput(PtrSize); // address_size
+ cput(0); // segment_size
+ strnput("", headersize - (4+2+4+1+1)); // align to PtrSize
+
+ addrput(b->value);
+ addrput(e->value - b->value);
+ addrput(0);
+ addrput(0);
+ }
+ cflush();
+ return sectionstart;
+}
+
+static vlong
+writegdbscript(void)
+{
+ vlong sectionstart;
+
+ sectionstart = cpos();
+
+ if (gdbscript[0]) {
+ cput(1); // magic 1 byte?
+ strnput(gdbscript, strlen(gdbscript)+1);
+ cflush();
+ }
+ return sectionstart;
+}
+
+/*
+ * This is the main entry point for generating dwarf. After emitting
+ * the mandatory debug_abbrev section, it calls writelines() to set up
+ * the per-compilation unit part of the DIE tree, while simultaneously
+ * emitting the debug_line section. When the final tree contains
+ * forward references, it will write the debug_info section in 2
+ * passes.
+ *
+ */
+void
+dwarfemitdebugsections(void)
+{
+ vlong infoe;
+ DWDie* die;
+
+ // For diagnostic messages.
+ newattr(&dwtypes, DW_AT_name, DW_CLS_STRING, strlen("dwtypes"), "dwtypes");
+
+ mkindex(&dwroot);
+ mkindex(&dwtypes);
+ mkindex(&dwglobals);
+
+ // Some types that must exist to define other ones.
+ newdie(&dwtypes, DW_ABRV_NULLTYPE, "<unspecified>");
+ newdie(&dwtypes, DW_ABRV_NULLTYPE, "void");
+ newrefattr(newdie(&dwtypes, DW_ABRV_PTRTYPE, "unsafe.Pointer"),
+ DW_AT_type, find(&dwtypes, "void"));
+ die = newdie(&dwtypes, DW_ABRV_BASETYPE, "uintptr"); // needed for array size
+ newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_unsigned, 0);
+ newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, PtrSize, 0);
+
+ // Needed by the prettyprinter code for interface inspection.
+ defgotype(lookup("type.runtime.commonType",0));
+ defgotype(lookup("type.runtime.InterfaceType",0));
+ defgotype(lookup("type.runtime.itab",0));
+
+ genasmsym(defdwsymb);
+
+ writeabbrev();
+ writelines();
+ writeframes();
+
+ synthesizestringtypes(dwtypes.child);
+ synthesizeslicetypes(dwtypes.child);
+ synthesizemaptypes(dwtypes.child);
+ synthesizechantypes(dwtypes.child);
+
+ reversetree(&dwroot.child);
+ reversetree(&dwtypes.child);
+ reversetree(&dwglobals.child);
+
+ movetomodule(&dwtypes);
+ movetomodule(&dwglobals);
+
+ infoo = cpos();
+ writeinfo();
+ gdbscripto = arangeso = pubtypeso = pubnameso = infoe = cpos();
+
+ if (fwdcount > 0) {
+ if (debug['v'])
+ Bprint(&bso, "%5.2f dwarf pass 2.\n", cputime());
+ seek(cout, infoo, 0);
+ writeinfo();
+ if (fwdcount > 0) {
+ diag("unresolved references after first dwarf info pass");
+ errorexit();
+ }
+ if (infoe != cpos()) {
+ diag("inconsistent second dwarf info pass");
+ errorexit();
+ }
+ }
+ infosize = infoe - infoo;
+
+ pubnameso = writepub(ispubname);
+ pubtypeso = writepub(ispubtype);
+ arangeso = writearanges();
+ gdbscripto = writegdbscript();
+
+ pubnamessize = pubtypeso - pubnameso;
+ pubtypessize = arangeso - pubtypeso;
+ arangessize = gdbscripto - arangeso;
+ gdbscriptsize = cpos() - gdbscripto;
+}
+
+/*
+ * Elf.
+ */
+enum
+{
+ ElfStrDebugAbbrev,
+ ElfStrDebugAranges,
+ ElfStrDebugFrame,
+ ElfStrDebugInfo,
+ ElfStrDebugLine,
+ ElfStrDebugLoc,
+ ElfStrDebugMacinfo,
+ ElfStrDebugPubNames,
+ ElfStrDebugPubTypes,
+ ElfStrDebugRanges,
+ ElfStrDebugStr,
+ ElfStrGDBScripts,
+ NElfStrDbg
+};
+
+vlong elfstrdbg[NElfStrDbg];
+
+void
+dwarfaddshstrings(Sym *shstrtab)
+{
+ elfstrdbg[ElfStrDebugAbbrev] = addstring(shstrtab, ".debug_abbrev");
+ elfstrdbg[ElfStrDebugAranges] = addstring(shstrtab, ".debug_aranges");
+ elfstrdbg[ElfStrDebugFrame] = addstring(shstrtab, ".debug_frame");
+ elfstrdbg[ElfStrDebugInfo] = addstring(shstrtab, ".debug_info");
+ elfstrdbg[ElfStrDebugLine] = addstring(shstrtab, ".debug_line");
+ elfstrdbg[ElfStrDebugLoc] = addstring(shstrtab, ".debug_loc");
+ elfstrdbg[ElfStrDebugMacinfo] = addstring(shstrtab, ".debug_macinfo");
+ elfstrdbg[ElfStrDebugPubNames] = addstring(shstrtab, ".debug_pubnames");
+ elfstrdbg[ElfStrDebugPubTypes] = addstring(shstrtab, ".debug_pubtypes");
+ elfstrdbg[ElfStrDebugRanges] = addstring(shstrtab, ".debug_ranges");
+ elfstrdbg[ElfStrDebugStr] = addstring(shstrtab, ".debug_str");
+ elfstrdbg[ElfStrGDBScripts] = addstring(shstrtab, ".debug_gdb_scripts");
+}
+
+void
+dwarfaddelfheaders(void)
+{
+ ElfShdr *sh;
+
+ sh = newElfShdr(elfstrdbg[ElfStrDebugAbbrev]);
+ sh->type = SHT_PROGBITS;
+ sh->off = abbrevo;
+ sh->size = abbrevsize;
+ sh->addralign = 1;
+
+ sh = newElfShdr(elfstrdbg[ElfStrDebugLine]);
+ sh->type = SHT_PROGBITS;
+ sh->off = lineo;
+ sh->size = linesize;
+ sh->addralign = 1;
+
+ sh = newElfShdr(elfstrdbg[ElfStrDebugFrame]);
+ sh->type = SHT_PROGBITS;
+ sh->off = frameo;
+ sh->size = framesize;
+ sh->addralign = 1;
+
+ sh = newElfShdr(elfstrdbg[ElfStrDebugInfo]);
+ sh->type = SHT_PROGBITS;
+ sh->off = infoo;
+ sh->size = infosize;
+ sh->addralign = 1;
+
+ if (pubnamessize > 0) {
+ sh = newElfShdr(elfstrdbg[ElfStrDebugPubNames]);
+ sh->type = SHT_PROGBITS;
+ sh->off = pubnameso;
+ sh->size = pubnamessize;
+ sh->addralign = 1;
+ }
+
+ if (pubtypessize > 0) {
+ sh = newElfShdr(elfstrdbg[ElfStrDebugPubTypes]);
+ sh->type = SHT_PROGBITS;
+ sh->off = pubtypeso;
+ sh->size = pubtypessize;
+ sh->addralign = 1;
+ }
+
+ if (arangessize) {
+ sh = newElfShdr(elfstrdbg[ElfStrDebugAranges]);
+ sh->type = SHT_PROGBITS;
+ sh->off = arangeso;
+ sh->size = arangessize;
+ sh->addralign = 1;
+ }
+
+ if (gdbscriptsize) {
+ sh = newElfShdr(elfstrdbg[ElfStrGDBScripts]);
+ sh->type = SHT_PROGBITS;
+ sh->off = gdbscripto;
+ sh->size = gdbscriptsize;
+ sh->addralign = 1;
+ }
+}
+
+/*
+ * Macho
+ */
+void
+dwarfaddmachoheaders(void)
+{
+ MachoSect *msect;
+ MachoSeg *ms;
+ vlong fakestart;
+ int nsect;
+
+ // Zero vsize segments won't be loaded in memory, even so they
+ // have to be page aligned in the file.
+ fakestart = abbrevo & ~0xfff;
+
+ nsect = 4;
+ if (pubnamessize > 0)
+ nsect++;
+ if (pubtypessize > 0)
+ nsect++;
+ if (arangessize > 0)
+ nsect++;
+ if (gdbscriptsize > 0)
+ nsect++;
+
+ ms = newMachoSeg("__DWARF", nsect);
+ ms->fileoffset = fakestart;
+ ms->filesize = abbrevo-fakestart;
+
+ msect = newMachoSect(ms, "__debug_abbrev");
+ msect->off = abbrevo;
+ msect->size = abbrevsize;
+ ms->filesize += msect->size;
+
+ msect = newMachoSect(ms, "__debug_line");
+ msect->off = lineo;
+ msect->size = linesize;
+ ms->filesize += msect->size;
+
+ msect = newMachoSect(ms, "__debug_frame");
+ msect->off = frameo;
+ msect->size = framesize;
+ ms->filesize += msect->size;
+
+ msect = newMachoSect(ms, "__debug_info");
+ msect->off = infoo;
+ msect->size = infosize;
+ ms->filesize += msect->size;
+
+ if (pubnamessize > 0) {
+ msect = newMachoSect(ms, "__debug_pubnames");
+ msect->off = pubnameso;
+ msect->size = pubnamessize;
+ ms->filesize += msect->size;
+ }
+
+ if (pubtypessize > 0) {
+ msect = newMachoSect(ms, "__debug_pubtypes");
+ msect->off = pubtypeso;
+ msect->size = pubtypessize;
+ ms->filesize += msect->size;
+ }
+
+ if (arangessize > 0) {
+ msect = newMachoSect(ms, "__debug_aranges");
+ msect->off = arangeso;
+ msect->size = arangessize;
+ ms->filesize += msect->size;
+ }
+
+ // TODO(lvd) fix gdb/python to load MachO (16 char section name limit)
+ if (gdbscriptsize > 0) {
+ msect = newMachoSect(ms, "__debug_gdb_scripts");
+ msect->off = gdbscripto;
+ msect->size = gdbscriptsize;
+ ms->filesize += msect->size;
+ }
+}
diff --git a/src/cmd/ld/dwarf.h b/src/cmd/ld/dwarf.h
new file mode 100644
index 000000000..7881213c2
--- /dev/null
+++ b/src/cmd/ld/dwarf.h
@@ -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.
+
+/*
+ * Register 'f' symbol file fragments. Doing this while parsing the
+ * .6 input saves a pass over the symbol table later.
+ */
+void dwarfaddfrag(int n, char* frag);
+
+/*
+ * Emit debug_abbrevs, debug_info and debug_line sections to current
+ * offset in cout.
+ */
+void dwarfemitdebugsections(void);
+
+/*
+ * Add the dwarf section names to the ELF
+ * s[ection]h[eader]str[ing]tab. Prerequisite for
+ * dwarfaddelfheaders().
+ */
+void dwarfaddshstrings(Sym *shstrtab);
+
+/*
+ * Add section headers pointing to the sections emitted in
+ * dwarfemitdebugsections.
+ */
+void dwarfaddelfheaders(void);
+void dwarfaddmachoheaders(void);
diff --git a/src/cmd/ld/dwarf_defs.h b/src/cmd/ld/dwarf_defs.h
new file mode 100644
index 000000000..eed143dff
--- /dev/null
+++ b/src/cmd/ld/dwarf_defs.h
@@ -0,0 +1,503 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Cut, pasted, tr-and-awk'ed from tables in
+// http://dwarfstd.org/doc/Dwarf3.pdf
+
+// Table 18
+enum
+{
+ DW_TAG_array_type = 0x01,
+ DW_TAG_class_type = 0x02,
+ DW_TAG_entry_point = 0x03,
+ DW_TAG_enumeration_type = 0x04,
+ DW_TAG_formal_parameter = 0x05,
+ DW_TAG_imported_declaration = 0x08,
+ DW_TAG_label = 0x0a,
+ DW_TAG_lexical_block = 0x0b,
+ DW_TAG_member = 0x0d,
+ DW_TAG_pointer_type = 0x0f,
+ DW_TAG_reference_type = 0x10,
+ DW_TAG_compile_unit = 0x11,
+ DW_TAG_string_type = 0x12,
+ DW_TAG_structure_type = 0x13,
+ DW_TAG_subroutine_type = 0x15,
+ DW_TAG_typedef = 0x16,
+ DW_TAG_union_type = 0x17,
+ DW_TAG_unspecified_parameters = 0x18,
+ DW_TAG_variant = 0x19,
+ DW_TAG_common_block = 0x1a,
+ DW_TAG_common_inclusion = 0x1b,
+ DW_TAG_inheritance = 0x1c,
+ DW_TAG_inlined_subroutine = 0x1d,
+ DW_TAG_module = 0x1e,
+ DW_TAG_ptr_to_member_type = 0x1f,
+ DW_TAG_set_type = 0x20,
+ DW_TAG_subrange_type = 0x21,
+ DW_TAG_with_stmt = 0x22,
+ DW_TAG_access_declaration = 0x23,
+ DW_TAG_base_type = 0x24,
+ DW_TAG_catch_block = 0x25,
+ DW_TAG_const_type = 0x26,
+ DW_TAG_constant = 0x27,
+ DW_TAG_enumerator = 0x28,
+ DW_TAG_file_type = 0x29,
+ DW_TAG_friend = 0x2a,
+ DW_TAG_namelist = 0x2b,
+ DW_TAG_namelist_item = 0x2c,
+ DW_TAG_packed_type = 0x2d,
+ DW_TAG_subprogram = 0x2e,
+ DW_TAG_template_type_parameter = 0x2f,
+ DW_TAG_template_value_parameter = 0x30,
+ DW_TAG_thrown_type = 0x31,
+ DW_TAG_try_block = 0x32,
+ DW_TAG_variant_part = 0x33,
+ DW_TAG_variable = 0x34,
+ DW_TAG_volatile_type = 0x35,
+ // Dwarf3
+ DW_TAG_dwarf_procedure = 0x36,
+ DW_TAG_restrict_type = 0x37,
+ DW_TAG_interface_type = 0x38,
+ DW_TAG_namespace = 0x39,
+ DW_TAG_imported_module = 0x3a,
+ DW_TAG_unspecified_type = 0x3b,
+ DW_TAG_partial_unit = 0x3c,
+ DW_TAG_imported_unit = 0x3d,
+ DW_TAG_condition = 0x3f,
+ DW_TAG_shared_type = 0x40,
+ // Dwarf4
+ DW_TAG_type_unit = 0x41,
+ DW_TAG_rvalue_reference_type = 0x42,
+ DW_TAG_template_alias = 0x43,
+
+ // User defined
+ DW_TAG_lo_user = 0x4080,
+ DW_TAG_hi_user = 0xffff,
+
+};
+
+// Table 19
+enum
+{
+ DW_CHILDREN_no = 0x00,
+ DW_CHILDREN_yes = 0x01,
+};
+
+// Not from the spec, but logicaly belongs here
+enum
+{
+ DW_CLS_ADDRESS = 0x01,
+ DW_CLS_BLOCK,
+ DW_CLS_CONSTANT,
+ DW_CLS_FLAG,
+ DW_CLS_PTR, // lineptr, loclistptr, macptr, rangelistptr
+ DW_CLS_REFERENCE,
+ DW_CLS_STRING
+};
+
+// Table 20
+enum
+{
+ DW_AT_sibling = 0x01, // reference
+ DW_AT_location = 0x02, // block, loclistptr
+ DW_AT_name = 0x03, // string
+ DW_AT_ordering = 0x09, // constant
+ DW_AT_byte_size = 0x0b, // block, constant, reference
+ DW_AT_bit_offset = 0x0c, // block, constant, reference
+ DW_AT_bit_size = 0x0d, // block, constant, reference
+ DW_AT_stmt_list = 0x10, // lineptr
+ DW_AT_low_pc = 0x11, // address
+ DW_AT_high_pc = 0x12, // address
+ DW_AT_language = 0x13, // constant
+ DW_AT_discr = 0x15, // reference
+ DW_AT_discr_value = 0x16, // constant
+ DW_AT_visibility = 0x17, // constant
+ DW_AT_import = 0x18, // reference
+ DW_AT_string_length = 0x19, // block, loclistptr
+ DW_AT_common_reference = 0x1a, // reference
+ DW_AT_comp_dir = 0x1b, // string
+ DW_AT_const_value = 0x1c, // block, constant, string
+ DW_AT_containing_type = 0x1d, // reference
+ DW_AT_default_value = 0x1e, // reference
+ DW_AT_inline = 0x20, // constant
+ DW_AT_is_optional = 0x21, // flag
+ DW_AT_lower_bound = 0x22, // block, constant, reference
+ DW_AT_producer = 0x25, // string
+ DW_AT_prototyped = 0x27, // flag
+ DW_AT_return_addr = 0x2a, // block, loclistptr
+ DW_AT_start_scope = 0x2c, // constant
+ DW_AT_bit_stride = 0x2e, // constant
+ DW_AT_upper_bound = 0x2f, // block, constant, reference
+ DW_AT_abstract_origin = 0x31, // reference
+ DW_AT_accessibility = 0x32, // constant
+ DW_AT_address_class = 0x33, // constant
+ DW_AT_artificial = 0x34, // flag
+ DW_AT_base_types = 0x35, // reference
+ DW_AT_calling_convention = 0x36, // constant
+ DW_AT_count = 0x37, // block, constant, reference
+ DW_AT_data_member_location = 0x38, // block, constant, loclistptr
+ DW_AT_decl_column = 0x39, // constant
+ DW_AT_decl_file = 0x3a, // constant
+ DW_AT_decl_line = 0x3b, // constant
+ DW_AT_declaration = 0x3c, // flag
+ DW_AT_discr_list = 0x3d, // block
+ DW_AT_encoding = 0x3e, // constant
+ DW_AT_external = 0x3f, // flag
+ DW_AT_frame_base = 0x40, // block, loclistptr
+ DW_AT_friend = 0x41, // reference
+ DW_AT_identifier_case = 0x42, // constant
+ DW_AT_macro_info = 0x43, // macptr
+ DW_AT_namelist_item = 0x44, // block
+ DW_AT_priority = 0x45, // reference
+ DW_AT_segment = 0x46, // block, loclistptr
+ DW_AT_specification = 0x47, // reference
+ DW_AT_static_link = 0x48, // block, loclistptr
+ DW_AT_type = 0x49, // reference
+ DW_AT_use_location = 0x4a, // block, loclistptr
+ DW_AT_variable_parameter = 0x4b, // flag
+ DW_AT_virtuality = 0x4c, // constant
+ DW_AT_vtable_elem_location = 0x4d, // block, loclistptr
+ // Dwarf3
+ DW_AT_allocated = 0x4e, // block, constant, reference
+ DW_AT_associated = 0x4f, // block, constant, reference
+ DW_AT_data_location = 0x50, // block
+ DW_AT_byte_stride = 0x51, // block, constant, reference
+ DW_AT_entry_pc = 0x52, // address
+ DW_AT_use_UTF8 = 0x53, // flag
+ DW_AT_extension = 0x54, // reference
+ DW_AT_ranges = 0x55, // rangelistptr
+ DW_AT_trampoline = 0x56, // address, flag, reference, string
+ DW_AT_call_column = 0x57, // constant
+ DW_AT_call_file = 0x58, // constant
+ DW_AT_call_line = 0x59, // constant
+ DW_AT_description = 0x5a, // string
+ DW_AT_binary_scale = 0x5b, // constant
+ DW_AT_decimal_scale = 0x5c, // constant
+ DW_AT_small = 0x5d, // reference
+ DW_AT_decimal_sign = 0x5e, // constant
+ DW_AT_digit_count = 0x5f, // constant
+ DW_AT_picture_string = 0x60, // string
+ DW_AT_mutable = 0x61, // flag
+ DW_AT_threads_scaled = 0x62, // flag
+ DW_AT_explicit = 0x63, // flag
+ DW_AT_object_pointer = 0x64, // reference
+ DW_AT_endianity = 0x65, // constant
+ DW_AT_elemental = 0x66, // flag
+ DW_AT_pure = 0x67, // flag
+ DW_AT_recursive = 0x68, // flag
+
+ DW_AT_lo_user = 0x2000, // ---
+ DW_AT_hi_user = 0x3fff, // ---
+
+};
+
+// Table 21
+enum
+{
+ DW_FORM_addr = 0x01, // address
+ DW_FORM_block2 = 0x03, // block
+ DW_FORM_block4 = 0x04, // block
+ DW_FORM_data2 = 0x05, // constant
+ DW_FORM_data4 = 0x06, // constant, lineptr, loclistptr, macptr, rangelistptr
+ DW_FORM_data8 = 0x07, // constant, lineptr, loclistptr, macptr, rangelistptr
+ DW_FORM_string = 0x08, // string
+ DW_FORM_block = 0x09, // block
+ DW_FORM_block1 = 0x0a, // block
+ DW_FORM_data1 = 0x0b, // constant
+ DW_FORM_flag = 0x0c, // flag
+ DW_FORM_sdata = 0x0d, // constant
+ DW_FORM_strp = 0x0e, // string
+ DW_FORM_udata = 0x0f, // constant
+ DW_FORM_ref_addr = 0x10, // reference
+ DW_FORM_ref1 = 0x11, // reference
+ DW_FORM_ref2 = 0x12, // reference
+ DW_FORM_ref4 = 0x13, // reference
+ DW_FORM_ref8 = 0x14, // reference
+ DW_FORM_ref_udata = 0x15, // reference
+ DW_FORM_indirect = 0x16, // (see Section 7.5.3)
+};
+
+// Table 24 (#operands, notes)
+enum
+{
+ DW_OP_addr = 0x03, // 1 constant address (size target specific)
+ DW_OP_deref = 0x06, // 0
+ DW_OP_const1u = 0x08, // 1 1-byte constant
+ DW_OP_const1s = 0x09, // 1 1-byte constant
+ DW_OP_const2u = 0x0a, // 1 2-byte constant
+ DW_OP_const2s = 0x0b, // 1 2-byte constant
+ DW_OP_const4u = 0x0c, // 1 4-byte constant
+ DW_OP_const4s = 0x0d, // 1 4-byte constant
+ DW_OP_const8u = 0x0e, // 1 8-byte constant
+ DW_OP_const8s = 0x0f, // 1 8-byte constant
+ DW_OP_constu = 0x10, // 1 ULEB128 constant
+ DW_OP_consts = 0x11, // 1 SLEB128 constant
+ DW_OP_dup = 0x12, // 0
+ DW_OP_drop = 0x13, // 0
+ DW_OP_over = 0x14, // 0
+ DW_OP_pick = 0x15, // 1 1-byte stack index
+ DW_OP_swap = 0x16, // 0
+ DW_OP_rot = 0x17, // 0
+ DW_OP_xderef = 0x18, // 0
+ DW_OP_abs = 0x19, // 0
+ DW_OP_and = 0x1a, // 0
+ DW_OP_div = 0x1b, // 0
+ DW_OP_minus = 0x1c, // 0
+ DW_OP_mod = 0x1d, // 0
+ DW_OP_mul = 0x1e, // 0
+ DW_OP_neg = 0x1f, // 0
+ DW_OP_not = 0x20, // 0
+ DW_OP_or = 0x21, // 0
+ DW_OP_plus = 0x22, // 0
+ DW_OP_plus_uconst = 0x23, // 1 ULEB128 addend
+ DW_OP_shl = 0x24, // 0
+ DW_OP_shr = 0x25, // 0
+ DW_OP_shra = 0x26, // 0
+ DW_OP_xor = 0x27, // 0
+ DW_OP_skip = 0x2f, // 1 signed 2-byte constant
+ DW_OP_bra = 0x28, // 1 signed 2-byte constant
+ DW_OP_eq = 0x29, // 0
+ DW_OP_ge = 0x2a, // 0
+ DW_OP_gt = 0x2b, // 0
+ DW_OP_le = 0x2c, // 0
+ DW_OP_lt = 0x2d, // 0
+ DW_OP_ne = 0x2e, // 0
+ DW_OP_lit0 = 0x30, // 0 ...
+ DW_OP_lit31 = 0x4f, // 0 literals 0..31 = (DW_OP_lit0 +
+ // literal)
+ DW_OP_reg0 = 0x50, // 0 ..
+ DW_OP_reg31 = 0x6f, // 0 reg 0..31 = (DW_OP_reg0 + regnum)
+ DW_OP_breg0 = 0x70, // 1 ...
+ DW_OP_breg31 = 0x8f, // 1 SLEB128 offset base register 0..31 = (DW_OP_breg0 + regnum)
+ DW_OP_regx = 0x90, // 1 ULEB128 register
+ DW_OP_fbreg = 0x91, // 1 SLEB128 offset
+ DW_OP_bregx = 0x92, // 2 ULEB128 register followed by SLEB128 offset
+ DW_OP_piece = 0x93, // 1 ULEB128 size of piece addressed
+ DW_OP_deref_size = 0x94, // 1 1-byte size of data retrieved
+ DW_OP_xderef_size = 0x95, // 1 1-byte size of data retrieved
+ DW_OP_nop = 0x96, // 0
+ DW_OP_push_object_address = 0x97, // 0
+ DW_OP_call2 = 0x98, // 1 2-byte offset of DIE
+ DW_OP_call4 = 0x99, // 1 4-byte offset of DIE
+ DW_OP_call_ref = 0x9a, // 1 4- or 8-byte offset of DIE
+ DW_OP_form_tls_address = 0x9b, // 0
+ DW_OP_call_frame_cfa = 0x9c, // 0
+ DW_OP_bit_piece = 0x9d, // 2
+ DW_OP_lo_user = 0xe0,
+ DW_OP_hi_user = 0xff,
+};
+
+// Table 25
+enum
+{
+ DW_ATE_address = 0x01,
+ DW_ATE_boolean = 0x02,
+ DW_ATE_complex_float = 0x03,
+ DW_ATE_float = 0x04,
+ DW_ATE_signed = 0x05,
+ DW_ATE_signed_char = 0x06,
+ DW_ATE_unsigned = 0x07,
+ DW_ATE_unsigned_char = 0x08,
+ DW_ATE_imaginary_float = 0x09,
+ DW_ATE_packed_decimal = 0x0a,
+ DW_ATE_numeric_string = 0x0b,
+ DW_ATE_edited = 0x0c,
+ DW_ATE_signed_fixed = 0x0d,
+ DW_ATE_unsigned_fixed = 0x0e,
+ DW_ATE_decimal_float = 0x0f,
+ DW_ATE_lo_user = 0x80,
+ DW_ATE_hi_user = 0xff,
+};
+
+// Table 26
+enum
+{
+ DW_DS_unsigned = 0x01,
+ DW_DS_leading_overpunch = 0x02,
+ DW_DS_trailing_overpunch = 0x03,
+ DW_DS_leading_separate = 0x04,
+ DW_DS_trailing_separate = 0x05,
+};
+
+// Table 27
+enum
+{
+ DW_END_default = 0x00,
+ DW_END_big = 0x01,
+ DW_END_little = 0x02,
+ DW_END_lo_user = 0x40,
+ DW_END_hi_user = 0xff,
+};
+
+// Table 28
+enum
+{
+ DW_ACCESS_public = 0x01,
+ DW_ACCESS_protected = 0x02,
+ DW_ACCESS_private = 0x03,
+};
+
+// Table 29
+enum
+{
+ DW_VIS_local = 0x01,
+ DW_VIS_exported = 0x02,
+ DW_VIS_qualified = 0x03,
+};
+
+// Table 30
+enum
+{
+ DW_VIRTUALITY_none = 0x00,
+ DW_VIRTUALITY_virtual = 0x01,
+ DW_VIRTUALITY_pure_virtual = 0x02,
+};
+
+// Table 31
+enum
+{
+ DW_LANG_C89 = 0x0001,
+ DW_LANG_C = 0x0002,
+ DW_LANG_Ada83 = 0x0003,
+ DW_LANG_C_plus_plus = 0x0004,
+ DW_LANG_Cobol74 = 0x0005,
+ DW_LANG_Cobol85 = 0x0006,
+ DW_LANG_Fortran77 = 0x0007,
+ DW_LANG_Fortran90 = 0x0008,
+ DW_LANG_Pascal83 = 0x0009,
+ DW_LANG_Modula2 = 0x000a,
+ // Dwarf3
+ DW_LANG_Java = 0x000b,
+ DW_LANG_C99 = 0x000c,
+ DW_LANG_Ada95 = 0x000d,
+ DW_LANG_Fortran95 = 0x000e,
+ DW_LANG_PLI = 0x000f,
+ DW_LANG_ObjC = 0x0010,
+ DW_LANG_ObjC_plus_plus = 0x0011,
+ DW_LANG_UPC = 0x0012,
+ DW_LANG_D = 0x0013,
+ // Dwarf4
+ DW_LANG_Python = 0x0014,
+ // Dwarf5
+ DW_LANG_Go = 0x0016,
+
+ DW_LANG_lo_user = 0x8000,
+ DW_LANG_hi_user = 0xffff,
+};
+
+// Table 32
+enum
+{
+ DW_ID_case_sensitive = 0x00,
+ DW_ID_up_case = 0x01,
+ DW_ID_down_case = 0x02,
+ DW_ID_case_insensitive = 0x03,
+};
+
+// Table 33
+enum
+{
+ DW_CC_normal = 0x01,
+ DW_CC_program = 0x02,
+ DW_CC_nocall = 0x03,
+ DW_CC_lo_user = 0x40,
+ DW_CC_hi_user = 0xff,
+};
+
+// Table 34
+enum
+{
+ DW_INL_not_inlined = 0x00,
+ DW_INL_inlined = 0x01,
+ DW_INL_declared_not_inlined = 0x02,
+ DW_INL_declared_inlined = 0x03,
+};
+
+// Table 35
+enum
+{
+ DW_ORD_row_major = 0x00,
+ DW_ORD_col_major = 0x01,
+};
+
+// Table 36
+enum
+{
+ DW_DSC_label = 0x00,
+ DW_DSC_range = 0x01,
+};
+
+// Table 37
+enum
+{
+ DW_LNS_copy = 0x01,
+ DW_LNS_advance_pc = 0x02,
+ DW_LNS_advance_line = 0x03,
+ DW_LNS_set_file = 0x04,
+ DW_LNS_set_column = 0x05,
+ DW_LNS_negate_stmt = 0x06,
+ DW_LNS_set_basic_block = 0x07,
+ DW_LNS_const_add_pc = 0x08,
+ DW_LNS_fixed_advance_pc = 0x09,
+ // Dwarf3
+ DW_LNS_set_prologue_end = 0x0a,
+ DW_LNS_set_epilogue_begin = 0x0b,
+ DW_LNS_set_isa = 0x0c,
+};
+
+// Table 38
+enum
+{
+ DW_LNE_end_sequence = 0x01,
+ DW_LNE_set_address = 0x02,
+ DW_LNE_define_file = 0x03,
+ DW_LNE_lo_user = 0x80,
+ DW_LNE_hi_user = 0xff,
+};
+
+// Table 39
+enum
+{
+ DW_MACINFO_define = 0x01,
+ DW_MACINFO_undef = 0x02,
+ DW_MACINFO_start_file = 0x03,
+ DW_MACINFO_end_file = 0x04,
+ DW_MACINFO_vendor_ext = 0xff,
+};
+
+// Table 40.
+enum
+{ // operand,...
+ DW_CFA_nop = 0x00,
+ DW_CFA_set_loc = 0x01, // address
+ DW_CFA_advance_loc1 = 0x02, // 1-byte delta
+ DW_CFA_advance_loc2 = 0x03, // 2-byte delta
+ DW_CFA_advance_loc4 = 0x04, // 4-byte delta
+ DW_CFA_offset_extended = 0x05, // ULEB128 register, ULEB128 offset
+ DW_CFA_restore_extended = 0x06, // ULEB128 register
+ DW_CFA_undefined = 0x07, // ULEB128 register
+ DW_CFA_same_value = 0x08, // ULEB128 register
+ DW_CFA_register = 0x09, // ULEB128 register, ULEB128 register
+ DW_CFA_remember_state = 0x0a,
+ DW_CFA_restore_state = 0x0b,
+ DW_CFA_def_cfa = 0x0c, // ULEB128 register, ULEB128 offset
+ DW_CFA_def_cfa_register = 0x0d, // ULEB128 register
+ DW_CFA_def_cfa_offset = 0x0e, // ULEB128 offset
+ DW_CFA_def_cfa_expression = 0x0f, // BLOCK
+ DW_CFA_expression = 0x10, // ULEB128 register, BLOCK
+ DW_CFA_offset_extended_sf = 0x11, // ULEB128 register, SLEB128 offset
+ DW_CFA_def_cfa_sf = 0x12, // ULEB128 register, SLEB128 offset
+ DW_CFA_def_cfa_offset_sf = 0x13, // SLEB128 offset
+ DW_CFA_val_offset = 0x14, // ULEB128, ULEB128
+ DW_CFA_val_offset_sf = 0x15, // ULEB128, SLEB128
+ DW_CFA_val_expression = 0x16, // ULEB128, BLOCK
+
+ DW_CFA_lo_user = 0x1c,
+ DW_CFA_hi_user = 0x3f,
+
+ // Opcodes that take an addend operand.
+ DW_CFA_advance_loc = 0x1<<6, // +delta
+ DW_CFA_offset = 0x2<<6, // +register (ULEB128 offset)
+ DW_CFA_restore = 0x3<<6, // +register
+};
diff --git a/src/cmd/ld/elf.c b/src/cmd/ld/elf.c
index c5d58576d..d5b0b0311 100644
--- a/src/cmd/ld/elf.c
+++ b/src/cmd/ld/elf.c
@@ -21,6 +21,16 @@ static ElfPhdr *phdr[NSECT];
static ElfShdr *shdr[NSECT];
static char *interp;
+typedef struct Elfstring Elfstring;
+struct Elfstring
+{
+ char *s;
+ int off;
+};
+
+static Elfstring elfstr[100];
+static int nelfstr;
+
/*
Initialize the global variable that describes the ELF header. It will be updated as
we write section and prog headers.
@@ -122,6 +132,18 @@ elfwriteshdrs(void)
return hdr.shnum * ELF32SHDRSIZE;
}
+void
+elfsetstring(char *s, int off)
+{
+ if(nelfstr >= nelem(elfstr)) {
+ diag("too many elf strings");
+ errorexit();
+ }
+ elfstr[nelfstr].s = s;
+ elfstr[nelfstr].off = off;
+ nelfstr++;
+}
+
uint32
elfwritephdrs(void)
{
@@ -142,8 +164,7 @@ newElfPhdr(void)
{
ElfPhdr *e;
- e = malloc(sizeof *e);
- memset(e, 0, sizeof *e);
+ e = mal(sizeof *e);
if (hdr.phnum >= NSECT)
diag("too many phdrs");
else
@@ -167,8 +188,7 @@ newElfShdr(vlong name)
{
ElfShdr *e;
- e = malloc(sizeof *e);
- memset(e, 0, sizeof *e);
+ e = mal(sizeof *e);
e->name = name;
if (hdr.shnum >= NSECT) {
diag("too many shdrs");
@@ -294,7 +314,7 @@ elfwriteinterp(void)
n = strlen(interp)+1;
seek(cout, ELFRESERVE-n, 0);
- write(cout, interp, n);
+ ewrite(cout, interp, n);
return n;
}
@@ -310,17 +330,25 @@ elfinterp(ElfShdr *sh, uint64 startva, char *p)
sh->size = n;
}
+extern int nelfsym;
+
void
-elfdynhash(int nsym)
+elfdynhash(void)
{
Sym *s, *sy;
int i, h, nbucket, b;
uchar *pc;
uint32 hc, g;
uint32 *chain, *buckets;
+ int nsym;
+ char *name;
+
+ if(!iself)
+ return;
+ nsym = nelfsym;
s = lookup(".hash", 0);
- s->type = SELFDATA; // TODO: rodata
+ s->type = SELFDATA;
s->reachable = 1;
i = nsym;
@@ -331,17 +359,24 @@ elfdynhash(int nsym)
}
chain = malloc(nsym * sizeof(uint32));
- memset(chain, 0, nsym * sizeof(uint32));
buckets = malloc(nbucket * sizeof(uint32));
+ if(chain == nil || buckets == nil) {
+ cursym = nil;
+ diag("out of memory");
+ errorexit();
+ }
+ memset(chain, 0, nsym * sizeof(uint32));
memset(buckets, 0, nbucket * sizeof(uint32));
- i = 1;
for(h = 0; h<NHASH; h++) {
- for(sy=hash[h]; sy!=S; sy=sy->link) {
- if (!sy->reachable || (sy->type != STEXT && sy->type != SDATA && sy->type != SBSS) || sy->dynimpname == nil)
+ for(sy=hash[h]; sy!=S; sy=sy->hash) {
+ if (sy->dynid <= 0)
continue;
hc = 0;
- for(pc = (uchar*)sy->dynimpname; *pc; pc++) {
+ name = sy->dynimpname;
+ if(name == nil)
+ name = sy->name;
+ for(pc = (uchar*)name; *pc; pc++) {
hc = (hc<<4) + *pc;
g = hc & 0xf0000000;
hc ^= g >> 24;
@@ -349,9 +384,8 @@ elfdynhash(int nsym)
}
b = hc % nbucket;
- chain[i] = buckets[b];
- buckets[b] = i;
- i++;
+ chain[sy->dynid] = buckets[b];
+ buckets[b] = sy->dynid;
}
}
@@ -364,4 +398,64 @@ elfdynhash(int nsym)
free(chain);
free(buckets);
+
+ elfwritedynent(lookup(".dynamic", 0), DT_NULL, 0);
+}
+
+ElfPhdr*
+elfphload(Segment *seg)
+{
+ ElfPhdr *ph;
+
+ ph = newElfPhdr();
+ ph->type = PT_LOAD;
+ if(seg->rwx & 4)
+ ph->flags |= PF_R;
+ if(seg->rwx & 2)
+ ph->flags |= PF_W;
+ if(seg->rwx & 1)
+ ph->flags |= PF_X;
+ ph->vaddr = seg->vaddr;
+ ph->paddr = seg->vaddr;
+ ph->memsz = seg->len;
+ ph->off = seg->fileoff;
+ ph->filesz = seg->filelen;
+ ph->align = INITRND;
+
+ return ph;
+}
+
+ElfShdr*
+elfshbits(Section *sect)
+{
+ int i, off;
+ ElfShdr *sh;
+
+ for(i=0; i<nelfstr; i++) {
+ if(strcmp(sect->name, elfstr[i].s) == 0) {
+ off = elfstr[i].off;
+ goto found;
+ }
+ }
+ diag("cannot find elf name %s", sect->name);
+ errorexit();
+ return nil;
+
+found:
+ sh = newElfShdr(off);
+ if(sect->vaddr < sect->seg->vaddr + sect->seg->filelen)
+ sh->type = SHT_PROGBITS;
+ else
+ sh->type = SHT_NOBITS;
+ sh->flags = SHF_ALLOC;
+ if(sect->rwx & 1)
+ sh->flags |= SHF_EXECINSTR;
+ if(sect->rwx & 2)
+ sh->flags |= SHF_WRITE;
+ sh->addr = sect->vaddr;
+ sh->addralign = PtrSize;
+ sh->size = sect->len;
+ sh->off = sect->seg->fileoff + sect->vaddr - sect->seg->vaddr;
+
+ return sh;
}
diff --git a/src/cmd/ld/elf.h b/src/cmd/ld/elf.h
index 9b5fdb17e..df15cb115 100644
--- a/src/cmd/ld/elf.h
+++ b/src/cmd/ld/elf.h
@@ -964,7 +964,10 @@ extern int numelfshdr;
extern int iself;
int elfwriteinterp(void);
void elfinterp(ElfShdr*, uint64, char*);
-void elfdynhash(int);
+void elfdynhash(void);
+ElfPhdr* elfphload(Segment*);
+ElfShdr* elfshbits(Section*);
+void elfsetstring(char*, int);
/*
* Total amount of space to reserve at the start of the file
@@ -972,5 +975,4 @@ void elfdynhash(int);
* May waste some.
* On FreeBSD, cannot be larger than a page.
*/
-#define ELFRESERVE 2048
-
+#define ELFRESERVE 3072
diff --git a/src/cmd/ld/go.c b/src/cmd/ld/go.c
index 015f34db2..8966b2a1f 100644
--- a/src/cmd/ld/go.c
+++ b/src/cmd/ld/go.c
@@ -66,12 +66,11 @@ ilookup(char *name)
}
static void loadpkgdata(char*, char*, char*, int);
-static void loaddynimport(char*, char*, int);
+static void loaddynimport(char*, char*, char*, int);
static void loaddynexport(char*, char*, char*, int);
static int parsemethod(char**, char*, char**);
static int parsepkgdata(char*, char*, char**, char*, char**, char**, char**);
-static int ndynexp;
static Sym **dynexp;
void
@@ -194,7 +193,7 @@ ldpkg(Biobuf *f, char *pkg, int64 len, char *filename, int whence)
errorexit();
return;
}
- loaddynimport(filename, p0 + 1, p1 - (p0+1));
+ loaddynimport(filename, pkg, p0 + 1, p1 - (p0+1));
}
// look for dynexp section
@@ -266,6 +265,10 @@ expandpkg(char *t0, char *pkg)
// use malloc, not mal, so that caller can free
w0 = malloc(strlen(t0) + strlen(pkg)*n);
+ if(w0 == nil) {
+ diag("out of memory");
+ errorexit();
+ }
w = w0;
for(p=t=t0; (p=strstr(p, "\"\".")) != nil; p=t) {
memmove(w, t, p - t);
@@ -282,7 +285,7 @@ static int
parsepkgdata(char *file, char *pkg, char **pp, char *ep, char **prefixp, char **namep, char **defp)
{
char *p, *prefix, *name, *def, *edef, *meth;
- int n;
+ int n, inquote;
// skip white space
p = *pp;
@@ -319,8 +322,19 @@ loop:
// name: a.b followed by space
name = p;
- while(p < ep && *p != ' ')
+ inquote = 0;
+ while(p < ep) {
+ if (*p == ' ' && !inquote)
+ break;
+
+ if(*p == '\\')
+ p++;
+ else if(*p == '"')
+ inquote = !inquote;
+
p++;
+ }
+
if(p >= ep)
return -1;
*p++ = '\0';
@@ -397,7 +411,7 @@ parsemethod(char **pp, char *ep, char **methp)
}
static void
-loaddynimport(char *file, char *p, int n)
+loaddynimport(char *file, char *pkg, char *p, int n)
{
char *pend, *next, *name, *def, *p0, *lib;
Sym *s;
@@ -431,10 +445,21 @@ loaddynimport(char *file, char *p, int n)
// successful parse: now can edit the line
*strchr(name, ' ') = 0;
*strchr(def, ' ') = 0;
+
+ if(strcmp(name, "_") == 0 && strcmp(def, "_") == 0) {
+ // allow #pragma dynimport _ _ "foo.so"
+ // to force a link of foo.so.
+ adddynlib(lib);
+ continue;
+ }
+ name = expandpkg(name, pkg);
s = lookup(name, 0);
- s->dynimplib = lib;
- s->dynimpname = def;
+ if(s->type == 0 || s->type == SXREF) {
+ s->dynimplib = lib;
+ s->dynimpname = def;
+ s->type = SDYNIMPORT;
+ }
}
return;
@@ -499,38 +524,19 @@ err:
static int markdepth;
static void
-markdata(Prog *p, Sym *s)
-{
- markdepth++;
- if(p != P && debug['v'] > 1)
- Bprint(&bso, "%d markdata %s\n", markdepth, s->name);
- for(; p != P; p=p->dlink)
- if(p->to.sym)
- mark(p->to.sym);
- markdepth--;
-}
-
-static void
-marktext(Prog *p)
+marktext(Sym *s)
{
Auto *a;
+ Prog *p;
- if(p == P)
+ if(s == S)
return;
- if(p->as != ATEXT) {
- diag("marktext: %P", p);
- return;
- }
- for(a=p->to.autom; a; a=a->link)
- mark(a->gotype);
markdepth++;
if(debug['v'] > 1)
- Bprint(&bso, "%d marktext %s\n", markdepth, p->from.sym->name);
- for(a=p->to.autom; a; a=a->link)
+ Bprint(&bso, "%d marktext %s\n", markdepth, s->name);
+ for(a=s->autom; a; a=a->link)
mark(a->gotype);
- for(p=p->link; p != P; p=p->link) {
- if(p->as == ATEXT || p->as == ADATA || p->as == AGLOBL)
- break;
+ for(p=s->text; p != P; p=p->link) {
if(p->from.sym)
mark(p->from.sym);
if(p->to.sym)
@@ -542,45 +548,21 @@ marktext(Prog *p)
void
mark(Sym *s)
{
+ int i;
+
if(s == S || s->reachable)
return;
s->reachable = 1;
if(s->text)
- marktext(s->text);
- if(s->data)
- markdata(s->data, s);
+ marktext(s);
+ for(i=0; i<s->nr; i++)
+ mark(s->r[i].sym);
if(s->gotype)
mark(s->gotype);
-}
-
-static void
-sweeplist(Prog **first, Prog **last)
-{
- int reachable;
- Prog *p, *q;
-
- reachable = 1;
- q = P;
- for(p=*first; p != P; p=p->link) {
- switch(p->as) {
- case ATEXT:
- case ADATA:
- case AGLOBL:
- reachable = p->from.sym->reachable;
- }
- if(reachable) {
- if(q == P)
- *first = p;
- else
- q->link = p;
- q = p;
- }
- }
- if(q == P)
- *first = P;
- else
- q->link = P;
- *last = q;
+ if(s->sub)
+ mark(s->sub);
+ if(s->outer)
+ mark(s->outer);
}
static char*
@@ -602,10 +584,43 @@ morename[] =
"runtime.morestack48",
};
+static int
+isz(Auto *a)
+{
+ for(; a; a=a->link)
+ if(a->type == D_FILE || a->type == D_FILE1)
+ return 1;
+ return 0;
+}
+
+static void
+addz(Sym *s, Auto *z)
+{
+ Auto *a, *last;
+
+ // strip out non-z
+ last = nil;
+ for(a = z; a != nil; a = a->link) {
+ if(a->type == D_FILE || a->type == D_FILE1) {
+ if(last == nil)
+ z = a;
+ else
+ last->link = a;
+ last = a;
+ }
+ }
+ if(last) {
+ last->link = s->autom;
+ s->autom = z;
+ }
+}
+
void
deadcode(void)
{
int i;
+ Sym *s, *last;
+ Auto *z;
if(debug['v'])
Bprint(&bso, "%5.2f deadcode\n", cputime());
@@ -616,7 +631,38 @@ deadcode(void)
for(i=0; i<ndynexp; i++)
mark(dynexp[i]);
+
+ // remove dead text but keep file information (z symbols).
+ last = nil;
+ z = nil;
+ for(s = textp; s != nil; s = s->next) {
+ if(!s->reachable) {
+ if(isz(s->autom))
+ z = s->autom;
+ continue;
+ }
+ if(last == nil)
+ textp = s;
+ else
+ last->next = s;
+ last = s;
+ if(z != nil) {
+ if(!isz(s->autom))
+ addz(s, z);
+ z = nil;
+ }
+ }
+ if(last == nil)
+ textp = nil;
+ else
+ last->next = nil;
+}
- // remove dead data
- sweeplist(&datap, &edatap);
+void
+addexport(void)
+{
+ int i;
+
+ for(i=0; i<ndynexp; i++)
+ adddynsym(dynexp[i]);
}
diff --git a/src/cmd/ld/ldelf.c b/src/cmd/ld/ldelf.c
new file mode 100644
index 000000000..44bbe68ee
--- /dev/null
+++ b/src/cmd/ld/ldelf.c
@@ -0,0 +1,816 @@
+/*
+Derived from Plan 9 from User Space's src/libmach/elf.h, elf.c
+http://code.swtch.com/plan9port/src/tip/src/libmach/
+
+ Copyright © 2004 Russ Cox.
+ Portions Copyright © 2008-2010 Google Inc.
+ Portions Copyright © 2010 The Go Authors.
+
+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 "l.h"
+#include "lib.h"
+#include "../ld/elf.h"
+
+enum
+{
+ ElfClassNone = 0,
+ ElfClass32,
+ ElfClass64,
+
+ ElfDataNone = 0,
+ ElfDataLsb,
+ ElfDataMsb,
+
+ ElfTypeNone = 0,
+ ElfTypeRelocatable,
+ ElfTypeExecutable,
+ ElfTypeSharedObject,
+ ElfTypeCore,
+ /* 0xFF00 - 0xFFFF reserved for processor-specific types */
+
+ ElfMachNone = 0,
+ ElfMach32100, /* AT&T WE 32100 */
+ ElfMachSparc, /* SPARC */
+ ElfMach386, /* Intel 80386 */
+ ElfMach68000, /* Motorola 68000 */
+ ElfMach88000, /* Motorola 88000 */
+ ElfMach486, /* Intel 80486, no longer used */
+ ElfMach860, /* Intel 80860 */
+ ElfMachMips, /* MIPS RS3000 */
+ ElfMachS370, /* IBM System/370 */
+ ElfMachMipsLe, /* MIPS RS3000 LE */
+ ElfMachParisc = 15, /* HP PA RISC */
+ ElfMachVpp500 = 17, /* Fujitsu VPP500 */
+ ElfMachSparc32Plus, /* SPARC V8+ */
+ ElfMach960, /* Intel 80960 */
+ ElfMachPower, /* PowerPC */
+ ElfMachPower64, /* PowerPC 64 */
+ ElfMachS390, /* IBM System/390 */
+ ElfMachV800 = 36, /* NEC V800 */
+ ElfMachFr20, /* Fujitsu FR20 */
+ ElfMachRh32, /* TRW RH-32 */
+ ElfMachRce, /* Motorola RCE */
+ ElfMachArm, /* ARM */
+ ElfMachAlpha, /* Digital Alpha */
+ ElfMachSH, /* Hitachi SH */
+ ElfMachSparc9, /* SPARC V9 */
+ ElfMachAmd64 = 62,
+ /* and the list goes on... */
+
+ ElfAbiNone = 0,
+ ElfAbiSystemV = 0, /* [sic] */
+ ElfAbiHPUX,
+ ElfAbiNetBSD,
+ ElfAbiLinux,
+ ElfAbiSolaris = 6,
+ ElfAbiAix,
+ ElfAbiIrix,
+ ElfAbiFreeBSD,
+ ElfAbiTru64,
+ ElfAbiModesto,
+ ElfAbiOpenBSD,
+ ElfAbiARM = 97,
+ ElfAbiEmbedded = 255,
+
+ /* some of sections 0xFF00 - 0xFFFF reserved for various things */
+ ElfSectNone = 0,
+ ElfSectProgbits,
+ ElfSectSymtab,
+ ElfSectStrtab,
+ ElfSectRela,
+ ElfSectHash,
+ ElfSectDynamic,
+ ElfSectNote,
+ ElfSectNobits,
+ ElfSectRel,
+ ElfSectShlib,
+ ElfSectDynsym,
+
+ ElfSectFlagWrite = 0x1,
+ ElfSectFlagAlloc = 0x2,
+ ElfSectFlagExec = 0x4,
+ /* 0xF0000000 are reserved for processor specific */
+
+ ElfSymBindLocal = 0,
+ ElfSymBindGlobal,
+ ElfSymBindWeak,
+ /* 13-15 reserved */
+
+ ElfSymTypeNone = 0,
+ ElfSymTypeObject,
+ ElfSymTypeFunc,
+ ElfSymTypeSection,
+ ElfSymTypeFile,
+ /* 13-15 reserved */
+
+ ElfSymShnNone = 0,
+ ElfSymShnAbs = 0xFFF1,
+ ElfSymShnCommon = 0xFFF2,
+ /* 0xFF00-0xFF1F reserved for processors */
+ /* 0xFF20-0xFF3F reserved for operating systems */
+
+ ElfProgNone = 0,
+ ElfProgLoad,
+ ElfProgDynamic,
+ ElfProgInterp,
+ ElfProgNote,
+ ElfProgShlib,
+ ElfProgPhdr,
+
+ ElfProgFlagExec = 0x1,
+ ElfProgFlagWrite = 0x2,
+ ElfProgFlagRead = 0x4,
+
+ ElfNotePrStatus = 1,
+ ElfNotePrFpreg = 2,
+ ElfNotePrPsinfo = 3,
+ ElfNotePrTaskstruct = 4,
+ ElfNotePrAuxv = 6,
+ ElfNotePrXfpreg = 0x46e62b7f /* for gdb/386 */
+};
+
+typedef struct ElfHdrBytes ElfHdrBytes;
+typedef struct ElfSectBytes ElfSectBytes;
+typedef struct ElfProgBytes ElfProgBytes;
+typedef struct ElfSymBytes ElfSymBytes;
+
+typedef struct ElfHdrBytes64 ElfHdrBytes64;
+typedef struct ElfSectBytes64 ElfSectBytes64;
+typedef struct ElfProgBytes64 ElfProgBytes64;
+typedef struct ElfSymBytes64 ElfSymBytes64;
+
+struct ElfHdrBytes
+{
+ uchar ident[16];
+ uchar type[2];
+ uchar machine[2];
+ uchar version[4];
+ uchar entry[4];
+ uchar phoff[4];
+ uchar shoff[4];
+ uchar flags[4];
+ uchar ehsize[2];
+ uchar phentsize[2];
+ uchar phnum[2];
+ uchar shentsize[2];
+ uchar shnum[2];
+ uchar shstrndx[2];
+};
+
+struct ElfHdrBytes64
+{
+ uchar ident[16];
+ uchar type[2];
+ uchar machine[2];
+ uchar version[4];
+ uchar entry[8];
+ uchar phoff[8];
+ uchar shoff[8];
+ uchar flags[4];
+ uchar ehsize[2];
+ uchar phentsize[2];
+ uchar phnum[2];
+ uchar shentsize[2];
+ uchar shnum[2];
+ uchar shstrndx[2];
+};
+
+struct ElfSectBytes
+{
+ uchar name[4];
+ uchar type[4];
+ uchar flags[4];
+ uchar addr[4];
+ uchar off[4];
+ uchar size[4];
+ uchar link[4];
+ uchar info[4];
+ uchar align[4];
+ uchar entsize[4];
+};
+
+struct ElfSectBytes64
+{
+ uchar name[4];
+ uchar type[4];
+ uchar flags[8];
+ uchar addr[8];
+ uchar off[8];
+ uchar size[8];
+ uchar link[4];
+ uchar info[4];
+ uchar align[8];
+ uchar entsize[8];
+};
+
+struct ElfSymBytes
+{
+ uchar name[4];
+ uchar value[4];
+ uchar size[4];
+ uchar info; /* top4: bind, bottom4: type */
+ uchar other;
+ uchar shndx[2];
+};
+
+struct ElfSymBytes64
+{
+ uchar name[4];
+ uchar info; /* top4: bind, bottom4: type */
+ uchar other;
+ uchar shndx[2];
+ uchar value[8];
+ uchar size[8];
+};
+
+typedef struct ElfSect ElfSect;
+typedef struct ElfObj ElfObj;
+typedef struct ElfSym ElfSym;
+
+struct ElfSect
+{
+ char *name;
+ uint32 type;
+ uint64 flags;
+ uint64 addr;
+ uint64 off;
+ uint64 size;
+ uint32 link;
+ uint32 info;
+ uint64 align;
+ uint64 entsize;
+ uchar *base;
+ Sym *sym;
+};
+
+struct ElfObj
+{
+ Biobuf *f;
+ int64 base; // offset in f where ELF begins
+ int64 len; // length of ELF
+ int is64;
+ char *name;
+
+ Endian *e;
+ ElfSect *sect;
+ uint nsect;
+ char *shstrtab;
+ int nsymtab;
+ ElfSect *symtab;
+ ElfSect *symstr;
+
+ uint32 type;
+ uint32 machine;
+ uint32 version;
+ uint64 entry;
+ uint64 phoff;
+ uint64 shoff;
+ uint32 flags;
+ uint32 ehsize;
+ uint32 phentsize;
+ uint32 phnum;
+ uint32 shentsize;
+ uint32 shnum;
+ uint32 shstrndx;
+};
+
+struct ElfSym
+{
+ char* name;
+ uint64 value;
+ uint64 size;
+ uchar bind;
+ uchar type;
+ uchar other;
+ uint16 shndx;
+ Sym* sym;
+};
+
+uchar ElfMagic[4] = { 0x7F, 'E', 'L', 'F' };
+
+static ElfSect* section(ElfObj*, char*);
+static int map(ElfObj*, ElfSect*);
+static int readsym(ElfObj*, int i, ElfSym*);
+static int reltype(char*, int, uchar*);
+
+void
+ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
+{
+ int32 base;
+ uint64 add, info;
+ char *name;
+ int i, j, rela, is64, n;
+ uchar hdrbuf[64];
+ uchar *p, *dp;
+ ElfHdrBytes *hdr;
+ ElfObj *obj;
+ ElfSect *sect, *rsect;
+ ElfSym sym;
+ Endian *e;
+ Reloc *r, *rp;
+ Sym *s;
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f ldelf %s\n", cputime(), pn);
+
+ version++;
+ base = Boffset(f);
+
+ if(Bread(f, &hdrbuf, sizeof hdrbuf) != sizeof hdrbuf)
+ goto bad;
+ hdr = (ElfHdrBytes*)&hdrbuf;
+ if(memcmp(hdr->ident, ElfMagic, 4) != 0)
+ goto bad;
+ switch(hdr->ident[5]) {
+ case ElfDataLsb:
+ e = &le;
+ break;
+ case ElfDataMsb:
+ e = &be;
+ break;
+ default:
+ goto bad;
+ }
+
+ // read header
+ obj = mal(sizeof *obj);
+ obj->e = e;
+ obj->f = f;
+ obj->base = base;
+ obj->len = len;
+ obj->name = pn;
+
+ is64 = 0;
+ if(hdr->ident[4] == ElfClass64) {
+ ElfHdrBytes64* hdr;
+
+ is64 = 1;
+ hdr = (ElfHdrBytes64*)hdrbuf;
+ obj->type = e->e16(hdr->type);
+ obj->machine = e->e16(hdr->machine);
+ obj->version = e->e32(hdr->version);
+ obj->phoff = e->e64(hdr->phoff);
+ obj->shoff = e->e64(hdr->shoff);
+ obj->flags = e->e32(hdr->flags);
+ obj->ehsize = e->e16(hdr->ehsize);
+ obj->phentsize = e->e16(hdr->phentsize);
+ obj->phnum = e->e16(hdr->phnum);
+ obj->shentsize = e->e16(hdr->shentsize);
+ obj->shnum = e->e16(hdr->shnum);
+ obj->shstrndx = e->e16(hdr->shstrndx);
+ } else {
+ obj->type = e->e16(hdr->type);
+ obj->machine = e->e16(hdr->machine);
+ obj->version = e->e32(hdr->version);
+ obj->entry = e->e32(hdr->entry);
+ obj->phoff = e->e32(hdr->phoff);
+ obj->shoff = e->e32(hdr->shoff);
+ obj->flags = e->e32(hdr->flags);
+ obj->ehsize = e->e16(hdr->ehsize);
+ obj->phentsize = e->e16(hdr->phentsize);
+ obj->phnum = e->e16(hdr->phnum);
+ obj->shentsize = e->e16(hdr->shentsize);
+ obj->shnum = e->e16(hdr->shnum);
+ obj->shstrndx = e->e16(hdr->shstrndx);
+ }
+ obj->is64 = is64;
+
+ if(hdr->ident[6] != obj->version)
+ goto bad;
+
+ if(e->e16(hdr->type) != ElfTypeRelocatable) {
+ diag("%s: elf but not elf relocatable object");
+ return;
+ }
+
+ switch(thechar) {
+ default:
+ diag("%s: elf %s unimplemented", thestring);
+ return;
+ case '5':
+ if(e != &le || obj->machine != ElfMachArm || hdr->ident[4] != ElfClass32) {
+ diag("%s: elf object but not arm", pn);
+ return;
+ }
+ break;
+ case '6':
+ if(e != &le || obj->machine != ElfMachAmd64 || hdr->ident[4] != ElfClass64) {
+ diag("%s: elf object but not amd64", pn);
+ return;
+ }
+ break;
+ case '8':
+ if(e != &le || obj->machine != ElfMach386 || hdr->ident[4] != ElfClass32) {
+ diag("%s: elf object but not 386", pn);
+ return;
+ }
+ break;
+ }
+
+ // load section list into memory.
+ obj->sect = mal(obj->shnum*sizeof obj->sect[0]);
+ obj->nsect = obj->shnum;
+ for(i=0; i<obj->nsect; i++) {
+ if(Bseek(f, base+obj->shoff+i*obj->shentsize, 0) < 0)
+ goto bad;
+ sect = &obj->sect[i];
+ if(is64) {
+ ElfSectBytes64 b;
+
+ werrstr("short read");
+ if(Bread(f, &b, sizeof b) != sizeof b)
+ goto bad;
+
+ sect->name = (char*)(uintptr)e->e32(b.name);
+ sect->type = e->e32(b.type);
+ sect->flags = e->e64(b.flags);
+ sect->addr = e->e64(b.addr);
+ sect->off = e->e64(b.off);
+ sect->size = e->e64(b.size);
+ sect->link = e->e32(b.link);
+ sect->info = e->e32(b.info);
+ sect->align = e->e64(b.align);
+ sect->entsize = e->e64(b.entsize);
+ } else {
+ ElfSectBytes b;
+
+ werrstr("short read");
+ if(Bread(f, &b, sizeof b) != sizeof b)
+ goto bad;
+
+ sect->name = (char*)(uintptr)e->e32(b.name);
+ sect->type = e->e32(b.type);
+ sect->flags = e->e32(b.flags);
+ sect->addr = e->e32(b.addr);
+ sect->off = e->e32(b.off);
+ sect->size = e->e32(b.size);
+ sect->link = e->e32(b.link);
+ sect->info = e->e32(b.info);
+ sect->align = e->e32(b.align);
+ sect->entsize = e->e32(b.entsize);
+ }
+ }
+
+ // read section string table and translate names
+ if(obj->shstrndx >= obj->nsect) {
+ werrstr("shstrndx out of range %d >= %d", obj->shstrndx, obj->nsect);
+ goto bad;
+ }
+ sect = &obj->sect[obj->shstrndx];
+ if(map(obj, sect) < 0)
+ goto bad;
+ for(i=0; i<obj->nsect; i++)
+ if(obj->sect[i].name != nil)
+ obj->sect[i].name = (char*)sect->base + (uintptr)obj->sect[i].name;
+
+ // load string table for symbols into memory.
+ obj->symtab = section(obj, ".symtab");
+ if(obj->symtab == nil) {
+ // our work is done here - no symbols means nothing can refer to this file
+ return;
+ }
+ if(obj->symtab->link <= 0 || obj->symtab->link >= obj->nsect) {
+ diag("%s: elf object has symbol table with invalid string table link", pn);
+ return;
+ }
+ obj->symstr = &obj->sect[obj->symtab->link];
+ if(is64)
+ obj->nsymtab = obj->symtab->size / sizeof(ElfSymBytes64);
+ else
+ obj->nsymtab = obj->symtab->size / sizeof(ElfSymBytes);
+
+ if(map(obj, obj->symtab) < 0)
+ goto bad;
+ if(map(obj, obj->symstr) < 0)
+ goto bad;
+
+ // load text and data segments into memory.
+ // they are not as small as the section lists, but we'll need
+ // the memory anyway for the symbol images, so we might
+ // as well use one large chunk.
+
+ // create symbols for mapped sections
+ for(i=0; i<obj->nsect; i++) {
+ sect = &obj->sect[i];
+ if((sect->type != ElfSectProgbits && sect->type != ElfSectNobits) || !(sect->flags&ElfSectFlagAlloc))
+ continue;
+ if(sect->type != ElfSectNobits && map(obj, sect) < 0)
+ goto bad;
+
+ name = smprint("%s(%s)", pn, sect->name);
+ s = lookup(name, version);
+ free(name);
+ switch(sect->flags&(ElfSectFlagAlloc|ElfSectFlagWrite|ElfSectFlagExec)) {
+ default:
+ werrstr("unexpected flags for ELF section %s", sect->name);
+ goto bad;
+ case ElfSectFlagAlloc:
+ s->type = SRODATA;
+ break;
+ case ElfSectFlagAlloc + ElfSectFlagWrite:
+ s->type = SDATA;
+ break;
+ case ElfSectFlagAlloc + ElfSectFlagExec:
+ s->type = STEXT;
+ break;
+ }
+ if(sect->type == ElfSectProgbits) {
+ s->p = sect->base;
+ s->np = sect->size;
+ }
+ s->size = sect->size;
+ if(s->type == STEXT) {
+ if(etextp)
+ etextp->next = s;
+ else
+ textp = s;
+ etextp = s;
+ }
+ sect->sym = s;
+ }
+
+ // load relocations
+ for(i=0; i<obj->nsect; i++) {
+ rsect = &obj->sect[i];
+ if(rsect->type != ElfSectRela && rsect->type != ElfSectRel)
+ continue;
+ if(rsect->info >= obj->nsect || obj->sect[rsect->info].base == nil)
+ continue;
+ sect = &obj->sect[rsect->info];
+ if(map(obj, rsect) < 0)
+ goto bad;
+ rela = rsect->type == ElfSectRela;
+ n = rsect->size/(4+4*is64)/(2+rela);
+ r = mal(n*sizeof r[0]);
+ p = rsect->base;
+ dp = sect->base;
+ for(j=0; j<n; j++) {
+ add = 0;
+ rp = &r[j];
+ if(is64) {
+ // 64-bit rel/rela
+ rp->off = e->e64(p);
+ p += 8;
+ info = e->e64(p);
+ p += 8;
+ if(rela) {
+ add = e->e64(p);
+ p += 8;
+ }
+ } else {
+ // 32-bit rel/rela
+ rp->off = e->e32(p);
+ p += 4;
+ info = e->e32(p);
+ info = info>>8<<32 | (info&0xff); // convert to 64-bit info
+ p += 4;
+ if(rela) {
+ add = e->e32(p);
+ p += 4;
+ }
+ }
+ if(readsym(obj, info>>32, &sym) < 0)
+ goto bad;
+ if(sym.sym == nil) {
+ werrstr("%s#%d: reloc of invalid sym #%d %s shndx=%d type=%d",
+ sect->sym->name, j, (int)(info>>32), sym.name, sym.shndx, sym.type);
+ goto bad;
+ }
+ rp->sym = sym.sym;
+ rp->type = reltype(pn, (uint32)info, &rp->siz);
+ if(rela)
+ rp->add = add;
+ else {
+ // load addend from image
+ if(rp->siz == 4)
+ rp->add = e->e32(sect->base+rp->off);
+ else if(rp->siz == 8)
+ rp->add = e->e64(sect->base+rp->off);
+ else
+ diag("invalid rela size %d", rp->siz);
+ }
+ }
+ qsort(r, n, sizeof r[0], rbyoff); // just in case
+
+ s = sect->sym;
+ s->r = r;
+ s->nr = n;
+ }
+
+ // enter sub-symbols into symbol table.
+ // symbol 0 is the null symbol.
+ for(i=1; i<obj->nsymtab; i++) {
+ if(readsym(obj, i, &sym) < 0)
+ goto bad;
+ if(sym.type != ElfSymTypeFunc && sym.type != ElfSymTypeObject && sym.type != ElfSymTypeNone)
+ continue;
+ if(sym.shndx == ElfSymShnCommon) {
+ s = sym.sym;
+ if(s->size < sym.size)
+ s->size = sym.size;
+ if(s->type == 0 || s->type == SXREF)
+ s->type = SBSS;
+ continue;
+ }
+ if(sym.shndx >= obj->nsect || sym.shndx == 0)
+ continue;
+ sect = obj->sect+sym.shndx;
+ if(sect->sym == nil) {
+ diag("%s: sym#%d: ignoring %s in section %d (type %d)", pn, i, sym.name, sym.shndx, sym.type);
+ continue;
+ }
+ s = sym.sym;
+ s->sub = sect->sym->sub;
+ sect->sym->sub = s;
+ s->type = sect->sym->type | SSUB;
+ if(!s->dynexport) {
+ s->dynimplib = nil; // satisfy dynimport
+ s->dynimpname = nil; // satisfy dynimport
+ }
+ s->value = sym.value;
+ s->size = sym.size;
+ s->outer = sect->sym;
+ if(sect->sym->type == STEXT) {
+ Prog *p;
+
+ if(s->text != P)
+ diag("%s: duplicate definition of %s", pn, s->name);
+ // build a TEXT instruction with a unique pc
+ // just to make the rest of the linker happy.
+ p = prg();
+ p->as = ATEXT;
+ p->from.type = D_EXTERN;
+ p->from.sym = s;
+ p->textflag = 7;
+ p->to.type = D_CONST;
+ p->link = nil;
+ p->pc = pc++;
+ s->text = p;
+
+ etextp->next = s;
+ etextp = s;
+ }
+ }
+ return;
+
+bad:
+ diag("%s: malformed elf file: %r", pn);
+}
+
+static ElfSect*
+section(ElfObj *obj, char *name)
+{
+ int i;
+
+ for(i=0; i<obj->nsect; i++)
+ if(obj->sect[i].name && name && strcmp(obj->sect[i].name, name) == 0)
+ return &obj->sect[i];
+ return nil;
+}
+
+static int
+map(ElfObj *obj, ElfSect *sect)
+{
+ if(sect->base != nil)
+ return 0;
+
+ if(sect->off+sect->size > obj->len) {
+ werrstr("elf section past end of file");
+ return -1;
+ }
+
+ sect->base = mal(sect->size);
+ werrstr("short read");
+ if(Bseek(obj->f, obj->base+sect->off, 0) < 0 || Bread(obj->f, sect->base, sect->size) != sect->size)
+ return -1;
+
+ return 0;
+}
+
+static int
+readsym(ElfObj *obj, int i, ElfSym *sym)
+{
+ Sym *s;
+
+ if(i >= obj->nsymtab || i < 0) {
+ werrstr("invalid elf symbol index");
+ return -1;
+ }
+
+ if(obj->is64) {
+ ElfSymBytes64 *b;
+
+ b = (ElfSymBytes64*)(obj->symtab->base + i*sizeof *b);
+ sym->name = (char*)obj->symstr->base + obj->e->e32(b->name);
+ sym->value = obj->e->e64(b->value);
+ sym->size = obj->e->e64(b->size);
+ sym->shndx = obj->e->e16(b->shndx);
+ sym->bind = b->info>>4;
+ sym->type = b->info&0xf;
+ sym->other = b->other;
+ } else {
+ ElfSymBytes *b;
+
+ b = (ElfSymBytes*)(obj->symtab->base + i*sizeof *b);
+ sym->name = (char*)obj->symstr->base + obj->e->e32(b->name);
+ sym->value = obj->e->e32(b->value);
+ sym->size = obj->e->e32(b->size);
+ sym->shndx = obj->e->e16(b->shndx);
+ sym->bind = b->info>>4;
+ sym->type = b->info&0xf;
+ sym->other = b->other;
+ }
+
+ s = nil;
+ if(strcmp(sym->name, "_GLOBAL_OFFSET_TABLE_") == 0)
+ sym->name = ".got";
+ if(strcmp(sym->name, "__stack_chk_fail_local") == 0)
+ sym->other = 0; // rewrite hidden -> default visibility
+ switch(sym->type) {
+ case ElfSymTypeSection:
+ s = obj->sect[sym->shndx].sym;
+ break;
+ case ElfSymTypeObject:
+ case ElfSymTypeFunc:
+ case ElfSymTypeNone:
+ switch(sym->bind) {
+ case ElfSymBindGlobal:
+ if(sym->other != 2) {
+ s = lookup(sym->name, 0);
+ break;
+ }
+ // fall through
+ case ElfSymBindLocal:
+ s = lookup(sym->name, version);
+ break;
+ default:
+ werrstr("%s: invalid symbol binding %d", sym->name, sym->bind);
+ return -1;
+ }
+ break;
+ }
+ if(s != nil && s->type == 0 && sym->type != ElfSymTypeSection)
+ s->type = SXREF;
+ sym->sym = s;
+
+ return 0;
+}
+
+int
+rbyoff(const void *va, const void *vb)
+{
+ Reloc *a, *b;
+
+ a = (Reloc*)va;
+ b = (Reloc*)vb;
+ if(a->off < b->off)
+ return -1;
+ if(a->off > b->off)
+ return +1;
+ return 0;
+}
+
+#define R(x, y) ((x)|((y)<<24))
+
+static int
+reltype(char *pn, int elftype, uchar *siz)
+{
+ switch(R(thechar, elftype)) {
+ default:
+ diag("%s: unknown relocation type %d; compiled without -fpic?", pn, elftype);
+ case R('6', R_X86_64_PC32):
+ case R('6', R_X86_64_PLT32):
+ case R('6', R_X86_64_GOTPCREL):
+ case R('8', R_386_32):
+ case R('8', R_386_PC32):
+ case R('8', R_386_GOT32):
+ case R('8', R_386_PLT32):
+ case R('8', R_386_GOTOFF):
+ case R('8', R_386_GOTPC):
+ *siz = 4;
+ break;
+ case R('6', R_X86_64_64):
+ *siz = 8;
+ break;
+ }
+
+ return 256+elftype;
+}
diff --git a/src/cmd/ld/ldmacho.c b/src/cmd/ld/ldmacho.c
new file mode 100644
index 000000000..7e38db0e4
--- /dev/null
+++ b/src/cmd/ld/ldmacho.c
@@ -0,0 +1,794 @@
+/*
+Derived from Plan 9 from User Space's src/libmach/elf.h, elf.c
+http://code.swtch.com/plan9port/src/tip/src/libmach/
+
+ Copyright © 2004 Russ Cox.
+ Portions Copyright © 2008-2010 Google Inc.
+ Portions Copyright © 2010 The Go Authors.
+
+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 "l.h"
+#include "lib.h"
+
+enum {
+ MACHO_FAKE_GOTPCREL = 100, // from macho.h
+
+ N_EXT = 0x01,
+ N_TYPE = 0x1e,
+ N_STAB = 0xe0,
+};
+
+typedef struct MachoObj MachoObj;
+typedef struct MachoCmd MachoCmd;
+typedef struct MachoSeg MachoSeg;
+typedef struct MachoSect MachoSect;
+typedef struct MachoRel MachoRel;
+typedef struct MachoSymtab MachoSymtab;
+typedef struct MachoSym MachoSym;
+typedef struct MachoDysymtab MachoDysymtab;
+
+enum
+{
+ MachoCpuVax = 1,
+ MachoCpu68000 = 6,
+ MachoCpu386 = 7,
+ MachoCpuAmd64 = 0x1000007,
+ MachoCpuMips = 8,
+ MachoCpu98000 = 10,
+ MachoCpuHppa = 11,
+ MachoCpuArm = 12,
+ MachoCpu88000 = 13,
+ MachoCpuSparc = 14,
+ MachoCpu860 = 15,
+ MachoCpuAlpha = 16,
+ MachoCpuPower = 18,
+
+ MachoCmdSegment = 1,
+ MachoCmdSymtab = 2,
+ MachoCmdSymseg = 3,
+ MachoCmdThread = 4,
+ MachoCmdDysymtab = 11,
+ MachoCmdSegment64 = 25,
+
+ MachoFileObject = 1,
+ MachoFileExecutable = 2,
+ MachoFileFvmlib = 3,
+ MachoFileCore = 4,
+ MachoFilePreload = 5,
+};
+
+struct MachoSeg
+{
+ char name[16+1];
+ uint64 vmaddr;
+ uint64 vmsize;
+ uint32 fileoff;
+ uint32 filesz;
+ uint32 maxprot;
+ uint32 initprot;
+ uint32 nsect;
+ uint32 flags;
+ MachoSect *sect;
+};
+
+struct MachoSect
+{
+ char name[16+1];
+ char segname[16+1];
+ uint64 addr;
+ uint64 size;
+ uint32 off;
+ uint32 align;
+ uint32 reloff;
+ uint32 nreloc;
+ uint32 flags;
+ uint32 res1;
+ uint32 res2;
+ Sym *sym;
+
+ MachoRel *rel;
+};
+
+struct MachoRel
+{
+ uint32 addr;
+ uint32 symnum;
+ uint8 pcrel;
+ uint8 length;
+ uint8 extrn;
+ uint8 type;
+ uint8 scattered;
+ uint32 value;
+};
+
+struct MachoSymtab
+{
+ uint32 symoff;
+ uint32 nsym;
+ uint32 stroff;
+ uint32 strsize;
+
+ char *str;
+ MachoSym *sym;
+};
+
+struct MachoSym
+{
+ char *name;
+ uint8 type;
+ uint8 sectnum;
+ uint16 desc;
+ char kind;
+ uint64 value;
+ Sym *sym;
+};
+
+struct MachoDysymtab
+{
+ uint32 ilocalsym;
+ uint32 nlocalsym;
+ uint32 iextdefsym;
+ uint32 nextdefsym;
+ uint32 iundefsym;
+ uint32 nundefsym;
+ uint32 tocoff;
+ uint32 ntoc;
+ uint32 modtaboff;
+ uint32 nmodtab;
+ uint32 extrefsymoff;
+ uint32 nextrefsyms;
+ uint32 indirectsymoff;
+ uint32 nindirectsyms;
+ uint32 extreloff;
+ uint32 nextrel;
+ uint32 locreloff;
+ uint32 nlocrel;
+ uint32 *indir;
+};
+
+struct MachoCmd
+{
+ int type;
+ uint32 off;
+ uint32 size;
+ MachoSeg seg;
+ MachoSymtab sym;
+ MachoDysymtab dsym;
+};
+
+struct MachoObj
+{
+ Biobuf *f;
+ int64 base; // off in f where Mach-O begins
+ int64 len; // length of Mach-O
+ int is64;
+ char *name;
+
+ Endian *e;
+ uint cputype;
+ uint subcputype;
+ uint32 filetype;
+ uint32 flags;
+ MachoCmd *cmd;
+ uint ncmd;
+};
+
+static int
+unpackcmd(uchar *p, MachoObj *m, MachoCmd *c, uint type, uint sz)
+{
+ uint32 (*e4)(uchar*);
+ uint64 (*e8)(uchar*);
+ MachoSect *s;
+ int i;
+
+ e4 = m->e->e32;
+ e8 = m->e->e64;
+
+ c->type = type;
+ c->size = sz;
+ switch(type){
+ default:
+ return -1;
+ case MachoCmdSegment:
+ if(sz < 56)
+ return -1;
+ strecpy(c->seg.name, c->seg.name+sizeof c->seg.name, (char*)p+8);
+ c->seg.vmaddr = e4(p+24);
+ c->seg.vmsize = e4(p+28);
+ c->seg.fileoff = e4(p+32);
+ c->seg.filesz = e4(p+36);
+ c->seg.maxprot = e4(p+40);
+ c->seg.initprot = e4(p+44);
+ c->seg.nsect = e4(p+48);
+ c->seg.flags = e4(p+52);
+ c->seg.sect = mal(c->seg.nsect * sizeof c->seg.sect[0]);
+ if(sz < 56+c->seg.nsect*68)
+ return -1;
+ p += 56;
+ for(i=0; i<c->seg.nsect; i++) {
+ s = &c->seg.sect[i];
+ strecpy(s->name, s->name+sizeof s->name, (char*)p+0);
+ strecpy(s->segname, s->segname+sizeof s->segname, (char*)p+16);
+ s->addr = e4(p+32);
+ s->size = e4(p+36);
+ s->off = e4(p+40);
+ s->align = e4(p+44);
+ s->reloff = e4(p+48);
+ s->nreloc = e4(p+52);
+ s->flags = e4(p+56);
+ s->res1 = e4(p+60);
+ s->res2 = e4(p+64);
+ p += 68;
+ }
+ break;
+ case MachoCmdSegment64:
+ if(sz < 72)
+ return -1;
+ strecpy(c->seg.name, c->seg.name+sizeof c->seg.name, (char*)p+8);
+ c->seg.vmaddr = e8(p+24);
+ c->seg.vmsize = e8(p+32);
+ c->seg.fileoff = e8(p+40);
+ c->seg.filesz = e8(p+48);
+ c->seg.maxprot = e4(p+56);
+ c->seg.initprot = e4(p+60);
+ c->seg.nsect = e4(p+64);
+ c->seg.flags = e4(p+68);
+ c->seg.sect = mal(c->seg.nsect * sizeof c->seg.sect[0]);
+ if(sz < 72+c->seg.nsect*80)
+ return -1;
+ p += 72;
+ for(i=0; i<c->seg.nsect; i++) {
+ s = &c->seg.sect[i];
+ strecpy(s->name, s->name+sizeof s->name, (char*)p+0);
+ strecpy(s->segname, s->segname+sizeof s->segname, (char*)p+16);
+ s->addr = e8(p+32);
+ s->size = e8(p+40);
+ s->off = e4(p+48);
+ s->align = e4(p+52);
+ s->reloff = e4(p+56);
+ s->nreloc = e4(p+60);
+ s->flags = e4(p+64);
+ s->res1 = e4(p+68);
+ s->res2 = e4(p+72);
+ // p+76 is reserved
+ p += 80;
+ }
+ break;
+ case MachoCmdSymtab:
+ if(sz < 24)
+ return -1;
+ c->sym.symoff = e4(p+8);
+ c->sym.nsym = e4(p+12);
+ c->sym.stroff = e4(p+16);
+ c->sym.strsize = e4(p+20);
+ break;
+ case MachoCmdDysymtab:
+ if(sz < 80)
+ return -1;
+ c->dsym.ilocalsym = e4(p+8);
+ c->dsym.nlocalsym = e4(p+12);
+ c->dsym.iextdefsym = e4(p+16);
+ c->dsym.nextdefsym = e4(p+20);
+ c->dsym.iundefsym = e4(p+24);
+ c->dsym.nundefsym = e4(p+28);
+ c->dsym.tocoff = e4(p+32);
+ c->dsym.ntoc = e4(p+36);
+ c->dsym.modtaboff = e4(p+40);
+ c->dsym.nmodtab = e4(p+44);
+ c->dsym.extrefsymoff = e4(p+48);
+ c->dsym.nextrefsyms = e4(p+52);
+ c->dsym.indirectsymoff = e4(p+56);
+ c->dsym.nindirectsyms = e4(p+60);
+ c->dsym.extreloff = e4(p+64);
+ c->dsym.nextrel = e4(p+68);
+ c->dsym.locreloff = e4(p+72);
+ c->dsym.nlocrel = e4(p+76);
+ break;
+ }
+ return 0;
+}
+
+static int
+macholoadrel(MachoObj *m, MachoSect *sect)
+{
+ MachoRel *rel, *r;
+ uchar *buf, *p;
+ int i, n;
+ uint32 v;
+
+ if(sect->rel != nil || sect->nreloc == 0)
+ return 0;
+ rel = mal(sect->nreloc * sizeof r[0]);
+ n = sect->nreloc * 8;
+ buf = mal(n);
+ if(Bseek(m->f, m->base + sect->reloff, 0) < 0 || Bread(m->f, buf, n) != n)
+ return -1;
+ for(i=0; i<sect->nreloc; i++) {
+ r = &rel[i];
+ p = buf+i*8;
+ r->addr = m->e->e32(p);
+
+ // TODO(rsc): Wrong interpretation for big-endian bitfields?
+ if(r->addr & 0x80000000) {
+ // scatterbrained relocation
+ r->scattered = 1;
+ v = r->addr >> 24;
+ r->addr &= 0xFFFFFF;
+ r->type = v & 0xF;
+ v >>= 4;
+ r->length = 1<<(v&3);
+ v >>= 2;
+ r->pcrel = v & 1;
+ r->value = m->e->e32(p+4);
+ } else {
+ v = m->e->e32(p+4);
+ r->symnum = v & 0xFFFFFF;
+ v >>= 24;
+ r->pcrel = v&1;
+ v >>= 1;
+ r->length = 1<<(v&3);
+ v >>= 2;
+ r->extrn = v&1;
+ v >>= 1;
+ r->type = v;
+ }
+ }
+ sect->rel = rel;
+ return 0;
+}
+
+static int
+macholoaddsym(MachoObj *m, MachoDysymtab *d)
+{
+ uchar *p;
+ int i, n;
+
+ n = d->nindirectsyms;
+
+ p = mal(n*4);
+ if(Bseek(m->f, m->base + d->indirectsymoff, 0) < 0 || Bread(m->f, p, n*4) != n*4)
+ return -1;
+
+ d->indir = (uint32*)p;
+ for(i=0; i<n; i++)
+ d->indir[i] = m->e->e32(p+4*i);
+ return 0;
+}
+
+static int
+macholoadsym(MachoObj *m, MachoSymtab *symtab)
+{
+ char *strbuf;
+ uchar *symbuf, *p;
+ int i, n, symsize;
+ MachoSym *sym, *s;
+ uint32 v;
+
+ if(symtab->sym != nil)
+ return 0;
+
+ strbuf = mal(symtab->strsize);
+ if(Bseek(m->f, m->base + symtab->stroff, 0) < 0 || Bread(m->f, strbuf, symtab->strsize) != symtab->strsize)
+ return -1;
+
+ symsize = 12;
+ if(m->is64)
+ symsize = 16;
+ n = symtab->nsym * symsize;
+ symbuf = mal(n);
+ if(Bseek(m->f, m->base + symtab->symoff, 0) < 0 || Bread(m->f, symbuf, n) != n)
+ return -1;
+ sym = mal(symtab->nsym * sizeof sym[0]);
+ p = symbuf;
+ for(i=0; i<symtab->nsym; i++) {
+ s = &sym[i];
+ v = m->e->e32(p);
+ if(v >= symtab->strsize)
+ return -1;
+ s->name = strbuf + v;
+ s->type = p[4];
+ s->sectnum = p[5];
+ s->desc = m->e->e16(p+6);
+ if(m->is64)
+ s->value = m->e->e64(p+8);
+ else
+ s->value = m->e->e32(p+8);
+ p += symsize;
+ }
+ symtab->str = strbuf;
+ symtab->sym = sym;
+ return 0;
+}
+
+void
+ldmacho(Biobuf *f, char *pkg, int64 len, char *pn)
+{
+ int i, j, is64;
+ uchar hdr[7*4], *cmdp;
+ uchar tmp[4];
+ uchar *dat;
+ ulong ncmd, cmdsz, ty, sz, off;
+ MachoObj *m;
+ Endian *e;
+ int64 base;
+ MachoSect *sect;
+ MachoRel *rel;
+ Sym *s, *outer;
+ MachoCmd *c;
+ MachoSymtab *symtab;
+ MachoDysymtab *dsymtab;
+ MachoSym *sym;
+ Reloc *r, *rp;
+ char *name;
+
+ version++;
+ base = Boffset(f);
+ if(Bread(f, hdr, sizeof hdr) != sizeof hdr)
+ goto bad;
+
+ if((be.e32(hdr)&~1) == 0xFEEDFACE){
+ e = &be;
+ }else if((le.e32(hdr)&~1) == 0xFEEDFACE){
+ e = &le;
+ }else{
+ werrstr("bad magic - not mach-o file");
+ goto bad;
+ }
+
+ is64 = e->e32(hdr) == 0xFEEDFACF;
+ ncmd = e->e32(hdr+4*4);
+ cmdsz = e->e32(hdr+5*4);
+ if(ncmd > 0x10000 || cmdsz >= 0x01000000){
+ werrstr("implausible mach-o header ncmd=%lud cmdsz=%lud", ncmd, cmdsz);
+ goto bad;
+ }
+ if(is64)
+ Bread(f, tmp, 4); // skip reserved word in header
+
+ m = mal(sizeof(*m)+ncmd*sizeof(MachoCmd)+cmdsz);
+ m->f = f;
+ m->e = e;
+ m->cputype = e->e32(hdr+1*4);
+ m->subcputype = e->e32(hdr+2*4);
+ m->filetype = e->e32(hdr+3*4);
+ m->ncmd = ncmd;
+ m->flags = e->e32(hdr+6*4);
+ m->is64 = is64;
+ m->base = base;
+ m->len = len;
+ m->name = pn;
+
+ switch(thechar) {
+ default:
+ diag("%s: mach-o %s unimplemented", thestring);
+ return;
+ case '6':
+ if(e != &le || m->cputype != MachoCpuAmd64) {
+ diag("%s: mach-o object but not amd64", pn);
+ return;
+ }
+ break;
+ case '8':
+ if(e != &le || m->cputype != MachoCpu386) {
+ diag("%s: mach-o object but not 386", pn);
+ return;
+ }
+ break;
+ }
+
+ m->cmd = (MachoCmd*)(m+1);
+ off = sizeof hdr;
+ cmdp = (uchar*)(m->cmd+ncmd);
+ if(Bread(f, cmdp, cmdsz) != cmdsz){
+ werrstr("reading cmds: %r");
+ goto bad;
+ }
+
+ // read and parse load commands
+ c = nil;
+ symtab = nil;
+ dsymtab = nil;
+ for(i=0; i<ncmd; i++){
+ ty = e->e32(cmdp);
+ sz = e->e32(cmdp+4);
+ m->cmd[i].off = off;
+ unpackcmd(cmdp, m, &m->cmd[i], ty, sz);
+ cmdp += sz;
+ off += sz;
+ if(ty == MachoCmdSymtab) {
+ if(symtab != nil) {
+ werrstr("multiple symbol tables");
+ goto bad;
+ }
+ symtab = &m->cmd[i].sym;
+ macholoadsym(m, symtab);
+ }
+ if(ty == MachoCmdDysymtab) {
+ dsymtab = &m->cmd[i].dsym;
+ macholoaddsym(m, dsymtab);
+ }
+ if((is64 && ty == MachoCmdSegment64) || (!is64 && ty == MachoCmdSegment)) {
+ if(c != nil) {
+ werrstr("multiple load commands");
+ goto bad;
+ }
+ c = &m->cmd[i];
+ }
+ }
+
+ // load text and data segments into memory.
+ // they are not as small as the load commands, but we'll need
+ // the memory anyway for the symbol images, so we might
+ // as well use one large chunk.
+ if(c == nil) {
+ werrstr("no load command");
+ goto bad;
+ }
+ if(symtab == nil) {
+ // our work is done here - no symbols means nothing can refer to this file
+ return;
+ }
+
+ if(c->seg.fileoff+c->seg.filesz >= len) {
+ werrstr("load segment out of range");
+ goto bad;
+ }
+
+ dat = mal(c->seg.filesz);
+ if(Bseek(f, m->base + c->seg.fileoff, 0) < 0 || Bread(f, dat, c->seg.filesz) != c->seg.filesz) {
+ werrstr("cannot load object data: %r");
+ goto bad;
+ }
+
+ for(i=0; i<c->seg.nsect; i++) {
+ sect = &c->seg.sect[i];
+ if(strcmp(sect->segname, "__TEXT") != 0 && strcmp(sect->segname, "__DATA") != 0)
+ continue;
+ if(strcmp(sect->name, "__eh_frame") == 0)
+ continue;
+ name = smprint("%s(%s/%s)", pn, sect->segname, sect->name);
+ s = lookup(name, version);
+ if(s->type != 0) {
+ werrstr("duplicate %s/%s", sect->segname, sect->name);
+ goto bad;
+ }
+ free(name);
+ s->p = dat + sect->addr - c->seg.vmaddr;
+ s->np = sect->size;
+ s->size = s->np;
+
+ if(strcmp(sect->segname, "__TEXT") == 0) {
+ if(strcmp(sect->name, "__text") == 0)
+ s->type = STEXT;
+ else
+ s->type = SRODATA;
+ } else {
+ s->type = SDATA;
+ }
+ if(s->type == STEXT) {
+ if(etextp)
+ etextp->next = s;
+ else
+ textp = s;
+ etextp = s;
+ }
+ sect->sym = s;
+ }
+
+ // enter sub-symbols into symbol table.
+ // have to guess sizes from next symbol.
+ for(i=0; i<symtab->nsym; i++) {
+ int v;
+ sym = &symtab->sym[i];
+ if(sym->type&N_STAB)
+ continue;
+ // TODO: check sym->type against outer->type.
+ name = sym->name;
+ if(name[0] == '_' && name[1] != '\0')
+ name++;
+ v = 0;
+ if(!(sym->type&N_EXT))
+ v = version;
+ s = lookup(name, v);
+ sym->sym = s;
+ if(sym->sectnum == 0) // undefined
+ continue;
+ if(sym->sectnum > c->seg.nsect) {
+ werrstr("reference to invalid section %d", sym->sectnum);
+ goto bad;
+ }
+ sect = &c->seg.sect[sym->sectnum-1];
+ outer = sect->sym;
+ if(outer == nil) {
+ werrstr("reference to invalid section %s/%s", sect->segname, sect->name);
+ continue;
+ }
+ s->type = outer->type | SSUB;
+ s->sub = outer->sub;
+ outer->sub = s;
+ s->outer = outer;
+ s->value = sym->value - sect->addr;
+ if(i+1 < symtab->nsym)
+ s->size = (sym+1)->value - sym->value;
+ else
+ s->size = sect->addr + sect->size - sym->value;
+ if(!s->dynexport) {
+ s->dynimplib = nil; // satisfy dynimport
+ s->dynimpname = nil; // satisfy dynimport
+ }
+ if(outer->type == STEXT) {
+ Prog *p;
+
+ if(s->text != P)
+ diag("%s sym#%d: duplicate definition of %s", pn, i, s->name);
+ // build a TEXT instruction with a unique pc
+ // just to make the rest of the linker happy.
+ // TODO: this is too 6l-specific ?
+ p = prg();
+ p->as = ATEXT;
+ p->from.type = D_EXTERN;
+ p->from.sym = s;
+ p->textflag = 7;
+ p->to.type = D_CONST;
+ p->link = nil;
+ p->pc = pc++;
+ s->text = p;
+
+ etextp->next = s;
+ etextp = s;
+ }
+ sym->sym = s;
+ }
+
+ // load relocations
+ for(i=0; i<c->seg.nsect; i++) {
+ sect = &c->seg.sect[i];
+ if((s = sect->sym) == S)
+ continue;
+ macholoadrel(m, sect);
+ if(sect->rel == nil)
+ continue;
+ r = mal(sect->nreloc*sizeof r[0]);
+ rp = r;
+ rel = sect->rel;
+ for(j=0; j<sect->nreloc; j++, rel++) {
+ if(rel->scattered) {
+ int k;
+ MachoSect *ks;
+
+ if(thechar != '8')
+ diag("unexpected scattered relocation");
+
+ // on 386, rewrite scattered 4/1 relocation into
+ // the pseudo-pc-relative reference that it is.
+ // assume that the second in the pair is in this section
+ // and use that as the pc-relative base.
+ if(thechar != '8' || rel->type != 4 || j+1 >= sect->nreloc ||
+ !(rel+1)->scattered || (rel+1)->type != 1 ||
+ (rel+1)->value < sect->addr || (rel+1)->value >= sect->addr+sect->size) {
+ werrstr("unsupported scattered relocation %d/%d", (int)rel->type, (int)(rel+1)->type);
+ goto bad;
+ }
+ rp->siz = rel->length;
+ rp->off = rel->addr;
+
+ // NOTE(rsc): I haven't worked out why (really when)
+ // we should ignore the addend on a
+ // scattered relocation, but it seems that the
+ // common case is we ignore it.
+ // It's likely that this is not strictly correct
+ // and that the math should look something
+ // like the non-scattered case below.
+ rp->add = 0;
+
+ // want to make it pc-relative aka relative to rp->off+4
+ // but the scatter asks for relative to off = (rel+1)->value - sect->addr.
+ // adjust rp->add accordingly.
+ rp->type = D_PCREL;
+ rp->add += (rp->off+4) - ((rel+1)->value - sect->addr);
+
+ // now consider the desired symbol.
+ // find the section where it lives.
+ for(k=0; k<c->seg.nsect; k++) {
+ ks = &c->seg.sect[k];
+ if(ks->addr <= rel->value && rel->value < ks->addr+ks->size)
+ goto foundk;
+ }
+ werrstr("unsupported scattered relocation: invalid address %#ux", rel->addr);
+ goto bad;
+ foundk:
+ if(ks->sym != S) {
+ rp->sym = ks->sym;
+ rp->add += rel->value - ks->addr;
+ } else if(strcmp(ks->segname, "__IMPORT") == 0 && strcmp(ks->name, "__pointers") == 0) {
+ // handle reference to __IMPORT/__pointers.
+ // how much worse can this get?
+ // why are we supporting 386 on the mac anyway?
+ rp->type = 512 + MACHO_FAKE_GOTPCREL;
+ // figure out which pointer this is a reference to.
+ k = ks->res1 + (rel->value - ks->addr) / 4;
+ // load indirect table for __pointers
+ // fetch symbol number
+ if(dsymtab == nil || k < 0 || k >= dsymtab->nindirectsyms || dsymtab->indir == nil) {
+ werrstr("invalid scattered relocation: indirect symbol reference out of range");
+ goto bad;
+ }
+ k = dsymtab->indir[k];
+ if(k < 0 || k >= symtab->nsym) {
+ werrstr("invalid scattered relocation: symbol reference out of range");
+ goto bad;
+ }
+ rp->sym = symtab->sym[k].sym;
+ } else {
+ werrstr("unsupported scattered relocation: reference to %s/%s", ks->segname, ks->name);
+ goto bad;
+ }
+ rp++;
+ // skip #1 of 2 rel; continue skips #2 of 2.
+ rel++;
+ j++;
+ continue;
+ }
+
+ rp->siz = rel->length;
+ rp->type = 512 + (rel->type<<1) + rel->pcrel;
+ rp->off = rel->addr;
+
+ rp->add = e->e32(s->p+rp->off);
+ // For i386 Mach-O PC-relative, the addend is written such that
+ // it *is* the PC being subtracted. Use that to make
+ // it match our version of PC-relative.
+ if(rel->pcrel && thechar == '8')
+ rp->add += rp->off+rp->siz;
+ if(!rel->extrn) {
+ if(rel->symnum < 1 || rel->symnum > c->seg.nsect) {
+ werrstr("invalid relocation: section reference out of range %d vs %d", rel->symnum, c->seg.nsect);
+ goto bad;
+ }
+ rp->sym = c->seg.sect[rel->symnum-1].sym;
+ if(rp->sym == nil) {
+ werrstr("invalid relocation: %s", c->seg.sect[rel->symnum-1].name);
+ goto bad;
+ }
+ // References to symbols in other sections
+ // include that information in the addend.
+ // We only care about the delta from the
+ // section base.
+ if(thechar == '8')
+ rp->add -= c->seg.sect[rel->symnum-1].addr;
+ } else {
+ if(rel->symnum >= symtab->nsym) {
+ werrstr("invalid relocation: symbol reference out of range");
+ goto bad;
+ }
+ rp->sym = symtab->sym[rel->symnum].sym;
+ }
+ rp++;
+ }
+ qsort(r, rp - r, sizeof r[0], rbyoff);
+ s->r = r;
+ s->nr = rp - r;
+ }
+ return;
+
+bad:
+ diag("%s: malformed mach-o file: %r", pn);
+}
diff --git a/src/cmd/ld/lib.c b/src/cmd/ld/lib.c
index 1af9f7a41..ae77247c3 100644
--- a/src/cmd/ld/lib.c
+++ b/src/cmd/ld/lib.c
@@ -1,5 +1,6 @@
-// Derived from Inferno utils/6l/obj.c
+// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
@@ -118,7 +119,7 @@ addlib(char *src, char *obj)
}
for(; i<histfrogp; i++) {
- snprint(comp, sizeof comp, histfrog[i]->name+1);
+ snprint(comp, sizeof comp, "%s", histfrog[i]->name+1);
for(;;) {
p = strstr(comp, "$O");
if(p == 0)
@@ -146,6 +147,22 @@ addlib(char *src, char *obj)
strcat(name, comp);
}
cleanname(name);
+
+ // runtime.a -> runtime
+ p = nil;
+ if(strlen(name) > 2 && name[strlen(name)-2] == '.') {
+ p = name+strlen(name)-2;
+ *p = '\0';
+ }
+
+ // already loaded?
+ for(i=0; i<libraryp; i++)
+ if(strcmp(library[i].pkg, name) == 0)
+ return;
+
+ // runtime -> runtime.a for search
+ if(p != nil)
+ *p = '.';
if(search) {
// try dot, -L "libdir", and then goroot.
@@ -159,8 +176,8 @@ addlib(char *src, char *obj)
cleanname(pname);
/* runtime.a -> runtime */
- if(strlen(name) > 2 && name[strlen(name)-2] == '.')
- name[strlen(name)-2] = '\0';
+ if(p != nil)
+ *p = '\0';
if(debug['v'])
Bprint(&bso, "%5.2f addlib: %s %s pulls in %s\n", cputime(), obj, src, pname);
@@ -186,9 +203,9 @@ addlibpath(char *srcref, char *objref, char *file, char *pkg)
if(strcmp(file, library[i].file) == 0)
return;
- if(debug['v'])
+ if(debug['v'] > 1)
Bprint(&bso, "%5.2f addlibpath: srcref: %s objref: %s file: %s pkg: %s\n",
- cputime(), srcref, objref, file, pkg);
+ cputime(), srcref, objref, file, pkg);
if(libraryp == nlibrary){
nlibrary = 50 + 2*libraryp;
@@ -219,8 +236,6 @@ loadlib(void)
{
char pname[1024];
int i, found;
- int32 h;
- Sym *s;
found = 0;
for(i=0; i<nlibdir; i++) {
@@ -233,47 +248,51 @@ loadlib(void)
break;
}
}
- if(!found) Bprint(&bso, "warning: unable to find runtime.a\n");
+ if(!found)
+ Bprint(&bso, "warning: unable to find runtime.a\n");
-loop:
- xrefresolv = 0;
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);
objfile(library[i].file, library[i].pkg);
}
+}
- if(xrefresolv)
- for(h=0; h<nelem(hash); h++)
- for(s = hash[h]; s != S; s = s->link)
- if(s->type == SXREF)
- goto loop;
-
+/*
+ * look for the next file in an archive.
+ * adapted from libmach.
+ */
+int
+nextar(Biobuf *bp, int off, struct ar_hdr *a)
+{
+ int r;
+ int32 arsize;
+
+ if (off&01)
+ off++;
+ Bseek(bp, off, 0);
+ r = Bread(bp, a, SAR_HDR);
+ if(r != SAR_HDR)
+ return 0;
+ if(strncmp(a->fmag, ARFMAG, sizeof(a->fmag)))
+ return -1;
+ arsize = strtol(a->size, 0, 0);
+ if (arsize&1)
+ arsize++;
+ return arsize + SAR_HDR;
}
void
objfile(char *file, char *pkg)
{
- int32 off, esym, cnt, l;
- int work;
+ int32 off, l;
Biobuf *f;
- Sym *s;
char magbuf[SARMAG];
- char name[100], pname[150];
+ char pname[150];
struct ar_hdr arhdr;
- char *e, *start, *stop, *x;
pkg = smprint("%i", pkg);
- if(file[0] == '-' && file[1] == 'l') { // TODO: fix this
- if(debug['9'])
- sprint(name, "/%s/lib/lib", thestring);
- else
- sprint(name, "/usr/%clib/lib", thechar);
- strcat(name, file+2);
- strcat(name, ".a");
- file = name;
- }
if(debug['v'])
Bprint(&bso, "%5.2f ldobj: %s (%s)\n", cputime(), file, pkg);
Bflush(&bso);
@@ -291,9 +310,10 @@ objfile(char *file, char *pkg)
Bterm(f);
return;
}
-
- l = Bread(f, &arhdr, SAR_HDR);
- if(l != SAR_HDR) {
+
+ /* skip over __.SYMDEF */
+ off = Boffset(f);
+ if((l = nextar(f, off, &arhdr)) <= 0) {
diag("%s: short read on archive file symbol header", file);
goto out;
}
@@ -301,88 +321,52 @@ objfile(char *file, char *pkg)
diag("%s: first entry not symbol header", file);
goto out;
}
-
- esym = SARMAG + SAR_HDR + atolwhex(arhdr.size);
- off = SARMAG + SAR_HDR;
-
- if(debug['u']) {
- struct ar_hdr pkghdr;
- int n;
-
- // Read next ar header to check for package safe bit.
- Bseek(f, esym+(esym&1), 0);
- l = Bread(f, &pkghdr, SAR_HDR);
- if(l != SAR_HDR) {
- diag("%s: short read on second archive header", file);
- goto out;
- }
- if(strncmp(pkghdr.name, pkgname, strlen(pkgname))) {
- diag("%s: second entry not package header", file);
- goto out;
- }
- n = atolwhex(pkghdr.size);
- ldpkg(f, pkg, n, file, Pkgdef);
+ off += l;
+
+ /* skip over (or process) __.PKGDEF */
+ if((l = nextar(f, off, &arhdr)) <= 0) {
+ diag("%s: short read on archive file symbol header", file);
+ goto out;
}
+ if(strncmp(arhdr.name, pkgname, strlen(pkgname))) {
+ diag("%s: second entry not package header", file);
+ goto out;
+ }
+ off += l;
+
+ if(debug['u'])
+ ldpkg(f, pkg, atolwhex(arhdr.size), file, Pkgdef);
/*
- * just bang the whole symbol file into memory
+ * load all the object files from the archive now.
+ * this gives us sequential file access and keeps us
+ * from needing to come back later to pick up more
+ * objects. it breaks the usual C archive model, but
+ * this is Go, not C. the common case in Go is that
+ * we need to load all the objects, and then we throw away
+ * the individual symbols that are unused.
+ *
+ * loading every object will also make it possible to
+ * load foreign objects not referenced by __.SYMDEF.
*/
- Bseek(f, off, 0);
- cnt = esym - off;
- start = mal(cnt + 10);
- cnt = Bread(f, start, cnt);
- if(cnt <= 0){
- Bterm(f);
- return;
- }
- stop = &start[cnt];
- memset(stop, 0, 10);
-
- work = 1;
- while(work) {
- if(debug['v'])
- Bprint(&bso, "%5.2f library pass: %s\n", cputime(), file);
- Bflush(&bso);
- work = 0;
- for(e = start; e < stop; e = strchr(e+5, 0) + 1) {
- x = expandpkg(e+5, pkg);
- s = lookup(x, 0);
- if(x != e+5)
- free(x);
- if(s->type != SXREF)
- continue;
- sprint(pname, "%s(%s)", file, s->name);
- if(debug['v'])
- Bprint(&bso, "%5.2f library: %s\n", cputime(), pname);
- Bflush(&bso);
- l = e[1] & 0xff;
- l |= (e[2] & 0xff) << 8;
- l |= (e[3] & 0xff) << 16;
- l |= (e[4] & 0xff) << 24;
- Bseek(f, l, 0);
- l = Bread(f, &arhdr, SAR_HDR);
- if(l != SAR_HDR)
- goto bad;
- if(strncmp(arhdr.fmag, ARFMAG, sizeof(arhdr.fmag)))
- goto bad;
- l = SARNAME;
- while(l > 0 && arhdr.name[l-1] == ' ')
- l--;
- sprint(pname, "%s(%.*s)", file, l, arhdr.name);
- l = atolwhex(arhdr.size);
- ldobj(f, pkg, l, pname, ArchiveObj);
- if(s->type == SXREF) {
- diag("%s: failed to load: %s", file, s->name);
- errorexit();
- }
- work = 1;
- xrefresolv = 1;
+ for(;;) {
+ l = nextar(f, off, &arhdr);
+ if(l == 0)
+ break;
+ if(l < 0) {
+ diag("%s: malformed archive", file);
+ goto out;
}
+ off += l;
+
+ l = SARNAME;
+ while(l > 0 && arhdr.name[l-1] == ' ')
+ l--;
+ snprint(pname, sizeof pname, "%s(%.*s)", file, utfnlen(arhdr.name, l), arhdr.name);
+ l = atolwhex(arhdr.size);
+ ldobj(f, pkg, l, pname, ArchiveObj);
}
- return;
-bad:
- diag("%s: bad or out of date archive", file);
out:
Bterm(f);
}
@@ -390,32 +374,38 @@ out:
void
ldobj(Biobuf *f, char *pkg, int64 len, char *pn, int whence)
{
- static int files;
- static char **filen;
- char **nfilen, *line;
- int i, n, c1, c2, c3;
+ char *line;
+ int n, c1, c2, c3, c4;
+ uint32 magic;
vlong import0, import1, eof;
char src[1024];
eof = Boffset(f) + len;
src[0] = '\0';
- // don't load individual object more than once.
- // happens with import of .6 files because of loop in xresolv.
- // doesn't happen with .a because SYMDEF is consulted
- // first to decide whether each individual object file is needed.
- for(i=0; i<files; i++)
- if(strcmp(filen[i], pn) == 0)
- return;
+ pn = strdup(pn);
+
+ USED(c4);
+ USED(magic);
- if((files&15) == 0){
- nfilen = malloc((files+16)*sizeof(char*));
- memmove(nfilen, filen, files*sizeof(char*));
- free(filen);
- filen = nfilen;
+ c1 = Bgetc(f);
+ c2 = Bgetc(f);
+ c3 = Bgetc(f);
+ c4 = Bgetc(f);
+ Bungetc(f);
+ Bungetc(f);
+ Bungetc(f);
+ Bungetc(f);
+
+ magic = c1<<24 | c2<<16 | c3<<8 | c4;
+ if(magic == 0x7f454c46) { // \x7F E L F
+ ldelf(f, pkg, len, pn);
+ return;
+ }
+ if((magic&~1) == 0xfeedface || (magic&~0x01000000) == 0xcefaedfe) {
+ ldmacho(f, pkg, len, pn);
+ return;
}
- pn = strdup(pn);
- filen[files++] = pn;
/* check the header */
line = Brdline(f, '\n');
@@ -478,7 +468,7 @@ lookup(char *symb, int v)
// not if(h < 0) h = ~h, because gcc 4.3 -O2 miscompiles it.
h &= 0xffffff;
h %= NHASH;
- for(s = hash[h]; s != S; s = s->link)
+ for(s = hash[h]; s != S; s = s->hash)
if(s->version == v)
if(memcmp(s->name, symb, l) == 0)
return s;
@@ -487,14 +477,18 @@ lookup(char *symb, int v)
if(debug['v'] > 1)
Bprint(&bso, "lookup %s\n", symb);
+ s->dynid = -1;
+ s->plt = -1;
+ s->got = -1;
s->name = mal(l + 1);
memmove(s->name, symb, l);
- s->link = hash[h];
+ s->hash = hash[h];
s->type = 0;
s->version = v;
s->value = 0;
s->sig = 0;
+ s->size = 0;
hash[h] = s;
nsymbol++;
return s;
@@ -607,8 +601,13 @@ nuxiinit(void)
if(i < 1)
inuxi1[i] = c;
inuxi4[i] = c;
- inuxi8[i] = c;
- inuxi8[i+4] = c+4;
+ if(c == i) {
+ inuxi8[i] = c;
+ inuxi8[i+4] = c+4;
+ } else {
+ inuxi8[i] = c+4;
+ inuxi8[i+4] = c;
+ }
fnuxi4[i] = c;
fnuxi8[i] = c;
fnuxi8[i+4] = c+4;
@@ -732,21 +731,6 @@ ieeedtod(Ieee *ieeep)
}
void
-undefsym(Sym *s)
-{
- int n;
-
- n = imports;
- if(s->value != 0)
- diag("value != 0 on SXREF");
- if(n >= 1<<Rindex)
- diag("import index %d out of range", n);
- s->value = n<<Roffset;
- s->type = SUNDEF;
- imports++;
-}
-
-void
zerosig(char *sp)
{
Sym *s;
@@ -755,47 +739,6 @@ zerosig(char *sp)
s->sig = 0;
}
-void
-readundefs(char *f, int t)
-{
- int i, n;
- Sym *s;
- Biobuf *b;
- char *l, buf[256], *fields[64];
-
- if(f == nil)
- return;
- b = Bopen(f, OREAD);
- if(b == nil){
- diag("could not open %s: %r", f);
- errorexit();
- }
- while((l = Brdline(b, '\n')) != nil){
- n = Blinelen(b);
- if(n >= sizeof(buf)){
- diag("%s: line too long", f);
- errorexit();
- }
- memmove(buf, l, n);
- buf[n-1] = '\0';
- n = getfields(buf, fields, nelem(fields), 1, " \t\r\n");
- if(n == nelem(fields)){
- diag("%s: bad format", f);
- errorexit();
- }
- for(i = 0; i < n; i++){
- s = lookup(fields[i], 0);
- s->type = SXREF;
- s->subtype = t;
- if(t == SIMPORT)
- nimports++;
- else
- nexports++;
- }
- }
- Bterm(b);
-}
-
int32
Bget4(Biobuf *f)
{
@@ -829,15 +772,22 @@ mal(uint32 n)
{
void *v;
- while(n & 7)
- n++;
+ n = (n+7)&~7;
if(n > NHUNK) {
v = malloc(n);
+ if(v == nil) {
+ diag("out of memory");
+ errorexit();
+ }
memset(v, 0, n);
return v;
}
if(n > nhunk) {
hunk = malloc(NHUNK);
+ if(hunk == nil) {
+ diag("out of memory");
+ errorexit();
+ }
nhunk = NHUNK;
}
@@ -849,6 +799,16 @@ mal(uint32 n)
return v;
}
+void
+unmal(void *v, uint32 n)
+{
+ n = (n+7)&~7;
+ if(hunk - n == v) {
+ hunk -= n;
+ nhunk += n;
+ }
+}
+
// Copied from ../gc/subr.c:/^pathtoprefix; must stay in sync.
/*
* Convert raw string to the prefix that will be used in the symbol table.
@@ -901,3 +861,211 @@ iconv(Fmt *fp)
return 0;
}
+void
+mangle(char *file)
+{
+ fprint(2, "%s: mangled input file\n", file);
+ errorexit();
+}
+
+Section*
+addsection(Segment *seg, char *name, int rwx)
+{
+ Section **l;
+ Section *sect;
+
+ for(l=&seg->sect; *l; l=&(*l)->next)
+ ;
+ sect = mal(sizeof *sect);
+ sect->rwx = rwx;
+ sect->name = name;
+ sect->seg = seg;
+ *l = sect;
+ return sect;
+}
+
+void
+ewrite(int fd, void *buf, int n)
+{
+ if(write(fd, buf, n) < 0) {
+ diag("write error: %r");
+ errorexit();
+ }
+}
+
+void
+pclntab(void)
+{
+ vlong oldpc;
+ Prog *p;
+ int32 oldlc, v, s;
+ Sym *sym;
+ uchar *bp;
+
+ sym = lookup("pclntab", 0);
+ sym->type = SRODATA;
+ sym->reachable = 1;
+ if(debug['s'])
+ return;
+
+ oldpc = INITTEXT;
+ oldlc = 0;
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ for(p = cursym->text; p != P; p = p->link) {
+ if(p->line == oldlc || p->as == ATEXT || p->as == ANOP) {
+ if(debug['O'])
+ Bprint(&bso, "%6llux %P\n",
+ (vlong)p->pc, p);
+ continue;
+ }
+ if(debug['O'])
+ Bprint(&bso, "\t\t%6d", lcsize);
+ v = (p->pc - oldpc) / MINLC;
+ while(v) {
+ s = 127;
+ if(v < 127)
+ s = v;
+ symgrow(sym, lcsize+1);
+ bp = sym->p + lcsize;
+ *bp = s+128; /* 129-255 +pc */
+ if(debug['O'])
+ Bprint(&bso, " pc+%d*%d(%d)", s, MINLC, s+128);
+ v -= s;
+ lcsize++;
+ }
+ s = p->line - oldlc;
+ oldlc = p->line;
+ oldpc = p->pc + MINLC;
+ if(s > 64 || s < -64) {
+ symgrow(sym, lcsize+5);
+ bp = sym->p + lcsize;
+ *bp++ = 0; /* 0 vv +lc */
+ *bp++ = s>>24;
+ *bp++ = s>>16;
+ *bp++ = s>>8;
+ *bp = s;
+ if(debug['O']) {
+ if(s > 0)
+ Bprint(&bso, " lc+%d(%d,%d)\n",
+ s, 0, s);
+ else
+ Bprint(&bso, " lc%d(%d,%d)\n",
+ s, 0, s);
+ Bprint(&bso, "%6llux %P\n",
+ (vlong)p->pc, p);
+ }
+ lcsize += 5;
+ continue;
+ }
+ symgrow(sym, lcsize+1);
+ bp = sym->p + lcsize;
+ if(s > 0) {
+ *bp = 0+s; /* 1-64 +lc */
+ if(debug['O']) {
+ Bprint(&bso, " lc+%d(%d)\n", s, 0+s);
+ Bprint(&bso, "%6llux %P\n",
+ (vlong)p->pc, p);
+ }
+ } else {
+ *bp = 64-s; /* 65-128 -lc */
+ if(debug['O']) {
+ Bprint(&bso, " lc%d(%d)\n", s, 64-s);
+ Bprint(&bso, "%6llux %P\n",
+ (vlong)p->pc, p);
+ }
+ }
+ lcsize++;
+ }
+ }
+ if(lcsize & 1) {
+ symgrow(sym, lcsize+1);
+ sym->p[lcsize] = 129;
+ lcsize++;
+ }
+ sym->size = lcsize;
+ lcsize = 0;
+
+ if(debug['v'] || debug['O'])
+ Bprint(&bso, "lcsize = %d\n", lcsize);
+ Bflush(&bso);
+}
+
+#define LOG 5
+void
+mkfwd(void)
+{
+ Prog *p;
+ int i;
+ int32 dwn[LOG], cnt[LOG];
+ Prog *lst[LOG], *last;
+
+ for(i=0; i<LOG; i++) {
+ if(i == 0)
+ cnt[i] = 1;
+ else
+ cnt[i] = LOG * cnt[i-1];
+ dwn[i] = 1;
+ lst[i] = P;
+ }
+ i = 0;
+ last = nil;
+ for(cursym = textp; cursym != nil; cursym = cursym->next) {
+ for(p = cursym->text; p != P; p = p->link) {
+ if(p->link == P) {
+ if(cursym->next)
+ p->forwd = cursym->next->text;
+ break;
+ }
+ i--;
+ if(i < 0)
+ i = LOG-1;
+ p->forwd = P;
+ dwn[i]--;
+ if(dwn[i] <= 0) {
+ dwn[i] = cnt[i];
+ if(lst[i] != P)
+ lst[i]->forwd = p;
+ lst[i] = p;
+ }
+ }
+ }
+}
+
+uint16
+le16(uchar *b)
+{
+ return b[0] | b[1]<<8;
+}
+
+uint32
+le32(uchar *b)
+{
+ return b[0] | b[1]<<8 | b[2]<<16 | b[3]<<24;
+}
+
+uint64
+le64(uchar *b)
+{
+ return le32(b) | (uint64)le32(b+4)<<32;
+}
+
+uint16
+be16(uchar *b)
+{
+ return b[0]<<8 | b[1];
+}
+
+uint32
+be32(uchar *b)
+{
+ return b[0]<<24 | b[1]<<16 | b[2]<<8 | b[3];
+}
+
+uint64
+be64(uchar *b)
+{
+ return (uvlong)be32(b)<<32 | be32(b+4);
+}
+
+Endian be = { be16, be32, be64 };
+Endian le = { le16, le32, le64 };
diff --git a/src/cmd/ld/lib.h b/src/cmd/ld/lib.h
index 652d845fb..bcf297116 100644
--- a/src/cmd/ld/lib.h
+++ b/src/cmd/ld/lib.h
@@ -40,6 +40,34 @@ struct Library
char *pkg; // import path
};
+// Terrible but standard terminology.
+// A segment describes a block of file to load into memory.
+// A section further describes the pieces of that block for
+// use in debuggers and such.
+
+typedef struct Segment Segment;
+typedef struct Section Section;
+
+struct Segment
+{
+ uchar rwx; // permission as usual unix bits (5 = r-x etc)
+ uvlong vaddr; // virtual address
+ uvlong len; // length in memory
+ uvlong fileoff; // file offset
+ uvlong filelen; // length on disk
+ Section* sect;
+};
+
+struct Section
+{
+ uchar rwx;
+ char *name;
+ uvlong vaddr;
+ uvlong len;
+ Section *next; // in segment list
+ Segment *seg;
+};
+
extern char symname[];
extern char *libdir[];
extern int nlibdir;
@@ -64,11 +92,18 @@ EXTERN uchar inuxi8[8];
EXTERN char* outfile;
EXTERN int32 nsymbol;
EXTERN char* thestring;
+EXTERN int ndynexp;
+
+EXTERN Segment segtext;
+EXTERN Segment segdata;
+EXTERN Segment segsym;
void addlib(char *src, char *obj);
void addlibpath(char *srcref, char *objref, char *file, char *pkg);
+Section* addsection(Segment*, char*, int);
void copyhistfrog(char *buf, int nbuf);
void addhist(int32 line, int type);
+void asmlc(void);
void histtoauto(void);
void collapsefrog(Sym *s);
Sym* lookup(char *symb, int v);
@@ -83,20 +118,82 @@ void readundefs(char *f, int t);
int32 Bget4(Biobuf *f);
void loadlib(void);
void errorexit(void);
+void mangle(char*);
void objfile(char *file, char *pkg);
void libinit(void);
+void pclntab(void);
+void symtab(void);
void Lflag(char *arg);
void usage(void);
+void adddynrel(Sym*, Reloc*);
void ldobj1(Biobuf *f, char*, int64 len, char *pn);
void ldobj(Biobuf*, char*, int64, char*, int);
+void ldelf(Biobuf*, char*, int64, char*);
+void ldmacho(Biobuf*, char*, int64, char*);
void ldpkg(Biobuf*, char*, int64, char*, int);
void mark(Sym *s);
+void mkfwd(void);
char* expandpkg(char*, char*);
void deadcode(void);
+void ewrite(int, void*, int);
+Reloc* addrel(Sym*);
+void codeblk(int32, int32);
+void datblk(int32, int32);
+Sym* datsort(Sym*);
+void reloc(void);
+void relocsym(Sym*);
+void savedata(Sym*, Prog*);
+void symgrow(Sym*, int32);
+vlong addstring(Sym*, char*);
+vlong adduint32(Sym*, uint32);
+vlong adduint64(Sym*, uint64);
+vlong addaddr(Sym*, Sym*);
+vlong addaddrplus(Sym*, Sym*, int32);
+vlong addpcrelplus(Sym*, Sym*, int32);
+vlong addsize(Sym*, Sym*);
+vlong adduint8(Sym*, uint8);
+vlong adduint16(Sym*, uint16);
+void asmsym(void);
+void asmelfsym64(void);
+void strnput(char*, int);
+void dodata(void);
+void address(void);
+void textaddress(void);
+void genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*));
+vlong datoff(vlong);
+void adddynlib(char*);
+int archreloc(Reloc*, Sym*, vlong*);
+void adddynsym(Sym*);
+void addexport(void);
int pathchar(void);
void* mal(uint32);
+void unmal(void*, uint32);
void mywhatsys(void);
+int rbyoff(const void*, const void*);
+
+uint16 le16(uchar*);
+uint32 le32(uchar*);
+uint64 le64(uchar*);
+uint16 be16(uchar*);
+uint32 be32(uchar*);
+uint64 be64(uchar*);
+
+typedef struct Endian Endian;
+struct Endian
+{
+ uint16 (*e16)(uchar*);
+ uint32 (*e32)(uchar*);
+ uint64 (*e64)(uchar*);
+};
+
+extern Endian be, le;
+
+// relocation size bits
+enum {
+ Rbig = 128,
+ Rlittle = 64,
+};
/* set by call to mywhatsys() */
extern char* goroot;
diff --git a/src/cmd/ld/macho.c b/src/cmd/ld/macho.c
index 24400cf14..402e0ec63 100644
--- a/src/cmd/ld/macho.c
+++ b/src/cmd/ld/macho.c
@@ -6,6 +6,7 @@
// http://developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html
#include "l.h"
+#include "../ld/dwarf.h"
#include "../ld/lib.h"
#include "../ld/macho.h"
@@ -46,6 +47,10 @@ newMachoLoad(uint32 type, uint32 ndata)
diag("too many loads");
errorexit();
}
+
+ if(macho64 && (ndata & 1))
+ ndata++;
+
l = &load[nload++];
l->type = type;
l->ndata = ndata;
@@ -97,22 +102,6 @@ newMachoDebug(void)
// Generic linking code.
-static uchar *linkdata;
-static uint32 nlinkdata;
-static uint32 mlinkdata;
-
-static uchar *strtab;
-static uint32 nstrtab;
-static uint32 mstrtab;
-
-struct Expsym
-{
- int off;
- Sym* s;
-} *expsym;
-static int nexpsym;
-static int nimpsym;
-
static char **dylib;
static int ndylib;
@@ -129,7 +118,7 @@ machowrite(void)
MachoDebug *d;
MachoLoad *l;
- o1 = Boffset(&bso);
+ o1 = cpos();
loadsize = 4*4*ndebug;
for(i=0; i<nload; i++)
@@ -194,8 +183,8 @@ machowrite(void)
LPUT(t->reloc);
LPUT(t->nreloc);
LPUT(t->flag);
- LPUT(0); /* reserved */
- LPUT(0); /* reserved */
+ LPUT(t->res1); /* reserved */
+ LPUT(t->res2); /* reserved */
LPUT(0); /* reserved */
} else {
strnput(t->name, 16);
@@ -207,8 +196,8 @@ machowrite(void)
LPUT(t->reloc);
LPUT(t->nreloc);
LPUT(t->flag);
- LPUT(0); /* reserved */
- LPUT(0); /* reserved */
+ LPUT(t->res1); /* reserved */
+ LPUT(t->res2); /* reserved */
}
}
}
@@ -229,224 +218,71 @@ machowrite(void)
LPUT(d->filesize);
}
- return Boffset(&bso) - o1;
-}
-
-static void*
-grow(uchar **dat, uint32 *ndat, uint32 *mdat, uint32 n)
-{
- uchar *p;
- uint32 old;
-
- if(*ndat+n > *mdat) {
- old = *mdat;
- *mdat = (*ndat+n)*2 + 128;
- *dat = realloc(*dat, *mdat);
- if(*dat == 0) {
- diag("out of memory");
- errorexit();
- }
- memset(*dat+old, 0, *mdat-old);
- }
- p = *dat + *ndat;
- *ndat += n;
- return p;
-}
-
-static int
-needlib(char *name)
-{
- char *p;
- Sym *s;
-
- /* reuse hash code in symbol table */
- p = smprint(".machoload.%s", name);
- s = lookup(p, 0);
- if(s->type == 0) {
- s->type = 100; // avoid SDATA, etc.
- return 1;
- }
- return 0;
+ return cpos() - o1;
}
void
domacho(void)
{
- int h, ptrsize, t;
- char *p;
- uchar *dat;
- uint32 x;
Sym *s;
- Sym **impsym;
- ptrsize = 4;
- if(macho64)
- ptrsize = 8;
+ if(debug['d'])
+ return;
// empirically, string table must begin with " \x00".
- if(!debug['d'])
- *(char*)grow(&strtab, &nstrtab, &mstrtab, 2) = ' ';
-
- impsym = nil;
- for(h=0; h<NHASH; h++) {
- for(s=hash[h]; s!=S; s=s->link) {
- if(!s->reachable || (s->type != STEXT && s->type != SDATA && s->type != SBSS) || s->dynimpname == nil)
- continue;
- if(debug['d']) {
- diag("cannot use dynamic loading and -d");
- errorexit();
- }
- if(!s->dynexport) {
- if(nimpsym%32 == 0) {
- impsym = realloc(impsym, (nimpsym+32)*sizeof impsym[0]);
- if(impsym == nil) {
- diag("out of memory");
- errorexit();
- }
- }
- impsym[nimpsym++] = s;
- continue;
- }
-
- /* symbol table entry - darwin still puts _ prefixes on all C symbols */
- x = nstrtab;
- p = grow(&strtab, &nstrtab, &mstrtab, 1+strlen(s->dynimpname)+1);
- *p++ = '_';
- strcpy(p, s->dynimpname);
-
- dat = grow(&linkdata, &nlinkdata, &mlinkdata, 8+ptrsize);
- dat[0] = x;
- dat[1] = x>>8;
- dat[2] = x>>16;
- dat[3] = x>>24;
-
- dat[4] = 0x0f; // type: N_SECT | N_EXT - external, defined in sect
- switch(s->type) {
- default:
- case STEXT:
- t = 1;
- break;
- case SDATA:
- t = 2;
- break;
- case SBSS:
- t = 4;
- break;
- }
- dat[5] = t; // sect: section number
-
- if (nexpsym%32 == 0) {
- expsym = realloc(expsym, (nexpsym+32)*sizeof expsym[0]);
- if (expsym == nil) {
- diag("out of memory");
- errorexit();
- }
- }
- expsym[nexpsym].off = nlinkdata - ptrsize;
- expsym[nexpsym++].s = s;
- }
- }
-
- for(h=0; h<nimpsym; h++) {
- s = impsym[h];
- s->type = SMACHO;
- s->value = (nexpsym+h) * ptrsize;
-
- /* symbol table entry - darwin still puts _ prefixes on all C symbols */
- x = nstrtab;
- p = grow(&strtab, &nstrtab, &mstrtab, 1+strlen(s->dynimpname)+1);
- *p++ = '_';
- strcpy(p, s->dynimpname);
-
- dat = grow(&linkdata, &nlinkdata, &mlinkdata, 8+ptrsize);
- dat[0] = x;
- dat[1] = x>>8;
- dat[2] = x>>16;
- dat[3] = x>>24;
-
- dat[4] = 0x01; // type: N_EXT - external symbol
-
- if(needlib(s->dynimplib)) {
- if(ndylib%32 == 0) {
- dylib = realloc(dylib, (ndylib+32)*sizeof dylib[0]);
- if(dylib == nil) {
- diag("out of memory");
- errorexit();
- }
- }
- dylib[ndylib++] = s->dynimplib;
- }
- }
- free(impsym);
-
- /*
- * list of symbol table indexes.
- * we don't take advantage of the opportunity
- * to order the symbol table differently from
- * this list, so it is boring: 0 1 2 3 4 ...
- */
- for(x=0; x<nexpsym+nimpsym; x++) {
- dat = grow(&linkdata, &nlinkdata, &mlinkdata, 4);
- dat[0] = x;
- dat[1] = x>>8;
- dat[2] = x>>16;
- dat[3] = x>>24;
- }
-
- dynptrsize = (nexpsym+nimpsym) * ptrsize;
+ s = lookup(".dynstr", 0);
+ s->type = SMACHODYNSTR;
+ s->reachable = 1;
+ adduint8(s, ' ');
+ adduint8(s, '\0');
+
+ s = lookup(".dynsym", 0);
+ s->type = SMACHODYNSYM;
+ s->reachable = 1;
+
+ s = lookup(".plt", 0); // will be __symbol_stub
+ s->type = SMACHOPLT;
+ s->reachable = 1;
+
+ s = lookup(".got", 0); // will be __nl_symbol_ptr
+ s->type = SMACHOGOT;
+ s->reachable = 1;
+
+ s = lookup(".linkedit.plt", 0); // indirect table for .plt
+ s->type = SMACHOINDIRECTPLT;
+ s->reachable = 1;
+
+ s = lookup(".linkedit.got", 0); // indirect table for .got
+ s->type = SMACHOINDIRECTGOT;
+ s->reachable = 1;
}
-vlong
-domacholink(void)
+void
+machoadddynlib(char *lib)
{
- int i;
- uchar *p;
- Sym *s;
- uint64 val;
-
- linkoff = 0;
- if(nlinkdata > 0) {
- linkoff = rnd(HEADR+textsize, INITRND) + rnd(datsize, INITRND);
- seek(cout, linkoff, 0);
-
- for(i = 0; i<nexpsym; ++i) {
- s = expsym[i].s;
- val = s->value;
- if(s->type == SUNDEF)
- diag("export of undefined symbol %s", s->name);
- if (s->type != STEXT)
- val += INITDAT;
- p = linkdata+expsym[i].off;
- p[0] = val;
- p[1] = val >> 8;
- p[2] = val >> 16;
- p[3] = val >> 24;
- if (macho64) {
- p[4] = val >> 32;
- p[5] = val >> 40;
- p[6] = val >> 48;
- p[7] = val >> 56;
- }
+ if(ndylib%32 == 0) {
+ dylib = realloc(dylib, (ndylib+32)*sizeof dylib[0]);
+ if(dylib == nil) {
+ diag("out of memory");
+ errorexit();
}
-
- write(cout, linkdata, nlinkdata);
- write(cout, strtab, nstrtab);
}
- return rnd(nlinkdata+nstrtab, INITRND);
+ dylib[ndylib++] = lib;
}
void
-asmbmacho(vlong symdatva, vlong symo)
+asmbmacho(void)
{
vlong v, w;
vlong va;
- int a, i, ptrsize;
+ int a, i;
char *pkgroot;
MachoHdr *mh;
MachoSect *msect;
MachoSeg *ms;
MachoDebug *md;
MachoLoad *ml;
+ Sym *s;
/* apple MACH */
va = INITTEXT - HEADR;
@@ -458,12 +294,10 @@ asmbmacho(vlong symdatva, vlong symo)
case '6':
mh->cpu = MACHO_CPU_AMD64;
mh->subcpu = MACHO_SUBCPU_X86;
- ptrsize = 8;
break;
case '8':
mh->cpu = MACHO_CPU_386;
mh->subcpu = MACHO_SUBCPU_X86;
- ptrsize = 4;
break;
}
@@ -472,8 +306,8 @@ asmbmacho(vlong symdatva, vlong symo)
ms->vsize = va;
/* text */
- v = rnd(HEADR+textsize, INITRND);
- ms = newMachoSeg("__TEXT", 1);
+ v = rnd(HEADR+segtext.len, INITRND);
+ ms = newMachoSeg("__TEXT", 2);
ms->vaddr = va;
ms->vsize = v;
ms->filesize = v;
@@ -482,45 +316,50 @@ asmbmacho(vlong symdatva, vlong symo)
msect = newMachoSect(ms, "__text");
msect->addr = INITTEXT;
- msect->size = textsize;
+ msect->size = segtext.sect->len;
msect->off = INITTEXT - va;
msect->flag = 0x400; /* flag - some instructions */
+
+ s = lookup(".plt", 0);
+ if(s->size > 0) {
+ msect = newMachoSect(ms, "__symbol_stub1");
+ msect->addr = symaddr(s);
+ msect->size = s->size;
+ msect->off = ms->fileoffset + msect->addr - ms->vaddr;
+ msect->flag = 0x80000408; /* flag */
+ msect->res1 = 0; /* index into indirect symbol table */
+ msect->res2 = 6; /* size of stubs */
+ }
/* data */
- w = datsize+dynptrsize+bsssize;
- ms = newMachoSeg("__DATA", 2+(dynptrsize>0));
+ w = segdata.len;
+ ms = newMachoSeg("__DATA", 3);
ms->vaddr = va+v;
ms->vsize = w;
ms->fileoffset = v;
- ms->filesize = datsize;
+ ms->filesize = segdata.filelen;
ms->prot1 = 7;
ms->prot2 = 3;
msect = newMachoSect(ms, "__data");
msect->addr = va+v;
- msect->size = datsize;
+ msect->size = symaddr(lookup(".got", 0)) - msect->addr;
msect->off = v;
- if(dynptrsize > 0) {
+ s = lookup(".got", 0);
+ if(s->size > 0) {
msect = newMachoSect(ms, "__nl_symbol_ptr");
- msect->addr = va+v+datsize;
- msect->size = dynptrsize;
+ msect->addr = symaddr(s);
+ msect->size = s->size;
+ msect->off = datoff(msect->addr);
msect->align = 2;
msect->flag = 6; /* section with nonlazy symbol pointers */
- /*
- * The reserved1 field is supposed to be the index of
- * the first entry in the list of symbol table indexes
- * in isymtab for the symbols we need. We only use
- * pointers, so we need the entire list, so the index
- * here should be 0, which luckily is what the Mach-O
- * writing code emits by default for this not really reserved field.
- msect->reserved1 = 0; - first indirect symbol table entry we need
- */
+ msect->res1 = lookup(".linkedit.plt", 0)->size / 4; /* offset into indirect symbol table */
}
msect = newMachoSect(ms, "__bss");
- msect->addr = va+v+datsize+dynptrsize;
- msect->size = bsssize;
+ msect->addr = va+v+segdata.filelen;
+ msect->size = segdata.len - segdata.filelen;
msect->flag = 1; /* flag - zero fill */
switch(thechar) {
@@ -532,7 +371,7 @@ asmbmacho(vlong symdatva, vlong symo)
ml->data[0] = 4; /* thread type */
ml->data[1] = 42; /* word count */
ml->data[2+32] = entryvalue(); /* start pc */
- ml->data[2+32+1] = entryvalue()>>32;
+ ml->data[2+32+1] = entryvalue()>>16>>16; // hide >>32 for 8l
break;
case '8':
ml = newMachoLoad(5, 16+2); /* unix thread */
@@ -543,39 +382,43 @@ asmbmacho(vlong symdatva, vlong symo)
}
if(!debug['d']) {
- int nsym;
+ Sym *s1, *s2, *s3, *s4;
- nsym = dynptrsize/ptrsize;
+ // must match domacholink below
+ s1 = lookup(".dynsym", 0);
+ s2 = lookup(".dynstr", 0);
+ s3 = lookup(".linkedit.plt", 0);
+ s4 = lookup(".linkedit.got", 0);
ms = newMachoSeg("__LINKEDIT", 0);
- ms->vaddr = va+v+rnd(datsize+dynptrsize+bsssize, INITRND);
- ms->vsize = nlinkdata+nstrtab;
+ ms->vaddr = va+v+rnd(segdata.len, INITRND);
+ ms->vsize = s1->size + s2->size + s3->size + s4->size;
ms->fileoffset = linkoff;
- ms->filesize = nlinkdata+nstrtab;
+ ms->filesize = ms->vsize;
ms->prot1 = 7;
ms->prot2 = 3;
ml = newMachoLoad(2, 4); /* LC_SYMTAB */
ml->data[0] = linkoff; /* symoff */
- ml->data[1] = nsym; /* nsyms */
- ml->data[2] = linkoff + nlinkdata; /* stroff */
- ml->data[3] = nstrtab; /* strsize */
+ ml->data[1] = s1->size / (macho64 ? 16 : 12); /* nsyms */
+ ml->data[2] = linkoff + s1->size; /* stroff */
+ ml->data[3] = s2->size; /* strsize */
ml = newMachoLoad(11, 18); /* LC_DYSYMTAB */
ml->data[0] = 0; /* ilocalsym */
ml->data[1] = 0; /* nlocalsym */
ml->data[2] = 0; /* iextdefsym */
- ml->data[3] = nexpsym; /* nextdefsym */
- ml->data[4] = nexpsym; /* iundefsym */
- ml->data[5] = nimpsym; /* nundefsym */
+ ml->data[3] = ndynexp; /* nextdefsym */
+ ml->data[4] = ndynexp; /* iundefsym */
+ ml->data[5] = (s1->size / (macho64 ? 16 : 12)) - ndynexp; /* nundefsym */
ml->data[6] = 0; /* tocoffset */
ml->data[7] = 0; /* ntoc */
ml->data[8] = 0; /* modtaboff */
ml->data[9] = 0; /* nmodtab */
ml->data[10] = 0; /* extrefsymoff */
ml->data[11] = 0; /* nextrefsyms */
- ml->data[12] = linkoff + nlinkdata - nsym*4; /* indirectsymoff */
- ml->data[13] = nsym; /* nindirectsyms */
+ ml->data[12] = linkoff + s1->size + s2->size; /* indirectsymoff */
+ ml->data[13] = (s3->size + s4->size) / 4; /* nindirectsyms */
ml->data[14] = 0; /* extreloff */
ml->data[15] = 0; /* nextrel */
ml->data[16] = 0; /* locreloff */
@@ -602,24 +445,53 @@ asmbmacho(vlong symdatva, vlong symo)
}
if(!debug['s']) {
- ms = newMachoSeg("__SYMDAT", 1);
- ms->vaddr = symdatva;
- ms->vsize = 8+symsize+lcsize;
- ms->fileoffset = symo;
- ms->filesize = 8+symsize+lcsize;
- ms->prot1 = 7;
- ms->prot2 = 5;
+ Sym *s;
md = newMachoDebug();
- md->fileoffset = symo+8;
- md->filesize = symsize;
+ s = lookup("symtab", 0);
+ md->fileoffset = datoff(s->value);
+ md->filesize = s->size;
md = newMachoDebug();
- md->fileoffset = symo+8+symsize;
- md->filesize = lcsize;
+ s = lookup("pclntab", 0);
+ md->fileoffset = datoff(s->value);
+ md->filesize = s->size;
+
+ dwarfaddmachoheaders();
}
a = machowrite();
if(a > MACHORESERVE)
diag("MACHORESERVE too small: %d > %d", a, MACHORESERVE);
}
+
+vlong
+domacholink(void)
+{
+ int size;
+ Sym *s1, *s2, *s3, *s4;
+
+ // 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);
+
+ size = s1->size + s2->size + s3->size + s4->size;
+
+ if(size > 0) {
+ linkoff = rnd(HEADR+segtext.len, INITRND) + rnd(segdata.filelen, INITRND);
+ seek(cout, linkoff, 0);
+
+ ewrite(cout, s1->p, s1->size);
+ ewrite(cout, s2->p, s2->size);
+ ewrite(cout, s3->p, s3->size);
+ ewrite(cout, s4->p, s4->size);
+ }
+
+ return rnd(size, INITRND);
+}
diff --git a/src/cmd/ld/macho.h b/src/cmd/ld/macho.h
index a96b2a383..4cc7edc80 100644
--- a/src/cmd/ld/macho.h
+++ b/src/cmd/ld/macho.h
@@ -18,6 +18,8 @@ struct MachoSect {
uint32 reloc;
uint32 nreloc;
uint32 flag;
+ uint32 res1;
+ uint32 res2;
};
typedef struct MachoSeg MachoSeg;
@@ -70,8 +72,23 @@ enum {
MACHO32SYMSIZE = 12,
MACHO64SYMSIZE = 16,
+
+ MACHO_X86_64_RELOC_UNSIGNED = 0,
+ MACHO_X86_64_RELOC_SIGNED = 1,
+ MACHO_X86_64_RELOC_BRANCH = 2,
+ MACHO_X86_64_RELOC_GOT_LOAD = 3,
+ MACHO_X86_64_RELOC_GOT = 4,
+ MACHO_X86_64_RELOC_SUBTRACTOR = 5,
+ MACHO_X86_64_RELOC_SIGNED_1 = 6,
+ MACHO_X86_64_RELOC_SIGNED_2 = 7,
+ MACHO_X86_64_RELOC_SIGNED_4 = 8,
+
+ MACHO_GENERIC_RELOC_VANILLA = 0,
+
+ MACHO_FAKE_GOTPCREL = 100,
};
void domacho(void);
vlong domacholink(void);
-void asmbmacho(vlong, vlong);
+void asmbmacho(void);
+void machoadddynlib(char*);
diff --git a/src/cmd/ld/pe.c b/src/cmd/ld/pe.c
index d3439abfb..82c6941f2 100644
--- a/src/cmd/ld/pe.c
+++ b/src/cmd/ld/pe.c
@@ -33,18 +33,39 @@ static char dosstub[] =
0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
+int32 PESECTHEADR;
+int32 PEFILEHEADR;
+
static int pe64;
static int nsect;
-static int sect_virt_begin;
-static int sect_raw_begin = PERESERVE;
+static int nextsectoff;
+static int nextfileoff;
static IMAGE_FILE_HEADER fh;
static IMAGE_OPTIONAL_HEADER oh;
static IMAGE_SECTION_HEADER sh[16];
-static IMAGE_SECTION_HEADER *textsect, *datsect, *bsssect;
+
+typedef struct Imp Imp;
+struct Imp {
+ Sym* s;
+ long va;
+ long vb;
+ Imp* next;
+};
+
+typedef struct Dll Dll;
+struct Dll {
+ char* name;
+ int count;
+ Imp* ms;
+ Dll* next;
+};
+
+static Dll* dr;
+static int ndll, nimp, nsize;
static IMAGE_SECTION_HEADER*
-new_section(char *name, int size, int noraw)
+addpesection(char *name, int sectsize, int filesize, Segment *s)
{
IMAGE_SECTION_HEADER *h;
@@ -54,15 +75,23 @@ new_section(char *name, int size, int noraw)
}
h = &sh[nsect++];
strncpy((char*)h->Name, name, sizeof(h->Name));
- h->VirtualSize = size;
- if(!sect_virt_begin)
- sect_virt_begin = 0x1000;
- h->VirtualAddress = sect_virt_begin;
- sect_virt_begin = rnd(sect_virt_begin+size, 0x1000);
- if(!noraw) {
- h->SizeOfRawData = rnd(size, PEALIGN);
- h->PointerToRawData = sect_raw_begin;
- sect_raw_begin += h->SizeOfRawData;
+ h->VirtualSize = sectsize;
+ h->VirtualAddress = nextsectoff;
+ nextsectoff = rnd(nextsectoff+sectsize, PESECTALIGN);
+ h->PointerToRawData = nextfileoff;
+ if(filesize > 0) {
+ h->SizeOfRawData = rnd(filesize, PEFILEALIGN);
+ nextfileoff += h->SizeOfRawData;
+ }
+ if(s) {
+ if(s->vaddr-PEBASE != h->VirtualAddress) {
+ diag("%s.VirtualAddress = %#llux, want %#llux", name, (vlong)h->VirtualAddress, (vlong)(s->vaddr-PEBASE));
+ errorexit();
+ }
+ if(s->fileoff != h->PointerToRawData) {
+ diag("%s.PointerToRawData = %#llux, want %#llux", name, (vlong)h->PointerToRawData, (vlong)(s->fileoff));
+ errorexit();
+ }
}
return h;
}
@@ -79,6 +108,11 @@ peinit(void)
default:
break;
}
+
+ PEFILEHEADR = rnd(sizeof(dosstub)+sizeof(fh)+sizeof(oh)+sizeof(sh), PEFILEALIGN);
+ PESECTHEADR = rnd(PEFILEHEADR, PESECTALIGN);
+ nextsectoff = PESECTHEADR;
+ nextfileoff = PEFILEHEADR;
}
static void
@@ -86,7 +120,8 @@ pewrite(void)
{
int i, j;
- write(cout, dosstub, sizeof dosstub);
+ seek(cout, 0, 0);
+ ewrite(cout, dosstub, sizeof dosstub);
strnput("PE", 4);
for (i=0; i<sizeof(fh); i++)
@@ -98,24 +133,6 @@ pewrite(void)
cput(((char*)&sh[i])[j]);
}
-void
-dope(void)
-{
- textsect = new_section(".text", textsize, 0);
- textsect->Characteristics = IMAGE_SCN_CNT_CODE|
- IMAGE_SCN_CNT_INITIALIZED_DATA|
- IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ;
-
- datsect = new_section(".data", datsize, 0);
- datsect->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA|
- IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE;
- INITDAT = PEBASE+datsect->VirtualAddress;
-
- bsssect = new_section(".bss", bsssize, 1);
- bsssect->Characteristics = IMAGE_SCN_CNT_UNINITIALIZED_DATA|
- IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE;
-}
-
static void
strput(char *s)
{
@@ -124,73 +141,167 @@ strput(char *s)
cput('\0');
}
-static void
-add_import_table(void)
+static Dll*
+initdynimport(void)
{
- IMAGE_IMPORT_DESCRIPTOR ds[2], *d;
- char *dllname = "kernel32.dll";
- struct {
- char *name;
- uint32 thunk;
- } *f, fs[] = {
- { "GetProcAddress", 0 },
- { "LoadLibraryExA", 0 },
- { 0, 0 }
- };
-
- uint32 size = 0;
- memset(ds, 0, sizeof(ds));
- size += sizeof(ds);
- ds[0].Name = size;
- size += strlen(dllname) + 1;
- for(f=fs; f->name; f++) {
- f->thunk = size;
- size += sizeof(uint16) + strlen(f->name) + 1;
+ Imp *m;
+ Dll *d;
+ Sym *s;
+ int i;
+ Sym *dynamic;
+
+ dr = nil;
+ ndll = 0;
+ nimp = 0;
+ nsize = 0;
+
+ for(i=0; i<NHASH; i++)
+ for(s = hash[i]; s != S; s = s->hash) {
+ if(!s->reachable || !s->dynimpname)
+ continue;
+ nimp++;
+ for(d = dr; d != nil; d = d->next) {
+ if(strcmp(d->name,s->dynimplib) == 0) {
+ m = mal(sizeof *m);
+ m->s = s;
+ m->next = d->ms;
+ d->ms = m;
+ d->count++;
+ nsize += strlen(s->dynimpname)+2+1;
+ break;
+ }
+ }
+ if(d == nil) {
+ d = mal(sizeof *d);
+ d->name = s->dynimplib;
+ d->count = 1;
+ d->next = dr;
+ dr = d;
+ m = mal(sizeof *m);
+ m->s = s;
+ m->next = 0;
+ d->ms = m;
+ ndll++;
+ nsize += strlen(s->dynimpname)+2+1;
+ nsize += strlen(s->dynimplib)+1;
+ }
+ }
+
+ nsize += 20*ndll + 20;
+ nsize += 4*nimp + 4*ndll;
+
+ dynamic = lookup(".windynamic", 0);
+ dynamic->reachable = 1;
+ dynamic->type = SWINDOWS;
+ for(d = dr; d != nil; d = d->next) {
+ for(m = d->ms; m != nil; m = m->next) {
+ m->s->type = SWINDOWS | SSUB;
+ m->s->sub = dynamic->sub;
+ dynamic->sub = m->s;
+ m->s->value = dynamic->size;
+ dynamic->size += 4;
+ }
+ dynamic->size += 4;
}
- ds[0].FirstThunk = size;
- for(f=fs; f->name; f++)
- size += sizeof(fs[0].thunk);
+
+ return dr;
+}
+static void
+addimports(vlong fileoff, IMAGE_SECTION_HEADER *datsect)
+{
IMAGE_SECTION_HEADER *isect;
- isect = new_section(".idata", size, 0);
+ uint32 va;
+ int noff, aoff, o, last_fn, last_name_off, iat_off;
+ Imp *m;
+ Dll *d;
+ Sym* dynamic;
+
+ isect = addpesection(".idata", nsize, nsize, 0);
isect->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA|
IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE;
-
- uint32 va = isect->VirtualAddress;
+ va = isect->VirtualAddress;
oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = va;
oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = isect->VirtualSize;
- ds[0].Name += va;
- ds[0].FirstThunk += va;
- for(f=fs; f->name; f++)
- f->thunk += va;
+ seek(cout, fileoff, 0);
- vlong off = seek(cout, 0, 1);
- seek(cout, 0, 2);
- for(d=ds; ; d++) {
- lputl(d->OriginalFirstThunk);
- lputl(d->TimeDateStamp);
- lputl(d->ForwarderChain);
- lputl(d->Name);
- lputl(d->FirstThunk);
- if(!d->Name)
- break;
+ dynamic = lookup(".windynamic", 0);
+ iat_off = dynamic->value - PEBASE; // FirstThunk allocated in .data
+ oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = iat_off;
+ oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size = dynamic->size;
+
+ noff = va + 20*ndll + 20;
+ aoff = noff + 4*nimp + 4*ndll;
+ last_fn = 0;
+ last_name_off = aoff;
+ for(d = dr; d != nil; d = d->next) {
+ lputl(noff);
+ lputl(0);
+ lputl(0);
+ lputl(last_name_off);
+ lputl(iat_off);
+ last_fn = d->count;
+ noff += 4*last_fn + 4;
+ aoff += 4*last_fn + 4;
+ iat_off += 4*last_fn + 4;
+ last_name_off += strlen(d->name)+1;
}
- strput(dllname);
- for(f=fs; f->name; f++) {
- wputl(0);
- strput(f->name);
+ lputl(0); //end
+ lputl(0);
+ lputl(0);
+ lputl(0);
+ lputl(0);
+
+ // put OriginalFirstThunk
+ o = last_name_off;
+ for(d = dr; d != nil; d = d->next) {
+ for(m = d->ms; m != nil; m = m->next) {
+ lputl(o);
+ o += 2 + strlen(m->s->dynimpname) + 1;
+ }
+ lputl(0);
+ }
+ // put names
+ for(d = dr; d != nil; d = d->next) {
+ strput(d->name);
+ }
+ // put hint+name
+ for(d = dr; d != nil; d = d->next) {
+ for(m = d->ms; m != nil; m = m->next) {
+ wputl(0);
+ strput(m->s->dynimpname);
+ }
+ }
+
+ strnput("", isect->SizeOfRawData - nsize);
+ cflush();
+
+ // put FirstThunk
+ o = last_name_off;
+ seek(cout, datsect->PointerToRawData + dynamic->value - PEBASE - datsect->VirtualAddress, 0);
+ for(d = dr; d != nil; d = d->next) {
+ for(m = d->ms; m != nil; m = m->next) {
+ lputl(o);
+ o += 2 + strlen(m->s->dynimpname) + 1;
+ }
+ lputl(0);
}
- for(f=fs; f->name; f++)
- lputl(f->thunk);
- strnput("", isect->SizeOfRawData - size);
cflush();
- seek(cout, off, 0);
+ seek(cout, 0, 2);
+}
+
+void
+dope(void)
+{
+ initdynimport();
}
void
asmbpe(void)
{
+ IMAGE_SECTION_HEADER *t, *d;
+
switch(thechar) {
default:
diag("unknown PE architecture");
@@ -203,14 +314,16 @@ asmbpe(void)
break;
}
- if(!debug['s']) {
- IMAGE_SECTION_HEADER *symsect;
- symsect = new_section(".symdat", 8+symsize+lcsize, 0);
- symsect->Characteristics = IMAGE_SCN_MEM_READ|
- IMAGE_SCN_CNT_INITIALIZED_DATA;
- }
+ t = addpesection(".text", segtext.len, segtext.len, &segtext);
+ t->Characteristics = IMAGE_SCN_CNT_CODE|
+ IMAGE_SCN_CNT_INITIALIZED_DATA|
+ IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ;
+
+ d = addpesection(".data", segdata.len, segdata.filelen, &segdata);
+ d->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA|
+ IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE;
- add_import_table();
+ addimports(nextfileoff, d);
fh.NumberOfSections = nsect;
fh.TimeDateStamp = time(0);
@@ -223,24 +336,24 @@ asmbpe(void)
oh.Magic = 0x10b; // PE32
oh.MajorLinkerVersion = 1;
oh.MinorLinkerVersion = 0;
- oh.SizeOfCode = textsect->SizeOfRawData;
- oh.SizeOfInitializedData = datsect->SizeOfRawData;
- oh.SizeOfUninitializedData = bsssect->SizeOfRawData;
+ oh.SizeOfCode = t->SizeOfRawData;
+ oh.SizeOfInitializedData = d->SizeOfRawData;
+ oh.SizeOfUninitializedData = 0;
oh.AddressOfEntryPoint = entryvalue()-PEBASE;
- oh.BaseOfCode = textsect->VirtualAddress;
- oh.BaseOfData = datsect->VirtualAddress;
+ oh.BaseOfCode = t->VirtualAddress;
+ oh.BaseOfData = d->VirtualAddress;
oh.ImageBase = PEBASE;
- oh.SectionAlignment = 0x00001000;
- oh.FileAlignment = PEALIGN;
+ oh.SectionAlignment = PESECTALIGN;
+ oh.FileAlignment = PEFILEALIGN;
oh.MajorOperatingSystemVersion = 4;
oh.MinorOperatingSystemVersion = 0;
oh.MajorImageVersion = 1;
oh.MinorImageVersion = 0;
oh.MajorSubsystemVersion = 4;
oh.MinorSubsystemVersion = 0;
- oh.SizeOfImage = sect_virt_begin;
- oh.SizeOfHeaders = PERESERVE;
+ oh.SizeOfImage = nextsectoff;
+ oh.SizeOfHeaders = PEFILEHEADR;
oh.Subsystem = 3; // WINDOWS_CUI
oh.SizeOfStackReserve = 0x00200000;
oh.SizeOfStackCommit = 0x00001000;
diff --git a/src/cmd/ld/pe.h b/src/cmd/ld/pe.h
index b64dd97c0..f8161cc4a 100644
--- a/src/cmd/ld/pe.h
+++ b/src/cmd/ld/pe.h
@@ -72,9 +72,16 @@ typedef struct {
uint32 FirstThunk;
} IMAGE_IMPORT_DESCRIPTOR;
-#define PERESERVE 0x400
-#define PEALIGN 0x200
#define PEBASE 0x00400000
+// SectionAlignment must be greater than or equal to FileAlignment.
+// The default is the page size for the architecture.
+#define PESECTALIGN 0x1000
+// FileAlignment should be a power of 2 between 512 and 64 K, inclusive.
+// The default is 512. If the SectionAlignment is less than
+// the architecture's page size, then FileAlignment must match SectionAlignment.
+#define PEFILEALIGN (2<<8)
+extern int32 PESECTHEADR;
+extern int32 PEFILEHEADR;
enum {
IMAGE_FILE_MACHINE_I386 = 0x14c,
@@ -112,5 +119,6 @@ enum {
};
void peinit(void);
-void dope(void);
void asmbpe(void);
+void dope(void);
+
diff --git a/src/cmd/ld/symtab.c b/src/cmd/ld/symtab.c
new file mode 100644
index 000000000..26e4def64
--- /dev/null
+++ b/src/cmd/ld/symtab.c
@@ -0,0 +1,259 @@
+// Inferno utils/6l/span.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+// Symbol table.
+
+#include "l.h"
+#include "../ld/lib.h"
+#include "../ld/elf.h"
+
+char *elfstrdat;
+int elfstrsize;
+int maxelfstr;
+int elftextsh;
+
+int
+putelfstr(char *s)
+{
+ int off, n;
+
+ if(elfstrsize == 0 && s[0] != 0) {
+ // first entry must be empty string
+ putelfstr("");
+ }
+
+ n = strlen(s)+1;
+ if(elfstrsize+n > maxelfstr) {
+ maxelfstr = 2*(elfstrsize+n+(1<<20));
+ elfstrdat = realloc(elfstrdat, maxelfstr);
+ }
+ off = elfstrsize;
+ elfstrsize += n;
+ memmove(elfstrdat+off, s, n);
+ return off;
+}
+
+void
+putelfsym64(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go)
+{
+ int bind, type, shndx, stroff;
+
+ bind = STB_GLOBAL;
+ switch(t) {
+ default:
+ return;
+ case 'T':
+ type = STT_FUNC;
+ shndx = elftextsh + 0;
+ break;
+ case 'D':
+ type = STT_OBJECT;
+ shndx = elftextsh + 1;
+ break;
+ case 'B':
+ type = STT_OBJECT;
+ shndx = elftextsh + 2;
+ break;
+ }
+
+ stroff = putelfstr(s);
+ LPUT(stroff); // string
+ cput((bind<<4)|(type&0xF));
+ cput(0);
+ WPUT(shndx);
+ VPUT(addr);
+ VPUT(size);
+}
+
+void
+asmelfsym64(void)
+{
+ genasmsym(putelfsym64);
+}
+
+void
+putelfsym32(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go)
+{
+ int bind, type, shndx, stroff;
+
+ bind = STB_GLOBAL;
+ switch(t) {
+ default:
+ return;
+ case 'T':
+ type = STT_FUNC;
+ shndx = elftextsh + 0;
+ break;
+ case 'D':
+ type = STT_OBJECT;
+ shndx = elftextsh + 1;
+ break;
+ case 'B':
+ type = STT_OBJECT;
+ shndx = elftextsh + 2;
+ break;
+ }
+
+ stroff = putelfstr(s);
+ LPUT(stroff); // string
+ LPUT(addr);
+ LPUT(size);
+ cput((bind<<4)|(type&0xF));
+ cput(0);
+ WPUT(shndx);
+}
+
+void
+asmelfsym32(void)
+{
+ genasmsym(putelfsym32);
+}
+
+
+static Sym *symt;
+
+static void
+scput(int b)
+{
+ uchar *p;
+
+ symgrow(symt, symt->size+1);
+ p = symt->p + symt->size;
+ *p = b;
+ symt->size++;
+}
+
+static void
+slputb(int32 v)
+{
+ uchar *p;
+
+ symgrow(symt, symt->size+4);
+ p = symt->p + symt->size;
+ *p++ = v>>24;
+ *p++ = v>>16;
+ *p++ = v>>8;
+ *p = v;
+ symt->size += 4;
+}
+
+void
+putsymb(Sym *s, char *name, int t, vlong v, vlong size, int ver, Sym *typ)
+{
+ int i, f, l;
+ Reloc *rel;
+
+ if(t == 'f')
+ name++;
+ l = 4;
+// if(!debug['8'])
+// l = 8;
+ if(s != nil) {
+ rel = addrel(symt);
+ rel->siz = l + Rbig;
+ rel->sym = s;
+ rel->type = D_ADDR;
+ rel->off = symt->size;
+ v = 0;
+ }
+ if(l == 8)
+ slputb(v>>32);
+ slputb(v);
+ if(ver)
+ t += 'a' - 'A';
+ scput(t+0x80); /* 0x80 is variable length */
+
+ if(t == 'Z' || t == 'z') {
+ scput(name[0]);
+ for(i=1; name[i] != 0 || name[i+1] != 0; i += 2) {
+ scput(name[i]);
+ scput(name[i+1]);
+ }
+ scput(0);
+ scput(0);
+ i++;
+ }
+ else {
+ for(i=0; name[i]; i++)
+ scput(name[i]);
+ scput(0);
+ }
+ if(typ) {
+ if(!typ->reachable)
+ diag("unreachable type %s", typ->name);
+ rel = addrel(symt);
+ rel->siz = l;
+ rel->sym = typ;
+ rel->type = D_ADDR;
+ rel->off = symt->size;
+ }
+ if(l == 8)
+ slputb(0);
+ slputb(0);
+
+ if(debug['n']) {
+ if(t == 'z' || t == 'Z') {
+ Bprint(&bso, "%c %.8llux ", t, v);
+ for(i=1; name[i] != 0 || name[i+1] != 0; i+=2) {
+ f = ((name[i]&0xff) << 8) | (name[i+1]&0xff);
+ Bprint(&bso, "/%x", f);
+ }
+ Bprint(&bso, "\n");
+ return;
+ }
+ if(ver)
+ Bprint(&bso, "%c %.8llux %s<%d> %s\n", t, v, s, ver, typ ? typ->name : "");
+ else
+ Bprint(&bso, "%c %.8llux %s %s\n", t, v, s, typ ? typ->name : "");
+ }
+}
+
+void
+symtab(void)
+{
+ // 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("end", SBSS, 0);
+ xdefine("epclntab", SRODATA, 0);
+ xdefine("esymtab", SRODATA, 0);
+
+ symt = lookup("symtab", 0);
+ symt->type = SRODATA;
+ symt->size = 0;
+ symt->reachable = 1;
+
+ genasmsym(putsymb);
+}
diff --git a/src/cmd/make.bash b/src/cmd/make.bash
index d0fda7d18..63da74625 100755
--- a/src/cmd/make.bash
+++ b/src/cmd/make.bash
@@ -7,9 +7,7 @@ set -e
bash clean.bash
-GOBIN="${GOBIN:-$HOME/bin}"
-
-. "$GOROOT"/src/Make.$GOARCH
+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
@@ -17,16 +15,16 @@ fi
cd ${O}l
bash mkenam
-"$GOBIN"/gomake enam.o
+gomake enam.o
cd ..
# Note: commands written in Go are not listed here.
-# They are in ../make.bash so that they can be built
+# They are in ../pkg/Makefile so that they can be built
# after the Go libraries on which they depend.
for i in cc ${O}l ${O}a ${O}c gc ${O}g cov godefs gopack gotest nm prof
do
echo; echo; echo %%%% making $i %%%%; echo
cd $i
- "$GOBIN"/gomake install
+ gomake install
cd ..
done
diff --git a/src/cmd/nm/Makefile b/src/cmd/nm/Makefile
index bb1545122..383dbd973 100644
--- a/src/cmd/nm/Makefile
+++ b/src/cmd/nm/Makefile
@@ -2,23 +2,17 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.conf
+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 and because this binary
-# is linked only with amd64 and x86 support.
+# We call the binary 6nm to avoid confusion with the host nm.
TARG=6nm
OFILES=\
nm.$O\
-$(TARG): $(OFILES)
- $(LD) -o $(TARG) -L"$(GOROOT)"/lib $(OFILES) -lmach -lbio -l9
+LIB=\
+ ../../../lib/libmach.a\
-clean:
- rm -f *.$O $(TARG)
-
-install: $(TARG)
- cp $(TARG) "$(GOBIN)"/$(TARG)
-
-$(OFILES): $(HFILES)
+include ../../Make.ccmd
diff --git a/src/cmd/nm/nm.c b/src/cmd/nm/nm.c
index 978218bff..845b6c773 100644
--- a/src/cmd/nm/nm.c
+++ b/src/cmd/nm/nm.c
@@ -126,31 +126,34 @@ void
doar(Biobuf *bp)
{
int offset, size, obj;
- char membername[SARNAME];
+ char name[SARNAME];
multifile = 1;
for (offset = Boffset(bp);;offset += size) {
- size = nextar(bp, offset, membername);
+ size = nextar(bp, offset, name);
if (size < 0) {
- error("phase error on ar header %ld", offset);
+ error("phase error on ar header %d", offset);
return;
}
if (size == 0)
return;
- if (strcmp(membername, symname) == 0)
+ if (strcmp(name, symname) == 0)
continue;
obj = objtype(bp, 0);
if (obj < 0) {
+ // perhaps foreign object
+ if(strlen(name) > 2 && strcmp(name+strlen(name)-2, ".o") == 0)
+ return;
error("inconsistent file %s in %s",
- membername, filename);
+ name, filename);
return;
}
if (!readar(bp, obj, offset+size, 1)) {
error("invalid symbol reference in file %s",
- membername);
+ name);
return;
}
- filename = membername;
+ filename = name;
nsym=0;
objtraverse(psym, 0);
printsyms(symptr, nsym);
diff --git a/src/cmd/prof/Makefile b/src/cmd/prof/Makefile
index 602c07da6..e643f267c 100644
--- a/src/cmd/prof/Makefile
+++ b/src/cmd/prof/Makefile
@@ -2,7 +2,8 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.conf
+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
@@ -12,19 +13,22 @@ TARG=6prof
OFILES=\
main.$O\
-#HFILES=\
-# defs.h\
-# fns.h\
+LIB=\
+ ../../../lib/libmach.a\
-$(TARG): $(OFILES)
- $(LD) -o $(TARG) -L"$(GOROOT)"/lib $(OFILES) -lmach -lbio -l9
+NOINSTALL=1
+include ../../Make.ccmd
-clean:
- rm -f *.$O $(TARG)
+ifeq ($(GOOS),windows)
+NAME=windows
+else
+NAME=$(shell uname | tr A-Z a-z)
+endif
-install: install-$(shell uname | tr A-Z a-z) install-pprof
+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)
@@ -33,7 +37,5 @@ install-darwin: $(TARG)
install-default: $(TARG)
cp $(TARG) "$(GOBIN)"/$(TARG)
-$(OFILES): $(HFILES)
-
install-pprof: gopprof
cp gopprof "$(GOBIN)"/gopprof
diff --git a/src/cmd/prof/gopprof b/src/cmd/prof/gopprof
index dffeeffa1..4bcfa5800 100755
--- a/src/cmd/prof/gopprof
+++ b/src/cmd/prof/gopprof
@@ -2736,6 +2736,7 @@ sub IsSymbolizedProfileFile {
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
@@ -2816,7 +2817,7 @@ sub ResolveRedirectionForCurl {
# $main::prog to have the correct program name.
sub ReadSymbols {
my $in = shift;
- my $map = {};
+ 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.
@@ -2858,20 +2859,30 @@ sub FetchSymbols {
my @pcs = grep { !$seen{$_}++ } keys(%$pcset); # uniq
if (!defined($symbol_map)) {
- my $post_data = join("+", sort((map {"0x" . "$_"} @pcs)));
-
- 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);
- $symbol_map = ReadSymbols(*SYMBOL{IO});
- close(SYMBOL);
+ $symbol_map = {};
+ my @toask = @pcs;
+ while (@toask > 0) {
+ my $n = @toask;
+ if ($n > 49) { $n = 49; }
+ my @thisround = @toask[0..$n];
+my $t = @toask;
+print STDERR "$n $t\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);
+
+print STDERR "SYMBL!\n";
+ 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 = {};
diff --git a/src/cmd/prof/main.c b/src/cmd/prof/main.c
index 2bb67f596..f36759cd3 100644
--- a/src/cmd/prof/main.c
+++ b/src/cmd/prof/main.c
@@ -53,9 +53,10 @@ Map *map[32]; // thread maps
void
Usage(void)
{
- fprint(2, "Usage: prof -p pid [-t total_secs] [-d delta_msec] [6.out args ...]\n");
+ 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-c file.prof: write [c]pprof output to file.prof\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");
@@ -192,22 +193,22 @@ amd64_ppword(uvlong w)
void
x86_regprint(void)
{
- fprint(2, "ax\t0x%llux\n", ureg_x86.ax);
- fprint(2, "bx\t0x%llux\n", ureg_x86.bx);
- fprint(2, "cx\t0x%llux\n", ureg_x86.cx);
- fprint(2, "dx\t0x%llux\n", ureg_x86.dx);
- fprint(2, "si\t0x%llux\n", ureg_x86.si);
- fprint(2, "di\t0x%llux\n", ureg_x86.di);
- fprint(2, "bp\t0x%llux\n", ureg_x86.bp);
- fprint(2, "ds\t0x%llux\n", ureg_x86.ds);
- fprint(2, "es\t0x%llux\n", ureg_x86.es);
- fprint(2, "fs\t0x%llux\n", ureg_x86.fs);
- fprint(2, "gs\t0x%llux\n", ureg_x86.gs);
- fprint(2, "cs\t0x%llux\n", ureg_x86.cs);
- fprint(2, "flags\t0x%llux\n", ureg_x86.flags);
- fprint(2, "pc\t0x%llux\n", ureg_x86.pc);
- fprint(2, "sp\t0x%llux\n", ureg_x86.sp);
- fprint(2, "ss\t0x%llux\n", ureg_x86.ss);
+ 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
diff --git a/src/env.bash b/src/env.bash
index 2a63e6480..2518c4233 100644
--- a/src/env.bash
+++ b/src/env.bash
@@ -3,24 +3,11 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-if test -z "$GOBIN"; then
- if ! test -d "$HOME"/bin; then
- echo '$GOBIN is not set and $HOME/bin is not a directory or does not exist.' 1>&2
- echo 'mkdir $HOME/bin or set $GOBIN to a directory where binaries should' 1>&2
- echo 'be installed.' 1>&2
- exit 1
- fi
- GOBIN="$HOME/bin"
-elif ! test -d "$GOBIN"; 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 GOROOT=${GOROOT:-$(cd ..; pwd)}
-GOROOT=${GOROOT:-$(cd ..; pwd)}
if ! test -f "$GOROOT"/include/u.h
then
- echo '$GOROOT is not set correctly or not exported' 1>&2
+ echo '$GOROOT is not set correctly or not exported: '$GOROOT 1>&2
exit 1
fi
@@ -28,28 +15,35 @@ fi
# 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)
+DIR2=$(cd "$GOROOT"; pwd)
if [ "$DIR1" != "$DIR2" ]; then
- echo 'Suspicious $GOROOT: does not match current directory.' 1>&2
+ echo 'Suspicious $GOROOT '"$GOROOT"': does not match current directory.' 1>&2
exit 1
fi
-GOARCH=${GOARCH:-$(uname -m | sed 's/^..86$/386/; s/^.86$/386/; s/x86_64/amd64/')}
-case "$GOARCH" in
-amd64 | 386 | arm)
- ;;
-*)
- echo '$GOARCH is set to <'$GOARCH'>, must be amd64, 386, or arm' 1>&2
- exit 1
-esac
-
-GOOS=${GOOS:-$(uname | tr A-Z a-z)}
-case "$GOOS" in
-darwin | freebsd | linux | windows | nacl)
- ;;
-*)
- echo '$GOOS is set to <'$GOOS'>, must be darwin, freebsd, linux, windows, or nacl' 1>&2
+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
-esac
+fi
+
+export OLDPATH=$PATH
+export PATH=/bin:/usr/bin:"$GOBIN":$PATH
+
+MAKE=make
+if ! make --version 2>/dev/null | grep 'GNU Make' >/dev/null; then
+ MAKE=gmake
+fi
-export GOBIN GOROOT GOARCH GOOS
+# 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|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 ccaf41a0f..a10d7730a 100644
--- a/src/lib9/Makefile
+++ b/src/lib9/Makefile
@@ -2,7 +2,8 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../Make.conf
+include ../Make.inc
+O:=$(HOST_O)
LIB=lib9.a
@@ -101,38 +102,19 @@ OFILES=\
$(UTFOFILES)\
HFILES=\
- "$(GOROOT)"/include/u.h\
- "$(GOROOT)"/include/libc.h\
+ $(QUOTED_GOROOT)/include/u.h\
+ $(QUOTED_GOROOT)/include/libc.h\
-install: $(LIB)
- cp $(LIB) "$(GOROOT)/lib"
+include ../Make.clib
-$(LIB): $(OFILES)
- ar rsc $(LIB) $(OFILES)
+GOROOT_FINAL?=$(GOROOT)
%.$O: fmt/%.c
- $(CC) -c $(CFLAGS) -DPLAN9PORT -Ifmt $<
+ $(HOST_CC) -c $(HOST_CFLAGS) -DPLAN9PORT -Ifmt $<
%.$O: utf/%.c
- $(CC) -c $(CFLAGS) $<
+ $(HOST_CC) -c $(HOST_CFLAGS) $<
goos.$O: goos.c
- $(CC) -c $(CFLAGS) -DGOOS='"$(GOOS)"' -DGOARCH='"$(GOARCH)"' -DGOROOT='"$(GOROOT)"' -DGOVERSION='"'"$$(../version.bash)"'"' $<
-
-clean:
- rm -f *.$O *.6 6.out $(LIB)
-
-nuke: clean
- rm -f "$(GOROOT)"/lib/$(LIB)
-
-#XLIB=$PLAN9/lib/$LIB
-
-#testfmt: testfmt.$O $XLIB
-# $LD -o $target testfmt.$O
-
-#testfltfmt: testfltfmt.$O $XLIB
-# $LD -o $target testfltfmt.$O
-
-#testprint: testprint.$O $XLIB
-# $LD -o $target testprint.$O
+ $(HOST_CC) -c $(HOST_CFLAGS) -DGOOS='"$(GOOS)"' -DGOARCH='"$(GOARCH)"' -DGOROOT='"$(GOROOT_FINAL)"' -DGOVERSION='"'"$$(../version.bash)"'"' $<
diff --git a/src/lib9/dirfwstat.c b/src/lib9/dirfwstat.c
index 15f1c1252..fe9153b9b 100644
--- a/src/lib9/dirfwstat.c
+++ b/src/lib9/dirfwstat.c
@@ -61,7 +61,7 @@ dirfwstat(int fd, Dir *dir)
struct timeval tv[2];
ret = 0;
-#ifndef __MINGW32__
+#ifndef _WIN32
if(~dir->mode != 0){
if(fchmod(fd, dir->mode) < 0)
ret = -1;
diff --git a/src/lib9/dirstat.c b/src/lib9/dirstat.c
index 6c476753b..6d804ca7c 100644
--- a/src/lib9/dirstat.c
+++ b/src/lib9/dirstat.c
@@ -39,7 +39,7 @@ dirstat(char *file)
Dir *d;
char *str;
-#ifdef __MINGW32__
+#ifdef _WIN32
if(stat(file, &st) < 0)
return nil;
lst = st;
diff --git a/src/lib9/time.c b/src/lib9/time.c
index 720dd702e..7394e9e60 100644
--- a/src/lib9/time.c
+++ b/src/lib9/time.c
@@ -25,7 +25,7 @@ THE SOFTWARE.
#include <u.h>
#include <sys/time.h>
#include <time.h>
-#ifndef __MINGW32__
+#ifndef _WIN32
#include <sys/resource.h>
#endif
#define NOPLAN9DEFINES
@@ -34,7 +34,7 @@ THE SOFTWARE.
long
p9times(long *t)
{
-#ifdef __MINGW32__
+#ifdef _WIN32
memset(t, 0, 4*sizeof(long));
#else
struct rusage ru, cru;
diff --git a/src/lib9/utf/Makefile b/src/lib9/utf/Makefile
new file mode 100644
index 000000000..bd15f9eab
--- /dev/null
+++ b/src/lib9/utf/Makefile
@@ -0,0 +1,16 @@
+# Copyright 2010 The Go 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 library is built by the Makefile in the parent directory.
+# This Makefile only builds mkrunetype.
+
+include ../../Make.inc
+O:=$(HOST_O)
+
+TARG=mkrunetype
+
+OFILES=\
+ mkrunetype.$O\
+
+include ../../Make.ccmd
diff --git a/src/lib9/utf/mkrunetype.c b/src/lib9/utf/mkrunetype.c
index f1a9f8a77..848056451 100644
--- a/src/lib9/utf/mkrunetype.c
+++ b/src/lib9/utf/mkrunetype.c
@@ -32,11 +32,9 @@
* isdigitrune is true iff c is a numeric-digit category.
*/
+#include <u.h>
+#include <libc.h>
#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <libgen.h>
#include "utf.h"
#include "utfdef.h"
@@ -149,8 +147,8 @@ main(int argc, char *argv[]){
last = -1;
while(getunicodeline(in, fields, buf)){
code = getcode(fields[FIELD_CODE]);
- if (code >= NRUNES)
- fatal("code-point value too big: %x", code);
+ if (code >= NRUNES)
+ fatal("code-point value too big: %x", code);
if(code <= last)
fatal("bad code sequence: %x then %x", last, code);
last = code;
@@ -588,8 +586,7 @@ mkisronly(const char* label, char* prop) {
static void
mktables(char *src, int usepairs)
{
- printf("/* generated automatically by mkrunetype.c from %s */\n\n",
- basename(src));
+ printf("/* generated automatically by mkrunetype.c from %s */\n\n", src);
/*
* we special case the space and digit tables, since they are assumed
@@ -703,8 +700,8 @@ getcode(char *s)
int i, code;
code = 0;
- i = 0;
- /* Parse a hex number */
+ i = 0;
+ /* Parse a hex number */
while(s[i]) {
code <<= 4;
if(s[i] >= '0' && s[i] <= '9')
@@ -713,7 +710,7 @@ getcode(char *s)
code += s[i] - 'A' + 10;
else
fatal("bad code char '%c'", s[i]);
- i++;
+ i++;
}
return code;
}
diff --git a/src/lib9/utf/runetype.c b/src/lib9/utf/runetype.c
index ff2dbb539..19cf433e5 100644
--- a/src/lib9/utf/runetype.c
+++ b/src/lib9/utf/runetype.c
@@ -46,14 +46,27 @@ rbsearch(Rune c, Rune *t, int n, int ne)
* chars as ideographic as well: 20000..2a6d6, and 2f800..2Fa1d.
*/
static Rune __isideographicr[] = {
- 0x3006, 0x3007, /* 3006 not in Unicode 2, in 2.1 */
+ 0x3006, 0x3007, /* 0x3006 added in 2.0.14 */
0x3021, 0x3029,
- 0x3038, 0x303a, /* not in Unicode 2 or 2.1 */
- 0x3400, 0x4db5, /* not in Unicode 2 or 2.1 */
- 0x4e00, 0x9fbb, /* 0x9FA6..0x9FBB added for 4.1.0? */
+ 0x3038, 0x303a, /* added in 3.0.0 */
+ 0x3400, 0x4db5, /* added in 3.0.0 */
+
+ /* consecutive */
+ 0x4e00, 0x9fa5,
+ 0x9fa6, 0x9fbb, /* added in 4.1.0 */
+ 0x9fbc, 0x9fc3, /* added in 5.1.0 */
+ 0x9fc4, 0x9fcb, /* added in 5.2.0 */
+
0xf900, 0xfa2d,
- 0x20000, 0x2A6D6,
- 0x2F800, 0x2FA1D,
+
+ /* consecutive */
+ 0xfa30, 0xfa6a, /* added in 5.1.0 */
+ 0xfa6b, 0xfa6d, /* added in 5.2.0 */
+
+ 0xfa70, 0xfad9, /* added in 4.1.0 */
+ 0x20000, 0x2a6d6, /* added in 3.1.0 */
+ 0x2a700, 0x2b734, /* added in 5.2.0 */
+ 0x2f800, 0x2fa1d, /* added in 3.1.0 */
};
int
@@ -67,4 +80,4 @@ isideographicrune(Rune c)
return 0;
}
-#include "runetypebody-5.0.0.c"
+#include "runetypebody-5.2.0.c"
diff --git a/src/lib9/utf/runetypebody-5.2.0.c b/src/lib9/utf/runetypebody-5.2.0.c
new file mode 100644
index 000000000..4ff66b9d9
--- /dev/null
+++ b/src/lib9/utf/runetypebody-5.2.0.c
@@ -0,0 +1,1541 @@
+/* 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/libbio/Makefile b/src/libbio/Makefile
index 32fdedd91..4340b0eae 100644
--- a/src/libbio/Makefile
+++ b/src/libbio/Makefile
@@ -22,7 +22,8 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
-include ../Make.conf
+include ../Make.inc
+O:=$(HOST_O)
LIB=libbio.a
@@ -47,19 +48,4 @@ OFILES=\
HFILES=\
../../include/bio.h
-install: $(LIB)
- cp $(LIB) ../../lib
-
-$(LIB): $(OFILES)
- ar rsc $(LIB) $(OFILES)
-
-$(OFILES): $(HFILES)
-
-y.tab.c: $(YFILES)
- yacc $(YFLAGS) $(YFILES)
-
-clean:
- rm -f $(OFILES) *.6 6.out $(LIB)
-
-nuke: clean
- rm -f ../../lib/$(LIB)
+include ../Make.clib
diff --git a/src/libbio/bprint.c b/src/libbio/bprint.c
index 2e3867ae6..b5d3e9ece 100644
--- a/src/libbio/bprint.c
+++ b/src/libbio/bprint.c
@@ -3,6 +3,7 @@ http://code.google.com/p/inferno-os/source/browse/libbio/bprint.c
Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
+ Revisions Copyright © 2010 Google Inc. 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
@@ -30,25 +31,52 @@ THE SOFTWARE.
int
Bprint(Biobuf *bp, char *fmt, ...)
{
- va_list ap;
- char *ip, *ep, *out;
- int n;
-
- ep = (char*)bp->ebuf;
- ip = ep + bp->ocount;
- va_start(ap, fmt);
- out = vseprint(ip, ep, fmt, ap);
- va_end(ap);
- if(out == nil || out >= ep-5) {
- Bflush(bp);
- ip = ep + bp->ocount;
- va_start(ap, fmt);
- out = vseprint(ip, ep, fmt, ap);
- va_end(ap);
- if(out >= ep-5)
- return Beof;
- }
- n = out-ip;
- bp->ocount += n;
- return n;
+ int n;
+ va_list arg;
+
+ va_start(arg, fmt);
+ n = Bvprint(bp, fmt, arg);
+ va_end(arg);
+ return n;
+}
+
+static int
+bflush(Fmt *f)
+{
+ Biobuf *bp;
+
+ if(f->stop == nil)
+ return 0;
+
+ bp = f->farg;
+ bp->ocount = (char*)f->to - (char*)f->stop;
+ if(Bflush(bp) < 0) {
+ f->stop = nil;
+ f->to = nil;
+ return 0;
+ }
+ f->to = (char*)f->stop + bp->ocount;
+
+ return 1;
+}
+
+int
+Bvprint(Biobuf *bp, char *fmt, va_list arg)
+{
+ int n;
+ Fmt f;
+
+ memset(&f, 0, sizeof f);
+ fmtlocaleinit(&f, nil, nil, nil);
+ f.stop = bp->ebuf;
+ f.to = (char*)f.stop + bp->ocount;
+ f.flush = bflush;
+ f.farg = bp;
+
+ n = fmtvprint(&f, fmt, arg);
+
+ if(f.stop != nil)
+ bp->ocount = (char*)f.to - (char*)f.stop;
+
+ return n;
}
diff --git a/src/libbio/bseek.c b/src/libbio/bseek.c
index be00ab1a7..291498108 100644
--- a/src/libbio/bseek.c
+++ b/src/libbio/bseek.c
@@ -33,7 +33,7 @@ Bseek(Biobuf *bp, vlong offset, int base)
vlong n, d;
int bufsz;
-#ifndef __MINGW32__
+#ifndef _WIN32
if(sizeof(offset) != sizeof(off_t)) {
fprint(2, "Bseek: libbio compiled with %d-byte offset\n", sizeof(off_t));
abort();
diff --git a/src/libcgo/Makefile b/src/libcgo/Makefile
deleted file mode 100755
index 0d65af70c..000000000
--- a/src/libcgo/Makefile
+++ /dev/null
@@ -1,42 +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.
-
-# ugly hack to deal with whitespaces in $GOROOT
-nullstring :=
-space := $(nullstring) # a space at the end
-QUOTED_GOROOT=$(subst $(space),\ ,$(GOROOT))
-
-all: libcgo.so
-
-install: $(QUOTED_GOROOT)/pkg/$(GOOS)_$(GOARCH)/libcgo.so
-
-OFILES=\
- $(GOOS)_$(GOARCH).o\
- $(GOARCH).o\
- util.o\
-
-CFLAGS_386=-m32
-CFLAGS_amd64=-m64
-
-
-LDFLAGS_linux=-shared -lpthread -lm
-LDFLAGS_darwin=-dynamiclib -Wl,-undefined,dynamic_lookup /usr/lib/libpthread.dylib
-LDFLAGS_freebsd=-pthread -shared -lm
-LDFLAGS_windows=-shared -lm -mthreads
-
-%.o: %.c
- gcc $(CFLAGS_$(GOARCH)) -O2 -fPIC -o $@ -c $*.c
-
-%.o: %.S
- gcc $(CFLAGS_$(GOARCH)) -O2 -fPIC -o $@ -c $*.S
-
-libcgo.so: $(OFILES)
- gcc $(CFLAGS_$(GOARCH)) -o libcgo.so $(OFILES) $(LDFLAGS_$(GOOS))
-
-$(QUOTED_GOROOT)/pkg/$(GOOS)_$(GOARCH)/libcgo.so: libcgo.so
- cp libcgo.so $(QUOTED_GOROOT)/pkg/$(GOOS)_$(GOARCH)
-
-clean:
- rm -f *.o *.so
-
diff --git a/src/libcgo/darwin_amd64.c b/src/libcgo/darwin_amd64.c
deleted file mode 100644
index 2e0e12411..000000000
--- a/src/libcgo/darwin_amd64.c
+++ /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.
-
-#include <pthread.h>
-#include "libcgo.h"
-
-static void* threadentry(void*);
-
-static pthread_key_t km, kg;
-
-void
-initcgo(void)
-{
- if(pthread_key_create(&km, nil) < 0) {
- fprintf(stderr, "libcgo: pthread_key_create failed\n");
- abort();
- }
- if(pthread_key_create(&kg, nil) < 0) {
- fprintf(stderr, "libcgo: pthread_key_create failed\n");
- abort();
- }
-}
-
-void
-libcgo_sys_thread_start(ThreadStart *ts)
-{
- pthread_attr_t attr;
- pthread_t p;
- size_t size;
-
- pthread_attr_init(&attr);
- pthread_attr_getstacksize(&attr, &size);
- ts->g->stackguard = size;
- pthread_create(&p, &attr, threadentry, ts);
-}
-
-static void*
-threadentry(void *v)
-{
- ThreadStart ts;
-
- ts = *(ThreadStart*)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;
-
- crosscall_amd64(ts.m, ts.g, ts.fn);
- return nil;
-}
-
-void
-libcgo_set_scheduler(void *m, void *g)
-{
- pthread_setspecific(km, m);
- pthread_setspecific(kg, g);
-}
-
-struct get_scheduler_args {
- void *m;
- void *g;
-};
-
-void libcgo_get_scheduler(struct get_scheduler_args *)
- __attribute__ ((visibility("hidden")));
-
-void
-libcgo_get_scheduler(struct get_scheduler_args *p)
-{
- p->m = pthread_getspecific(km);
- p->g = pthread_getspecific(kg);
-}
diff --git a/src/libcgo/freebsd_amd64.c b/src/libcgo/freebsd_amd64.c
deleted file mode 100644
index 4baf16ee8..000000000
--- a/src/libcgo/freebsd_amd64.c
+++ /dev/null
@@ -1,74 +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 <pthread.h>
-#include "libcgo.h"
-
-static void* threadentry(void*);
-
-char *environ[] = { 0 };
-char *__progname;
-
-void
-initcgo(void)
-{
-}
-
-void
-libcgo_sys_thread_start(ThreadStart *ts)
-{
- pthread_attr_t attr;
- pthread_t p;
- size_t size;
-
- pthread_attr_init(&attr);
- pthread_attr_getstacksize(&attr, &size);
- ts->g->stackguard = size;
- pthread_create(&p, &attr, threadentry, ts);
-}
-
-static void*
-threadentry(void *v)
-{
- ThreadStart ts;
-
- ts = *(ThreadStart*)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;
-
- crosscall_amd64(ts.m, ts.g, ts.fn);
- return nil;
-}
-
-static __thread void *libcgo_m;
-static __thread void *libcgo_g;
-
-void
-libcgo_set_scheduler(void *m, void *g)
-{
- libcgo_m = m;
- libcgo_g = g;
-}
-
-struct get_scheduler_args {
- void *m;
- void *g;
-};
-
-void libcgo_get_scheduler(struct get_scheduler_args *)
- __attribute__ ((visibility("hidden")));
-
-void
-libcgo_get_scheduler(struct get_scheduler_args *p)
-{
- p->m = libcgo_m;
- p->g = libcgo_g;
-}
diff --git a/src/libcgo/nacl_386.c b/src/libcgo/nacl_386.c
deleted file mode 100644
index 32d862984..000000000
--- a/src/libcgo/nacl_386.c
+++ /dev/null
@@ -1 +0,0 @@
-/* unimplemented */
diff --git a/src/libcgo/windows_386.c b/src/libcgo/windows_386.c
deleted file mode 100755
index 62be9303e..000000000
--- a/src/libcgo/windows_386.c
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#include "libcgo.h"
-
-static void *threadentry(void*);
-
-/* From what I've read 1MB is default for 32-bit Linux.
- Allocation granularity on Windows is typically 64 KB. */
-#define STACKSIZE (1*1024*1024)
-
-void
-initcgo(void)
-{
-}
-
-void
-libcgo_sys_thread_start(ThreadStart *ts)
-{
- ts->g->stackguard = STACKSIZE;
- _beginthread(threadentry, STACKSIZE, ts);
-}
-
-static void*
-threadentry(void *v)
-{
- ThreadStart ts;
-
- ts = *(ThreadStart*)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;
-
- crosscall_386(ts.fn);
- return nil;
-}
diff --git a/src/libmach/5obj.c b/src/libmach/5obj.c
index 034deea2c..e539362b0 100644
--- a/src/libmach/5obj.c
+++ b/src/libmach/5obj.c
@@ -123,6 +123,9 @@ addr(Biobuf *bp)
case D_PSR:
case D_FPCR:
break;
+ case D_REGREG:
+ Bgetc(bp);
+ break;
case D_CONST2:
Bgetc(bp);
Bgetc(bp);
diff --git a/src/libmach/8db.c b/src/libmach/8db.c
index 92e4c7694..80aa4fe69 100644
--- a/src/libmach/8db.c
+++ b/src/libmach/8db.c
@@ -329,8 +329,8 @@ struct Instr
uchar mod; /* bits 6-7 of mod r/m field */
uchar reg; /* bits 3-5 of mod r/m field */
char ss; /* bits 6-7 of SIB */
- char index; /* bits 3-5 of SIB */
- char base; /* bits 0-2 of SIB */
+ schar index; /* bits 3-5 of SIB */
+ schar base; /* bits 0-2 of SIB */
char rip; /* RIP-relative in amd64 mode */
uchar opre; /* f2/f3 could introduce media */
short seg; /* segment of far address */
@@ -355,14 +355,15 @@ enum{
DI,
/* amd64 */
- R8,
- R9,
- R10,
- R11,
- R12,
- R13,
- R14,
- R15
+ /* be careful: some unix system headers #define R8, R9, etc */
+ AMD64_R8,
+ AMD64_R9,
+ AMD64_R10,
+ AMD64_R11,
+ AMD64_R12,
+ AMD64_R13,
+ AMD64_R14,
+ AMD64_R15
};
/* amd64 rex extension byte */
@@ -416,8 +417,8 @@ enum {
RMOPB, /* Byte R/M field with op code (/digit) */
RMR, /* R/M register only (mod = 11) */
RMM, /* R/M memory only (mod = 0/1/2) */
- R0, /* Base reg of Mod R/M is literal 0x00 */
- R1, /* Base reg of Mod R/M is literal 0x01 */
+ Op_R0, /* Base reg of Mod R/M is literal 0x00 */
+ Op_R1, /* Base reg of Mod R/M is literal 0x01 */
FRMOP, /* Floating point R/M field with opcode */
FRMEX, /* Extended floating point R/M field with opcode */
JUMP, /* Jump or Call flag - no operand */
@@ -1006,7 +1007,7 @@ static Optable optabDA[8+8] =
[0x09] 0,0, "FCMOVEQ %f,F0",
[0x0a] 0,0, "FCMOVLS %f,F0",
[0x0b] 0,0, "FCMOVUN %f,F0",
-[0x0d] R1,0, "FUCOMPP",
+[0x0d] Op_R1,0, "FUCOMPP",
};
static Optable optabDB[8+64] =
@@ -1071,7 +1072,7 @@ static Optable optabDE[8+8] =
[0x07] 0,0, "FDIVRW %e,F0",
[0x08] 0,0, "FADDDP F0,%f",
[0x09] 0,0, "FMULDP F0,%f",
-[0x0b] R1,0, "FCOMPDP",
+[0x0b] Op_R1,0, "FCOMPDP",
[0x0c] 0,0, "FSUBRDP F0,%f",
[0x0d] 0,0, "FSUBDP F0,%f",
[0x0e] 0,0, "FDIVRDP F0,%f",
@@ -1087,7 +1088,7 @@ static Optable optabDF[8+8] =
[0x05] 0,0, "FMOVL %e,F0",
[0x06] 0,0, "FBSTP %e",
[0x07] 0,0, "FMOVLP F0,%e",
-[0x0c] R0,0, "FSTSW %OAX",
+[0x0c] Op_R0,0, "FSTSW %OAX",
[0x0d] 0,0, "FUCOMIP F0,%f",
[0x0e] 0,0, "FCOMIP F0,%f",
};
@@ -1713,11 +1714,11 @@ badop:
if (c != 0x0a)
goto badop;
break;
- case R0: /* base register must be R0 */
+ case Op_R0: /* base register must be R0 */
if (ip->base != 0)
goto badop;
break;
- case R1: /* base register must be R1 */
+ case Op_R1: /* base register must be R1 */
if (ip->base != 1)
goto badop;
break;
@@ -1903,14 +1904,14 @@ static char *reg[] = {
[DI] "DI",
/* amd64 */
-[R8] "R8",
-[R9] "R9",
-[R10] "R10",
-[R11] "R11",
-[R12] "R12",
-[R13] "R13",
-[R14] "R14",
-[R15] "R15",
+[AMD64_R8] "R8",
+[AMD64_R9] "R9",
+[AMD64_R10] "R10",
+[AMD64_R11] "R11",
+[AMD64_R12] "R12",
+[AMD64_R13] "R13",
+[AMD64_R14] "R14",
+[AMD64_R15] "R15",
};
static char *breg[] = { "AL", "CL", "DL", "BL", "AH", "CH", "DH", "BH" };
diff --git a/src/libmach/Makefile b/src/libmach/Makefile
index 900d27861..5d7e87d86 100644
--- a/src/libmach/Makefile
+++ b/src/libmach/Makefile
@@ -26,7 +26,8 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
-include ../Make.conf
+include ../Make.inc
+O:=$(HOST_O)
LIB=libmach.a
OFILES=\
@@ -52,21 +53,12 @@ ifneq ($(GOOS),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
-install: $(LIB)
- cp $(LIB) ../../lib
-
-$(LIB): $(OFILES)
- ar rsc $(LIB) $(OFILES)
-
-$(OFILES): $(HFILES)
-
-clean:
- rm -f *.$O $(LIB)
-
-nuke: clean
- rm -f "$(GOROOT)"/lib/$(LIB)
-
+include ../Make.clib
diff --git a/src/libmach/darwin.c b/src/libmach/darwin.c
index feb49c059..7ee6f7ace 100644
--- a/src/libmach/darwin.c
+++ b/src/libmach/darwin.c
@@ -807,8 +807,10 @@ ctlproc(int id, char *msg)
// Find Mach thread for pid and suspend it.
t = addpid(id, 1);
- if(t == nil)
+ if(t == nil) {
+ fprint(2, "ctlproc attached: addpid: %r\n");
return -1;
+ }
if(me(thread_suspend(t->thread)) < 0){
fprint(2, "ctlproc attached: thread_suspend: %r\n");
return -1;
@@ -816,7 +818,12 @@ ctlproc(int id, char *msg)
// Let ptrace tell the process to keep going:
// then ptrace is out of the way and we're back in Mach land.
- return ptrace(PT_CONTINUE, id, (caddr_t)1, 0);
+ if(ptrace(PT_CONTINUE, id, (caddr_t)1, 0) < 0) {
+ fprint(2, "ctlproc attached: ptrace continue: %r\n");
+ return -1;
+ }
+
+ return 0;
}
// All the other control messages require a Thread structure.
diff --git a/src/libmach/executable.c b/src/libmach/executable.c
index 34da72151..33000ed07 100644
--- a/src/libmach/executable.c
+++ b/src/libmach/executable.c
@@ -66,7 +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 void setsym(Fhdr*, int32, int32, int32, vlong);
+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);
static void hswal(void*, int, uint32(*)(uint32));
@@ -427,7 +427,7 @@ adotout(int fd, Fhdr *fp, ExecHdr *hp)
hp->e.exechdr.text, sizeof(Exec));
setdata(fp, _round(pgsize+fp->txtsz+sizeof(Exec), pgsize),
hp->e.exechdr.data, fp->txtsz+sizeof(Exec), hp->e.exechdr.bss);
- setsym(fp, hp->e.exechdr.syms, hp->e.exechdr.spsz, hp->e.exechdr.pcsz, fp->datoff+fp->datsz);
+ setsym(fp, fp->datoff+fp->datsz, hp->e.exechdr.syms, 0, hp->e.exechdr.spsz, 0, hp->e.exechdr.pcsz);
return 1;
}
@@ -525,7 +525,7 @@ commonllp64(int unused, Fhdr *fp, ExecHdr *hp)
settext(fp, entry, pgsize+fp->hdrsz, hp->e.exechdr.text, fp->hdrsz);
setdata(fp, _round(pgsize+fp->txtsz+fp->hdrsz, pgsize),
hp->e.exechdr.data, fp->txtsz+fp->hdrsz, hp->e.exechdr.bss);
- setsym(fp, hp->e.exechdr.syms, hp->e.exechdr.spsz, hp->e.exechdr.pcsz, fp->datoff+fp->datsz);
+ setsym(fp, fp->datoff+fp->datsz, hp->e.exechdr.syms, 0, hp->e.exechdr.spsz, 0, hp->e.exechdr.pcsz);
if(hp->e.exechdr.magic & DYN_MAGIC) {
fp->txtaddr = 0;
@@ -758,13 +758,12 @@ elf64dotout(int fd, Fhdr *fp, ExecHdr *hp)
bsssz = ph[0].memsz - ph[0].filesz;
settext(fp, ep->elfentry | 0x80000000, txtaddr, txtsz, ph[0].offset);
setdata(fp, dataddr, ph[0].paddr, ph[0].offset + txtsz, bsssz);
- setsym(fp, ph[1].filesz, 0, ph[1].memsz, ph[1].offset);
+ setsym(fp, ph[1].offset, ph[1].filesz, 0, 0, 0, ph[1].memsz);
free(ph);
return 1;
}
werrstr("No TEXT or DATA sections");
-error:
free(ph);
free(sh);
return 0;
@@ -773,12 +772,13 @@ error:
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);
if(is != -1)
- setsym(fp, ph[is].filesz, 0, ph[is].memsz, ph[is].offset);
+ setsym(fp, ph[is].offset, ph[is].filesz, 0, 0, 0, ph[is].memsz);
else if(sh != 0){
char *buf;
uvlong symsize = 0;
uvlong symoff = 0;
uvlong pclnsz = 0;
+ uvlong pclnoff = 0;
/* load shstrtab names */
buf = malloc(sh[ep->shstrndx].size);
@@ -786,7 +786,8 @@ error:
goto done;
memset(buf, 0, sizeof buf);
seek(fd, sh[ep->shstrndx].offset, 0);
- read(fd, buf, sh[ep->shstrndx].size);
+ i = read(fd, buf, sh[ep->shstrndx].size);
+ USED(i); // shut up ubuntu gcc
for(i = 0; i < ep->shnum; i++) {
if (strcmp(&buf[sh[i].name], ".gosymtab") == 0) {
@@ -794,15 +795,11 @@ error:
symoff = sh[i].offset;
}
if (strcmp(&buf[sh[i].name], ".gopclntab") == 0) {
- if (sh[i].offset != symoff+symsize) {
- werrstr("pc line table not contiguous with symbol table");
- free(buf);
- goto error;
- }
pclnsz = sh[i].size;
+ pclnoff = sh[i].offset;
}
}
- setsym(fp, symsize, 0, pclnsz, symoff);
+ setsym(fp, symoff, symsize, 0, 0, pclnoff, pclnsz);
free(buf);
}
done:
@@ -939,13 +936,12 @@ elfdotout(int fd, Fhdr *fp, ExecHdr *hp)
bsssz = ph[0].memsz - ph[0].filesz;
settext(fp, ep->elfentry | 0x80000000, txtaddr, txtsz, ph[0].offset);
setdata(fp, dataddr, ph[0].paddr, ph[0].offset + txtsz, bsssz);
- setsym(fp, ph[1].filesz, 0, ph[1].memsz, ph[1].offset);
+ setsym(fp, ph[1].offset, ph[1].filesz, 0, 0, 0, ph[1].memsz);
free(ph);
return 1;
}
werrstr("No TEXT or DATA sections");
-error:
free(sh);
free(ph);
return 0;
@@ -954,12 +950,13 @@ error:
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);
if(is != -1)
- setsym(fp, ph[is].filesz, 0, ph[is].memsz, ph[is].offset);
+ setsym(fp, ph[is].offset, ph[is].filesz, 0, 0, 0, ph[is].memsz);
else if(sh != 0){
char *buf;
uvlong symsize = 0;
uvlong symoff = 0;
- uvlong pclnsz = 0;
+ uvlong pclnsize = 0;
+ uvlong pclnoff = 0;
/* load shstrtab names */
buf = malloc(sh[ep->shstrndx].size);
@@ -967,7 +964,8 @@ error:
goto done;
memset(buf, 0, sizeof buf);
seek(fd, sh[ep->shstrndx].offset, 0);
- read(fd, buf, sh[ep->shstrndx].size);
+ i = read(fd, buf, sh[ep->shstrndx].size);
+ USED(i); // shut up ubuntu gcc
for(i = 0; i < ep->shnum; i++) {
if (strcmp(&buf[sh[i].name], ".gosymtab") == 0) {
@@ -975,15 +973,11 @@ error:
symoff = sh[i].offset;
}
if (strcmp(&buf[sh[i].name], ".gopclntab") == 0) {
- if (sh[i].offset != symoff+symsize) {
- werrstr("pc line table not contiguous with symbol table");
- free(buf);
- goto error;
- }
- pclnsz = sh[i].size;
+ pclnsize = sh[i].size;
+ pclnoff = sh[i].offset;
}
}
- setsym(fp, symsize, 0, pclnsz, symoff);
+ setsym(fp, symoff, symsize, 0, 0, pclnoff, pclnsize);
free(buf);
}
done:
@@ -1207,7 +1201,7 @@ machdotout(int fd, Fhdr *fp, ExecHdr *hp)
settext(fp, textva+sizeof(Machhdr) + mp->sizeofcmds, textva, textsize, textoff);
setdata(fp, datava, datasize, dataoff, bsssize);
if(symtab != 0)
- setsym(fp, symtab->filesize, 0, pclntab? pclntab->filesize : 0, symtab->fileoff);
+ setsym(fp, symtab->fileoff, symtab->filesize, 0, 0, 0, pclntab? pclntab->filesize : 0);
free(cmd);
free(cmdbuf);
return 1;
@@ -1228,7 +1222,7 @@ armdotout(int fd, Fhdr *fp, ExecHdr *hp)
USED(fd);
settext(fp, hp->e.exechdr.entry, sizeof(Exec), hp->e.exechdr.text, sizeof(Exec));
setdata(fp, fp->txtsz, hp->e.exechdr.data, fp->txtsz, hp->e.exechdr.bss);
- setsym(fp, hp->e.exechdr.syms, hp->e.exechdr.spsz, hp->e.exechdr.pcsz, fp->datoff+fp->datsz);
+ setsym(fp, fp->datoff+fp->datsz, hp->e.exechdr.syms, 0, hp->e.exechdr.spsz, 0, hp->e.exechdr.pcsz);
kbase = 0xF0000000;
if ((fp->entry & kbase) == kbase) { /* Boot image */
@@ -1259,14 +1253,20 @@ setdata(Fhdr *fp, uvlong a, int32 s, vlong off, int32 bss)
}
static void
-setsym(Fhdr *fp, int32 symsz, int32 sppcsz, int32 lnpcsz, vlong symoff)
+setsym(Fhdr *fp, vlong symoff, int32 symsz, vlong sppcoff, int32 sppcsz, vlong lnpcoff, int32 lnpcsz)
{
- fp->symsz = symsz;
fp->symoff = symoff;
+ fp->symsz = symsz;
+
+ if(sppcoff == 0)
+ sppcoff = symoff+symsz;
+ fp->sppcoff = symoff;
fp->sppcsz = sppcsz;
- fp->sppcoff = fp->symoff+fp->symsz;
+
+ if(lnpcoff == 0)
+ lnpcoff = sppcoff + sppcsz;
+ fp->lnpcoff = lnpcoff;
fp->lnpcsz = lnpcsz;
- fp->lnpcoff = fp->sppcoff+fp->sppcsz;
}
diff --git a/src/libmach/linux.c b/src/libmach/linux.c
index 46724b87e..30b4da240 100644
--- a/src/libmach/linux.c
+++ b/src/libmach/linux.c
@@ -199,9 +199,11 @@ attachthread(int pid, int tid, int *new, int newstate)
t = malloc(sizeof *t);
if(t == nil)
return nil;
- memset(t, 0, sizeof *t);
+ memset(t, 0, sizeof *t);
thr[nthr++] = t;
+ if(pid == 0 && nthr > 0)
+ pid = thr[0]->pid;
t->pid = pid;
t->tid = tid;
t->state = newstate;
@@ -296,7 +298,9 @@ wait1(int nohang)
if(nohang != 0)
nohang = WNOHANG;
+ status = 0;
tid = waitpid(-1, &status, __WALL|WUNTRACED|WSTOPPED|WCONTINUED|nohang);
+
if(tid < 0)
return -1;
if(tid == 0)
@@ -305,11 +309,15 @@ wait1(int nohang)
if(trace > 0 && status != NormalStop)
fprint(2, "TID %d: %#x\n", tid, status);
- // If we've not heard of this tid, something is wrong.
t = findthread(tid);
if(t == nil) {
- fprint(2, "ptrace waitpid: unexpected new tid %d status %#x\n", tid, status);
- return -1;
+ // Sometimes the kernel tells us about new threads
+ // before we see the parent clone.
+ t = attachthread(0, tid, &new, Stopped);
+ if(t == nil) {
+ fprint(2, "failed to attach to new thread %d\n", tid);
+ return -1;
+ }
}
if(WIFSTOPPED(status)) {
@@ -339,8 +347,6 @@ wait1(int nohang)
}
t->child = data;
attachthread(t->pid, t->child, &new, Running);
- if(!new)
- fprint(2, "ptrace child: not new\n");
break;
case PTRACE_EVENT_EXEC:
@@ -759,9 +765,9 @@ ptracerw(int type, int xtype, int isr, int pid, uvlong addr, void *v, uint n)
if(errno)
goto ptraceerr;
if(n-i >= sizeof(uintptr))
- *(uintptr*)((char*)v+i) = u;
+ memmove((char*)v+i, &u, sizeof(uintptr));
else{
- *(uintptr*)buf = u;
+ memmove(buf, &u, sizeof u);
memmove((char*)v+i, buf, n-i);
}
}else{
@@ -772,9 +778,9 @@ ptracerw(int type, int xtype, int isr, int pid, uvlong addr, void *v, uint n)
u = ptrace(xtype, pid, addr+i, 0);
if(errno)
return -1;
- *(uintptr*)buf = u;
+ memmove(buf, &u, sizeof u);
memmove(buf, (char*)v+i, n-i);
- u = *(uintptr*)buf;
+ memmove(&u, buf, sizeof u);
}
if(ptrace(type, pid, addr+i, u) < 0)
goto ptraceerr;
@@ -810,9 +816,22 @@ ptracesegrw(Map *map, Seg *seg, uvlong addr, void *v, uint n, int isr)
// Go 32-bit is
// DI SI BP NSP BX DX CX AX GS FS ES DS TRAP ECODE PC CS EFLAGS SP SS
-// uint go32tolinux32tab[] = {
-// 4, 3, 5, 15, 0, 2, 1, 6, 10, 9, 8, 7, -1, -1, 12, 13, 14, 15, 16
-// };
+uint go32tolinux32tab[] = {
+ 4, 3, 5, 15, 0, 2, 1, 6, 10, 9, 8, 7, -1, -1, 12, 13, 14, 15, 16
+};
+static int
+go32tolinux32(uvlong addr)
+{
+ int r;
+
+ if(addr%4 || addr/4 >= nelem(go32tolinux32tab))
+ return -1;
+ r = go32tolinux32tab[addr/4];
+ if(r < 0)
+ return -1;
+ return r*4;
+}
+
uint go32tolinux64tab[] = {
14, 13, 4, 19, 5, 12, 11, 10, 26, 25, 24, 23, -1, -1, 16, 17, 18, 19, 20
};
@@ -830,15 +849,24 @@ go32tolinux64(uvlong addr)
}
extern Mach mi386;
+extern Mach mamd64;
static int
go2linux(uvlong addr)
{
- // TODO(rsc): If this file is being compiled in 32-bit mode,
- // need to use the go32tolinux32 table instead.
+ if(sizeof(void*) == 4) {
+ if(mach == &mi386)
+ return go32tolinux32(addr);
+ werrstr("unsupported architecture");
+ return -1;
+ }
if(mach == &mi386)
return go32tolinux64(addr);
+ if(mach != &mamd64) {
+ werrstr("unsupported architecture");
+ return -1;
+ }
switch(addr){
case offsetof(Ureg64, ax):
diff --git a/src/libmach/windows.c b/src/libmach/windows.c
new file mode 100644
index 000000000..391761c18
--- /dev/null
+++ b/src/libmach/windows.c
@@ -0,0 +1,59 @@
+// 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 Windows");
+}
+
+char*
+proctextfile(int pid)
+{
+ sysfatal("proctextfile unimplemented in Windows");
+}
+
+char*
+procstatus(int pid)
+{
+ sysfatal("procstatus unimplemented in Windows");
+}
+
+Map*
+attachproc(int pid, Fhdr *fp)
+{
+ sysfatal("attachproc unimplemented in Windows");
+}
+
+void
+detachproc(Map *m)
+{
+ sysfatal("detachproc unimplemented in Windows");
+}
+
+int
+procthreadpids(int pid, int *p, int np)
+{
+ sysfatal("procthreadpids unimplemented in Windows");
+}
+
+int
+pread(int fd, void *buf, int count, int offset)
+{
+ sysfatal("pread unimplemented in Windows");
+}
+
+int
+pwrite(int fd, void *buf, int count, int offset)
+{
+ sysfatal("pwrite unimplemented in Windows");
+}
+
+int
+nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
+{
+ sysfatal("nanosleep unimplemented in Windows");
+}
diff --git a/src/make.bash b/src/make.bash
index b718bb956..0d0dae61f 100755
--- a/src/make.bash
+++ b/src/make.bash
@@ -4,23 +4,36 @@
# license that can be found in the LICENSE file.
set -e
+if [ ! -f env.bash ]; then
+ echo 'make.bash must be run from $GOROOT/src' 1>&2
+ exit 1
+fi
. ./env.bash
+# 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
-MAKE=make
-if ! make --version 2>/dev/null | grep 'GNU Make' >/dev/null; then
- MAKE=gmake
-fi
-(echo '#!/bin/sh'; echo 'exec '$MAKE' "$@"') >"$GOBIN"/gomake
+(
+ echo '#!/bin/sh'
+ echo 'export GOROOT=${GOROOT:-'$GOROOT_FINAL'}'
+ echo 'exec '$MAKE' "$@"'
+) >"$GOBIN"/gomake
chmod +x "$GOBIN"/gomake
if [ -d /selinux -a -f /selinux/booleans/allow_execstack ] ; then
@@ -45,10 +58,11 @@ fi
)
bash "$GOROOT"/src/clean.bash
-for i in lib9 libbio libmach cmd pkg libcgo cmd/cgo cmd/ebnflint cmd/godoc cmd/gofmt cmd/goinstall cmd/goyacc cmd/hgpatch
+# pkg builds libcgo and the Go programs in cmd.
+for i in lib9 libbio libmach cmd pkg
do
case "$i-$GOOS-$GOARCH" in
- libcgo-nacl-* | cmd/*-nacl-* | libcgo-linux-arm)
+ cmd/*-nacl-*)
;;
*)
# The ( ) here are to preserve the current directory
@@ -63,18 +77,41 @@ do
bash make.bash
;;
pkg)
- "$GOBIN"/gomake install
+ gomake install
;;
*)
- "$GOBIN"/gomake install
+ gomake install
esac
) || exit 1
esac
done
-case "`uname`" in
-Darwin)
- echo;
- echo %%% run sudo.bash to install debuggers
+# 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
-esac
+ 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".
+ fi
+}
+
+(installed) # run in sub-shell to avoid polluting environment
+
diff --git a/src/pkg/Makefile b/src/pkg/Makefile
index e489b71d4..05e2a26d1 100644
--- a/src/pkg/Makefile
+++ b/src/pkg/Makefile
@@ -9,18 +9,13 @@
#
# to rebuild the dependency information in Make.deps.
-nullstring :=
-space := $(nullstring) # a space at the end
-ifndef GOBIN
-QUOTED_HOME=$(subst $(space),\ ,$(HOME))
-GOBIN=$(QUOTED_HOME)/bin
-endif
-QUOTED_GOBIN=$(subst $(space),\ ,$(GOBIN))
+include ../Make.inc
all: install
DIRS=\
archive/tar\
+ archive/zip\
asn1\
big\
bufio\
@@ -36,9 +31,13 @@ DIRS=\
crypto/aes\
crypto/block\
crypto/blowfish\
+ crypto/cast5\
+ crypto/cipher\
+ crypto/elliptic\
crypto/hmac\
crypto/md4\
crypto/md5\
+ crypto/ocsp\
crypto/rand\
crypto/rc4\
crypto/ripemd160\
@@ -48,12 +47,14 @@ DIRS=\
crypto/sha512\
crypto/subtle\
crypto/tls\
+ crypto/twofish\
crypto/x509\
crypto/xtea\
debug/dwarf\
debug/macho\
debug/elf\
debug/gosym\
+ debug/pe\
debug/proc\
ebnf\
encoding/ascii85\
@@ -61,14 +62,13 @@ DIRS=\
encoding/binary\
encoding/git85\
encoding/hex\
+ encoding/line\
encoding/pem\
exec\
- exp/bignum\
exp/datafmt\
exp/draw\
exp/draw/x11\
exp/eval\
- exp/iterable\
expvar\
flag\
fmt\
@@ -78,26 +78,30 @@ DIRS=\
go/printer\
go/scanner\
go/token\
+ go/typechecker\
gob\
hash\
hash/adler32\
hash/crc32\
hash/crc64\
+ html\
http\
http/pprof\
image\
image/jpeg\
image/png\
+ index/suffixarray\
io\
io/ioutil\
json\
log\
math\
mime\
+ mime/multipart\
net\
+ net/dict\
+ net/textproto\
netchan\
- nntp\
- once\
os\
os/signal\
patch\
@@ -108,8 +112,10 @@ DIRS=\
rpc\
rpc/jsonrpc\
runtime\
+ runtime/cgo\
runtime/pprof\
scanner\
+ smtp\
sort\
strconv\
strings\
@@ -123,11 +129,30 @@ DIRS=\
testing/quick\
testing/script\
time\
+ try\
unicode\
utf16\
utf8\
websocket\
xml\
+ ../cmd/cgo\
+ ../cmd/ebnflint\
+ ../cmd/godoc\
+ ../cmd/gofmt\
+ ../cmd/goinstall\
+ ../cmd/govet\
+ ../cmd/goyacc\
+ ../cmd/hgpatch\
+
+ifeq ($(GOOS),linux)
+DIRS+=\
+ os/inotify\
+
+endif
+
+ifeq ($(GOOS),windows)
+DIRS:=$(filter-out runtime/cgo,$(DIRS))
+endif
NOTEST=\
debug/proc\
@@ -139,11 +164,22 @@ NOTEST=\
http/pprof\
image\
image/jpeg\
+ net/dict\
rand\
- runtime\
+ runtime/cgo\
runtime/pprof\
syscall\
+ testing\
testing/iotest\
+ try\
+ ../cmd/cgo\
+ ../cmd/ebnflint\
+ ../cmd/godoc\
+ ../cmd/gofmt\
+ ../cmd/goinstall\
+ ../cmd/govet\
+ ../cmd/goyacc\
+ ../cmd/hgpatch\
NOBENCH=\
container/vector\
@@ -153,24 +189,12 @@ ifeq ($(DISABLE_NET_TESTS),1)
NOTEST+=http net
endif
-# Disable tests that NaCl cannot run yet.
-ifeq ($(GOOS),nacl)
-NOTEST+=archive/tar # no pipe
-NOTEST+=debug/dwarf # no pread
-NOTEST+=debug/macho # no pread
-NOTEST+=debug/elf # no pread
-NOTEST+=exec # no pipe
-NOTEST+=http # no network
-NOTEST+=log # no runtime.Caller
-NOTEST+=net # no network
-NOTEST+=netchan # no network
-NOTEST+=os # many things unimplemented
+# Disable tests that windows cannot run yet.
+ifeq ($(GOOS),windows)
NOTEST+=os/signal # no signals
NOTEST+=path # tree walking does not work
-NOTEST+=rpc # no network
NOTEST+=syslog # no network
NOTEST+=time # no syscall.Kill, syscall.SIGCHLD for sleep tests
-NOTEST+=websocket # no network
endif
TEST=\
@@ -186,19 +210,19 @@ test.dirs: $(addsuffix .test, $(TEST))
bench.dirs: $(addsuffix .bench, $(BENCH))
%.clean:
- +cd $* && $(QUOTED_GOBIN)/gomake clean
+ +cd $* && gomake clean
%.install:
- +cd $* && $(QUOTED_GOBIN)/gomake install
+ +cd $* && gomake install
%.nuke:
- +cd $* && $(QUOTED_GOBIN)/gomake nuke
+ +cd $* && gomake nuke
%.test:
- +cd $* && $(QUOTED_GOBIN)/gomake test
+ +cd $* && gomake test
%.bench:
- +cd $* && $(QUOTED_GOBIN)/gomake bench
+ +cd $* && gomake bench
clean: clean.dirs
@@ -214,4 +238,9 @@ nuke: nuke.dirs
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
index 6a29de8f7..8897e883e 100644
--- a/src/pkg/archive/tar/Makefile
+++ b/src/pkg/archive/tar/Makefile
@@ -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 ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=archive/tar
GOFILES=\
diff --git a/src/pkg/archive/tar/reader_test.go b/src/pkg/archive/tar/reader_test.go
index cfc258507..aa4c797fb 100644
--- a/src/pkg/archive/tar/reader_test.go
+++ b/src/pkg/archive/tar/reader_test.go
@@ -136,7 +136,7 @@ testLoop:
break
}
if hdr != nil || err != nil {
- t.Errorf("test %d: Unexpected entry or error: hdr=%v err=%v", i, err)
+ t.Errorf("test %d: Unexpected entry or error: hdr=%v err=%v", i, hdr, err)
}
f.Close()
}
diff --git a/src/pkg/archive/tar/writer.go b/src/pkg/archive/tar/writer.go
index 1f2656d32..8673bad31 100644
--- a/src/pkg/archive/tar/writer.go
+++ b/src/pkg/archive/tar/writer.go
@@ -71,9 +71,7 @@ func (tw *Writer) cString(b []byte, s string) {
}
return
}
- for i, ch := range []byte(s) {
- b[i] = ch
- }
+ copy(b, s)
if len(s) < len(b) {
b[len(s)] = 0
}
diff --git a/src/pkg/archive/tar/writer_test.go b/src/pkg/archive/tar/writer_test.go
index 24db9b821..48b891140 100644
--- a/src/pkg/archive/tar/writer_test.go
+++ b/src/pkg/archive/tar/writer_test.go
@@ -141,7 +141,7 @@ testLoop:
}
}
if err := tw.Close(); err != nil {
- t.Errorf("test %d: Failed closing archive: %v", err)
+ 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
new file mode 100644
index 000000000..32a543133
--- /dev/null
+++ b/src/pkg/archive/zip/Makefile
@@ -0,0 +1,12 @@
+# Copyright 2010 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=archive/zip
+GOFILES=\
+ reader.go\
+ struct.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/archive/zip/reader.go b/src/pkg/archive/zip/reader.go
new file mode 100644
index 000000000..579ba1602
--- /dev/null
+++ b/src/pkg/archive/zip/reader.go
@@ -0,0 +1,278 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+The zip package provides support for reading ZIP archives.
+
+See: http://www.pkware.com/documents/casestudies/APPNOTE.TXT
+
+This package does not support ZIP64 or disk spanning.
+*/
+package zip
+
+import (
+ "bufio"
+ "bytes"
+ "compress/flate"
+ "hash"
+ "hash/crc32"
+ "encoding/binary"
+ "io"
+ "os"
+)
+
+var (
+ FormatError = os.NewError("not a valid zip file")
+ UnsupportedMethod = os.NewError("unsupported compression algorithm")
+ ChecksumError = os.NewError("checksum error")
+)
+
+type Reader struct {
+ r io.ReaderAt
+ File []*File
+ Comment string
+}
+
+type File struct {
+ FileHeader
+ zipr io.ReaderAt
+ zipsize int64
+ headerOffset uint32
+ bodyOffset int64
+}
+
+// OpenReader will open the Zip file specified by name and return a Reader.
+func OpenReader(name string) (*Reader, os.Error) {
+ f, err := os.Open(name, os.O_RDONLY, 0644)
+ if err != nil {
+ return nil, err
+ }
+ fi, err := f.Stat()
+ if err != nil {
+ return nil, err
+ }
+ return NewReader(f, fi.Size)
+}
+
+// NewReader returns a new Reader reading from r, which is assumed to
+// have the given size in bytes.
+func NewReader(r io.ReaderAt, size int64) (*Reader, os.Error) {
+ end, err := readDirectoryEnd(r, size)
+ if err != nil {
+ return nil, err
+ }
+ z := &Reader{
+ r: r,
+ File: make([]*File, end.directoryRecords),
+ Comment: end.comment,
+ }
+ rs := io.NewSectionReader(r, 0, size)
+ if _, err = rs.Seek(int64(end.directoryOffset), 0); err != nil {
+ return nil, err
+ }
+ buf := bufio.NewReader(rs)
+ for i := range z.File {
+ z.File[i] = &File{zipr: r, zipsize: size}
+ if err := readDirectoryHeader(z.File[i], buf); err != nil {
+ return nil, err
+ }
+ }
+ return z, nil
+}
+
+// Open returns a ReadCloser that provides access to the File's contents.
+func (f *File) Open() (rc io.ReadCloser, err os.Error) {
+ off := int64(f.headerOffset)
+ if f.bodyOffset == 0 {
+ r := io.NewSectionReader(f.zipr, off, f.zipsize-off)
+ if err = readFileHeader(f, r); err != nil {
+ return
+ }
+ if f.bodyOffset, err = r.Seek(0, 1); err != nil {
+ return
+ }
+ }
+ r := io.NewSectionReader(f.zipr, off+f.bodyOffset, int64(f.CompressedSize))
+ switch f.Method {
+ case 0: // store (no compression)
+ rc = nopCloser{r}
+ case 8: // DEFLATE
+ rc = flate.NewReader(r)
+ default:
+ err = UnsupportedMethod
+ }
+ if rc != nil {
+ rc = &checksumReader{rc, crc32.NewIEEE(), f.CRC32}
+ }
+ return
+}
+
+type checksumReader struct {
+ rc io.ReadCloser
+ hash hash.Hash32
+ sum uint32
+}
+
+func (r *checksumReader) Read(b []byte) (n int, err os.Error) {
+ n, err = r.rc.Read(b)
+ r.hash.Write(b[:n])
+ if err != os.EOF {
+ return
+ }
+ if r.hash.Sum32() != r.sum {
+ err = ChecksumError
+ }
+ return
+}
+
+func (r *checksumReader) Close() os.Error { return r.rc.Close() }
+
+type nopCloser struct {
+ io.Reader
+}
+
+func (f nopCloser) Close() os.Error { return nil }
+
+func readFileHeader(f *File, r io.Reader) (err os.Error) {
+ defer func() {
+ if rerr, ok := recover().(os.Error); ok {
+ err = rerr
+ }
+ }()
+ var (
+ signature uint32
+ filenameLength uint16
+ extraLength uint16
+ )
+ read(r, &signature)
+ if signature != fileHeaderSignature {
+ return FormatError
+ }
+ read(r, &f.ReaderVersion)
+ read(r, &f.Flags)
+ read(r, &f.Method)
+ read(r, &f.ModifiedTime)
+ read(r, &f.ModifiedDate)
+ read(r, &f.CRC32)
+ read(r, &f.CompressedSize)
+ read(r, &f.UncompressedSize)
+ read(r, &filenameLength)
+ read(r, &extraLength)
+ f.Name = string(readByteSlice(r, filenameLength))
+ f.Extra = readByteSlice(r, extraLength)
+ return
+}
+
+func readDirectoryHeader(f *File, r io.Reader) (err os.Error) {
+ defer func() {
+ if rerr, ok := recover().(os.Error); ok {
+ err = rerr
+ }
+ }()
+ var (
+ signature uint32
+ filenameLength uint16
+ extraLength uint16
+ commentLength uint16
+ startDiskNumber uint16 // unused
+ internalAttributes uint16 // unused
+ externalAttributes uint32 // unused
+ )
+ read(r, &signature)
+ if signature != directoryHeaderSignature {
+ return FormatError
+ }
+ read(r, &f.CreatorVersion)
+ read(r, &f.ReaderVersion)
+ read(r, &f.Flags)
+ read(r, &f.Method)
+ read(r, &f.ModifiedTime)
+ read(r, &f.ModifiedDate)
+ read(r, &f.CRC32)
+ read(r, &f.CompressedSize)
+ read(r, &f.UncompressedSize)
+ read(r, &filenameLength)
+ read(r, &extraLength)
+ read(r, &commentLength)
+ read(r, &startDiskNumber)
+ read(r, &internalAttributes)
+ read(r, &externalAttributes)
+ read(r, &f.headerOffset)
+ f.Name = string(readByteSlice(r, filenameLength))
+ f.Extra = readByteSlice(r, extraLength)
+ f.Comment = string(readByteSlice(r, commentLength))
+ return
+}
+
+func readDirectoryEnd(r io.ReaderAt, size int64) (d *directoryEnd, err os.Error) {
+ // look for directoryEndSignature in the last 1k, then in the last 65k
+ var b []byte
+ for i, bLen := range []int64{1024, 65 * 1024} {
+ if bLen > size {
+ bLen = size
+ }
+ b = make([]byte, int(bLen))
+ if _, err := r.ReadAt(b, size-bLen); err != nil && err != os.EOF {
+ return nil, err
+ }
+ if p := findSignatureInBlock(b); p >= 0 {
+ b = b[p:]
+ break
+ }
+ if i == 1 || bLen == size {
+ return nil, FormatError
+ }
+ }
+
+ // read header into struct
+ defer func() {
+ if rerr, ok := recover().(os.Error); ok {
+ err = rerr
+ d = nil
+ }
+ }()
+ br := bytes.NewBuffer(b[4:]) // skip over signature
+ d = new(directoryEnd)
+ read(br, &d.diskNbr)
+ read(br, &d.dirDiskNbr)
+ read(br, &d.dirRecordsThisDisk)
+ read(br, &d.directoryRecords)
+ read(br, &d.directorySize)
+ read(br, &d.directoryOffset)
+ read(br, &d.commentLen)
+ d.comment = string(readByteSlice(br, d.commentLen))
+ return d, nil
+}
+
+func findSignatureInBlock(b []byte) int {
+ const minSize = 4 + 2 + 2 + 2 + 2 + 4 + 4 + 2 // fixed part of header
+ for i := len(b) - minSize; i >= 0; i-- {
+ // defined from directoryEndSignature in struct.go
+ if b[i] == 'P' && b[i+1] == 'K' && b[i+2] == 0x05 && b[i+3] == 0x06 {
+ // n is length of comment
+ n := int(b[i+minSize-2]) | int(b[i+minSize-1])<<8
+ if n+minSize+i == len(b) {
+ return i
+ }
+ }
+ }
+ return -1
+}
+
+func read(r io.Reader, data interface{}) {
+ if err := binary.Read(r, binary.LittleEndian, data); err != nil {
+ panic(err)
+ }
+}
+
+func readByteSlice(r io.Reader, l uint16) []byte {
+ b := make([]byte, l)
+ if l == 0 {
+ return b
+ }
+ if _, err := io.ReadFull(r, b); err != nil {
+ panic(err)
+ }
+ return b
+}
diff --git a/src/pkg/archive/zip/reader_test.go b/src/pkg/archive/zip/reader_test.go
new file mode 100644
index 000000000..3c24f1467
--- /dev/null
+++ b/src/pkg/archive/zip/reader_test.go
@@ -0,0 +1,180 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package zip
+
+import (
+ "bytes"
+ "encoding/binary"
+ "io"
+ "io/ioutil"
+ "os"
+ "testing"
+)
+
+type ZipTest struct {
+ Name string
+ Comment string
+ File []ZipTestFile
+ Error os.Error // the error that Opening this file should return
+}
+
+type ZipTestFile struct {
+ Name string
+ Content []byte // if blank, will attempt to compare against File
+ File string // name of file to compare to (relative to testdata/)
+}
+
+var tests = []ZipTest{
+ {
+ Name: "test.zip",
+ Comment: "This is a zipfile comment.",
+ File: []ZipTestFile{
+ {
+ Name: "test.txt",
+ Content: []byte("This is a test text file.\n"),
+ },
+ {
+ Name: "gophercolor16x16.png",
+ File: "gophercolor16x16.png",
+ },
+ },
+ },
+ {
+ Name: "r.zip",
+ File: []ZipTestFile{
+ {
+ Name: "r/r.zip",
+ File: "r.zip",
+ },
+ },
+ },
+ {Name: "readme.zip"},
+ {Name: "readme.notzip", Error: FormatError},
+}
+
+func TestReader(t *testing.T) {
+ for _, zt := range tests {
+ readTestZip(t, zt)
+ }
+}
+
+func readTestZip(t *testing.T, zt ZipTest) {
+ z, err := OpenReader("testdata/" + zt.Name)
+ if err != zt.Error {
+ t.Errorf("error=%v, want %v", err, zt.Error)
+ return
+ }
+
+ // bail here if no Files expected to be tested
+ // (there may actually be files in the zip, but we don't care)
+ if zt.File == nil {
+ return
+ }
+
+ if z.Comment != zt.Comment {
+ t.Errorf("%s: comment=%q, want %q", zt.Name, z.Comment, zt.Comment)
+ }
+ if len(z.File) != len(zt.File) {
+ t.Errorf("%s: file count=%d, want %d", zt.Name, len(z.File), len(zt.File))
+ }
+
+ // test read of each file
+ for i, ft := range zt.File {
+ readTestFile(t, ft, z.File[i])
+ }
+
+ // test simultaneous reads
+ n := 0
+ done := make(chan bool)
+ for i := 0; i < 5; i++ {
+ for j, ft := range zt.File {
+ go func() {
+ readTestFile(t, ft, z.File[j])
+ done <- true
+ }()
+ n++
+ }
+ }
+ for ; n > 0; n-- {
+ <-done
+ }
+
+ // test invalid checksum
+ z.File[0].CRC32++ // invalidate
+ r, err := z.File[0].Open()
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ var b bytes.Buffer
+ _, err = io.Copy(&b, r)
+ if err != ChecksumError {
+ t.Errorf("%s: copy error=%v, want %v", z.File[0].Name, err, ChecksumError)
+ }
+}
+
+func readTestFile(t *testing.T, ft ZipTestFile, f *File) {
+ if f.Name != ft.Name {
+ t.Errorf("name=%q, want %q", f.Name, ft.Name)
+ }
+ var b bytes.Buffer
+ r, err := f.Open()
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ _, err = io.Copy(&b, r)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ r.Close()
+ var c []byte
+ if len(ft.Content) != 0 {
+ c = ft.Content
+ } else if c, err = ioutil.ReadFile("testdata/" + ft.File); err != nil {
+ t.Error(err)
+ return
+ }
+ if b.Len() != len(c) {
+ t.Errorf("%s: len=%d, want %d", f.Name, b.Len(), len(c))
+ return
+ }
+ for i, b := range b.Bytes() {
+ if b != c[i] {
+ t.Errorf("%s: content[%d]=%q want %q", f.Name, i, b, c[i])
+ return
+ }
+ }
+}
+
+func TestInvalidFiles(t *testing.T) {
+ const size = 1024 * 70 // 70kb
+ b := make([]byte, size)
+
+ // zeroes
+ _, err := NewReader(sliceReaderAt(b), size)
+ if err != FormatError {
+ t.Errorf("zeroes: error=%v, want %v", err, FormatError)
+ }
+
+ // repeated directoryEndSignatures
+ sig := make([]byte, 4)
+ binary.LittleEndian.PutUint32(sig, directoryEndSignature)
+ for i := 0; i < size-4; i += 4 {
+ copy(b[i:i+4], sig)
+ }
+ _, err = NewReader(sliceReaderAt(b), size)
+ if err != FormatError {
+ t.Errorf("sigs: error=%v, want %v", err, FormatError)
+ }
+}
+
+type sliceReaderAt []byte
+
+func (r sliceReaderAt) ReadAt(b []byte, off int64) (int, os.Error) {
+ copy(b, r[int(off):int(off)+len(b)])
+ return len(b), nil
+}
diff --git a/src/pkg/archive/zip/struct.go b/src/pkg/archive/zip/struct.go
new file mode 100644
index 000000000..8a8c727d4
--- /dev/null
+++ b/src/pkg/archive/zip/struct.go
@@ -0,0 +1,33 @@
+package zip
+
+const (
+ fileHeaderSignature = 0x04034b50
+ directoryHeaderSignature = 0x02014b50
+ directoryEndSignature = 0x06054b50
+)
+
+type FileHeader struct {
+ Name string
+ CreatorVersion uint16
+ ReaderVersion uint16
+ Flags uint16
+ Method uint16
+ ModifiedTime uint16
+ ModifiedDate uint16
+ CRC32 uint32
+ CompressedSize uint32
+ UncompressedSize uint32
+ Extra []byte
+ Comment string
+}
+
+type directoryEnd struct {
+ diskNbr uint16 // unused
+ dirDiskNbr uint16 // unused
+ dirRecordsThisDisk uint16 // unused
+ directoryRecords uint16
+ directorySize uint32
+ directoryOffset uint32 // relative to file
+ commentLen uint16
+ comment string
+}
diff --git a/src/pkg/archive/zip/testdata/gophercolor16x16.png b/src/pkg/archive/zip/testdata/gophercolor16x16.png
new file mode 100644
index 000000000..48854ff3b
--- /dev/null
+++ b/src/pkg/archive/zip/testdata/gophercolor16x16.png
Binary files differ
diff --git a/src/pkg/archive/zip/testdata/r.zip b/src/pkg/archive/zip/testdata/r.zip
new file mode 100644
index 000000000..ea0fa2ffc
--- /dev/null
+++ b/src/pkg/archive/zip/testdata/r.zip
Binary files differ
diff --git a/src/pkg/archive/zip/testdata/readme.notzip b/src/pkg/archive/zip/testdata/readme.notzip
new file mode 100644
index 000000000..06668c4c1
--- /dev/null
+++ b/src/pkg/archive/zip/testdata/readme.notzip
Binary files differ
diff --git a/src/pkg/archive/zip/testdata/readme.zip b/src/pkg/archive/zip/testdata/readme.zip
new file mode 100644
index 000000000..db3bb900e
--- /dev/null
+++ b/src/pkg/archive/zip/testdata/readme.zip
Binary files differ
diff --git a/src/pkg/archive/zip/testdata/test.zip b/src/pkg/archive/zip/testdata/test.zip
new file mode 100644
index 000000000..03890c05d
--- /dev/null
+++ b/src/pkg/archive/zip/testdata/test.zip
Binary files differ
diff --git a/src/pkg/asn1/Makefile b/src/pkg/asn1/Makefile
index 40b76b849..6b7770e82 100644
--- a/src/pkg/asn1/Makefile
+++ b/src/pkg/asn1/Makefile
@@ -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 ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=asn1
GOFILES=\
diff --git a/src/pkg/asn1/asn1.go b/src/pkg/asn1/asn1.go
index bba8a0fe2..d06b1d4d7 100644
--- a/src/pkg/asn1/asn1.go
+++ b/src/pkg/asn1/asn1.go
@@ -150,6 +150,20 @@ func parseBitString(bytes []byte) (ret BitString, err os.Error) {
// An ObjectIdentifier represents an ASN.1 OBJECT IDENTIFIER.
type ObjectIdentifier []int
+// Equal returns true iff oi and other represent the same identifier.
+func (oi ObjectIdentifier) Equal(other ObjectIdentifier) bool {
+ if len(oi) != len(other) {
+ return false
+ }
+ for i := 0; i < len(oi); i++ {
+ if oi[i] != other[i] {
+ return false
+ }
+ }
+
+ return true
+}
+
// parseObjectIdentifier parses an OBJECT IDENTIFER from the given bytes and
// returns it. An object identifer is a sequence of variable length integers
// that are assigned in a hierarachy.
@@ -179,6 +193,17 @@ func parseObjectIdentifier(bytes []byte) (s []int, err os.Error) {
return
}
+// ENUMERATED
+
+// An Enumerated is represented as a plain int.
+type Enumerated int
+
+
+// FLAG
+
+// A Flag accepts any data and is set to true if present.
+type Flag bool
+
// parseBase128Int parses a base-128 encoded int from the given offset in the
// given byte array. It returns the value and the new offset.
func parseBase128Int(bytes []byte, initOffset int) (ret, offset int, err os.Error) {
@@ -202,101 +227,20 @@ func parseBase128Int(bytes []byte, initOffset int) (ret, offset int, err os.Erro
// UTCTime
-func isDigit(b byte) bool { return '0' <= b && b <= '9' }
-
-// twoDigits returns the value of two, base 10 digits.
-func twoDigits(bytes []byte, max int) (int, bool) {
- for i := 0; i < 2; i++ {
- if !isDigit(bytes[i]) {
- return 0, false
- }
- }
- value := (int(bytes[0])-'0')*10 + int(bytes[1]-'0')
- if value > max {
- return 0, false
- }
- return value, true
-}
-
-// parseUTCTime parses the UTCTime from the given byte array and returns the
-// resulting time.
func parseUTCTime(bytes []byte) (ret *time.Time, err os.Error) {
- // A UTCTime can take the following formats:
- //
- // 1111111
- // 01234567890123456
- //
- // YYMMDDhhmmZ
- // YYMMDDhhmm+hhmm
- // YYMMDDhhmm-hhmm
- // YYMMDDhhmmssZ
- // YYMMDDhhmmss+hhmm
- // YYMMDDhhmmss-hhmm
- if len(bytes) < 11 {
- err = SyntaxError{"UTCTime too short"}
- return
- }
- ret = new(time.Time)
-
- var ok1, ok2, ok3, ok4, ok5 bool
- year, ok1 := twoDigits(bytes[0:2], 99)
- // RFC 5280, section 5.1.2.4 says that years 2050 or later use another date
- // scheme.
- if year >= 50 {
- ret.Year = 1900 + int64(year)
- } else {
- ret.Year = 2000 + int64(year)
- }
- ret.Month, ok2 = twoDigits(bytes[2:4], 12)
- ret.Day, ok3 = twoDigits(bytes[4:6], 31)
- ret.Hour, ok4 = twoDigits(bytes[6:8], 23)
- ret.Minute, ok5 = twoDigits(bytes[8:10], 59)
- if !ok1 || !ok2 || !ok3 || !ok4 || !ok5 {
- goto Error
- }
- bytes = bytes[10:]
- switch bytes[0] {
- case '0', '1', '2', '3', '4', '5', '6':
- if len(bytes) < 3 {
- goto Error
- }
- ret.Second, ok1 = twoDigits(bytes[0:2], 60) // 60, not 59, because of leap seconds.
- if !ok1 {
- goto Error
- }
- bytes = bytes[2:]
- }
- if len(bytes) == 0 {
- goto Error
- }
- switch bytes[0] {
- case 'Z':
- if len(bytes) != 1 {
- goto Error
- }
+ s := string(bytes)
+ ret, err = time.Parse("0601021504Z0700", s)
+ if err == nil {
return
- case '-', '+':
- if len(bytes) != 5 {
- goto Error
- }
- hours, ok1 := twoDigits(bytes[1:3], 12)
- minutes, ok2 := twoDigits(bytes[3:5], 59)
- if !ok1 || !ok2 {
- goto Error
- }
- sign := 1
- if bytes[0] == '-' {
- sign = -1
- }
- ret.ZoneOffset = sign * (60 * (hours*60 + minutes))
- default:
- goto Error
}
+ ret, err = time.Parse("060102150405Z0700", s)
return
+}
-Error:
- err = SyntaxError{"invalid UTCTime"}
- return
+// parseGeneralizedTime parses the GeneralizedTime from the given byte array
+// and returns the resulting time.
+func parseGeneralizedTime(bytes []byte) (ret *time.Time, err os.Error) {
+ return time.Parse("20060102150405Z0700", string(bytes))
}
// PrintableString
@@ -346,11 +290,20 @@ func parseIA5String(bytes []byte) (ret string, err os.Error) {
return
}
+// T61String
+
+// parseT61String parses a ASN.1 T61String (8-bit clean string) from the given
+// byte array and returns it.
+func parseT61String(bytes []byte) (ret string, err os.Error) {
+ return string(bytes), nil
+}
+
// A RawValue represents an undecoded ASN.1 object.
type RawValue struct {
Class, Tag int
IsCompound bool
Bytes []byte
+ FullBytes []byte // includes the tag and length
}
// RawContent is used to signal that the undecoded, DER data needs to be
@@ -462,6 +415,8 @@ func parseSequenceOf(bytes []byte, sliceType *reflect.SliceType, elemType reflec
var (
bitStringType = reflect.Typeof(BitString{})
objectIdentifierType = reflect.Typeof(ObjectIdentifier{})
+ enumeratedType = reflect.Typeof(Enumerated(0))
+ flagType = reflect.Typeof(Flag(false))
timeType = reflect.Typeof(&time.Time{})
rawValueType = reflect.Typeof(RawValue{})
rawContentsType = reflect.Typeof(RawContent(nil))
@@ -499,7 +454,7 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
err = SyntaxError{"data truncated"}
return
}
- result := RawValue{t.class, t.tag, t.isCompound, bytes[offset : offset+t.length]}
+ result := RawValue{t.class, t.tag, t.isCompound, bytes[offset : offset+t.length], bytes[initOffset : offset+t.length]}
offset += t.length
v.(*reflect.StructValue).Set(reflect.NewValue(result).(*reflect.StructValue))
return
@@ -525,6 +480,8 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
result, err = parsePrintableString(innerBytes)
case tagIA5String:
result, err = parseIA5String(innerBytes)
+ case tagT61String:
+ result, err = parseT61String(innerBytes)
case tagInteger:
result, err = parseInt64(innerBytes)
case tagBitString:
@@ -559,9 +516,20 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
return
}
if params.explicit {
- if t.class == classContextSpecific && t.tag == *params.tag && t.isCompound {
- t, offset, err = parseTagAndLength(bytes, offset)
- if err != nil {
+ if t.class == classContextSpecific && t.tag == *params.tag && (t.length == 0 || t.isCompound) {
+ if t.length > 0 {
+ t, offset, err = parseTagAndLength(bytes, offset)
+ if err != nil {
+ return
+ }
+ } else {
+ if fieldType != flagType {
+ err = StructuralError{"Zero length explicit tag was not an asn1.Flag"}
+ return
+ }
+
+ flagValue := v.(*reflect.BoolValue)
+ flagValue.Set(true)
return
}
} else {
@@ -584,6 +552,12 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
universalTag = tagIA5String
}
+ // Special case for time: UTCTime and GeneralizedTime both map to the
+ // Go type time.Time.
+ if universalTag == tagUTCTime && t.tag == tagGeneralizedTime {
+ universalTag = tagGeneralizedTime
+ }
+
expectedClass := classUniversal
expectedTag := universalTag
@@ -617,7 +591,7 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
sliceValue := v.(*reflect.SliceValue)
sliceValue.Set(reflect.MakeSlice(sliceValue.Type().(*reflect.SliceType), len(newSlice), len(newSlice)))
if err1 == nil {
- reflect.ArrayCopy(sliceValue, reflect.NewValue(newSlice).(reflect.ArrayOrSliceValue))
+ reflect.Copy(sliceValue, reflect.NewValue(newSlice).(reflect.ArrayOrSliceValue))
}
err = err1
return
@@ -631,12 +605,30 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
return
case timeType:
ptrValue := v.(*reflect.PtrValue)
- time, err1 := parseUTCTime(innerBytes)
+ var time *time.Time
+ var err1 os.Error
+ if universalTag == tagUTCTime {
+ time, err1 = parseUTCTime(innerBytes)
+ } else {
+ time, err1 = parseGeneralizedTime(innerBytes)
+ }
if err1 == nil {
ptrValue.Set(reflect.NewValue(time).(*reflect.PtrValue))
}
err = err1
return
+ case enumeratedType:
+ parsedInt, err1 := parseInt(innerBytes)
+ enumValue := v.(*reflect.IntValue)
+ if err1 == nil {
+ enumValue.Set(int64(parsedInt))
+ }
+ err = err1
+ return
+ case flagType:
+ flagValue := v.(*reflect.BoolValue)
+ flagValue.Set(true)
+ return
}
switch val := v.(type) {
case *reflect.BoolValue:
@@ -691,7 +683,7 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
sliceType := fieldType.(*reflect.SliceType)
if sliceType.Elem().Kind() == reflect.Uint8 {
val.Set(reflect.MakeSlice(sliceType, len(innerBytes), len(innerBytes)))
- reflect.ArrayCopy(val, reflect.NewValue(innerBytes).(reflect.ArrayOrSliceValue))
+ reflect.Copy(val, reflect.NewValue(innerBytes).(reflect.ArrayOrSliceValue))
return
}
newSlice, err1 := parseSequenceOf(innerBytes, sliceType, sliceType.Elem())
@@ -707,6 +699,8 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
v, err = parsePrintableString(innerBytes)
case tagIA5String:
v, err = parseIA5String(innerBytes)
+ case tagT61String:
+ v, err = parseT61String(innerBytes)
default:
err = SyntaxError{fmt.Sprintf("internal error: unknown string type %d", universalTag)}
}
@@ -753,6 +747,10 @@ func setDefaultValue(v reflect.Value, params fieldParameters) (ok bool) {
// An ASN.1 OBJECT IDENTIFIER can be written to an
// ObjectIdentifier.
//
+// An ASN.1 ENUMERATED can be written to an Enumerated.
+//
+// An ASN.1 UTCTIME or GENERALIZEDTIME can be written to a *time.Time.
+//
// An ASN.1 PrintableString or IA5String can be written to a string.
//
// Any of the above ASN.1 values can be written to an interface{}.
@@ -777,7 +775,7 @@ 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(val interface{}, b []byte) (rest []byte, err os.Error) {
+func Unmarshal(b []byte, val interface{}) (rest []byte, err os.Error) {
v := reflect.NewValue(val).(*reflect.PtrValue).Elem()
offset, err := parseField(v, b, 0, fieldParameters{})
if err != nil {
diff --git a/src/pkg/asn1/asn1_test.go b/src/pkg/asn1/asn1_test.go
index b5bce93b7..34b5f1ecd 100644
--- a/src/pkg/asn1/asn1_test.go
+++ b/src/pkg/asn1/asn1_test.go
@@ -18,16 +18,16 @@ type int64Test struct {
}
var int64TestData = []int64Test{
- int64Test{[]byte{0x00}, true, 0},
- int64Test{[]byte{0x7f}, true, 127},
- int64Test{[]byte{0x00, 0x80}, true, 128},
- int64Test{[]byte{0x01, 0x00}, true, 256},
- int64Test{[]byte{0x80}, true, -128},
- int64Test{[]byte{0xff, 0x7f}, true, -129},
- int64Test{[]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, true, -1},
- int64Test{[]byte{0xff}, true, -1},
- int64Test{[]byte{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, true, -9223372036854775808},
- int64Test{[]byte{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, false, 0},
+ {[]byte{0x00}, true, 0},
+ {[]byte{0x7f}, true, 127},
+ {[]byte{0x00, 0x80}, true, 128},
+ {[]byte{0x01, 0x00}, true, 256},
+ {[]byte{0x80}, true, -128},
+ {[]byte{0xff, 0x7f}, true, -129},
+ {[]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, true, -1},
+ {[]byte{0xff}, true, -1},
+ {[]byte{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, true, -9223372036854775808},
+ {[]byte{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, false, 0},
}
func TestParseInt64(t *testing.T) {
@@ -50,12 +50,12 @@ type bitStringTest struct {
}
var bitStringTestData = []bitStringTest{
- bitStringTest{[]byte{}, false, []byte{}, 0},
- bitStringTest{[]byte{0x00}, true, []byte{}, 0},
- bitStringTest{[]byte{0x07, 0x00}, true, []byte{0x00}, 1},
- bitStringTest{[]byte{0x07, 0x01}, false, []byte{}, 0},
- bitStringTest{[]byte{0x07, 0x40}, false, []byte{}, 0},
- bitStringTest{[]byte{0x08, 0x00}, false, []byte{}, 0},
+ {[]byte{}, false, []byte{}, 0},
+ {[]byte{0x00}, true, []byte{}, 0},
+ {[]byte{0x07, 0x00}, true, []byte{0x00}, 1},
+ {[]byte{0x07, 0x01}, false, []byte{}, 0},
+ {[]byte{0x07, 0x40}, false, []byte{}, 0},
+ {[]byte{0x08, 0x00}, false, []byte{}, 0},
}
func TestBitString(t *testing.T) {
@@ -95,12 +95,12 @@ type bitStringRightAlignTest struct {
}
var bitStringRightAlignTests = []bitStringRightAlignTest{
- bitStringRightAlignTest{[]byte{0x80}, 1, []byte{0x01}},
- bitStringRightAlignTest{[]byte{0x80, 0x80}, 9, []byte{0x01, 0x01}},
- bitStringRightAlignTest{[]byte{}, 0, []byte{}},
- bitStringRightAlignTest{[]byte{0xce}, 8, []byte{0xce}},
- bitStringRightAlignTest{[]byte{0xce, 0x47}, 16, []byte{0xce, 0x47}},
- bitStringRightAlignTest{[]byte{0x34, 0x50}, 12, []byte{0x03, 0x45}},
+ {[]byte{0x80}, 1, []byte{0x01}},
+ {[]byte{0x80, 0x80}, 9, []byte{0x01, 0x01}},
+ {[]byte{}, 0, []byte{}},
+ {[]byte{0xce}, 8, []byte{0xce}},
+ {[]byte{0xce, 0x47}, 16, []byte{0xce, 0x47}},
+ {[]byte{0x34, 0x50}, 12, []byte{0x03, 0x45}},
}
func TestBitStringRightAlign(t *testing.T) {
@@ -120,11 +120,11 @@ type objectIdentifierTest struct {
}
var objectIdentifierTestData = []objectIdentifierTest{
- objectIdentifierTest{[]byte{}, false, []int{}},
- objectIdentifierTest{[]byte{85}, true, []int{2, 5}},
- objectIdentifierTest{[]byte{85, 0x02}, true, []int{2, 5, 2}},
- objectIdentifierTest{[]byte{85, 0x02, 0xc0, 0x00}, true, []int{2, 5, 2, 0x2000}},
- objectIdentifierTest{[]byte{85, 0x02, 0xc0, 0x80, 0x80, 0x80, 0x80}, false, []int{}},
+ {[]byte{}, false, []int{}},
+ {[]byte{85}, true, []int{2, 5}},
+ {[]byte{85, 0x02}, true, []int{2, 5, 2}},
+ {[]byte{85, 0x02, 0xc0, 0x00}, true, []int{2, 5, 2, 0x2000}},
+ {[]byte{85, 0x02, 0xc0, 0x80, 0x80, 0x80, 0x80}, false, []int{}},
}
func TestObjectIdentifier(t *testing.T) {
@@ -147,23 +147,23 @@ type timeTest struct {
out *time.Time
}
-var timeTestData = []timeTest{
- timeTest{"910506164540-0700", true, &time.Time{1991, 05, 06, 16, 45, 40, 0, -7 * 60 * 60, ""}},
- timeTest{"910506164540+0730", true, &time.Time{1991, 05, 06, 16, 45, 40, 0, 7*60*60 + 30*60, ""}},
- timeTest{"910506234540Z", true, &time.Time{1991, 05, 06, 23, 45, 40, 0, 0, ""}},
- timeTest{"9105062345Z", true, &time.Time{1991, 05, 06, 23, 45, 0, 0, 0, ""}},
- timeTest{"a10506234540Z", false, nil},
- timeTest{"91a506234540Z", false, nil},
- timeTest{"9105a6234540Z", false, nil},
- timeTest{"910506a34540Z", false, nil},
- timeTest{"910506334a40Z", false, nil},
- timeTest{"91050633444aZ", false, nil},
- timeTest{"910506334461Z", false, nil},
- timeTest{"910506334400Za", false, nil},
+var utcTestData = []timeTest{
+ {"910506164540-0700", true, &time.Time{1991, 05, 06, 16, 45, 40, 0, -7 * 60 * 60, ""}},
+ {"910506164540+0730", true, &time.Time{1991, 05, 06, 16, 45, 40, 0, 7*60*60 + 30*60, ""}},
+ {"910506234540Z", true, &time.Time{1991, 05, 06, 23, 45, 40, 0, 0, "UTC"}},
+ {"9105062345Z", true, &time.Time{1991, 05, 06, 23, 45, 0, 0, 0, "UTC"}},
+ {"a10506234540Z", false, nil},
+ {"91a506234540Z", false, nil},
+ {"9105a6234540Z", false, nil},
+ {"910506a34540Z", false, nil},
+ {"910506334a40Z", false, nil},
+ {"91050633444aZ", false, nil},
+ {"910506334461Z", false, nil},
+ {"910506334400Za", false, nil},
}
-func TestTime(t *testing.T) {
- for i, test := range timeTestData {
+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)
@@ -176,6 +176,27 @@ func TestTime(t *testing.T) {
}
}
+var generalizedTimeTestData = []timeTest{
+ {"20100102030405Z", true, &time.Time{2010, 01, 02, 03, 04, 05, 0, 0, "UTC"}},
+ {"20100102030405", false, nil},
+ {"20100102030405+0607", true, &time.Time{2010, 01, 02, 03, 04, 05, 0, 6*60*60 + 7*60, ""}},
+ {"20100102030405-0607", true, &time.Time{2010, 01, 02, 03, 04, 05, 0, -6*60*60 - 7*60, ""}},
+}
+
+func TestGeneralizedTime(t *testing.T) {
+ for i, test := range generalizedTimeTestData {
+ ret, err := parseGeneralizedTime([]byte(test.in))
+ if (err == nil) != test.ok {
+ t.Errorf("#%d: Incorrect error result (did fail? %v, expected: %v)", i, err == nil, test.ok)
+ }
+ if err == nil {
+ if !reflect.DeepEqual(test.out, ret) {
+ t.Errorf("#%d: Bad result: %v (expected %v)", i, ret, test.out)
+ }
+ }
+ }
+}
+
type tagAndLengthTest struct {
in []byte
ok bool
@@ -183,18 +204,18 @@ type tagAndLengthTest struct {
}
var tagAndLengthData = []tagAndLengthTest{
- tagAndLengthTest{[]byte{0x80, 0x01}, true, tagAndLength{2, 0, 1, false}},
- tagAndLengthTest{[]byte{0xa0, 0x01}, true, tagAndLength{2, 0, 1, true}},
- tagAndLengthTest{[]byte{0x02, 0x00}, true, tagAndLength{0, 2, 0, false}},
- tagAndLengthTest{[]byte{0xfe, 0x00}, true, tagAndLength{3, 30, 0, true}},
- tagAndLengthTest{[]byte{0x1f, 0x01, 0x00}, true, tagAndLength{0, 1, 0, false}},
- tagAndLengthTest{[]byte{0x1f, 0x81, 0x00, 0x00}, true, tagAndLength{0, 128, 0, false}},
- tagAndLengthTest{[]byte{0x1f, 0x81, 0x80, 0x01, 0x00}, true, tagAndLength{0, 0x4001, 0, false}},
- tagAndLengthTest{[]byte{0x00, 0x81, 0x01}, true, tagAndLength{0, 0, 1, false}},
- tagAndLengthTest{[]byte{0x00, 0x82, 0x01, 0x00}, true, tagAndLength{0, 0, 256, false}},
- tagAndLengthTest{[]byte{0x00, 0x83, 0x01, 0x00}, false, tagAndLength{}},
- tagAndLengthTest{[]byte{0x1f, 0x85}, false, tagAndLength{}},
- tagAndLengthTest{[]byte{0x30, 0x80}, false, tagAndLength{}},
+ {[]byte{0x80, 0x01}, true, tagAndLength{2, 0, 1, false}},
+ {[]byte{0xa0, 0x01}, true, tagAndLength{2, 0, 1, true}},
+ {[]byte{0x02, 0x00}, true, tagAndLength{0, 2, 0, false}},
+ {[]byte{0xfe, 0x00}, true, tagAndLength{3, 30, 0, true}},
+ {[]byte{0x1f, 0x01, 0x00}, true, tagAndLength{0, 1, 0, false}},
+ {[]byte{0x1f, 0x81, 0x00, 0x00}, true, tagAndLength{0, 128, 0, false}},
+ {[]byte{0x1f, 0x81, 0x80, 0x01, 0x00}, true, tagAndLength{0, 0x4001, 0, false}},
+ {[]byte{0x00, 0x81, 0x01}, true, tagAndLength{0, 0, 1, false}},
+ {[]byte{0x00, 0x82, 0x01, 0x00}, true, tagAndLength{0, 0, 256, false}},
+ {[]byte{0x00, 0x83, 0x01, 0x00}, false, tagAndLength{}},
+ {[]byte{0x1f, 0x85}, false, tagAndLength{}},
+ {[]byte{0x30, 0x80}, false, tagAndLength{}},
}
func TestParseTagAndLength(t *testing.T) {
@@ -223,17 +244,17 @@ func newString(s string) *string { return &s }
func newBool(b bool) *bool { return &b }
var parseFieldParametersTestData []parseFieldParametersTest = []parseFieldParametersTest{
- parseFieldParametersTest{"", fieldParameters{}},
- parseFieldParametersTest{"ia5", fieldParameters{stringType: tagIA5String}},
- parseFieldParametersTest{"printable", fieldParameters{stringType: tagPrintableString}},
- parseFieldParametersTest{"optional", fieldParameters{optional: true}},
- parseFieldParametersTest{"explicit", fieldParameters{explicit: true, tag: new(int)}},
- parseFieldParametersTest{"optional,explicit", fieldParameters{optional: true, explicit: true, tag: new(int)}},
- parseFieldParametersTest{"default:42", fieldParameters{defaultValue: newInt64(42)}},
- parseFieldParametersTest{"tag:17", fieldParameters{tag: newInt(17)}},
- parseFieldParametersTest{"optional,explicit,default:42,tag:17", fieldParameters{optional: true, explicit: true, defaultValue: newInt64(42), tag: newInt(17)}},
- parseFieldParametersTest{"optional,explicit,default:42,tag:17,rubbish1", fieldParameters{true, true, newInt64(42), newInt(17), 0, false}},
- parseFieldParametersTest{"set", fieldParameters{set: true}},
+ {"", fieldParameters{}},
+ {"ia5", fieldParameters{stringType: tagIA5String}},
+ {"printable", fieldParameters{stringType: tagPrintableString}},
+ {"optional", fieldParameters{optional: true}},
+ {"explicit", fieldParameters{explicit: true, tag: new(int)}},
+ {"optional,explicit", fieldParameters{optional: true, explicit: true, tag: new(int)}},
+ {"default:42", fieldParameters{defaultValue: newInt64(42)}},
+ {"tag:17", fieldParameters{tag: newInt(17)}},
+ {"optional,explicit,default:42,tag:17", fieldParameters{optional: true, explicit: true, defaultValue: newInt64(42), tag: newInt(17)}},
+ {"optional,explicit,default:42,tag:17,rubbish1", fieldParameters{true, true, newInt64(42), newInt(17), 0, false}},
+ {"set", fieldParameters{set: true}},
}
func TestParseFieldParameters(t *testing.T) {
@@ -269,20 +290,20 @@ type TestElementsAfterString struct {
}
var unmarshalTestData []unmarshalTest = []unmarshalTest{
- unmarshalTest{[]byte{0x02, 0x01, 0x42}, newInt(0x42)},
- unmarshalTest{[]byte{0x30, 0x08, 0x06, 0x06, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d}, &TestObjectIdentifierStruct{[]int{1, 2, 840, 113549}}},
- unmarshalTest{[]byte{0x03, 0x04, 0x06, 0x6e, 0x5d, 0xc0}, &BitString{[]byte{110, 93, 192}, 18}},
- unmarshalTest{[]byte{0x30, 0x09, 0x02, 0x01, 0x01, 0x02, 0x01, 0x02, 0x02, 0x01, 0x03}, &[]int{1, 2, 3}},
- unmarshalTest{[]byte{0x02, 0x01, 0x10}, newInt(16)},
- unmarshalTest{[]byte{0x13, 0x04, 't', 'e', 's', 't'}, newString("test")},
- unmarshalTest{[]byte{0x16, 0x04, 't', 'e', 's', 't'}, newString("test")},
- unmarshalTest{[]byte{0x16, 0x04, 't', 'e', 's', 't'}, &RawValue{0, 22, false, []byte("test")}},
- unmarshalTest{[]byte{0x04, 0x04, 1, 2, 3, 4}, &RawValue{0, 4, false, []byte{1, 2, 3, 4}}},
- unmarshalTest{[]byte{0x30, 0x03, 0x81, 0x01, 0x01}, &TestContextSpecificTags{1}},
- unmarshalTest{[]byte{0x30, 0x08, 0xa1, 0x03, 0x02, 0x01, 0x01, 0x02, 0x01, 0x02}, &TestContextSpecificTags2{1, 2}},
- unmarshalTest{[]byte{0x01, 0x01, 0x00}, newBool(false)},
- unmarshalTest{[]byte{0x01, 0x01, 0x01}, newBool(true)},
- unmarshalTest{[]byte{0x30, 0x0b, 0x13, 0x03, 0x66, 0x6f, 0x6f, 0x02, 0x01, 0x22, 0x02, 0x01, 0x33}, &TestElementsAfterString{"foo", 0x22, 0x33}},
+ {[]byte{0x02, 0x01, 0x42}, newInt(0x42)},
+ {[]byte{0x30, 0x08, 0x06, 0x06, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d}, &TestObjectIdentifierStruct{[]int{1, 2, 840, 113549}}},
+ {[]byte{0x03, 0x04, 0x06, 0x6e, 0x5d, 0xc0}, &BitString{[]byte{110, 93, 192}, 18}},
+ {[]byte{0x30, 0x09, 0x02, 0x01, 0x01, 0x02, 0x01, 0x02, 0x02, 0x01, 0x03}, &[]int{1, 2, 3}},
+ {[]byte{0x02, 0x01, 0x10}, newInt(16)},
+ {[]byte{0x13, 0x04, 't', 'e', 's', 't'}, newString("test")},
+ {[]byte{0x16, 0x04, 't', 'e', 's', 't'}, newString("test")},
+ {[]byte{0x16, 0x04, 't', 'e', 's', 't'}, &RawValue{0, 22, false, []byte("test"), []byte("\x16\x04test")}},
+ {[]byte{0x04, 0x04, 1, 2, 3, 4}, &RawValue{0, 4, false, []byte{1, 2, 3, 4}, []byte{4, 4, 1, 2, 3, 4}}},
+ {[]byte{0x30, 0x03, 0x81, 0x01, 0x01}, &TestContextSpecificTags{1}},
+ {[]byte{0x30, 0x08, 0xa1, 0x03, 0x02, 0x01, 0x01, 0x02, 0x01, 0x02}, &TestContextSpecificTags2{1, 2}},
+ {[]byte{0x01, 0x01, 0x00}, newBool(false)},
+ {[]byte{0x01, 0x01, 0x01}, newBool(true)},
+ {[]byte{0x30, 0x0b, 0x13, 0x03, 0x66, 0x6f, 0x6f, 0x02, 0x01, 0x22, 0x02, 0x01, 0x33}, &TestElementsAfterString{"foo", 0x22, 0x33}},
}
func TestUnmarshal(t *testing.T) {
@@ -291,7 +312,7 @@ func TestUnmarshal(t *testing.T) {
zv := reflect.MakeZero(pv.Type().(*reflect.PtrType).Elem())
pv.(*reflect.PtrValue).PointTo(zv)
val := pv.Interface()
- _, err := Unmarshal(val, test.in)
+ _, err := Unmarshal(test.in, val)
if err != nil {
t.Errorf("Unmarshal failed at index %d %v", i, err)
}
@@ -342,11 +363,11 @@ type PublicKeyInfo struct {
func TestCertificate(t *testing.T) {
// This is a minimal, self-signed certificate that should parse correctly.
var cert Certificate
- if _, err := Unmarshal(&cert, derEncodedSelfSignedCertBytes); err != nil {
+ if _, err := Unmarshal(derEncodedSelfSignedCertBytes, &cert); err != nil {
t.Errorf("Unmarshal failed: %v", err)
}
if !reflect.DeepEqual(cert, derEncodedSelfSignedCert) {
- t.Errorf("Bad result:\ngot: %+v\nwant: %+v\n", cert, derEncodedSelfSignedCert)
+ t.Errorf("Bad result:\ngot: %+v\nwant: %+v", cert, derEncodedSelfSignedCert)
}
}
@@ -355,7 +376,7 @@ func TestCertificateWithNUL(t *testing.T) {
// NUL isn't a permitted character in a PrintableString.
var cert Certificate
- if _, err := Unmarshal(&cert, derEncodedPaypalNULCertBytes); err == nil {
+ if _, err := Unmarshal(derEncodedPaypalNULCertBytes, &cert); err == nil {
t.Error("Unmarshal succeeded, should not have")
}
}
@@ -369,7 +390,7 @@ func TestRawStructs(t *testing.T) {
var s rawStructTest
input := []byte{0x30, 0x03, 0x02, 0x01, 0x50}
- rest, err := Unmarshal(&s, input)
+ rest, err := Unmarshal(input, &s)
if len(rest) != 0 {
t.Errorf("incomplete parse: %x", rest)
return
@@ -389,7 +410,7 @@ func TestRawStructs(t *testing.T) {
var derEncodedSelfSignedCert = Certificate{
TBSCertificate: TBSCertificate{
Version: 0,
- SerialNumber: RawValue{Class: 0, Tag: 2, IsCompound: false, Bytes: []uint8{0x0, 0x8c, 0xc3, 0x37, 0x92, 0x10, 0xec, 0x2c, 0x98}},
+ SerialNumber: RawValue{Class: 0, Tag: 2, IsCompound: false, Bytes: []uint8{0x0, 0x8c, 0xc3, 0x37, 0x92, 0x10, 0xec, 0x2c, 0x98}, FullBytes: []byte{2, 9, 0x0, 0x8c, 0xc3, 0x37, 0x92, 0x10, 0xec, 0x2c, 0x98}},
SignatureAlgorithm: AlgorithmIdentifier{Algorithm: ObjectIdentifier{1, 2, 840, 113549, 1, 1, 5}},
Issuer: RDNSequence{
RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{2, 5, 4, 6}, Value: "XX"}},
@@ -399,7 +420,7 @@ 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: ""}, NotAfter: &time.Time{Year: 2010, Month: 10, Day: 8, Hour: 0, Minute: 25, Second: 53, Weekday: 0, ZoneOffset: 0, Zone: ""}},
+ Validity: Validity{NotBefore: &time.Time{Year: 2009, Month: 10, Day: 8, Hour: 0, Minute: 25, Second: 53, Weekday: 0, ZoneOffset: 0, Zone: "UTC"}, NotAfter: &time.Time{Year: 2010, Month: 10, Day: 8, Hour: 0, Minute: 25, Second: 53, Weekday: 0, ZoneOffset: 0, Zone: "UTC"}},
Subject: RDNSequence{
RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{2, 5, 4, 6}, Value: "XX"}},
RelativeDistinguishedNameSET{AttributeTypeAndValue{Type: ObjectIdentifier{2, 5, 4, 8}, Value: "Some-State"}},
diff --git a/src/pkg/asn1/common.go b/src/pkg/asn1/common.go
index 14fa30426..4a5eca145 100644
--- a/src/pkg/asn1/common.go
+++ b/src/pkg/asn1/common.go
@@ -24,11 +24,14 @@ const (
tagBitString = 3
tagOctetString = 4
tagOID = 6
+ tagEnum = 10
tagSequence = 16
tagSet = 17
tagPrintableString = 19
+ tagT61String = 20
tagIA5String = 22
tagUTCTime = 23
+ tagGeneralizedTime = 24
)
const (
@@ -121,6 +124,8 @@ func getUniversalType(t reflect.Type) (tagNumber int, isCompound, ok bool) {
return tagBitString, false, true
case timeType:
return tagUTCTime, false, true
+ case enumeratedType:
+ return tagEnum, false, true
}
switch t := t.(type) {
case *reflect.BoolType:
diff --git a/src/pkg/asn1/marshal.go b/src/pkg/asn1/marshal.go
index d4f8f782d..24548714b 100644
--- a/src/pkg/asn1/marshal.go
+++ b/src/pkg/asn1/marshal.go
@@ -96,19 +96,6 @@ func marshalBase128Int(out *forkableWriter, n int64) (err os.Error) {
return nil
}
-func base128Length(i int) (numBytes int) {
- if i == 0 {
- return 1
- }
-
- for i > 0 {
- numBytes++
- i >>= 7
- }
-
- return
-}
-
func marshalInt64(out *forkableWriter, i int64) (err os.Error) {
n := int64Length(i)
@@ -123,11 +110,14 @@ func marshalInt64(out *forkableWriter, i int64) (err os.Error) {
}
func int64Length(i int64) (numBytes int) {
- if i == 0 {
- return 1
+ numBytes = 1
+
+ for i > 127 {
+ numBytes++
+ i >>= 8
}
- for i > 0 {
+ for i < -128 {
numBytes++
i >>= 8
}
@@ -478,25 +468,15 @@ func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters)
return nil
}
-// Marshal serialises val as an ASN.1 structure and writes the result to out.
-// In the case of an error, no output is produced.
-func Marshal(out io.Writer, val interface{}) os.Error {
+// Marshal returns the ASN.1 encoding of val.
+func Marshal(val interface{}) ([]byte, os.Error) {
+ var out bytes.Buffer
v := reflect.NewValue(val)
f := newForkableWriter()
err := marshalField(f, v, fieldParameters{})
if err != nil {
- return err
- }
- _, err = f.writeTo(out)
- return err
-}
-
-// MarshalToMemory performs the same actions as Marshal, but returns the result
-// as a byte slice.
-func MarshalToMemory(val interface{}) ([]byte, os.Error) {
- var out bytes.Buffer
- if err := Marshal(&out, val); err != nil {
return nil, err
}
+ _, err = f.writeTo(&out)
return out.Bytes(), nil
}
diff --git a/src/pkg/asn1/marshal_test.go b/src/pkg/asn1/marshal_test.go
index 67878f9bb..85eafc9e4 100644
--- a/src/pkg/asn1/marshal_test.go
+++ b/src/pkg/asn1/marshal_test.go
@@ -58,40 +58,43 @@ type marshalTest struct {
}
var marshalTests = []marshalTest{
- marshalTest{10, "02010a"},
- marshalTest{intStruct{64}, "3003020140"},
- marshalTest{twoIntStruct{64, 65}, "3006020140020141"},
- marshalTest{nestedStruct{intStruct{127}}, "3005300302017f"},
- marshalTest{[]byte{1, 2, 3}, "0403010203"},
- marshalTest{implicitTagTest{64}, "3003850140"},
- marshalTest{explicitTagTest{64}, "3005a503020140"},
- marshalTest{time.SecondsToUTC(0), "170d3730303130313030303030305a"},
- marshalTest{time.SecondsToUTC(1258325776), "170d3039313131353232353631365a"},
- marshalTest{setPST(time.SecondsToUTC(1258325776)), "17113039313131353232353631362d30383030"},
- marshalTest{BitString{[]byte{0x80}, 1}, "03020780"},
- marshalTest{BitString{[]byte{0x81, 0xf0}, 12}, "03030481f0"},
- marshalTest{ObjectIdentifier([]int{1, 2, 3, 4}), "06032a0304"},
- marshalTest{ObjectIdentifier([]int{1, 2, 840, 133549, 1, 1, 5}), "06092a864888932d010105"},
- marshalTest{"test", "130474657374"},
- marshalTest{ia5StringTest{"test"}, "3006160474657374"},
- marshalTest{printableStringTest{"test"}, "3006130474657374"},
- marshalTest{printableStringTest{"test*"}, "30071305746573742a"},
- marshalTest{rawContentsStruct{nil, 64}, "3003020140"},
- marshalTest{rawContentsStruct{[]byte{0x30, 3, 1, 2, 3}, 64}, "3003010203"},
- marshalTest{RawValue{Tag: 1, Class: 2, IsCompound: false, Bytes: []byte{1, 2, 3}}, "8103010203"},
- marshalTest{testSET([]int{10}), "310302010a"},
+ {10, "02010a"},
+ {127, "02017f"},
+ {128, "02020080"},
+ {-128, "020180"},
+ {-129, "0202ff7f"},
+ {intStruct{64}, "3003020140"},
+ {twoIntStruct{64, 65}, "3006020140020141"},
+ {nestedStruct{intStruct{127}}, "3005300302017f"},
+ {[]byte{1, 2, 3}, "0403010203"},
+ {implicitTagTest{64}, "3003850140"},
+ {explicitTagTest{64}, "3005a503020140"},
+ {time.SecondsToUTC(0), "170d3730303130313030303030305a"},
+ {time.SecondsToUTC(1258325776), "170d3039313131353232353631365a"},
+ {setPST(time.SecondsToUTC(1258325776)), "17113039313131353232353631362d30383030"},
+ {BitString{[]byte{0x80}, 1}, "03020780"},
+ {BitString{[]byte{0x81, 0xf0}, 12}, "03030481f0"},
+ {ObjectIdentifier([]int{1, 2, 3, 4}), "06032a0304"},
+ {ObjectIdentifier([]int{1, 2, 840, 133549, 1, 1, 5}), "06092a864888932d010105"},
+ {"test", "130474657374"},
+ {ia5StringTest{"test"}, "3006160474657374"},
+ {printableStringTest{"test"}, "3006130474657374"},
+ {printableStringTest{"test*"}, "30071305746573742a"},
+ {rawContentsStruct{nil, 64}, "3003020140"},
+ {rawContentsStruct{[]byte{0x30, 3, 1, 2, 3}, 64}, "3003010203"},
+ {RawValue{Tag: 1, Class: 2, IsCompound: false, Bytes: []byte{1, 2, 3}}, "8103010203"},
+ {testSET([]int{10}), "310302010a"},
}
func TestMarshal(t *testing.T) {
for i, test := range marshalTests {
- buf := bytes.NewBuffer(nil)
- err := Marshal(buf, test.in)
+ data, err := Marshal(test.in)
if err != nil {
t.Errorf("#%d failed: %s", i, err)
}
out, _ := hex.DecodeString(test.out)
- if bytes.Compare(out, buf.Bytes()) != 0 {
- t.Errorf("#%d got: %x want %x", i, buf.Bytes(), out)
+ if bytes.Compare(out, data) != 0 {
+ t.Errorf("#%d got: %x want %x", i, data, out)
}
}
}
diff --git a/src/pkg/big/Makefile b/src/pkg/big/Makefile
index 7a4311dca..3d4b56d78 100644
--- a/src/pkg/big/Makefile
+++ b/src/pkg/big/Makefile
@@ -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 ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=big
GOFILES=\
diff --git a/src/pkg/big/arith.go b/src/pkg/big/arith.go
index 29966c7bc..df3808f5e 100644
--- a/src/pkg/big/arith.go
+++ b/src/pkg/big/arith.go
@@ -56,161 +56,29 @@ func subWW_g(x, y, c Word) (z1, z0 Word) {
// z1<<_W + z0 = x*y
+// Adapted from Warren, Hacker's Delight, p. 132.
func mulWW_g(x, y Word) (z1, z0 Word) {
- // Split x and y into 2 halfWords each, multiply
- // the halfWords separately while avoiding overflow,
- // and return the product as 2 Words.
-
- if x < y {
- x, y = y, x
- }
-
- if x < _B2 {
- // y < _B2 because y <= x
- // sub-digits of x and y are (0, x) and (0, y)
- // z = z[0] = x*y
- z0 = x * y
- return
- }
-
- if y < _B2 {
- // sub-digits of x and y are (x1, x0) and (0, y)
- // x = (x1*_B2 + x0)
- // y = (y1*_B2 + y0)
- x1, x0 := x>>_W2, x&_M2
-
- // x*y = t2*_B2*_B2 + t1*_B2 + t0
- t0 := x0 * y
- t1 := x1 * y
-
- // compute result digits but avoid overflow
- // z = z[1]*_B + z[0] = x*y
- z0 = t1<<_W2 + t0
- z1 = (t1 + t0>>_W2) >> _W2
- return
- }
-
- // general case
- // sub-digits of x and y are (x1, x0) and (y1, y0)
- // x = (x1*_B2 + x0)
- // y = (y1*_B2 + y0)
- x1, x0 := x>>_W2, x&_M2
- y1, y0 := y>>_W2, y&_M2
-
- // x*y = t2*_B2*_B2 + t1*_B2 + t0
- t0 := x0 * y0
- // t1 := x1*y0 + x0*y1;
- var c Word
- t1 := x1 * y0
- t1a := t1
- t1 += x0 * y1
- if t1 < t1a {
- c++
- }
- t2 := x1*y1 + c*_B2
-
- // compute result digits but avoid overflow
- // z = z[1]*_B + z[0] = x*y
- // This may overflow, but that's ok because we also sum t1 and t0 above
- // and we take care of the overflow there.
- z0 = t1<<_W2 + t0
-
- // z1 = t2 + (t1 + t0>>_W2)>>_W2;
- var c3 Word
- z1 = t1 + t0>>_W2
- if z1 < t1 {
- c3++
- }
- z1 >>= _W2
- z1 += c3 * _B2
- z1 += t2
+ x0 := x & _M2
+ x1 := x >> _W2
+ y0 := y & _M2
+ y1 := y >> _W2
+ w0 := x0 * y0
+ t := x1*y0 + w0>>_W2
+ w1 := t & _M2
+ w2 := t >> _W2
+ w1 += x0 * y1
+ z1 = x1*y1 + w2 + w1>>_W2
+ z0 = x * y
return
}
// z1<<_W + z0 = x*y + c
func mulAddWWW_g(x, y, c Word) (z1, z0 Word) {
- // Split x and y into 2 halfWords each, multiply
- // the halfWords separately while avoiding overflow,
- // and return the product as 2 Words.
-
- // TODO(gri) Should implement special cases for faster execution.
-
- // general case
- // sub-digits of x, y, and c are (x1, x0), (y1, y0), (c1, c0)
- // x = (x1*_B2 + x0)
- // y = (y1*_B2 + y0)
- x1, x0 := x>>_W2, x&_M2
- y1, y0 := y>>_W2, y&_M2
- c1, c0 := c>>_W2, c&_M2
-
- // x*y + c = t2*_B2*_B2 + t1*_B2 + t0
- // (1<<32-1)^2 == 1<<64 - 1<<33 + 1, so there's space to add c0 in here.
- t0 := x0*y0 + c0
-
- // t1 := x1*y0 + x0*y1 + c1;
- var c2 Word // extra carry
- t1 := x1*y0 + c1
- t1a := t1
- t1 += x0 * y1
- if t1 < t1a { // If the number got smaller then we overflowed.
- c2++
+ z1, zz0 := mulWW(x, y)
+ if z0 = zz0 + c; z0 < zz0 {
+ z1++
}
-
- t2 := x1*y1 + c2*_B2
-
- // compute result digits but avoid overflow
- // z = z[1]*_B + z[0] = x*y
- // z0 = t1<<_W2 + t0;
- // This may overflow, but that's ok because we also sum t1 and t0 below
- // and we take care of the overflow there.
- z0 = t1<<_W2 + t0
-
- var c3 Word
- z1 = t1 + t0>>_W2
- if z1 < t1 {
- c3++
- }
- z1 >>= _W2
- z1 += t2 + c3*_B2
-
- return
-}
-
-
-// q = (x1<<_W + x0 - r)/y
-// The most significant bit of y must be 1.
-func divStep(x1, x0, y Word) (q, r Word) {
- d1, d0 := y>>_W2, y&_M2
- q1, r1 := x1/d1, x1%d1
- m := q1 * d0
- r1 = r1*_B2 | x0>>_W2
- if r1 < m {
- q1--
- r1 += y
- if r1 >= y && r1 < m {
- q1--
- r1 += y
- }
- }
- r1 -= m
-
- r0 := r1 % d1
- q0 := r1 / d1
- m = q0 * d0
- r0 = r0*_B2 | x0&_M2
- if r0 < m {
- q0--
- r0 += y
- if r0 >= y && r0 < m {
- q0--
- r0 += y
- }
- }
- r0 -= m
-
- q = q1*_B2 | q0
- r = r0
return
}
@@ -241,46 +109,48 @@ func leadingZeros(x Word) uint {
}
-// q = (x1<<_W + x0 - r)/y
-func divWW_g(x1, x0, y Word) (q, r Word) {
- if x1 == 0 {
- q, r = x0/y, x0%y
- return
+// q = (u1<<_W + u0 - r)/y
+// Adapted from Warren, Hacker's Delight, p. 152.
+func divWW_g(u1, u0, v Word) (q, r Word) {
+ if u1 >= v {
+ return 1<<_W - 1, 1<<_W - 1
}
- var q0, q1 Word
- z := leadingZeros(y)
- if y > x1 {
- if z != 0 {
- y <<= z
- x1 = (x1 << z) | (x0 >> (_W - z))
- x0 <<= z
- }
- q0, x0 = divStep(x1, x0, y)
- q1 = 0
- } else {
- if z == 0 {
- x1 -= y
- q1 = 1
- } else {
- z1 := _W - z
- y <<= z
- x2 := x1 >> z1
- x1 = (x1 << z) | (x0 >> z1)
- x0 <<= z
- q1, x1 = divStep(x2, x1, y)
- }
+ s := leadingZeros(v)
+ v <<= s
+
+ vn1 := v >> _W2
+ vn0 := v & _M2
+ un32 := u1<<s | u0>>(_W-s)
+ un10 := u0 << s
+ un1 := un10 >> _W2
+ un0 := un10 & _M2
+ q1 := un32 / vn1
+ rhat := un32 - q1*vn1
- q0, x0 = divStep(x1, x0, y)
+again1:
+ if q1 >= _B2 || q1*vn0 > _B2*rhat+un1 {
+ q1--
+ rhat += vn1
+ if rhat < _B2 {
+ goto again1
+ }
}
- r = x0 >> z
+ un21 := un32*_B2 + un1 - q1*v
+ q0 := un21 / vn1
+ rhat = un21 - q0*vn1
- if q1 != 0 {
- panic("div out of range")
+again2:
+ if q0 >= _B2 || q0*vn0 > _B2*rhat+un0 {
+ q0--
+ rhat += vn1
+ if rhat < _B2 {
+ goto again2
+ }
}
- return q0, r
+ return q1*_B2 + q0, (un21*_B2 + un0 - q0*v) >> s
}
diff --git a/src/pkg/big/arith_arm.s b/src/pkg/big/arith_arm.s
index c8a45efc4..e4a9a962c 100644
--- a/src/pkg/big/arith_arm.s
+++ b/src/pkg/big/arith_arm.s
@@ -5,31 +5,302 @@
// This file provides fast assembly versions for the elementary
// arithmetic operations on vectors implemented in arith.go.
-// TODO(gri) Implement these routines.
+#define CFLAG 29 // bit position of carry flag
+
+// func addVV(z, x, y []Word) (c Word)
TEXT ·addVV(SB),7,$0
- B ·addVV_g(SB)
+ MOVW $0, R0
+ MOVW z+0(FP), R1
+ MOVW x+12(FP), R2
+ MOVW y+24(FP), R3
+ MOVW n+4(FP), R4
+ MOVW R4<<2, R4
+ ADD R1, R4
+ B E1
+L1:
+ MOVW.P 4(R2), R5
+ MOVW.P 4(R3), R6
+ MOVW R0, CPSR
+ ADC.S R6, R5
+ MOVW.P R5, 4(R1)
+ MOVW CPSR, R0
+E1:
+ CMP R1, R4
+ BNE L1
+
+ MOVW R0>>CFLAG, R0
+ AND $1, R0
+ MOVW R0, c+36(FP)
+ RET
+
+// func subVV(z, x, y []Word) (c Word)
+// (same as addVV except for SBC instead of ADC and label names)
TEXT ·subVV(SB),7,$0
- B ·subVV_g(SB)
+ MOVW $(1<<CFLAG), R0
+ MOVW z+0(FP), R1
+ MOVW x+12(FP), R2
+ MOVW y+24(FP), R3
+ MOVW n+4(FP), R4
+ MOVW R4<<2, R4
+ ADD R1, R4
+ B E2
+L2:
+ MOVW.P 4(R2), R5
+ MOVW.P 4(R3), R6
+ MOVW R0, CPSR
+ SBC.S R6, R5
+ MOVW.P R5, 4(R1)
+ MOVW CPSR, R0
+E2:
+ CMP R1, R4
+ BNE L2
+
+ MOVW R0>>CFLAG, R0
+ AND $1, R0
+ EOR $1, R0
+ MOVW R0, c+36(FP)
+ RET
+
+// func addVW(z, x []Word, y Word) (c Word)
TEXT ·addVW(SB),7,$0
- B ·addVW_g(SB)
+ MOVW z+0(FP), R1
+ MOVW x+12(FP), R2
+ MOVW y+24(FP), R3
+ MOVW n+4(FP), R4
+ MOVW R4<<2, R4
+ ADD R1, R4
+ CMP R1, R4
+ BNE L3a
+ MOVW R3, c+28(FP)
+ RET
+L3a:
+ MOVW.P 4(R2), R5
+ ADD.S R3, R5
+ MOVW.P R5, 4(R1)
+ MOVW CPSR, R0
+ B E3
+L3:
+ MOVW.P 4(R2), R5
+ MOVW R0, CPSR
+ ADC.S $0, R5
+ MOVW.P R5, 4(R1)
+ MOVW CPSR, R0
+E3:
+ CMP R1, R4
+ BNE L3
+
+ MOVW R0>>CFLAG, R0
+ AND $1, R0
+ MOVW R0, c+28(FP)
+ RET
+
TEXT ·subVW(SB),7,$0
- B ·subVW_g(SB)
+ MOVW z+0(FP), R1
+ MOVW x+12(FP), R2
+ MOVW y+24(FP), R3
+ MOVW n+4(FP), R4
+ MOVW R4<<2, R4
+ ADD R1, R4
+ CMP R1, R4
+ BNE L4a
+ MOVW R3, c+28(FP)
+ RET
+L4a:
+ MOVW.P 4(R2), R5
+ SUB.S R3, R5
+ MOVW.P R5, 4(R1)
+ MOVW CPSR, R0
+ B E4
+L4:
+ MOVW.P 4(R2), R5
+ MOVW R0, CPSR
+ SBC.S $0, R5
+ MOVW.P R5, 4(R1)
+ MOVW CPSR, R0
+E4:
+ CMP R1, R4
+ BNE L4
+
+ MOVW R0>>CFLAG, R0
+ AND $1, R0
+ EOR $1, R0
+ MOVW R0, c+28(FP)
+ RET
+
+// func shlVW(z, x []Word, s Word) (c Word)
TEXT ·shlVW(SB),7,$0
- B ·shlVW_g(SB)
+ MOVW n+4(FP), R5
+ CMP $0, R5
+ BEQ X7
+
+ MOVW z+0(FP), R1
+ MOVW x+12(FP), R2
+ MOVW R5<<2, R5
+ ADD R5, R2
+ ADD R1, R5
+ MOVW s+24(FP), R3
+ CMP $0, R3 // shift 0 is special
+ BEQ Y7
+ ADD $4, R1 // stop one word early
+ MOVW $32, R4
+ SUB R3, R4
+ MOVW $0, R7
+
+ MOVW.W -4(R2), R6
+ MOVW R6<<R3, R7
+ MOVW R6>>R4, R6
+ MOVW R6, c+28(FP)
+ B E7
+
+L7:
+ MOVW.W -4(R2), R6
+ ORR R6>>R4, R7
+ MOVW.W R7, -4(R5)
+ MOVW R6<<R3, R7
+E7:
+ CMP R1, R5
+ BNE L7
+
+ MOVW R7, -4(R5)
+ RET
+
+Y7: // copy loop, because shift 0 == shift 32
+ MOVW.W -4(R2), R6
+ MOVW.W R6, -4(R5)
+ CMP R1, R5
+ BNE Y7
+
+X7:
+ MOVW $0, R1
+ MOVW R1, c+28(FP)
+ RET
+
TEXT ·shrVW(SB),7,$0
- B ·shrVW_g(SB)
+ MOVW n+4(FP), R5
+ CMP $0, R5
+ BEQ X6
+
+ MOVW z+0(FP), R1
+ MOVW x+12(FP), R2
+ MOVW R5<<2, R5
+ ADD R1, R5
+ MOVW s+24(FP), R3
+ CMP $0, R3 // shift 0 is special
+ BEQ Y6
+ SUB $4, R5 // stop one word early
+ MOVW $32, R4
+ SUB R3, R4
+ MOVW $0, R7
+
+ // first word
+ MOVW.P 4(R2), R6
+ MOVW R6>>R3, R7
+ MOVW R6<<R4, R6
+ MOVW R6, c+28(FP)
+ B E6
+
+ // word loop
+L6:
+ MOVW.P 4(R2), R6
+ ORR R6<<R4, R7
+ MOVW.P R7, 4(R1)
+ MOVW R6>>R3, R7
+E6:
+ CMP R1, R5
+ BNE L6
+
+ MOVW R7, 0(R1)
+ RET
+
+Y6: // copy loop, because shift 0 == shift 32
+ MOVW.P 4(R2), R6
+ MOVW.P R6, 4(R1)
+ CMP R1, R5
+ BNE Y6
+
+X6:
+ MOVW $0, R1
+ MOVW R1, c+28(FP)
+ RET
+
TEXT ·mulAddVWW(SB),7,$0
- B ·mulAddVWW_g(SB)
+ MOVW $0, R0
+ MOVW z+0(FP), R1
+ MOVW x+12(FP), R2
+ MOVW y+24(FP), R3
+ MOVW r+28(FP), R4
+ MOVW n+4(FP), R5
+ MOVW R5<<2, R5
+ ADD R1, R5
+ B E8
+
+ // word loop
+L8:
+ MOVW.P 4(R2), R6
+ MULLU R6, R3, (R7, R6)
+ ADD.S R4, R6
+ ADC R0, R7
+ MOVW.P R6, 4(R1)
+ MOVW R7, R4
+E8:
+ CMP R1, R5
+ BNE L8
+
+ MOVW R4, c+32(FP)
+ RET
+
TEXT ·addMulVVW(SB),7,$0
- B ·addMulVVW_g(SB)
+ MOVW $0, R0
+ MOVW z+0(FP), R1
+ MOVW x+12(FP), R2
+ MOVW y+24(FP), R3
+ MOVW n+4(FP), R5
+ MOVW R5<<2, R5
+ ADD R1, R5
+ MOVW $0, R4
+ B E9
+
+ // word loop
+L9:
+ MOVW.P 4(R2), R6
+ MULLU R6, R3, (R7, R6)
+ ADD.S R4, R6
+ ADC R0, R7
+ MOVW 0(R1), R4
+ ADD.S R4, R6
+ ADC R0, R7
+ MOVW.P R6, 4(R1)
+ MOVW R7, R4
+E9:
+ CMP R1, R5
+ BNE L9
+
+ MOVW R4, c+28(FP)
+ RET
+
TEXT ·divWVW(SB),7,$0
+ // ARM has no multiword division, so use portable code.
B ·divWVW_g(SB)
+
+TEXT ·divWW(SB),7,$0
+ // ARM has no multiword division, so use portable code.
+ B ·divWW_g(SB)
+
+
+// func mulWW(x, y Word) (z1, z0 Word)
+TEXT ·mulWW(SB),7,$0
+ MOVW x+0(FP), R1
+ MOVW y+4(FP), R2
+ MULLU R1, R2, (R4, R3)
+ MOVW R4, z1+8(FP)
+ MOVW R3, z0+12(FP)
+ RET
diff --git a/src/pkg/big/arith_test.go b/src/pkg/big/arith_test.go
index efdb65123..934b302df 100644
--- a/src/pkg/big/arith_test.go
+++ b/src/pkg/big/arith_test.go
@@ -13,17 +13,17 @@ type argWW struct {
}
var sumWW = []argWW{
- argWW{0, 0, 0, 0, 0},
- argWW{0, 1, 0, 0, 1},
- argWW{0, 0, 1, 0, 1},
- argWW{0, 1, 1, 0, 2},
- argWW{12345, 67890, 0, 0, 80235},
- argWW{12345, 67890, 1, 0, 80236},
- argWW{_M, 1, 0, 1, 0},
- argWW{_M, 0, 1, 1, 0},
- argWW{_M, 1, 1, 1, 1},
- argWW{_M, _M, 0, 1, _M - 1},
- argWW{_M, _M, 1, 1, _M},
+ {0, 0, 0, 0, 0},
+ {0, 1, 0, 0, 1},
+ {0, 0, 1, 0, 1},
+ {0, 1, 1, 0, 2},
+ {12345, 67890, 0, 0, 80235},
+ {12345, 67890, 1, 0, 80236},
+ {_M, 1, 0, 1, 0},
+ {_M, 0, 1, 1, 0},
+ {_M, 1, 1, 1, 1},
+ {_M, _M, 0, 1, _M - 1},
+ {_M, _M, 1, 1, _M},
}
@@ -59,15 +59,15 @@ type argVV struct {
}
var sumVV = []argVV{
- argVV{},
- argVV{nat{0}, nat{0}, nat{0}, 0},
- argVV{nat{1}, nat{1}, nat{0}, 0},
- argVV{nat{0}, nat{_M}, nat{1}, 1},
- argVV{nat{80235}, nat{12345}, nat{67890}, 0},
- argVV{nat{_M - 1}, nat{_M}, nat{_M}, 1},
- argVV{nat{0, 0, 0, 0}, nat{_M, _M, _M, _M}, nat{1, 0, 0, 0}, 1},
- argVV{nat{0, 0, 0, _M}, nat{_M, _M, _M, _M - 1}, nat{1, 0, 0, 0}, 0},
- argVV{nat{0, 0, 0, 0}, nat{_M, 0, _M, 0}, nat{1, _M, 0, _M}, 1},
+ {},
+ {nat{0}, nat{0}, nat{0}, 0},
+ {nat{1}, nat{1}, nat{0}, 0},
+ {nat{0}, nat{_M}, nat{1}, 1},
+ {nat{80235}, nat{12345}, nat{67890}, 0},
+ {nat{_M - 1}, nat{_M}, nat{_M}, 1},
+ {nat{0, 0, 0, 0}, nat{_M, _M, _M, _M}, nat{1, 0, 0, 0}, 1},
+ {nat{0, 0, 0, _M}, nat{_M, _M, _M, _M - 1}, nat{1, 0, 0, 0}, 0},
+ {nat{0, 0, 0, 0}, nat{_M, 0, _M, 0}, nat{1, _M, 0, _M}, 1},
}
@@ -115,57 +115,58 @@ type argVW struct {
}
var sumVW = []argVW{
- argVW{},
- argVW{nat{0}, nat{0}, 0, 0},
- argVW{nat{1}, nat{0}, 1, 0},
- argVW{nat{1}, nat{1}, 0, 0},
- argVW{nat{0}, nat{_M}, 1, 1},
- argVW{nat{0, 0, 0, 0}, nat{_M, _M, _M, _M}, 1, 1},
+ {},
+ {nil, nil, 2, 2},
+ {nat{0}, nat{0}, 0, 0},
+ {nat{1}, nat{0}, 1, 0},
+ {nat{1}, nat{1}, 0, 0},
+ {nat{0}, nat{_M}, 1, 1},
+ {nat{0, 0, 0, 0}, nat{_M, _M, _M, _M}, 1, 1},
}
var prodVW = []argVW{
- argVW{},
- argVW{nat{0}, nat{0}, 0, 0},
- argVW{nat{0}, nat{_M}, 0, 0},
- argVW{nat{0}, nat{0}, _M, 0},
- argVW{nat{1}, nat{1}, 1, 0},
- argVW{nat{22793}, nat{991}, 23, 0},
- argVW{nat{0, 0, 0, 22793}, nat{0, 0, 0, 991}, 23, 0},
- argVW{nat{0, 0, 0, 0}, nat{7893475, 7395495, 798547395, 68943}, 0, 0},
- argVW{nat{0, 0, 0, 0}, nat{0, 0, 0, 0}, 894375984, 0},
- argVW{nat{_M << 1 & _M}, nat{_M}, 1 << 1, _M >> (_W - 1)},
- argVW{nat{_M << 7 & _M}, nat{_M}, 1 << 7, _M >> (_W - 7)},
- argVW{nat{_M << 7 & _M, _M, _M, _M}, nat{_M, _M, _M, _M}, 1 << 7, _M >> (_W - 7)},
+ {},
+ {nat{0}, nat{0}, 0, 0},
+ {nat{0}, nat{_M}, 0, 0},
+ {nat{0}, nat{0}, _M, 0},
+ {nat{1}, nat{1}, 1, 0},
+ {nat{22793}, nat{991}, 23, 0},
+ {nat{0, 0, 0, 22793}, nat{0, 0, 0, 991}, 23, 0},
+ {nat{0, 0, 0, 0}, nat{7893475, 7395495, 798547395, 68943}, 0, 0},
+ {nat{0, 0, 0, 0}, nat{0, 0, 0, 0}, 894375984, 0},
+ {nat{_M << 1 & _M}, nat{_M}, 1 << 1, _M >> (_W - 1)},
+ {nat{_M << 7 & _M}, nat{_M}, 1 << 7, _M >> (_W - 7)},
+ {nat{_M << 7 & _M, _M, _M, _M}, nat{_M, _M, _M, _M}, 1 << 7, _M >> (_W - 7)},
}
var lshVW = []argVW{
- argVW{},
- argVW{nat{0}, nat{0}, 0, 0},
- argVW{nat{0}, nat{0}, 1, 0},
- argVW{nat{0}, nat{0}, 20, 0},
-
- argVW{nat{_M}, nat{_M}, 0, 0},
- argVW{nat{_M << 1 & _M}, nat{_M}, 1, 1},
- argVW{nat{_M << 20 & _M}, nat{_M}, 20, _M >> (_W - 20)},
-
- argVW{nat{_M, _M, _M}, nat{_M, _M, _M}, 0, 0},
- argVW{nat{_M << 1 & _M, _M, _M}, nat{_M, _M, _M}, 1, 1},
- argVW{nat{_M << 20 & _M, _M, _M}, nat{_M, _M, _M}, 20, _M >> (_W - 20)},
+ {},
+ {nat{0}, nat{0}, 0, 0},
+ {nat{0}, nat{0}, 1, 0},
+ {nat{0}, nat{0}, 20, 0},
+
+ {nat{_M}, nat{_M}, 0, 0},
+ {nat{_M << 1 & _M}, nat{_M}, 1, 1},
+ {nat{_M << 20 & _M}, nat{_M}, 20, _M >> (_W - 20)},
+
+ {nat{_M, _M, _M}, nat{_M, _M, _M}, 0, 0},
+ {nat{_M << 1 & _M, _M, _M}, nat{_M, _M, _M}, 1, 1},
+ {nat{_M << 20 & _M, _M, _M}, nat{_M, _M, _M}, 20, _M >> (_W - 20)},
}
var rshVW = []argVW{
- argVW{},
- argVW{nat{0}, nat{0}, 0, 0},
- argVW{nat{0}, nat{0}, 1, 0},
- argVW{nat{0}, nat{0}, 20, 0},
-
- argVW{nat{_M}, nat{_M}, 0, 0},
- argVW{nat{_M >> 1}, nat{_M}, 1, _M << (_W - 1) & _M},
- argVW{nat{_M >> 20}, nat{_M}, 20, _M << (_W - 20) & _M},
-
- argVW{nat{_M, _M, _M}, nat{_M, _M, _M}, 0, 0},
- argVW{nat{_M, _M, _M >> 1}, nat{_M, _M, _M}, 1, _M << (_W - 1) & _M},
- argVW{nat{_M, _M, _M >> 20}, nat{_M, _M, _M}, 20, _M << (_W - 20) & _M},
+ {},
+ {nat{0}, nat{0}, 0, 0},
+ {nat{0}, nat{0}, 1, 0},
+ {nat{0}, nat{0}, 20, 0},
+
+ {nat{_M}, nat{_M}, 0, 0},
+ {nat{_M >> 1}, nat{_M}, 1, _M << (_W - 1) & _M},
+ {nat{_M >> 20}, nat{_M}, 20, _M << (_W - 20) & _M},
+
+ {nat{_M, _M, _M}, nat{_M, _M, _M}, 0, 0},
+ {nat{_M, _M, _M >> 1}, nat{_M, _M, _M}, 1, _M << (_W - 1) & _M},
+ {nat{_M, _M, _M >> 20}, nat{_M, _M, _M}, 20, _M << (_W - 20) & _M},
}
@@ -217,29 +218,29 @@ type argVWW struct {
}
var prodVWW = []argVWW{
- argVWW{},
- argVWW{nat{0}, nat{0}, 0, 0, 0},
- argVWW{nat{991}, nat{0}, 0, 991, 0},
- argVWW{nat{0}, nat{_M}, 0, 0, 0},
- argVWW{nat{991}, nat{_M}, 0, 991, 0},
- argVWW{nat{0}, nat{0}, _M, 0, 0},
- argVWW{nat{991}, nat{0}, _M, 991, 0},
- argVWW{nat{1}, nat{1}, 1, 0, 0},
- argVWW{nat{992}, nat{1}, 1, 991, 0},
- argVWW{nat{22793}, nat{991}, 23, 0, 0},
- argVWW{nat{22800}, nat{991}, 23, 7, 0},
- argVWW{nat{0, 0, 0, 22793}, nat{0, 0, 0, 991}, 23, 0, 0},
- argVWW{nat{7, 0, 0, 22793}, nat{0, 0, 0, 991}, 23, 7, 0},
- argVWW{nat{0, 0, 0, 0}, nat{7893475, 7395495, 798547395, 68943}, 0, 0, 0},
- argVWW{nat{991, 0, 0, 0}, nat{7893475, 7395495, 798547395, 68943}, 0, 991, 0},
- argVWW{nat{0, 0, 0, 0}, nat{0, 0, 0, 0}, 894375984, 0, 0},
- argVWW{nat{991, 0, 0, 0}, nat{0, 0, 0, 0}, 894375984, 991, 0},
- argVWW{nat{_M << 1 & _M}, nat{_M}, 1 << 1, 0, _M >> (_W - 1)},
- argVWW{nat{_M<<1&_M + 1}, nat{_M}, 1 << 1, 1, _M >> (_W - 1)},
- argVWW{nat{_M << 7 & _M}, nat{_M}, 1 << 7, 0, _M >> (_W - 7)},
- argVWW{nat{_M<<7&_M + 1<<6}, nat{_M}, 1 << 7, 1 << 6, _M >> (_W - 7)},
- argVWW{nat{_M << 7 & _M, _M, _M, _M}, nat{_M, _M, _M, _M}, 1 << 7, 0, _M >> (_W - 7)},
- argVWW{nat{_M<<7&_M + 1<<6, _M, _M, _M}, nat{_M, _M, _M, _M}, 1 << 7, 1 << 6, _M >> (_W - 7)},
+ {},
+ {nat{0}, nat{0}, 0, 0, 0},
+ {nat{991}, nat{0}, 0, 991, 0},
+ {nat{0}, nat{_M}, 0, 0, 0},
+ {nat{991}, nat{_M}, 0, 991, 0},
+ {nat{0}, nat{0}, _M, 0, 0},
+ {nat{991}, nat{0}, _M, 991, 0},
+ {nat{1}, nat{1}, 1, 0, 0},
+ {nat{992}, nat{1}, 1, 991, 0},
+ {nat{22793}, nat{991}, 23, 0, 0},
+ {nat{22800}, nat{991}, 23, 7, 0},
+ {nat{0, 0, 0, 22793}, nat{0, 0, 0, 991}, 23, 0, 0},
+ {nat{7, 0, 0, 22793}, nat{0, 0, 0, 991}, 23, 7, 0},
+ {nat{0, 0, 0, 0}, nat{7893475, 7395495, 798547395, 68943}, 0, 0, 0},
+ {nat{991, 0, 0, 0}, nat{7893475, 7395495, 798547395, 68943}, 0, 991, 0},
+ {nat{0, 0, 0, 0}, nat{0, 0, 0, 0}, 894375984, 0, 0},
+ {nat{991, 0, 0, 0}, nat{0, 0, 0, 0}, 894375984, 991, 0},
+ {nat{_M << 1 & _M}, nat{_M}, 1 << 1, 0, _M >> (_W - 1)},
+ {nat{_M<<1&_M + 1}, nat{_M}, 1 << 1, 1, _M >> (_W - 1)},
+ {nat{_M << 7 & _M}, nat{_M}, 1 << 7, 0, _M >> (_W - 7)},
+ {nat{_M<<7&_M + 1<<6}, nat{_M}, 1 << 7, 1 << 6, _M >> (_W - 7)},
+ {nat{_M << 7 & _M, _M, _M, _M}, nat{_M, _M, _M, _M}, 1 << 7, 0, _M >> (_W - 7)},
+ {nat{_M<<7&_M + 1<<6, _M, _M, _M}, nat{_M, _M, _M, _M}, 1 << 7, 1 << 6, _M >> (_W - 7)},
}
@@ -300,15 +301,12 @@ func TestFunVWW(t *testing.T) {
}
-type mulWWTest struct {
+var mulWWTests = []struct {
x, y Word
q, r Word
-}
-
-
-var mulWWTests = []mulWWTest{
- mulWWTest{_M, _M, _M - 1, 1},
- // 32 bit only: mulWWTest{0xc47dfa8c, 50911, 0x98a4, 0x998587f4},
+}{
+ {_M, _M, _M - 1, 1},
+ // 32 bit only: {0xc47dfa8c, 50911, 0x98a4, 0x998587f4},
}
@@ -322,18 +320,15 @@ func TestMulWW(t *testing.T) {
}
-type mulAddWWWTest struct {
+var mulAddWWWTests = []struct {
x, y, c Word
q, r Word
-}
-
-
-var mulAddWWWTests = []mulAddWWWTest{
+}{
// TODO(agl): These will only work on 64-bit platforms.
- // mulAddWWWTest{15064310297182388543, 0xe7df04d2d35d5d80, 13537600649892366549, 13644450054494335067, 10832252001440893781},
- // mulAddWWWTest{15064310297182388543, 0xdab2f18048baa68d, 13644450054494335067, 12869334219691522700, 14233854684711418382},
- mulAddWWWTest{_M, _M, 0, _M - 1, 1},
- mulAddWWWTest{_M, _M, _M, _M, 0},
+ // {15064310297182388543, 0xe7df04d2d35d5d80, 13537600649892366549, 13644450054494335067, 10832252001440893781},
+ // {15064310297182388543, 0xdab2f18048baa68d, 13644450054494335067, 12869334219691522700, 14233854684711418382},
+ {_M, _M, 0, _M - 1, 1},
+ {_M, _M, _M, _M, 0},
}
diff --git a/src/pkg/big/int.go b/src/pkg/big/int.go
index 873d5b50c..46e008734 100755
--- a/src/pkg/big/int.go
+++ b/src/pkg/big/int.go
@@ -6,8 +6,10 @@
package big
-import "fmt"
-
+import (
+ "fmt"
+ "rand"
+)
// An Int represents a signed multi-precision integer.
// The zero value for an Int represents the value 0.
@@ -20,6 +22,23 @@ type Int struct {
var intOne = &Int{false, natOne}
+// Sign returns:
+//
+// -1 if x < 0
+// 0 if x == 0
+// +1 if x > 0
+//
+func (x *Int) Sign() int {
+ if len(x.abs) == 0 {
+ return 0
+ }
+ if x.neg {
+ return -1
+ }
+ return 1
+}
+
+
// SetInt64 sets z to x and returns z.
func (z *Int) SetInt64(x int64) *Int {
neg := false
@@ -47,6 +66,14 @@ func (z *Int) Set(x *Int) *Int {
}
+// Abs sets z to |x| (the absolute value of x) and returns z.
+func (z *Int) Abs(x *Int) *Int {
+ z.abs = z.abs.set(x.abs)
+ z.neg = false
+ return z
+}
+
+
// Neg sets z to -x and returns z.
func (z *Int) Neg(x *Int) *Int {
z.abs = z.abs.set(x.abs)
@@ -347,10 +374,12 @@ func (z *Int) SetString(s string, base int) (*Int, bool) {
return z, false
}
- neg := false
- if s[0] == '-' {
- neg = true
+ neg := s[0] == '-'
+ if neg || s[0] == '+' {
s = s[1:]
+ if len(s) == 0 {
+ return z, false
+ }
}
var scanned int
@@ -518,6 +547,18 @@ func ProbablyPrime(z *Int, n int) bool {
}
+// Rand sets z to a pseudo-random number in [0, n) and returns z.
+func (z *Int) Rand(rnd *rand.Rand, n *Int) *Int {
+ z.neg = false
+ if n.neg == true || len(n.abs) == 0 {
+ z.abs = nil
+ return z
+ }
+ z.abs = z.abs.random(rnd, n.abs, n.abs.bitLen())
+ return z
+}
+
+
// ModInverse sets z to the multiplicative inverse of g in the group ℤ/pℤ (where
// p is a prime) and returns z.
func (z *Int) ModInverse(g, p *Int) *Int {
@@ -563,7 +604,7 @@ func (z *Int) And(x, y *Int) *Int {
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 := z.abs.sub(y.abs, natOne)
+ y1 := nat{}.sub(y.abs, natOne)
z.abs = z.abs.add(z.abs.or(x1, y1), natOne)
z.neg = true // z cannot be zero if x and y are negative
return z
@@ -581,7 +622,7 @@ func (z *Int) And(x, y *Int) *Int {
}
// x & (-y) == x & ^(y-1) == x &^ (y-1)
- y1 := z.abs.sub(y.abs, natOne)
+ y1 := nat{}.sub(y.abs, natOne)
z.abs = z.abs.andNot(x.abs, y1)
z.neg = false
return z
@@ -594,7 +635,7 @@ func (z *Int) AndNot(x, y *Int) *Int {
if x.neg {
// (-x) &^ (-y) == ^(x-1) &^ ^(y-1) == ^(x-1) & (y-1) == (y-1) &^ (x-1)
x1 := nat{}.sub(x.abs, natOne)
- y1 := z.abs.sub(y.abs, natOne)
+ y1 := nat{}.sub(y.abs, natOne)
z.abs = z.abs.andNot(y1, x1)
z.neg = false
return z
@@ -608,14 +649,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 := z.abs.sub(x.abs, natOne)
+ x1 := nat{}.sub(x.abs, natOne)
z.abs = z.abs.add(z.abs.or(x1, y.abs), natOne)
z.neg = true // z cannot be zero if x is negative and y is positive
return z
}
// x &^ (-y) == x &^ ^(y-1) == x & (y-1)
- y1 := z.abs.add(y.abs, natOne)
+ y1 := nat{}.add(y.abs, natOne)
z.abs = z.abs.and(x.abs, y1)
z.neg = false
return z
@@ -628,7 +669,7 @@ func (z *Int) Or(x, y *Int) *Int {
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 := z.abs.sub(y.abs, natOne)
+ y1 := nat{}.sub(y.abs, natOne)
z.abs = z.abs.add(z.abs.and(x1, y1), natOne)
z.neg = true // z cannot be zero if x and y are negative
return z
@@ -646,7 +687,7 @@ func (z *Int) Or(x, y *Int) *Int {
}
// x | (-y) == x | ^(y-1) == ^((y-1) &^ x) == -(^((y-1) &^ x) + 1)
- y1 := z.abs.sub(y.abs, natOne)
+ y1 := nat{}.sub(y.abs, natOne)
z.abs = z.abs.add(z.abs.andNot(y1, x.abs), natOne)
z.neg = true // z cannot be zero if one of x or y is negative
return z
@@ -659,7 +700,7 @@ func (z *Int) Xor(x, y *Int) *Int {
if x.neg {
// (-x) ^ (-y) == ^(x-1) ^ ^(y-1) == (x-1) ^ (y-1)
x1 := nat{}.sub(x.abs, natOne)
- y1 := z.abs.sub(y.abs, natOne)
+ y1 := nat{}.sub(y.abs, natOne)
z.abs = z.abs.xor(x1, y1)
z.neg = false
return z
@@ -677,7 +718,7 @@ func (z *Int) Xor(x, y *Int) *Int {
}
// x ^ (-y) == x ^ ^(y-1) == ^(x ^ (y-1)) == -((x ^ (y-1)) + 1)
- y1 := z.abs.sub(y.abs, natOne)
+ y1 := nat{}.sub(y.abs, natOne)
z.abs = z.abs.add(z.abs.xor(x.abs, y1), natOne)
z.neg = true // z cannot be zero if only one of x or y is negative
return z
diff --git a/src/pkg/big/int_test.go b/src/pkg/big/int_test.go
index 269c814d4..fc981e1da 100755
--- a/src/pkg/big/int_test.go
+++ b/src/pkg/big/int_test.go
@@ -29,24 +29,36 @@ type argZZ struct {
var sumZZ = []argZZ{
- argZZ{NewInt(0), NewInt(0), NewInt(0)},
- argZZ{NewInt(1), NewInt(1), NewInt(0)},
- argZZ{NewInt(1111111110), NewInt(123456789), NewInt(987654321)},
- argZZ{NewInt(-1), NewInt(-1), NewInt(0)},
- argZZ{NewInt(864197532), NewInt(-123456789), NewInt(987654321)},
- argZZ{NewInt(-1111111110), NewInt(-123456789), NewInt(-987654321)},
+ {NewInt(0), NewInt(0), NewInt(0)},
+ {NewInt(1), NewInt(1), NewInt(0)},
+ {NewInt(1111111110), NewInt(123456789), NewInt(987654321)},
+ {NewInt(-1), NewInt(-1), NewInt(0)},
+ {NewInt(864197532), NewInt(-123456789), NewInt(987654321)},
+ {NewInt(-1111111110), NewInt(-123456789), NewInt(-987654321)},
}
var prodZZ = []argZZ{
- argZZ{NewInt(0), NewInt(0), NewInt(0)},
- argZZ{NewInt(0), NewInt(1), NewInt(0)},
- argZZ{NewInt(1), NewInt(1), NewInt(1)},
- argZZ{NewInt(-991 * 991), NewInt(991), NewInt(-991)},
+ {NewInt(0), NewInt(0), NewInt(0)},
+ {NewInt(0), NewInt(1), NewInt(0)},
+ {NewInt(1), NewInt(1), NewInt(1)},
+ {NewInt(-991 * 991), NewInt(991), NewInt(-991)},
// TODO(gri) add larger products
}
+func TestSignZ(t *testing.T) {
+ var zero Int
+ for _, a := range sumZZ {
+ s := a.z.Sign()
+ e := a.z.Cmp(&zero)
+ if s != e {
+ t.Errorf("got %d; want %d for z = %v", s, e, a.z)
+ }
+ }
+}
+
+
func TestSetZ(t *testing.T) {
for _, a := range sumZZ {
var z Int
@@ -61,11 +73,28 @@ func TestSetZ(t *testing.T) {
}
+func TestAbsZ(t *testing.T) {
+ var zero Int
+ for _, a := range sumZZ {
+ var z Int
+ z.Abs(a.z)
+ var e Int
+ e.Set(a.z)
+ if e.Cmp(&zero) < 0 {
+ e.Sub(&zero, &e)
+ }
+ if z.Cmp(&e) != 0 {
+ t.Errorf("got z = %v; want %v", z, e)
+ }
+ }
+}
+
+
func testFunZZ(t *testing.T, msg string, f funZZ, a argZZ) {
var z Int
f(&z, a.x, a.y)
if !isNormalized(&z) {
- t.Errorf("msg: %v is not normalized", z, msg)
+ t.Errorf("%s%v is not normalized", z, msg)
}
if (&z).Cmp(a.z) != 0 {
t.Errorf("%s%+v\n\tgot z = %v; want %v", msg, a, &z, a.z)
@@ -157,28 +186,25 @@ func TestMul(t *testing.T) {
}
-type mulRangeZ struct {
+var mulRangesZ = []struct {
a, b int64
prod string
-}
-
-
-var mulRangesZ = []mulRangeZ{
+}{
// entirely positive ranges are covered by mulRangesN
- mulRangeZ{-1, 1, "0"},
- mulRangeZ{-2, -1, "2"},
- mulRangeZ{-3, -2, "6"},
- mulRangeZ{-3, -1, "-6"},
- mulRangeZ{1, 3, "6"},
- mulRangeZ{-10, -10, "-10"},
- mulRangeZ{0, -1, "1"}, // empty range
- mulRangeZ{-1, -100, "1"}, // empty range
- mulRangeZ{-1, 1, "0"}, // range includes 0
- mulRangeZ{-1e9, 0, "0"}, // range includes 0
- mulRangeZ{-1e9, 1e9, "0"}, // range includes 0
- mulRangeZ{-10, -1, "3628800"}, // 10!
- mulRangeZ{-20, -2, "-2432902008176640000"}, // -20!
- mulRangeZ{-99, -1,
+ {-1, 1, "0"},
+ {-2, -1, "2"},
+ {-3, -2, "6"},
+ {-3, -1, "-6"},
+ {1, 3, "6"},
+ {-10, -10, "-10"},
+ {0, -1, "1"}, // empty range
+ {-1, -100, "1"}, // empty range
+ {-1, 1, "0"}, // range includes 0
+ {-1e9, 0, "0"}, // range includes 0
+ {-1e9, 1e9, "0"}, // range includes 0
+ {-10, -1, "3628800"}, // 10!
+ {-20, -2, "-2432902008176640000"}, // -20!
+ {-99, -1,
"-933262154439441526816992388562667004907159682643816214685929" +
"638952175999932299156089414639761565182862536979208272237582" +
"511852109168640000000000000000000000", // -99!
@@ -205,50 +231,52 @@ func TestMulRangeZ(t *testing.T) {
}
-type stringTest struct {
+var stringTests = []struct {
in string
out string
base int
val int64
ok bool
-}
-
-
-var stringTests = []stringTest{
- stringTest{in: "", ok: false},
- stringTest{in: "a", ok: false},
- stringTest{in: "z", ok: false},
- stringTest{in: "+", ok: false},
- stringTest{in: "0b", ok: false},
- stringTest{in: "0x", ok: false},
- stringTest{in: "2", base: 2, ok: false},
- stringTest{in: "0b2", base: 0, ok: false},
- stringTest{in: "08", ok: false},
- stringTest{in: "8", base: 8, ok: false},
- stringTest{in: "0xg", base: 0, ok: false},
- stringTest{in: "g", base: 16, ok: false},
- stringTest{"0", "0", 0, 0, true},
- stringTest{"0", "0", 10, 0, true},
- stringTest{"0", "0", 16, 0, true},
- stringTest{"10", "10", 0, 10, true},
- stringTest{"10", "10", 10, 10, true},
- stringTest{"10", "10", 16, 16, true},
- stringTest{"-10", "-10", 16, -16, true},
- stringTest{"0x10", "16", 0, 16, true},
- stringTest{in: "0x10", base: 16, ok: false},
- stringTest{"-0x10", "-16", 0, -16, true},
- stringTest{"00", "0", 0, 0, true},
- stringTest{"0", "0", 8, 0, true},
- stringTest{"07", "7", 0, 7, true},
- stringTest{"7", "7", 8, 7, true},
- stringTest{"023", "19", 0, 19, true},
- stringTest{"23", "23", 8, 19, true},
- stringTest{"cafebabe", "cafebabe", 16, 0xcafebabe, true},
- stringTest{"0b0", "0", 0, 0, true},
- stringTest{"-111", "-111", 2, -7, true},
- stringTest{"-0b111", "-7", 0, -7, true},
- stringTest{"0b1001010111", "599", 0, 0x257, true},
- stringTest{"1001010111", "1001010111", 2, 0x257, true},
+}{
+ {in: "", ok: false},
+ {in: "a", ok: false},
+ {in: "z", ok: false},
+ {in: "+", ok: false},
+ {in: "-", ok: false},
+ {in: "0b", ok: false},
+ {in: "0x", ok: false},
+ {in: "2", base: 2, ok: false},
+ {in: "0b2", base: 0, ok: false},
+ {in: "08", ok: false},
+ {in: "8", base: 8, ok: false},
+ {in: "0xg", base: 0, ok: false},
+ {in: "g", base: 16, ok: false},
+ {"0", "0", 0, 0, true},
+ {"0", "0", 10, 0, true},
+ {"0", "0", 16, 0, true},
+ {"+0", "0", 0, 0, true},
+ {"-0", "0", 0, 0, true},
+ {"10", "10", 0, 10, true},
+ {"10", "10", 10, 10, true},
+ {"10", "10", 16, 16, true},
+ {"-10", "-10", 16, -16, true},
+ {"+10", "10", 16, 16, true},
+ {"0x10", "16", 0, 16, true},
+ {in: "0x10", base: 16, ok: false},
+ {"-0x10", "-16", 0, -16, true},
+ {"+0x10", "16", 0, 16, true},
+ {"00", "0", 0, 0, true},
+ {"0", "0", 8, 0, true},
+ {"07", "7", 0, 7, true},
+ {"7", "7", 8, 7, true},
+ {"023", "19", 0, 19, true},
+ {"23", "23", 8, 19, true},
+ {"cafebabe", "cafebabe", 16, 0xcafebabe, true},
+ {"0b0", "0", 0, 0, true},
+ {"-111", "-111", 2, -7, true},
+ {"-0b111", "-7", 0, -7, true},
+ {"0b1001010111", "599", 0, 0x257, true},
+ {"1001010111", "1001010111", 2, 0x257, true},
}
@@ -276,13 +304,13 @@ func TestGetString(t *testing.T) {
if test.base == 10 {
s := z.String()
if s != test.out {
- t.Errorf("#%da got %s; want %s\n", i, s, test.out)
+ t.Errorf("#%da got %s; want %s", i, s, test.out)
}
}
s := fmt.Sprintf(format(test.base), z)
if s != test.out {
- t.Errorf("#%db got %s; want %s\n", i, s, test.out)
+ t.Errorf("#%db got %s; want %s", i, s, test.out)
}
}
}
@@ -310,30 +338,27 @@ func TestSetString(t *testing.T) {
}
if n1.Cmp(expected) != 0 {
- t.Errorf("#%d (input '%s') got: %s want: %d\n", i, test.in, n1, test.val)
+ t.Errorf("#%d (input '%s') got: %s want: %d", i, test.in, n1, test.val)
}
if n2.Cmp(expected) != 0 {
- t.Errorf("#%d (input '%s') got: %s want: %d\n", i, test.in, n2, test.val)
+ t.Errorf("#%d (input '%s') got: %s want: %d", i, test.in, n2, test.val)
}
}
}
-type divisionSignsTest struct {
+// Examples from the Go Language Spec, section "Arithmetic operators"
+var divisionSignsTests = []struct {
x, y int64
q, r int64 // T-division
d, m int64 // Euclidian division
-}
-
-
-// Examples from the Go Language Spec, section "Arithmetic operators"
-var divisionSignsTests = []divisionSignsTest{
- divisionSignsTest{5, 3, 1, 2, 1, 2},
- divisionSignsTest{-5, 3, -1, -2, -2, 1},
- divisionSignsTest{5, -3, -1, 2, -1, 2},
- divisionSignsTest{-5, -3, 1, -2, 2, 1},
- divisionSignsTest{1, 2, 0, 1, 0, 1},
- divisionSignsTest{8, 4, 2, 0, 2, 0},
+}{
+ {5, 3, 1, 2, 1, 2},
+ {-5, 3, -1, -2, -2, 1},
+ {5, -3, -1, 2, -1, 2},
+ {-5, -3, 1, -2, 2, 1},
+ {1, 2, 0, 1, 0, 1},
+ {8, 4, 2, 0, 2, 0},
}
@@ -454,20 +479,17 @@ func checkQuo(x, y []byte) bool {
}
-type quoTest struct {
+var quoTests = []struct {
x, y string
q, r string
-}
-
-
-var quoTests = []quoTest{
- quoTest{
+}{
+ {
"476217953993950760840509444250624797097991362735329973741718102894495832294430498335824897858659711275234906400899559094370964723884706254265559534144986498357",
"9353930466774385905609975137998169297361893554149986716853295022578535724979483772383667534691121982974895531435241089241440253066816724367338287092081996",
"50911",
"1",
},
- quoTest{
+ {
"11510768301994997771168",
"1328165573307167369775",
"8",
@@ -517,25 +539,22 @@ func TestQuoStepD6(t *testing.T) {
}
-type bitLenTest struct {
+var bitLenTests = []struct {
in string
out int
-}
-
-
-var bitLenTests = []bitLenTest{
- bitLenTest{"-1", 1},
- bitLenTest{"0", 0},
- bitLenTest{"1", 1},
- bitLenTest{"2", 2},
- bitLenTest{"4", 3},
- bitLenTest{"0xabc", 12},
- bitLenTest{"0x8000", 16},
- bitLenTest{"0x80000000", 32},
- bitLenTest{"0x800000000000", 48},
- bitLenTest{"0x8000000000000000", 64},
- bitLenTest{"0x80000000000000000000", 80},
- bitLenTest{"-0x4000000000000000000000", 87},
+}{
+ {"-1", 1},
+ {"0", 0},
+ {"1", 1},
+ {"2", 2},
+ {"4", 3},
+ {"0xabc", 12},
+ {"0x8000", 16},
+ {"0x80000000", 32},
+ {"0x800000000000", 48},
+ {"0x8000000000000000", 64},
+ {"0x80000000000000000000", 80},
+ {"-0x4000000000000000000000", 87},
}
@@ -548,32 +567,29 @@ func TestBitLen(t *testing.T) {
}
if n := x.BitLen(); n != test.out {
- t.Errorf("#%d got %d want %d\n", i, n, test.out)
+ t.Errorf("#%d got %d want %d", i, n, test.out)
}
}
}
-type expTest struct {
+var expTests = []struct {
x, y, m string
out string
-}
-
-
-var expTests = []expTest{
- expTest{"5", "0", "", "1"},
- expTest{"-5", "0", "", "-1"},
- expTest{"5", "1", "", "5"},
- expTest{"-5", "1", "", "-5"},
- expTest{"-2", "3", "2", "0"},
- expTest{"5", "2", "", "25"},
- expTest{"1", "65537", "2", "1"},
- expTest{"0x8000000000000000", "2", "", "0x40000000000000000000000000000000"},
- expTest{"0x8000000000000000", "2", "6719", "4944"},
- expTest{"0x8000000000000000", "3", "6719", "5447"},
- expTest{"0x8000000000000000", "1000", "6719", "1603"},
- expTest{"0x8000000000000000", "1000000", "6719", "3199"},
- expTest{
+}{
+ {"5", "0", "", "1"},
+ {"-5", "0", "", "-1"},
+ {"5", "1", "", "5"},
+ {"-5", "1", "", "-5"},
+ {"-2", "3", "2", "0"},
+ {"5", "2", "", "25"},
+ {"1", "65537", "2", "1"},
+ {"0x8000000000000000", "2", "", "0x40000000000000000000000000000000"},
+ {"0x8000000000000000", "2", "6719", "4944"},
+ {"0x8000000000000000", "3", "6719", "5447"},
+ {"0x8000000000000000", "1000", "6719", "1603"},
+ {"0x8000000000000000", "1000000", "6719", "3199"},
+ {
"2938462938472983472983659726349017249287491026512746239764525612965293865296239471239874193284792387498274256129746192347",
"298472983472983471903246121093472394872319615612417471234712061",
"29834729834729834729347290846729561262544958723956495615629569234729836259263598127342374289365912465901365498236492183464",
@@ -630,14 +646,11 @@ func checkGcd(aBytes, bBytes []byte) bool {
}
-type gcdTest struct {
+var gcdTests = []struct {
a, b int64
d, x, y int64
-}
-
-
-var gcdTests = []gcdTest{
- gcdTest{120, 23, 1, -9, 47},
+}{
+ {120, 23, 1, -9, 47},
}
@@ -726,30 +739,30 @@ type intShiftTest struct {
var rshTests = []intShiftTest{
- intShiftTest{"0", 0, "0"},
- intShiftTest{"-0", 0, "0"},
- intShiftTest{"0", 1, "0"},
- intShiftTest{"0", 2, "0"},
- intShiftTest{"1", 0, "1"},
- intShiftTest{"1", 1, "0"},
- intShiftTest{"1", 2, "0"},
- intShiftTest{"2", 0, "2"},
- intShiftTest{"2", 1, "1"},
- intShiftTest{"-1", 0, "-1"},
- intShiftTest{"-1", 1, "-1"},
- intShiftTest{"-1", 10, "-1"},
- intShiftTest{"-100", 2, "-25"},
- intShiftTest{"-100", 3, "-13"},
- intShiftTest{"-100", 100, "-1"},
- intShiftTest{"4294967296", 0, "4294967296"},
- intShiftTest{"4294967296", 1, "2147483648"},
- intShiftTest{"4294967296", 2, "1073741824"},
- intShiftTest{"18446744073709551616", 0, "18446744073709551616"},
- intShiftTest{"18446744073709551616", 1, "9223372036854775808"},
- intShiftTest{"18446744073709551616", 2, "4611686018427387904"},
- intShiftTest{"18446744073709551616", 64, "1"},
- intShiftTest{"340282366920938463463374607431768211456", 64, "18446744073709551616"},
- intShiftTest{"340282366920938463463374607431768211456", 128, "1"},
+ {"0", 0, "0"},
+ {"-0", 0, "0"},
+ {"0", 1, "0"},
+ {"0", 2, "0"},
+ {"1", 0, "1"},
+ {"1", 1, "0"},
+ {"1", 2, "0"},
+ {"2", 0, "2"},
+ {"2", 1, "1"},
+ {"-1", 0, "-1"},
+ {"-1", 1, "-1"},
+ {"-1", 10, "-1"},
+ {"-100", 2, "-25"},
+ {"-100", 3, "-13"},
+ {"-100", 100, "-1"},
+ {"4294967296", 0, "4294967296"},
+ {"4294967296", 1, "2147483648"},
+ {"4294967296", 2, "1073741824"},
+ {"18446744073709551616", 0, "18446744073709551616"},
+ {"18446744073709551616", 1, "9223372036854775808"},
+ {"18446744073709551616", 2, "4611686018427387904"},
+ {"18446744073709551616", 64, "1"},
+ {"340282366920938463463374607431768211456", 64, "18446744073709551616"},
+ {"340282366920938463463374607431768211456", 128, "1"},
}
@@ -786,25 +799,25 @@ func TestRshSelf(t *testing.T) {
var lshTests = []intShiftTest{
- intShiftTest{"0", 0, "0"},
- intShiftTest{"0", 1, "0"},
- intShiftTest{"0", 2, "0"},
- intShiftTest{"1", 0, "1"},
- intShiftTest{"1", 1, "2"},
- intShiftTest{"1", 2, "4"},
- intShiftTest{"2", 0, "2"},
- intShiftTest{"2", 1, "4"},
- intShiftTest{"2", 2, "8"},
- intShiftTest{"-87", 1, "-174"},
- intShiftTest{"4294967296", 0, "4294967296"},
- intShiftTest{"4294967296", 1, "8589934592"},
- intShiftTest{"4294967296", 2, "17179869184"},
- intShiftTest{"18446744073709551616", 0, "18446744073709551616"},
- intShiftTest{"9223372036854775808", 1, "18446744073709551616"},
- intShiftTest{"4611686018427387904", 2, "18446744073709551616"},
- intShiftTest{"1", 64, "18446744073709551616"},
- intShiftTest{"18446744073709551616", 64, "340282366920938463463374607431768211456"},
- intShiftTest{"1", 128, "340282366920938463463374607431768211456"},
+ {"0", 0, "0"},
+ {"0", 1, "0"},
+ {"0", 2, "0"},
+ {"1", 0, "1"},
+ {"1", 1, "2"},
+ {"1", 2, "4"},
+ {"2", 0, "2"},
+ {"2", 1, "4"},
+ {"2", 2, "8"},
+ {"-87", 1, "-174"},
+ {"4294967296", 0, "4294967296"},
+ {"4294967296", 1, "8589934592"},
+ {"4294967296", 2, "17179869184"},
+ {"18446744073709551616", 0, "18446744073709551616"},
+ {"9223372036854775808", 1, "18446744073709551616"},
+ {"4611686018427387904", 2, "18446744073709551616"},
+ {"1", 64, "18446744073709551616"},
+ {"18446744073709551616", 64, "340282366920938463463374607431768211456"},
+ {"1", 128, "340282366920938463463374607431768211456"},
}
@@ -894,26 +907,24 @@ func TestInt64(t *testing.T) {
}
-type bitwiseTest struct {
+var bitwiseTests = []struct {
x, y string
and, or, xor, andNot string
-}
-
-var bitwiseTests = []bitwiseTest{
- bitwiseTest{"0x00", "0x00", "0x00", "0x00", "0x00", "0x00"},
- bitwiseTest{"0x00", "0x01", "0x00", "0x01", "0x01", "0x00"},
- bitwiseTest{"0x01", "0x00", "0x00", "0x01", "0x01", "0x01"},
- bitwiseTest{"-0x01", "0x00", "0x00", "-0x01", "-0x01", "-0x01"},
- bitwiseTest{"-0xAF", "-0x50", "0x00", "-0xFF", "-0x01", "-0x01"},
- bitwiseTest{"0x00", "-0x01", "0x00", "-0x01", "-0x01", "0x00"},
- bitwiseTest{"0x01", "0x01", "0x01", "0x01", "0x00", "0x00"},
- bitwiseTest{"-0x01", "-0x01", "-0x01", "-0x01", "0x00", "0x00"},
- bitwiseTest{"0x07", "0x08", "0x00", "0x0f", "0x0f", "0x07"},
- bitwiseTest{"0x05", "0x0f", "0x05", "0x0f", "0x0a", "0x00"},
- bitwiseTest{"0x013ff6", "0x9a4e", "0x1a46", "0x01bffe", "0x01a5b8", "0x0125b0"},
- bitwiseTest{"-0x013ff6", "0x9a4e", "0x800a", "-0x0125b2", "-0x01a5bc", "-0x01c000"},
- bitwiseTest{"-0x013ff6", "-0x9a4e", "-0x01bffe", "-0x1a46", "0x01a5b8", "0x8008"},
- bitwiseTest{
+}{
+ {"0x00", "0x00", "0x00", "0x00", "0x00", "0x00"},
+ {"0x00", "0x01", "0x00", "0x01", "0x01", "0x00"},
+ {"0x01", "0x00", "0x00", "0x01", "0x01", "0x01"},
+ {"-0x01", "0x00", "0x00", "-0x01", "-0x01", "-0x01"},
+ {"-0xaf", "-0x50", "-0xf0", "-0x0f", "0xe1", "0x41"},
+ {"0x00", "-0x01", "0x00", "-0x01", "-0x01", "0x00"},
+ {"0x01", "0x01", "0x01", "0x01", "0x00", "0x00"},
+ {"-0x01", "-0x01", "-0x01", "-0x01", "0x00", "0x00"},
+ {"0x07", "0x08", "0x00", "0x0f", "0x0f", "0x07"},
+ {"0x05", "0x0f", "0x05", "0x0f", "0x0a", "0x00"},
+ {"0x013ff6", "0x9a4e", "0x1a46", "0x01bffe", "0x01a5b8", "0x0125b0"},
+ {"-0x013ff6", "0x9a4e", "0x800a", "-0x0125b2", "-0x01a5bc", "-0x01c000"},
+ {"-0x013ff6", "-0x9a4e", "-0x01bffe", "-0x1a46", "0x01a5b8", "0x8008"},
+ {
"0x1000009dc6e3d9822cba04129bcbe3401",
"0xb9bd7d543685789d57cb918e833af352559021483cdb05cc21fd",
"0x1000001186210100001000009048c2001",
@@ -921,7 +932,7 @@ var bitwiseTests = []bitwiseTest{
"0xb9bd7d543685789d57ca918e8ae69d6fcdb2eae87df2b97215fc",
"0x8c40c2d8822caa04120b8321400",
},
- bitwiseTest{
+ {
"0x1000009dc6e3d9822cba04129bcbe3401",
"-0xb9bd7d543685789d57cb918e833af352559021483cdb05cc21fd",
"0x8c40c2d8822caa04120b8321401",
@@ -929,7 +940,7 @@ var bitwiseTests = []bitwiseTest{
"-0xb9bd7d543685789d57ca918e8ae69d6fcdb2eae87df2b97215fe",
"0x1000001186210100001000009048c2000",
},
- bitwiseTest{
+ {
"-0x1000009dc6e3d9822cba04129bcbe3401",
"-0xb9bd7d543685789d57cb918e833af352559021483cdb05cc21fd",
"-0xb9bd7d543685789d57cb918e8bfeff7fddb2ebe87dfbbdfe35fd",
@@ -944,24 +955,24 @@ type bitFun func(z, x, y *Int) *Int
func testBitFun(t *testing.T, msg string, f bitFun, x, y *Int, exp string) {
expected := new(Int)
- expected.SetString(exp, 16)
+ expected.SetString(exp, 0)
out := f(new(Int), x, y)
if out.Cmp(expected) != 0 {
- println("Test failed")
t.Errorf("%s: got %s want %s", msg, out, expected)
}
}
func testBitFunSelf(t *testing.T, msg string, f bitFun, x, y *Int, exp string) {
+ self := new(Int)
+ self.Set(x)
expected := new(Int)
- expected.SetString(exp, 16)
+ expected.SetString(exp, 0)
- x = f(x, x, y)
- if x.Cmp(expected) != 0 {
- println("Test failed")
- t.Errorf("%s: got %s want %s", msg, x, expected)
+ self = f(self, self, y)
+ if self.Cmp(expected) != 0 {
+ t.Errorf("%s: got %s want %s", msg, self, expected)
}
}
@@ -970,8 +981,8 @@ func TestBitwise(t *testing.T) {
x := new(Int)
y := new(Int)
for _, test := range bitwiseTests {
- x.SetString(test.x, 16)
- y.SetString(test.y, 16)
+ x.SetString(test.x, 0)
+ y.SetString(test.y, 0)
testBitFun(t, "and", (*Int).And, x, y, test.and)
testBitFunSelf(t, "and", (*Int).And, x, y, test.and)
@@ -985,18 +996,16 @@ func TestBitwise(t *testing.T) {
}
-type notTest struct {
+var notTests = []struct {
in string
out string
-}
-
-var notTests = []notTest{
- notTest{"0", "-1"},
- notTest{"1", "-2"},
- notTest{"7", "-8"},
- notTest{"0", "-1"},
- notTest{"-81910", "81909"},
- notTest{
+}{
+ {"0", "-1"},
+ {"1", "-2"},
+ {"7", "-8"},
+ {"0", "-1"},
+ {"-81910", "81909"},
+ {
"298472983472983471903246121093472394872319615612417471234712061",
"-298472983472983471903246121093472394872319615612417471234712062",
},
@@ -1021,15 +1030,13 @@ func TestNot(t *testing.T) {
}
-type modInverseTest struct {
+var modInverseTests = []struct {
element string
prime string
-}
-
-var modInverseTests = []modInverseTest{
- modInverseTest{"1", "7"},
- modInverseTest{"1", "13"},
- modInverseTest{"239487239847", "2410312426921032588552076022197566074856950548502459942654116941958108831682612228890093858261341614673227141477904012196503648957050582631942730706805009223062734745341073406696246014589361659774041027169249453200378729434170325843778659198143763193776859869524088940195577346119843545301547043747207749969763750084308926339295559968882457872412993810129130294592999947926365264059284647209730384947211681434464714438488520940127459844288859336526896320919633919"},
+}{
+ {"1", "7"},
+ {"1", "13"},
+ {"239487239847", "2410312426921032588552076022197566074856950548502459942654116941958108831682612228890093858261341614673227141477904012196503648957050582631942730706805009223062734745341073406696246014589361659774041027169249453200378729434170325843778659198143763193776859869524088940195577346119843545301547043747207749969763750084308926339295559968882457872412993810129130294592999947926365264059284647209730384947211681434464714438488520940127459844288859336526896320919633919"},
}
func TestModInverse(t *testing.T) {
diff --git a/src/pkg/big/nat.go b/src/pkg/big/nat.go
index dc2e6be28..a308f69e8 100755
--- a/src/pkg/big/nat.go
+++ b/src/pkg/big/nat.go
@@ -103,9 +103,7 @@ func (z nat) setUint64(x uint64) nat {
func (z nat) set(x nat) nat {
z = z.make(len(x))
- for i, d := range x {
- z[i] = d
- }
+ copy(z, x)
return z
}
@@ -666,7 +664,7 @@ func (z nat) scan(s string, base int) (nat, int, int) {
}
}
- return z, base, i
+ return z.norm(), base, i
}
@@ -818,13 +816,13 @@ func (z nat) or(x, y nat) nat {
n, m = m, n
s = y
}
- // n >= m
+ // m >= n
- z = z.make(n)
- for i := 0; i < m; i++ {
+ z = z.make(m)
+ for i := 0; i < n; i++ {
z[i] = x[i] | y[i]
}
- copy(z[m:n], s[m:n])
+ copy(z[n:m], s[n:m])
return z.norm()
}
@@ -834,17 +832,17 @@ func (z nat) xor(x, y nat) nat {
m := len(x)
n := len(y)
s := x
- if n < m {
+ if m < n {
n, m = m, n
s = y
}
- // n >= m
+ // m >= n
- z = z.make(n)
- for i := 0; i < m; i++ {
+ z = z.make(m)
+ for i := 0; i < n; i++ {
z[i] = x[i] ^ y[i]
}
- copy(z[m:n], s[m:n])
+ copy(z[n:m], s[n:m])
return z.norm()
}
diff --git a/src/pkg/big/nat_test.go b/src/pkg/big/nat_test.go
index 8545981c0..0bcb94554 100755
--- a/src/pkg/big/nat_test.go
+++ b/src/pkg/big/nat_test.go
@@ -6,27 +6,24 @@ package big
import "testing"
-type cmpTest struct {
+var cmpTests = []struct {
x, y nat
r int
-}
-
-
-var cmpTests = []cmpTest{
- cmpTest{nil, nil, 0},
- cmpTest{nil, nat{}, 0},
- cmpTest{nat{}, nil, 0},
- cmpTest{nat{}, nat{}, 0},
- cmpTest{nat{0}, nat{0}, 0},
- cmpTest{nat{0}, nat{1}, -1},
- cmpTest{nat{1}, nat{0}, 1},
- cmpTest{nat{1}, nat{1}, 0},
- cmpTest{nat{0, _M}, nat{1}, 1},
- cmpTest{nat{1}, nat{0, _M}, -1},
- cmpTest{nat{1, _M}, nat{0, _M}, 1},
- cmpTest{nat{0, _M}, nat{1, _M}, -1},
- cmpTest{nat{16, 571956, 8794, 68}, nat{837, 9146, 1, 754489}, -1},
- cmpTest{nat{34986, 41, 105, 1957}, nat{56, 7458, 104, 1957}, 1},
+}{
+ {nil, nil, 0},
+ {nil, nat{}, 0},
+ {nat{}, nil, 0},
+ {nat{}, nat{}, 0},
+ {nat{0}, nat{0}, 0},
+ {nat{0}, nat{1}, -1},
+ {nat{1}, nat{0}, 1},
+ {nat{1}, nat{1}, 0},
+ {nat{0, _M}, nat{1}, 1},
+ {nat{1}, nat{0, _M}, -1},
+ {nat{1, _M}, nat{0, _M}, 1},
+ {nat{0, _M}, nat{1, _M}, -1},
+ {nat{16, 571956, 8794, 68}, nat{837, 9146, 1, 754489}, -1},
+ {nat{34986, 41, 105, 1957}, nat{56, 7458, 104, 1957}, 1},
}
@@ -47,24 +44,24 @@ type argNN struct {
var sumNN = []argNN{
- argNN{},
- argNN{nat{1}, nil, nat{1}},
- argNN{nat{1111111110}, nat{123456789}, nat{987654321}},
- argNN{nat{0, 0, 0, 1}, nil, nat{0, 0, 0, 1}},
- argNN{nat{0, 0, 0, 1111111110}, nat{0, 0, 0, 123456789}, nat{0, 0, 0, 987654321}},
- argNN{nat{0, 0, 0, 1}, nat{0, 0, _M}, nat{0, 0, 1}},
+ {},
+ {nat{1}, nil, nat{1}},
+ {nat{1111111110}, nat{123456789}, nat{987654321}},
+ {nat{0, 0, 0, 1}, nil, nat{0, 0, 0, 1}},
+ {nat{0, 0, 0, 1111111110}, nat{0, 0, 0, 123456789}, nat{0, 0, 0, 987654321}},
+ {nat{0, 0, 0, 1}, nat{0, 0, _M}, nat{0, 0, 1}},
}
var prodNN = []argNN{
- argNN{},
- argNN{nil, nil, nil},
- argNN{nil, nat{991}, nil},
- argNN{nat{991}, nat{991}, nat{1}},
- argNN{nat{991 * 991}, nat{991}, nat{991}},
- argNN{nat{0, 0, 991 * 991}, nat{0, 991}, nat{0, 991}},
- argNN{nat{1 * 991, 2 * 991, 3 * 991, 4 * 991}, nat{1, 2, 3, 4}, nat{991}},
- argNN{nat{4, 11, 20, 30, 20, 11, 4}, nat{1, 2, 3, 4}, nat{4, 3, 2, 1}},
+ {},
+ {nil, nil, nil},
+ {nil, nat{991}, nil},
+ {nat{991}, nat{991}, nat{1}},
+ {nat{991 * 991}, nat{991}, nat{991}},
+ {nat{0, 0, 991 * 991}, nat{0, 991}, nat{0, 991}},
+ {nat{1 * 991, 2 * 991, 3 * 991, 4 * 991}, nat{1, 2, 3, 4}, nat{991}},
+ {nat{4, 11, 20, 30, 20, 11, 4}, nat{1, 2, 3, 4}, nat{4, 3, 2, 1}},
}
@@ -111,25 +108,22 @@ func TestFunNN(t *testing.T) {
}
-type mulRangeN struct {
+var mulRangesN = []struct {
a, b uint64
prod string
-}
-
-
-var mulRangesN = []mulRangeN{
- mulRangeN{0, 0, "0"},
- mulRangeN{1, 1, "1"},
- mulRangeN{1, 2, "2"},
- mulRangeN{1, 3, "6"},
- mulRangeN{10, 10, "10"},
- mulRangeN{0, 100, "0"},
- mulRangeN{0, 1e9, "0"},
- mulRangeN{1, 0, "1"}, // empty range
- mulRangeN{100, 1, "1"}, // empty range
- mulRangeN{1, 10, "3628800"}, // 10!
- mulRangeN{1, 20, "2432902008176640000"}, // 20!
- mulRangeN{1, 100,
+}{
+ {0, 0, "0"},
+ {1, 1, "1"},
+ {1, 2, "2"},
+ {1, 3, "6"},
+ {10, 10, "10"},
+ {0, 100, "0"},
+ {0, 1e9, "0"},
+ {1, 0, "1"}, // empty range
+ {100, 1, "1"}, // empty range
+ {1, 10, "3628800"}, // 10!
+ {1, 20, "2432902008176640000"}, // 20!
+ {1, 100,
"933262154439441526816992388562667004907159682643816214685929" +
"638952175999932299156089414639761565182862536979208272237582" +
"51185210916864000000000000000000000000", // 100!
@@ -173,18 +167,15 @@ func BenchmarkMul(b *testing.B) {
}
-type str struct {
+var tab = []struct {
x nat
b int
s string
-}
-
-
-var tab = []str{
- str{nil, 10, "0"},
- str{nat{1}, 10, "1"},
- str{nat{10}, 10, "10"},
- str{nat{1234567890}, 10, "1234567890"},
+}{
+ {nil, 10, "0"},
+ {nat{1}, 10, "1"},
+ {nat{10}, 10, "10"},
+ {nat{1234567890}, 10, "1234567890"},
}
@@ -228,12 +219,12 @@ type shiftTest struct {
var leftShiftTests = []shiftTest{
- shiftTest{nil, 0, nil},
- shiftTest{nil, 1, nil},
- shiftTest{natOne, 0, natOne},
- shiftTest{natOne, 1, natTwo},
- shiftTest{nat{1 << (_W - 1)}, 1, nat{0}},
- shiftTest{nat{1 << (_W - 1), 0}, 1, nat{0, 1}},
+ {nil, 0, nil},
+ {nil, 1, nil},
+ {natOne, 0, natOne},
+ {natOne, 1, natTwo},
+ {nat{1 << (_W - 1)}, 1, nat{0}},
+ {nat{1 << (_W - 1), 0}, 1, nat{0, 1}},
}
@@ -252,13 +243,13 @@ func TestShiftLeft(t *testing.T) {
var rightShiftTests = []shiftTest{
- shiftTest{nil, 0, nil},
- shiftTest{nil, 1, nil},
- shiftTest{natOne, 0, natOne},
- shiftTest{natOne, 1, nil},
- shiftTest{natTwo, 1, natOne},
- shiftTest{nat{0, 1}, 1, nat{1 << (_W - 1)}},
- shiftTest{nat{2, 1, 1}, 1, nat{1<<(_W-1) + 1, 1 << (_W - 1)}},
+ {nil, 0, nil},
+ {nil, 1, nil},
+ {natOne, 0, natOne},
+ {natOne, 1, nil},
+ {natTwo, 1, natOne},
+ {nat{0, 1}, 1, nat{1 << (_W - 1)}},
+ {nat{2, 1, 1}, 1, nat{1<<(_W-1) + 1, 1 << (_W - 1)}},
}
@@ -284,12 +275,12 @@ type modWTest struct {
var modWTests32 = []modWTest{
- modWTest{"23492635982634928349238759823742", "252341", "220170"},
+ {"23492635982634928349238759823742", "252341", "220170"},
}
var modWTests64 = []modWTest{
- modWTest{"6527895462947293856291561095690465243862946", "524326975699234", "375066989628668"},
+ {"6527895462947293856291561095690465243862946", "524326975699234", "375066989628668"},
}
@@ -301,7 +292,7 @@ func runModWTests(t *testing.T, tests []modWTest) {
r := in.abs.modW(d.abs[0])
if r != out.abs[0] {
- t.Errorf("#%d failed: got %s want %s\n", i, r, out)
+ t.Errorf("#%d failed: got %s want %s", i, r, out)
}
}
}
@@ -322,26 +313,23 @@ func TestTrailingZeroBits(t *testing.T) {
x--
for i := 0; i < _W; i++ {
if trailingZeroBits(x) != i {
- t.Errorf("Failed at step %d: x: %x got: %d\n", i, x, trailingZeroBits(x))
+ t.Errorf("Failed at step %d: x: %x got: %d", i, x, trailingZeroBits(x))
}
x <<= 1
}
}
-type expNNTest struct {
+var expNNTests = []struct {
x, y, m string
out string
-}
-
-
-var expNNTests = []expNNTest{
- expNNTest{"0x8000000000000000", "2", "", "0x40000000000000000000000000000000"},
- expNNTest{"0x8000000000000000", "2", "6719", "4944"},
- expNNTest{"0x8000000000000000", "3", "6719", "5447"},
- expNNTest{"0x8000000000000000", "1000", "6719", "1603"},
- expNNTest{"0x8000000000000000", "1000000", "6719", "3199"},
- expNNTest{
+}{
+ {"0x8000000000000000", "2", "", "0x40000000000000000000000000000000"},
+ {"0x8000000000000000", "2", "6719", "4944"},
+ {"0x8000000000000000", "3", "6719", "5447"},
+ {"0x8000000000000000", "1000", "6719", "1603"},
+ {"0x8000000000000000", "1000000", "6719", "3199"},
+ {
"2938462938472983472983659726349017249287491026512746239764525612965293865296239471239874193284792387498274256129746192347",
"298472983472983471903246121093472394872319615612417471234712061",
"29834729834729834729347290846729561262544958723956495615629569234729836259263598127342374289365912465901365498236492183464",
diff --git a/src/pkg/big/rat.go b/src/pkg/big/rat.go
index ddd858d5c..e70673a1c 100644
--- a/src/pkg/big/rat.go
+++ b/src/pkg/big/rat.go
@@ -35,9 +35,8 @@ func (z *Rat) SetFrac(a, b *Int) *Rat {
func (z *Rat) SetFrac64(a, b int64) *Rat {
z.a.SetInt64(a)
if b < 0 {
- z.b.setUint64(uint64(-b))
+ b = -b
z.a.neg = !z.a.neg
- return z.norm()
}
z.b = z.b.setUint64(uint64(b))
return z.norm()
@@ -60,6 +59,23 @@ func (z *Rat) SetInt64(x int64) *Rat {
}
+// Sign returns:
+//
+// -1 if x < 0
+// 0 if x == 0
+// +1 if x > 0
+//
+func (x *Rat) Sign() int {
+ return x.a.Sign()
+}
+
+
+// IsInt returns true if the denominator of x is 1.
+func (x *Rat) IsInt() bool {
+ return len(x.b) == 1 && x.b[0] == 1
+}
+
+
// Num returns the numerator of z; it may be <= 0.
// The result is a reference to z's numerator; it
// may change if a new value is assigned to z.
@@ -126,6 +142,14 @@ func (x *Rat) Cmp(y *Rat) (r int) {
}
+// Abs sets z to |x| (the absolute value of x) and returns z.
+func (z *Rat) Abs(x *Rat) *Rat {
+ z.a.Abs(&x.a)
+ z.b = z.b.set(x.b)
+ return z
+}
+
+
// Add sets z to the sum x+y and returns z.
func (z *Rat) Add(x, y *Rat) *Rat {
a1 := mulNat(&x.a, y.b)
@@ -186,26 +210,17 @@ func (z *Rat) Set(x *Rat) *Rat {
// 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 decimal number "a.b".
-// If the operation failed, the value of z is undefined.
+// success. s can be given as a fraction "a/b" or as a floating-point number
+// optionally followed by an exponent. If the operation failed, the value of z
+// is undefined.
func (z *Rat) SetString(s string) (*Rat, bool) {
if len(s) == 0 {
return z, false
}
- // Check for a decimal point
- sep := strings.Index(s, ".")
- if sep < 0 {
- // Check for a quotient
- sep = strings.Index(s, "/")
- if sep < 0 {
- // Just read in the string as an integer
- if _, ok := z.a.SetString(s, 10); !ok {
- return z, false
- }
- z.b = z.b.setWord(1)
- return z, true
- }
+ // check for a quotient
+ sep := strings.Index(s, "/")
+ if sep >= 0 {
if _, ok := z.a.SetString(s[0:sep], 10); !ok {
return z, false
}
@@ -214,59 +229,98 @@ func (z *Rat) SetString(s string) (*Rat, bool) {
if z.b, _, n = z.b.scan(s, 10); n != len(s) {
return z, false
}
-
return z.norm(), true
}
- s = s[0:sep] + s[sep+1:]
+ // check for a decimal point
+ sep = strings.Index(s, ".")
+ // check for an exponent
+ e := strings.IndexAny(s, "eE")
+ var exp Int
+ if e >= 0 {
+ if e < sep {
+ // The E must come after the decimal point.
+ return z, false
+ }
+ if _, ok := exp.SetString(s[e+1:], 10); !ok {
+ return z, false
+ }
+ s = s[0:e]
+ }
+ if sep >= 0 {
+ s = s[0:sep] + s[sep+1:]
+ exp.Sub(&exp, NewInt(int64(len(s)-sep)))
+ }
+
if _, ok := z.a.SetString(s, 10); !ok {
return z, false
}
- z.b = z.b.expNN(natTen, nat{Word(len(s) - sep)}, nil)
+ powTen := nat{}.expNN(natTen, exp.abs, nil)
+ if exp.neg {
+ z.b = powTen
+ z.norm()
+ } else {
+ z.a.abs = z.a.abs.mul(z.a.abs, powTen)
+ z.b = z.b.setWord(1)
+ }
- return z.norm(), true
+ return z, true
}
-// String returns a string representation of z in the form "a/b".
+// String returns a string representation of z in the form "a/b" (even if b == 1).
func (z *Rat) String() string {
- s := z.a.String()
- if len(z.b) == 1 && z.b[0] == 1 {
- return s
+ return z.a.String() + "/" + z.b.string(10)
+}
+
+
+// RatString returns a string representation of z in the form "a/b" if b != 1,
+// and in the form "a" if b == 1.
+func (z *Rat) RatString() string {
+ if z.IsInt() {
+ return z.a.String()
}
- return s + "/" + z.b.string(10)
+ return z.String()
}
// FloatString returns a string representation of z in decimal form with prec
// digits of precision after the decimal point and the last digit rounded.
func (z *Rat) FloatString(prec int) string {
- q, r := nat{}.div(nat{}, z.a.abs, z.b)
-
- s := ""
- if z.a.neg {
- s = "-"
+ if z.IsInt() {
+ return z.a.String()
}
- s += q.string(10)
- if len(z.b) == 1 && z.b[0] == 1 {
- return s
+ q, r := nat{}.div(nat{}, z.a.abs, z.b)
+
+ p := natOne
+ if prec > 0 {
+ p = nat{}.expNN(natTen, nat{}.setUint64(uint64(prec)), nil)
}
- p := nat{}.expNN(natTen, nat{Word(prec)}, nil)
r = r.mul(r, p)
r, r2 := r.div(nat{}, r, z.b)
- // See if we need to round up
- r2 = r2.mul(r2, natTwo)
+ // see if we need to round up
+ r2 = r2.add(r2, r2)
if z.b.cmp(r2) <= 0 {
r = r.add(r, natOne)
+ if r.cmp(p) >= 0 {
+ q = nat{}.add(q, natOne)
+ r = nat{}.sub(r, p)
+ }
}
- rs := r.string(10)
- leadingZeros := prec - len(rs)
- s += "." + strings.Repeat("0", leadingZeros) + rs
- s = strings.TrimRight(s, "0")
+ s := q.string(10)
+ if z.a.neg {
+ s = "-" + s
+ }
+
+ if prec > 0 {
+ rs := r.string(10)
+ leadingZeros := prec - len(rs)
+ s += "." + strings.Repeat("0", leadingZeros) + rs
+ }
return s
}
diff --git a/src/pkg/big/rat_test.go b/src/pkg/big/rat_test.go
index 2379cc0d5..8f42949b0 100644
--- a/src/pkg/big/rat_test.go
+++ b/src/pkg/big/rat_test.go
@@ -7,57 +7,71 @@ package big
import "testing"
-type setStringTest struct {
+var setStringTests = []struct {
in, out string
ok bool
-}
-
-var setStringTests = []setStringTest{
- setStringTest{"0", "0", true},
- setStringTest{"-0", "0", true},
- setStringTest{"1", "1", true},
- setStringTest{"-1", "-1", true},
- setStringTest{in: "r", ok: false},
- setStringTest{in: "a/b", ok: false},
- setStringTest{in: "a.b", ok: false},
- setStringTest{"-0.1", "-1/10", true},
- setStringTest{"-.1", "-1/10", true},
- setStringTest{"2/4", "1/2", true},
- setStringTest{".25", "1/4", true},
- setStringTest{"-1/5", "-1/5", true},
- setStringTest{"884243222337379604041632732738665534", "884243222337379604041632732738665534", true},
- setStringTest{"53/70893980658822810696", "53/70893980658822810696", true},
- setStringTest{"106/141787961317645621392", "53/70893980658822810696", true},
- setStringTest{"204211327800791583.81095", "4084226556015831676219/20000", true},
+}{
+ {"0", "0", true},
+ {"-0", "0", true},
+ {"1", "1", true},
+ {"-1", "-1", true},
+ {"1.", "1", true},
+ {"1e0", "1", true},
+ {"1.e1", "10", true},
+ {in: "1e", ok: false},
+ {in: "1.e", ok: false},
+ {in: "1e+14e-5", ok: false},
+ {in: "1e4.5", ok: false},
+ {in: "r", ok: false},
+ {in: "a/b", ok: false},
+ {in: "a.b", ok: false},
+ {"-0.1", "-1/10", true},
+ {"-.1", "-1/10", true},
+ {"2/4", "1/2", true},
+ {".25", "1/4", true},
+ {"-1/5", "-1/5", true},
+ {"8129567.7690E14", "812956776900000000000", true},
+ {"78189e+4", "781890000", true},
+ {"553019.8935e+8", "55301989350000", true},
+ {"98765432109876543210987654321e-10", "98765432109876543210987654321/10000000000", true},
+ {"9877861857500000E-7", "3951144743/4", true},
+ {"2169378.417e-3", "2169378417/1000000", true},
+ {"884243222337379604041632732738665534", "884243222337379604041632732738665534", true},
+ {"53/70893980658822810696", "53/70893980658822810696", true},
+ {"106/141787961317645621392", "53/70893980658822810696", true},
+ {"204211327800791583.81095", "4084226556015831676219/20000", true},
}
func TestRatSetString(t *testing.T) {
for i, test := range setStringTests {
x, ok := new(Rat).SetString(test.in)
- if ok != test.ok || ok && x.String() != test.out {
- t.Errorf("#%d got %s want %s", i, x.String(), test.out)
+ if ok != test.ok || ok && x.RatString() != test.out {
+ t.Errorf("#%d got %s want %s", i, x.RatString(), test.out)
}
}
}
-type floatStringTest struct {
+var floatStringTests = []struct {
in string
prec int
out string
-}
-
-var floatStringTests = []floatStringTest{
- floatStringTest{"0", 0, "0"},
- floatStringTest{"0", 4, "0"},
- floatStringTest{"1", 0, "1"},
- floatStringTest{"1", 2, "1"},
- floatStringTest{"-1", 0, "-1"},
- floatStringTest{".25", 2, "0.25"},
- floatStringTest{".25", 1, "0.3"},
- floatStringTest{"-1/3", 3, "-0.333"},
- floatStringTest{"-2/3", 4, "-0.6667"},
+}{
+ {"0", 0, "0"},
+ {"0", 4, "0"},
+ {"1", 0, "1"},
+ {"1", 2, "1"},
+ {"-1", 0, "-1"},
+ {".25", 2, "0.25"},
+ {".25", 1, "0.3"},
+ {"-1/3", 3, "-0.333"},
+ {"-2/3", 4, "-0.6667"},
+ {"0.96", 1, "1.0"},
+ {"0.999", 2, "1.00"},
+ {"0.9", 0, "1"},
+ {".25", -1, "0"},
+ {".55", -1, "1"},
}
func TestFloatString(t *testing.T) {
@@ -71,21 +85,33 @@ func TestFloatString(t *testing.T) {
}
-type ratCmpTest struct {
- rat1, rat2 string
- out int
+func TestRatSign(t *testing.T) {
+ zero := NewRat(0, 1)
+ for _, a := range setStringTests {
+ var x Rat
+ x.SetString(a.in)
+ s := x.Sign()
+ e := x.Cmp(zero)
+ if s != e {
+ t.Errorf("got %d; want %d for z = %v", s, e, &x)
+ }
+ }
}
-var ratCmpTests = []ratCmpTest{
- ratCmpTest{"0", "0/1", 0},
- ratCmpTest{"1/1", "1", 0},
- ratCmpTest{"-1", "-2/2", 0},
- ratCmpTest{"1", "0", 1},
- ratCmpTest{"0/1", "1/1", -1},
- ratCmpTest{"-5/1434770811533343057144", "-5/1434770811533343057145", -1},
- ratCmpTest{"49832350382626108453/8964749413", "49832350382626108454/8964749413", -1},
- ratCmpTest{"-37414950961700930/7204075375675961", "37414950961700930/7204075375675961", -1},
- ratCmpTest{"37414950961700930/7204075375675961", "74829901923401860/14408150751351922", 0},
+
+var ratCmpTests = []struct {
+ rat1, rat2 string
+ out int
+}{
+ {"0", "0/1", 0},
+ {"1/1", "1", 0},
+ {"-1", "-2/2", 0},
+ {"1", "0", 1},
+ {"0/1", "1/1", -1},
+ {"-5/1434770811533343057144", "-5/1434770811533343057145", -1},
+ {"49832350382626108453/8964749413", "49832350382626108454/8964749413", -1},
+ {"-37414950961700930/7204075375675961", "37414950961700930/7204075375675961", -1},
+ {"37414950961700930/7204075375675961", "74829901923401860/14408150751351922", 0},
}
func TestRatCmp(t *testing.T) {
@@ -101,6 +127,38 @@ func TestRatCmp(t *testing.T) {
}
+func TestIsInt(t *testing.T) {
+ one := NewInt(1)
+ for _, a := range setStringTests {
+ var x Rat
+ x.SetString(a.in)
+ i := x.IsInt()
+ e := x.Denom().Cmp(one) == 0
+ if i != e {
+ t.Errorf("got %v; want %v for z = %v", i, e, &x)
+ }
+ }
+}
+
+
+func TestRatAbs(t *testing.T) {
+ zero := NewRat(0, 1)
+ for _, a := range setStringTests {
+ var z Rat
+ z.SetString(a.in)
+ var e Rat
+ e.Set(&z)
+ if e.Cmp(zero) < 0 {
+ e.Sub(zero, &e)
+ }
+ z.Abs(&z)
+ if z.Cmp(&e) != 0 {
+ t.Errorf("got z = %v; want %v", &z, &e)
+ }
+ }
+}
+
+
type ratBinFun func(z, x, y *Rat) *Rat
type ratBinArg struct {
x, y, z string
@@ -118,30 +176,28 @@ func testRatBin(t *testing.T, i int, name string, f ratBinFun, a ratBinArg) {
}
-type ratBinTest struct {
+var ratBinTests = []struct {
x, y string
sum, prod string
-}
-
-var ratBinTests = []ratBinTest{
- ratBinTest{"0", "0", "0", "0"},
- ratBinTest{"0", "1", "1", "0"},
- ratBinTest{"-1", "0", "-1", "0"},
- ratBinTest{"-1", "1", "0", "-1"},
- ratBinTest{"1", "1", "2", "1"},
- ratBinTest{"1/2", "1/2", "1", "1/4"},
- ratBinTest{"1/4", "1/3", "7/12", "1/12"},
- ratBinTest{"2/5", "-14/3", "-64/15", "-28/15"},
- ratBinTest{"4707/49292519774798173060", "-3367/70976135186689855734", "84058377121001851123459/1749296273614329067191168098769082663020", "-1760941/388732505247628681598037355282018369560"},
- ratBinTest{"-61204110018146728334/3", "-31052192278051565633/2", "-215564796870448153567/6", "950260896245257153059642991192710872711/3"},
- ratBinTest{"-854857841473707320655/4237645934602118692642972629634714039", "-18/31750379913563777419", "-27/133467566250814981", "15387441146526731771790/134546868362786310073779084329032722548987800600710485341"},
- ratBinTest{"618575745270541348005638912139/19198433543745179392300736", "-19948846211000086/637313996471", "27674141753240653/30123979153216", "-6169936206128396568797607742807090270137721977/6117715203873571641674006593837351328"},
- ratBinTest{"-3/26206484091896184128", "5/2848423294177090248", "15310893822118706237/9330894968229805033368778458685147968", "-5/24882386581946146755650075889827061248"},
- ratBinTest{"26946729/330400702820", "41563965/225583428284", "1238218672302860271/4658307703098666660055", "224002580204097/14906584649915733312176"},
- ratBinTest{"-8259900599013409474/7", "-84829337473700364773/56707961321161574960", "-468402123685491748914621885145127724451/396955729248131024720", "350340947706464153265156004876107029701/198477864624065512360"},
- ratBinTest{"575775209696864/1320203974639986246357", "29/712593081308", "410331716733912717985762465/940768218243776489278275419794956", "808/45524274987585732633"},
- ratBinTest{"1786597389946320496771/2066653520653241", "6269770/1992362624741777", "3559549865190272133656109052308126637/4117523232840525481453983149257", "8967230/3296219033"},
- ratBinTest{"-36459180403360509753/32150500941194292113930", "9381566963714/9633539", "301622077145533298008420642898530153/309723104686531919656937098270", "-3784609207827/3426986245"},
+}{
+ {"0", "0", "0", "0"},
+ {"0", "1", "1", "0"},
+ {"-1", "0", "-1", "0"},
+ {"-1", "1", "0", "-1"},
+ {"1", "1", "2", "1"},
+ {"1/2", "1/2", "1", "1/4"},
+ {"1/4", "1/3", "7/12", "1/12"},
+ {"2/5", "-14/3", "-64/15", "-28/15"},
+ {"4707/49292519774798173060", "-3367/70976135186689855734", "84058377121001851123459/1749296273614329067191168098769082663020", "-1760941/388732505247628681598037355282018369560"},
+ {"-61204110018146728334/3", "-31052192278051565633/2", "-215564796870448153567/6", "950260896245257153059642991192710872711/3"},
+ {"-854857841473707320655/4237645934602118692642972629634714039", "-18/31750379913563777419", "-27/133467566250814981", "15387441146526731771790/134546868362786310073779084329032722548987800600710485341"},
+ {"618575745270541348005638912139/19198433543745179392300736", "-19948846211000086/637313996471", "27674141753240653/30123979153216", "-6169936206128396568797607742807090270137721977/6117715203873571641674006593837351328"},
+ {"-3/26206484091896184128", "5/2848423294177090248", "15310893822118706237/9330894968229805033368778458685147968", "-5/24882386581946146755650075889827061248"},
+ {"26946729/330400702820", "41563965/225583428284", "1238218672302860271/4658307703098666660055", "224002580204097/14906584649915733312176"},
+ {"-8259900599013409474/7", "-84829337473700364773/56707961321161574960", "-468402123685491748914621885145127724451/396955729248131024720", "350340947706464153265156004876107029701/198477864624065512360"},
+ {"575775209696864/1320203974639986246357", "29/712593081308", "410331716733912717985762465/940768218243776489278275419794956", "808/45524274987585732633"},
+ {"1786597389946320496771/2066653520653241", "6269770/1992362624741777", "3559549865190272133656109052308126637/4117523232840525481453983149257", "8967230/3296219033"},
+ {"-36459180403360509753/32150500941194292113930", "9381566963714/9633539", "301622077145533298008420642898530153/309723104686531919656937098270", "-3784609207827/3426986245"},
}
func TestRatBin(t *testing.T) {
@@ -201,3 +257,26 @@ func TestIssue820(t *testing.T) {
t.Errorf("got %s want %s", z, q)
}
}
+
+
+var setFrac64Tests = []struct {
+ a, b int64
+ out string
+}{
+ {0, 1, "0"},
+ {0, -1, "0"},
+ {1, 1, "1"},
+ {-1, 1, "-1"},
+ {1, -1, "-1"},
+ {-1, -1, "1"},
+ {-9223372036854775808, -9223372036854775808, "1"},
+}
+
+func TestRatSetFrac64Rat(t *testing.T) {
+ for i, test := range setFrac64Tests {
+ x := new(Rat).SetFrac64(test.a, test.b)
+ if x.RatString() != test.out {
+ t.Errorf("#%d got %s want %s", i, x.RatString(), test.out)
+ }
+ }
+}
diff --git a/src/pkg/bufio/Makefile b/src/pkg/bufio/Makefile
index 1f5fc349b..85430e8e8 100644
--- a/src/pkg/bufio/Makefile
+++ b/src/pkg/bufio/Makefile
@@ -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 ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=bufio
GOFILES=\
diff --git a/src/pkg/bufio/bufio.go b/src/pkg/bufio/bufio.go
index 6a73c41ef..c13456a63 100644
--- a/src/pkg/bufio/bufio.go
+++ b/src/pkg/bufio/bufio.go
@@ -27,7 +27,9 @@ type Error struct {
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"}
)
@@ -43,11 +45,12 @@ func (b BufSizeError) String() string {
// Reader implements buffering for an io.Reader object.
type Reader struct {
- buf []byte
- rd io.Reader
- r, w int
- err os.Error
- lastbyte int
+ buf []byte
+ rd io.Reader
+ r, w int
+ err os.Error
+ lastByte int
+ lastRuneSize int
}
// NewReaderSize creates a new Reader whose buffer has the specified size,
@@ -66,7 +69,8 @@ func NewReaderSize(rd io.Reader, size int) (*Reader, os.Error) {
b = new(Reader)
b.buf = make([]byte, size)
b.rd = rd
- b.lastbyte = -1
+ b.lastByte = -1
+ b.lastRuneSize = -1
return b, nil
}
@@ -83,13 +87,11 @@ func NewReader(rd io.Reader) *Reader {
// fill reads a new chunk into the buffer.
func (b *Reader) fill() {
// Slide existing data to beginning.
- if b.w > b.r {
- copy(b.buf[0:b.w-b.r], b.buf[b.r:b.w])
+ if b.r > 0 {
+ copy(b.buf, b.buf[b.r:b.w])
b.w -= b.r
- } else {
- b.w = 0
+ b.r = 0
}
- b.r = 0
// Read new data.
n, e := b.rd.Read(b.buf[b.w:])
@@ -99,48 +101,75 @@ func (b *Reader) fill() {
}
}
+// Peek returns the next n bytes without advancing the reader. The bytes stop
+// being valid at the next read call. If Peek returns fewer than n bytes, it
+// also returns an error explaining why the read is short. The error is
+// ErrBufferFull if n is larger than b's buffer size.
+func (b *Reader) Peek(n int) ([]byte, os.Error) {
+ if n < 0 {
+ return nil, ErrNegativeCount
+ }
+ if n > len(b.buf) {
+ return nil, ErrBufferFull
+ }
+ for b.w-b.r < n && b.err == nil {
+ b.fill()
+ }
+ m := b.w - b.r
+ if m > n {
+ m = n
+ }
+ err := b.err
+ if m < n && err == nil {
+ err = ErrBufferFull
+ }
+ return b.buf[b.r : b.r+m], err
+}
+
// Read reads data into p.
// It returns the number of bytes read into p.
-// If nn < len(p), also returns an error explaining
-// why the read is short. At EOF, the count will be
-// zero and err will be os.EOF.
-func (b *Reader) Read(p []byte) (nn int, err os.Error) {
- nn = 0
- for len(p) > 0 {
- n := len(p)
- if b.w == b.r {
- if b.err != nil {
- return nn, b.err
- }
- if len(p) >= len(b.buf) {
- // Large read, empty buffer.
- // Read directly into p to avoid copy.
- n, b.err = b.rd.Read(p)
- if n > 0 {
- b.lastbyte = int(p[n-1])
- }
- p = p[n:]
- nn += n
- continue
+// It calls Read at most once on the underlying Reader,
+// hence n may be less than len(p).
+// At EOF, the count will be zero and err will be os.EOF.
+func (b *Reader) Read(p []byte) (n int, err os.Error) {
+ n = len(p)
+ if n == 0 {
+ return 0, b.err
+ }
+ if b.w == b.r {
+ if b.err != nil {
+ return 0, b.err
+ }
+ if len(p) >= len(b.buf) {
+ // Large read, empty buffer.
+ // Read directly into p to avoid copy.
+ n, b.err = b.rd.Read(p)
+ if n > 0 {
+ b.lastByte = int(p[n-1])
+ b.lastRuneSize = -1
}
- b.fill()
- continue
+ return n, b.err
}
- if n > b.w-b.r {
- n = b.w - b.r
+ b.fill()
+ if b.w == b.r {
+ return 0, b.err
}
- copy(p[0:n], b.buf[b.r:b.r+n])
- p = p[n:]
- b.r += n
- b.lastbyte = int(b.buf[b.r-1])
- nn += n
}
- return nn, nil
+
+ if n > b.w-b.r {
+ n = b.w - b.r
+ }
+ copy(p[0:n], b.buf[b.r:])
+ b.r += n
+ b.lastByte = int(b.buf[b.r-1])
+ b.lastRuneSize = -1
+ return n, nil
}
// ReadByte reads and returns a single byte.
// If no byte is available, returns an error.
func (b *Reader) ReadByte() (c byte, err os.Error) {
+ b.lastRuneSize = -1
for b.w == b.r {
if b.err != nil {
return 0, b.err
@@ -149,24 +178,25 @@ func (b *Reader) ReadByte() (c byte, err os.Error) {
}
c = b.buf[b.r]
b.r++
- b.lastbyte = int(c)
+ b.lastByte = int(c)
return c, nil
}
// UnreadByte unreads the last byte. Only the most recently read byte can be unread.
func (b *Reader) UnreadByte() os.Error {
- if b.r == b.w && b.lastbyte >= 0 {
+ b.lastRuneSize = -1
+ if b.r == b.w && b.lastByte >= 0 {
b.w = 1
b.r = 0
- b.buf[0] = byte(b.lastbyte)
- b.lastbyte = -1
+ b.buf[0] = byte(b.lastByte)
+ b.lastByte = -1
return nil
}
if b.r <= 0 {
return ErrInvalidUnreadByte
}
b.r--
- b.lastbyte = -1
+ b.lastByte = -1
return nil
}
@@ -176,6 +206,7 @@ func (b *Reader) ReadRune() (rune int, size int, err os.Error) {
for b.r+utf8.UTFMax > b.w && !utf8.FullRune(b.buf[b.r:b.w]) && b.err == nil {
b.fill()
}
+ b.lastRuneSize = -1
if b.r == b.w {
return 0, 0, b.err
}
@@ -184,10 +215,25 @@ func (b *Reader) ReadRune() (rune int, size int, err os.Error) {
rune, size = utf8.DecodeRune(b.buf[b.r:b.w])
}
b.r += size
- b.lastbyte = int(b.buf[b.r-1])
+ b.lastByte = int(b.buf[b.r-1])
+ b.lastRuneSize = size
return rune, size, nil
}
+// UnreadRune unreads the last rune. If the most recent read operation on
+// the buffer was not a ReadRune, UnreadRune returns an error. (In this
+// regard it is stricter than UnreadByte, which will unread the last byte
+// from any read operation.)
+func (b *Reader) UnreadRune() os.Error {
+ if b.lastRuneSize < 0 || b.r == 0 {
+ return ErrInvalidUnreadRune
+ }
+ b.r -= b.lastRuneSize
+ b.lastByte = -1
+ b.lastRuneSize = -1
+ return nil
+}
+
// Buffered returns the number of bytes that can be read from the current buffer.
func (b *Reader) Buffered() int { return b.w - b.r }
@@ -237,7 +283,7 @@ func (b *Reader) ReadSlice(delim byte) (line []byte, err os.Error) {
}
// ReadBytes reads until the first occurrence of delim in the input,
-// returning a string containing the data up to and including the delimiter.
+// returning a slice containing the data up to and including the delimiter.
// If ReadBytes encounters an error before finding a delimiter,
// it returns the data read before the error and the error itself (often os.EOF).
// ReadBytes returns err != nil if and only if line does not end in delim.
@@ -246,7 +292,6 @@ func (b *Reader) ReadBytes(delim byte) (line []byte, err os.Error) {
// accumulating full buffers.
var frag []byte
var full [][]byte
- nfull := 0
err = nil
for {
@@ -263,26 +308,12 @@ func (b *Reader) ReadBytes(delim byte) (line []byte, err os.Error) {
// Make a copy of the buffer.
buf := make([]byte, len(frag))
copy(buf, frag)
-
- // Grow list if needed.
- if full == nil {
- full = make([][]byte, 16)
- } else if nfull >= len(full) {
- newfull := make([][]byte, len(full)*2)
- for i := 0; i < len(full); i++ {
- newfull[i] = full[i]
- }
- full = newfull
- }
-
- // Save buffer
- full[nfull] = buf
- nfull++
+ full = append(full, buf)
}
// Allocate new buffer to hold the full pieces and the fragment.
n := 0
- for i := 0; i < nfull; i++ {
+ for i := range full {
n += len(full[i])
}
n += len(frag)
@@ -290,11 +321,10 @@ func (b *Reader) ReadBytes(delim byte) (line []byte, err os.Error) {
// Copy full pieces and fragment in.
buf := make([]byte, n)
n = 0
- for i := 0; i < nfull; i++ {
- copy(buf[n:n+len(full[i])], full[i])
- n += len(full[i])
+ for i := range full {
+ n += copy(buf[n:], full[i])
}
- copy(buf[n:n+len(frag)], frag)
+ copy(buf[n:], frag)
return buf, err
}
@@ -392,7 +422,7 @@ func (b *Writer) Write(p []byte) (nn int, err os.Error) {
}
n = b.Available()
}
- if b.Available() == 0 && len(p) >= len(b.buf) {
+ if b.Buffered() == 0 && len(p) >= len(b.buf) {
// Large write, empty buffer.
// Write directly from p to avoid copy.
n, b.err = b.wr.Write(p)
@@ -451,7 +481,7 @@ func (b *Writer) WriteRune(rune int) (size int, err os.Error) {
return b.WriteString(string(rune))
}
}
- size = utf8.EncodeRune(rune, b.buf[b.n:])
+ size = utf8.EncodeRune(b.buf[b.n:], rune)
b.n += size
return size, nil
}
diff --git a/src/pkg/bufio/bufio_test.go b/src/pkg/bufio/bufio_test.go
index 2279fe3b1..059ca6dd2 100644
--- a/src/pkg/bufio/bufio_test.go
+++ b/src/pkg/bufio/bufio_test.go
@@ -69,7 +69,7 @@ func TestReaderSimple(t *testing.T) {
b = NewReader(newRot13Reader(bytes.NewBufferString(data)))
if s := readBytes(b); s != "uryyb jbeyq" {
- t.Error("rot13 hello world test failed: got %q", s)
+ t.Errorf("rot13 hello world test failed: got %q", s)
}
}
@@ -80,10 +80,10 @@ type readMaker struct {
}
var readMakers = []readMaker{
- readMaker{"full", func(r io.Reader) io.Reader { return r }},
- readMaker{"byte", iotest.OneByteReader},
- readMaker{"half", iotest.HalfReader},
- readMaker{"data+err", iotest.DataErrReader},
+ {"full", func(r io.Reader) io.Reader { return r }},
+ {"byte", iotest.OneByteReader},
+ {"half", iotest.HalfReader},
+ {"data+err", iotest.DataErrReader},
}
// Call ReadString (which ends up calling everything else)
@@ -123,14 +123,14 @@ type bufReader struct {
}
var bufreaders = []bufReader{
- bufReader{"1", func(b *Reader) string { return reads(b, 1) }},
- bufReader{"2", func(b *Reader) string { return reads(b, 2) }},
- bufReader{"3", func(b *Reader) string { return reads(b, 3) }},
- bufReader{"4", func(b *Reader) string { return reads(b, 4) }},
- bufReader{"5", func(b *Reader) string { return reads(b, 5) }},
- bufReader{"7", func(b *Reader) string { return reads(b, 7) }},
- bufReader{"bytes", readBytes},
- bufReader{"lines", readLines},
+ {"1", func(b *Reader) string { return reads(b, 1) }},
+ {"2", func(b *Reader) string { return reads(b, 2) }},
+ {"3", func(b *Reader) string { return reads(b, 3) }},
+ {"4", func(b *Reader) string { return reads(b, 4) }},
+ {"5", func(b *Reader) string { return reads(b, 5) }},
+ {"7", func(b *Reader) string { return reads(b, 7) }},
+ {"bytes", readBytes},
+ {"lines", readLines},
}
var bufsizes = []int{
@@ -179,10 +179,7 @@ type StringReader struct {
func (r *StringReader) Read(p []byte) (n int, err os.Error) {
if r.step < len(r.data) {
s := r.data[r.step]
- for i := 0; i < len(s); i++ {
- p[i] = s[i]
- }
- n = len(s)
+ n = copy(p, s)
r.step++
} else {
err = os.EOF
@@ -210,14 +207,14 @@ func readRuneSegments(t *testing.T, segments []string) {
}
var segmentList = [][]string{
- []string{},
- []string{""},
- []string{"日", "本語"},
- []string{"\u65e5", "\u672c", "\u8a9e"},
- []string{"\U000065e5", "\U0000672c", "\U00008a9e"},
- []string{"\xe6", "\x97\xa5\xe6", "\x9c\xac\xe8\xaa\x9e"},
- []string{"Hello", ", ", "World", "!"},
- []string{"Hello", ", ", "", "World", "!"},
+ {},
+ {""},
+ {"日", "本語"},
+ {"\u65e5", "\u672c", "\u8a9e"},
+ {"\U000065e5", "\U0000672c", "\U00008a9e"},
+ {"\xe6", "\x97\xa5\xe6", "\x9c\xac\xe8\xaa\x9e"},
+ {"Hello", ", ", "World", "!"},
+ {"Hello", ", ", "", "World", "!"},
}
func TestReadRune(t *testing.T) {
@@ -226,6 +223,113 @@ func TestReadRune(t *testing.T) {
}
}
+func TestUnreadRune(t *testing.T) {
+ got := ""
+ segments := []string{"Hello, world:", "日本語"}
+ data := strings.Join(segments, "")
+ r := NewReader(&StringReader{data: segments})
+ // Normal execution.
+ for {
+ rune, _, err := r.ReadRune()
+ if err != nil {
+ if err != os.EOF {
+ t.Error("unexpected EOF")
+ }
+ break
+ }
+ got += string(rune)
+ // Put it back and read it again
+ if err = r.UnreadRune(); err != nil {
+ t.Error("unexpected error on UnreadRune:", err)
+ }
+ rune1, _, err := r.ReadRune()
+ if err != nil {
+ t.Error("unexpected error reading after unreading:", err)
+ }
+ if rune != rune1 {
+ t.Errorf("incorrect rune after unread: got %c wanted %c", rune1, rune)
+ }
+ }
+ if got != data {
+ t.Errorf("want=%q got=%q", data, got)
+ }
+}
+
+// Test that UnreadRune fails if the preceding operation was not a ReadRune.
+func TestUnreadRuneError(t *testing.T) {
+ buf := make([]byte, 3) // All runes in this test are 3 bytes long
+ r := NewReader(&StringReader{data: []string{"日本語日本語日本語"}})
+ if r.UnreadRune() == nil {
+ t.Error("expected error on UnreadRune from fresh buffer")
+ }
+ _, _, err := r.ReadRune()
+ if err != nil {
+ t.Error("unexpected error on ReadRune (1):", err)
+ }
+ if err = r.UnreadRune(); err != nil {
+ t.Error("unexpected error on UnreadRune (1):", err)
+ }
+ if r.UnreadRune() == nil {
+ t.Error("expected error after UnreadRune (1)")
+ }
+ // Test error after Read.
+ _, _, err = r.ReadRune() // reset state
+ if err != nil {
+ t.Error("unexpected error on ReadRune (2):", err)
+ }
+ _, err = r.Read(buf)
+ if err != nil {
+ t.Error("unexpected error on Read (2):", err)
+ }
+ if r.UnreadRune() == nil {
+ t.Error("expected error after Read (2)")
+ }
+ // Test error after ReadByte.
+ _, _, err = r.ReadRune() // reset state
+ if err != nil {
+ t.Error("unexpected error on ReadRune (2):", err)
+ }
+ for _ = range buf {
+ _, err = r.ReadByte()
+ if err != nil {
+ t.Error("unexpected error on ReadByte (2):", err)
+ }
+ }
+ if r.UnreadRune() == nil {
+ t.Error("expected error after ReadByte")
+ }
+ // Test error after UnreadByte.
+ _, _, err = r.ReadRune() // reset state
+ if err != nil {
+ t.Error("unexpected error on ReadRune (3):", err)
+ }
+ _, err = r.ReadByte()
+ if err != nil {
+ t.Error("unexpected error on ReadByte (3):", err)
+ }
+ err = r.UnreadByte()
+ if err != nil {
+ t.Error("unexpected error on UnreadByte (3):", err)
+ }
+ if r.UnreadRune() == nil {
+ t.Error("expected error after UnreadByte (3)")
+ }
+}
+
+func TestUnreadRuneAtEOF(t *testing.T) {
+ // UnreadRune/ReadRune should error at EOF (was a bug; used to panic)
+ r := NewReader(strings.NewReader("x"))
+ r.ReadRune()
+ r.ReadRune()
+ r.UnreadRune()
+ _, _, err := r.ReadRune()
+ if err == nil {
+ t.Error("expected error at EOF")
+ } else if err != os.EOF {
+ t.Error("expected EOF; got", err)
+ }
+}
+
func TestReadWriteRune(t *testing.T) {
const NRune = 1000
byteBuf := new(bytes.Buffer)
@@ -233,7 +337,7 @@ func TestReadWriteRune(t *testing.T) {
// Write the runes out using WriteRune
buf := make([]byte, utf8.UTFMax)
for rune := 0; rune < NRune; rune++ {
- size := utf8.EncodeRune(rune, buf)
+ size := utf8.EncodeRune(buf, rune)
nbytes, err := w.WriteRune(rune)
if err != nil {
t.Fatalf("WriteRune(0x%x) error: %s", rune, err)
@@ -247,7 +351,7 @@ func TestReadWriteRune(t *testing.T) {
r := NewReader(byteBuf)
// Read them back with ReadRune
for rune := 0; rune < NRune; rune++ {
- size := utf8.EncodeRune(rune, buf)
+ size := utf8.EncodeRune(buf, rune)
nr, nbytes, err := r.ReadRune()
if nr != rune || nbytes != size || err != nil {
t.Fatalf("ReadRune(0x%x) got 0x%x,%d not 0x%x,%d (err=%s)", r, nr, nbytes, r, size, err)
@@ -293,9 +397,9 @@ func TestWriter(t *testing.T) {
}
for l := 0; l < len(written); l++ {
if written[i] != data[i] {
- t.Errorf("%s: wrong bytes written")
- t.Errorf("want=%s", data[0:len(written)])
- t.Errorf("have=%s", written)
+ t.Errorf("wrong bytes written")
+ t.Errorf("want=%q", data[0:len(written)])
+ t.Errorf("have=%q", written)
}
}
}
@@ -315,12 +419,12 @@ func (w errorWriterTest) Write(p []byte) (int, os.Error) {
}
var errorWriterTests = []errorWriterTest{
- errorWriterTest{0, 1, nil, io.ErrShortWrite},
- errorWriterTest{1, 2, nil, io.ErrShortWrite},
- errorWriterTest{1, 1, nil, nil},
- errorWriterTest{0, 1, os.EPIPE, os.EPIPE},
- errorWriterTest{1, 2, os.EPIPE, os.EPIPE},
- errorWriterTest{1, 1, os.EPIPE, os.EPIPE},
+ {0, 1, nil, io.ErrShortWrite},
+ {1, 2, nil, io.ErrShortWrite},
+ {1, 1, nil, nil},
+ {0, 1, os.EPIPE, os.EPIPE},
+ {1, 2, os.EPIPE, os.EPIPE},
+ {1, 1, os.EPIPE, os.EPIPE},
}
func TestWriteErrors(t *testing.T) {
@@ -419,3 +523,50 @@ func TestBufferFull(t *testing.T) {
t.Errorf("second ReadSlice(,) = %q, %v", line, err)
}
}
+
+func TestPeek(t *testing.T) {
+ p := make([]byte, 10)
+ buf, _ := NewReaderSize(strings.NewReader("abcdefghij"), 4)
+ if s, err := buf.Peek(1); string(s) != "a" || err != nil {
+ t.Fatalf("want %q got %q, err=%v", "a", string(s), err)
+ }
+ if s, err := buf.Peek(4); string(s) != "abcd" || err != nil {
+ t.Fatalf("want %q got %q, err=%v", "abcd", string(s), err)
+ }
+ if _, err := buf.Peek(5); err != ErrBufferFull {
+ t.Fatalf("want ErrBufFull got %v", err)
+ }
+ if _, err := buf.Read(p[0:3]); string(p[0:3]) != "abc" || err != nil {
+ t.Fatalf("want %q got %q, err=%v", "abc", string(p[0:3]), err)
+ }
+ if s, err := buf.Peek(1); string(s) != "d" || err != nil {
+ t.Fatalf("want %q got %q, err=%v", "d", string(s), err)
+ }
+ if s, err := buf.Peek(2); string(s) != "de" || err != nil {
+ t.Fatalf("want %q got %q, err=%v", "de", string(s), err)
+ }
+ if _, err := buf.Read(p[0:3]); string(p[0:3]) != "def" || err != nil {
+ t.Fatalf("want %q got %q, err=%v", "def", string(p[0:3]), err)
+ }
+ if s, err := buf.Peek(4); string(s) != "ghij" || err != nil {
+ t.Fatalf("want %q got %q, err=%v", "ghij", string(s), err)
+ }
+ if _, err := buf.Read(p[0:4]); string(p[0:4]) != "ghij" || err != nil {
+ t.Fatalf("want %q got %q, err=%v", "ghij", string(p[0:3]), err)
+ }
+ if s, err := buf.Peek(0); string(s) != "" || err != nil {
+ t.Fatalf("want %q got %q, err=%v", "", string(s), err)
+ }
+ if _, err := buf.Peek(1); err != os.EOF {
+ t.Fatalf("want EOF got %v", err)
+ }
+}
+
+func TestPeekThenUnreadRune(t *testing.T) {
+ // This sequence used to cause a crash.
+ r := NewReader(strings.NewReader("x"))
+ r.ReadRune()
+ r.Peek(1)
+ r.UnreadRune()
+ r.ReadRune() // Used to panic here
+}
diff --git a/src/pkg/bytes/Makefile b/src/pkg/bytes/Makefile
index d50e624d6..03395c7a4 100644
--- a/src/pkg/bytes/Makefile
+++ b/src/pkg/bytes/Makefile
@@ -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 ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=bytes
GOFILES=\
diff --git a/src/pkg/bytes/asm_amd64.s b/src/pkg/bytes/asm_amd64.s
index 7e78700ec..c6793cbdc 100644
--- a/src/pkg/bytes/asm_amd64.s
+++ b/src/pkg/bytes/asm_amd64.s
@@ -3,15 +3,90 @@
// license that can be found in the LICENSE file.
TEXT ·IndexByte(SB),7,$0
- MOVQ p+0(FP), SI
- MOVL len+8(FP), CX
- MOVB b+16(FP), AL
- MOVQ SI, DI
+ MOVQ p+0(FP), SI
+ MOVL len+8(FP), BX
+ MOVB b+16(FP), AL
+ MOVQ SI, DI
+
+ CMPL BX, $16
+ JLT small
+
+ // round up to first 16-byte boundary
+ TESTQ $15, SI
+ JZ aligned
+ MOVQ SI, CX
+ ANDQ $~15, CX
+ ADDQ $16, CX
+
+ // search the beginning
+ SUBQ SI, CX
+ REPN; SCASB
+ JZ success
+
+// DI is 16-byte aligned; get ready to search using SSE instructions
+aligned:
+ // round down to last 16-byte boundary
+ MOVQ BX, R11
+ ADDQ SI, R11
+ ANDQ $~15, R11
+
+ // shuffle X0 around so that each byte contains c
+ MOVD AX, X0
+ PUNPCKLBW X0, X0
+ PUNPCKLBW X0, X0
+ PSHUFL $0, X0, X0
+ JMP condition
+
+sse:
+ // move the next 16-byte chunk of the buffer into X1
+ MOVO (DI), X1
+ // compare bytes in X0 to X1
+ PCMPEQB X0, X1
+ // take the top bit of each byte in X1 and put the result in DX
+ PMOVMSKB X1, DX
+ TESTL DX, DX
+ JNZ ssesuccess
+ ADDQ $16, DI
+
+condition:
+ CMPQ DI, R11
+ JLT sse
+
+ // search the end
+ MOVQ SI, CX
+ ADDQ BX, CX
+ SUBQ R11, CX
+ // if CX == 0, the zero flag will be set and we'll end up
+ // returning a false success
+ JZ failure
REPN; SCASB
- JZ 3(PC)
- MOVL $-1, ret+24(FP)
+ JZ success
+
+failure:
+ MOVL $-1, ret+24(FP)
+ RET
+
+// handle for lengths < 16
+small:
+ MOVL BX, CX
+ REPN; SCASB
+ JZ success
+ MOVL $-1, ret+24(FP)
RET
- SUBQ SI, DI
- SUBL $1, DI
- MOVL DI, ret+24(FP)
+
+// we've found the chunk containing the byte
+// now just figure out which specific byte it is
+ssesuccess:
+ // get the index of the least significant set bit
+ BSFW DX, DX
+ SUBQ SI, DI
+ ADDQ DI, DX
+ MOVL DX, ret+24(FP)
+ RET
+
+success:
+ SUBQ SI, DI
+ SUBL $1, DI
+ MOVL DI, ret+24(FP)
RET
+
diff --git a/src/pkg/bytes/buffer.go b/src/pkg/bytes/buffer.go
index 01e6aef67..2574b4f43 100644
--- a/src/pkg/bytes/buffer.go
+++ b/src/pkg/bytes/buffer.go
@@ -12,14 +12,6 @@ import (
"utf8"
)
-// Copy from string to byte array at offset doff. Assume there's room.
-func copyString(dst []byte, doff int, str string) {
- for soff := 0; soff < len(str); soff++ {
- dst[doff] = str[soff]
- doff++
- }
-}
-
// A Buffer is a variable-sized buffer of bytes with Read and Write methods.
// The zero value for Buffer is an empty buffer ready to use.
type Buffer struct {
@@ -27,8 +19,20 @@ type Buffer struct {
off int // read at &buf[off], write at &buf[len(buf)]
runeBytes [utf8.UTFMax]byte // avoid allocation of slice on each WriteByte or Rune
bootstrap [64]byte // memory to hold first slice; helps small buffers (Printf) avoid allocation.
+ lastRead readOp // last read operation, so that Unread* can work correctly.
}
+// The readOp constants describe the last action performed on
+// the buffer, so that UnreadRune and UnreadByte can
+// check for invalid usage.
+type readOp int
+
+const (
+ opInvalid readOp = iota // Non-read operation.
+ opReadRune // Read rune.
+ opRead // Any other read operation.
+)
+
// Bytes returns a slice of the contents of the unread portion of the buffer;
// len(b.Bytes()) == b.Len(). If the caller changes the contents of the
// returned slice, the contents of the buffer will change provided there
@@ -52,6 +56,7 @@ func (b *Buffer) Len() int { return len(b.buf) - b.off }
// Truncate discards all but the first n unread bytes from the buffer.
// It is an error to call b.Truncate(n) with n > b.Len().
func (b *Buffer) Truncate(n int) {
+ b.lastRead = opInvalid
if n == 0 {
// Reuse buffer space.
b.off = 0
@@ -90,6 +95,7 @@ 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) {
+ b.lastRead = opInvalid
m := b.grow(len(p))
copy(b.buf[m:], p)
return len(p), nil
@@ -98,9 +104,9 @@ func (b *Buffer) Write(p []byte) (n int, err os.Error) {
// WriteString appends the contents of s to the buffer. The return
// value n is the length of s; err is always nil.
func (b *Buffer) WriteString(s string) (n int, err os.Error) {
+ b.lastRead = opInvalid
m := b.grow(len(s))
- copyString(b.buf, m, s)
- return len(s), nil
+ return copy(b.buf[m:], s), nil
}
// MinRead is the minimum slice size passed to a Read call by
@@ -114,6 +120,7 @@ const MinRead = 512
// Any error except os.EOF encountered during the read
// is also returned.
func (b *Buffer) ReadFrom(r io.Reader) (n int64, err os.Error) {
+ b.lastRead = opInvalid
// If buffer is empty, reset to recover space.
if b.off >= len(b.buf) {
b.Truncate(0)
@@ -150,6 +157,7 @@ func (b *Buffer) ReadFrom(r io.Reader) (n int64, err os.Error) {
// occurs. The return value n is the number of bytes written.
// Any error encountered during the write is also returned.
func (b *Buffer) WriteTo(w io.Writer) (n int64, err os.Error) {
+ b.lastRead = opInvalid
for b.off < len(b.buf) {
m, e := w.Write(b.buf[b.off:])
n += int64(m)
@@ -167,6 +175,7 @@ func (b *Buffer) WriteTo(w io.Writer) (n int64, err os.Error) {
// The returned error is always nil, but is included
// to match bufio.Writer's WriteByte.
func (b *Buffer) WriteByte(c byte) os.Error {
+ b.lastRead = opInvalid
m := b.grow(1)
b.buf[m] = c
return nil
@@ -181,7 +190,7 @@ func (b *Buffer) WriteRune(r int) (n int, err os.Error) {
b.WriteByte(byte(r))
return 1, nil
}
- n = utf8.EncodeRune(r, b.runeBytes[0:])
+ n = utf8.EncodeRune(b.runeBytes[0:], r)
b.Write(b.runeBytes[0:n])
return n, nil
}
@@ -191,6 +200,7 @@ func (b *Buffer) WriteRune(r int) (n int, err os.Error) {
// buffer has no data to return, err is os.EOF even if len(p) is zero;
// otherwise it is nil.
func (b *Buffer) Read(p []byte) (n int, err os.Error) {
+ b.lastRead = opInvalid
if b.off >= len(b.buf) {
// Buffer is empty, reset to recover space.
b.Truncate(0)
@@ -198,6 +208,9 @@ func (b *Buffer) Read(p []byte) (n int, err os.Error) {
}
n = copy(p, b.buf[b.off:])
b.off += n
+ if n > 0 {
+ b.lastRead = opRead
+ }
return
}
@@ -206,18 +219,23 @@ func (b *Buffer) Read(p []byte) (n int, err os.Error) {
// If there are fewer than n bytes in the buffer, Next returns the entire buffer.
// The slice is only valid until the next call to a read or write method.
func (b *Buffer) Next(n int) []byte {
+ b.lastRead = opInvalid
m := b.Len()
if n > m {
n = m
}
data := b.buf[b.off : b.off+n]
b.off += n
+ if n > 0 {
+ b.lastRead = opRead
+ }
return data
}
// ReadByte reads and returns the next byte from the buffer.
// If no byte is available, it returns error os.EOF.
func (b *Buffer) ReadByte() (c byte, err os.Error) {
+ b.lastRead = opInvalid
if b.off >= len(b.buf) {
// Buffer is empty, reset to recover space.
b.Truncate(0)
@@ -225,6 +243,7 @@ func (b *Buffer) ReadByte() (c byte, err os.Error) {
}
c = b.buf[b.off]
b.off++
+ b.lastRead = opRead
return c, nil
}
@@ -234,11 +253,13 @@ func (b *Buffer) ReadByte() (c byte, err os.Error) {
// If the bytes are an erroneous UTF-8 encoding, it
// consumes one byte and returns U+FFFD, 1.
func (b *Buffer) ReadRune() (r int, size int, err os.Error) {
+ b.lastRead = opInvalid
if b.off >= len(b.buf) {
// Buffer is empty, reset to recover space.
b.Truncate(0)
return 0, 0, os.EOF
}
+ b.lastRead = opReadRune
c := b.buf[b.off]
if c < utf8.RuneSelf {
b.off++
@@ -249,6 +270,37 @@ func (b *Buffer) ReadRune() (r int, size int, err os.Error) {
return r, n, nil
}
+// UnreadRune unreads the last rune returned by ReadRune.
+// If the most recent read or write operation on the buffer was
+// not a ReadRune, UnreadRune returns an error. (In this regard
+// it is stricter than UnreadByte, which will unread the last byte
+// from any read operation.)
+func (b *Buffer) UnreadRune() os.Error {
+ if b.lastRead != opReadRune {
+ return os.ErrorString("bytes.Buffer: UnreadRune: previous operation was not ReadRune")
+ }
+ b.lastRead = opInvalid
+ if b.off > 0 {
+ _, n := utf8.DecodeLastRune(b.buf[0:b.off])
+ b.off -= n
+ }
+ return nil
+}
+
+// UnreadByte unreads the last byte returned by the most recent
+// read operation. If write has happened since the last read, UnreadByte
+// returns an error.
+func (b *Buffer) UnreadByte() os.Error {
+ if b.lastRead != opReadRune && b.lastRead != opRead {
+ return os.ErrorString("bytes.Buffer: UnreadByte: previous operation was not a read")
+ }
+ b.lastRead = opInvalid
+ if b.off > 0 {
+ b.off--
+ }
+ return nil
+}
+
// NewBuffer creates and initializes a new Buffer using buf as its initial
// contents. It is intended to prepare a Buffer to read existing data. It
// can also be used to to size the internal buffer for writing. To do that,
@@ -259,7 +311,5 @@ func NewBuffer(buf []byte) *Buffer { return &Buffer{buf: buf} }
// initial contents. It is intended to prepare a buffer to read an existing
// string.
func NewBufferString(s string) *Buffer {
- buf := make([]byte, len(s))
- copyString(buf, 0, s)
- return &Buffer{buf: buf}
+ return &Buffer{buf: []byte(s)}
}
diff --git a/src/pkg/bytes/buffer_test.go b/src/pkg/bytes/buffer_test.go
index bc696f4b5..509793d24 100644
--- a/src/pkg/bytes/buffer_test.go
+++ b/src/pkg/bytes/buffer_test.go
@@ -30,19 +30,19 @@ func check(t *testing.T, testname string, buf *Buffer, s string) {
bytes := buf.Bytes()
str := buf.String()
if buf.Len() != len(bytes) {
- t.Errorf("%s: buf.Len() == %d, len(buf.Bytes()) == %d\n", testname, buf.Len(), len(bytes))
+ t.Errorf("%s: buf.Len() == %d, len(buf.Bytes()) == %d", testname, buf.Len(), len(bytes))
}
if buf.Len() != len(str) {
- t.Errorf("%s: buf.Len() == %d, len(buf.String()) == %d\n", testname, buf.Len(), len(str))
+ t.Errorf("%s: buf.Len() == %d, len(buf.String()) == %d", testname, buf.Len(), len(str))
}
if buf.Len() != len(s) {
- t.Errorf("%s: buf.Len() == %d, len(s) == %d\n", testname, buf.Len(), len(s))
+ t.Errorf("%s: buf.Len() == %d, len(s) == %d", testname, buf.Len(), len(s))
}
if string(bytes) != s {
- t.Errorf("%s: string(buf.Bytes()) == %q, s == %q\n", testname, string(bytes), s)
+ t.Errorf("%s: string(buf.Bytes()) == %q, s == %q", testname, string(bytes), s)
}
}
@@ -55,10 +55,10 @@ func fillString(t *testing.T, testname string, buf *Buffer, s string, n int, fus
for ; n > 0; n-- {
m, err := buf.WriteString(fus)
if m != len(fus) {
- t.Errorf(testname+" (fill 2): m == %d, expected %d\n", m, len(fus))
+ t.Errorf(testname+" (fill 2): m == %d, expected %d", m, len(fus))
}
if err != nil {
- t.Errorf(testname+" (fill 3): err should always be nil, found err == %s\n", err)
+ t.Errorf(testname+" (fill 3): err should always be nil, found err == %s", err)
}
s += fus
check(t, testname+" (fill 4)", buf, s)
@@ -75,10 +75,10 @@ func fillBytes(t *testing.T, testname string, buf *Buffer, s string, n int, fub
for ; n > 0; n-- {
m, err := buf.Write(fub)
if m != len(fub) {
- t.Errorf(testname+" (fill 2): m == %d, expected %d\n", m, len(fub))
+ t.Errorf(testname+" (fill 2): m == %d, expected %d", m, len(fub))
}
if err != nil {
- t.Errorf(testname+" (fill 3): err should always be nil, found err == %s\n", err)
+ t.Errorf(testname+" (fill 3): err should always be nil, found err == %s", err)
}
s += string(fub)
check(t, testname+" (fill 4)", buf, s)
@@ -110,7 +110,7 @@ func empty(t *testing.T, testname string, buf *Buffer, s string, fub []byte) {
break
}
if err != nil {
- t.Errorf(testname+" (empty 2): err should always be nil, found err == %s\n", err)
+ t.Errorf(testname+" (empty 2): err should always be nil, found err == %s", err)
}
s = s[n:]
check(t, testname+" (empty 3)", buf, s)
@@ -132,21 +132,21 @@ func TestBasicOperations(t *testing.T) {
buf.Truncate(0)
check(t, "TestBasicOperations (3)", &buf, "")
- n, err := buf.Write(Bytes(data[0:1]))
+ n, err := buf.Write([]byte(data[0:1]))
if n != 1 {
- t.Errorf("wrote 1 byte, but n == %d\n", n)
+ t.Errorf("wrote 1 byte, but n == %d", n)
}
if err != nil {
- t.Errorf("err should always be nil, but err == %s\n", err)
+ t.Errorf("err should always be nil, but err == %s", err)
}
check(t, "TestBasicOperations (4)", &buf, "a")
buf.WriteByte(data[1])
check(t, "TestBasicOperations (5)", &buf, "ab")
- n, err = buf.Write(Bytes(data[2:26]))
+ n, err = buf.Write([]byte(data[2:26]))
if n != 24 {
- t.Errorf("wrote 25 bytes, but n == %d\n", n)
+ t.Errorf("wrote 25 bytes, but n == %d", n)
}
check(t, "TestBasicOperations (6)", &buf, string(data[0:26]))
@@ -162,14 +162,14 @@ func TestBasicOperations(t *testing.T) {
buf.WriteByte(data[1])
c, err := buf.ReadByte()
if err != nil {
- t.Errorf("ReadByte unexpected eof\n")
+ t.Error("ReadByte unexpected eof")
}
if c != data[1] {
- t.Errorf("ReadByte wrong value c=%v\n", c)
+ t.Errorf("ReadByte wrong value c=%v", c)
}
c, err = buf.ReadByte()
if err == nil {
- t.Errorf("ReadByte unexpected not eof\n")
+ t.Error("ReadByte unexpected not eof")
}
}
}
@@ -238,7 +238,7 @@ func TestMixedReadsAndWrites(t *testing.T) {
func TestNil(t *testing.T) {
var b *Buffer
if b.String() != "<nil>" {
- t.Error("expcted <nil>; got %q", b.String())
+ t.Errorf("expcted <nil>; got %q", b.String())
}
}
@@ -272,13 +272,13 @@ func TestRuneIO(t *testing.T) {
var buf Buffer
n := 0
for r := 0; r < NRune; r++ {
- size := utf8.EncodeRune(r, b[n:])
+ size := utf8.EncodeRune(b[n:], r)
nbytes, err := buf.WriteRune(r)
if err != nil {
- t.Fatalf("WriteRune(0x%x) error: %s", r, err)
+ t.Fatalf("WriteRune(%U) error: %s", r, err)
}
if nbytes != size {
- t.Fatalf("WriteRune(0x%x) expected %d, got %d", r, size, nbytes)
+ t.Fatalf("WriteRune(%U) expected %d, got %d", r, size, nbytes)
}
n += size
}
@@ -289,12 +289,27 @@ func TestRuneIO(t *testing.T) {
t.Fatalf("incorrect result from WriteRune: %q not %q", buf.Bytes(), b)
}
+ p := make([]byte, utf8.UTFMax)
// Read it back with ReadRune
for r := 0; r < NRune; r++ {
- size := utf8.EncodeRune(r, b)
+ size := utf8.EncodeRune(p, r)
nr, nbytes, err := buf.ReadRune()
if nr != r || 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)
+ t.Fatalf("ReadRune(%U) got %U,%d not %U,%d (err=%s)", r, nr, nbytes, r, size, err)
+ }
+ }
+
+ // Check that UnreadRune works
+ buf.Reset()
+ buf.Write(b)
+ for r := 0; r < NRune; r++ {
+ r1, size, _ := buf.ReadRune()
+ if err := buf.UnreadRune(); err != nil {
+ t.Fatalf("UnreadRune(%U) got error %q", r, err)
+ }
+ r2, nbytes, err := buf.ReadRune()
+ if r1 != r2 || r1 != r || nbytes != size || err != nil {
+ t.Fatalf("ReadRune(%U) after UnreadRune got %U,%d not %U,%d (err=%s)", r, r2, nbytes, r, size, err)
}
}
}
diff --git a/src/pkg/bytes/bytes.go b/src/pkg/bytes/bytes.go
index bcf7b8609..bfe2ef39d 100644
--- a/src/pkg/bytes/bytes.go
+++ b/src/pkg/bytes/bytes.go
@@ -3,7 +3,7 @@
// license that can be found in the LICENSE file.
// The bytes package implements functions for the manipulation of byte slices.
-// Analagous to the facilities of the strings package.
+// Analogous to the facilities of the strings package.
package bytes
import (
@@ -127,7 +127,21 @@ func LastIndex(s, sep []byte) int {
return -1
}
-// IndexAny interprets s as a sequence of UTF-8 encoded Unicode code points.
+// IndexRune interprets s as a sequence of UTF-8-encoded Unicode code points.
+// It returns the byte index of the first occurrence in s of the given rune.
+// It returns -1 if rune is not present in s.
+func IndexRune(s []byte, rune int) int {
+ for i := 0; i < len(s); {
+ r, size := utf8.DecodeRune(s[i:])
+ if r == rune {
+ return i
+ }
+ i += size
+ }
+ return -1
+}
+
+// IndexAny interprets s as a sequence of UTF-8-encoded Unicode code points.
// It returns the byte index of the first occurrence in s of any of the Unicode
// code points in chars. It returns -1 if chars is empty or if there is no code
// point in common.
@@ -151,6 +165,25 @@ func IndexAny(s []byte, chars string) int {
return -1
}
+// LastIndexAny interprets s as a sequence of UTF-8-encoded Unicode code
+// points. It returns the byte index of the last occurrence in s of any of
+// the Unicode code points in chars. It returns -1 if chars is empty or if
+// there is no code point in common.
+func LastIndexAny(s []byte, chars string) int {
+ if len(chars) > 0 {
+ for i := len(s); i > 0; {
+ rune, size := utf8.DecodeLastRune(s[0:i])
+ i -= size
+ for _, m := range chars {
+ if rune == m {
+ return i
+ }
+ }
+ }
+ }
+ return -1
+}
+
// Generic split: splits after each instance of sep,
// including sepSave bytes of sep in the subarrays.
func genSplit(s, sep []byte, sepSave, n int) [][]byte {
@@ -179,17 +212,22 @@ func genSplit(s, sep []byte, sepSave, n int) [][]byte {
return a[0 : na+1]
}
-// Split splits the array s around each instance of sep, returning an array of subarrays of s.
-// If sep is empty, Split splits s after each UTF-8 sequence.
-// If n >= 0, Split splits s into at most n subarrays; the last subarray will contain an unsplit remainder.
-// Thus if n == 0, the result will ne nil.
+// Split slices s into subslices separated by sep and returns a slice of
+// the subslices between those separators.
+// If sep is empty, Split splits after each UTF-8 sequence.
+// The count determines the number of subslices to return:
+// n > 0: at most n subslices; the last subslice will be the unsplit remainder.
+// n == 0: the result is nil (zero subslices)
+// n < 0: all subslices
func Split(s, sep []byte, n int) [][]byte { return genSplit(s, sep, 0, n) }
-// SplitAfter splits the array s after each instance of sep, returning an array of subarrays of s.
-// If sep is empty, SplitAfter splits s after each UTF-8 sequence.
-// If n >= 0, SplitAfter splits s into at most n subarrays; the last subarray will contain an
-// unsplit remainder.
-// Thus if n == 0, the result will ne nil.
+// SplitAfter slices s into subslices after each instance of sep and
+// returns a slice of those subslices.
+// If sep is empty, Split splits after each UTF-8 sequence.
+// The count determines the number of subslices to return:
+// n > 0: at most n subslices; the last subslice will be the unsplit remainder.
+// n == 0: the result is nil (zero subslices)
+// n < 0: all subslices
func SplitAfter(s, sep []byte, n int) [][]byte {
return genSplit(s, sep, len(sep), n)
}
@@ -197,12 +235,20 @@ func SplitAfter(s, sep []byte, n int) [][]byte {
// Fields splits the array s around each instance of one or more consecutive white space
// characters, returning a slice of subarrays of s or an empty list if s contains only white space.
func Fields(s []byte) [][]byte {
+ return FieldsFunc(s, unicode.IsSpace)
+}
+
+// FieldsFunc interprets s as a sequence of UTF-8-encoded Unicode code points.
+// It splits the array s at each run of code points c satisfying f(c) and
+// returns a slice of subarrays of s. If no code points in s satisfy f(c), an
+// empty slice is returned.
+func FieldsFunc(s []byte, f func(int) bool) [][]byte {
n := 0
inField := false
for i := 0; i < len(s); {
rune, size := utf8.DecodeRune(s[i:])
wasInField := inField
- inField = !unicode.IsSpace(rune)
+ inField = !f(rune)
if inField && !wasInField {
n++
}
@@ -214,12 +260,12 @@ func Fields(s []byte) [][]byte {
fieldStart := -1
for i := 0; i <= len(s) && na < n; {
rune, size := utf8.DecodeRune(s[i:])
- if fieldStart < 0 && size > 0 && !unicode.IsSpace(rune) {
+ if fieldStart < 0 && size > 0 && !f(rune) {
fieldStart = i
i += size
continue
}
- if fieldStart >= 0 && (size == 0 || unicode.IsSpace(rune)) {
+ if fieldStart >= 0 && (size == 0 || f(rune)) {
a[na] = s[fieldStart:i]
na++
fieldStart = -1
@@ -278,7 +324,7 @@ func HasSuffix(s, suffix []byte) bool {
// Map returns a copy of the byte array s with all its characters modified
// according to the mapping function. If mapping returns a negative value, the character is
// dropped from the string with no replacement. The characters in s and the
-// output are interpreted as UTF-8 encoded Unicode code points.
+// output are interpreted as UTF-8-encoded Unicode code points.
func Map(mapping func(rune int) int, s []byte) []byte {
// In the worst case, the array can grow when mapped, making
// things unpleasant. But it's so rare we barge in assuming it's
@@ -298,12 +344,10 @@ func Map(mapping func(rune int) int, s []byte) []byte {
// Grow the buffer.
maxbytes = maxbytes*2 + utf8.UTFMax
nb := make([]byte, maxbytes)
- for i, c := range b[0:nbytes] {
- nb[i] = c
- }
+ copy(nb, b[0:nbytes])
b = nb
}
- nbytes += utf8.EncodeRune(rune, b[nbytes:maxbytes])
+ nbytes += utf8.EncodeRune(b[nbytes:maxbytes], rune)
}
i += wid
}
@@ -332,52 +376,147 @@ func ToLower(s []byte) []byte { return Map(unicode.ToLower, s) }
// ToTitle returns a copy of the byte array s with all Unicode letters mapped to their title case.
func ToTitle(s []byte) []byte { return Map(unicode.ToTitle, s) }
-// TrimLeftFunc returns a subslice of s by slicing off all leading UTF-8 encoded
+// ToUpperSpecial returns a copy of the byte array s with all Unicode letters mapped to their
+// upper case, giving priority to the special casing rules.
+func ToUpperSpecial(_case unicode.SpecialCase, s []byte) []byte {
+ return Map(func(r int) int { return _case.ToUpper(r) }, s)
+}
+
+// ToLowerSpecial returns a copy of the byte array s with all Unicode letters mapped to their
+// lower case, giving priority to the special casing rules.
+func ToLowerSpecial(_case unicode.SpecialCase, s []byte) []byte {
+ return Map(func(r int) int { return _case.ToLower(r) }, s)
+}
+
+// ToTitleSpecial returns a copy of the byte array s with all Unicode letters mapped to their
+// title case, giving priority to the special casing rules.
+func ToTitleSpecial(_case unicode.SpecialCase, s []byte) []byte {
+ return Map(func(r int) int { return _case.ToTitle(r) }, s)
+}
+
+
+// isSeparator reports whether the rune could mark a word boundary.
+// TODO: update when package unicode captures more of the properties.
+func isSeparator(rune int) bool {
+ // ASCII alphanumerics and underscore are not separators
+ if rune <= 0x7F {
+ switch {
+ case '0' <= rune && rune <= '9':
+ return false
+ case 'a' <= rune && rune <= 'z':
+ return false
+ case 'A' <= rune && rune <= 'Z':
+ return false
+ case rune == '_':
+ return false
+ }
+ return true
+ }
+ // Letters and digits are not separators
+ if unicode.IsLetter(rune) || unicode.IsDigit(rune) {
+ return false
+ }
+ // Otherwise, all we can do for now is treat spaces as separators.
+ return unicode.IsSpace(rune)
+}
+
+// BUG(r): The rule Title uses for word boundaries does not handle Unicode punctuation properly.
+
+// Title returns a copy of s with all Unicode letters that begin words
+// mapped to their title case.
+func Title(s []byte) []byte {
+ // Use a closure here to remember state.
+ // Hackish but effective. Depends on Map scanning in order and calling
+ // the closure once per rune.
+ prev := ' '
+ return Map(
+ func(r int) int {
+ if isSeparator(prev) {
+ prev = r
+ return unicode.ToTitle(r)
+ }
+ prev = r
+ return r
+ },
+ s)
+}
+
+// TrimLeftFunc returns a subslice of s by slicing off all leading UTF-8-encoded
// Unicode code points c that satisfy f(c).
func TrimLeftFunc(s []byte, f func(r int) bool) []byte {
- var start, wid int
- for start = 0; start < len(s); start += wid {
- wid = 1
- rune := int(s[start])
- if rune >= utf8.RuneSelf {
- rune, wid = utf8.DecodeRune(s[start:])
- }
- if !f(rune) {
- break
- }
+ i := indexFunc(s, f, false)
+ if i == -1 {
+ return nil
}
- return s[start:]
+ return s[i:]
}
// TrimRightFunc returns a subslice of s by slicing off all trailing UTF-8
// encoded Unicode code points c that satisfy f(c).
func TrimRightFunc(s []byte, f func(r int) bool) []byte {
- var end, wid int
- for end = len(s); end > 0; end -= wid {
- wid = 1
- rune := int(s[end-wid])
- if rune >= utf8.RuneSelf {
- // Back up & look for beginning of rune. Mustn't pass start.
- for wid = 2; end-wid >= 0 && !utf8.RuneStart(s[end-wid]); wid++ {
- }
- if end-wid < 0 { // invalid UTF-8 sequence; stop processing
- break
- }
- rune, wid = utf8.DecodeRune(s[end-wid : end])
- }
- if !f(rune) {
- break
- }
+ i := lastIndexFunc(s, f, false)
+ if i >= 0 && s[i] >= utf8.RuneSelf {
+ _, wid := utf8.DecodeRune(s[i:])
+ i += wid
+ } else {
+ i++
}
- return s[0:end]
+ return s[0:i]
}
// TrimFunc returns a subslice of s by slicing off all leading and trailing
-// UTF-8 encoded Unicode code points c that satisfy f(c).
+// UTF-8-encoded Unicode code points c that satisfy f(c).
func TrimFunc(s []byte, f func(r int) bool) []byte {
return TrimRightFunc(TrimLeftFunc(s, f), f)
}
+// IndexFunc interprets s as a sequence of UTF-8-encoded Unicode code points.
+// It returns the byte index in s of the first Unicode
+// code point satisfying f(c), or -1 if none do.
+func IndexFunc(s []byte, f func(r int) bool) int {
+ return indexFunc(s, f, true)
+}
+
+// LastIndexFunc interprets s as a sequence of UTF-8-encoded Unicode code points.
+// It returns the byte index in s of the last Unicode
+// code point satisfying f(c), or -1 if none do.
+func LastIndexFunc(s []byte, f func(r int) bool) int {
+ return lastIndexFunc(s, f, true)
+}
+
+// indexFunc is the same as IndexFunc except that if
+// truth==false, the sense of the predicate function is
+// inverted.
+func indexFunc(s []byte, f func(r int) bool, truth bool) int {
+ start := 0
+ for start < len(s) {
+ wid := 1
+ rune := int(s[start])
+ if rune >= utf8.RuneSelf {
+ rune, wid = utf8.DecodeRune(s[start:])
+ }
+ if f(rune) == truth {
+ return start
+ }
+ start += wid
+ }
+ return -1
+}
+
+// lastIndexFunc is the same as LastIndexFunc except that if
+// truth==false, the sense of the predicate function is
+// inverted.
+func lastIndexFunc(s []byte, f func(r int) bool, truth bool) int {
+ for i := len(s); i > 0; {
+ rune, size := utf8.DecodeLastRune(s[0:i])
+ i -= size
+ if f(rune) == truth {
+ return i
+ }
+ }
+ return -1
+}
+
func makeCutsetFunc(cutset string) func(rune int) bool {
return func(rune int) bool {
for _, c := range cutset {
@@ -390,71 +529,29 @@ func makeCutsetFunc(cutset string) func(rune int) bool {
}
// Trim returns a subslice of s by slicing off all leading and
-// trailing UTF-8 encoded Unicode code points contained in cutset.
+// trailing UTF-8-encoded Unicode code points contained in cutset.
func Trim(s []byte, cutset string) []byte {
return TrimFunc(s, makeCutsetFunc(cutset))
}
// TrimLeft returns a subslice of s by slicing off all leading
-// UTF-8 encoded Unicode code points contained in cutset.
+// UTF-8-encoded Unicode code points contained in cutset.
func TrimLeft(s []byte, cutset string) []byte {
return TrimLeftFunc(s, makeCutsetFunc(cutset))
}
// TrimRight returns a subslice of s by slicing off all trailing
-// UTF-8 encoded Unicode code points that are contained in cutset.
+// UTF-8-encoded Unicode code points that are contained in cutset.
func TrimRight(s []byte, cutset string) []byte {
return TrimRightFunc(s, makeCutsetFunc(cutset))
}
// TrimSpace returns a subslice of s by slicing off all leading and
-// trailing white space, as as defined by Unicode.
+// trailing white space, as defined by Unicode.
func TrimSpace(s []byte) []byte {
return TrimFunc(s, unicode.IsSpace)
}
-// How big to make a byte array when growing.
-// Heuristic: Scale by 50% to give n log n time.
-func resize(n int) int {
- if n < 16 {
- n = 16
- }
- return n + n/2
-}
-
-// Add appends the contents of t to the end of s and returns the result.
-// If s has enough capacity, it is extended in place; otherwise a
-// new array is allocated and returned.
-func Add(s, t []byte) []byte {
- lens := len(s)
- lent := len(t)
- if lens+lent <= cap(s) {
- s = s[0 : lens+lent]
- } else {
- news := make([]byte, lens+lent, resize(lens+lent))
- copy(news, s)
- s = news
- }
- copy(s[lens:lens+lent], t)
- return s
-}
-
-// AddByte appends byte b to the end of s and returns the result.
-// If s has enough capacity, it is extended in place; otherwise a
-// new array is allocated and returned.
-func AddByte(s []byte, t byte) []byte {
- lens := len(s)
- if lens+1 <= cap(s) {
- s = s[0 : lens+1]
- } else {
- news := make([]byte, lens+1, resize(lens+1))
- copy(news, s)
- s = news
- }
- s[lens] = t
- return s
-}
-
// Runes returns a slice of runes (Unicode code points) equivalent to s.
func Runes(s []byte) []int {
t := make([]int, utf8.RuneCount(s))
diff --git a/src/pkg/bytes/bytes_test.go b/src/pkg/bytes/bytes_test.go
index 8197543dc..063686ec5 100644
--- a/src/pkg/bytes/bytes_test.go
+++ b/src/pkg/bytes/bytes_test.go
@@ -8,6 +8,7 @@ import (
. "bytes"
"testing"
"unicode"
+ "utf8"
)
func eq(a, b []string) bool {
@@ -45,16 +46,16 @@ type BinOpTest struct {
}
var comparetests = []BinOpTest{
- BinOpTest{"", "", 0},
- BinOpTest{"a", "", 1},
- BinOpTest{"", "a", -1},
- BinOpTest{"abc", "abc", 0},
- BinOpTest{"ab", "abc", -1},
- BinOpTest{"abc", "ab", 1},
- BinOpTest{"x", "ab", 1},
- BinOpTest{"ab", "x", -1},
- BinOpTest{"x", "a", 1},
- BinOpTest{"b", "x", -1},
+ {"", "", 0},
+ {"a", "", 1},
+ {"", "a", -1},
+ {"abc", "abc", 0},
+ {"ab", "abc", -1},
+ {"abc", "ab", 1},
+ {"x", "ab", 1},
+ {"ab", "x", -1},
+ {"x", "a", 1},
+ {"b", "x", -1},
}
func TestCompare(t *testing.T) {
@@ -73,55 +74,81 @@ func TestCompare(t *testing.T) {
}
var indexTests = []BinOpTest{
- BinOpTest{"", "", 0},
- BinOpTest{"", "a", -1},
- BinOpTest{"", "foo", -1},
- BinOpTest{"fo", "foo", -1},
- BinOpTest{"foo", "foo", 0},
- BinOpTest{"oofofoofooo", "f", 2},
- BinOpTest{"oofofoofooo", "foo", 4},
- BinOpTest{"barfoobarfoo", "foo", 3},
- BinOpTest{"foo", "", 0},
- BinOpTest{"foo", "o", 1},
- BinOpTest{"abcABCabc", "A", 3},
+ {"", "", 0},
+ {"", "a", -1},
+ {"", "foo", -1},
+ {"fo", "foo", -1},
+ {"foo", "foo", 0},
+ {"oofofoofooo", "f", 2},
+ {"oofofoofooo", "foo", 4},
+ {"barfoobarfoo", "foo", 3},
+ {"foo", "", 0},
+ {"foo", "o", 1},
+ {"abcABCabc", "A", 3},
// cases with one byte strings - test IndexByte and special case in Index()
- BinOpTest{"", "a", -1},
- BinOpTest{"x", "a", -1},
- BinOpTest{"x", "x", 0},
- BinOpTest{"abc", "a", 0},
- BinOpTest{"abc", "b", 1},
- BinOpTest{"abc", "c", 2},
- BinOpTest{"abc", "x", -1},
+ {"", "a", -1},
+ {"x", "a", -1},
+ {"x", "x", 0},
+ {"abc", "a", 0},
+ {"abc", "b", 1},
+ {"abc", "c", 2},
+ {"abc", "x", -1},
+ {"barfoobarfooyyyzzzyyyzzzyyyzzzyyyxxxzzzyyy", "x", 33},
+ {"foofyfoobarfoobar", "y", 4},
+ {"oooooooooooooooooooooo", "r", -1},
}
var lastIndexTests = []BinOpTest{
- BinOpTest{"", "", 0},
- BinOpTest{"", "a", -1},
- BinOpTest{"", "foo", -1},
- BinOpTest{"fo", "foo", -1},
- BinOpTest{"foo", "foo", 0},
- BinOpTest{"foo", "f", 0},
- BinOpTest{"oofofoofooo", "f", 7},
- BinOpTest{"oofofoofooo", "foo", 7},
- BinOpTest{"barfoobarfoo", "foo", 9},
- BinOpTest{"foo", "", 3},
- BinOpTest{"foo", "o", 2},
- BinOpTest{"abcABCabc", "A", 3},
- BinOpTest{"abcABCabc", "a", 6},
+ {"", "", 0},
+ {"", "a", -1},
+ {"", "foo", -1},
+ {"fo", "foo", -1},
+ {"foo", "foo", 0},
+ {"foo", "f", 0},
+ {"oofofoofooo", "f", 7},
+ {"oofofoofooo", "foo", 7},
+ {"barfoobarfoo", "foo", 9},
+ {"foo", "", 3},
+ {"foo", "o", 2},
+ {"abcABCabc", "A", 3},
+ {"abcABCabc", "a", 6},
}
var indexAnyTests = []BinOpTest{
- BinOpTest{"", "", -1},
- BinOpTest{"", "a", -1},
- BinOpTest{"", "abc", -1},
- BinOpTest{"a", "", -1},
- BinOpTest{"a", "a", 0},
- BinOpTest{"aaa", "a", 0},
- BinOpTest{"abc", "xyz", -1},
- BinOpTest{"abc", "xcz", 2},
- BinOpTest{"ab☺c", "x☺yz", 2},
- BinOpTest{"aRegExp*", ".(|)*+?^$[]", 7},
- BinOpTest{dots + dots + dots, " ", -1},
+ {"", "", -1},
+ {"", "a", -1},
+ {"", "abc", -1},
+ {"a", "", -1},
+ {"a", "a", 0},
+ {"aaa", "a", 0},
+ {"abc", "xyz", -1},
+ {"abc", "xcz", 2},
+ {"ab☺c", "x☺yz", 2},
+ {"aRegExp*", ".(|)*+?^$[]", 7},
+ {dots + dots + dots, " ", -1},
+}
+
+var lastIndexAnyTests = []BinOpTest{
+ {"", "", -1},
+ {"", "a", -1},
+ {"", "abc", -1},
+ {"a", "", -1},
+ {"a", "a", 0},
+ {"aaa", "a", 2},
+ {"abc", "xyz", -1},
+ {"abc", "ab", 1},
+ {"a☺b☻c☹d", "uvw☻xyz", 2 + len("☺")},
+ {"a.RegExp*", ".(|)*+?^$[]", 8},
+ {dots + dots + dots, " ", -1},
+}
+
+var indexRuneTests = []BinOpTest{
+ {"", "a", -1},
+ {"", "☺", -1},
+ {"foo", "☹", -1},
+ {"foo", "o", 1},
+ {"foo☺bar", "☺", 3},
+ {"foo☺☻☹bar", "☹", 9},
}
// Execute f on each test case. funcName should be the name of f; it's used
@@ -137,18 +164,23 @@ func runIndexTests(t *testing.T, f func(s, sep []byte) int, funcName string, tes
}
}
-func TestIndex(t *testing.T) { runIndexTests(t, Index, "Index", indexTests) }
-func TestLastIndex(t *testing.T) { runIndexTests(t, LastIndex, "LastIndex", lastIndexTests) }
-func TestIndexAny(t *testing.T) {
- for _, test := range indexAnyTests {
+func runIndexAnyTests(t *testing.T, f func(s []byte, chars string) int, funcName string, testCases []BinOpTest) {
+ for _, test := range testCases {
a := []byte(test.a)
- actual := IndexAny(a, test.b)
+ actual := f(a, test.b)
if actual != test.i {
- t.Errorf("IndexAny(%q,%q) = %v; want %v", a, test.b, actual, test.i)
+ t.Errorf("%s(%q,%q) = %v; want %v", funcName, a, test.b, actual, test.i)
}
}
}
+func TestIndex(t *testing.T) { runIndexTests(t, Index, "Index", indexTests) }
+func TestLastIndex(t *testing.T) { runIndexTests(t, LastIndex, "LastIndex", lastIndexTests) }
+func TestIndexAny(t *testing.T) { runIndexAnyTests(t, IndexAny, "IndexAny", indexAnyTests) }
+func TestLastIndexAny(t *testing.T) {
+ runIndexAnyTests(t, LastIndexAny, "LastIndexAny", lastIndexAnyTests)
+}
+
func TestIndexByte(t *testing.T) {
for _, tt := range indexTests {
if len(tt.b) != 1 {
@@ -167,6 +199,67 @@ func TestIndexByte(t *testing.T) {
}
}
+// test a larger buffer with different sizes and alignments
+func TestIndexByteBig(t *testing.T) {
+ const n = 1024
+ b := make([]byte, n)
+ for i := 0; i < n; i++ {
+ // different start alignments
+ b1 := b[i:]
+ for j := 0; j < len(b1); j++ {
+ b1[j] = 'x'
+ pos := IndexByte(b1, 'x')
+ if pos != j {
+ t.Errorf("IndexByte(%q, 'x') = %v", b1, pos)
+ }
+ b1[j] = 0
+ pos = IndexByte(b1, 'x')
+ if pos != -1 {
+ t.Errorf("IndexByte(%q, 'x') = %v", b1, pos)
+ }
+ }
+ // different end alignments
+ b1 = b[:i]
+ for j := 0; j < len(b1); j++ {
+ b1[j] = 'x'
+ pos := IndexByte(b1, 'x')
+ if pos != j {
+ t.Errorf("IndexByte(%q, 'x') = %v", b1, pos)
+ }
+ b1[j] = 0
+ pos = IndexByte(b1, 'x')
+ if pos != -1 {
+ t.Errorf("IndexByte(%q, 'x') = %v", b1, pos)
+ }
+ }
+ // different start and end alignments
+ b1 = b[i/2 : n-(i+1)/2]
+ for j := 0; j < len(b1); j++ {
+ b1[j] = 'x'
+ pos := IndexByte(b1, 'x')
+ if pos != j {
+ t.Errorf("IndexByte(%q, 'x') = %v", b1, pos)
+ }
+ b1[j] = 0
+ pos = IndexByte(b1, 'x')
+ if pos != -1 {
+ t.Errorf("IndexByte(%q, 'x') = %v", b1, pos)
+ }
+ }
+ }
+}
+
+func TestIndexRune(t *testing.T) {
+ for _, tt := range indexRuneTests {
+ a := []byte(tt.a)
+ r, _ := utf8.DecodeRuneInString(tt.b)
+ pos := IndexRune(a, r)
+ if pos != tt.i {
+ t.Errorf(`IndexRune(%q, '%c') = %v`, tt.a, r, pos)
+ }
+ }
+}
+
func BenchmarkIndexByte4K(b *testing.B) { bmIndex(b, IndexByte, 4<<10) }
func BenchmarkIndexByte4M(b *testing.B) { bmIndex(b, IndexByte, 4<<20) }
@@ -211,9 +304,10 @@ type ExplodeTest struct {
}
var explodetests = []ExplodeTest{
- ExplodeTest{abcd, -1, []string{"a", "b", "c", "d"}},
- ExplodeTest{faces, -1, []string{"☺", "☻", "☹"}},
- ExplodeTest{abcd, 2, []string{"a", "bcd"}},
+ {"", -1, []string{}},
+ {abcd, -1, []string{"a", "b", "c", "d"}},
+ {faces, -1, []string{"☺", "☻", "☹"}},
+ {abcd, 2, []string{"a", "bcd"}},
}
func TestExplode(t *testing.T) {
@@ -240,19 +334,19 @@ type SplitTest struct {
}
var splittests = []SplitTest{
- SplitTest{abcd, "a", 0, nil},
- SplitTest{abcd, "a", -1, []string{"", "bcd"}},
- SplitTest{abcd, "z", -1, []string{"abcd"}},
- SplitTest{abcd, "", -1, []string{"a", "b", "c", "d"}},
- SplitTest{commas, ",", -1, []string{"1", "2", "3", "4"}},
- SplitTest{dots, "...", -1, []string{"1", ".2", ".3", ".4"}},
- SplitTest{faces, "☹", -1, []string{"☺☻", ""}},
- SplitTest{faces, "~", -1, []string{faces}},
- SplitTest{faces, "", -1, []string{"☺", "☻", "☹"}},
- SplitTest{"1 2 3 4", " ", 3, []string{"1", "2", "3 4"}},
- SplitTest{"1 2", " ", 3, []string{"1", "2"}},
- SplitTest{"123", "", 2, []string{"1", "23"}},
- SplitTest{"123", "", 17, []string{"1", "2", "3"}},
+ {abcd, "a", 0, nil},
+ {abcd, "a", -1, []string{"", "bcd"}},
+ {abcd, "z", -1, []string{"abcd"}},
+ {abcd, "", -1, []string{"a", "b", "c", "d"}},
+ {commas, ",", -1, []string{"1", "2", "3", "4"}},
+ {dots, "...", -1, []string{"1", ".2", ".3", ".4"}},
+ {faces, "☹", -1, []string{"☺☻", ""}},
+ {faces, "~", -1, []string{faces}},
+ {faces, "", -1, []string{"☺", "☻", "☹"}},
+ {"1 2 3 4", " ", 3, []string{"1", "2", "3 4"}},
+ {"1 2", " ", 3, []string{"1", "2"}},
+ {"123", "", 2, []string{"1", "23"}},
+ {"123", "", 17, []string{"1", "2", "3"}},
}
func TestSplit(t *testing.T) {
@@ -274,19 +368,19 @@ func TestSplit(t *testing.T) {
}
var splitaftertests = []SplitTest{
- SplitTest{abcd, "a", -1, []string{"a", "bcd"}},
- SplitTest{abcd, "z", -1, []string{"abcd"}},
- SplitTest{abcd, "", -1, []string{"a", "b", "c", "d"}},
- SplitTest{commas, ",", -1, []string{"1,", "2,", "3,", "4"}},
- SplitTest{dots, "...", -1, []string{"1...", ".2...", ".3...", ".4"}},
- SplitTest{faces, "☹", -1, []string{"☺☻☹", ""}},
- SplitTest{faces, "~", -1, []string{faces}},
- SplitTest{faces, "", -1, []string{"☺", "☻", "☹"}},
- SplitTest{"1 2 3 4", " ", 3, []string{"1 ", "2 ", "3 4"}},
- SplitTest{"1 2 3", " ", 3, []string{"1 ", "2 ", "3"}},
- SplitTest{"1 2", " ", 3, []string{"1 ", "2"}},
- SplitTest{"123", "", 2, []string{"1", "23"}},
- SplitTest{"123", "", 17, []string{"1", "2", "3"}},
+ {abcd, "a", -1, []string{"a", "bcd"}},
+ {abcd, "z", -1, []string{"abcd"}},
+ {abcd, "", -1, []string{"a", "b", "c", "d"}},
+ {commas, ",", -1, []string{"1,", "2,", "3,", "4"}},
+ {dots, "...", -1, []string{"1...", ".2...", ".3...", ".4"}},
+ {faces, "☹", -1, []string{"☺☻☹", ""}},
+ {faces, "~", -1, []string{faces}},
+ {faces, "", -1, []string{"☺", "☻", "☹"}},
+ {"1 2 3 4", " ", 3, []string{"1 ", "2 ", "3 4"}},
+ {"1 2 3", " ", 3, []string{"1 ", "2 ", "3"}},
+ {"1 2", " ", 3, []string{"1 ", "2"}},
+ {"123", "", 2, []string{"1", "23"}},
+ {"123", "", 17, []string{"1", "2", "3"}},
}
func TestSplitAfter(t *testing.T) {
@@ -310,17 +404,17 @@ type FieldsTest struct {
}
var fieldstests = []FieldsTest{
- FieldsTest{"", []string{}},
- FieldsTest{" ", []string{}},
- FieldsTest{" \t ", []string{}},
- FieldsTest{" abc ", []string{"abc"}},
- FieldsTest{"1 2 3 4", []string{"1", "2", "3", "4"}},
- FieldsTest{"1 2 3 4", []string{"1", "2", "3", "4"}},
- FieldsTest{"1\t\t2\t\t3\t4", []string{"1", "2", "3", "4"}},
- FieldsTest{"1\u20002\u20013\u20024", []string{"1", "2", "3", "4"}},
- FieldsTest{"\u2000\u2001\u2002", []string{}},
- FieldsTest{"\n™\t™\n", []string{"™", "™"}},
- FieldsTest{faces, []string{faces}},
+ {"", []string{}},
+ {" ", []string{}},
+ {" \t ", []string{}},
+ {" abc ", []string{"abc"}},
+ {"1 2 3 4", []string{"1", "2", "3", "4"}},
+ {"1 2 3 4", []string{"1", "2", "3", "4"}},
+ {"1\t\t2\t\t3\t4", []string{"1", "2", "3", "4"}},
+ {"1\u20002\u20013\u20024", []string{"1", "2", "3", "4"}},
+ {"\u2000\u2001\u2002", []string{}},
+ {"\n™\t™\n", []string{"™", "™"}},
+ {faces, []string{faces}},
}
func TestFields(t *testing.T) {
@@ -334,6 +428,23 @@ func TestFields(t *testing.T) {
}
}
+func TestFieldsFunc(t *testing.T) {
+ pred := func(c int) bool { return c == 'X' }
+ var fieldsFuncTests = []FieldsTest{
+ {"", []string{}},
+ {"XX", []string{}},
+ {"XXhiXXX", []string{"hi"}},
+ {"aXXbXXXcX", []string{"a", "b", "c"}},
+ }
+ for _, tt := range fieldsFuncTests {
+ a := FieldsFunc([]byte(tt.s), pred)
+ result := arrayOfString(a)
+ if !eq(result, tt.a) {
+ t.Errorf("FieldsFunc(%q) = %v, want %v", tt.s, a, tt.a)
+ }
+ }
+}
+
// Test case for any function which accepts and returns a byte array.
// For ease of creation, we write the byte arrays as strings.
type StringTest struct {
@@ -341,51 +452,47 @@ type StringTest struct {
}
var upperTests = []StringTest{
- StringTest{"", ""},
- StringTest{"abc", "ABC"},
- StringTest{"AbC123", "ABC123"},
- StringTest{"azAZ09_", "AZAZ09_"},
- StringTest{"\u0250\u0250\u0250\u0250\u0250", "\u2C6F\u2C6F\u2C6F\u2C6F\u2C6F"}, // grows one byte per char
+ {"", ""},
+ {"abc", "ABC"},
+ {"AbC123", "ABC123"},
+ {"azAZ09_", "AZAZ09_"},
+ {"\u0250\u0250\u0250\u0250\u0250", "\u2C6F\u2C6F\u2C6F\u2C6F\u2C6F"}, // grows one byte per char
}
var lowerTests = []StringTest{
- StringTest{"", ""},
- StringTest{"abc", "abc"},
- StringTest{"AbC123", "abc123"},
- StringTest{"azAZ09_", "azaz09_"},
- StringTest{"\u2C6D\u2C6D\u2C6D\u2C6D\u2C6D", "\u0251\u0251\u0251\u0251\u0251"}, // shrinks one byte per char
+ {"", ""},
+ {"abc", "abc"},
+ {"AbC123", "abc123"},
+ {"azAZ09_", "azaz09_"},
+ {"\u2C6D\u2C6D\u2C6D\u2C6D\u2C6D", "\u0251\u0251\u0251\u0251\u0251"}, // shrinks one byte per char
}
const space = "\t\v\r\f\n\u0085\u00a0\u2000\u3000"
var trimSpaceTests = []StringTest{
- StringTest{"", ""},
- StringTest{"abc", "abc"},
- StringTest{space + "abc" + space, "abc"},
- StringTest{" ", ""},
- StringTest{" \t\r\n \t\t\r\r\n\n ", ""},
- StringTest{" \t\r\n x\t\t\r\r\n\n ", "x"},
- StringTest{" \u2000\t\r\n x\t\t\r\r\ny\n \u3000", "x\t\t\r\r\ny"},
- StringTest{"1 \t\r\n2", "1 \t\r\n2"},
- StringTest{" x\x80", "x\x80"}, // invalid UTF-8 on end
- StringTest{" x\xc0", "x\xc0"}, // invalid UTF-8 on end
-}
-
-// Bytes returns a new slice containing the bytes in s.
-// Borrowed from strings to avoid dependency.
-func Bytes(s string) []byte {
- b := make([]byte, len(s))
- for i := 0; i < len(s); i++ {
- b[i] = s[i]
- }
- return b
+ {"", ""},
+ {"abc", "abc"},
+ {space + "abc" + space, "abc"},
+ {" ", ""},
+ {" \t\r\n \t\t\r\r\n\n ", ""},
+ {" \t\r\n x\t\t\r\r\n\n ", "x"},
+ {" \u2000\t\r\n x\t\t\r\r\ny\n \u3000", "x\t\t\r\r\ny"},
+ {"1 \t\r\n2", "1 \t\r\n2"},
+ {" x\x80", "x\x80"},
+ {" x\xc0", "x\xc0"},
+ {"x \xc0\xc0 ", "x \xc0\xc0"},
+ {"x \xc0", "x \xc0"},
+ {"x \xc0 ", "x \xc0"},
+ {"x \xc0\xc0 ", "x \xc0\xc0"},
+ {"x ☺\xc0\xc0 ", "x ☺\xc0\xc0"},
+ {"x ☺ ", "x ☺"},
}
// Execute f on each test case. funcName should be the name of f; it's used
// in failure reports.
func runStringTests(t *testing.T, f func([]byte) []byte, funcName string, testCases []StringTest) {
for _, tc := range testCases {
- actual := string(f(Bytes(tc.in)))
+ actual := string(f([]byte(tc.in)))
if actual != tc.out {
t.Errorf("%s(%q) = %q; want %q", funcName, tc.in, actual, tc.out)
}
@@ -418,7 +525,7 @@ func TestMap(t *testing.T) {
// 1. Grow. This triggers two reallocations in Map.
maxRune := func(rune int) int { return unicode.MaxRune }
- m := Map(maxRune, Bytes(a))
+ m := Map(maxRune, []byte(a))
expect := tenRunes(unicode.MaxRune)
if string(m) != expect {
t.Errorf("growing: expected %q got %q", expect, m)
@@ -426,21 +533,21 @@ func TestMap(t *testing.T) {
// 2. Shrink
minRune := func(rune int) int { return 'a' }
- m = Map(minRune, Bytes(tenRunes(unicode.MaxRune)))
+ m = Map(minRune, []byte(tenRunes(unicode.MaxRune)))
expect = a
if string(m) != expect {
t.Errorf("shrinking: expected %q got %q", expect, m)
}
// 3. Rot13
- m = Map(rot13, Bytes("a to zed"))
+ m = Map(rot13, []byte("a to zed"))
expect = "n gb mrq"
if string(m) != expect {
t.Errorf("rot13: expected %q got %q", expect, m)
}
// 4. Rot13^2
- m = Map(rot13, Map(rot13, Bytes("a to zed")))
+ m = Map(rot13, Map(rot13, []byte("a to zed")))
expect = "a to zed"
if string(m) != expect {
t.Errorf("rot13: expected %q got %q", expect, m)
@@ -453,7 +560,7 @@ func TestMap(t *testing.T) {
}
return -1
}
- m = Map(dropNotLatin, Bytes("Hello, 세계"))
+ m = Map(dropNotLatin, []byte("Hello, 세계"))
expect = "Hello"
if string(m) != expect {
t.Errorf("drop: expected %q got %q", expect, m)
@@ -466,60 +573,19 @@ func TestToLower(t *testing.T) { runStringTests(t, ToLower, "ToLower", lowerTest
func TestTrimSpace(t *testing.T) { runStringTests(t, TrimSpace, "TrimSpace", trimSpaceTests) }
-type AddTest struct {
- s, t string
- cap int
-}
-
-var addtests = []AddTest{
- AddTest{"", "", 0},
- AddTest{"a", "", 1},
- AddTest{"a", "b", 1},
- AddTest{"abc", "def", 100},
-}
-
-func TestAdd(t *testing.T) {
- for _, test := range addtests {
- b := make([]byte, len(test.s), test.cap)
- for i := 0; i < len(test.s); i++ {
- b[i] = test.s[i]
- }
- b = Add(b, []byte(test.t))
- if string(b) != test.s+test.t {
- t.Errorf("Add(%q,%q) = %q", test.s, test.t, string(b))
- }
- }
-}
-
-func TestAddByte(t *testing.T) {
- const N = 2e5
- b := make([]byte, 0)
- for i := 0; i < N; i++ {
- b = AddByte(b, byte(i))
- }
- if len(b) != N {
- t.Errorf("AddByte: too small; expected %d got %d", N, len(b))
- }
- for i, c := range b {
- if c != byte(i) {
- t.Fatalf("AddByte: b[%d] should be %d is %d", i, c, byte(i))
- }
- }
-}
-
type RepeatTest struct {
in, out string
count int
}
var RepeatTests = []RepeatTest{
- RepeatTest{"", "", 0},
- RepeatTest{"", "", 1},
- RepeatTest{"", "", 2},
- RepeatTest{"-", "", 0},
- RepeatTest{"-", "-", 1},
- RepeatTest{"-", "----------", 10},
- RepeatTest{"abc ", "abc abc abc ", 3},
+ {"", "", 0},
+ {"", "", 1},
+ {"", "", 2},
+ {"-", "", 0},
+ {"-", "-", 1},
+ {"-", "----------", 10},
+ {"abc ", "abc abc abc ", 3},
}
func TestRepeat(t *testing.T) {
@@ -553,13 +619,13 @@ type RunesTest struct {
}
var RunesTests = []RunesTest{
- RunesTest{"", []int{}, false},
- RunesTest{" ", []int{32}, false},
- RunesTest{"ABC", []int{65, 66, 67}, false},
- RunesTest{"abc", []int{97, 98, 99}, false},
- RunesTest{"\u65e5\u672c\u8a9e", []int{26085, 26412, 35486}, false},
- RunesTest{"ab\x80c", []int{97, 98, 0xFFFD, 99}, true},
- RunesTest{"ab\xc0c", []int{97, 98, 0xFFFD, 99}, true},
+ {"", []int{}, false},
+ {" ", []int{32}, false},
+ {"ABC", []int{65, 66, 67}, false},
+ {"abc", []int{97, 98, 99}, false},
+ {"\u65e5\u672c\u8a9e", []int{26085, 26412, 35486}, false},
+ {"ab\x80c", []int{97, 98, 0xFFFD, 99}, true},
+ {"ab\xc0c", []int{97, 98, 0xFFFD, 99}, true},
}
func TestRunes(t *testing.T) {
@@ -587,26 +653,27 @@ type TrimTest struct {
}
var trimTests = []TrimTest{
- TrimTest{Trim, "abba", "a", "bb"},
- TrimTest{Trim, "abba", "ab", ""},
- TrimTest{TrimLeft, "abba", "ab", ""},
- TrimTest{TrimRight, "abba", "ab", ""},
- TrimTest{TrimLeft, "abba", "a", "bba"},
- TrimTest{TrimRight, "abba", "a", "abb"},
- TrimTest{Trim, "<tag>", "<>", "tag"},
- TrimTest{Trim, "* listitem", " *", "listitem"},
- TrimTest{Trim, `"quote"`, `"`, "quote"},
- TrimTest{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
- TrimTest{Trim, "abba", "", "abba"},
- TrimTest{Trim, "", "123", ""},
- TrimTest{Trim, "", "", ""},
- TrimTest{TrimLeft, "abba", "", "abba"},
- TrimTest{TrimLeft, "", "123", ""},
- TrimTest{TrimLeft, "", "", ""},
- TrimTest{TrimRight, "abba", "", "abba"},
- TrimTest{TrimRight, "", "123", ""},
- TrimTest{TrimRight, "", "", ""},
+ {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) {
@@ -629,22 +696,90 @@ func TestTrim(t *testing.T) {
}
}
+type predicate struct {
+ f func(r int) bool
+ name string
+}
+
+var isSpace = predicate{unicode.IsSpace, "IsSpace"}
+var isDigit = predicate{unicode.IsDigit, "IsDigit"}
+var isUpper = predicate{unicode.IsUpper, "IsUpper"}
+var isValidRune = predicate{
+ func(r int) bool {
+ return r != utf8.RuneError
+ },
+ "IsValidRune",
+}
+
type TrimFuncTest struct {
- f func(r int) bool
- name, in, out string
+ f predicate
+ in, out string
+}
+
+func not(p predicate) predicate {
+ return predicate{
+ func(r int) bool {
+ return !p.f(r)
+ },
+ "not " + p.name,
+ }
}
var trimFuncTests = []TrimFuncTest{
- TrimFuncTest{unicode.IsSpace, "IsSpace", space + " hello " + space, "hello"},
- TrimFuncTest{unicode.IsDigit, "IsDigit", "\u0e50\u0e5212hello34\u0e50\u0e51", "hello"},
- TrimFuncTest{unicode.IsUpper, "IsUpper", "\u2C6F\u2C6F\u2C6F\u2C6FABCDhelloEF\u2C6F\u2C6FGH\u2C6F\u2C6F", "hello"},
+ {isSpace, space + " hello " + space, "hello"},
+ {isDigit, "\u0e50\u0e5212hello34\u0e50\u0e51", "hello"},
+ {isUpper, "\u2C6F\u2C6F\u2C6F\u2C6FABCDhelloEF\u2C6F\u2C6FGH\u2C6F\u2C6F", "hello"},
+ {not(isSpace), "hello" + space + "hello", space},
+ {not(isDigit), "hello\u0e50\u0e521234\u0e50\u0e51helo", "\u0e50\u0e521234\u0e50\u0e51"},
+ {isValidRune, "ab\xc0a\xc0cd", "\xc0a\xc0"},
+ {not(isValidRune), "\xc0a\xc0", "a"},
}
func TestTrimFunc(t *testing.T) {
for _, tc := range trimFuncTests {
- actual := string(TrimFunc([]byte(tc.in), tc.f))
+ actual := string(TrimFunc([]byte(tc.in), tc.f.f))
if actual != tc.out {
- t.Errorf("TrimFunc(%q, %q) = %q; want %q", tc.in, tc.name, actual, tc.out)
+ t.Errorf("TrimFunc(%q, %q) = %q; want %q", tc.in, tc.f.name, actual, tc.out)
+ }
+ }
+}
+
+type IndexFuncTest struct {
+ in string
+ f predicate
+ first, last int
+}
+
+var indexFuncTests = []IndexFuncTest{
+ {"", isValidRune, -1, -1},
+ {"abc", isDigit, -1, -1},
+ {"0123", isDigit, 0, 3},
+ {"a1b", isDigit, 1, 1},
+ {space, isSpace, 0, len(space) - 3}, // last rune in space is 3 bytes
+ {"\u0e50\u0e5212hello34\u0e50\u0e51", isDigit, 0, 18},
+ {"\u2C6F\u2C6F\u2C6F\u2C6FABCDhelloEF\u2C6F\u2C6FGH\u2C6F\u2C6F", isUpper, 0, 34},
+ {"12\u0e50\u0e52hello34\u0e50\u0e51", not(isDigit), 8, 12},
+
+ // tests of invalid UTF-8
+ {"\x801", isDigit, 1, 1},
+ {"\x80abc", isDigit, -1, -1},
+ {"\xc0a\xc0", isValidRune, 1, 1},
+ {"\xc0a\xc0", not(isValidRune), 0, 2},
+ {"\xc0☺\xc0", not(isValidRune), 0, 4},
+ {"\xc0☺\xc0\xc0", not(isValidRune), 0, 5},
+ {"ab\xc0a\xc0cd", not(isValidRune), 2, 4},
+ {"a\xe0\x80cd", not(isValidRune), 1, 2},
+}
+
+func TestIndexFunc(t *testing.T) {
+ for _, tc := range indexFuncTests {
+ first := IndexFunc([]byte(tc.in), tc.f.f)
+ if first != tc.first {
+ t.Errorf("IndexFunc(%q, %s) = %d; want %d", tc.in, tc.f.name, first, tc.first)
+ }
+ last := LastIndexFunc([]byte(tc.in), tc.f.f)
+ if last != tc.last {
+ t.Errorf("LastIndexFunc(%q, %s) = %d; want %d", tc.in, tc.f.name, last, tc.last)
}
}
}
@@ -657,25 +792,25 @@ type ReplaceTest struct {
}
var ReplaceTests = []ReplaceTest{
- ReplaceTest{"hello", "l", "L", 0, "hello"},
- ReplaceTest{"hello", "l", "L", -1, "heLLo"},
- ReplaceTest{"hello", "x", "X", -1, "hello"},
- ReplaceTest{"", "x", "X", -1, ""},
- ReplaceTest{"radar", "r", "<r>", -1, "<r>ada<r>"},
- ReplaceTest{"", "", "<>", -1, "<>"},
- ReplaceTest{"banana", "a", "<>", -1, "b<>n<>n<>"},
- ReplaceTest{"banana", "a", "<>", 1, "b<>nana"},
- ReplaceTest{"banana", "a", "<>", 1000, "b<>n<>n<>"},
- ReplaceTest{"banana", "an", "<>", -1, "b<><>a"},
- ReplaceTest{"banana", "ana", "<>", -1, "b<>na"},
- ReplaceTest{"banana", "", "<>", -1, "<>b<>a<>n<>a<>n<>a<>"},
- ReplaceTest{"banana", "", "<>", 10, "<>b<>a<>n<>a<>n<>a<>"},
- ReplaceTest{"banana", "", "<>", 6, "<>b<>a<>n<>a<>n<>a"},
- ReplaceTest{"banana", "", "<>", 5, "<>b<>a<>n<>a<>na"},
- ReplaceTest{"banana", "", "<>", 1, "<>banana"},
- ReplaceTest{"banana", "a", "a", -1, "banana"},
- ReplaceTest{"banana", "a", "a", 1, "banana"},
- ReplaceTest{"☺☻☹", "", "<>", -1, "<>☺<>☻<>☹<>"},
+ {"hello", "l", "L", 0, "hello"},
+ {"hello", "l", "L", -1, "heLLo"},
+ {"hello", "x", "X", -1, "hello"},
+ {"", "x", "X", -1, ""},
+ {"radar", "r", "<r>", -1, "<r>ada<r>"},
+ {"", "", "<>", -1, "<>"},
+ {"banana", "a", "<>", -1, "b<>n<>n<>"},
+ {"banana", "a", "<>", 1, "b<>nana"},
+ {"banana", "a", "<>", 1000, "b<>n<>n<>"},
+ {"banana", "an", "<>", -1, "b<><>a"},
+ {"banana", "ana", "<>", -1, "b<>na"},
+ {"banana", "", "<>", -1, "<>b<>a<>n<>a<>n<>a<>"},
+ {"banana", "", "<>", 10, "<>b<>a<>n<>a<>n<>a<>"},
+ {"banana", "", "<>", 6, "<>b<>a<>n<>a<>n<>a"},
+ {"banana", "", "<>", 5, "<>b<>a<>n<>a<>na"},
+ {"banana", "", "<>", 1, "<>banana"},
+ {"banana", "a", "a", -1, "banana"},
+ {"banana", "a", "a", 1, "banana"},
+ {"☺☻☹", "", "<>", -1, "<>☺<>☻<>☹<>"},
}
func TestReplace(t *testing.T) {
@@ -685,3 +820,25 @@ func TestReplace(t *testing.T) {
}
}
}
+
+type TitleTest struct {
+ in, out string
+}
+
+var TitleTests = []TitleTest{
+ {"", ""},
+ {"a", "A"},
+ {" aaa aaa aaa ", " Aaa Aaa Aaa "},
+ {" Aaa Aaa Aaa ", " Aaa Aaa Aaa "},
+ {"123a456", "123a456"},
+ {"double-blind", "Double-Blind"},
+ {"ÿøû", "Ÿøû"},
+}
+
+func TestTitle(t *testing.T) {
+ for _, tt := range TitleTests {
+ if s := string(Title([]byte(tt.in))); s != tt.out {
+ t.Errorf("Title(%q) = %q, want %q", tt.in, s, tt.out)
+ }
+ }
+}
diff --git a/src/pkg/cmath/Makefile b/src/pkg/cmath/Makefile
index 1936fbda1..486caace4 100644
--- a/src/pkg/cmath/Makefile
+++ b/src/pkg/cmath/Makefile
@@ -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 ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=cmath
diff --git a/src/pkg/cmath/cmath_test.go b/src/pkg/cmath/cmath_test.go
index 25e4f2254..93fac4e20 100644
--- a/src/pkg/cmath/cmath_test.go
+++ b/src/pkg/cmath/cmath_test.go
@@ -203,16 +203,16 @@ type ff struct {
}
var polar = []ff{
- ff{9.2022120669932650313380972e+00, 9.9909115046919291062461269e-01},
- ff{7.7438239742296106616261394e+00, -3.5762575021856971295156489e-02},
- ff{5.0182478202557746902556648e+00, -1.6259990074019058442232221e+00},
- ff{1.0861137372799545160704002e+01, 2.0502936359659111755031062e+00},
- ff{1.0070841084922199607011905e+01, 2.9483213155446756211881774e-01},
- ff{5.9922447613166942183705192e+00, 1.0605860367252556281902109e+00},
- ff{5.8978784056736762299945176e+00, 4.8084556083358307819310911e-01},
- ff{3.2822866700678709020367184e+00, 5.8969634164776659423195222e-01},
- ff{8.8756430028990417290744307e+00, -1.3636647724582455028314573e+00},
- ff{1.0011785496777731986390856e+01, 2.6210913895386013290915234e+00},
+ {9.2022120669932650313380972e+00, 9.9909115046919291062461269e-01},
+ {7.7438239742296106616261394e+00, -3.5762575021856971295156489e-02},
+ {5.0182478202557746902556648e+00, -1.6259990074019058442232221e+00},
+ {1.0861137372799545160704002e+01, 2.0502936359659111755031062e+00},
+ {1.0070841084922199607011905e+01, 2.9483213155446756211881774e-01},
+ {5.9922447613166942183705192e+00, 1.0605860367252556281902109e+00},
+ {5.8978784056736762299945176e+00, 4.8084556083358307819310911e-01},
+ {3.2822866700678709020367184e+00, 5.8969634164776659423195222e-01},
+ {8.8756430028990417290744307e+00, -1.3636647724582455028314573e+00},
+ {1.0011785496777731986390856e+01, 2.6210913895386013290915234e+00},
}
var pow = []complex128{
(-2.499956739197529585028819e+00 + 1.759751724335650228957144e+00i),
@@ -392,10 +392,10 @@ var vcPolarSC = []complex128{
NaN(),
}
var polarSC = []ff{
- ff{math.NaN(), math.NaN()},
+ {math.NaN(), math.NaN()},
}
var vcPowSC = [][2]complex128{
- [2]complex128{NaN(), NaN()},
+ {NaN(), NaN()},
}
var powSC = []complex128{
NaN(),
@@ -483,175 +483,175 @@ func cAlike(a, b complex128) bool {
func TestAbs(t *testing.T) {
for i := 0; i < len(vc); i++ {
if f := Abs(vc[i]); !veryclose(abs[i], f) {
- t.Errorf("Abs(%g) = %g, want %g\n", vc[i], f, abs[i])
+ t.Errorf("Abs(%g) = %g, want %g", vc[i], f, abs[i])
}
}
for i := 0; i < len(vcAbsSC); i++ {
if f := Abs(vcAbsSC[i]); !alike(absSC[i], f) {
- t.Errorf("Abs(%g) = %g, want %g\n", vcAbsSC[i], f, absSC[i])
+ t.Errorf("Abs(%g) = %g, want %g", vcAbsSC[i], f, absSC[i])
}
}
}
func TestAcos(t *testing.T) {
for i := 0; i < len(vc); i++ {
if f := Acos(vc[i]); !cSoclose(acos[i], f, 1e-14) {
- t.Errorf("Acos(%g) = %g, want %g\n", vc[i], f, acos[i])
+ t.Errorf("Acos(%g) = %g, want %g", vc[i], f, acos[i])
}
}
for i := 0; i < len(vcAcosSC); i++ {
if f := Acos(vcAcosSC[i]); !cAlike(acosSC[i], f) {
- t.Errorf("Acos(%g) = %g, want %g\n", vcAcosSC[i], f, acosSC[i])
+ t.Errorf("Acos(%g) = %g, want %g", vcAcosSC[i], f, acosSC[i])
}
}
}
func TestAcosh(t *testing.T) {
for i := 0; i < len(vc); i++ {
if f := Acosh(vc[i]); !cSoclose(acosh[i], f, 1e-14) {
- t.Errorf("Acosh(%g) = %g, want %g\n", vc[i], f, acosh[i])
+ t.Errorf("Acosh(%g) = %g, want %g", vc[i], f, acosh[i])
}
}
for i := 0; i < len(vcAcoshSC); i++ {
if f := Acosh(vcAcoshSC[i]); !cAlike(acoshSC[i], f) {
- t.Errorf("Acosh(%g) = %g, want %g\n", vcAcoshSC[i], f, acoshSC[i])
+ t.Errorf("Acosh(%g) = %g, want %g", vcAcoshSC[i], f, acoshSC[i])
}
}
}
func TestAsin(t *testing.T) {
for i := 0; i < len(vc); i++ {
if f := Asin(vc[i]); !cSoclose(asin[i], f, 1e-14) {
- t.Errorf("Asin(%g) = %g, want %g\n", vc[i], f, asin[i])
+ t.Errorf("Asin(%g) = %g, want %g", vc[i], f, asin[i])
}
}
for i := 0; i < len(vcAsinSC); i++ {
if f := Asin(vcAsinSC[i]); !cAlike(asinSC[i], f) {
- t.Errorf("Asin(%g) = %g, want %g\n", vcAsinSC[i], f, asinSC[i])
+ t.Errorf("Asin(%g) = %g, want %g", vcAsinSC[i], f, asinSC[i])
}
}
}
func TestAsinh(t *testing.T) {
for i := 0; i < len(vc); i++ {
if f := Asinh(vc[i]); !cSoclose(asinh[i], f, 4e-15) {
- t.Errorf("Asinh(%g) = %g, want %g\n", vc[i], f, asinh[i])
+ t.Errorf("Asinh(%g) = %g, want %g", vc[i], f, asinh[i])
}
}
for i := 0; i < len(vcAsinhSC); i++ {
if f := Asinh(vcAsinhSC[i]); !cAlike(asinhSC[i], f) {
- t.Errorf("Asinh(%g) = %g, want %g\n", vcAsinhSC[i], f, asinhSC[i])
+ t.Errorf("Asinh(%g) = %g, want %g", vcAsinhSC[i], f, asinhSC[i])
}
}
}
func TestAtan(t *testing.T) {
for i := 0; i < len(vc); i++ {
if f := Atan(vc[i]); !cVeryclose(atan[i], f) {
- t.Errorf("Atan(%g) = %g, want %g\n", vc[i], f, atan[i])
+ t.Errorf("Atan(%g) = %g, want %g", vc[i], f, atan[i])
}
}
for i := 0; i < len(vcAtanSC); i++ {
if f := Atan(vcAtanSC[i]); !cAlike(atanSC[i], f) {
- t.Errorf("Atan(%g) = %g, want %g\n", vcAtanSC[i], f, atanSC[i])
+ t.Errorf("Atan(%g) = %g, want %g", vcAtanSC[i], f, atanSC[i])
}
}
}
func TestAtanh(t *testing.T) {
for i := 0; i < len(vc); i++ {
if f := Atanh(vc[i]); !cVeryclose(atanh[i], f) {
- t.Errorf("Atanh(%g) = %g, want %g\n", vc[i], f, atanh[i])
+ t.Errorf("Atanh(%g) = %g, want %g", vc[i], f, atanh[i])
}
}
for i := 0; i < len(vcAtanhSC); i++ {
if f := Atanh(vcAtanhSC[i]); !cAlike(atanhSC[i], f) {
- t.Errorf("Atanh(%g) = %g, want %g\n", vcAtanhSC[i], f, atanhSC[i])
+ t.Errorf("Atanh(%g) = %g, want %g", vcAtanhSC[i], f, atanhSC[i])
}
}
}
func TestConj(t *testing.T) {
for i := 0; i < len(vc); i++ {
if f := Conj(vc[i]); !cVeryclose(conj[i], f) {
- t.Errorf("Conj(%g) = %g, want %g\n", vc[i], f, conj[i])
+ t.Errorf("Conj(%g) = %g, want %g", vc[i], f, conj[i])
}
}
for i := 0; i < len(vcConjSC); i++ {
if f := Conj(vcConjSC[i]); !cAlike(conjSC[i], f) {
- t.Errorf("Conj(%g) = %g, want %g\n", vcConjSC[i], f, conjSC[i])
+ t.Errorf("Conj(%g) = %g, want %g", vcConjSC[i], f, conjSC[i])
}
}
}
func TestCos(t *testing.T) {
for i := 0; i < len(vc); i++ {
if f := Cos(vc[i]); !cSoclose(cos[i], f, 3e-15) {
- t.Errorf("Cos(%g) = %g, want %g\n", vc[i], f, cos[i])
+ t.Errorf("Cos(%g) = %g, want %g", vc[i], f, cos[i])
}
}
for i := 0; i < len(vcCosSC); i++ {
if f := Cos(vcCosSC[i]); !cAlike(cosSC[i], f) {
- t.Errorf("Cos(%g) = %g, want %g\n", vcCosSC[i], f, cosSC[i])
+ t.Errorf("Cos(%g) = %g, want %g", vcCosSC[i], f, cosSC[i])
}
}
}
func TestCosh(t *testing.T) {
for i := 0; i < len(vc); i++ {
if f := Cosh(vc[i]); !cSoclose(cosh[i], f, 2e-15) {
- t.Errorf("Cosh(%g) = %g, want %g\n", vc[i], f, cosh[i])
+ t.Errorf("Cosh(%g) = %g, want %g", vc[i], f, cosh[i])
}
}
for i := 0; i < len(vcCoshSC); i++ {
if f := Cosh(vcCoshSC[i]); !cAlike(coshSC[i], f) {
- t.Errorf("Cosh(%g) = %g, want %g\n", vcCoshSC[i], f, coshSC[i])
+ t.Errorf("Cosh(%g) = %g, want %g", vcCoshSC[i], f, coshSC[i])
}
}
}
func TestExp(t *testing.T) {
for i := 0; i < len(vc); i++ {
if f := Exp(vc[i]); !cSoclose(exp[i], f, 1e-15) {
- t.Errorf("Exp(%g) = %g, want %g\n", vc[i], f, exp[i])
+ t.Errorf("Exp(%g) = %g, want %g", vc[i], f, exp[i])
}
}
for i := 0; i < len(vcExpSC); i++ {
if f := Exp(vcExpSC[i]); !cAlike(expSC[i], f) {
- t.Errorf("Exp(%g) = %g, want %g\n", vcExpSC[i], f, expSC[i])
+ t.Errorf("Exp(%g) = %g, want %g", vcExpSC[i], f, expSC[i])
}
}
}
func TestIsNaN(t *testing.T) {
for i := 0; i < len(vcIsNaNSC); i++ {
if f := IsNaN(vcIsNaNSC[i]); isNaNSC[i] != f {
- t.Errorf("IsNaN(%g) = %g, want %g\n", vcIsNaNSC[i], f, isNaNSC[i])
+ t.Errorf("IsNaN(%g) = %g, want %g", vcIsNaNSC[i], f, isNaNSC[i])
}
}
}
func TestLog(t *testing.T) {
for i := 0; i < len(vc); i++ {
if f := Log(vc[i]); !cVeryclose(log[i], f) {
- t.Errorf("Log(%g) = %g, want %g\n", vc[i], f, log[i])
+ t.Errorf("Log(%g) = %g, want %g", vc[i], f, log[i])
}
}
for i := 0; i < len(vcLogSC); i++ {
if f := Log(vcLogSC[i]); !cAlike(logSC[i], f) {
- t.Errorf("Log(%g) = %g, want %g\n", vcLogSC[i], f, logSC[i])
+ t.Errorf("Log(%g) = %g, want %g", vcLogSC[i], f, logSC[i])
}
}
}
func TestLog10(t *testing.T) {
for i := 0; i < len(vc); i++ {
if f := Log10(vc[i]); !cVeryclose(log10[i], f) {
- t.Errorf("Log10(%g) = %g, want %g\n", vc[i], f, log10[i])
+ t.Errorf("Log10(%g) = %g, want %g", vc[i], f, log10[i])
}
}
for i := 0; i < len(vcLog10SC); i++ {
if f := Log10(vcLog10SC[i]); !cAlike(log10SC[i], f) {
- t.Errorf("Log10(%g) = %g, want %g\n", vcLog10SC[i], f, log10SC[i])
+ t.Errorf("Log10(%g) = %g, want %g", vcLog10SC[i], f, log10SC[i])
}
}
}
func TestPolar(t *testing.T) {
for i := 0; i < len(vc); i++ {
if r, theta := Polar(vc[i]); !veryclose(polar[i].r, r) && !veryclose(polar[i].theta, theta) {
- t.Errorf("Polar(%g) = %g, %g want %g, %g\n", vc[i], r, theta, polar[i].r, polar[i].theta)
+ t.Errorf("Polar(%g) = %g, %g want %g, %g", vc[i], r, theta, polar[i].r, polar[i].theta)
}
}
for i := 0; i < len(vcPolarSC); i++ {
if r, theta := Polar(vcPolarSC[i]); !alike(polarSC[i].r, r) && !alike(polarSC[i].theta, theta) {
- t.Errorf("Polar(%g) = %g, %g, want %g, %g\n", vcPolarSC[i], r, theta, polarSC[i].r, polarSC[i].theta)
+ t.Errorf("Polar(%g) = %g, %g, want %g, %g", vcPolarSC[i], r, theta, polarSC[i].r, polarSC[i].theta)
}
}
}
@@ -659,84 +659,84 @@ func TestPow(t *testing.T) {
var a = cmplx(float64(3), float64(3))
for i := 0; i < len(vc); i++ {
if f := Pow(a, vc[i]); !cSoclose(pow[i], f, 4e-15) {
- t.Errorf("Pow(%g, %g) = %g, want %g\n", a, vc[i], f, pow[i])
+ t.Errorf("Pow(%g, %g) = %g, want %g", a, vc[i], f, pow[i])
}
}
for i := 0; i < len(vcPowSC); i++ {
if f := Pow(vcPowSC[i][0], vcPowSC[i][0]); !cAlike(powSC[i], f) {
- t.Errorf("Pow(%g, %g) = %g, want %g\n", vcPowSC[i][0], vcPowSC[i][0], f, powSC[i])
+ t.Errorf("Pow(%g, %g) = %g, want %g", vcPowSC[i][0], vcPowSC[i][0], f, powSC[i])
}
}
}
func TestRect(t *testing.T) {
for i := 0; i < len(vc); i++ {
if f := Rect(polar[i].r, polar[i].theta); !cVeryclose(vc[i], f) {
- t.Errorf("Rect(%g, %g) = %g want %g\n", polar[i].r, polar[i].theta, f, vc[i])
+ t.Errorf("Rect(%g, %g) = %g want %g", polar[i].r, polar[i].theta, f, vc[i])
}
}
for i := 0; i < len(vcPolarSC); i++ {
if f := Rect(polarSC[i].r, polarSC[i].theta); !cAlike(vcPolarSC[i], f) {
- t.Errorf("Rect(%g, %g) = %g, want %g\n", polarSC[i].r, polarSC[i].theta, f, vcPolarSC[i])
+ t.Errorf("Rect(%g, %g) = %g, want %g", polarSC[i].r, polarSC[i].theta, f, vcPolarSC[i])
}
}
}
func TestSin(t *testing.T) {
for i := 0; i < len(vc); i++ {
if f := Sin(vc[i]); !cSoclose(sin[i], f, 2e-15) {
- t.Errorf("Sin(%g) = %g, want %g\n", vc[i], f, sin[i])
+ t.Errorf("Sin(%g) = %g, want %g", vc[i], f, sin[i])
}
}
for i := 0; i < len(vcSinSC); i++ {
if f := Sin(vcSinSC[i]); !cAlike(sinSC[i], f) {
- t.Errorf("Sin(%g) = %g, want %g\n", vcSinSC[i], f, sinSC[i])
+ t.Errorf("Sin(%g) = %g, want %g", vcSinSC[i], f, sinSC[i])
}
}
}
func TestSinh(t *testing.T) {
for i := 0; i < len(vc); i++ {
if f := Sinh(vc[i]); !cSoclose(sinh[i], f, 2e-15) {
- t.Errorf("Sinh(%g) = %g, want %g\n", vc[i], f, sinh[i])
+ t.Errorf("Sinh(%g) = %g, want %g", vc[i], f, sinh[i])
}
}
for i := 0; i < len(vcSinhSC); i++ {
if f := Sinh(vcSinhSC[i]); !cAlike(sinhSC[i], f) {
- t.Errorf("Sinh(%g) = %g, want %g\n", vcSinhSC[i], f, sinhSC[i])
+ t.Errorf("Sinh(%g) = %g, want %g", vcSinhSC[i], f, sinhSC[i])
}
}
}
func TestSqrt(t *testing.T) {
for i := 0; i < len(vc); i++ {
if f := Sqrt(vc[i]); !cVeryclose(sqrt[i], f) {
- t.Errorf("Sqrt(%g) = %g, want %g\n", vc[i], f, sqrt[i])
+ t.Errorf("Sqrt(%g) = %g, want %g", vc[i], f, sqrt[i])
}
}
for i := 0; i < len(vcSqrtSC); i++ {
if f := Sqrt(vcSqrtSC[i]); !cAlike(sqrtSC[i], f) {
- t.Errorf("Sqrt(%g) = %g, want %g\n", vcSqrtSC[i], f, sqrtSC[i])
+ t.Errorf("Sqrt(%g) = %g, want %g", vcSqrtSC[i], f, sqrtSC[i])
}
}
}
func TestTan(t *testing.T) {
for i := 0; i < len(vc); i++ {
if f := Tan(vc[i]); !cSoclose(tan[i], f, 3e-15) {
- t.Errorf("Tan(%g) = %g, want %g\n", vc[i], f, tan[i])
+ t.Errorf("Tan(%g) = %g, want %g", vc[i], f, tan[i])
}
}
for i := 0; i < len(vcTanSC); i++ {
if f := Tan(vcTanSC[i]); !cAlike(tanSC[i], f) {
- t.Errorf("Tan(%g) = %g, want %g\n", vcTanSC[i], f, tanSC[i])
+ t.Errorf("Tan(%g) = %g, want %g", vcTanSC[i], f, tanSC[i])
}
}
}
func TestTanh(t *testing.T) {
for i := 0; i < len(vc); i++ {
if f := Tanh(vc[i]); !cSoclose(tanh[i], f, 2e-15) {
- t.Errorf("Tanh(%g) = %g, want %g\n", vc[i], f, tanh[i])
+ t.Errorf("Tanh(%g) = %g, want %g", vc[i], f, tanh[i])
}
}
for i := 0; i < len(vcTanhSC); i++ {
if f := Tanh(vcTanhSC[i]); !cAlike(tanhSC[i], f) {
- t.Errorf("Tanh(%g) = %g, want %g\n", vcTanhSC[i], f, tanhSC[i])
+ t.Errorf("Tanh(%g) = %g, want %g", vcTanhSC[i], f, tanhSC[i])
}
}
}
diff --git a/src/pkg/compress/flate/Makefile b/src/pkg/compress/flate/Makefile
index 6f9ee74d4..197828a92 100644
--- a/src/pkg/compress/flate/Makefile
+++ b/src/pkg/compress/flate/Makefile
@@ -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 ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=compress/flate
GOFILES=\
diff --git a/src/pkg/compress/flate/deflate.go b/src/pkg/compress/flate/deflate.go
index 79952e713..591b35c44 100644
--- a/src/pkg/compress/flate/deflate.go
+++ b/src/pkg/compress/flate/deflate.go
@@ -53,19 +53,19 @@ type compressionLevel struct {
}
var levels = []compressionLevel{
- compressionLevel{}, // 0
+ {}, // 0
// For levels 1-3 we don't bother trying with lazy matches
- compressionLevel{3, 0, 8, 4, 4},
- compressionLevel{3, 0, 16, 8, 5},
- compressionLevel{3, 0, 32, 32, 6},
+ {3, 0, 8, 4, 4},
+ {3, 0, 16, 8, 5},
+ {3, 0, 32, 32, 6},
// Levels 4-9 use increasingly more lazy matching
// and increasingly stringent conditions for "good enough".
- compressionLevel{4, 4, 16, 16, math.MaxInt32},
- compressionLevel{8, 16, 32, 32, math.MaxInt32},
- compressionLevel{8, 16, 128, 128, math.MaxInt32},
- compressionLevel{8, 32, 128, 256, math.MaxInt32},
- compressionLevel{32, 128, 258, 1024, math.MaxInt32},
- compressionLevel{32, 258, 258, 4096, math.MaxInt32},
+ {4, 4, 16, 16, math.MaxInt32},
+ {8, 16, 32, 32, math.MaxInt32},
+ {8, 16, 128, 128, math.MaxInt32},
+ {8, 32, 128, 256, math.MaxInt32},
+ {32, 128, 258, 1024, math.MaxInt32},
+ {32, 258, 258, 4096, math.MaxInt32},
}
func (sw *syncPipeWriter) Close() os.Error {
@@ -89,6 +89,10 @@ type compressor struct {
// (1 << logWindowSize) - 1.
windowMask int
+ eof bool // has eof been reached on input?
+ sync bool // writer wants to flush
+ syncChan chan os.Error
+
// hashHead[hashValue] contains the largest inputIndex with the specified hash value
hashHead []int
@@ -124,6 +128,9 @@ func (d *compressor) flush() os.Error {
}
func (d *compressor) fillWindow(index int) (int, os.Error) {
+ if d.sync {
+ return index, nil
+ }
wSize := d.windowMask + 1
if index >= wSize+wSize-(minMatchLength+maxMatchLength) {
// shift the window by wSize
@@ -142,12 +149,14 @@ func (d *compressor) fillWindow(index int) (int, os.Error) {
d.hashPrev[i] = max(h-wSize, -1)
}
}
- var count int
- var err os.Error
- count, err = io.ReadAtLeast(d.r, d.window[d.windowEnd:], 1)
+ count, err := d.r.Read(d.window[d.windowEnd:])
d.windowEnd += count
+ if count == 0 && err == nil {
+ d.sync = true
+ }
if err == os.EOF {
- return index, nil
+ d.eof = true
+ err = nil
}
return index, err
}
@@ -227,10 +236,17 @@ func (d *compressor) storedDeflate() os.Error {
buf := make([]byte, maxStoreBlockSize)
for {
n, err := d.r.Read(buf)
- if n > 0 {
+ if n == 0 && err == nil {
+ d.sync = true
+ }
+ if n > 0 || d.sync {
if err := d.writeStoredBlock(buf[0:n]); err != nil {
return err
}
+ if d.sync {
+ d.syncChan <- nil
+ d.sync = false
+ }
}
if err != nil {
if err == os.EOF {
@@ -275,6 +291,7 @@ func (d *compressor) doDeflate() (err os.Error) {
hash = int(d.window[index])<<hashShift + int(d.window[index+1])
}
chainHead := -1
+Loop:
for {
if index > windowEnd {
panic("index > windowEnd")
@@ -291,7 +308,31 @@ func (d *compressor) doDeflate() (err os.Error) {
maxInsertIndex = windowEnd - (minMatchLength - 1)
lookahead = windowEnd - index
if lookahead == 0 {
- break
+ // Flush current output block if any.
+ if byteAvailable {
+ // There is still one pending token that needs to be flushed
+ tokens[ti] = literalToken(uint32(d.window[index-1]) & 0xFF)
+ ti++
+ byteAvailable = false
+ }
+ if ti > 0 {
+ if err = d.writeBlock(tokens[0:ti], index, false); err != nil {
+ return
+ }
+ ti = 0
+ }
+ if d.sync {
+ d.w.writeStoredHeader(0, false)
+ d.w.flush()
+ d.syncChan <- d.w.err
+ d.sync = false
+ }
+
+ // If this was only a sync (not at EOF) keep going.
+ if !d.eof {
+ continue
+ }
+ break Loop
}
}
if index < maxInsertIndex {
@@ -383,23 +424,11 @@ func (d *compressor) doDeflate() (err os.Error) {
byteAvailable = true
}
}
-
- }
- if byteAvailable {
- // There is still one pending token that needs to be flushed
- tokens[ti] = literalToken(uint32(d.window[index-1]) & 0xFF)
- ti++
- }
-
- if ti > 0 {
- if err = d.writeBlock(tokens[0:ti], index, false); err != nil {
- return
- }
}
return
}
-func (d *compressor) compressor(r io.Reader, w io.Writer, level int, logWindowSize uint) (err os.Error) {
+func (d *compressor) compress(r io.Reader, w io.Writer, level int, logWindowSize uint) (err os.Error) {
d.r = r
d.w = newHuffmanBitWriter(w)
d.level = level
@@ -417,6 +446,10 @@ func (d *compressor) compressor(r io.Reader, w io.Writer, level int, logWindowSi
return WrongValueError{"level", 0, 9, int32(level)}
}
+ if d.sync {
+ d.syncChan <- err
+ d.sync = false
+ }
if err != nil {
return err
}
@@ -426,16 +459,63 @@ func (d *compressor) compressor(r io.Reader, w io.Writer, level int, logWindowSi
return d.flush()
}
-func newCompressor(w io.Writer, level int, logWindowSize uint) io.WriteCloser {
+// NewWriter returns a new Writer compressing
+// data at the given level. Following zlib, levels
+// range from 1 (BestSpeed) to 9 (BestCompression);
+// higher levels typically run slower but compress more.
+// Level 0 (NoCompression) does not attempt any
+// compression; it only adds the necessary DEFLATE framing.
+func NewWriter(w io.Writer, level int) *Writer {
+ const logWindowSize = logMaxOffsetSize
var d compressor
+ d.syncChan = make(chan os.Error, 1)
pr, pw := syncPipe()
go func() {
- err := d.compressor(pr, w, level, logWindowSize)
+ err := d.compress(pr, w, level, logWindowSize)
pr.CloseWithError(err)
}()
- return pw
+ return &Writer{pw, &d}
+}
+
+// A Writer takes data written to it and writes the compressed
+// form of that data to an underlying writer (see NewWriter).
+type Writer struct {
+ w *syncPipeWriter
+ d *compressor
+}
+
+// Write writes data to w, which will eventually write the
+// compressed form of data to its underlying writer.
+func (w *Writer) Write(data []byte) (n int, err os.Error) {
+ if len(data) == 0 {
+ // no point, and nil interferes with sync
+ return
+ }
+ return w.w.Write(data)
+}
+
+// Flush flushes any pending compressed data to the underlying writer.
+// It is useful mainly in compressed network protocols, to ensure that
+// a remote reader has enough data to reconstruct a packet.
+// Flush does not return until the data has been written.
+// If the underlying writer returns an error, Flush returns that error.
+//
+// In the terminology of the zlib library, Flush is equivalent to Z_SYNC_FLUSH.
+func (w *Writer) Flush() os.Error {
+ // For more about flushing:
+ // http://www.bolet.org/~pornin/deflate-flush.html
+ if w.d.sync {
+ panic("compress/flate: double Flush")
+ }
+ _, err := w.w.Write(nil)
+ err1 := <-w.d.syncChan
+ if err == nil {
+ err = err1
+ }
+ return err
}
-func NewWriter(w io.Writer, level int) io.WriteCloser {
- return newCompressor(w, level, logMaxOffsetSize)
+// Close flushes and closes the writer.
+func (w *Writer) Close() os.Error {
+ return w.w.Close()
}
diff --git a/src/pkg/compress/flate/deflate_test.go b/src/pkg/compress/flate/deflate_test.go
index 9718d2f5a..3db955609 100644
--- a/src/pkg/compress/flate/deflate_test.go
+++ b/src/pkg/compress/flate/deflate_test.go
@@ -7,8 +7,10 @@ package flate
import (
"bytes"
"fmt"
+ "io"
"io/ioutil"
"os"
+ "sync"
"testing"
)
@@ -79,7 +81,7 @@ func getLargeDataChunk() []byte {
func TestDeflate(t *testing.T) {
for _, h := range deflateTests {
- buffer := bytes.NewBuffer([]byte{})
+ buffer := bytes.NewBuffer(nil)
w := NewWriter(buffer, h.level)
w.Write(h.in)
w.Close()
@@ -90,21 +92,144 @@ func TestDeflate(t *testing.T) {
}
}
+type syncBuffer struct {
+ buf bytes.Buffer
+ mu sync.RWMutex
+ closed bool
+ ready chan bool
+}
+
+func newSyncBuffer() *syncBuffer {
+ return &syncBuffer{ready: make(chan bool, 1)}
+}
+
+func (b *syncBuffer) Read(p []byte) (n int, err os.Error) {
+ for {
+ b.mu.RLock()
+ n, err = b.buf.Read(p)
+ b.mu.RUnlock()
+ if n > 0 || b.closed {
+ return
+ }
+ <-b.ready
+ }
+ panic("unreachable")
+}
+
+func (b *syncBuffer) Write(p []byte) (n int, err os.Error) {
+ n, err = b.buf.Write(p)
+ _ = b.ready <- true
+ return
+}
+
+func (b *syncBuffer) WriteMode() {
+ b.mu.Lock()
+}
+
+func (b *syncBuffer) ReadMode() {
+ b.mu.Unlock()
+ _ = b.ready <- true
+}
+
+func (b *syncBuffer) Close() os.Error {
+ b.closed = true
+ _ = b.ready <- true
+ return nil
+}
+
+func testSync(t *testing.T, level int, input []byte, name string) {
+ if len(input) == 0 {
+ return
+ }
+
+ t.Logf("--testSync %d, %d, %s", level, len(input), name)
+ buf := newSyncBuffer()
+ buf1 := new(bytes.Buffer)
+ buf.WriteMode()
+ w := NewWriter(io.MultiWriter(buf, buf1), level)
+ r := NewReader(buf)
+
+ // Write half the input and read back.
+ for i := 0; i < 2; i++ {
+ var lo, hi int
+ if i == 0 {
+ lo, hi = 0, (len(input)+1)/2
+ } else {
+ lo, hi = (len(input)+1)/2, len(input)
+ }
+ t.Logf("#%d: write %d-%d", i, lo, hi)
+ if _, err := w.Write(input[lo:hi]); err != nil {
+ t.Errorf("testSync: write: %v", err)
+ return
+ }
+ if i == 0 {
+ if err := w.Flush(); err != nil {
+ t.Errorf("testSync: flush: %v", err)
+ return
+ }
+ } else {
+ if err := w.Close(); err != nil {
+ t.Errorf("testSync: close: %v", err)
+ }
+ }
+ buf.ReadMode()
+ out := make([]byte, hi-lo+1)
+ m, err := io.ReadAtLeast(r, out, hi-lo)
+ t.Logf("#%d: read %d", i, m)
+ if m != hi-lo || err != nil {
+ t.Errorf("testSync/%d (%d, %d, %s): read %d: %d, %v (%d left)", i, level, len(input), name, hi-lo, m, err, buf.buf.Len())
+ return
+ }
+ if !bytes.Equal(input[lo:hi], out[:hi-lo]) {
+ t.Errorf("testSync/%d: read wrong bytes: %x vs %x", i, input[lo:hi], out[:hi-lo])
+ return
+ }
+ if i == 0 && buf.buf.Len() != 0 {
+ t.Errorf("testSync/%d (%d, %d, %s): extra data after %d", i, level, len(input), name, hi-lo)
+ }
+ buf.WriteMode()
+ }
+ buf.ReadMode()
+ out := make([]byte, 10)
+ if n, err := r.Read(out); n > 0 || err != os.EOF {
+ t.Errorf("testSync (%d, %d, %s): final Read: %d, %v (hex: %x)", level, len(input), name, n, err, out[0:n])
+ }
+ if buf.buf.Len() != 0 {
+ t.Errorf("testSync (%d, %d, %s): extra data at end", level, len(input), name)
+ }
+ r.Close()
+
+ // stream should work for ordinary reader too
+ r = NewReader(buf1)
+ out, err := ioutil.ReadAll(r)
+ if err != nil {
+ t.Errorf("testSync: read: %s", err)
+ return
+ }
+ r.Close()
+ if !bytes.Equal(input, out) {
+ t.Errorf("testSync: decompress(compress(data)) != data: level=%d input=%s", level, name)
+ }
+}
+
+
func testToFromWithLevel(t *testing.T, level int, input []byte, name string) os.Error {
- buffer := bytes.NewBuffer([]byte{})
+ buffer := bytes.NewBuffer(nil)
w := NewWriter(buffer, level)
w.Write(input)
w.Close()
- decompressor := NewReader(buffer)
- decompressed, err := ioutil.ReadAll(decompressor)
+ r := NewReader(buffer)
+ out, err := ioutil.ReadAll(r)
if err != nil {
- t.Errorf("reading decompressor: %s", err)
+ t.Errorf("read: %s", err)
return err
}
- decompressor.Close()
- if bytes.Compare(input, decompressed) != 0 {
+ r.Close()
+ if !bytes.Equal(input, out) {
t.Errorf("decompress(compress(data)) != data: level=%d input=%s", level, name)
}
+
+ testSync(t, level, input, name)
return nil
}
diff --git a/src/pkg/compress/flate/huffman_code.go b/src/pkg/compress/flate/huffman_code.go
index 38cbf4396..6be605f0a 100644
--- a/src/pkg/compress/flate/huffman_code.go
+++ b/src/pkg/compress/flate/huffman_code.go
@@ -270,7 +270,6 @@ func (h *huffmanEncoder) bitCounts(list []literalNode, maxBits int32) []int32 {
}
}
-
// Somethings is wrong if at the end, the top level is null or hasn't used
// all of the leaves.
if top.lastChain.leafCount != n {
diff --git a/src/pkg/compress/flate/inflate.go b/src/pkg/compress/flate/inflate.go
index f0bd00531..7dc8cf93b 100644
--- a/src/pkg/compress/flate/inflate.go
+++ b/src/pkg/compress/flate/inflate.go
@@ -47,7 +47,7 @@ func (e *ReadError) String() string {
// A WriteError reports an error encountered while writing output.
type WriteError struct {
Offset int64 // byte offset where error occurred
- Error os.Error // error returned by underlying Read
+ Error os.Error // error returned by underlying Write
}
func (e *WriteError) String() string {
@@ -102,7 +102,6 @@ func (h *huffmanDecoder) init(bits []int) bool {
h.min = min
h.max = max
-
// For each code range, compute
// nextcode (first code of that length),
// limit (last code of that length), and
@@ -218,6 +217,7 @@ type decompressor struct {
// Output history, buffer.
hist [maxHist]byte
hp int // current output position in buffer
+ hw int // have written hist[0:hw] already
hfull bool // buffer has filled at least once
// Temporary buffer (avoids repeated allocation).
@@ -498,6 +498,11 @@ func (f *decompressor) dataBlock() os.Error {
return CorruptInputError(f.roffset)
}
+ if n == 0 {
+ // 0-length block means sync
+ return f.flush()
+ }
+
// Read len bytes into history,
// writing as history fills.
for n > 0 {
@@ -561,19 +566,23 @@ func (f *decompressor) huffSym(h *huffmanDecoder) (int, os.Error) {
// Flush any buffered output to the underlying writer.
func (f *decompressor) flush() os.Error {
- if f.hp == 0 {
+ if f.hw == f.hp {
return nil
}
- n, err := f.w.Write(f.hist[0:f.hp])
- if n != f.hp && err == nil {
+ n, err := f.w.Write(f.hist[f.hw:f.hp])
+ if n != f.hp-f.hw && err == nil {
err = io.ErrShortWrite
}
if err != nil {
return &WriteError{f.woffset, err}
}
- f.woffset += int64(f.hp)
- f.hp = 0
- f.hfull = true
+ f.woffset += int64(f.hp - f.hw)
+ f.hw = f.hp
+ if f.hp == len(f.hist) {
+ f.hp = 0
+ f.hw = 0
+ f.hfull = true
+ }
return nil
}
@@ -584,9 +593,9 @@ func makeReader(r io.Reader) Reader {
return bufio.NewReader(r)
}
-// Inflate reads DEFLATE-compressed data from r and writes
+// decompress reads DEFLATE-compressed data from r and writes
// the uncompressed data to w.
-func (f *decompressor) decompressor(r io.Reader, w io.Writer) os.Error {
+func (f *decompressor) decompress(r io.Reader, w io.Writer) os.Error {
f.r = makeReader(r)
f.w = w
f.woffset = 0
@@ -606,6 +615,6 @@ func (f *decompressor) decompressor(r io.Reader, w io.Writer) os.Error {
func NewReader(r io.Reader) io.ReadCloser {
var f decompressor
pr, pw := io.Pipe()
- go func() { pw.CloseWithError(f.decompressor(r, pw)) }()
+ go func() { pw.CloseWithError(f.decompress(r, pw)) }()
return pr
}
diff --git a/src/pkg/compress/gzip/Makefile b/src/pkg/compress/gzip/Makefile
index bb4705a8f..b671fc72c 100644
--- a/src/pkg/compress/gzip/Makefile
+++ b/src/pkg/compress/gzip/Makefile
@@ -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 ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=compress/gzip
GOFILES=\
diff --git a/src/pkg/compress/gzip/gunzip_test.go b/src/pkg/compress/gzip/gunzip_test.go
index d5ac0cc14..1c08c7374 100644
--- a/src/pkg/compress/gzip/gunzip_test.go
+++ b/src/pkg/compress/gzip/gunzip_test.go
@@ -20,7 +20,7 @@ type gunzipTest struct {
}
var gunzipTests = []gunzipTest{
- gunzipTest{ // has 1 empty fixed-huffman block
+ { // has 1 empty fixed-huffman block
"empty.txt",
"empty.txt",
"",
@@ -32,7 +32,7 @@ var gunzipTests = []gunzipTest{
},
nil,
},
- gunzipTest{ // has 1 non-empty fixed huffman block
+ { // has 1 non-empty fixed huffman block
"hello.txt",
"hello.txt",
"hello world\n",
@@ -46,7 +46,7 @@ var gunzipTests = []gunzipTest{
},
nil,
},
- gunzipTest{ // concatenation
+ { // concatenation
"hello.txt",
"hello.txt x2",
"hello world\n" +
@@ -67,7 +67,7 @@ var gunzipTests = []gunzipTest{
},
nil,
},
- gunzipTest{ // has a fixed huffman block with some length-distance pairs
+ { // has a fixed huffman block with some length-distance pairs
"shesells.txt",
"shesells.txt",
"she sells seashells by the seashore\n",
@@ -83,7 +83,7 @@ var gunzipTests = []gunzipTest{
},
nil,
},
- gunzipTest{ // has dynamic huffman blocks
+ { // has dynamic huffman blocks
"gettysburg",
"gettysburg",
" Four score and seven years ago our fathers brought forth on\n" +
@@ -221,7 +221,7 @@ var gunzipTests = []gunzipTest{
},
nil,
},
- gunzipTest{ // has 1 non-empty fixed huffman block then garbage
+ { // has 1 non-empty fixed huffman block then garbage
"hello.txt",
"hello.txt + garbage",
"hello world\n",
@@ -235,7 +235,7 @@ var gunzipTests = []gunzipTest{
},
HeaderError,
},
- gunzipTest{ // has 1 non-empty fixed huffman block not enough header
+ { // has 1 non-empty fixed huffman block not enough header
"hello.txt",
"hello.txt + garbage",
"hello world\n",
@@ -249,7 +249,7 @@ var gunzipTests = []gunzipTest{
},
io.ErrUnexpectedEOF,
},
- gunzipTest{ // has 1 non-empty fixed huffman block but corrupt checksum
+ { // has 1 non-empty fixed huffman block but corrupt checksum
"hello.txt",
"hello.txt + corrupt checksum",
"hello world\n",
@@ -263,7 +263,7 @@ var gunzipTests = []gunzipTest{
},
ChecksumError,
},
- gunzipTest{ // has 1 non-empty fixed huffman block but corrupt size
+ { // has 1 non-empty fixed huffman block but corrupt size
"hello.txt",
"hello.txt + corrupt size",
"hello world\n",
diff --git a/src/pkg/compress/zlib/Makefile b/src/pkg/compress/zlib/Makefile
index 4cfda4f1b..791072d34 100644
--- a/src/pkg/compress/zlib/Makefile
+++ b/src/pkg/compress/zlib/Makefile
@@ -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 ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=compress/zlib
GOFILES=\
diff --git a/src/pkg/compress/zlib/reader_test.go b/src/pkg/compress/zlib/reader_test.go
index 8ae8d0070..eaefc3a36 100644
--- a/src/pkg/compress/zlib/reader_test.go
+++ b/src/pkg/compress/zlib/reader_test.go
@@ -22,13 +22,13 @@ type zlibTest struct {
// http://www.zlib.net/zpipe.c
var zlibTests = []zlibTest{
- zlibTest{
+ {
"empty",
"",
[]byte{0x78, 0x9c, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01},
nil,
},
- zlibTest{
+ {
"goodbye",
"goodbye, world",
[]byte{
@@ -38,25 +38,25 @@ var zlibTests = []zlibTest{
},
nil,
},
- zlibTest{
+ {
"bad header",
"",
[]byte{0x78, 0x9f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01},
HeaderError,
},
- zlibTest{
+ {
"bad checksum",
"",
[]byte{0x78, 0x9c, 0x03, 0x00, 0x00, 0x00, 0x00, 0xff},
ChecksumError,
},
- zlibTest{
+ {
"not enough data",
"",
[]byte{0x78, 0x9c, 0x03, 0x00, 0x00, 0x00},
io.ErrUnexpectedEOF,
},
- zlibTest{
+ {
"excess data is silently ignored",
"",
[]byte{
diff --git a/src/pkg/container/heap/Makefile b/src/pkg/container/heap/Makefile
index 244ebae06..4291d1122 100644
--- a/src/pkg/container/heap/Makefile
+++ b/src/pkg/container/heap/Makefile
@@ -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 ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=container/heap
GOFILES=\
diff --git a/src/pkg/container/list/Makefile b/src/pkg/container/list/Makefile
index 2d5b35715..7fcd5f99a 100644
--- a/src/pkg/container/list/Makefile
+++ b/src/pkg/container/list/Makefile
@@ -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 ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=container/list
GOFILES=\
diff --git a/src/pkg/container/list/list.go b/src/pkg/container/list/list.go
index 40c968099..c1ebcddaa 100644
--- a/src/pkg/container/list/list.go
+++ b/src/pkg/container/list/list.go
@@ -3,6 +3,12 @@
// license that can be found in the LICENSE file.
// The list package implements a doubly linked list.
+//
+// To iterate over a list (where l is a *List):
+// for e := l.Front(); e != nil; e = e.Next() {
+// // do something with e.Value
+// }
+//
package list
// Element is an element in the linked list.
@@ -11,8 +17,8 @@ type Element struct {
// The front of the list has prev = nil, and the back has next = nil.
next, prev *Element
- // A unique ID for the list to which this element belongs.
- id *byte
+ // The list to which this element belongs.
+ list *List
// The contents of this list element.
Value interface{}
@@ -25,10 +31,10 @@ func (e *Element) Next() *Element { return e.next }
func (e *Element) Prev() *Element { return e.prev }
// List represents a doubly linked list.
+// The zero value for List is an empty list ready to use.
type List struct {
front, back *Element
len int
- id *byte
}
// Init initializes or clears a List.
@@ -36,12 +42,11 @@ func (l *List) Init() *List {
l.front = nil
l.back = nil
l.len = 0
- l.id = new(byte)
return l
}
// New returns an initialized list.
-func New() *List { return new(List).Init() }
+func New() *List { return new(List) }
// Front returns the first element in the list.
func (l *List) Front() *Element { return l.front }
@@ -49,9 +54,19 @@ func (l *List) Front() *Element { return l.front }
// Back returns the last element in the list.
func (l *List) Back() *Element { return l.back }
-// Remove removes the element from the list.
-func (l *List) Remove(e *Element) {
- if e.id != l.id {
+// Remove removes the element from the list
+// and returns its Value.
+func (l *List) Remove(e *Element) interface{} {
+ l.remove(e)
+ e.list = nil // do what remove does not
+ return e.Value
+}
+
+// remove the element from the list, but do not clear the Element's list field.
+// This is so that other List methods may use remove when relocating Elements
+// without needing to restore the list field.
+func (l *List) remove(e *Element) {
+ if e.list != l {
return
}
if e.prev == nil {
@@ -120,78 +135,59 @@ func (l *List) insertBack(e *Element) {
// PushFront inserts the value at the front of the list and returns a new Element containing the value.
func (l *List) PushFront(value interface{}) *Element {
- if l.id == nil {
- l.Init()
- }
- e := &Element{nil, nil, l.id, value}
+ e := &Element{nil, nil, l, value}
l.insertFront(e)
return e
}
// PushBack inserts the value at the back of the list and returns a new Element containing the value.
func (l *List) PushBack(value interface{}) *Element {
- if l.id == nil {
- l.Init()
- }
- e := &Element{nil, nil, l.id, value}
+ e := &Element{nil, nil, l, value}
l.insertBack(e)
return e
}
// InsertBefore inserts the value immediately before mark and returns a new Element containing the value.
func (l *List) InsertBefore(value interface{}, mark *Element) *Element {
- if mark.id != l.id {
+ if mark.list != l {
return nil
}
- e := &Element{nil, nil, l.id, value}
+ e := &Element{nil, nil, l, value}
l.insertBefore(e, mark)
return e
}
// InsertAfter inserts the value immediately after mark and returns a new Element containing the value.
func (l *List) InsertAfter(value interface{}, mark *Element) *Element {
- if mark.id != l.id {
+ if mark.list != l {
return nil
}
- e := &Element{nil, nil, l.id, value}
+ e := &Element{nil, nil, l, value}
l.insertAfter(e, mark)
return e
}
// MoveToFront moves the element to the front of the list.
func (l *List) MoveToFront(e *Element) {
- if e.id != l.id || l.front == e {
+ if e.list != l || l.front == e {
return
}
- l.Remove(e)
+ l.remove(e)
l.insertFront(e)
}
// MoveToBack moves the element to the back of the list.
func (l *List) MoveToBack(e *Element) {
- if e.id != l.id || l.back == e {
+ if e.list != l || l.back == e {
return
}
- l.Remove(e)
+ l.remove(e)
l.insertBack(e)
}
// Len returns the number of elements in the list.
func (l *List) Len() int { return l.len }
-func (l *List) iterate(c chan<- interface{}) {
- for e := l.front; e != nil; e = e.next {
- c <- e.Value
- }
- close(c)
-}
-
-func (l *List) Iter() <-chan interface{} {
- c := make(chan interface{})
- go l.iterate(c)
- return c
-}
-
// PushBackList inserts each element of ol at the back of the list.
func (l *List) PushBackList(ol *List) {
last := ol.Back()
diff --git a/src/pkg/container/list/list_test.go b/src/pkg/container/list/list_test.go
index bf35c9dd9..1d44ff84e 100644
--- a/src/pkg/container/list/list_test.go
+++ b/src/pkg/container/list/list_test.go
@@ -23,8 +23,7 @@ func checkListPointers(t *testing.T, l *List, es []*Element) {
t.Errorf("l.back = %v, want %v", l.back, last)
}
- for i := 0; i < len(es); i++ {
- e := es[i]
+ for i, e := range es {
var e_prev, e_next *Element = nil, nil
if i > 0 {
e_prev = es[i-1]
@@ -116,8 +115,8 @@ func TestList(t *testing.T) {
// Check standard iteration.
sum := 0
- for e := range l.Iter() {
- if i, ok := e.(int); ok {
+ for e := l.Front(); e != nil; e = e.Next() {
+ if i, ok := e.Value.(int); ok {
sum += i
}
}
@@ -141,7 +140,8 @@ func checkList(t *testing.T, l *List, es []interface{}) {
return
}
i := 0
- for le := range l.Iter() {
+ for e := l.Front(); e != nil; e = e.Next() {
+ le := e.Value.(int)
if le != es[i] {
t.Errorf("elt #%d has value=%v, want %v", i, le, es[i])
}
@@ -193,3 +193,17 @@ func TestExtending(t *testing.T) {
l1.PushFrontList(l3)
checkList(t, l1, []interface{}{1, 2, 3})
}
+
+func TestRemove(t *testing.T) {
+ l := New()
+ e1 := l.PushBack(1)
+ e2 := l.PushBack(2)
+ checkListPointers(t, l, []*Element{e1, e2})
+ e := l.Front()
+ l.Remove(e)
+ checkListPointers(t, l, []*Element{e2})
+ checkListLen(t, l, 1)
+ l.Remove(e)
+ checkListPointers(t, l, []*Element{e2})
+ checkListLen(t, l, 1)
+}
diff --git a/src/pkg/container/ring/Makefile b/src/pkg/container/ring/Makefile
index 4755bab07..fb0900774 100644
--- a/src/pkg/container/ring/Makefile
+++ b/src/pkg/container/ring/Makefile
@@ -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 ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=container/ring
GOFILES=\
diff --git a/src/pkg/container/vector/Makefile b/src/pkg/container/vector/Makefile
index c456c6a6c..f6b50156f 100644
--- a/src/pkg/container/vector/Makefile
+++ b/src/pkg/container/vector/Makefile
@@ -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 ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=container/vector
GOFILES=\
@@ -42,8 +42,7 @@ generate: vector.go vector_test.go
| gofmt -r='make_vector -> make_vectorInt'\
| gofmt -r='TestInsertVector -> TestIntInsertVector'\
| gofmt -r='TestDo -> TestIntDo'\
- | gofmt -r='TestIter -> TestIntIter'\
- | gofmt -r='TestVectorData -> TestIntVectorData'\
+ | gofmt -r='TestVectorCopy -> TestIntVectorCopy'\
| gofmt -r='interface{} -> int'\
> intvector_test.go\
@@ -65,7 +64,6 @@ generate: vector.go vector_test.go
| gofmt -r='make_vector -> make_vectorStr'\
| gofmt -r='TestInsertVector -> TestStrInsertVector'\
| gofmt -r='TestDo -> TestStrDo'\
- | gofmt -r='TestIter -> TestStrIter'\
- | gofmt -r='TestVectorData -> TestStrVectorData'\
+ | gofmt -r='TestVectorCopy -> TestStrVectorCopy'\
| gofmt -r='interface{} -> string'\
> stringvector_test.go
diff --git a/src/pkg/container/vector/intvector.go b/src/pkg/container/vector/intvector.go
index 6aad358e3..5ad9e294b 100644
--- a/src/pkg/container/vector/intvector.go
+++ b/src/pkg/container/vector/intvector.go
@@ -104,8 +104,8 @@ func (p *IntVector) Set(i int, x int) { (*p)[i] = x }
func (p *IntVector) Last() int { return (*p)[len(*p)-1] }
-// Data returns all the elements as a slice.
-func (p *IntVector) Data() []int {
+// 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
@@ -199,23 +199,6 @@ func (p *IntVector) Swap(i, j int) {
}
-// Iterate over all elements; driver for range
-func (p *IntVector) iterate(c chan<- int) {
- for _, v := range *p {
- c <- v
- }
- close(c)
-}
-
-
-// Channel iterator for range.
-func (p *IntVector) Iter() <-chan int {
- c := make(chan int)
- go p.iterate(c)
- return c
-}
-
-
// Do calls function f for each element of the vector, in order.
// The behavior of Do is undefined if f changes *p.
func (p *IntVector) Do(f func(elem int)) {
diff --git a/src/pkg/container/vector/intvector_test.go b/src/pkg/container/vector/intvector_test.go
index c80dd52cc..1e38a1982 100644
--- a/src/pkg/container/vector/intvector_test.go
+++ b/src/pkg/container/vector/intvector_test.go
@@ -127,59 +127,59 @@ func TestIntInsertDeleteClear(t *testing.T) {
for i := 0; i < n; i++ {
if a.Len() != i {
- t.Errorf("T%: A) wrong Len() %d (expected %d)", a, 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)
+ 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.Error("T%: B", a)
+ t.Errorf("%T: B", a)
}
}
for i := n - 1; i >= 0; i-- {
if elem2IntValue(a.Last()) != int2IntValue(val(0)) {
- t.Error("T%: C", a)
+ t.Errorf("%T: C", a)
}
if elem2IntValue(a.At(0)) != int2IntValue(val(i)) {
- t.Error("T%: D", a)
+ t.Errorf("%T: D", a)
}
if elem2IntValue(a[0]) != int2IntValue(val(i)) {
- t.Error("T%: D2", a)
+ 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)
+ 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)
+ 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())
+ 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))
+ 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)
+ 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)
+ t.Errorf("%T: G) wrong len() %d (expected %d)", a, len(a), i+1)
}
if elem2IntValue(a.Last()) != int2IntValue(val(i)) {
- t.Error("T%: H", a)
+ 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())
+ 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))
+ t.Errorf("%T: I wrong len() %d (expected 0)", a, len(a))
}
const m = 5
@@ -189,21 +189,21 @@ func TestIntInsertDeleteClear(t *testing.T) {
x := val(i)
a.Push(int2IntValue(x))
if elem2IntValue(a.Pop()) != int2IntValue(x) {
- t.Error("T%: J", a)
+ t.Errorf("%T: J", a)
}
if a.Len() != j+1 {
- t.Errorf("T%: K) wrong Len() %d (expected %d)", a, 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)
+ 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)
+ 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)
+ t.Errorf("%T: L) wrong len() %d (expected %d)", a, len(a), m)
}
}
@@ -211,14 +211,14 @@ func TestIntInsertDeleteClear(t *testing.T) {
func verify_sliceInt(t *testing.T, x *IntVector, elt, i, j int) {
for k := i; k < j; k++ {
if elem2IntValue(x.At(k)) != int2IntValue(elt) {
- t.Errorf("T%: M) wrong [%d] element %v (expected %v)", x, k, 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))
+ t.Errorf("%T: N) wrong [%d] element %v (expected %v)", x, k, elem2IntValue(x.At(k)), int2IntValue(elt))
}
}
}
@@ -227,10 +227,10 @@ func verify_sliceInt(t *testing.T, x *IntVector, elt, i, j int) {
func verify_patternInt(t *testing.T, x *IntVector, a, b, c int) {
n := a + b + c
if x.Len() != n {
- t.Errorf("T%: O) wrong Len() %d (expected %d)", x, 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)
+ 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)
@@ -326,61 +326,14 @@ func TestIntDo(t *testing.T) {
}
-func TestIntIter(t *testing.T) {
- const Len = 100
- x := new(IntVector).Resize(Len, 0)
- for i := 0; i < Len; i++ {
- x.Set(i, int2IntValue(i*i))
- }
- i := 0
- for v := range x.Iter() {
- if elem2IntValue(v) != int2IntValue(i*i) {
- t.Error(tname(x), "Iter expected", i*i, "got", elem2IntValue(v))
- }
- i++
- }
- if i != Len {
- t.Error(tname(x), "Iter stopped at", i, "not", Len)
- }
- y := new(IntVector).Resize(Len, 0)
- for i := 0; i < Len; i++ {
- (*y)[i] = int2IntValue(i * i)
- }
- i = 0
- for v := range y.Iter() {
- if elem2IntValue(v) != int2IntValue(i*i) {
- t.Error(tname(y), "y, Iter expected", i*i, "got", elem2IntValue(v))
- }
- i++
- }
- if i != Len {
- t.Error(tname(y), "y, Iter stopped at", i, "not", Len)
- }
- var z IntVector
- z.Resize(Len, 0)
- for i := 0; i < Len; i++ {
- z[i] = int2IntValue(i * i)
- }
- i = 0
- for v := range z.Iter() {
- if elem2IntValue(v) != int2IntValue(i*i) {
- t.Error(tname(z), "z, Iter expected", i*i, "got", elem2IntValue(v))
- }
- i++
- }
- if i != Len {
- t.Error(tname(z), "z, Iter stopped at", i, "not", Len)
- }
-}
-
-func TestIntVectorData(t *testing.T) {
- // verify Data() returns a slice of a copy, not a slice of the original vector
+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.Data()
+ dest := src.Copy()
for i := 0; i < Len; i++ {
src[i] = int2IntValue(-1)
v := elem2IntValue(dest[i])
diff --git a/src/pkg/container/vector/numbers_test.go b/src/pkg/container/vector/numbers_test.go
index a44242f67..93335ca60 100644
--- a/src/pkg/container/vector/numbers_test.go
+++ b/src/pkg/container/vector/numbers_test.go
@@ -20,7 +20,7 @@ func s(n uint64) string {
lens := len(str)
a := make([]string, (lens+2)/3)
start := lens
- for i, _ := range a {
+ for i := range a {
start -= 3
if start < 0 {
start = 0
diff --git a/src/pkg/container/vector/stringvector.go b/src/pkg/container/vector/stringvector.go
index ddc030f81..852685f5a 100644
--- a/src/pkg/container/vector/stringvector.go
+++ b/src/pkg/container/vector/stringvector.go
@@ -104,8 +104,8 @@ func (p *StringVector) Set(i int, x string) { (*p)[i] = x }
func (p *StringVector) Last() string { return (*p)[len(*p)-1] }
-// Data returns all the elements as a slice.
-func (p *StringVector) Data() []string {
+// 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
@@ -199,23 +199,6 @@ func (p *StringVector) Swap(i, j int) {
}
-// Iterate over all elements; driver for range
-func (p *StringVector) iterate(c chan<- string) {
- for _, v := range *p {
- c <- v
- }
- close(c)
-}
-
-
-// Channel iterator for range.
-func (p *StringVector) Iter() <-chan string {
- c := make(chan string)
- go p.iterate(c)
- return c
-}
-
-
// Do calls function f for each element of the vector, in order.
// The behavior of Do is undefined if f changes *p.
func (p *StringVector) Do(f func(elem string)) {
diff --git a/src/pkg/container/vector/stringvector_test.go b/src/pkg/container/vector/stringvector_test.go
index 859dac2fd..776ae26de 100644
--- a/src/pkg/container/vector/stringvector_test.go
+++ b/src/pkg/container/vector/stringvector_test.go
@@ -127,59 +127,59 @@ func TestStrInsertDeleteClear(t *testing.T) {
for i := 0; i < n; i++ {
if a.Len() != i {
- t.Errorf("T%: A) wrong Len() %d (expected %d)", a, 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)
+ 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.Error("T%: B", a)
+ t.Errorf("%T: B", a)
}
}
for i := n - 1; i >= 0; i-- {
if elem2StrValue(a.Last()) != int2StrValue(val(0)) {
- t.Error("T%: C", a)
+ t.Errorf("%T: C", a)
}
if elem2StrValue(a.At(0)) != int2StrValue(val(i)) {
- t.Error("T%: D", a)
+ t.Errorf("%T: D", a)
}
if elem2StrValue(a[0]) != int2StrValue(val(i)) {
- t.Error("T%: D2", a)
+ 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)
+ 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)
+ 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())
+ 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))
+ 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)
+ 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)
+ t.Errorf("%T: G) wrong len() %d (expected %d)", a, len(a), i+1)
}
if elem2StrValue(a.Last()) != int2StrValue(val(i)) {
- t.Error("T%: H", a)
+ 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())
+ 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))
+ t.Errorf("%T: I wrong len() %d (expected 0)", a, len(a))
}
const m = 5
@@ -189,21 +189,21 @@ func TestStrInsertDeleteClear(t *testing.T) {
x := val(i)
a.Push(int2StrValue(x))
if elem2StrValue(a.Pop()) != int2StrValue(x) {
- t.Error("T%: J", a)
+ t.Errorf("%T: J", a)
}
if a.Len() != j+1 {
- t.Errorf("T%: K) wrong Len() %d (expected %d)", a, 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)
+ 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)
+ 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)
+ t.Errorf("%T: L) wrong len() %d (expected %d)", a, len(a), m)
}
}
@@ -211,14 +211,14 @@ func TestStrInsertDeleteClear(t *testing.T) {
func verify_sliceStr(t *testing.T, x *StringVector, elt, i, j int) {
for k := i; k < j; k++ {
if elem2StrValue(x.At(k)) != int2StrValue(elt) {
- t.Errorf("T%: M) wrong [%d] element %v (expected %v)", x, k, 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))
+ t.Errorf("%T: N) wrong [%d] element %v (expected %v)", x, k, elem2StrValue(x.At(k)), int2StrValue(elt))
}
}
}
@@ -227,10 +227,10 @@ func verify_sliceStr(t *testing.T, x *StringVector, elt, i, j int) {
func verify_patternStr(t *testing.T, x *StringVector, a, b, c int) {
n := a + b + c
if x.Len() != n {
- t.Errorf("T%: O) wrong Len() %d (expected %d)", x, 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)
+ 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)
@@ -326,61 +326,14 @@ func TestStrDo(t *testing.T) {
}
-func TestStrIter(t *testing.T) {
- const Len = 100
- x := new(StringVector).Resize(Len, 0)
- for i := 0; i < Len; i++ {
- x.Set(i, int2StrValue(i*i))
- }
- i := 0
- for v := range x.Iter() {
- if elem2StrValue(v) != int2StrValue(i*i) {
- t.Error(tname(x), "Iter expected", i*i, "got", elem2StrValue(v))
- }
- i++
- }
- if i != Len {
- t.Error(tname(x), "Iter stopped at", i, "not", Len)
- }
- y := new(StringVector).Resize(Len, 0)
- for i := 0; i < Len; i++ {
- (*y)[i] = int2StrValue(i * i)
- }
- i = 0
- for v := range y.Iter() {
- if elem2StrValue(v) != int2StrValue(i*i) {
- t.Error(tname(y), "y, Iter expected", i*i, "got", elem2StrValue(v))
- }
- i++
- }
- if i != Len {
- t.Error(tname(y), "y, Iter stopped at", i, "not", Len)
- }
- var z StringVector
- z.Resize(Len, 0)
- for i := 0; i < Len; i++ {
- z[i] = int2StrValue(i * i)
- }
- i = 0
- for v := range z.Iter() {
- if elem2StrValue(v) != int2StrValue(i*i) {
- t.Error(tname(z), "z, Iter expected", i*i, "got", elem2StrValue(v))
- }
- i++
- }
- if i != Len {
- t.Error(tname(z), "z, Iter stopped at", i, "not", Len)
- }
-}
-
-func TestStrVectorData(t *testing.T) {
- // verify Data() returns a slice of a copy, not a slice of the original vector
+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.Data()
+ dest := src.Copy()
for i := 0; i < Len; i++ {
src[i] = int2StrValue(-1)
v := elem2StrValue(dest[i])
diff --git a/src/pkg/container/vector/vector.go b/src/pkg/container/vector/vector.go
index 986321b14..f43e4d23c 100644
--- a/src/pkg/container/vector/vector.go
+++ b/src/pkg/container/vector/vector.go
@@ -104,8 +104,8 @@ func (p *Vector) Set(i int, x interface{}) { (*p)[i] = x }
func (p *Vector) Last() interface{} { return (*p)[len(*p)-1] }
-// Data returns all the elements as a slice.
-func (p *Vector) Data() []interface{} {
+// 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
@@ -199,23 +199,6 @@ func (p *Vector) Swap(i, j int) {
}
-// Iterate over all elements; driver for range
-func (p *Vector) iterate(c chan<- interface{}) {
- for _, v := range *p {
- c <- v
- }
- close(c)
-}
-
-
-// Channel iterator for range.
-func (p *Vector) Iter() <-chan interface{} {
- c := make(chan interface{})
- go p.iterate(c)
- return c
-}
-
-
// Do calls function f for each element of the vector, in order.
// The behavior of Do is undefined if f changes *p.
func (p *Vector) Do(f func(elem interface{})) {
diff --git a/src/pkg/container/vector/vector_test.go b/src/pkg/container/vector/vector_test.go
index 158b34479..a9c4ceb55 100644
--- a/src/pkg/container/vector/vector_test.go
+++ b/src/pkg/container/vector/vector_test.go
@@ -127,59 +127,59 @@ func TestInsertDeleteClear(t *testing.T) {
for i := 0; i < n; i++ {
if a.Len() != i {
- t.Errorf("T%: A) wrong Len() %d (expected %d)", a, 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)
+ 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.Error("T%: B", a)
+ t.Errorf("%T: B", a)
}
}
for i := n - 1; i >= 0; i-- {
if elem2Value(a.Last()) != int2Value(val(0)) {
- t.Error("T%: C", a)
+ t.Errorf("%T: C", a)
}
if elem2Value(a.At(0)) != int2Value(val(i)) {
- t.Error("T%: D", a)
+ t.Errorf("%T: D", a)
}
if elem2Value(a[0]) != int2Value(val(i)) {
- t.Error("T%: D2", a)
+ 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)
+ 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)
+ 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())
+ 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))
+ 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)
+ 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)
+ t.Errorf("%T: G) wrong len() %d (expected %d)", a, len(a), i+1)
}
if elem2Value(a.Last()) != int2Value(val(i)) {
- t.Error("T%: H", a)
+ 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())
+ 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))
+ t.Errorf("%T: I wrong len() %d (expected 0)", a, len(a))
}
const m = 5
@@ -189,21 +189,21 @@ func TestInsertDeleteClear(t *testing.T) {
x := val(i)
a.Push(int2Value(x))
if elem2Value(a.Pop()) != int2Value(x) {
- t.Error("T%: J", a)
+ t.Errorf("%T: J", a)
}
if a.Len() != j+1 {
- t.Errorf("T%: K) wrong Len() %d (expected %d)", a, 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)
+ 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)
+ 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)
+ t.Errorf("%T: L) wrong len() %d (expected %d)", a, len(a), m)
}
}
@@ -211,14 +211,14 @@ func TestInsertDeleteClear(t *testing.T) {
func verify_slice(t *testing.T, x *Vector, elt, i, j int) {
for k := i; k < j; k++ {
if elem2Value(x.At(k)) != int2Value(elt) {
- t.Errorf("T%: M) wrong [%d] element %v (expected %v)", x, k, 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))
+ t.Errorf("%T: N) wrong [%d] element %v (expected %v)", x, k, elem2Value(x.At(k)), int2Value(elt))
}
}
}
@@ -227,10 +227,10 @@ func verify_slice(t *testing.T, x *Vector, elt, i, j int) {
func verify_pattern(t *testing.T, x *Vector, a, b, c int) {
n := a + b + c
if x.Len() != n {
- t.Errorf("T%: O) wrong Len() %d (expected %d)", x, 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)
+ 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)
@@ -326,61 +326,14 @@ func TestDo(t *testing.T) {
}
-func TestIter(t *testing.T) {
- const Len = 100
- x := new(Vector).Resize(Len, 0)
- for i := 0; i < Len; i++ {
- x.Set(i, int2Value(i*i))
- }
- i := 0
- for v := range x.Iter() {
- if elem2Value(v) != int2Value(i*i) {
- t.Error(tname(x), "Iter expected", i*i, "got", elem2Value(v))
- }
- i++
- }
- if i != Len {
- t.Error(tname(x), "Iter stopped at", i, "not", Len)
- }
- y := new(Vector).Resize(Len, 0)
- for i := 0; i < Len; i++ {
- (*y)[i] = int2Value(i * i)
- }
- i = 0
- for v := range y.Iter() {
- if elem2Value(v) != int2Value(i*i) {
- t.Error(tname(y), "y, Iter expected", i*i, "got", elem2Value(v))
- }
- i++
- }
- if i != Len {
- t.Error(tname(y), "y, Iter stopped at", i, "not", Len)
- }
- var z Vector
- z.Resize(Len, 0)
- for i := 0; i < Len; i++ {
- z[i] = int2Value(i * i)
- }
- i = 0
- for v := range z.Iter() {
- if elem2Value(v) != int2Value(i*i) {
- t.Error(tname(z), "z, Iter expected", i*i, "got", elem2Value(v))
- }
- i++
- }
- if i != Len {
- t.Error(tname(z), "z, Iter stopped at", i, "not", Len)
- }
-}
-
-func TestVectorData(t *testing.T) {
- // verify Data() returns a slice of a copy, not a slice of the original vector
+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.Data()
+ dest := src.Copy()
for i := 0; i < Len; i++ {
src[i] = int2Value(-1)
v := elem2Value(dest[i])
diff --git a/src/pkg/crypto/aes/Makefile b/src/pkg/crypto/aes/Makefile
index 07d759b4b..9dc846ee3 100644
--- a/src/pkg/crypto/aes/Makefile
+++ b/src/pkg/crypto/aes/Makefile
@@ -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 ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=crypto/aes
GOFILES=\
diff --git a/src/pkg/crypto/aes/aes_test.go b/src/pkg/crypto/aes/aes_test.go
index 1629a33ed..2136d447d 100644
--- a/src/pkg/crypto/aes/aes_test.go
+++ b/src/pkg/crypto/aes/aes_test.go
@@ -130,7 +130,7 @@ type KeyTest struct {
}
var keyTests = []KeyTest{
- KeyTest{
+ {
// A.1. Expansion of a 128-bit Cipher Key
[]byte{0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c},
[]uint32{
@@ -160,7 +160,7 @@ var keyTests = []KeyTest{
0x2b7e1516, 0x28aed2a6, 0xabf71588, 0x9cf4f3c,
},
},
- KeyTest{
+ {
// A.2. Expansion of a 192-bit Cipher Key
[]byte{
0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52, 0xc8, 0x10, 0xf3, 0x2b, 0x80, 0x90, 0x79, 0xe5,
@@ -183,7 +183,7 @@ var keyTests = []KeyTest{
},
nil,
},
- KeyTest{
+ {
// A.3. Expansion of a 256-bit Cipher Key
[]byte{
0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81,
@@ -245,19 +245,19 @@ type CryptTest struct {
}
var encryptTests = []CryptTest{
- CryptTest{
+ {
// Appendix B.
[]byte{0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c},
[]byte{0x32, 0x43, 0xf6, 0xa8, 0x88, 0x5a, 0x30, 0x8d, 0x31, 0x31, 0x98, 0xa2, 0xe0, 0x37, 0x07, 0x34},
[]byte{0x39, 0x25, 0x84, 0x1d, 0x02, 0xdc, 0x09, 0xfb, 0xdc, 0x11, 0x85, 0x97, 0x19, 0x6a, 0x0b, 0x32},
},
- CryptTest{
+ {
// Appendix C.1. AES-128
[]byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f},
[]byte{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff},
[]byte{0x69, 0xc4, 0xe0, 0xd8, 0x6a, 0x7b, 0x04, 0x30, 0xd8, 0xcd, 0xb7, 0x80, 0x70, 0xb4, 0xc5, 0x5a},
},
- CryptTest{
+ {
// Appendix C.2. AES-192
[]byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
@@ -265,7 +265,7 @@ var encryptTests = []CryptTest{
[]byte{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff},
[]byte{0xdd, 0xa9, 0x7c, 0xa4, 0x86, 0x4c, 0xdf, 0xe0, 0x6e, 0xaf, 0x70, 0xa0, 0xec, 0x0d, 0x71, 0x91},
},
- CryptTest{
+ {
// Appendix C.3. AES-256
[]byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
@@ -283,7 +283,7 @@ func TestEncryptBlock(t *testing.T) {
dec := make([]uint32, n)
expandKey(tt.key, enc, dec)
out := make([]byte, len(tt.in))
- encryptBlock(enc, tt.in, out)
+ encryptBlock(enc, out, tt.in)
for j, v := range out {
if v != tt.out[j] {
t.Errorf("encryptBlock %d: out[%d] = %#x, want %#x", i, j, v, tt.out[j])
@@ -301,7 +301,7 @@ func TestDecryptBlock(t *testing.T) {
dec := make([]uint32, n)
expandKey(tt.key, enc, dec)
plain := make([]byte, len(tt.in))
- decryptBlock(dec, tt.out, plain)
+ decryptBlock(dec, plain, tt.out)
for j, v := range plain {
if v != tt.in[j] {
t.Errorf("decryptBlock %d: plain[%d] = %#x, want %#x", i, j, v, tt.in[j])
@@ -320,7 +320,7 @@ func TestCipherEncrypt(t *testing.T) {
continue
}
out := make([]byte, len(tt.in))
- c.Encrypt(tt.in, out)
+ c.Encrypt(out, tt.in)
for j, v := range out {
if v != tt.out[j] {
t.Errorf("Cipher.Encrypt %d: out[%d] = %#x, want %#x", i, j, v, tt.out[j])
@@ -339,7 +339,7 @@ func TestCipherDecrypt(t *testing.T) {
continue
}
plain := make([]byte, len(tt.in))
- c.Decrypt(tt.out, plain)
+ c.Decrypt(plain, tt.out)
for j, v := range plain {
if v != tt.in[j] {
t.Errorf("decryptBlock %d: plain[%d] = %#x, want %#x", i, j, v, tt.in[j])
diff --git a/src/pkg/crypto/aes/block.go b/src/pkg/crypto/aes/block.go
index a502554bd..130cd011c 100644
--- a/src/pkg/crypto/aes/block.go
+++ b/src/pkg/crypto/aes/block.go
@@ -37,7 +37,7 @@
package aes
// Encrypt one block from src into dst, using the expanded key xk.
-func encryptBlock(xk []uint32, src, dst []byte) {
+func encryptBlock(xk []uint32, dst, src []byte) {
var s0, s1, s2, s3, t0, t1, t2, t3 uint32
s0 = uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
@@ -82,7 +82,7 @@ func encryptBlock(xk []uint32, src, dst []byte) {
}
// Decrypt one block from src into dst, using the expanded key xk.
-func decryptBlock(xk []uint32, src, dst []byte) {
+func decryptBlock(xk []uint32, dst, src []byte) {
var s0, s1, s2, s3, t0, t1, t2, t3 uint32
s0 = uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
diff --git a/src/pkg/crypto/aes/cipher.go b/src/pkg/crypto/aes/cipher.go
index 44e905e01..3a9d02318 100644
--- a/src/pkg/crypto/aes/cipher.go
+++ b/src/pkg/crypto/aes/cipher.go
@@ -53,11 +53,11 @@ func (c *Cipher) BlockSize() int { return BlockSize }
// Note that for amounts of data larger than a block,
// it is not safe to just call Encrypt on successive blocks;
// instead, use an encryption mode like CBC (see crypto/block/cbc.go).
-func (c *Cipher) Encrypt(src, dst []byte) { encryptBlock(c.enc, src, dst) }
+func (c *Cipher) Encrypt(dst, src []byte) { encryptBlock(c.enc, dst, src) }
// Decrypt decrypts the 16-byte buffer src using the key k
// and stores the result in dst.
-func (c *Cipher) Decrypt(src, dst []byte) { decryptBlock(c.dec, src, 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.
diff --git a/src/pkg/crypto/aes/const.go b/src/pkg/crypto/aes/const.go
index 8ddcaff26..97a5b64ec 100644
--- a/src/pkg/crypto/aes/const.go
+++ b/src/pkg/crypto/aes/const.go
@@ -81,7 +81,7 @@ var sbox1 = [256]byte{
// These can be recomputed by adapting the tests in aes_test.go.
var te = [4][256]uint32{
- [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,
@@ -115,7 +115,7 @@ var te = [4][256]uint32{
0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17, 0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8,
0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11, 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a,
},
- [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,
@@ -149,7 +149,7 @@ var te = [4][256]uint32{
0x8f038c8c, 0xf859a1a1, 0x80098989, 0x171a0d0d, 0xda65bfbf, 0x31d7e6e6, 0xc6844242, 0xb8d06868,
0xc3824141, 0xb0299999, 0x775a2d2d, 0x111e0f0f, 0xcb7bb0b0, 0xfca85454, 0xd66dbbbb, 0x3a2c1616,
},
- [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,
@@ -183,7 +183,7 @@ var te = [4][256]uint32{
0x8c8f038c, 0xa1f859a1, 0x89800989, 0x0d171a0d, 0xbfda65bf, 0xe631d7e6, 0x42c68442, 0x68b8d068,
0x41c38241, 0x99b02999, 0x2d775a2d, 0x0f111e0f, 0xb0cb7bb0, 0x54fca854, 0xbbd66dbb, 0x163a2c16,
},
- [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,
@@ -223,7 +223,7 @@ var te = [4][256]uint32{
// These can be recomputed by adapting the tests in aes_test.go.
var td = [4][256]uint32{
- [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,
@@ -257,7 +257,7 @@ var td = [4][256]uint32{
0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f, 0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541,
0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190, 0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742,
},
- [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,
@@ -291,7 +291,7 @@ var td = [4][256]uint32{
0x81caaff3, 0x3eb968c4, 0x2c382434, 0x5fc2a340, 0x72161dc3, 0x0cbce225, 0x8b283c49, 0x41ff0d95,
0x7139a801, 0xde080cb3, 0x9cd8b4e4, 0x906456c1, 0x617bcb84, 0x70d532b6, 0x74486c5c, 0x42d0b857,
},
- [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,
@@ -325,7 +325,7 @@ var td = [4][256]uint32{
0xf381caaf, 0xc43eb968, 0x342c3824, 0x405fc2a3, 0xc372161d, 0x250cbce2, 0x498b283c, 0x9541ff0d,
0x017139a8, 0xb3de080c, 0xe49cd8b4, 0xc1906456, 0x84617bcb, 0xb670d532, 0x5c74486c, 0x5742d0b8,
},
- [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,
diff --git a/src/pkg/crypto/block/Makefile b/src/pkg/crypto/block/Makefile
index 25c3483ae..71c7aff64 100644
--- a/src/pkg/crypto/block/Makefile
+++ b/src/pkg/crypto/block/Makefile
@@ -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 ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=crypto/block
GOFILES=\
diff --git a/src/pkg/crypto/block/cbc.go b/src/pkg/crypto/block/cbc.go
index 10235f541..23229c09f 100644
--- a/src/pkg/crypto/block/cbc.go
+++ b/src/pkg/crypto/block/cbc.go
@@ -27,14 +27,14 @@ func newCBC(c Cipher, iv []byte) *cbcCipher {
x := new(cbcCipher)
x.c = c
x.blockSize = n
- x.iv = copy(iv)
+ x.iv = dup(iv)
x.tmp = make([]byte, n)
return x
}
func (x *cbcCipher) BlockSize() int { return x.blockSize }
-func (x *cbcCipher) Encrypt(src, dst []byte) {
+func (x *cbcCipher) Encrypt(dst, src []byte) {
for i := 0; i < x.blockSize; i++ {
x.iv[i] ^= src[i]
}
@@ -44,8 +44,8 @@ func (x *cbcCipher) Encrypt(src, dst []byte) {
}
}
-func (x *cbcCipher) Decrypt(src, dst []byte) {
- x.c.Decrypt(src, x.tmp)
+func (x *cbcCipher) Decrypt(dst, src []byte) {
+ x.c.Decrypt(x.tmp, src)
for i := 0; i < x.blockSize; i++ {
x.tmp[i] ^= x.iv[i]
x.iv[i] = src[i]
diff --git a/src/pkg/crypto/block/cfb.go b/src/pkg/crypto/block/cfb.go
index 177ae939d..f20c0a04f 100644
--- a/src/pkg/crypto/block/cfb.go
+++ b/src/pkg/crypto/block/cfb.go
@@ -33,16 +33,16 @@ func newCFB(c Cipher, s int, iv []byte) *cfbCipher {
x.c = c
x.blockSize = s / 8
x.cipherSize = b
- x.iv = copy(iv)
+ x.iv = dup(iv)
x.tmp = make([]byte, b)
return x
}
func (x *cfbCipher) BlockSize() int { return x.blockSize }
-func (x *cfbCipher) Encrypt(src, dst []byte) {
+func (x *cfbCipher) Encrypt(dst, src []byte) {
// Encrypt old IV and xor prefix with src to make dst.
- x.c.Encrypt(x.iv, x.tmp)
+ x.c.Encrypt(x.tmp, x.iv)
for i := 0; i < x.blockSize; i++ {
dst[i] = src[i] ^ x.tmp[i]
}
@@ -57,9 +57,9 @@ func (x *cfbCipher) Encrypt(src, dst []byte) {
}
}
-func (x *cfbCipher) Decrypt(src, dst []byte) {
+func (x *cfbCipher) Decrypt(dst, src []byte) {
// Encrypt [sic] old IV and xor prefix with src to make dst.
- x.c.Encrypt(x.iv, x.tmp)
+ x.c.Encrypt(x.tmp, x.iv)
for i := 0; i < x.blockSize; i++ {
dst[i] = src[i] ^ x.tmp[i]
}
diff --git a/src/pkg/crypto/block/cfb_aes_test.go b/src/pkg/crypto/block/cfb_aes_test.go
index 8a245a2cb..e400c182a 100644
--- a/src/pkg/crypto/block/cfb_aes_test.go
+++ b/src/pkg/crypto/block/cfb_aes_test.go
@@ -27,7 +27,7 @@ type cfbTest struct {
}
var cfbAESTests = []cfbTest{
- cfbTest{
+ {
"CFB1-AES128",
1,
commonKey128,
@@ -41,7 +41,7 @@ var cfbAESTests = []cfbTest{
1<<7 | 0<<6 | 1<<5 | 1<<4 | 0<<3 | 0<<2 | 1<<1,
},
},
- cfbTest{
+ {
"CFB1-AES192",
1,
commonKey192,
@@ -55,7 +55,7 @@ var cfbAESTests = []cfbTest{
0<<7 | 1<<6 | 0<<5 | 1<<4 | 1<<3 | 0<<2 | 0<<1,
},
},
- cfbTest{
+ {
"CFB1-AES256",
1,
commonKey256,
@@ -70,7 +70,7 @@ var cfbAESTests = []cfbTest{
},
},
- cfbTest{
+ {
"CFB8-AES128",
8,
commonKey128,
@@ -117,7 +117,7 @@ var cfbAESTests = []cfbTest{
},
},
- cfbTest{
+ {
"CFB8-AES192",
8,
commonKey192,
@@ -164,7 +164,7 @@ var cfbAESTests = []cfbTest{
},
},
- cfbTest{
+ {
"CFB8-AES256",
8,
commonKey256,
@@ -211,7 +211,7 @@ var cfbAESTests = []cfbTest{
},
},
- cfbTest{
+ {
"CFB128-AES128",
128,
commonKey128,
@@ -230,7 +230,7 @@ var cfbAESTests = []cfbTest{
},
},
- cfbTest{
+ {
"CFB128-AES192",
128,
commonKey192,
@@ -249,7 +249,7 @@ var cfbAESTests = []cfbTest{
},
},
- cfbTest{
+ {
"CFB128-AES256",
128,
commonKey256,
diff --git a/src/pkg/crypto/block/cipher.go b/src/pkg/crypto/block/cipher.go
index 1b786cca4..e1099e9a1 100644
--- a/src/pkg/crypto/block/cipher.go
+++ b/src/pkg/crypto/block/cipher.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// The block package is deprecated, use cipher instead.
// The block package implements standard block cipher modes
// that can be wrapped around low-level block cipher implementations.
// See http://csrc.nist.gov/groups/ST/toolkit/BCM/current_modes.html
@@ -18,16 +19,16 @@ type Cipher interface {
// Encrypt encrypts the first block in src into dst.
// Src and dst may point at the same memory.
- Encrypt(src, dst []byte)
+ Encrypt(dst, src []byte)
// Decrypt decrypts the first block in src into dst.
// Src and dst may point at the same memory.
- Decrypt(src, dst []byte)
+ Decrypt(dst, src []byte)
}
// Utility routines
-func shift1(src, dst []byte) byte {
+func shift1(dst, src []byte) byte {
var b byte
for i := len(src) - 1; i >= 0; i-- {
bb := src[i] >> 7
@@ -49,10 +50,8 @@ func same(p, q []byte) bool {
return true
}
-func copy(p []byte) []byte {
+func dup(p []byte) []byte {
q := make([]byte, len(p))
- for i, b := range p {
- q[i] = b
- }
+ copy(q, p)
return q
}
diff --git a/src/pkg/crypto/block/cmac.go b/src/pkg/crypto/block/cmac.go
index 6082299ab..b85cde72e 100644
--- a/src/pkg/crypto/block/cmac.go
+++ b/src/pkg/crypto/block/cmac.go
@@ -52,7 +52,7 @@ func NewCMAC(c Cipher) hash.Hash {
if shift1(d.k1, d.k1) != 0 {
d.k1[n-1] ^= r
}
- if shift1(d.k1, d.k2) != 0 {
+ if shift1(d.k2, d.k1) != 0 {
d.k2[n-1] ^= r
}
diff --git a/src/pkg/crypto/block/cmac_aes_test.go b/src/pkg/crypto/block/cmac_aes_test.go
index a9cbc71a6..0a4a1a418 100644
--- a/src/pkg/crypto/block/cmac_aes_test.go
+++ b/src/pkg/crypto/block/cmac_aes_test.go
@@ -18,17 +18,17 @@ type cmacAESTest struct {
}
var cmacAESTests = []cmacAESTest{
- cmacAESTest{
+ {
commonKey128,
nil,
[]byte{0xbb, 0x1d, 0x69, 0x29, 0xe9, 0x59, 0x37, 0x28, 0x7f, 0xa3, 0x7d, 0x12, 0x9b, 0x75, 0x67, 0x46},
},
- cmacAESTest{
+ {
commonKey128,
[]byte{0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a},
[]byte{0x07, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44, 0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c},
},
- cmacAESTest{
+ {
commonKey128,
[]byte{
0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
@@ -37,7 +37,7 @@ var cmacAESTests = []cmacAESTest{
},
[]byte{0xdf, 0xa6, 0x67, 0x47, 0xde, 0x9a, 0xe6, 0x30, 0x30, 0xca, 0x32, 0x61, 0x14, 0x97, 0xc8, 0x27},
},
- cmacAESTest{
+ {
commonKey128,
[]byte{
0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
@@ -47,17 +47,17 @@ var cmacAESTests = []cmacAESTest{
},
[]byte{0x51, 0xf0, 0xbe, 0xbf, 0x7e, 0x3b, 0x9d, 0x92, 0xfc, 0x49, 0x74, 0x17, 0x79, 0x36, 0x3c, 0xfe},
},
- cmacAESTest{
+ {
commonKey192,
nil,
[]byte{0xd1, 0x7d, 0xdf, 0x46, 0xad, 0xaa, 0xcd, 0xe5, 0x31, 0xca, 0xc4, 0x83, 0xde, 0x7a, 0x93, 0x67},
},
- cmacAESTest{
+ {
commonKey192,
[]byte{0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a},
[]byte{0x9e, 0x99, 0xa7, 0xbf, 0x31, 0xe7, 0x10, 0x90, 0x06, 0x62, 0xf6, 0x5e, 0x61, 0x7c, 0x51, 0x84},
},
- cmacAESTest{
+ {
commonKey192,
[]byte{
0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
@@ -66,7 +66,7 @@ var cmacAESTests = []cmacAESTest{
},
[]byte{0x8a, 0x1d, 0xe5, 0xbe, 0x2e, 0xb3, 0x1a, 0xad, 0x08, 0x9a, 0x82, 0xe6, 0xee, 0x90, 0x8b, 0x0e},
},
- cmacAESTest{
+ {
commonKey192,
[]byte{
0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
@@ -76,17 +76,17 @@ var cmacAESTests = []cmacAESTest{
},
[]byte{0xa1, 0xd5, 0xdf, 0x0e, 0xed, 0x79, 0x0f, 0x79, 0x4d, 0x77, 0x58, 0x96, 0x59, 0xf3, 0x9a, 0x11},
},
- cmacAESTest{
+ {
commonKey256,
nil,
[]byte{0x02, 0x89, 0x62, 0xf6, 0x1b, 0x7b, 0xf8, 0x9e, 0xfc, 0x6b, 0x55, 0x1f, 0x46, 0x67, 0xd9, 0x83},
},
- cmacAESTest{
+ {
commonKey256,
[]byte{0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a},
[]byte{0x28, 0xa7, 0x02, 0x3f, 0x45, 0x2e, 0x8f, 0x82, 0xbd, 0x4b, 0xf2, 0x8d, 0x8c, 0x37, 0xc3, 0x5c},
},
- cmacAESTest{
+ {
commonKey256,
[]byte{
0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
@@ -95,7 +95,7 @@ var cmacAESTests = []cmacAESTest{
},
[]byte{0xaa, 0xf3, 0xd8, 0xf1, 0xde, 0x56, 0x40, 0xc2, 0x32, 0xf5, 0xb1, 0x69, 0xb9, 0xc9, 0x11, 0xe6},
},
- cmacAESTest{
+ {
commonKey256,
[]byte{
0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
diff --git a/src/pkg/crypto/block/ctr.go b/src/pkg/crypto/block/ctr.go
index 085ae05b1..5d65c0c9a 100644
--- a/src/pkg/crypto/block/ctr.go
+++ b/src/pkg/crypto/block/ctr.go
@@ -25,14 +25,14 @@ type ctrStream struct {
func newCTRStream(c Cipher, ctr []byte) *ctrStream {
x := new(ctrStream)
x.c = c
- x.ctr = copy(ctr)
+ x.ctr = dup(ctr)
x.out = make([]byte, len(ctr))
return x
}
func (x *ctrStream) Next() []byte {
// Next block is encryption of counter.
- x.c.Encrypt(x.ctr, x.out)
+ x.c.Encrypt(x.out, x.ctr)
// Increment counter
for i := len(x.ctr) - 1; i >= 0; i-- {
diff --git a/src/pkg/crypto/block/eax.go b/src/pkg/crypto/block/eax.go
index cc3662787..3f3b96431 100644
--- a/src/pkg/crypto/block/eax.go
+++ b/src/pkg/crypto/block/eax.go
@@ -45,8 +45,8 @@ func setupEAX(c Cipher, iv, hdr []byte, tagBytes int) (ctrIV, tag []byte, cmac h
cmac.Write(buf) // 0
cmac.Write(iv)
sum := cmac.Sum()
- ctrIV = copy(sum)
- tag = copy(sum[0:tagBytes])
+ ctrIV = dup(sum)
+ tag = dup(sum[0:tagBytes])
cmac.Reset()
buf[n-1] = 1
@@ -237,8 +237,8 @@ func (x *eaxDecrypter) checkTag() os.Error {
finishEAX(x.tag, x.cr.cmac)
if !same(x.tag, x.cr.tag) {
e := new(EAXTagError)
- e.Computed = copy(x.tag)
- e.Read = copy(x.cr.tag)
+ e.Computed = dup(x.tag)
+ e.Read = dup(x.cr.tag)
return e
}
return nil
diff --git a/src/pkg/crypto/block/eax_aes_test.go b/src/pkg/crypto/block/eax_aes_test.go
index a1a099429..93aa771be 100644
--- a/src/pkg/crypto/block/eax_aes_test.go
+++ b/src/pkg/crypto/block/eax_aes_test.go
@@ -23,70 +23,70 @@ type eaxAESTest struct {
}
var eaxAESTests = []eaxAESTest{
- eaxAESTest{
+ {
[]byte{},
[]byte{0x23, 0x39, 0x52, 0xDE, 0xE4, 0xD5, 0xED, 0x5F, 0x9B, 0x9C, 0x6D, 0x6F, 0xF8, 0x0F, 0xF4, 0x78},
[]byte{0x62, 0xEC, 0x67, 0xF9, 0xC3, 0xA4, 0xA4, 0x07, 0xFC, 0xB2, 0xA8, 0xC4, 0x90, 0x31, 0xA8, 0xB3},
[]byte{0x6B, 0xFB, 0x91, 0x4F, 0xD0, 0x7E, 0xAE, 0x6B},
[]byte{0xE0, 0x37, 0x83, 0x0E, 0x83, 0x89, 0xF2, 0x7B, 0x02, 0x5A, 0x2D, 0x65, 0x27, 0xE7, 0x9D, 0x01},
},
- eaxAESTest{
+ {
[]byte{0xF7, 0xFB},
[]byte{0x91, 0x94, 0x5D, 0x3F, 0x4D, 0xCB, 0xEE, 0x0B, 0xF4, 0x5E, 0xF5, 0x22, 0x55, 0xF0, 0x95, 0xA4},
[]byte{0xBE, 0xCA, 0xF0, 0x43, 0xB0, 0xA2, 0x3D, 0x84, 0x31, 0x94, 0xBA, 0x97, 0x2C, 0x66, 0xDE, 0xBD},
[]byte{0xFA, 0x3B, 0xFD, 0x48, 0x06, 0xEB, 0x53, 0xFA},
[]byte{0x19, 0xDD, 0x5C, 0x4C, 0x93, 0x31, 0x04, 0x9D, 0x0B, 0xDA, 0xB0, 0x27, 0x74, 0x08, 0xF6, 0x79, 0x67, 0xE5},
},
- eaxAESTest{
+ {
[]byte{0x1A, 0x47, 0xCB, 0x49, 0x33},
[]byte{0x01, 0xF7, 0x4A, 0xD6, 0x40, 0x77, 0xF2, 0xE7, 0x04, 0xC0, 0xF6, 0x0A, 0xDA, 0x3D, 0xD5, 0x23},
[]byte{0x70, 0xC3, 0xDB, 0x4F, 0x0D, 0x26, 0x36, 0x84, 0x00, 0xA1, 0x0E, 0xD0, 0x5D, 0x2B, 0xFF, 0x5E},
[]byte{0x23, 0x4A, 0x34, 0x63, 0xC1, 0x26, 0x4A, 0xC6},
[]byte{0xD8, 0x51, 0xD5, 0xBA, 0xE0, 0x3A, 0x59, 0xF2, 0x38, 0xA2, 0x3E, 0x39, 0x19, 0x9D, 0xC9, 0x26, 0x66, 0x26, 0xC4, 0x0F, 0x80},
},
- eaxAESTest{
+ {
[]byte{0x48, 0x1C, 0x9E, 0x39, 0xB1},
[]byte{0xD0, 0x7C, 0xF6, 0xCB, 0xB7, 0xF3, 0x13, 0xBD, 0xDE, 0x66, 0xB7, 0x27, 0xAF, 0xD3, 0xC5, 0xE8},
[]byte{0x84, 0x08, 0xDF, 0xFF, 0x3C, 0x1A, 0x2B, 0x12, 0x92, 0xDC, 0x19, 0x9E, 0x46, 0xB7, 0xD6, 0x17},
[]byte{0x33, 0xCC, 0xE2, 0xEA, 0xBF, 0xF5, 0xA7, 0x9D},
[]byte{0x63, 0x2A, 0x9D, 0x13, 0x1A, 0xD4, 0xC1, 0x68, 0xA4, 0x22, 0x5D, 0x8E, 0x1F, 0xF7, 0x55, 0x93, 0x99, 0x74, 0xA7, 0xBE, 0xDE},
},
- eaxAESTest{
+ {
[]byte{0x40, 0xD0, 0xC0, 0x7D, 0xA5, 0xE4},
[]byte{0x35, 0xB6, 0xD0, 0x58, 0x00, 0x05, 0xBB, 0xC1, 0x2B, 0x05, 0x87, 0x12, 0x45, 0x57, 0xD2, 0xC2},
[]byte{0xFD, 0xB6, 0xB0, 0x66, 0x76, 0xEE, 0xDC, 0x5C, 0x61, 0xD7, 0x42, 0x76, 0xE1, 0xF8, 0xE8, 0x16},
[]byte{0xAE, 0xB9, 0x6E, 0xAE, 0xBE, 0x29, 0x70, 0xE9},
[]byte{0x07, 0x1D, 0xFE, 0x16, 0xC6, 0x75, 0xCB, 0x06, 0x77, 0xE5, 0x36, 0xF7, 0x3A, 0xFE, 0x6A, 0x14, 0xB7, 0x4E, 0xE4, 0x98, 0x44, 0xDD},
},
- eaxAESTest{
+ {
[]byte{0x4D, 0xE3, 0xB3, 0x5C, 0x3F, 0xC0, 0x39, 0x24, 0x5B, 0xD1, 0xFB, 0x7D},
[]byte{0xBD, 0x8E, 0x6E, 0x11, 0x47, 0x5E, 0x60, 0xB2, 0x68, 0x78, 0x4C, 0x38, 0xC6, 0x2F, 0xEB, 0x22},
[]byte{0x6E, 0xAC, 0x5C, 0x93, 0x07, 0x2D, 0x8E, 0x85, 0x13, 0xF7, 0x50, 0x93, 0x5E, 0x46, 0xDA, 0x1B},
[]byte{0xD4, 0x48, 0x2D, 0x1C, 0xA7, 0x8D, 0xCE, 0x0F},
[]byte{0x83, 0x5B, 0xB4, 0xF1, 0x5D, 0x74, 0x3E, 0x35, 0x0E, 0x72, 0x84, 0x14, 0xAB, 0xB8, 0x64, 0x4F, 0xD6, 0xCC, 0xB8, 0x69, 0x47, 0xC5, 0xE1, 0x05, 0x90, 0x21, 0x0A, 0x4F},
},
- eaxAESTest{
+ {
[]byte{0x8B, 0x0A, 0x79, 0x30, 0x6C, 0x9C, 0xE7, 0xED, 0x99, 0xDA, 0xE4, 0xF8, 0x7F, 0x8D, 0xD6, 0x16, 0x36},
[]byte{0x7C, 0x77, 0xD6, 0xE8, 0x13, 0xBE, 0xD5, 0xAC, 0x98, 0xBA, 0xA4, 0x17, 0x47, 0x7A, 0x2E, 0x7D},
[]byte{0x1A, 0x8C, 0x98, 0xDC, 0xD7, 0x3D, 0x38, 0x39, 0x3B, 0x2B, 0xF1, 0x56, 0x9D, 0xEE, 0xFC, 0x19},
[]byte{0x65, 0xD2, 0x01, 0x79, 0x90, 0xD6, 0x25, 0x28},
[]byte{0x02, 0x08, 0x3E, 0x39, 0x79, 0xDA, 0x01, 0x48, 0x12, 0xF5, 0x9F, 0x11, 0xD5, 0x26, 0x30, 0xDA, 0x30, 0x13, 0x73, 0x27, 0xD1, 0x06, 0x49, 0xB0, 0xAA, 0x6E, 0x1C, 0x18, 0x1D, 0xB6, 0x17, 0xD7, 0xF2},
},
- eaxAESTest{
+ {
[]byte{0x1B, 0xDA, 0x12, 0x2B, 0xCE, 0x8A, 0x8D, 0xBA, 0xF1, 0x87, 0x7D, 0x96, 0x2B, 0x85, 0x92, 0xDD, 0x2D, 0x56},
[]byte{0x5F, 0xFF, 0x20, 0xCA, 0xFA, 0xB1, 0x19, 0xCA, 0x2F, 0xC7, 0x35, 0x49, 0xE2, 0x0F, 0x5B, 0x0D},
[]byte{0xDD, 0xE5, 0x9B, 0x97, 0xD7, 0x22, 0x15, 0x6D, 0x4D, 0x9A, 0xFF, 0x2B, 0xC7, 0x55, 0x98, 0x26},
[]byte{0x54, 0xB9, 0xF0, 0x4E, 0x6A, 0x09, 0x18, 0x9A},
[]byte{0x2E, 0xC4, 0x7B, 0x2C, 0x49, 0x54, 0xA4, 0x89, 0xAF, 0xC7, 0xBA, 0x48, 0x97, 0xED, 0xCD, 0xAE, 0x8C, 0xC3, 0x3B, 0x60, 0x45, 0x05, 0x99, 0xBD, 0x02, 0xC9, 0x63, 0x82, 0x90, 0x2A, 0xEF, 0x7F, 0x83, 0x2A},
},
- eaxAESTest{
+ {
[]byte{0x6C, 0xF3, 0x67, 0x20, 0x87, 0x2B, 0x85, 0x13, 0xF6, 0xEA, 0xB1, 0xA8, 0xA4, 0x44, 0x38, 0xD5, 0xEF, 0x11},
[]byte{0xA4, 0xA4, 0x78, 0x2B, 0xCF, 0xFD, 0x3E, 0xC5, 0xE7, 0xEF, 0x6D, 0x8C, 0x34, 0xA5, 0x61, 0x23},
[]byte{0xB7, 0x81, 0xFC, 0xF2, 0xF7, 0x5F, 0xA5, 0xA8, 0xDE, 0x97, 0xA9, 0xCA, 0x48, 0xE5, 0x22, 0xEC},
[]byte{0x89, 0x9A, 0x17, 0x58, 0x97, 0x56, 0x1D, 0x7E},
[]byte{0x0D, 0xE1, 0x8F, 0xD0, 0xFD, 0xD9, 0x1E, 0x7A, 0xF1, 0x9F, 0x1D, 0x8E, 0xE8, 0x73, 0x39, 0x38, 0xB1, 0xE8, 0xE7, 0xF6, 0xD2, 0x23, 0x16, 0x18, 0x10, 0x2F, 0xDB, 0x7F, 0xE5, 0x5F, 0xF1, 0x99, 0x17, 0x00},
},
- eaxAESTest{
+ {
[]byte{0xCA, 0x40, 0xD7, 0x44, 0x6E, 0x54, 0x5F, 0xFA, 0xED, 0x3B, 0xD1, 0x2A, 0x74, 0x0A, 0x65, 0x9F, 0xFB, 0xBB, 0x3C, 0xEA, 0xB7},
[]byte{0x83, 0x95, 0xFC, 0xF1, 0xE9, 0x5B, 0xEB, 0xD6, 0x97, 0xBD, 0x01, 0x0B, 0xC7, 0x66, 0xAA, 0xC3},
[]byte{0x22, 0xE7, 0xAD, 0xD9, 0x3C, 0xFC, 0x63, 0x93, 0xC5, 0x7E, 0xC0, 0xB3, 0xC1, 0x7D, 0x6B, 0x44},
diff --git a/src/pkg/crypto/block/ecb.go b/src/pkg/crypto/block/ecb.go
index 73d1d63f7..cf09f7cb3 100644
--- a/src/pkg/crypto/block/ecb.go
+++ b/src/pkg/crypto/block/ecb.go
@@ -127,9 +127,7 @@ func (x *ecbDecrypter) Read(p []byte) (n int, err os.Error) {
// Save it for next time.
if i < n {
p = p[i:n]
- for j, v := range p {
- x.buf[j] = v
- }
+ copy(x.buf, p)
x.crypt = x.buf[0:len(p)]
n = i
}
@@ -191,11 +189,7 @@ func (x *ecbEncrypter) slidePlain() {
if len(x.plain) == 0 {
x.plain = x.buf[0:0]
} else if cap(x.plain) < cap(x.buf) {
- // plain and buf share same data,
- // but buf is before plain, so forward loop is correct
- for i := 0; i < len(x.plain); i++ {
- x.buf[i] = x.plain[i]
- }
+ copy(x.buf, x.plain)
x.plain = x.buf[0:len(x.plain)]
}
}
diff --git a/src/pkg/crypto/block/ecb_aes_test.go b/src/pkg/crypto/block/ecb_aes_test.go
index db0e085fa..14481d096 100644
--- a/src/pkg/crypto/block/ecb_aes_test.go
+++ b/src/pkg/crypto/block/ecb_aes_test.go
@@ -47,7 +47,7 @@ var commonIV = []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09
var ecbAESTests = []ecbTest{
// FIPS 197, Appendix B, C
- ecbTest{
+ {
"FIPS-197 Appendix B",
commonKey128,
[]byte{0x32, 0x43, 0xf6, 0xa8, 0x88, 0x5a, 0x30, 0x8d, 0x31, 0x31, 0x98, 0xa2, 0xe0, 0x37, 0x07, 0x34},
@@ -55,7 +55,7 @@ var ecbAESTests = []ecbTest{
},
// NIST SP 800-38A pp 24-27
- ecbTest{
+ {
"ECB-AES128",
commonKey128,
commonInput,
@@ -66,7 +66,7 @@ var ecbAESTests = []ecbTest{
0x7b, 0x0c, 0x78, 0x5e, 0x27, 0xe8, 0xad, 0x3f, 0x82, 0x23, 0x20, 0x71, 0x04, 0x72, 0x5d, 0xd4,
},
},
- ecbTest{
+ {
"ECB-AES192",
commonKey192,
commonInput,
@@ -77,7 +77,7 @@ var ecbAESTests = []ecbTest{
0x9a, 0x4b, 0x41, 0xba, 0x73, 0x8d, 0x6c, 0x72, 0xfb, 0x16, 0x69, 0x16, 0x03, 0xc1, 0x8e, 0x0e,
},
},
- ecbTest{
+ {
"ECB-AES256",
commonKey256,
commonInput,
diff --git a/src/pkg/crypto/block/ecb_test.go b/src/pkg/crypto/block/ecb_test.go
index 1e991e1dd..6f79d929a 100644
--- a/src/pkg/crypto/block/ecb_test.go
+++ b/src/pkg/crypto/block/ecb_test.go
@@ -22,7 +22,7 @@ type IncCipher struct {
func (c *IncCipher) BlockSize() int { return c.blockSize }
-func (c *IncCipher) Encrypt(src, dst []byte) {
+func (c *IncCipher) Encrypt(dst, src []byte) {
if !c.encrypting {
panic("encrypt: not encrypting")
}
@@ -35,7 +35,7 @@ func (c *IncCipher) Encrypt(src, dst []byte) {
}
}
-func (c *IncCipher) Decrypt(src, dst []byte) {
+func (c *IncCipher) Decrypt(dst, src []byte) {
if c.encrypting {
panic("decrypt: not decrypting")
}
diff --git a/src/pkg/crypto/block/ofb.go b/src/pkg/crypto/block/ofb.go
index 0cd5e73c4..11aaaa4d7 100644
--- a/src/pkg/crypto/block/ofb.go
+++ b/src/pkg/crypto/block/ofb.go
@@ -29,7 +29,7 @@ func newOFBStream(c Cipher, iv []byte) *ofbStream {
if n != c.BlockSize() {
panic(fmt.Sprintln("crypto/block: newOFBStream: invalid iv size", n, "!=", c.BlockSize()))
}
- x.iv = copy(iv)
+ x.iv = dup(iv)
return x
}
diff --git a/src/pkg/crypto/block/ofb_aes_test.go b/src/pkg/crypto/block/ofb_aes_test.go
index f2faa4432..9c527a6b3 100644
--- a/src/pkg/crypto/block/ofb_aes_test.go
+++ b/src/pkg/crypto/block/ofb_aes_test.go
@@ -27,7 +27,7 @@ type ofbTest struct {
var ofbAESTests = []ofbTest{
// NIST SP 800-38A pp 52-55
- ofbTest{
+ {
"OFB-AES128",
commonKey128,
commonIV,
@@ -39,7 +39,7 @@ var ofbAESTests = []ofbTest{
0x30, 0x4c, 0x65, 0x28, 0xf6, 0x59, 0xc7, 0x78, 0x66, 0xa5, 0x10, 0xd9, 0xc1, 0xd6, 0xae, 0x5e,
},
},
- ofbTest{
+ {
"OFB-AES192",
commonKey192,
commonIV,
@@ -51,7 +51,7 @@ var ofbAESTests = []ofbTest{
0x6d, 0x9f, 0x20, 0x08, 0x57, 0xca, 0x6c, 0x3e, 0x9c, 0xac, 0x52, 0x4b, 0xd9, 0xac, 0xc9, 0x2a,
},
},
- ofbTest{
+ {
"OFB-AES256",
commonKey256,
commonIV,
diff --git a/src/pkg/crypto/blowfish/Makefile b/src/pkg/crypto/blowfish/Makefile
index c2999cc1d..f370ab28b 100644
--- a/src/pkg/crypto/blowfish/Makefile
+++ b/src/pkg/crypto/blowfish/Makefile
@@ -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 ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=crypto/blowfish
GOFILES=\
diff --git a/src/pkg/crypto/blowfish/blowfish_test.go b/src/pkg/crypto/blowfish/blowfish_test.go
index 44fed9668..3a7ab6c2a 100644
--- a/src/pkg/crypto/blowfish/blowfish_test.go
+++ b/src/pkg/crypto/blowfish/blowfish_test.go
@@ -16,140 +16,140 @@ type CryptTest struct {
// Test vector values are from http://www.schneier.com/code/vectors.txt.
var encryptTests = []CryptTest{
- 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}},
- CryptTest{
+ {
[]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}},
- CryptTest{
+ {
[]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}},
- CryptTest{
+ {
[]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}},
- CryptTest{
+ {
[]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}},
- CryptTest{
+ {
[]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}},
- 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}},
- CryptTest{
+ {
[]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}},
- CryptTest{
+ {
[]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}},
- CryptTest{
+ {
[]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}},
- CryptTest{
+ {
[]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}},
- CryptTest{
+ {
[]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}},
- CryptTest{
+ {
[]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}},
- CryptTest{
+ {
[]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}},
- CryptTest{
+ {
[]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}},
- CryptTest{
+ {
[]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}},
- CryptTest{
+ {
[]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}},
- CryptTest{
+ {
[]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}},
- CryptTest{
+ {
[]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}},
- CryptTest{
+ {
[]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}},
- CryptTest{
+ {
[]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}},
- CryptTest{
+ {
[]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}},
- CryptTest{
+ {
[]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}},
- CryptTest{
+ {
[]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}},
- CryptTest{
+ {
[]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}},
- CryptTest{
+ {
[]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}},
- CryptTest{
+ {
[]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}},
- CryptTest{
+ {
[]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}},
- CryptTest{
+ {
[]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}},
- CryptTest{
+ {
[]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}},
- CryptTest{
+ {
[]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}},
- CryptTest{
+ {
[]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}},
- CryptTest{
+ {
[]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}},
- CryptTest{
+ {
[]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}},
@@ -163,7 +163,7 @@ func TestCipherEncrypt(t *testing.T) {
continue
}
ct := make([]byte, len(tt.out))
- c.Encrypt(tt.in, ct)
+ 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])
@@ -181,7 +181,7 @@ func TestCipherDecrypt(t *testing.T) {
continue
}
pt := make([]byte, len(tt.in))
- c.Decrypt(tt.out, pt)
+ 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])
diff --git a/src/pkg/crypto/blowfish/cipher.go b/src/pkg/crypto/blowfish/cipher.go
index ee0def85e..947f762d8 100644
--- a/src/pkg/crypto/blowfish/cipher.go
+++ b/src/pkg/crypto/blowfish/cipher.go
@@ -50,7 +50,7 @@ func (c *Cipher) BlockSize() int { return BlockSize }
// Note that for amounts of data larger than a block,
// it is not safe to just call Encrypt on successive blocks;
// instead, use an encryption mode like CBC (see crypto/block/cbc.go).
-func (c *Cipher) Encrypt(src, dst []byte) {
+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)
@@ -60,7 +60,7 @@ func (c *Cipher) Encrypt(src, dst []byte) {
// Decrypt decrypts the 8-byte buffer src using the key k
// and stores the result in dst.
-func (c *Cipher) Decrypt(src, dst []byte) {
+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)
diff --git a/src/pkg/crypto/cast5/Makefile b/src/pkg/crypto/cast5/Makefile
new file mode 100644
index 000000000..346fadd94
--- /dev/null
+++ b/src/pkg/crypto/cast5/Makefile
@@ -0,0 +1,11 @@
+# Copyright 2010 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+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
new file mode 100644
index 000000000..35f3e64b6
--- /dev/null
+++ b/src/pkg/crypto/cast5/cast5.go
@@ -0,0 +1,536 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package implements CAST5, as defined in RFC 2144. CAST5 is a common
+// OpenPGP cipher.
+package cast5
+
+import (
+ "os"
+)
+
+const BlockSize = 8
+const KeySize = 16
+
+type Cipher struct {
+ masking [16]uint32
+ rotate [16]uint8
+}
+
+func NewCipher(key []byte) (c *Cipher, err os.Error) {
+ if len(key) != KeySize {
+ return nil, os.ErrorString("CAST5: keys must be 16 bytes")
+ }
+
+ c = new(Cipher)
+ c.keySchedule(key)
+ return
+}
+
+func (c *Cipher) BlockSize() int {
+ return BlockSize
+}
+
+// Reset zeros the key material in memory.
+func (c *Cipher) Reset() {
+ for i := 0; i < 16; i++ {
+ c.masking[i] = 0
+ c.rotate[i] = 0
+ }
+}
+
+func (c *Cipher) Encrypt(dst, src []byte) {
+ l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
+ r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
+
+ l, r = r, l^f1(r, c.masking[0], c.rotate[0])
+ l, r = r, l^f2(r, c.masking[1], c.rotate[1])
+ l, r = r, l^f3(r, c.masking[2], c.rotate[2])
+ l, r = r, l^f1(r, c.masking[3], c.rotate[3])
+
+ l, r = r, l^f2(r, c.masking[4], c.rotate[4])
+ l, r = r, l^f3(r, c.masking[5], c.rotate[5])
+ l, r = r, l^f1(r, c.masking[6], c.rotate[6])
+ l, r = r, l^f2(r, c.masking[7], c.rotate[7])
+
+ l, r = r, l^f3(r, c.masking[8], c.rotate[8])
+ l, r = r, l^f1(r, c.masking[9], c.rotate[9])
+ l, r = r, l^f2(r, c.masking[10], c.rotate[10])
+ l, r = r, l^f3(r, c.masking[11], c.rotate[11])
+
+ l, r = r, l^f1(r, c.masking[12], c.rotate[12])
+ l, r = r, l^f2(r, c.masking[13], c.rotate[13])
+ l, r = r, l^f3(r, c.masking[14], c.rotate[14])
+ l, r = r, l^f1(r, c.masking[15], c.rotate[15])
+
+ dst[0] = uint8(r >> 24)
+ dst[1] = uint8(r >> 16)
+ dst[2] = uint8(r >> 8)
+ dst[3] = uint8(r)
+ dst[4] = uint8(l >> 24)
+ dst[5] = uint8(l >> 16)
+ dst[6] = uint8(l >> 8)
+ dst[7] = uint8(l)
+}
+
+func (c *Cipher) Decrypt(dst, src []byte) {
+ l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
+ r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
+
+ l, r = r, l^f1(r, c.masking[15], c.rotate[15])
+ l, r = r, l^f3(r, c.masking[14], c.rotate[14])
+ l, r = r, l^f2(r, c.masking[13], c.rotate[13])
+ l, r = r, l^f1(r, c.masking[12], c.rotate[12])
+
+ l, r = r, l^f3(r, c.masking[11], c.rotate[11])
+ l, r = r, l^f2(r, c.masking[10], c.rotate[10])
+ l, r = r, l^f1(r, c.masking[9], c.rotate[9])
+ l, r = r, l^f3(r, c.masking[8], c.rotate[8])
+
+ l, r = r, l^f2(r, c.masking[7], c.rotate[7])
+ l, r = r, l^f1(r, c.masking[6], c.rotate[6])
+ l, r = r, l^f3(r, c.masking[5], c.rotate[5])
+ l, r = r, l^f2(r, c.masking[4], c.rotate[4])
+
+ l, r = r, l^f1(r, c.masking[3], c.rotate[3])
+ l, r = r, l^f3(r, c.masking[2], c.rotate[2])
+ l, r = r, l^f2(r, c.masking[1], c.rotate[1])
+ l, r = r, l^f1(r, c.masking[0], c.rotate[0])
+
+ dst[0] = uint8(r >> 24)
+ dst[1] = uint8(r >> 16)
+ dst[2] = uint8(r >> 8)
+ dst[3] = uint8(r)
+ dst[4] = uint8(l >> 24)
+ dst[5] = uint8(l >> 16)
+ dst[6] = uint8(l >> 8)
+ dst[7] = uint8(l)
+}
+
+type keyScheduleA [4][7]uint8
+type keyScheduleB [4][5]uint8
+
+// keyScheduleRound contains the magic values for a round of the key schedule.
+// The keyScheduleA deals with the lines like:
+// z0z1z2z3 = x0x1x2x3 ^ S5[xD] ^ S6[xF] ^ S7[xC] ^ S8[xE] ^ S7[x8]
+// Conceptually, both x and z are in the same array, x first. The first
+// element describes which word of this array gets written to and the
+// second, which word gets read. So, for the line above, it's "4, 0", because
+// it's writing to the first word of z, which, being after x, is word 4, and
+// reading from the first word of x: word 0.
+//
+// Next are the indexes into the S-boxes. Now the array is treated as bytes. So
+// "xD" is 0xd. The first byte of z is written as "16 + 0", just to be clear
+// that it's z that we're indexing.
+//
+// keyScheduleB deals with lines like:
+// K1 = S5[z8] ^ S6[z9] ^ S7[z7] ^ S8[z6] ^ S5[z2]
+// "K1" is ignored because key words are always written in order. So the five
+// elements are the S-box indexes. They use the same form as in keyScheduleA,
+// above.
+
+type keyScheduleRound struct{}
+type keySchedule []keyScheduleRound
+
+var schedule = []struct {
+ a keyScheduleA
+ b keyScheduleB
+}{
+ {
+ keyScheduleA{
+ {4, 0, 0xd, 0xf, 0xc, 0xe, 0x8},
+ {5, 2, 16 + 0, 16 + 2, 16 + 1, 16 + 3, 0xa},
+ {6, 3, 16 + 7, 16 + 6, 16 + 5, 16 + 4, 9},
+ {7, 1, 16 + 0xa, 16 + 9, 16 + 0xb, 16 + 8, 0xb},
+ },
+ keyScheduleB{
+ {16 + 8, 16 + 9, 16 + 7, 16 + 6, 16 + 2},
+ {16 + 0xa, 16 + 0xb, 16 + 5, 16 + 4, 16 + 6},
+ {16 + 0xc, 16 + 0xd, 16 + 3, 16 + 2, 16 + 9},
+ {16 + 0xe, 16 + 0xf, 16 + 1, 16 + 0, 16 + 0xc},
+ },
+ },
+ {
+ keyScheduleA{
+ {0, 6, 16 + 5, 16 + 7, 16 + 4, 16 + 6, 16 + 0},
+ {1, 4, 0, 2, 1, 3, 16 + 2},
+ {2, 5, 7, 6, 5, 4, 16 + 1},
+ {3, 7, 0xa, 9, 0xb, 8, 16 + 3},
+ },
+ keyScheduleB{
+ {3, 2, 0xc, 0xd, 8},
+ {1, 0, 0xe, 0xf, 0xd},
+ {7, 6, 8, 9, 3},
+ {5, 4, 0xa, 0xb, 7},
+ },
+ },
+ {
+ keyScheduleA{
+ {4, 0, 0xd, 0xf, 0xc, 0xe, 8},
+ {5, 2, 16 + 0, 16 + 2, 16 + 1, 16 + 3, 0xa},
+ {6, 3, 16 + 7, 16 + 6, 16 + 5, 16 + 4, 9},
+ {7, 1, 16 + 0xa, 16 + 9, 16 + 0xb, 16 + 8, 0xb},
+ },
+ keyScheduleB{
+ {16 + 3, 16 + 2, 16 + 0xc, 16 + 0xd, 16 + 9},
+ {16 + 1, 16 + 0, 16 + 0xe, 16 + 0xf, 16 + 0xc},
+ {16 + 7, 16 + 6, 16 + 8, 16 + 9, 16 + 2},
+ {16 + 5, 16 + 4, 16 + 0xa, 16 + 0xb, 16 + 6},
+ },
+ },
+ {
+ keyScheduleA{
+ {0, 6, 16 + 5, 16 + 7, 16 + 4, 16 + 6, 16 + 0},
+ {1, 4, 0, 2, 1, 3, 16 + 2},
+ {2, 5, 7, 6, 5, 4, 16 + 1},
+ {3, 7, 0xa, 9, 0xb, 8, 16 + 3},
+ },
+ keyScheduleB{
+ {8, 9, 7, 6, 3},
+ {0xa, 0xb, 5, 4, 7},
+ {0xc, 0xd, 3, 2, 8},
+ {0xe, 0xf, 1, 0, 0xd},
+ },
+ },
+}
+
+func (c *Cipher) keySchedule(in []byte) {
+ var t [8]uint32
+ var k [32]uint32
+
+ for i := 0; i < 4; i++ {
+ j := i * 4
+ t[i] = uint32(in[j])<<24 | uint32(in[j+1])<<16 | uint32(in[j+2])<<8 | uint32(in[j+3])
+ }
+
+ x := []byte{6, 7, 4, 5}
+ ki := 0
+
+ for half := 0; half < 2; half++ {
+ for _, round := range schedule {
+ for j := 0; j < 4; j++ {
+ var a [7]uint8
+ copy(a[:], round.a[j][:])
+ w := t[a[1]]
+ w ^= sBox[4][(t[a[2]>>2]>>(24-8*(a[2]&3)))&0xff]
+ w ^= sBox[5][(t[a[3]>>2]>>(24-8*(a[3]&3)))&0xff]
+ w ^= sBox[6][(t[a[4]>>2]>>(24-8*(a[4]&3)))&0xff]
+ w ^= sBox[7][(t[a[5]>>2]>>(24-8*(a[5]&3)))&0xff]
+ w ^= sBox[x[j]][(t[a[6]>>2]>>(24-8*(a[6]&3)))&0xff]
+ t[a[0]] = w
+ }
+
+ for j := 0; j < 4; j++ {
+ var b [5]uint8
+ copy(b[:], round.b[j][:])
+ w := sBox[4][(t[b[0]>>2]>>(24-8*(b[0]&3)))&0xff]
+ w ^= sBox[5][(t[b[1]>>2]>>(24-8*(b[1]&3)))&0xff]
+ w ^= sBox[6][(t[b[2]>>2]>>(24-8*(b[2]&3)))&0xff]
+ w ^= sBox[7][(t[b[3]>>2]>>(24-8*(b[3]&3)))&0xff]
+ w ^= sBox[4+j][(t[b[4]>>2]>>(24-8*(b[4]&3)))&0xff]
+ k[ki] = w
+ ki++
+ }
+ }
+ }
+
+ for i := 0; i < 16; i++ {
+ c.masking[i] = k[i]
+ c.rotate[i] = uint8(k[16+i] & 0x1f)
+ }
+}
+
+// These are the three 'f' functions. See RFC 2144, section 2.2.
+func f1(d, m uint32, r uint8) uint32 {
+ t := m + d
+ I := (t << r) | (t >> (32 - r))
+ return ((sBox[0][I>>24] ^ sBox[1][(I>>16)&0xff]) - sBox[2][(I>>8)&0xff]) + sBox[3][I&0xff]
+}
+
+func f2(d, m uint32, r uint8) uint32 {
+ t := m ^ d
+ I := (t << r) | (t >> (32 - r))
+ return ((sBox[0][I>>24] - sBox[1][(I>>16)&0xff]) + sBox[2][(I>>8)&0xff]) ^ sBox[3][I&0xff]
+}
+
+func f3(d, m uint32, r uint8) uint32 {
+ t := m - d
+ I := (t << r) | (t >> (32 - r))
+ return ((sBox[0][I>>24] + sBox[1][(I>>16)&0xff]) ^ sBox[2][(I>>8)&0xff]) - sBox[3][I&0xff]
+}
+
+var sBox = [8][256]uint32{
+ {
+ 0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f, 0x9c004dd3, 0x6003e540, 0xcf9fc949,
+ 0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675, 0x6e63a0e0, 0x15c361d2, 0xc2e7661d, 0x22d4ff8e,
+ 0x28683b6f, 0xc07fd059, 0xff2379c8, 0x775f50e2, 0x43c340d3, 0xdf2f8656, 0x887ca41a, 0xa2d2bd2d,
+ 0xa1c9e0d6, 0x346c4819, 0x61b76d87, 0x22540f2f, 0x2abe32e1, 0xaa54166b, 0x22568e3a, 0xa2d341d0,
+ 0x66db40c8, 0xa784392f, 0x004dff2f, 0x2db9d2de, 0x97943fac, 0x4a97c1d8, 0x527644b7, 0xb5f437a7,
+ 0xb82cbaef, 0xd751d159, 0x6ff7f0ed, 0x5a097a1f, 0x827b68d0, 0x90ecf52e, 0x22b0c054, 0xbc8e5935,
+ 0x4b6d2f7f, 0x50bb64a2, 0xd2664910, 0xbee5812d, 0xb7332290, 0xe93b159f, 0xb48ee411, 0x4bff345d,
+ 0xfd45c240, 0xad31973f, 0xc4f6d02e, 0x55fc8165, 0xd5b1caad, 0xa1ac2dae, 0xa2d4b76d, 0xc19b0c50,
+ 0x882240f2, 0x0c6e4f38, 0xa4e4bfd7, 0x4f5ba272, 0x564c1d2f, 0xc59c5319, 0xb949e354, 0xb04669fe,
+ 0xb1b6ab8a, 0xc71358dd, 0x6385c545, 0x110f935d, 0x57538ad5, 0x6a390493, 0xe63d37e0, 0x2a54f6b3,
+ 0x3a787d5f, 0x6276a0b5, 0x19a6fcdf, 0x7a42206a, 0x29f9d4d5, 0xf61b1891, 0xbb72275e, 0xaa508167,
+ 0x38901091, 0xc6b505eb, 0x84c7cb8c, 0x2ad75a0f, 0x874a1427, 0xa2d1936b, 0x2ad286af, 0xaa56d291,
+ 0xd7894360, 0x425c750d, 0x93b39e26, 0x187184c9, 0x6c00b32d, 0x73e2bb14, 0xa0bebc3c, 0x54623779,
+ 0x64459eab, 0x3f328b82, 0x7718cf82, 0x59a2cea6, 0x04ee002e, 0x89fe78e6, 0x3fab0950, 0x325ff6c2,
+ 0x81383f05, 0x6963c5c8, 0x76cb5ad6, 0xd49974c9, 0xca180dcf, 0x380782d5, 0xc7fa5cf6, 0x8ac31511,
+ 0x35e79e13, 0x47da91d0, 0xf40f9086, 0xa7e2419e, 0x31366241, 0x051ef495, 0xaa573b04, 0x4a805d8d,
+ 0x548300d0, 0x00322a3c, 0xbf64cddf, 0xba57a68e, 0x75c6372b, 0x50afd341, 0xa7c13275, 0x915a0bf5,
+ 0x6b54bfab, 0x2b0b1426, 0xab4cc9d7, 0x449ccd82, 0xf7fbf265, 0xab85c5f3, 0x1b55db94, 0xaad4e324,
+ 0xcfa4bd3f, 0x2deaa3e2, 0x9e204d02, 0xc8bd25ac, 0xeadf55b3, 0xd5bd9e98, 0xe31231b2, 0x2ad5ad6c,
+ 0x954329de, 0xadbe4528, 0xd8710f69, 0xaa51c90f, 0xaa786bf6, 0x22513f1e, 0xaa51a79b, 0x2ad344cc,
+ 0x7b5a41f0, 0xd37cfbad, 0x1b069505, 0x41ece491, 0xb4c332e6, 0x032268d4, 0xc9600acc, 0xce387e6d,
+ 0xbf6bb16c, 0x6a70fb78, 0x0d03d9c9, 0xd4df39de, 0xe01063da, 0x4736f464, 0x5ad328d8, 0xb347cc96,
+ 0x75bb0fc3, 0x98511bfb, 0x4ffbcc35, 0xb58bcf6a, 0xe11f0abc, 0xbfc5fe4a, 0xa70aec10, 0xac39570a,
+ 0x3f04442f, 0x6188b153, 0xe0397a2e, 0x5727cb79, 0x9ceb418f, 0x1cacd68d, 0x2ad37c96, 0x0175cb9d,
+ 0xc69dff09, 0xc75b65f0, 0xd9db40d8, 0xec0e7779, 0x4744ead4, 0xb11c3274, 0xdd24cb9e, 0x7e1c54bd,
+ 0xf01144f9, 0xd2240eb1, 0x9675b3fd, 0xa3ac3755, 0xd47c27af, 0x51c85f4d, 0x56907596, 0xa5bb15e6,
+ 0x580304f0, 0xca042cf1, 0x011a37ea, 0x8dbfaadb, 0x35ba3e4a, 0x3526ffa0, 0xc37b4d09, 0xbc306ed9,
+ 0x98a52666, 0x5648f725, 0xff5e569d, 0x0ced63d0, 0x7c63b2cf, 0x700b45e1, 0xd5ea50f1, 0x85a92872,
+ 0xaf1fbda7, 0xd4234870, 0xa7870bf3, 0x2d3b4d79, 0x42e04198, 0x0cd0ede7, 0x26470db8, 0xf881814c,
+ 0x474d6ad7, 0x7c0c5e5c, 0xd1231959, 0x381b7298, 0xf5d2f4db, 0xab838653, 0x6e2f1e23, 0x83719c9e,
+ 0xbd91e046, 0x9a56456e, 0xdc39200c, 0x20c8c571, 0x962bda1c, 0xe1e696ff, 0xb141ab08, 0x7cca89b9,
+ 0x1a69e783, 0x02cc4843, 0xa2f7c579, 0x429ef47d, 0x427b169c, 0x5ac9f049, 0xdd8f0f00, 0x5c8165bf,
+ },
+ {
+ 0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380, 0xfe61cf7a, 0xeec5207a, 0x55889c94, 0x72fc0651,
+ 0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba, 0x99c430ef, 0x5f0c0794, 0x18dcdb7d, 0xa1d6eff3,
+ 0xa0b52f7b, 0x59e83605, 0xee15b094, 0xe9ffd909, 0xdc440086, 0xef944459, 0xba83ccb3, 0xe0c3cdfb,
+ 0xd1da4181, 0x3b092ab1, 0xf997f1c1, 0xa5e6cf7b, 0x01420ddb, 0xe4e7ef5b, 0x25a1ff41, 0xe180f806,
+ 0x1fc41080, 0x179bee7a, 0xd37ac6a9, 0xfe5830a4, 0x98de8b7f, 0x77e83f4e, 0x79929269, 0x24fa9f7b,
+ 0xe113c85b, 0xacc40083, 0xd7503525, 0xf7ea615f, 0x62143154, 0x0d554b63, 0x5d681121, 0xc866c359,
+ 0x3d63cf73, 0xcee234c0, 0xd4d87e87, 0x5c672b21, 0x071f6181, 0x39f7627f, 0x361e3084, 0xe4eb573b,
+ 0x602f64a4, 0xd63acd9c, 0x1bbc4635, 0x9e81032d, 0x2701f50c, 0x99847ab4, 0xa0e3df79, 0xba6cf38c,
+ 0x10843094, 0x2537a95e, 0xf46f6ffe, 0xa1ff3b1f, 0x208cfb6a, 0x8f458c74, 0xd9e0a227, 0x4ec73a34,
+ 0xfc884f69, 0x3e4de8df, 0xef0e0088, 0x3559648d, 0x8a45388c, 0x1d804366, 0x721d9bfd, 0xa58684bb,
+ 0xe8256333, 0x844e8212, 0x128d8098, 0xfed33fb4, 0xce280ae1, 0x27e19ba5, 0xd5a6c252, 0xe49754bd,
+ 0xc5d655dd, 0xeb667064, 0x77840b4d, 0xa1b6a801, 0x84db26a9, 0xe0b56714, 0x21f043b7, 0xe5d05860,
+ 0x54f03084, 0x066ff472, 0xa31aa153, 0xdadc4755, 0xb5625dbf, 0x68561be6, 0x83ca6b94, 0x2d6ed23b,
+ 0xeccf01db, 0xa6d3d0ba, 0xb6803d5c, 0xaf77a709, 0x33b4a34c, 0x397bc8d6, 0x5ee22b95, 0x5f0e5304,
+ 0x81ed6f61, 0x20e74364, 0xb45e1378, 0xde18639b, 0x881ca122, 0xb96726d1, 0x8049a7e8, 0x22b7da7b,
+ 0x5e552d25, 0x5272d237, 0x79d2951c, 0xc60d894c, 0x488cb402, 0x1ba4fe5b, 0xa4b09f6b, 0x1ca815cf,
+ 0xa20c3005, 0x8871df63, 0xb9de2fcb, 0x0cc6c9e9, 0x0beeff53, 0xe3214517, 0xb4542835, 0x9f63293c,
+ 0xee41e729, 0x6e1d2d7c, 0x50045286, 0x1e6685f3, 0xf33401c6, 0x30a22c95, 0x31a70850, 0x60930f13,
+ 0x73f98417, 0xa1269859, 0xec645c44, 0x52c877a9, 0xcdff33a6, 0xa02b1741, 0x7cbad9a2, 0x2180036f,
+ 0x50d99c08, 0xcb3f4861, 0xc26bd765, 0x64a3f6ab, 0x80342676, 0x25a75e7b, 0xe4e6d1fc, 0x20c710e6,
+ 0xcdf0b680, 0x17844d3b, 0x31eef84d, 0x7e0824e4, 0x2ccb49eb, 0x846a3bae, 0x8ff77888, 0xee5d60f6,
+ 0x7af75673, 0x2fdd5cdb, 0xa11631c1, 0x30f66f43, 0xb3faec54, 0x157fd7fa, 0xef8579cc, 0xd152de58,
+ 0xdb2ffd5e, 0x8f32ce19, 0x306af97a, 0x02f03ef8, 0x99319ad5, 0xc242fa0f, 0xa7e3ebb0, 0xc68e4906,
+ 0xb8da230c, 0x80823028, 0xdcdef3c8, 0xd35fb171, 0x088a1bc8, 0xbec0c560, 0x61a3c9e8, 0xbca8f54d,
+ 0xc72feffa, 0x22822e99, 0x82c570b4, 0xd8d94e89, 0x8b1c34bc, 0x301e16e6, 0x273be979, 0xb0ffeaa6,
+ 0x61d9b8c6, 0x00b24869, 0xb7ffce3f, 0x08dc283b, 0x43daf65a, 0xf7e19798, 0x7619b72f, 0x8f1c9ba4,
+ 0xdc8637a0, 0x16a7d3b1, 0x9fc393b7, 0xa7136eeb, 0xc6bcc63e, 0x1a513742, 0xef6828bc, 0x520365d6,
+ 0x2d6a77ab, 0x3527ed4b, 0x821fd216, 0x095c6e2e, 0xdb92f2fb, 0x5eea29cb, 0x145892f5, 0x91584f7f,
+ 0x5483697b, 0x2667a8cc, 0x85196048, 0x8c4bacea, 0x833860d4, 0x0d23e0f9, 0x6c387e8a, 0x0ae6d249,
+ 0xb284600c, 0xd835731d, 0xdcb1c647, 0xac4c56ea, 0x3ebd81b3, 0x230eabb0, 0x6438bc87, 0xf0b5b1fa,
+ 0x8f5ea2b3, 0xfc184642, 0x0a036b7a, 0x4fb089bd, 0x649da589, 0xa345415e, 0x5c038323, 0x3e5d3bb9,
+ 0x43d79572, 0x7e6dd07c, 0x06dfdf1e, 0x6c6cc4ef, 0x7160a539, 0x73bfbe70, 0x83877605, 0x4523ecf1,
+ },
+ {
+ 0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907, 0x47607fff, 0x369fe44b, 0x8c1fc644, 0xaececa90,
+ 0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae, 0x920e8806, 0xf0ad0548, 0xe13c8d83, 0x927010d5,
+ 0x11107d9f, 0x07647db9, 0xb2e3e4d4, 0x3d4f285e, 0xb9afa820, 0xfade82e0, 0xa067268b, 0x8272792e,
+ 0x553fb2c0, 0x489ae22b, 0xd4ef9794, 0x125e3fbc, 0x21fffcee, 0x825b1bfd, 0x9255c5ed, 0x1257a240,
+ 0x4e1a8302, 0xbae07fff, 0x528246e7, 0x8e57140e, 0x3373f7bf, 0x8c9f8188, 0xa6fc4ee8, 0xc982b5a5,
+ 0xa8c01db7, 0x579fc264, 0x67094f31, 0xf2bd3f5f, 0x40fff7c1, 0x1fb78dfc, 0x8e6bd2c1, 0x437be59b,
+ 0x99b03dbf, 0xb5dbc64b, 0x638dc0e6, 0x55819d99, 0xa197c81c, 0x4a012d6e, 0xc5884a28, 0xccc36f71,
+ 0xb843c213, 0x6c0743f1, 0x8309893c, 0x0feddd5f, 0x2f7fe850, 0xd7c07f7e, 0x02507fbf, 0x5afb9a04,
+ 0xa747d2d0, 0x1651192e, 0xaf70bf3e, 0x58c31380, 0x5f98302e, 0x727cc3c4, 0x0a0fb402, 0x0f7fef82,
+ 0x8c96fdad, 0x5d2c2aae, 0x8ee99a49, 0x50da88b8, 0x8427f4a0, 0x1eac5790, 0x796fb449, 0x8252dc15,
+ 0xefbd7d9b, 0xa672597d, 0xada840d8, 0x45f54504, 0xfa5d7403, 0xe83ec305, 0x4f91751a, 0x925669c2,
+ 0x23efe941, 0xa903f12e, 0x60270df2, 0x0276e4b6, 0x94fd6574, 0x927985b2, 0x8276dbcb, 0x02778176,
+ 0xf8af918d, 0x4e48f79e, 0x8f616ddf, 0xe29d840e, 0x842f7d83, 0x340ce5c8, 0x96bbb682, 0x93b4b148,
+ 0xef303cab, 0x984faf28, 0x779faf9b, 0x92dc560d, 0x224d1e20, 0x8437aa88, 0x7d29dc96, 0x2756d3dc,
+ 0x8b907cee, 0xb51fd240, 0xe7c07ce3, 0xe566b4a1, 0xc3e9615e, 0x3cf8209d, 0x6094d1e3, 0xcd9ca341,
+ 0x5c76460e, 0x00ea983b, 0xd4d67881, 0xfd47572c, 0xf76cedd9, 0xbda8229c, 0x127dadaa, 0x438a074e,
+ 0x1f97c090, 0x081bdb8a, 0x93a07ebe, 0xb938ca15, 0x97b03cff, 0x3dc2c0f8, 0x8d1ab2ec, 0x64380e51,
+ 0x68cc7bfb, 0xd90f2788, 0x12490181, 0x5de5ffd4, 0xdd7ef86a, 0x76a2e214, 0xb9a40368, 0x925d958f,
+ 0x4b39fffa, 0xba39aee9, 0xa4ffd30b, 0xfaf7933b, 0x6d498623, 0x193cbcfa, 0x27627545, 0x825cf47a,
+ 0x61bd8ba0, 0xd11e42d1, 0xcead04f4, 0x127ea392, 0x10428db7, 0x8272a972, 0x9270c4a8, 0x127de50b,
+ 0x285ba1c8, 0x3c62f44f, 0x35c0eaa5, 0xe805d231, 0x428929fb, 0xb4fcdf82, 0x4fb66a53, 0x0e7dc15b,
+ 0x1f081fab, 0x108618ae, 0xfcfd086d, 0xf9ff2889, 0x694bcc11, 0x236a5cae, 0x12deca4d, 0x2c3f8cc5,
+ 0xd2d02dfe, 0xf8ef5896, 0xe4cf52da, 0x95155b67, 0x494a488c, 0xb9b6a80c, 0x5c8f82bc, 0x89d36b45,
+ 0x3a609437, 0xec00c9a9, 0x44715253, 0x0a874b49, 0xd773bc40, 0x7c34671c, 0x02717ef6, 0x4feb5536,
+ 0xa2d02fff, 0xd2bf60c4, 0xd43f03c0, 0x50b4ef6d, 0x07478cd1, 0x006e1888, 0xa2e53f55, 0xb9e6d4bc,
+ 0xa2048016, 0x97573833, 0xd7207d67, 0xde0f8f3d, 0x72f87b33, 0xabcc4f33, 0x7688c55d, 0x7b00a6b0,
+ 0x947b0001, 0x570075d2, 0xf9bb88f8, 0x8942019e, 0x4264a5ff, 0x856302e0, 0x72dbd92b, 0xee971b69,
+ 0x6ea22fde, 0x5f08ae2b, 0xaf7a616d, 0xe5c98767, 0xcf1febd2, 0x61efc8c2, 0xf1ac2571, 0xcc8239c2,
+ 0x67214cb8, 0xb1e583d1, 0xb7dc3e62, 0x7f10bdce, 0xf90a5c38, 0x0ff0443d, 0x606e6dc6, 0x60543a49,
+ 0x5727c148, 0x2be98a1d, 0x8ab41738, 0x20e1be24, 0xaf96da0f, 0x68458425, 0x99833be5, 0x600d457d,
+ 0x282f9350, 0x8334b362, 0xd91d1120, 0x2b6d8da0, 0x642b1e31, 0x9c305a00, 0x52bce688, 0x1b03588a,
+ 0xf7baefd5, 0x4142ed9c, 0xa4315c11, 0x83323ec5, 0xdfef4636, 0xa133c501, 0xe9d3531c, 0xee353783,
+ },
+ {
+ 0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, 0x4a4f7bdb, 0x64ad8c57, 0x85510443, 0xfa020ed1,
+ 0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120, 0xfd059d43, 0x6497b7b1, 0xf3641f63, 0x241e4adf,
+ 0x28147f5f, 0x4fa2b8cd, 0xc9430040, 0x0cc32220, 0xfdd30b30, 0xc0a5374f, 0x1d2d00d9, 0x24147b15,
+ 0xee4d111a, 0x0fca5167, 0x71ff904c, 0x2d195ffe, 0x1a05645f, 0x0c13fefe, 0x081b08ca, 0x05170121,
+ 0x80530100, 0xe83e5efe, 0xac9af4f8, 0x7fe72701, 0xd2b8ee5f, 0x06df4261, 0xbb9e9b8a, 0x7293ea25,
+ 0xce84ffdf, 0xf5718801, 0x3dd64b04, 0xa26f263b, 0x7ed48400, 0x547eebe6, 0x446d4ca0, 0x6cf3d6f5,
+ 0x2649abdf, 0xaea0c7f5, 0x36338cc1, 0x503f7e93, 0xd3772061, 0x11b638e1, 0x72500e03, 0xf80eb2bb,
+ 0xabe0502e, 0xec8d77de, 0x57971e81, 0xe14f6746, 0xc9335400, 0x6920318f, 0x081dbb99, 0xffc304a5,
+ 0x4d351805, 0x7f3d5ce3, 0xa6c866c6, 0x5d5bcca9, 0xdaec6fea, 0x9f926f91, 0x9f46222f, 0x3991467d,
+ 0xa5bf6d8e, 0x1143c44f, 0x43958302, 0xd0214eeb, 0x022083b8, 0x3fb6180c, 0x18f8931e, 0x281658e6,
+ 0x26486e3e, 0x8bd78a70, 0x7477e4c1, 0xb506e07c, 0xf32d0a25, 0x79098b02, 0xe4eabb81, 0x28123b23,
+ 0x69dead38, 0x1574ca16, 0xdf871b62, 0x211c40b7, 0xa51a9ef9, 0x0014377b, 0x041e8ac8, 0x09114003,
+ 0xbd59e4d2, 0xe3d156d5, 0x4fe876d5, 0x2f91a340, 0x557be8de, 0x00eae4a7, 0x0ce5c2ec, 0x4db4bba6,
+ 0xe756bdff, 0xdd3369ac, 0xec17b035, 0x06572327, 0x99afc8b0, 0x56c8c391, 0x6b65811c, 0x5e146119,
+ 0x6e85cb75, 0xbe07c002, 0xc2325577, 0x893ff4ec, 0x5bbfc92d, 0xd0ec3b25, 0xb7801ab7, 0x8d6d3b24,
+ 0x20c763ef, 0xc366a5fc, 0x9c382880, 0x0ace3205, 0xaac9548a, 0xeca1d7c7, 0x041afa32, 0x1d16625a,
+ 0x6701902c, 0x9b757a54, 0x31d477f7, 0x9126b031, 0x36cc6fdb, 0xc70b8b46, 0xd9e66a48, 0x56e55a79,
+ 0x026a4ceb, 0x52437eff, 0x2f8f76b4, 0x0df980a5, 0x8674cde3, 0xedda04eb, 0x17a9be04, 0x2c18f4df,
+ 0xb7747f9d, 0xab2af7b4, 0xefc34d20, 0x2e096b7c, 0x1741a254, 0xe5b6a035, 0x213d42f6, 0x2c1c7c26,
+ 0x61c2f50f, 0x6552daf9, 0xd2c231f8, 0x25130f69, 0xd8167fa2, 0x0418f2c8, 0x001a96a6, 0x0d1526ab,
+ 0x63315c21, 0x5e0a72ec, 0x49bafefd, 0x187908d9, 0x8d0dbd86, 0x311170a7, 0x3e9b640c, 0xcc3e10d7,
+ 0xd5cad3b6, 0x0caec388, 0xf73001e1, 0x6c728aff, 0x71eae2a1, 0x1f9af36e, 0xcfcbd12f, 0xc1de8417,
+ 0xac07be6b, 0xcb44a1d8, 0x8b9b0f56, 0x013988c3, 0xb1c52fca, 0xb4be31cd, 0xd8782806, 0x12a3a4e2,
+ 0x6f7de532, 0x58fd7eb6, 0xd01ee900, 0x24adffc2, 0xf4990fc5, 0x9711aac5, 0x001d7b95, 0x82e5e7d2,
+ 0x109873f6, 0x00613096, 0xc32d9521, 0xada121ff, 0x29908415, 0x7fbb977f, 0xaf9eb3db, 0x29c9ed2a,
+ 0x5ce2a465, 0xa730f32c, 0xd0aa3fe8, 0x8a5cc091, 0xd49e2ce7, 0x0ce454a9, 0xd60acd86, 0x015f1919,
+ 0x77079103, 0xdea03af6, 0x78a8565e, 0xdee356df, 0x21f05cbe, 0x8b75e387, 0xb3c50651, 0xb8a5c3ef,
+ 0xd8eeb6d2, 0xe523be77, 0xc2154529, 0x2f69efdf, 0xafe67afb, 0xf470c4b2, 0xf3e0eb5b, 0xd6cc9876,
+ 0x39e4460c, 0x1fda8538, 0x1987832f, 0xca007367, 0xa99144f8, 0x296b299e, 0x492fc295, 0x9266beab,
+ 0xb5676e69, 0x9bd3ddda, 0xdf7e052f, 0xdb25701c, 0x1b5e51ee, 0xf65324e6, 0x6afce36c, 0x0316cc04,
+ 0x8644213e, 0xb7dc59d0, 0x7965291f, 0xccd6fd43, 0x41823979, 0x932bcdf6, 0xb657c34d, 0x4edfd282,
+ 0x7ae5290c, 0x3cb9536b, 0x851e20fe, 0x9833557e, 0x13ecf0b0, 0xd3ffb372, 0x3f85c5c1, 0x0aef7ed2,
+ },
+ {
+ 0x7ec90c04, 0x2c6e74b9, 0x9b0e66df, 0xa6337911, 0xb86a7fff, 0x1dd358f5, 0x44dd9d44, 0x1731167f,
+ 0x08fbf1fa, 0xe7f511cc, 0xd2051b00, 0x735aba00, 0x2ab722d8, 0x386381cb, 0xacf6243a, 0x69befd7a,
+ 0xe6a2e77f, 0xf0c720cd, 0xc4494816, 0xccf5c180, 0x38851640, 0x15b0a848, 0xe68b18cb, 0x4caadeff,
+ 0x5f480a01, 0x0412b2aa, 0x259814fc, 0x41d0efe2, 0x4e40b48d, 0x248eb6fb, 0x8dba1cfe, 0x41a99b02,
+ 0x1a550a04, 0xba8f65cb, 0x7251f4e7, 0x95a51725, 0xc106ecd7, 0x97a5980a, 0xc539b9aa, 0x4d79fe6a,
+ 0xf2f3f763, 0x68af8040, 0xed0c9e56, 0x11b4958b, 0xe1eb5a88, 0x8709e6b0, 0xd7e07156, 0x4e29fea7,
+ 0x6366e52d, 0x02d1c000, 0xc4ac8e05, 0x9377f571, 0x0c05372a, 0x578535f2, 0x2261be02, 0xd642a0c9,
+ 0xdf13a280, 0x74b55bd2, 0x682199c0, 0xd421e5ec, 0x53fb3ce8, 0xc8adedb3, 0x28a87fc9, 0x3d959981,
+ 0x5c1ff900, 0xfe38d399, 0x0c4eff0b, 0x062407ea, 0xaa2f4fb1, 0x4fb96976, 0x90c79505, 0xb0a8a774,
+ 0xef55a1ff, 0xe59ca2c2, 0xa6b62d27, 0xe66a4263, 0xdf65001f, 0x0ec50966, 0xdfdd55bc, 0x29de0655,
+ 0x911e739a, 0x17af8975, 0x32c7911c, 0x89f89468, 0x0d01e980, 0x524755f4, 0x03b63cc9, 0x0cc844b2,
+ 0xbcf3f0aa, 0x87ac36e9, 0xe53a7426, 0x01b3d82b, 0x1a9e7449, 0x64ee2d7e, 0xcddbb1da, 0x01c94910,
+ 0xb868bf80, 0x0d26f3fd, 0x9342ede7, 0x04a5c284, 0x636737b6, 0x50f5b616, 0xf24766e3, 0x8eca36c1,
+ 0x136e05db, 0xfef18391, 0xfb887a37, 0xd6e7f7d4, 0xc7fb7dc9, 0x3063fcdf, 0xb6f589de, 0xec2941da,
+ 0x26e46695, 0xb7566419, 0xf654efc5, 0xd08d58b7, 0x48925401, 0xc1bacb7f, 0xe5ff550f, 0xb6083049,
+ 0x5bb5d0e8, 0x87d72e5a, 0xab6a6ee1, 0x223a66ce, 0xc62bf3cd, 0x9e0885f9, 0x68cb3e47, 0x086c010f,
+ 0xa21de820, 0xd18b69de, 0xf3f65777, 0xfa02c3f6, 0x407edac3, 0xcbb3d550, 0x1793084d, 0xb0d70eba,
+ 0x0ab378d5, 0xd951fb0c, 0xded7da56, 0x4124bbe4, 0x94ca0b56, 0x0f5755d1, 0xe0e1e56e, 0x6184b5be,
+ 0x580a249f, 0x94f74bc0, 0xe327888e, 0x9f7b5561, 0xc3dc0280, 0x05687715, 0x646c6bd7, 0x44904db3,
+ 0x66b4f0a3, 0xc0f1648a, 0x697ed5af, 0x49e92ff6, 0x309e374f, 0x2cb6356a, 0x85808573, 0x4991f840,
+ 0x76f0ae02, 0x083be84d, 0x28421c9a, 0x44489406, 0x736e4cb8, 0xc1092910, 0x8bc95fc6, 0x7d869cf4,
+ 0x134f616f, 0x2e77118d, 0xb31b2be1, 0xaa90b472, 0x3ca5d717, 0x7d161bba, 0x9cad9010, 0xaf462ba2,
+ 0x9fe459d2, 0x45d34559, 0xd9f2da13, 0xdbc65487, 0xf3e4f94e, 0x176d486f, 0x097c13ea, 0x631da5c7,
+ 0x445f7382, 0x175683f4, 0xcdc66a97, 0x70be0288, 0xb3cdcf72, 0x6e5dd2f3, 0x20936079, 0x459b80a5,
+ 0xbe60e2db, 0xa9c23101, 0xeba5315c, 0x224e42f2, 0x1c5c1572, 0xf6721b2c, 0x1ad2fff3, 0x8c25404e,
+ 0x324ed72f, 0x4067b7fd, 0x0523138e, 0x5ca3bc78, 0xdc0fd66e, 0x75922283, 0x784d6b17, 0x58ebb16e,
+ 0x44094f85, 0x3f481d87, 0xfcfeae7b, 0x77b5ff76, 0x8c2302bf, 0xaaf47556, 0x5f46b02a, 0x2b092801,
+ 0x3d38f5f7, 0x0ca81f36, 0x52af4a8a, 0x66d5e7c0, 0xdf3b0874, 0x95055110, 0x1b5ad7a8, 0xf61ed5ad,
+ 0x6cf6e479, 0x20758184, 0xd0cefa65, 0x88f7be58, 0x4a046826, 0x0ff6f8f3, 0xa09c7f70, 0x5346aba0,
+ 0x5ce96c28, 0xe176eda3, 0x6bac307f, 0x376829d2, 0x85360fa9, 0x17e3fe2a, 0x24b79767, 0xf5a96b20,
+ 0xd6cd2595, 0x68ff1ebf, 0x7555442c, 0xf19f06be, 0xf9e0659a, 0xeeb9491d, 0x34010718, 0xbb30cab8,
+ 0xe822fe15, 0x88570983, 0x750e6249, 0xda627e55, 0x5e76ffa8, 0xb1534546, 0x6d47de08, 0xefe9e7d4,
+ },
+ {
+ 0xf6fa8f9d, 0x2cac6ce1, 0x4ca34867, 0xe2337f7c, 0x95db08e7, 0x016843b4, 0xeced5cbc, 0x325553ac,
+ 0xbf9f0960, 0xdfa1e2ed, 0x83f0579d, 0x63ed86b9, 0x1ab6a6b8, 0xde5ebe39, 0xf38ff732, 0x8989b138,
+ 0x33f14961, 0xc01937bd, 0xf506c6da, 0xe4625e7e, 0xa308ea99, 0x4e23e33c, 0x79cbd7cc, 0x48a14367,
+ 0xa3149619, 0xfec94bd5, 0xa114174a, 0xeaa01866, 0xa084db2d, 0x09a8486f, 0xa888614a, 0x2900af98,
+ 0x01665991, 0xe1992863, 0xc8f30c60, 0x2e78ef3c, 0xd0d51932, 0xcf0fec14, 0xf7ca07d2, 0xd0a82072,
+ 0xfd41197e, 0x9305a6b0, 0xe86be3da, 0x74bed3cd, 0x372da53c, 0x4c7f4448, 0xdab5d440, 0x6dba0ec3,
+ 0x083919a7, 0x9fbaeed9, 0x49dbcfb0, 0x4e670c53, 0x5c3d9c01, 0x64bdb941, 0x2c0e636a, 0xba7dd9cd,
+ 0xea6f7388, 0xe70bc762, 0x35f29adb, 0x5c4cdd8d, 0xf0d48d8c, 0xb88153e2, 0x08a19866, 0x1ae2eac8,
+ 0x284caf89, 0xaa928223, 0x9334be53, 0x3b3a21bf, 0x16434be3, 0x9aea3906, 0xefe8c36e, 0xf890cdd9,
+ 0x80226dae, 0xc340a4a3, 0xdf7e9c09, 0xa694a807, 0x5b7c5ecc, 0x221db3a6, 0x9a69a02f, 0x68818a54,
+ 0xceb2296f, 0x53c0843a, 0xfe893655, 0x25bfe68a, 0xb4628abc, 0xcf222ebf, 0x25ac6f48, 0xa9a99387,
+ 0x53bddb65, 0xe76ffbe7, 0xe967fd78, 0x0ba93563, 0x8e342bc1, 0xe8a11be9, 0x4980740d, 0xc8087dfc,
+ 0x8de4bf99, 0xa11101a0, 0x7fd37975, 0xda5a26c0, 0xe81f994f, 0x9528cd89, 0xfd339fed, 0xb87834bf,
+ 0x5f04456d, 0x22258698, 0xc9c4c83b, 0x2dc156be, 0x4f628daa, 0x57f55ec5, 0xe2220abe, 0xd2916ebf,
+ 0x4ec75b95, 0x24f2c3c0, 0x42d15d99, 0xcd0d7fa0, 0x7b6e27ff, 0xa8dc8af0, 0x7345c106, 0xf41e232f,
+ 0x35162386, 0xe6ea8926, 0x3333b094, 0x157ec6f2, 0x372b74af, 0x692573e4, 0xe9a9d848, 0xf3160289,
+ 0x3a62ef1d, 0xa787e238, 0xf3a5f676, 0x74364853, 0x20951063, 0x4576698d, 0xb6fad407, 0x592af950,
+ 0x36f73523, 0x4cfb6e87, 0x7da4cec0, 0x6c152daa, 0xcb0396a8, 0xc50dfe5d, 0xfcd707ab, 0x0921c42f,
+ 0x89dff0bb, 0x5fe2be78, 0x448f4f33, 0x754613c9, 0x2b05d08d, 0x48b9d585, 0xdc049441, 0xc8098f9b,
+ 0x7dede786, 0xc39a3373, 0x42410005, 0x6a091751, 0x0ef3c8a6, 0x890072d6, 0x28207682, 0xa9a9f7be,
+ 0xbf32679d, 0xd45b5b75, 0xb353fd00, 0xcbb0e358, 0x830f220a, 0x1f8fb214, 0xd372cf08, 0xcc3c4a13,
+ 0x8cf63166, 0x061c87be, 0x88c98f88, 0x6062e397, 0x47cf8e7a, 0xb6c85283, 0x3cc2acfb, 0x3fc06976,
+ 0x4e8f0252, 0x64d8314d, 0xda3870e3, 0x1e665459, 0xc10908f0, 0x513021a5, 0x6c5b68b7, 0x822f8aa0,
+ 0x3007cd3e, 0x74719eef, 0xdc872681, 0x073340d4, 0x7e432fd9, 0x0c5ec241, 0x8809286c, 0xf592d891,
+ 0x08a930f6, 0x957ef305, 0xb7fbffbd, 0xc266e96f, 0x6fe4ac98, 0xb173ecc0, 0xbc60b42a, 0x953498da,
+ 0xfba1ae12, 0x2d4bd736, 0x0f25faab, 0xa4f3fceb, 0xe2969123, 0x257f0c3d, 0x9348af49, 0x361400bc,
+ 0xe8816f4a, 0x3814f200, 0xa3f94043, 0x9c7a54c2, 0xbc704f57, 0xda41e7f9, 0xc25ad33a, 0x54f4a084,
+ 0xb17f5505, 0x59357cbe, 0xedbd15c8, 0x7f97c5ab, 0xba5ac7b5, 0xb6f6deaf, 0x3a479c3a, 0x5302da25,
+ 0x653d7e6a, 0x54268d49, 0x51a477ea, 0x5017d55b, 0xd7d25d88, 0x44136c76, 0x0404a8c8, 0xb8e5a121,
+ 0xb81a928a, 0x60ed5869, 0x97c55b96, 0xeaec991b, 0x29935913, 0x01fdb7f1, 0x088e8dfa, 0x9ab6f6f5,
+ 0x3b4cbf9f, 0x4a5de3ab, 0xe6051d35, 0xa0e1d855, 0xd36b4cf1, 0xf544edeb, 0xb0e93524, 0xbebb8fbd,
+ 0xa2d762cf, 0x49c92f54, 0x38b5f331, 0x7128a454, 0x48392905, 0xa65b1db8, 0x851c97bd, 0xd675cf2f,
+ },
+ {
+ 0x85e04019, 0x332bf567, 0x662dbfff, 0xcfc65693, 0x2a8d7f6f, 0xab9bc912, 0xde6008a1, 0x2028da1f,
+ 0x0227bce7, 0x4d642916, 0x18fac300, 0x50f18b82, 0x2cb2cb11, 0xb232e75c, 0x4b3695f2, 0xb28707de,
+ 0xa05fbcf6, 0xcd4181e9, 0xe150210c, 0xe24ef1bd, 0xb168c381, 0xfde4e789, 0x5c79b0d8, 0x1e8bfd43,
+ 0x4d495001, 0x38be4341, 0x913cee1d, 0x92a79c3f, 0x089766be, 0xbaeeadf4, 0x1286becf, 0xb6eacb19,
+ 0x2660c200, 0x7565bde4, 0x64241f7a, 0x8248dca9, 0xc3b3ad66, 0x28136086, 0x0bd8dfa8, 0x356d1cf2,
+ 0x107789be, 0xb3b2e9ce, 0x0502aa8f, 0x0bc0351e, 0x166bf52a, 0xeb12ff82, 0xe3486911, 0xd34d7516,
+ 0x4e7b3aff, 0x5f43671b, 0x9cf6e037, 0x4981ac83, 0x334266ce, 0x8c9341b7, 0xd0d854c0, 0xcb3a6c88,
+ 0x47bc2829, 0x4725ba37, 0xa66ad22b, 0x7ad61f1e, 0x0c5cbafa, 0x4437f107, 0xb6e79962, 0x42d2d816,
+ 0x0a961288, 0xe1a5c06e, 0x13749e67, 0x72fc081a, 0xb1d139f7, 0xf9583745, 0xcf19df58, 0xbec3f756,
+ 0xc06eba30, 0x07211b24, 0x45c28829, 0xc95e317f, 0xbc8ec511, 0x38bc46e9, 0xc6e6fa14, 0xbae8584a,
+ 0xad4ebc46, 0x468f508b, 0x7829435f, 0xf124183b, 0x821dba9f, 0xaff60ff4, 0xea2c4e6d, 0x16e39264,
+ 0x92544a8b, 0x009b4fc3, 0xaba68ced, 0x9ac96f78, 0x06a5b79a, 0xb2856e6e, 0x1aec3ca9, 0xbe838688,
+ 0x0e0804e9, 0x55f1be56, 0xe7e5363b, 0xb3a1f25d, 0xf7debb85, 0x61fe033c, 0x16746233, 0x3c034c28,
+ 0xda6d0c74, 0x79aac56c, 0x3ce4e1ad, 0x51f0c802, 0x98f8f35a, 0x1626a49f, 0xeed82b29, 0x1d382fe3,
+ 0x0c4fb99a, 0xbb325778, 0x3ec6d97b, 0x6e77a6a9, 0xcb658b5c, 0xd45230c7, 0x2bd1408b, 0x60c03eb7,
+ 0xb9068d78, 0xa33754f4, 0xf430c87d, 0xc8a71302, 0xb96d8c32, 0xebd4e7be, 0xbe8b9d2d, 0x7979fb06,
+ 0xe7225308, 0x8b75cf77, 0x11ef8da4, 0xe083c858, 0x8d6b786f, 0x5a6317a6, 0xfa5cf7a0, 0x5dda0033,
+ 0xf28ebfb0, 0xf5b9c310, 0xa0eac280, 0x08b9767a, 0xa3d9d2b0, 0x79d34217, 0x021a718d, 0x9ac6336a,
+ 0x2711fd60, 0x438050e3, 0x069908a8, 0x3d7fedc4, 0x826d2bef, 0x4eeb8476, 0x488dcf25, 0x36c9d566,
+ 0x28e74e41, 0xc2610aca, 0x3d49a9cf, 0xbae3b9df, 0xb65f8de6, 0x92aeaf64, 0x3ac7d5e6, 0x9ea80509,
+ 0xf22b017d, 0xa4173f70, 0xdd1e16c3, 0x15e0d7f9, 0x50b1b887, 0x2b9f4fd5, 0x625aba82, 0x6a017962,
+ 0x2ec01b9c, 0x15488aa9, 0xd716e740, 0x40055a2c, 0x93d29a22, 0xe32dbf9a, 0x058745b9, 0x3453dc1e,
+ 0xd699296e, 0x496cff6f, 0x1c9f4986, 0xdfe2ed07, 0xb87242d1, 0x19de7eae, 0x053e561a, 0x15ad6f8c,
+ 0x66626c1c, 0x7154c24c, 0xea082b2a, 0x93eb2939, 0x17dcb0f0, 0x58d4f2ae, 0x9ea294fb, 0x52cf564c,
+ 0x9883fe66, 0x2ec40581, 0x763953c3, 0x01d6692e, 0xd3a0c108, 0xa1e7160e, 0xe4f2dfa6, 0x693ed285,
+ 0x74904698, 0x4c2b0edd, 0x4f757656, 0x5d393378, 0xa132234f, 0x3d321c5d, 0xc3f5e194, 0x4b269301,
+ 0xc79f022f, 0x3c997e7e, 0x5e4f9504, 0x3ffafbbd, 0x76f7ad0e, 0x296693f4, 0x3d1fce6f, 0xc61e45be,
+ 0xd3b5ab34, 0xf72bf9b7, 0x1b0434c0, 0x4e72b567, 0x5592a33d, 0xb5229301, 0xcfd2a87f, 0x60aeb767,
+ 0x1814386b, 0x30bcc33d, 0x38a0c07d, 0xfd1606f2, 0xc363519b, 0x589dd390, 0x5479f8e6, 0x1cb8d647,
+ 0x97fd61a9, 0xea7759f4, 0x2d57539d, 0x569a58cf, 0xe84e63ad, 0x462e1b78, 0x6580f87e, 0xf3817914,
+ 0x91da55f4, 0x40a230f3, 0xd1988f35, 0xb6e318d2, 0x3ffa50bc, 0x3d40f021, 0xc3c0bdae, 0x4958c24c,
+ 0x518f36b2, 0x84b1d370, 0x0fedce83, 0x878ddada, 0xf2a279c7, 0x94e01be8, 0x90716f4b, 0x954b8aa3,
+ },
+ {
+ 0xe216300d, 0xbbddfffc, 0xa7ebdabd, 0x35648095, 0x7789f8b7, 0xe6c1121b, 0x0e241600, 0x052ce8b5,
+ 0x11a9cfb0, 0xe5952f11, 0xece7990a, 0x9386d174, 0x2a42931c, 0x76e38111, 0xb12def3a, 0x37ddddfc,
+ 0xde9adeb1, 0x0a0cc32c, 0xbe197029, 0x84a00940, 0xbb243a0f, 0xb4d137cf, 0xb44e79f0, 0x049eedfd,
+ 0x0b15a15d, 0x480d3168, 0x8bbbde5a, 0x669ded42, 0xc7ece831, 0x3f8f95e7, 0x72df191b, 0x7580330d,
+ 0x94074251, 0x5c7dcdfa, 0xabbe6d63, 0xaa402164, 0xb301d40a, 0x02e7d1ca, 0x53571dae, 0x7a3182a2,
+ 0x12a8ddec, 0xfdaa335d, 0x176f43e8, 0x71fb46d4, 0x38129022, 0xce949ad4, 0xb84769ad, 0x965bd862,
+ 0x82f3d055, 0x66fb9767, 0x15b80b4e, 0x1d5b47a0, 0x4cfde06f, 0xc28ec4b8, 0x57e8726e, 0x647a78fc,
+ 0x99865d44, 0x608bd593, 0x6c200e03, 0x39dc5ff6, 0x5d0b00a3, 0xae63aff2, 0x7e8bd632, 0x70108c0c,
+ 0xbbd35049, 0x2998df04, 0x980cf42a, 0x9b6df491, 0x9e7edd53, 0x06918548, 0x58cb7e07, 0x3b74ef2e,
+ 0x522fffb1, 0xd24708cc, 0x1c7e27cd, 0xa4eb215b, 0x3cf1d2e2, 0x19b47a38, 0x424f7618, 0x35856039,
+ 0x9d17dee7, 0x27eb35e6, 0xc9aff67b, 0x36baf5b8, 0x09c467cd, 0xc18910b1, 0xe11dbf7b, 0x06cd1af8,
+ 0x7170c608, 0x2d5e3354, 0xd4de495a, 0x64c6d006, 0xbcc0c62c, 0x3dd00db3, 0x708f8f34, 0x77d51b42,
+ 0x264f620f, 0x24b8d2bf, 0x15c1b79e, 0x46a52564, 0xf8d7e54e, 0x3e378160, 0x7895cda5, 0x859c15a5,
+ 0xe6459788, 0xc37bc75f, 0xdb07ba0c, 0x0676a3ab, 0x7f229b1e, 0x31842e7b, 0x24259fd7, 0xf8bef472,
+ 0x835ffcb8, 0x6df4c1f2, 0x96f5b195, 0xfd0af0fc, 0xb0fe134c, 0xe2506d3d, 0x4f9b12ea, 0xf215f225,
+ 0xa223736f, 0x9fb4c428, 0x25d04979, 0x34c713f8, 0xc4618187, 0xea7a6e98, 0x7cd16efc, 0x1436876c,
+ 0xf1544107, 0xbedeee14, 0x56e9af27, 0xa04aa441, 0x3cf7c899, 0x92ecbae6, 0xdd67016d, 0x151682eb,
+ 0xa842eedf, 0xfdba60b4, 0xf1907b75, 0x20e3030f, 0x24d8c29e, 0xe139673b, 0xefa63fb8, 0x71873054,
+ 0xb6f2cf3b, 0x9f326442, 0xcb15a4cc, 0xb01a4504, 0xf1e47d8d, 0x844a1be5, 0xbae7dfdc, 0x42cbda70,
+ 0xcd7dae0a, 0x57e85b7a, 0xd53f5af6, 0x20cf4d8c, 0xcea4d428, 0x79d130a4, 0x3486ebfb, 0x33d3cddc,
+ 0x77853b53, 0x37effcb5, 0xc5068778, 0xe580b3e6, 0x4e68b8f4, 0xc5c8b37e, 0x0d809ea2, 0x398feb7c,
+ 0x132a4f94, 0x43b7950e, 0x2fee7d1c, 0x223613bd, 0xdd06caa2, 0x37df932b, 0xc4248289, 0xacf3ebc3,
+ 0x5715f6b7, 0xef3478dd, 0xf267616f, 0xc148cbe4, 0x9052815e, 0x5e410fab, 0xb48a2465, 0x2eda7fa4,
+ 0xe87b40e4, 0xe98ea084, 0x5889e9e1, 0xefd390fc, 0xdd07d35b, 0xdb485694, 0x38d7e5b2, 0x57720101,
+ 0x730edebc, 0x5b643113, 0x94917e4f, 0x503c2fba, 0x646f1282, 0x7523d24a, 0xe0779695, 0xf9c17a8f,
+ 0x7a5b2121, 0xd187b896, 0x29263a4d, 0xba510cdf, 0x81f47c9f, 0xad1163ed, 0xea7b5965, 0x1a00726e,
+ 0x11403092, 0x00da6d77, 0x4a0cdd61, 0xad1f4603, 0x605bdfb0, 0x9eedc364, 0x22ebe6a8, 0xcee7d28a,
+ 0xa0e736a0, 0x5564a6b9, 0x10853209, 0xc7eb8f37, 0x2de705ca, 0x8951570f, 0xdf09822b, 0xbd691a6c,
+ 0xaa12e4f2, 0x87451c0f, 0xe0f6a27a, 0x3ada4819, 0x4cf1764f, 0x0d771c2b, 0x67cdb156, 0x350d8384,
+ 0x5938fa0f, 0x42399ef3, 0x36997b07, 0x0e84093d, 0x4aa93e61, 0x8360d87b, 0x1fa98b0c, 0x1149382c,
+ 0xe97625a5, 0x0614d1b7, 0x0e25244b, 0x0c768347, 0x589e8d82, 0x0d2059d1, 0xa466bb1e, 0xf8da0a82,
+ 0x04f19130, 0xba6e4ec0, 0x99265164, 0x1ee7230d, 0x50b2ad80, 0xeaee6801, 0x8db2a283, 0xea8bf59e,
+ },
+}
diff --git a/src/pkg/crypto/cast5/cast5_test.go b/src/pkg/crypto/cast5/cast5_test.go
new file mode 100644
index 000000000..5f7025ff2
--- /dev/null
+++ b/src/pkg/crypto/cast5/cast5_test.go
@@ -0,0 +1,104 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cast5
+
+import (
+ "bytes"
+ "encoding/hex"
+ "testing"
+)
+
+// This test vector is taken from RFC 2144, App B.1.
+// Since the other two test vectors are for reduced-round variants, we can't
+// use them.
+var basicTests = []struct {
+ key, plainText, cipherText string
+}{
+ {
+ "0123456712345678234567893456789a",
+ "0123456789abcdef",
+ "238b4fe5847e44b2",
+ },
+}
+
+func TestBasic(t *testing.T) {
+ for i, test := range basicTests {
+ key, _ := hex.DecodeString(test.key)
+ plainText, _ := hex.DecodeString(test.plainText)
+ expected, _ := hex.DecodeString(test.cipherText)
+
+ c, err := NewCipher(key)
+ if err != nil {
+ t.Errorf("#%d: failed to create Cipher: %s", i, err)
+ continue
+ }
+ var cipherText [BlockSize]byte
+ c.Encrypt(cipherText[:], plainText)
+ if !bytes.Equal(cipherText[:], expected) {
+ t.Errorf("#%d: got:%x want:%x", i, cipherText, expected)
+ }
+
+ var plainTextAgain [BlockSize]byte
+ c.Decrypt(plainTextAgain[:], cipherText[:])
+ if !bytes.Equal(plainTextAgain[:], plainText) {
+ t.Errorf("#%d: got:%x want:%x", i, plainTextAgain, plainText)
+ }
+ }
+}
+
+// TestFull performs the test specified in RFC 2144, App B.2.
+// However, due to the length of time taken, it's disabled here and a more
+// limited version is included, below.
+func TestFull(t *testing.T) {
+ // This is too slow for normal testing
+ return
+
+ a, b := iterate(1000000)
+
+ const expectedA = "eea9d0a249fd3ba6b3436fb89d6dca92"
+ const expectedB = "b2c95eb00c31ad7180ac05b8e83d696e"
+
+ if hex.EncodeToString(a) != expectedA {
+ t.Errorf("a: got:%x want:%s", a, expectedA)
+ }
+ if hex.EncodeToString(b) != expectedB {
+ t.Errorf("b: got:%x want:%s", b, expectedB)
+ }
+}
+
+func iterate(iterations int) ([]byte, []byte) {
+ const initValueHex = "0123456712345678234567893456789a"
+
+ initValue, _ := hex.DecodeString(initValueHex)
+
+ var a, b [16]byte
+ copy(a[:], initValue)
+ copy(b[:], initValue)
+
+ for i := 0; i < iterations; i++ {
+ c, _ := NewCipher(b[:])
+ c.Encrypt(a[:8], a[:8])
+ c.Encrypt(a[8:], a[8:])
+ c, _ = NewCipher(a[:])
+ c.Encrypt(b[:8], b[:8])
+ c.Encrypt(b[8:], b[8:])
+ }
+
+ return a[:], b[:]
+}
+
+func TestLimited(t *testing.T) {
+ a, b := iterate(1000)
+
+ const expectedA = "23f73b14b02a2ad7dfb9f2c35644798d"
+ const expectedB = "e5bf37eff14c456a40b21ce369370a9f"
+
+ if hex.EncodeToString(a) != expectedA {
+ t.Errorf("a: got:%x want:%s", a, expectedA)
+ }
+ if hex.EncodeToString(b) != expectedB {
+ t.Errorf("b: got:%x want:%s", b, expectedB)
+ }
+}
diff --git a/src/pkg/crypto/cipher/Makefile b/src/pkg/crypto/cipher/Makefile
new file mode 100644
index 000000000..d7e8a7a13
--- /dev/null
+++ b/src/pkg/crypto/cipher/Makefile
@@ -0,0 +1,16 @@
+# Copyright 2010 The Go Authors. 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\
+ cipher.go\
+ ctr.go\
+ io.go\
+ ocfb.go\
+ cfb.go
+
+include ../../../Make.pkg
diff --git a/src/pkg/crypto/cipher/cbc.go b/src/pkg/crypto/cipher/cbc.go
new file mode 100644
index 000000000..4632f882a
--- /dev/null
+++ b/src/pkg/crypto/cipher/cbc.go
@@ -0,0 +1,78 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Cipher block chaining (CBC) mode.
+
+// CBC provides confidentiality by xoring (chaining) each plaintext block
+// with the previous ciphertext block before applying the block cipher.
+
+// See NIST SP 800-38A, pp 10-11
+
+package cipher
+
+type cbc struct {
+ b Block
+ blockSize int
+ iv []byte
+ tmp []byte
+}
+
+func newCBC(b Block, iv []byte) *cbc {
+ return &cbc{
+ b: b,
+ blockSize: b.BlockSize(),
+ iv: dup(iv),
+ tmp: make([]byte, b.BlockSize()),
+ }
+}
+
+type cbcEncrypter cbc
+
+// NewCBCEncrypter returns a BlockMode which encrypts in cipher block chaining
+// mode, using the given Block. The length of iv must be the same as the
+// Block's block size.
+func NewCBCEncrypter(b Block, iv []byte) BlockMode {
+ return (*cbcEncrypter)(newCBC(b, iv))
+}
+
+func (x *cbcEncrypter) BlockSize() int { return x.blockSize }
+
+func (x *cbcEncrypter) CryptBlocks(dst, src []byte) {
+ for len(src) > 0 {
+ for i := 0; i < x.blockSize; i++ {
+ x.iv[i] ^= src[i]
+ }
+ x.b.Encrypt(x.iv, x.iv)
+ for i := 0; i < x.blockSize; i++ {
+ dst[i] = x.iv[i]
+ }
+ src = src[x.blockSize:]
+ dst = dst[x.blockSize:]
+ }
+}
+
+type cbcDecrypter cbc
+
+// NewCBCDecrypter returns a BlockMode which decrypts in cipher block chaining
+// mode, using the given Block. The length of iv must be the same as the
+// Block's block size as must match the iv used to encrypt the data.
+func NewCBCDecrypter(b Block, iv []byte) BlockMode {
+ return (*cbcDecrypter)(newCBC(b, iv))
+}
+
+func (x *cbcDecrypter) BlockSize() int { return x.blockSize }
+
+func (x *cbcDecrypter) CryptBlocks(dst, src []byte) {
+ for len(src) > 0 {
+ x.b.Decrypt(x.tmp, src[:x.blockSize])
+ for i := 0; i < x.blockSize; i++ {
+ x.tmp[i] ^= x.iv[i]
+ x.iv[i] = src[i]
+ dst[i] = x.tmp[i]
+ }
+
+ src = src[x.blockSize:]
+ dst = dst[x.blockSize:]
+ }
+}
diff --git a/src/pkg/crypto/block/cbc_aes_test.go b/src/pkg/crypto/cipher/cbc_aes_test.go
index 5531f3ab9..944ca1ba8 100644
--- a/src/pkg/crypto/block/cbc_aes_test.go
+++ b/src/pkg/crypto/cipher/cbc_aes_test.go
@@ -8,26 +8,23 @@
// Special Publication 800-38A, ``Recommendation for Block Cipher
// Modes of Operation,'' 2001 Edition, pp. 24-29.
-package block
+package cipher
import (
"bytes"
"crypto/aes"
- "io"
"testing"
)
-type cbcTest struct {
+var cbcAESTests = []struct {
name string
key []byte
iv []byte
in []byte
out []byte
-}
-
-var cbcAESTests = []cbcTest{
+}{
// NIST SP 800-38A pp 27-29
- cbcTest{
+ {
"CBC-AES128",
commonKey128,
commonIV,
@@ -39,7 +36,7 @@ var cbcAESTests = []cbcTest{
0x3f, 0xf1, 0xca, 0xa1, 0x68, 0x1f, 0xac, 0x09, 0x12, 0x0e, 0xca, 0x30, 0x75, 0x86, 0xe1, 0xa7,
},
},
- cbcTest{
+ {
"CBC-AES192",
commonKey192,
commonIV,
@@ -51,7 +48,7 @@ var cbcAESTests = []cbcTest{
0x08, 0xb0, 0xe2, 0x79, 0x88, 0x59, 0x88, 0x81, 0xd9, 0x20, 0xa9, 0xe6, 0x4f, 0x56, 0x15, 0xcd,
},
},
- cbcTest{
+ {
"CBC-AES256",
commonKey256,
commonIV,
@@ -75,28 +72,18 @@ func TestCBC_AES(t *testing.T) {
continue
}
- var crypt bytes.Buffer
- w := NewCBCEncrypter(c, tt.iv, &crypt)
- var r io.Reader = bytes.NewBuffer(tt.in)
- n, err := io.Copy(w, r)
- if n != int64(len(tt.in)) || err != nil {
- t.Errorf("%s: CBCEncrypter io.Copy = %d, %v want %d, nil", test, n, err, len(tt.in))
- } else if d := crypt.Bytes(); !same(tt.out, d) {
+ encrypter := NewCBCEncrypter(c, tt.iv)
+ d := make([]byte, len(tt.in))
+ encrypter.CryptBlocks(d, tt.in)
+ if !bytes.Equal(tt.out, d) {
t.Errorf("%s: CBCEncrypter\nhave %x\nwant %x", test, d, tt.out)
}
- var plain bytes.Buffer
- r = NewCBCDecrypter(c, tt.iv, bytes.NewBuffer(tt.out))
- w = &plain
- n, err = io.Copy(w, r)
- if n != int64(len(tt.out)) || err != nil {
- t.Errorf("%s: CBCDecrypter io.Copy = %d, %v want %d, nil", test, n, err, len(tt.out))
- } else if d := plain.Bytes(); !same(tt.in, d) {
+ decrypter := NewCBCDecrypter(c, tt.iv)
+ p := make([]byte, len(d))
+ decrypter.CryptBlocks(p, d)
+ if !bytes.Equal(tt.in, p) {
t.Errorf("%s: CBCDecrypter\nhave %x\nwant %x", test, d, tt.in)
}
-
- if t.Failed() {
- break
- }
}
}
diff --git a/src/pkg/crypto/cipher/cfb.go b/src/pkg/crypto/cipher/cfb.go
new file mode 100644
index 000000000..d14165a86
--- /dev/null
+++ b/src/pkg/crypto/cipher/cfb.go
@@ -0,0 +1,64 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// CFB (Cipher Feedback) Mode.
+
+package cipher
+
+type cfb struct {
+ b Block
+ out []byte
+ outUsed int
+ decrypt bool
+}
+
+// NewCFBEncrypter returns a Stream which encrypts with cipher feedback mode,
+// using the given Block. The iv must be the same length as the Block's block
+// size.
+func NewCFBEncrypter(block Block, iv []byte) Stream {
+ return newCFB(block, iv, false)
+}
+
+// NewCFBDecrypter returns a Stream which decrypts with cipher feedback mode,
+// using the given Block. The iv must be the same length as the Block's block
+// size.
+func NewCFBDecrypter(block Block, iv []byte) Stream {
+ return newCFB(block, iv, true)
+}
+
+func newCFB(block Block, iv []byte, decrypt bool) Stream {
+ blockSize := block.BlockSize()
+ if len(iv) != blockSize {
+ return nil
+ }
+
+ x := &cfb{
+ b: block,
+ out: make([]byte, blockSize),
+ outUsed: 0,
+ decrypt: decrypt,
+ }
+ block.Encrypt(x.out, iv)
+
+ return x
+}
+
+func (x *cfb) XORKeyStream(dst, src []byte) {
+ for i := 0; i < len(src); i++ {
+ if x.outUsed == len(x.out) {
+ x.b.Encrypt(x.out, x.out)
+ x.outUsed = 0
+ }
+
+ if x.decrypt {
+ t := src[i]
+ dst[i] = src[i] ^ x.out[x.outUsed]
+ x.out[x.outUsed] = t
+ } else {
+ x.out[x.outUsed] ^= src[i]
+ dst[i] = x.out[x.outUsed]
+ }
+ x.outUsed++
+ }
+}
diff --git a/src/pkg/crypto/cipher/cfb_test.go b/src/pkg/crypto/cipher/cfb_test.go
new file mode 100644
index 000000000..9547bfceb
--- /dev/null
+++ b/src/pkg/crypto/cipher/cfb_test.go
@@ -0,0 +1,35 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cipher
+
+import (
+ "bytes"
+ "crypto/aes"
+ "crypto/rand"
+ "testing"
+)
+
+func TestCFB(t *testing.T) {
+ block, err := aes.NewCipher(commonKey128)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ plaintext := []byte("this is the plaintext")
+ iv := make([]byte, block.BlockSize())
+ rand.Reader.Read(iv)
+ cfb := NewCFBEncrypter(block, iv)
+ ciphertext := make([]byte, len(plaintext))
+ cfb.XORKeyStream(ciphertext, plaintext)
+
+ cfbdec := NewCFBDecrypter(block, iv)
+ plaintextCopy := make([]byte, len(plaintext))
+ cfbdec.XORKeyStream(plaintextCopy, ciphertext)
+
+ if !bytes.Equal(plaintextCopy, plaintext) {
+ t.Errorf("got: %x, want: %x", plaintextCopy, plaintext)
+ }
+}
diff --git a/src/pkg/crypto/cipher/cipher.go b/src/pkg/crypto/cipher/cipher.go
new file mode 100644
index 000000000..50516b23a
--- /dev/null
+++ b/src/pkg/crypto/cipher/cipher.go
@@ -0,0 +1,63 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The cipher package implements standard block cipher modes
+// that can be wrapped around low-level block cipher implementations.
+// See http://csrc.nist.gov/groups/ST/toolkit/BCM/current_modes.html
+// and NIST Special Publication 800-38A.
+package cipher
+
+// A Block represents an implementation of block cipher
+// using a given key. It provides the capability to encrypt
+// or decrypt individual blocks. The mode implementations
+// extend that capability to streams of blocks.
+type Block interface {
+ // BlockSize returns the cipher's block size.
+ BlockSize() int
+
+ // Encrypt encrypts the first block in src into dst.
+ // Dst and src may point at the same memory.
+ Encrypt(dst, src []byte)
+
+ // Decrypt decrypts the first block in src into dst.
+ // Dst and src may point at the same memory.
+ Decrypt(dst, src []byte)
+}
+
+// A Stream represents a stream cipher.
+type Stream interface {
+ // XORKeyStream XORs each byte in the given slice with a byte from the
+ // cipher's key stream. Dst and src may point to the same memory.
+ XORKeyStream(dst, src []byte)
+}
+
+// A BlockMode represents a block cipher running in a block-based mode (CBC,
+// ECB etc).
+type BlockMode interface {
+ // BlockSize returns the mode's block size.
+ BlockSize() int
+
+ // CryptBlocks encrypts or decrypts a number of blocks. The length of
+ // src must be a multiple of the block size. Dst and src may point to
+ // the same memory.
+ CryptBlocks(dst, src []byte)
+}
+
+// Utility routines
+
+func shift1(dst, src []byte) byte {
+ var b byte
+ for i := len(src) - 1; i >= 0; i-- {
+ bb := src[i] >> 7
+ dst[i] = src[i]<<1 | b
+ b = bb
+ }
+ return b
+}
+
+func dup(p []byte) []byte {
+ q := make([]byte, len(p))
+ copy(q, p)
+ return q
+}
diff --git a/src/pkg/crypto/cipher/common_test.go b/src/pkg/crypto/cipher/common_test.go
new file mode 100644
index 000000000..fb755757c
--- /dev/null
+++ b/src/pkg/crypto/cipher/common_test.go
@@ -0,0 +1,28 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cipher
+
+// Common values for tests.
+
+var commonInput = []byte{
+ 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+ 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+ 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+ 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10,
+}
+
+var commonKey128 = []byte{0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c}
+
+var commonKey192 = []byte{
+ 0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52, 0xc8, 0x10, 0xf3, 0x2b, 0x80, 0x90, 0x79, 0xe5,
+ 0x62, 0xf8, 0xea, 0xd2, 0x52, 0x2c, 0x6b, 0x7b,
+}
+
+var commonKey256 = []byte{
+ 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81,
+ 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4,
+}
+
+var commonIV = []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}
diff --git a/src/pkg/crypto/cipher/ctr.go b/src/pkg/crypto/cipher/ctr.go
new file mode 100644
index 000000000..04436ec23
--- /dev/null
+++ b/src/pkg/crypto/cipher/ctr.go
@@ -0,0 +1,51 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Counter (CTR) mode.
+
+// CTR converts a block cipher into a stream cipher by
+// repeatedly encrypting an incrementing counter and
+// xoring the resulting stream of data with the input.
+
+// See NIST SP 800-38A, pp 13-15
+
+package cipher
+
+type ctr struct {
+ b Block
+ ctr []byte
+ out []byte
+ outUsed int
+}
+
+// NewCTR returns a Stream which encrypts/decrypts using the given Block in
+// counter mode. The length of iv must be the same as the Block's block size.
+func NewCTR(block Block, iv []byte) Stream {
+ return &ctr{
+ b: block,
+ ctr: dup(iv),
+ out: make([]byte, len(iv)),
+ outUsed: len(iv),
+ }
+}
+
+func (x *ctr) XORKeyStream(dst, src []byte) {
+ for i := 0; i < len(src); i++ {
+ if x.outUsed == len(x.ctr) {
+ x.b.Encrypt(x.out, x.ctr)
+ x.outUsed = 0
+
+ // Increment counter
+ for i := len(x.ctr) - 1; i >= 0; i-- {
+ x.ctr[i]++
+ if x.ctr[i] != 0 {
+ break
+ }
+ }
+ }
+
+ dst[i] = src[i] ^ x.out[x.outUsed]
+ x.outUsed++
+ }
+}
diff --git a/src/pkg/crypto/block/ctr_aes_test.go b/src/pkg/crypto/cipher/ctr_aes_test.go
index adb996c1d..8dca9968c 100644
--- a/src/pkg/crypto/block/ctr_aes_test.go
+++ b/src/pkg/crypto/cipher/ctr_aes_test.go
@@ -8,28 +8,25 @@
// Special Publication 800-38A, ``Recommendation for Block Cipher
// Modes of Operation,'' 2001 Edition, pp. 55-58.
-package block
+package cipher
import (
"bytes"
"crypto/aes"
- "io"
"testing"
)
-type ctrTest struct {
+var commonCounter = []byte{0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff}
+
+var ctrAESTests = []struct {
name string
key []byte
iv []byte
in []byte
out []byte
-}
-
-var commonCounter = []byte{0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff}
-
-var ctrAESTests = []ctrTest{
+}{
// NIST SP 800-38A pp 55-58
- ctrTest{
+ {
"CTR-AES128",
commonKey128,
commonCounter,
@@ -41,7 +38,7 @@ var ctrAESTests = []ctrTest{
0x1e, 0x03, 0x1d, 0xda, 0x2f, 0xbe, 0x03, 0xd1, 0x79, 0x21, 0x70, 0xa0, 0xf3, 0x00, 0x9c, 0xee,
},
},
- ctrTest{
+ {
"CTR-AES192",
commonKey192,
commonCounter,
@@ -53,7 +50,7 @@ var ctrAESTests = []ctrTest{
0x4f, 0x78, 0xa7, 0xf6, 0xd2, 0x98, 0x09, 0x58, 0x5a, 0x97, 0xda, 0xec, 0x58, 0xc6, 0xb0, 0x50,
},
},
- ctrTest{
+ {
"CTR-AES256",
commonKey256,
commonCounter,
@@ -78,28 +75,22 @@ func TestCTR_AES(t *testing.T) {
}
for j := 0; j <= 5; j += 5 {
- var crypt bytes.Buffer
in := tt.in[0 : len(tt.in)-j]
- w := NewCTRWriter(c, tt.iv, &crypt)
- var r io.Reader = bytes.NewBuffer(in)
- n, err := io.Copy(w, r)
- if n != int64(len(in)) || err != nil {
- t.Errorf("%s/%d: CTRWriter io.Copy = %d, %v want %d, nil", test, len(in), n, err, len(in))
- } else if d, out := crypt.Bytes(), tt.out[0:len(in)]; !same(out, d) {
- t.Errorf("%s/%d: CTRWriter\ninpt %x\nhave %x\nwant %x", test, len(in), in, d, out)
+ ctr := NewCTR(c, tt.iv)
+ encrypted := make([]byte, len(in))
+ ctr.XORKeyStream(encrypted, in)
+ if out := tt.out[0:len(in)]; !bytes.Equal(out, encrypted) {
+ t.Errorf("%s/%d: CTR\ninpt %x\nhave %x\nwant %x", test, len(in), in, encrypted, out)
}
}
for j := 0; j <= 7; j += 7 {
- var plain bytes.Buffer
- out := tt.out[0 : len(tt.out)-j]
- r := NewCTRReader(c, tt.iv, bytes.NewBuffer(out))
- w := &plain
- n, err := io.Copy(w, r)
- if n != int64(len(out)) || err != nil {
- t.Errorf("%s/%d: CTRReader io.Copy = %d, %v want %d, nil", test, len(out), n, err, len(out))
- } else if d, in := plain.Bytes(), tt.in[0:len(out)]; !same(in, d) {
- t.Errorf("%s/%d: CTRReader\nhave %x\nwant %x", test, len(out), d, in)
+ in := tt.out[0 : len(tt.out)-j]
+ ctr := NewCTR(c, tt.iv)
+ plain := make([]byte, len(in))
+ ctr.XORKeyStream(plain, in)
+ if out := tt.in[0:len(in)]; !bytes.Equal(out, plain) {
+ t.Errorf("%s/%d: CTRReader\nhave %x\nwant %x", test, len(out), plain, out)
}
}
diff --git a/src/pkg/crypto/cipher/io.go b/src/pkg/crypto/cipher/io.go
new file mode 100644
index 000000000..97f40b8e7
--- /dev/null
+++ b/src/pkg/crypto/cipher/io.go
@@ -0,0 +1,57 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cipher
+
+import (
+ "os"
+ "io"
+)
+
+// The Stream* objects are so simple that all their members are public. Users
+// can create them themselves.
+
+// StreamReader wraps a Stream into an io.Reader. It simply calls XORKeyStream
+// to process each slice of data which passes through.
+type StreamReader struct {
+ S Stream
+ R io.Reader
+}
+
+func (r StreamReader) Read(dst []byte) (n int, err os.Error) {
+ n, err = r.R.Read(dst)
+ r.S.XORKeyStream(dst[:n], dst[:n])
+ return
+}
+
+// StreamWriter wraps a Stream into an io.Writer. It simply calls XORKeyStream
+// to process each slice of data which passes through. If any Write call
+// returns short then the StreamWriter is out of sync and must be discarded.
+type StreamWriter struct {
+ S Stream
+ W io.Writer
+ Err os.Error
+}
+
+func (w StreamWriter) Write(src []byte) (n int, err os.Error) {
+ if w.Err != nil {
+ return 0, w.Err
+ }
+ c := make([]byte, len(src))
+ w.S.XORKeyStream(c, src)
+ n, err = w.W.Write(c)
+ if n != len(src) {
+ if err == nil { // should never happen
+ err = io.ErrShortWrite
+ }
+ w.Err = err
+ }
+ return
+}
+
+func (w StreamWriter) Close() os.Error {
+ // This saves us from either requiring a WriteCloser or having a
+ // StreamWriterCloser.
+ return w.W.(io.Closer).Close()
+}
diff --git a/src/pkg/crypto/cipher/ocfb.go b/src/pkg/crypto/cipher/ocfb.go
new file mode 100644
index 000000000..43cb5a531
--- /dev/null
+++ b/src/pkg/crypto/cipher/ocfb.go
@@ -0,0 +1,112 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// OpenPGP CFB Mode. http://tools.ietf.org/html/rfc4880#section-13.9
+
+package cipher
+
+type ocfbEncrypter struct {
+ b Block
+ fre []byte
+ outUsed int
+}
+
+// NewOCFBEncrypter returns a Stream which encrypts data with OpenPGP's cipher
+// feedback mode using the given Block, and an initial amount of ciphertext.
+// randData must be random bytes and be the same length as the Block's block
+// size.
+func NewOCFBEncrypter(block Block, randData []byte) (Stream, []byte) {
+ blockSize := block.BlockSize()
+ if len(randData) != blockSize {
+ return nil, nil
+ }
+
+ x := &ocfbEncrypter{
+ b: block,
+ fre: make([]byte, blockSize),
+ outUsed: 0,
+ }
+ prefix := make([]byte, blockSize+2)
+
+ block.Encrypt(x.fre, x.fre)
+ for i := 0; i < blockSize; i++ {
+ prefix[i] = randData[i] ^ x.fre[i]
+ }
+
+ block.Encrypt(x.fre, prefix[:blockSize])
+ prefix[blockSize] = x.fre[0] ^ randData[blockSize-2]
+ prefix[blockSize+1] = x.fre[1] ^ randData[blockSize-1]
+
+ block.Encrypt(x.fre, prefix[2:])
+ return x, prefix
+}
+
+func (x *ocfbEncrypter) XORKeyStream(dst, src []byte) {
+ for i := 0; i < len(src); i++ {
+ if x.outUsed == len(x.fre) {
+ x.b.Encrypt(x.fre, x.fre)
+ x.outUsed = 0
+ }
+
+ x.fre[x.outUsed] ^= src[i]
+ dst[i] = x.fre[x.outUsed]
+ x.outUsed++
+ }
+}
+
+type ocfbDecrypter struct {
+ b Block
+ fre []byte
+ outUsed int
+}
+
+// NewOCFBDecrypter returns a Stream which decrypts data with OpenPGP's cipher
+// feedback mode using the given Block. Prefix must be the first blockSize + 2
+// bytes of the ciphertext, where blockSize is the Block's block size. If an
+// incorrect key is detected then nil is returned.
+func NewOCFBDecrypter(block Block, prefix []byte) Stream {
+ blockSize := block.BlockSize()
+ if len(prefix) != blockSize+2 {
+ return nil
+ }
+
+ x := &ocfbDecrypter{
+ b: block,
+ fre: make([]byte, blockSize),
+ outUsed: 0,
+ }
+ prefixCopy := make([]byte, len(prefix))
+ copy(prefixCopy, prefix)
+
+ block.Encrypt(x.fre, x.fre)
+ for i := 0; i < blockSize; i++ {
+ prefixCopy[i] ^= x.fre[i]
+ }
+
+ block.Encrypt(x.fre, prefix[:blockSize])
+ prefixCopy[blockSize] ^= x.fre[0]
+ prefixCopy[blockSize+1] ^= x.fre[1]
+
+ if prefixCopy[blockSize-2] != prefixCopy[blockSize] ||
+ prefixCopy[blockSize-1] != prefixCopy[blockSize+1] {
+ return nil
+ }
+
+ block.Encrypt(x.fre, prefix[2:])
+ return x
+}
+
+func (x *ocfbDecrypter) XORKeyStream(dst, src []byte) {
+ for i := 0; i < len(src); i++ {
+ if x.outUsed == len(x.fre) {
+ x.b.Encrypt(x.fre, x.fre)
+ x.outUsed = 0
+ }
+
+ c := src[i]
+ dst[i] = x.fre[x.outUsed] ^ src[i]
+ x.fre[x.outUsed] = c
+ x.outUsed++
+ }
+}
diff --git a/src/pkg/crypto/cipher/ocfb_test.go b/src/pkg/crypto/cipher/ocfb_test.go
new file mode 100644
index 000000000..289bb7c91
--- /dev/null
+++ b/src/pkg/crypto/cipher/ocfb_test.go
@@ -0,0 +1,39 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cipher
+
+import (
+ "bytes"
+ "crypto/aes"
+ "crypto/rand"
+ "testing"
+)
+
+func TestOCFB(t *testing.T) {
+ block, err := aes.NewCipher(commonKey128)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ plaintext := []byte("this is the plaintext")
+ randData := make([]byte, block.BlockSize())
+ rand.Reader.Read(randData)
+ ocfb, prefix := NewOCFBEncrypter(block, randData)
+ ciphertext := make([]byte, len(plaintext))
+ ocfb.XORKeyStream(ciphertext, plaintext)
+
+ ocfbdec := NewOCFBDecrypter(block, prefix)
+ if ocfbdec == nil {
+ t.Error("NewOCFBDecrypter failed")
+ return
+ }
+ plaintextCopy := make([]byte, len(plaintext))
+ ocfbdec.XORKeyStream(plaintextCopy, ciphertext)
+
+ if !bytes.Equal(plaintextCopy, plaintext) {
+ t.Errorf("got: %x, want: %x", plaintextCopy, plaintext)
+ }
+}
diff --git a/src/pkg/crypto/elliptic/Makefile b/src/pkg/crypto/elliptic/Makefile
new file mode 100644
index 000000000..4db5d7de5
--- /dev/null
+++ b/src/pkg/crypto/elliptic/Makefile
@@ -0,0 +1,11 @@
+# Copyright 2010 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+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
new file mode 100644
index 000000000..beac45ca0
--- /dev/null
+++ b/src/pkg/crypto/elliptic/elliptic.go
@@ -0,0 +1,376 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The elliptic package implements several standard elliptic curves over prime
+// fields
+package elliptic
+
+// This package operates, internally, on Jacobian coordinates. For a given
+// (x, y) position on the curve, the Jacobian coordinates are (x1, y1, z1)
+// where x = x1/z1² and y = y1/z1³. The greatest speedups come when the whole
+// calculation can be performed within the transform (as in ScalarMult and
+// ScalarBaseMult). But even for Add and Double, it's faster to apply and
+// reverse the transform than to operate in affine coordinates.
+
+import (
+ "big"
+ "io"
+ "os"
+ "sync"
+)
+
+// A Curve represents a short-form Weierstrass curve with a=-3.
+// See http://www.hyperelliptic.org/EFD/g1p/auto-shortw.html
+type Curve struct {
+ P *big.Int // the order of the underlying field
+ B *big.Int // the constant of the curve equation
+ Gx, Gy *big.Int // (x,y) of the base point
+ BitSize int // the size of the underlying field
+}
+
+// IsOnCurve returns true if the given (x,y) lies on the curve.
+func (curve *Curve) IsOnCurve(x, y *big.Int) bool {
+ // y² = x³ - 3x + b
+ y2 := new(big.Int).Mul(y, y)
+ y2.Mod(y2, curve.P)
+
+ x3 := new(big.Int).Mul(x, x)
+ x3.Mul(x3, x)
+
+ threeX := new(big.Int).Lsh(x, 1)
+ threeX.Add(threeX, x)
+
+ x3.Sub(x3, threeX)
+ x3.Add(x3, curve.B)
+ x3.Mod(x3, curve.P)
+
+ return x3.Cmp(y2) == 0
+}
+
+// affineFromJacobian reverses the Jacobian transform. See the comment at the
+// top of the file.
+func (curve *Curve) affineFromJacobian(x, y, z *big.Int) (xOut, yOut *big.Int) {
+ zinv := new(big.Int).ModInverse(z, curve.P)
+ zinvsq := new(big.Int).Mul(zinv, zinv)
+
+ xOut = new(big.Int).Mul(x, zinvsq)
+ xOut.Mod(xOut, curve.P)
+ zinvsq.Mul(zinvsq, zinv)
+ yOut = new(big.Int).Mul(y, zinvsq)
+ yOut.Mod(yOut, curve.P)
+ return
+}
+
+// Add returns the sum of (x1,y1) and (x2,y2)
+func (curve *Curve) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) {
+ z := new(big.Int).SetInt64(1)
+ return curve.affineFromJacobian(curve.addJacobian(x1, y1, z, x2, y2, z))
+}
+
+// addJacobian takes two points in Jacobian coordinates, (x1, y1, z1) and
+// (x2, y2, z2) and returns their sum, also in Jacobian form.
+func (curve *Curve) addJacobian(x1, y1, z1, x2, y2, z2 *big.Int) (*big.Int, *big.Int, *big.Int) {
+ // See http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl
+ z1z1 := new(big.Int).Mul(z1, z1)
+ z1z1.Mod(z1z1, curve.P)
+ z2z2 := new(big.Int).Mul(z2, z2)
+ z2z2.Mod(z2z2, curve.P)
+
+ u1 := new(big.Int).Mul(x1, z2z2)
+ u1.Mod(u1, curve.P)
+ u2 := new(big.Int).Mul(x2, z1z1)
+ u2.Mod(u2, curve.P)
+ h := new(big.Int).Sub(u2, u1)
+ if h.Sign() == -1 {
+ h.Add(h, curve.P)
+ }
+ i := new(big.Int).Lsh(h, 1)
+ i.Mul(i, i)
+ j := new(big.Int).Mul(h, i)
+
+ s1 := new(big.Int).Mul(y1, z2)
+ s1.Mul(s1, z2z2)
+ s1.Mod(s1, curve.P)
+ s2 := new(big.Int).Mul(y2, z1)
+ s2.Mul(s2, z1z1)
+ s2.Mod(s2, curve.P)
+ r := new(big.Int).Sub(s2, s1)
+ if r.Sign() == -1 {
+ r.Add(r, curve.P)
+ }
+ r.Lsh(r, 1)
+ v := new(big.Int).Mul(u1, i)
+
+ x3 := new(big.Int).Set(r)
+ x3.Mul(x3, x3)
+ x3.Sub(x3, j)
+ x3.Sub(x3, v)
+ x3.Sub(x3, v)
+ x3.Mod(x3, curve.P)
+
+ y3 := new(big.Int).Set(r)
+ v.Sub(v, x3)
+ y3.Mul(y3, v)
+ s1.Mul(s1, j)
+ s1.Lsh(s1, 1)
+ y3.Sub(y3, s1)
+ y3.Mod(y3, curve.P)
+
+ z3 := new(big.Int).Add(z1, z2)
+ z3.Mul(z3, z3)
+ z3.Sub(z3, z1z1)
+ if z3.Sign() == -1 {
+ z3.Add(z3, curve.P)
+ }
+ z3.Sub(z3, z2z2)
+ if z3.Sign() == -1 {
+ z3.Add(z3, curve.P)
+ }
+ z3.Mul(z3, h)
+ z3.Mod(z3, curve.P)
+
+ return x3, y3, z3
+}
+
+// Double returns 2*(x,y)
+func (curve *Curve) Double(x1, y1 *big.Int) (*big.Int, *big.Int) {
+ z1 := new(big.Int).SetInt64(1)
+ return curve.affineFromJacobian(curve.doubleJacobian(x1, y1, z1))
+}
+
+// doubleJacobian takes a point in Jacobian coordinates, (x, y, z), and
+// returns its double, also in Jacobian form.
+func (curve *Curve) doubleJacobian(x, y, z *big.Int) (*big.Int, *big.Int, *big.Int) {
+ // See http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b
+ delta := new(big.Int).Mul(z, z)
+ delta.Mod(delta, curve.P)
+ gamma := new(big.Int).Mul(y, y)
+ gamma.Mod(gamma, curve.P)
+ alpha := new(big.Int).Sub(x, delta)
+ if alpha.Sign() == -1 {
+ alpha.Add(alpha, curve.P)
+ }
+ alpha2 := new(big.Int).Add(x, delta)
+ alpha.Mul(alpha, alpha2)
+ alpha2.Set(alpha)
+ alpha.Lsh(alpha, 1)
+ alpha.Add(alpha, alpha2)
+
+ beta := alpha2.Mul(x, gamma)
+
+ x3 := new(big.Int).Mul(alpha, alpha)
+ beta8 := new(big.Int).Lsh(beta, 3)
+ x3.Sub(x3, beta8)
+ for x3.Sign() == -1 {
+ x3.Add(x3, curve.P)
+ }
+ x3.Mod(x3, curve.P)
+
+ z3 := new(big.Int).Add(y, z)
+ z3.Mul(z3, z3)
+ z3.Sub(z3, gamma)
+ if z3.Sign() == -1 {
+ z3.Add(z3, curve.P)
+ }
+ z3.Sub(z3, delta)
+ if z3.Sign() == -1 {
+ z3.Add(z3, curve.P)
+ }
+ z3.Mod(z3, curve.P)
+
+ beta.Lsh(beta, 2)
+ beta.Sub(beta, x3)
+ if beta.Sign() == -1 {
+ beta.Add(beta, curve.P)
+ }
+ y3 := alpha.Mul(alpha, beta)
+
+ gamma.Mul(gamma, gamma)
+ gamma.Lsh(gamma, 3)
+ gamma.Mod(gamma, curve.P)
+
+ y3.Sub(y3, gamma)
+ if y3.Sign() == -1 {
+ y3.Add(y3, curve.P)
+ }
+ y3.Mod(y3, curve.P)
+
+ return x3, y3, z3
+}
+
+// ScalarMult returns k*(Bx,By) where k is a number in big-endian form.
+func (curve *Curve) ScalarMult(Bx, By *big.Int, k []byte) (*big.Int, *big.Int) {
+ // We have a slight problem in that the identity of the group (the
+ // point at infinity) cannot be represented in (x, y) form on a finite
+ // machine. Thus the standard add/double algorithm has to be tweaked
+ // slightly: our initial state is not the identity, but x, and we
+ // ignore the first true bit in |k|. If we don't find any true bits in
+ // |k|, then we return nil, nil, because we cannot return the identity
+ // element.
+
+ Bz := new(big.Int).SetInt64(1)
+ x := Bx
+ y := By
+ z := Bz
+
+ seenFirstTrue := false
+ for _, byte := range k {
+ for bitNum := 0; bitNum < 8; bitNum++ {
+ if seenFirstTrue {
+ x, y, z = curve.doubleJacobian(x, y, z)
+ }
+ if byte&0x80 == 0x80 {
+ if !seenFirstTrue {
+ seenFirstTrue = true
+ } else {
+ x, y, z = curve.addJacobian(Bx, By, Bz, x, y, z)
+ }
+ }
+ byte <<= 1
+ }
+ }
+
+ if !seenFirstTrue {
+ return nil, nil
+ }
+
+ return curve.affineFromJacobian(x, y, z)
+}
+
+// ScalarBaseMult returns k*G, where G is the base point of the group and k is
+// an integer in big-endian form.
+func (curve *Curve) ScalarBaseMult(k []byte) (*big.Int, *big.Int) {
+ return curve.ScalarMult(curve.Gx, curve.Gy, k)
+}
+
+var mask = []byte{0xff, 0x1, 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f}
+
+// GenerateKey returns a public/private key pair. The private key is generated
+// using the given reader, which must return random data.
+func (curve *Curve) GenerateKey(rand io.Reader) (priv []byte, x, y *big.Int, err os.Error) {
+ byteLen := (curve.BitSize + 7) >> 3
+ priv = make([]byte, byteLen)
+
+ for x == nil {
+ _, err = io.ReadFull(rand, priv)
+ if err != nil {
+ return
+ }
+ // We have to mask off any excess bits in the case that the size of the
+ // underlying field is not a whole number of bytes.
+ priv[0] &= mask[curve.BitSize%8]
+ // This is because, in tests, rand will return all zeros and we don't
+ // want to get the point at infinity and loop forever.
+ priv[1] ^= 0x42
+ x, y = curve.ScalarBaseMult(priv)
+ }
+ return
+}
+
+// Marshal converts a point into the form specified in section 4.3.6 of ANSI
+// X9.62.
+func (curve *Curve) Marshal(x, y *big.Int) []byte {
+ byteLen := (curve.BitSize + 7) >> 3
+
+ ret := make([]byte, 1+2*byteLen)
+ ret[0] = 4 // uncompressed point
+
+ xBytes := x.Bytes()
+ copy(ret[1+byteLen-len(xBytes):], xBytes)
+ yBytes := y.Bytes()
+ copy(ret[1+2*byteLen-len(yBytes):], yBytes)
+ return ret
+}
+
+// Unmarshal converts a point, serialised by Marshal, into an x, y pair. On
+// error, x = nil.
+func (curve *Curve) Unmarshal(data []byte) (x, y *big.Int) {
+ byteLen := (curve.BitSize + 7) >> 3
+ if len(data) != 1+2*byteLen {
+ return
+ }
+ if data[0] != 4 { // uncompressed form
+ return
+ }
+ x = new(big.Int).SetBytes(data[1 : 1+byteLen])
+ y = new(big.Int).SetBytes(data[1+byteLen:])
+ return
+}
+
+var initonce sync.Once
+var p224 *Curve
+var p256 *Curve
+var p384 *Curve
+var p521 *Curve
+
+func initAll() {
+ initP224()
+ initP256()
+ initP384()
+ initP521()
+}
+
+func initP224() {
+ // See FIPS 186-3, section D.2.2
+ p224 = new(Curve)
+ p224.P, _ = new(big.Int).SetString("26959946667150639794667015087019630673557916260026308143510066298881", 10)
+ p224.B, _ = new(big.Int).SetString("b4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4", 16)
+ p224.Gx, _ = new(big.Int).SetString("b70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21", 16)
+ p224.Gy, _ = new(big.Int).SetString("bd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34", 16)
+ p224.BitSize = 224
+}
+
+func initP256() {
+ // See FIPS 186-3, section D.2.3
+ p256 = new(Curve)
+ p256.P, _ = new(big.Int).SetString("115792089210356248762697446949407573530086143415290314195533631308867097853951", 10)
+ p256.B, _ = new(big.Int).SetString("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", 16)
+ p256.Gx, _ = new(big.Int).SetString("6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296", 16)
+ p256.Gy, _ = new(big.Int).SetString("4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5", 16)
+ p256.BitSize = 256
+}
+
+func initP384() {
+ // See FIPS 186-3, section D.2.4
+ p384 = new(Curve)
+ p384.P, _ = new(big.Int).SetString("39402006196394479212279040100143613805079739270465446667948293404245721771496870329047266088258938001861606973112319", 10)
+ p384.B, _ = new(big.Int).SetString("b3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef", 16)
+ p384.Gx, _ = new(big.Int).SetString("aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7", 16)
+ p384.Gy, _ = new(big.Int).SetString("3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f", 16)
+ p384.BitSize = 384
+}
+
+func initP521() {
+ // See FIPS 186-3, section D.2.5
+ p521 = new(Curve)
+ p521.P, _ = new(big.Int).SetString("6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151", 10)
+ p521.B, _ = new(big.Int).SetString("051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00", 16)
+ p521.Gx, _ = new(big.Int).SetString("c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66", 16)
+ p521.Gy, _ = new(big.Int).SetString("11839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650", 16)
+ p521.BitSize = 521
+}
+
+// P224 returns a Curve which implements P-224 (see FIPS 186-3, section D.2.2)
+func P224() *Curve {
+ initonce.Do(initAll)
+ return p224
+}
+
+// P256 returns a Curve which implements P-256 (see FIPS 186-3, section D.2.3)
+func P256() *Curve {
+ initonce.Do(initAll)
+ return p256
+}
+
+// P384 returns a Curve which implements P-384 (see FIPS 186-3, section D.2.4)
+func P384() *Curve {
+ initonce.Do(initAll)
+ return p384
+}
+
+// P256 returns a Curve which implements P-521 (see FIPS 186-3, section D.2.5)
+func P521() *Curve {
+ initonce.Do(initAll)
+ return p521
+}
diff --git a/src/pkg/crypto/elliptic/elliptic_test.go b/src/pkg/crypto/elliptic/elliptic_test.go
new file mode 100644
index 000000000..6ae6fb96d
--- /dev/null
+++ b/src/pkg/crypto/elliptic/elliptic_test.go
@@ -0,0 +1,331 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package elliptic
+
+import (
+ "big"
+ "crypto/rand"
+ "fmt"
+ "testing"
+)
+
+func TestOnCurve(t *testing.T) {
+ p224 := P224()
+ if !p224.IsOnCurve(p224.Gx, p224.Gy) {
+ t.Errorf("FAIL")
+ }
+}
+
+type baseMultTest struct {
+ k string
+ x, y string
+}
+
+var p224BaseMultTests = []baseMultTest{
+ {
+ "1",
+ "b70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21",
+ "bd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34",
+ },
+ {
+ "2",
+ "706a46dc76dcb76798e60e6d89474788d16dc18032d268fd1a704fa6",
+ "1c2b76a7bc25e7702a704fa986892849fca629487acf3709d2e4e8bb",
+ },
+ {
+ "3",
+ "df1b1d66a551d0d31eff822558b9d2cc75c2180279fe0d08fd896d04",
+ "a3f7f03cadd0be444c0aa56830130ddf77d317344e1af3591981a925",
+ },
+ {
+ "4",
+ "ae99feebb5d26945b54892092a8aee02912930fa41cd114e40447301",
+ "482580a0ec5bc47e88bc8c378632cd196cb3fa058a7114eb03054c9",
+ },
+ {
+ "5",
+ "31c49ae75bce7807cdff22055d94ee9021fedbb5ab51c57526f011aa",
+ "27e8bff1745635ec5ba0c9f1c2ede15414c6507d29ffe37e790a079b",
+ },
+ {
+ "6",
+ "1f2483f82572251fca975fea40db821df8ad82a3c002ee6c57112408",
+ "89faf0ccb750d99b553c574fad7ecfb0438586eb3952af5b4b153c7e",
+ },
+ {
+ "7",
+ "db2f6be630e246a5cf7d99b85194b123d487e2d466b94b24a03c3e28",
+ "f3a30085497f2f611ee2517b163ef8c53b715d18bb4e4808d02b963",
+ },
+ {
+ "8",
+ "858e6f9cc6c12c31f5df124aa77767b05c8bc021bd683d2b55571550",
+ "46dcd3ea5c43898c5c5fc4fdac7db39c2f02ebee4e3541d1e78047a",
+ },
+ {
+ "9",
+ "2fdcccfee720a77ef6cb3bfbb447f9383117e3daa4a07e36ed15f78d",
+ "371732e4f41bf4f7883035e6a79fcedc0e196eb07b48171697517463",
+ },
+ {
+ "10",
+ "aea9e17a306517eb89152aa7096d2c381ec813c51aa880e7bee2c0fd",
+ "39bb30eab337e0a521b6cba1abe4b2b3a3e524c14a3fe3eb116b655f",
+ },
+ {
+ "11",
+ "ef53b6294aca431f0f3c22dc82eb9050324f1d88d377e716448e507c",
+ "20b510004092e96636cfb7e32efded8265c266dfb754fa6d6491a6da",
+ },
+ {
+ "12",
+ "6e31ee1dc137f81b056752e4deab1443a481033e9b4c93a3044f4f7a",
+ "207dddf0385bfdeab6e9acda8da06b3bbef224a93ab1e9e036109d13",
+ },
+ {
+ "13",
+ "34e8e17a430e43289793c383fac9774247b40e9ebd3366981fcfaeca",
+ "252819f71c7fb7fbcb159be337d37d3336d7feb963724fdfb0ecb767",
+ },
+ {
+ "14",
+ "a53640c83dc208603ded83e4ecf758f24c357d7cf48088b2ce01e9fa",
+ "d5814cd724199c4a5b974a43685fbf5b8bac69459c9469bc8f23ccaf",
+ },
+ {
+ "15",
+ "baa4d8635511a7d288aebeedd12ce529ff102c91f97f867e21916bf9",
+ "979a5f4759f80f4fb4ec2e34f5566d595680a11735e7b61046127989",
+ },
+ {
+ "16",
+ "b6ec4fe1777382404ef679997ba8d1cc5cd8e85349259f590c4c66d",
+ "3399d464345906b11b00e363ef429221f2ec720d2f665d7dead5b482",
+ },
+ {
+ "17",
+ "b8357c3a6ceef288310e17b8bfeff9200846ca8c1942497c484403bc",
+ "ff149efa6606a6bd20ef7d1b06bd92f6904639dce5174db6cc554a26",
+ },
+ {
+ "18",
+ "c9ff61b040874c0568479216824a15eab1a838a797d189746226e4cc",
+ "ea98d60e5ffc9b8fcf999fab1df7e7ef7084f20ddb61bb045a6ce002",
+ },
+ {
+ "19",
+ "a1e81c04f30ce201c7c9ace785ed44cc33b455a022f2acdbc6cae83c",
+ "dcf1f6c3db09c70acc25391d492fe25b4a180babd6cea356c04719cd",
+ },
+ {
+ "20",
+ "fcc7f2b45df1cd5a3c0c0731ca47a8af75cfb0347e8354eefe782455",
+ "d5d7110274cba7cdee90e1a8b0d394c376a5573db6be0bf2747f530",
+ },
+ {
+ "112233445566778899",
+ "61f077c6f62ed802dad7c2f38f5c67f2cc453601e61bd076bb46179e",
+ "2272f9e9f5933e70388ee652513443b5e289dd135dcc0d0299b225e4",
+ },
+ {
+ "112233445566778899112233445566778899",
+ "29895f0af496bfc62b6ef8d8a65c88c613949b03668aab4f0429e35",
+ "3ea6e53f9a841f2019ec24bde1a75677aa9b5902e61081c01064de93",
+ },
+ {
+ "6950511619965839450988900688150712778015737983940691968051900319680",
+ "ab689930bcae4a4aa5f5cb085e823e8ae30fd365eb1da4aba9cf0379",
+ "3345a121bbd233548af0d210654eb40bab788a03666419be6fbd34e7",
+ },
+ {
+ "13479972933410060327035789020509431695094902435494295338570602119423",
+ "bdb6a8817c1f89da1c2f3dd8e97feb4494f2ed302a4ce2bc7f5f4025",
+ "4c7020d57c00411889462d77a5438bb4e97d177700bf7243a07f1680",
+ },
+ {
+ "13479971751745682581351455311314208093898607229429740618390390702079",
+ "d58b61aa41c32dd5eba462647dba75c5d67c83606c0af2bd928446a9",
+ "d24ba6a837be0460dd107ae77725696d211446c5609b4595976b16bd",
+ },
+ {
+ "13479972931865328106486971546324465392952975980343228160962702868479",
+ "dc9fa77978a005510980e929a1485f63716df695d7a0c18bb518df03",
+ "ede2b016f2ddffc2a8c015b134928275ce09e5661b7ab14ce0d1d403",
+ },
+ {
+ "11795773708834916026404142434151065506931607341523388140225443265536",
+ "499d8b2829cfb879c901f7d85d357045edab55028824d0f05ba279ba",
+ "bf929537b06e4015919639d94f57838fa33fc3d952598dcdbb44d638",
+ },
+ {
+ "784254593043826236572847595991346435467177662189391577090",
+ "8246c999137186632c5f9eddf3b1b0e1764c5e8bd0e0d8a554b9cb77",
+ "e80ed8660bc1cb17ac7d845be40a7a022d3306f116ae9f81fea65947",
+ },
+ {
+ "13479767645505654746623887797783387853576174193480695826442858012671",
+ "6670c20afcceaea672c97f75e2e9dd5c8460e54bb38538ebb4bd30eb",
+ "f280d8008d07a4caf54271f993527d46ff3ff46fd1190a3f1faa4f74",
+ },
+ {
+ "205688069665150753842126177372015544874550518966168735589597183",
+ "eca934247425cfd949b795cb5ce1eff401550386e28d1a4c5a8eb",
+ "d4c01040dba19628931bc8855370317c722cbd9ca6156985f1c2e9ce",
+ },
+ {
+ "13479966930919337728895168462090683249159702977113823384618282123295",
+ "ef353bf5c73cd551b96d596fbc9a67f16d61dd9fe56af19de1fba9cd",
+ "21771b9cdce3e8430c09b3838be70b48c21e15bc09ee1f2d7945b91f",
+ },
+ {
+ "50210731791415612487756441341851895584393717453129007497216",
+ "4036052a3091eb481046ad3289c95d3ac905ca0023de2c03ecd451cf",
+ "d768165a38a2b96f812586a9d59d4136035d9c853a5bf2e1c86a4993",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368041",
+ "fcc7f2b45df1cd5a3c0c0731ca47a8af75cfb0347e8354eefe782455",
+ "f2a28eefd8b345832116f1e574f2c6b2c895aa8c24941f40d8b80ad1",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368042",
+ "a1e81c04f30ce201c7c9ace785ed44cc33b455a022f2acdbc6cae83c",
+ "230e093c24f638f533dac6e2b6d01da3b5e7f45429315ca93fb8e634",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368043",
+ "c9ff61b040874c0568479216824a15eab1a838a797d189746226e4cc",
+ "156729f1a003647030666054e208180f8f7b0df2249e44fba5931fff",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368044",
+ "b8357c3a6ceef288310e17b8bfeff9200846ca8c1942497c484403bc",
+ "eb610599f95942df1082e4f9426d086fb9c6231ae8b24933aab5db",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368045",
+ "b6ec4fe1777382404ef679997ba8d1cc5cd8e85349259f590c4c66d",
+ "cc662b9bcba6f94ee4ff1c9c10bd6ddd0d138df2d099a282152a4b7f",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368046",
+ "baa4d8635511a7d288aebeedd12ce529ff102c91f97f867e21916bf9",
+ "6865a0b8a607f0b04b13d1cb0aa992a5a97f5ee8ca1849efb9ed8678",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368047",
+ "a53640c83dc208603ded83e4ecf758f24c357d7cf48088b2ce01e9fa",
+ "2a7eb328dbe663b5a468b5bc97a040a3745396ba636b964370dc3352",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368048",
+ "34e8e17a430e43289793c383fac9774247b40e9ebd3366981fcfaeca",
+ "dad7e608e380480434ea641cc82c82cbc92801469c8db0204f13489a",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368049",
+ "6e31ee1dc137f81b056752e4deab1443a481033e9b4c93a3044f4f7a",
+ "df82220fc7a4021549165325725f94c3410ddb56c54e161fc9ef62ee",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368050",
+ "ef53b6294aca431f0f3c22dc82eb9050324f1d88d377e716448e507c",
+ "df4aefffbf6d1699c930481cd102127c9a3d992048ab05929b6e5927",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368051",
+ "aea9e17a306517eb89152aa7096d2c381ec813c51aa880e7bee2c0fd",
+ "c644cf154cc81f5ade49345e541b4d4b5c1adb3eb5c01c14ee949aa2",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368052",
+ "2fdcccfee720a77ef6cb3bfbb447f9383117e3daa4a07e36ed15f78d",
+ "c8e8cd1b0be40b0877cfca1958603122f1e6914f84b7e8e968ae8b9e",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368053",
+ "858e6f9cc6c12c31f5df124aa77767b05c8bc021bd683d2b55571550",
+ "fb9232c15a3bc7673a3a03b0253824c53d0fd1411b1cabe2e187fb87",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368054",
+ "db2f6be630e246a5cf7d99b85194b123d487e2d466b94b24a03c3e28",
+ "f0c5cff7ab680d09ee11dae84e9c1072ac48ea2e744b1b7f72fd469e",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368055",
+ "1f2483f82572251fca975fea40db821df8ad82a3c002ee6c57112408",
+ "76050f3348af2664aac3a8b05281304ebc7a7914c6ad50a4b4eac383",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368056",
+ "31c49ae75bce7807cdff22055d94ee9021fedbb5ab51c57526f011aa",
+ "d817400e8ba9ca13a45f360e3d121eaaeb39af82d6001c8186f5f866",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368057",
+ "ae99feebb5d26945b54892092a8aee02912930fa41cd114e40447301",
+ "fb7da7f5f13a43b81774373c879cd32d6934c05fa758eeb14fcfab38",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368058",
+ "df1b1d66a551d0d31eff822558b9d2cc75c2180279fe0d08fd896d04",
+ "5c080fc3522f41bbb3f55a97cfecf21f882ce8cbb1e50ca6e67e56dc",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368059",
+ "706a46dc76dcb76798e60e6d89474788d16dc18032d268fd1a704fa6",
+ "e3d4895843da188fd58fb0567976d7b50359d6b78530c8f62d1b1746",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368060",
+ "b70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21",
+ "42c89c774a08dc04b3dd201932bc8a5ea5f8b89bbb2a7e667aff81cd",
+ },
+}
+
+func TestBaseMult(t *testing.T) {
+ p224 := P224()
+ for i, e := range p224BaseMultTests {
+ k, ok := new(big.Int).SetString(e.k, 10)
+ if !ok {
+ t.Errorf("%d: bad value for k: %s", i, e.k)
+ }
+ x, y := p224.ScalarBaseMult(k.Bytes())
+ if fmt.Sprintf("%x", x) != e.x || fmt.Sprintf("%x", y) != e.y {
+ t.Errorf("%d: bad output for k=%s: got (%x, %s), want (%s, %s)", i, e.k, x, y, e.x, e.y)
+ }
+ }
+}
+
+func BenchmarkBaseMult(b *testing.B) {
+ b.ResetTimer()
+ p224 := P224()
+ e := p224BaseMultTests[25]
+ k, _ := new(big.Int).SetString(e.k, 10)
+ b.StartTimer()
+ for i := 0; i < b.N; i++ {
+ p224.ScalarBaseMult(k.Bytes())
+ }
+}
+
+func TestMarshal(t *testing.T) {
+ p224 := P224()
+ _, x, y, err := p224.GenerateKey(rand.Reader)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ serialised := p224.Marshal(x, y)
+ xx, yy := p224.Unmarshal(serialised)
+ if xx == nil {
+ t.Error("failed to unmarshal")
+ return
+ }
+ if xx.Cmp(x) != 0 || yy.Cmp(y) != 0 {
+ t.Error("unmarshal returned different values")
+ return
+ }
+}
diff --git a/src/pkg/crypto/hmac/Makefile b/src/pkg/crypto/hmac/Makefile
index d1a6bfc2b..cc69abf60 100644
--- a/src/pkg/crypto/hmac/Makefile
+++ b/src/pkg/crypto/hmac/Makefile
@@ -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 ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=crypto/hmac
GOFILES=\
diff --git a/src/pkg/crypto/hmac/hmac.go b/src/pkg/crypto/hmac/hmac.go
index 38d13738d..298fb2c06 100644
--- a/src/pkg/crypto/hmac/hmac.go
+++ b/src/pkg/crypto/hmac/hmac.go
@@ -11,6 +11,7 @@ package hmac
import (
"crypto/md5"
"crypto/sha1"
+ "crypto/sha256"
"hash"
"os"
)
@@ -34,10 +35,9 @@ const (
)
type hmac struct {
- size int
- key []byte
- tmp []byte
- inner hash.Hash
+ size int
+ key, tmp []byte
+ outer, inner hash.Hash
}
func (h *hmac) tmpPad(xor byte) {
@@ -50,14 +50,14 @@ func (h *hmac) tmpPad(xor byte) {
}
func (h *hmac) Sum() []byte {
- h.tmpPad(0x5c)
sum := h.inner.Sum()
+ h.tmpPad(0x5c)
for i, b := range sum {
h.tmp[padSize+i] = b
}
- h.inner.Reset()
- h.inner.Write(h.tmp)
- return h.inner.Sum()
+ h.outer.Reset()
+ h.outer.Write(h.tmp)
+ return h.outer.Sum()
}
func (h *hmac) Write(p []byte) (n int, err os.Error) {
@@ -72,27 +72,29 @@ func (h *hmac) Reset() {
h.inner.Write(h.tmp[0:padSize])
}
-// New returns a new HMAC hash using the given hash and key.
-func New(h hash.Hash, key []byte) hash.Hash {
+// New returns a new HMAC hash using the given hash generator and key.
+func New(h func() hash.Hash, key []byte) hash.Hash {
+ hm := new(hmac)
+ hm.outer = h()
+ hm.inner = h()
+ hm.size = hm.inner.Size()
+ hm.tmp = make([]byte, padSize+hm.size)
if len(key) > padSize {
// If key is too big, hash it.
- h.Write(key)
- key = h.Sum()
+ hm.outer.Write(key)
+ key = hm.outer.Sum()
}
- hm := new(hmac)
- hm.inner = h
- hm.size = h.Size()
hm.key = make([]byte, len(key))
- for i, k := range key {
- hm.key[i] = k
- }
- hm.tmp = make([]byte, padSize+hm.size)
+ 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) }
+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) }
+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 d867c83a9..40adbad04 100644
--- a/src/pkg/crypto/hmac/hmac_test.go
+++ b/src/pkg/crypto/hmac/hmac_test.go
@@ -17,10 +17,10 @@ type hmacTest struct {
out string
}
-// Tests from US FIPS 198
-// http://csrc.nist.gov/publications/fips/fips198/fips-198a.pdf
var hmacTests = []hmacTest{
- hmacTest{
+ // Tests from US FIPS 198
+ // http://csrc.nist.gov/publications/fips/fips198/fips-198a.pdf
+ {
NewSHA1,
[]byte{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
@@ -35,7 +35,7 @@ var hmacTests = []hmacTest{
[]byte("Sample #1"),
"4f4ca3d5d68ba7cc0a1208c9c61e9c5da0403c0a",
},
- hmacTest{
+ {
NewSHA1,
[]byte{
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
@@ -45,7 +45,7 @@ var hmacTests = []hmacTest{
[]byte("Sample #2"),
"0922d3405faa3d194f82a45830737d5cc6c75d24",
},
- hmacTest{
+ {
NewSHA1,
[]byte{
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
@@ -67,12 +67,117 @@ var hmacTests = []hmacTest{
},
// Test from Plan 9.
- hmacTest{
+ {
NewMD5,
[]byte("Jefe"),
[]byte("what do ya want for nothing?"),
"750c783e6ab0b503eaa86e310a5db738",
},
+
+ // Tests from RFC 4231
+ {
+ NewSHA256,
+ []byte{
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b,
+ },
+ []byte("Hi There"),
+ "b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7",
+ },
+ {
+ NewSHA256,
+ []byte("Jefe"),
+ []byte("what do ya want for nothing?"),
+ "5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843",
+ },
+ {
+ NewSHA256,
+ []byte{
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa,
+ },
+ []byte{
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd,
+ },
+ "773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe",
+ },
+ {
+ NewSHA256,
+ []byte{
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
+ 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+ 0x19,
+ },
+ []byte{
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd,
+ },
+ "82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b",
+ },
+ {
+ NewSHA256,
+ []byte{
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa,
+ },
+ []byte("Test Using Larger Than Block-Size Key - Hash Key First"),
+ "60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54",
+ },
+ {
+ NewSHA256,
+ []byte{
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa,
+ },
+ []byte("This is a test using a larger than block-size key " +
+ "and a larger than block-size data. The key needs to " +
+ "be hashed before being used by the HMAC algorithm."),
+ "9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2",
+ },
}
func TestHMAC(t *testing.T) {
@@ -84,9 +189,13 @@ func TestHMAC(t *testing.T) {
t.Errorf("test %d.%d: Write(%d) = %d, %v", i, j, len(tt.in), n, err)
continue
}
- sum := fmt.Sprintf("%x", h.Sum())
- if sum != tt.out {
- t.Errorf("test %d.%d: have %s want %s\n", i, j, sum, tt.out)
+
+ // Repetive Sum() calls should return the same value
+ for k := 0; k < 2; k++ {
+ sum := fmt.Sprintf("%x", h.Sum())
+ if sum != tt.out {
+ t.Errorf("test %d.%d.%d: have %s want %s\n", i, j, k, sum, tt.out)
+ }
}
// Second iteration: make sure reset works.
diff --git a/src/pkg/crypto/md4/Makefile b/src/pkg/crypto/md4/Makefile
index 5fff2dd8f..eef05ab70 100644
--- a/src/pkg/crypto/md4/Makefile
+++ b/src/pkg/crypto/md4/Makefile
@@ -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 ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=crypto/md4
GOFILES=\
diff --git a/src/pkg/crypto/md4/md4.go b/src/pkg/crypto/md4/md4.go
index adbdf29e7..e13c986e6 100644
--- a/src/pkg/crypto/md4/md4.go
+++ b/src/pkg/crypto/md4/md4.go
@@ -68,10 +68,7 @@ func (d *digest) Write(p []byte) (nn int, err os.Error) {
n := _Block(d, p)
p = p[n:]
if len(p) > 0 {
- for i, x := range p {
- d.x[i] = x
- }
- d.nx = len(p)
+ d.nx = copy(d.x[:], p)
}
return
}
diff --git a/src/pkg/crypto/md4/md4_test.go b/src/pkg/crypto/md4/md4_test.go
index b883e6459..721bd4cbc 100644
--- a/src/pkg/crypto/md4/md4_test.go
+++ b/src/pkg/crypto/md4/md4_test.go
@@ -16,37 +16,37 @@ type md4Test struct {
}
var golden = []md4Test{
- md4Test{"31d6cfe0d16ae931b73c59d7e0c089c0", ""},
- md4Test{"bde52cb31de33e46245e05fbdbd6fb24", "a"},
- md4Test{"ec388dd78999dfc7cf4632465693b6bf", "ab"},
- md4Test{"a448017aaf21d8525fc10ae87aa6729d", "abc"},
- md4Test{"41decd8f579255c5200f86a4bb3ba740", "abcd"},
- md4Test{"9803f4a34e8eb14f96adba49064a0c41", "abcde"},
- md4Test{"804e7f1c2586e50b49ac65db5b645131", "abcdef"},
- md4Test{"752f4adfe53d1da0241b5bc216d098fc", "abcdefg"},
- md4Test{"ad9daf8d49d81988590a6f0e745d15dd", "abcdefgh"},
- md4Test{"1e4e28b05464316b56402b3815ed2dfd", "abcdefghi"},
- md4Test{"dc959c6f5d6f9e04e4380777cc964b3d", "abcdefghij"},
- md4Test{"1b5701e265778898ef7de5623bbe7cc0", "Discard medicine more than two years old."},
- md4Test{"d7f087e090fe7ad4a01cb59dacc9a572", "He who has a shady past knows that nice guys finish last."},
- md4Test{"a6f8fd6df617c72837592fc3570595c9", "I wouldn't marry him with a ten foot pole."},
- md4Test{"c92a84a9526da8abc240c05d6b1a1ce0", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
- md4Test{"f6013160c4dcb00847069fee3bb09803", "The days of the digital watch are numbered. -Tom Stoppard"},
- md4Test{"2c3bb64f50b9107ed57640fe94bec09f", "Nepal premier won't resign."},
- md4Test{"45b7d8a32c7806f2f7f897332774d6e4", "For every action there is an equal and opposite government program."},
- md4Test{"b5b4f9026b175c62d7654bdc3a1cd438", "His money is twice tainted: 'taint yours and 'taint mine."},
- md4Test{"caf44e80f2c20ce19b5ba1cab766e7bd", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
- md4Test{"191fae6707f496aa54a6bce9f2ecf74d", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
- md4Test{"9ddc753e7a4ccee6081cd1b45b23a834", "size: a.out: bad magic"},
- md4Test{"8d050f55b1cadb9323474564be08a521", "The major problem is with sendmail. -Mark Horton"},
- md4Test{"ad6e2587f74c3e3cc19146f6127fa2e3", "Give me a rock, paper and scissors and I will move the world. CCFestoon"},
- md4Test{"1d616d60a5fabe85589c3f1566ca7fca", "If the enemy is within range, then so are you."},
- md4Test{"aec3326a4f496a2ced65a1963f84577f", "It's well we cannot hear the screams/That we create in others' dreams."},
- md4Test{"77b4fd762d6b9245e61c50bf6ebf118b", "You remind me of a TV show, but that's all right: I watch it anyway."},
- md4Test{"e8f48c726bae5e516f6ddb1a4fe62438", "C is as portable as Stonehedge!!"},
- md4Test{"a3a84366e7219e887423b01f9be7166e", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
- md4Test{"a6b7aa35157e984ef5d9b7f32e5fbb52", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"},
- md4Test{"75661f0545955f8f9abeeb17845f3fd6", "How can you write a big system without C++? -Paul Glick"},
+ {"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) {
diff --git a/src/pkg/crypto/md5/Makefile b/src/pkg/crypto/md5/Makefile
index 7f37f6a33..5cde3e6d6 100644
--- a/src/pkg/crypto/md5/Makefile
+++ b/src/pkg/crypto/md5/Makefile
@@ -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 ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=crypto/md5
GOFILES=\
diff --git a/src/pkg/crypto/md5/md5.go b/src/pkg/crypto/md5/md5.go
index a83337651..54fddb63b 100644
--- a/src/pkg/crypto/md5/md5.go
+++ b/src/pkg/crypto/md5/md5.go
@@ -68,10 +68,7 @@ func (d *digest) Write(p []byte) (nn int, err os.Error) {
n := _Block(d, p)
p = p[n:]
if len(p) > 0 {
- for i, x := range p {
- d.x[i] = x
- }
- d.nx = len(p)
+ d.nx = copy(d.x[:], p)
}
return
}
diff --git a/src/pkg/crypto/md5/md5_test.go b/src/pkg/crypto/md5/md5_test.go
index f6c293837..857002b70 100644
--- a/src/pkg/crypto/md5/md5_test.go
+++ b/src/pkg/crypto/md5/md5_test.go
@@ -16,37 +16,37 @@ type md5Test struct {
}
var golden = []md5Test{
- md5Test{"d41d8cd98f00b204e9800998ecf8427e", ""},
- md5Test{"0cc175b9c0f1b6a831c399e269772661", "a"},
- md5Test{"187ef4436122d1cc2f40dc2b92f0eba0", "ab"},
- md5Test{"900150983cd24fb0d6963f7d28e17f72", "abc"},
- md5Test{"e2fc714c4727ee9395f324cd2e7f331f", "abcd"},
- md5Test{"ab56b4d92b40713acc5af89985d4b786", "abcde"},
- md5Test{"e80b5017098950fc58aad83c8c14978e", "abcdef"},
- md5Test{"7ac66c0f148de9519b8bd264312c4d64", "abcdefg"},
- md5Test{"e8dc4081b13434b45189a720b77b6818", "abcdefgh"},
- md5Test{"8aa99b1f439ff71293e95357bac6fd94", "abcdefghi"},
- md5Test{"a925576942e94b2ef57a066101b48876", "abcdefghij"},
- md5Test{"d747fc1719c7eacb84058196cfe56d57", "Discard medicine more than two years old."},
- md5Test{"bff2dcb37ef3a44ba43ab144768ca837", "He who has a shady past knows that nice guys finish last."},
- md5Test{"0441015ecb54a7342d017ed1bcfdbea5", "I wouldn't marry him with a ten foot pole."},
- md5Test{"9e3cac8e9e9757a60c3ea391130d3689", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
- md5Test{"a0f04459b031f916a59a35cc482dc039", "The days of the digital watch are numbered. -Tom Stoppard"},
- md5Test{"e7a48e0fe884faf31475d2a04b1362cc", "Nepal premier won't resign."},
- md5Test{"637d2fe925c07c113800509964fb0e06", "For every action there is an equal and opposite government program."},
- md5Test{"834a8d18d5c6562119cf4c7f5086cb71", "His money is twice tainted: 'taint yours and 'taint mine."},
- md5Test{"de3a4d2fd6c73ec2db2abad23b444281", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
- md5Test{"acf203f997e2cf74ea3aff86985aefaf", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
- md5Test{"e1c1384cb4d2221dfdd7c795a4222c9a", "size: a.out: bad magic"},
- md5Test{"c90f3ddecc54f34228c063d7525bf644", "The major problem is with sendmail. -Mark Horton"},
- md5Test{"cdf7ab6c1fd49bd9933c43f3ea5af185", "Give me a rock, paper and scissors and I will move the world. CCFestoon"},
- md5Test{"83bc85234942fc883c063cbd7f0ad5d0", "If the enemy is within range, then so are you."},
- md5Test{"277cbe255686b48dd7e8f389394d9299", "It's well we cannot hear the screams/That we create in others' dreams."},
- md5Test{"fd3fb0a7ffb8af16603f3d3af98f8e1f", "You remind me of a TV show, but that's all right: I watch it anyway."},
- md5Test{"469b13a78ebf297ecda64d4723655154", "C is as portable as Stonehedge!!"},
- md5Test{"63eb3a2f466410104731c4b037600110", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
- md5Test{"72c2ed7592debca1c90fc0100f931a2f", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"},
- md5Test{"132f7619d33b523b1d9e5bd8e0928355", "How can you write a big system without C++? -Paul Glick"},
+ {"d41d8cd98f00b204e9800998ecf8427e", ""},
+ {"0cc175b9c0f1b6a831c399e269772661", "a"},
+ {"187ef4436122d1cc2f40dc2b92f0eba0", "ab"},
+ {"900150983cd24fb0d6963f7d28e17f72", "abc"},
+ {"e2fc714c4727ee9395f324cd2e7f331f", "abcd"},
+ {"ab56b4d92b40713acc5af89985d4b786", "abcde"},
+ {"e80b5017098950fc58aad83c8c14978e", "abcdef"},
+ {"7ac66c0f148de9519b8bd264312c4d64", "abcdefg"},
+ {"e8dc4081b13434b45189a720b77b6818", "abcdefgh"},
+ {"8aa99b1f439ff71293e95357bac6fd94", "abcdefghi"},
+ {"a925576942e94b2ef57a066101b48876", "abcdefghij"},
+ {"d747fc1719c7eacb84058196cfe56d57", "Discard medicine more than two years old."},
+ {"bff2dcb37ef3a44ba43ab144768ca837", "He who has a shady past knows that nice guys finish last."},
+ {"0441015ecb54a7342d017ed1bcfdbea5", "I wouldn't marry him with a ten foot pole."},
+ {"9e3cac8e9e9757a60c3ea391130d3689", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
+ {"a0f04459b031f916a59a35cc482dc039", "The days of the digital watch are numbered. -Tom Stoppard"},
+ {"e7a48e0fe884faf31475d2a04b1362cc", "Nepal premier won't resign."},
+ {"637d2fe925c07c113800509964fb0e06", "For every action there is an equal and opposite government program."},
+ {"834a8d18d5c6562119cf4c7f5086cb71", "His money is twice tainted: 'taint yours and 'taint mine."},
+ {"de3a4d2fd6c73ec2db2abad23b444281", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
+ {"acf203f997e2cf74ea3aff86985aefaf", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
+ {"e1c1384cb4d2221dfdd7c795a4222c9a", "size: a.out: bad magic"},
+ {"c90f3ddecc54f34228c063d7525bf644", "The major problem is with sendmail. -Mark Horton"},
+ {"cdf7ab6c1fd49bd9933c43f3ea5af185", "Give me a rock, paper and scissors and I will move the world. CCFestoon"},
+ {"83bc85234942fc883c063cbd7f0ad5d0", "If the enemy is within range, then so are you."},
+ {"277cbe255686b48dd7e8f389394d9299", "It's well we cannot hear the screams/That we create in others' dreams."},
+ {"fd3fb0a7ffb8af16603f3d3af98f8e1f", "You remind me of a TV show, but that's all right: I watch it anyway."},
+ {"469b13a78ebf297ecda64d4723655154", "C is as portable as Stonehedge!!"},
+ {"63eb3a2f466410104731c4b037600110", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
+ {"72c2ed7592debca1c90fc0100f931a2f", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"},
+ {"132f7619d33b523b1d9e5bd8e0928355", "How can you write a big system without C++? -Paul Glick"},
}
func TestGolden(t *testing.T) {
diff --git a/src/pkg/exp/iterable/Makefile b/src/pkg/crypto/ocsp/Makefile
index 9adf714da..6e132ff9b 100644
--- a/src/pkg/exp/iterable/Makefile
+++ b/src/pkg/crypto/ocsp/Makefile
@@ -2,11 +2,10 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../../Make.$(GOARCH)
+include ../../../Make.inc
-TARG=exp/iterable
+TARG=crypto/ocsp
GOFILES=\
- array.go\
- iterable.go\
+ ocsp.go\
include ../../../Make.pkg
diff --git a/src/pkg/crypto/ocsp/ocsp.go b/src/pkg/crypto/ocsp/ocsp.go
new file mode 100644
index 000000000..f3fa3bc83
--- /dev/null
+++ b/src/pkg/crypto/ocsp/ocsp.go
@@ -0,0 +1,203 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package parses OCSP responses as specified in RFC 2560. OCSP responses
+// are signed messages attesting to the validity of a certificate for a small
+// period of time. This is used to manage revocation for X.509 certificates.
+package ocsp
+
+import (
+ "asn1"
+ "crypto/rsa"
+ "crypto/sha1"
+ "crypto/x509"
+ "os"
+ "time"
+)
+
+var idPKIXOCSPBasic = asn1.ObjectIdentifier([]int{1, 3, 6, 1, 5, 5, 7, 48, 1, 1})
+var idSHA1WithRSA = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 1, 5})
+
+// These are internal structures that reflect the ASN.1 structure of an OCSP
+// response. See RFC 2560, section 4.2.
+
+const (
+ ocspSuccess = 0
+ ocspMalformed = 1
+ ocspInternalError = 2
+ ocspTryLater = 3
+ ocspSigRequired = 4
+ ocspUnauthorized = 5
+)
+
+type rdnSequence []relativeDistinguishedNameSET
+
+type relativeDistinguishedNameSET []attributeTypeAndValue
+
+type attributeTypeAndValue struct {
+ Type asn1.ObjectIdentifier
+ Value interface{}
+}
+
+type algorithmIdentifier struct {
+ Algorithm asn1.ObjectIdentifier
+}
+
+type certID struct {
+ HashAlgorithm algorithmIdentifier
+ NameHash []byte
+ IssuerKeyHash []byte
+ SerialNumber asn1.RawValue
+}
+
+type responseASN1 struct {
+ Status asn1.Enumerated
+ Response responseBytes "explicit,tag:0"
+}
+
+type responseBytes struct {
+ ResponseType asn1.ObjectIdentifier
+ Response []byte
+}
+
+type basicResponse struct {
+ TBSResponseData responseData
+ SignatureAlgorithm algorithmIdentifier
+ Signature asn1.BitString
+ Certificates []asn1.RawValue "explicit,tag:0,optional"
+}
+
+type responseData struct {
+ Raw asn1.RawContent
+ Version int "optional,default:1,explicit,tag:0"
+ RequestorName rdnSequence "optional,explicit,tag:1"
+ KeyHash []byte "optional,explicit,tag:2"
+ ProducedAt *time.Time
+ Responses []singleResponse
+}
+
+type singleResponse struct {
+ CertID certID
+ Good asn1.Flag "explicit,tag:0,optional"
+ Revoked revokedInfo "explicit,tag:1,optional"
+ Unknown asn1.Flag "explicit,tag:2,optional"
+ ThisUpdate *time.Time
+ NextUpdate *time.Time "explicit,tag:0,optional"
+}
+
+type revokedInfo struct {
+ RevocationTime *time.Time
+ Reason int "explicit,tag:0,optional"
+}
+
+// This is the exposed reflection of the internal OCSP structures.
+
+const (
+ // Good means that the certificate is valid.
+ Good = iota
+ // Revoked means that the certificate has been deliberately revoked.
+ Revoked = iota
+ // Unknown means that the OCSP responder doesn't know about the certificate.
+ Unknown = iota
+ // ServerFailed means that the OCSP responder failed to process the request.
+ ServerFailed = iota
+)
+
+// Response represents an OCSP response. See RFC 2560.
+type Response struct {
+ // Status is one of {Good, Revoked, Unknown, ServerFailed}
+ Status int
+ SerialNumber []byte
+ ProducedAt, ThisUpdate, NextUpdate, RevokedAt *time.Time
+ RevocationReason int
+ Certificate *x509.Certificate
+}
+
+// ParseError results from an invalid OCSP response.
+type ParseError string
+
+func (p ParseError) String() string {
+ return string(p)
+}
+
+// ParseResponse parses an OCSP response in DER form. It only supports
+// responses for a single certificate and only those using RSA signatures.
+// Non-RSA responses will result in an x509.UnsupportedAlgorithmError.
+// Signature errors or parse failures will result in a ParseError.
+func ParseResponse(bytes []byte) (*Response, os.Error) {
+ var resp responseASN1
+ rest, err := asn1.Unmarshal(bytes, &resp)
+ if err != nil {
+ return nil, err
+ }
+ if len(rest) > 0 {
+ return nil, ParseError("trailing data in OCSP response")
+ }
+
+ ret := new(Response)
+ if resp.Status != ocspSuccess {
+ ret.Status = ServerFailed
+ return ret, nil
+ }
+
+ if !resp.Response.ResponseType.Equal(idPKIXOCSPBasic) {
+ return nil, ParseError("bad OCSP response type")
+ }
+
+ var basicResp basicResponse
+ rest, err = asn1.Unmarshal(resp.Response.Response, &basicResp)
+ if err != nil {
+ return nil, err
+ }
+
+ if len(basicResp.Certificates) != 1 {
+ return nil, ParseError("OCSP response contains bad number of certificates")
+ }
+
+ if len(basicResp.TBSResponseData.Responses) != 1 {
+ return nil, ParseError("OCSP response contains bad number of responses")
+ }
+
+ ret.Certificate, err = x509.ParseCertificate(basicResp.Certificates[0].FullBytes)
+ if err != nil {
+ return nil, err
+ }
+
+ if ret.Certificate.PublicKeyAlgorithm != x509.RSA || !basicResp.SignatureAlgorithm.Algorithm.Equal(idSHA1WithRSA) {
+ return nil, x509.UnsupportedAlgorithmError{}
+ }
+
+ h := sha1.New()
+ hashType := rsa.HashSHA1
+
+ pub := ret.Certificate.PublicKey.(*rsa.PublicKey)
+ h.Write(basicResp.TBSResponseData.Raw)
+ digest := h.Sum()
+ signature := basicResp.Signature.RightAlign()
+
+ if rsa.VerifyPKCS1v15(pub, hashType, digest, signature) != nil {
+ return nil, ParseError("bad OCSP signature")
+ }
+
+ r := basicResp.TBSResponseData.Responses[0]
+
+ ret.SerialNumber = r.CertID.SerialNumber.Bytes
+
+ switch {
+ case bool(r.Good):
+ ret.Status = Good
+ case bool(r.Unknown):
+ ret.Status = Unknown
+ default:
+ ret.Status = Revoked
+ ret.RevokedAt = r.Revoked.RevocationTime
+ ret.RevocationReason = r.Revoked.Reason
+ }
+
+ ret.ProducedAt = basicResp.TBSResponseData.ProducedAt
+ ret.ThisUpdate = r.ThisUpdate
+ ret.NextUpdate = r.NextUpdate
+
+ return ret, nil
+}
diff --git a/src/pkg/crypto/ocsp/ocsp_test.go b/src/pkg/crypto/ocsp/ocsp_test.go
new file mode 100644
index 000000000..f9889790f
--- /dev/null
+++ b/src/pkg/crypto/ocsp/ocsp_test.go
@@ -0,0 +1,97 @@
+package ocsp
+
+import (
+ "bytes"
+ "encoding/hex"
+ "reflect"
+ "testing"
+ "time"
+)
+
+func TestOCSPDecode(t *testing.T) {
+ responseBytes, _ := hex.DecodeString(ocspResponseHex)
+ resp, err := ParseResponse(responseBytes)
+ if err != nil {
+ t.Error(err)
+ }
+
+ expected := Response{Status: 0, SerialNumber: []byte{0x1, 0xd0, 0xfa}, RevocationReason: 0, ThisUpdate: &time.Time{Year: 2010, Month: 7, Day: 7, Hour: 15, Minute: 1, Second: 5, Weekday: 0, ZoneOffset: 0, Zone: "UTC"}, NextUpdate: &time.Time{Year: 2010, Month: 7, Day: 7, Hour: 18, Minute: 35, Second: 17, Weekday: 0, ZoneOffset: 0, Zone: "UTC"}}
+
+ if !reflect.DeepEqual(resp.ThisUpdate, resp.ThisUpdate) {
+ t.Errorf("resp.ThisUpdate: got %d, want %d", resp.ThisUpdate, expected.ThisUpdate)
+ }
+
+ if !reflect.DeepEqual(resp.NextUpdate, resp.NextUpdate) {
+ t.Errorf("resp.NextUpdate: got %d, want %d", resp.NextUpdate, expected.NextUpdate)
+ }
+
+ if resp.Status != expected.Status {
+ t.Errorf("resp.Status: got %d, want %d", resp.Status, expected.Status)
+ }
+
+ if !bytes.Equal(resp.SerialNumber, expected.SerialNumber) {
+ t.Errorf("resp.SerialNumber: got %x, want %x", resp.SerialNumber, expected.SerialNumber)
+ }
+
+ if resp.RevocationReason != expected.RevocationReason {
+ t.Errorf("resp.RevocationReason: got %d, want %d", resp.RevocationReason, expected.RevocationReason)
+ }
+}
+
+// This OCSP response was taken from Thawte's public OCSP responder.
+// To recreate:
+// $ openssl s_client -tls1 -showcerts -servername www.google.com -connect www.google.com:443
+// Copy and paste the first certificate into /tmp/cert.crt and the second into
+// /tmp/intermediate.crt
+// $ openssl ocsp -issuer /tmp/intermediate.crt -cert /tmp/cert.crt -url http://ocsp.thawte.com -resp_text -respout /tmp/ocsp.der
+// Then hex encode the result:
+// $ python -c 'print file("/tmp/ocsp.der", "r").read().encode("hex")'
+
+const ocspResponseHex = "308206bc0a0100a08206b5308206b106092b0601050507300101048206a23082069e3081" +
+ "c9a14e304c310b300906035504061302494c31163014060355040a130d5374617274436f" +
+ "6d204c74642e312530230603550403131c5374617274436f6d20436c6173732031204f43" +
+ "5350205369676e6572180f32303130303730373137333531375a30663064303c30090605" +
+ "2b0e03021a050004146568874f40750f016a3475625e1f5c93e5a26d580414eb4234d098" +
+ "b0ab9ff41b6b08f7cc642eef0e2c45020301d0fa8000180f323031303037303731353031" +
+ "30355aa011180f32303130303730373138333531375a300d06092a864886f70d01010505" +
+ "000382010100ab557ff070d1d7cebbb5f0ec91a15c3fed22eb2e1b8244f1b84545f013a4" +
+ "fb46214c5e3fbfbebb8a56acc2b9db19f68fd3c3201046b3824d5ba689f99864328710cb" +
+ "467195eb37d84f539e49f859316b32964dc3e47e36814ce94d6c56dd02733b1d0802f7ff" +
+ "4eebdbbd2927dcf580f16cbc290f91e81b53cb365e7223f1d6e20a88ea064104875e0145" +
+ "672b20fc14829d51ca122f5f5d77d3ad6c83889c55c7dc43680ba2fe3cef8b05dbcabdc0" +
+ "d3e09aaf9725597f8c858c2fa38c0d6aed2e6318194420dd1a1137445d13e1c97ab47896" +
+ "17a4e08925f46f867b72e3a4dc1f08cb870b2b0717f7207faa0ac512e628a029aba7457a" +
+ "e63dcf3281e2162d9349a08204ba308204b6308204b23082039aa003020102020101300d" +
+ "06092a864886f70d010105050030818c310b300906035504061302494c31163014060355" +
+ "040a130d5374617274436f6d204c74642e312b3029060355040b13225365637572652044" +
+ "69676974616c204365727469666963617465205369676e696e6731383036060355040313" +
+ "2f5374617274436f6d20436c6173732031205072696d61727920496e7465726d65646961" +
+ "746520536572766572204341301e170d3037313032353030323330365a170d3132313032" +
+ "333030323330365a304c310b300906035504061302494c31163014060355040a130d5374" +
+ "617274436f6d204c74642e312530230603550403131c5374617274436f6d20436c617373" +
+ "2031204f435350205369676e657230820122300d06092a864886f70d0101010500038201" +
+ "0f003082010a0282010100b9561b4c45318717178084e96e178df2255e18ed8d8ecc7c2b" +
+ "7b51a6c1c2e6bf0aa3603066f132fe10ae97b50e99fa24b83fc53dd2777496387d14e1c3" +
+ "a9b6a4933e2ac12413d085570a95b8147414a0bc007c7bcf222446ef7f1a156d7ea1c577" +
+ "fc5f0facdfd42eb0f5974990cb2f5cefebceef4d1bdc7ae5c1075c5a99a93171f2b0845b" +
+ "4ff0864e973fcfe32f9d7511ff87a3e943410c90a4493a306b6944359340a9ca96f02b66" +
+ "ce67f028df2980a6aaee8d5d5d452b8b0eb93f923cc1e23fcccbdbe7ffcb114d08fa7a6a" +
+ "3c404f825d1a0e715935cf623a8c7b59670014ed0622f6089a9447a7a19010f7fe58f841" +
+ "29a2765ea367824d1c3bb2fda308530203010001a382015c30820158300c0603551d1301" +
+ "01ff04023000300b0603551d0f0404030203a8301e0603551d250417301506082b060105" +
+ "0507030906092b0601050507300105301d0603551d0e0416041445e0a36695414c5dd449" +
+ "bc00e33cdcdbd2343e173081a80603551d230481a030819d8014eb4234d098b0ab9ff41b" +
+ "6b08f7cc642eef0e2c45a18181a47f307d310b300906035504061302494c311630140603" +
+ "55040a130d5374617274436f6d204c74642e312b3029060355040b132253656375726520" +
+ "4469676974616c204365727469666963617465205369676e696e67312930270603550403" +
+ "13205374617274436f6d2043657274696669636174696f6e20417574686f726974798201" +
+ "0a30230603551d12041c301a8618687474703a2f2f7777772e737461727473736c2e636f" +
+ "6d2f302c06096086480186f842010d041f161d5374617274436f6d205265766f63617469" +
+ "6f6e20417574686f72697479300d06092a864886f70d01010505000382010100182d2215" +
+ "8f0fc0291324fa8574c49bb8ff2835085adcbf7b7fc4191c397ab6951328253fffe1e5ec" +
+ "2a7da0d50fca1a404e6968481366939e666c0a6209073eca57973e2fefa9ed1718e8176f" +
+ "1d85527ff522c08db702e3b2b180f1cbff05d98128252cf0f450f7dd2772f4188047f19d" +
+ "c85317366f94bc52d60f453a550af58e308aaab00ced33040b62bf37f5b1ab2a4f7f0f80" +
+ "f763bf4d707bc8841d7ad9385ee2a4244469260b6f2bf085977af9074796048ecc2f9d48" +
+ "a1d24ce16e41a9941568fec5b42771e118f16c106a54ccc339a4b02166445a167902e75e" +
+ "6d8620b0825dcd18a069b90fd851d10fa8effd409deec02860d26d8d833f304b10669b42"
diff --git a/src/pkg/exp/nacl/av/Makefile b/src/pkg/crypto/openpgp/armor/Makefile
index d966078ec..138e314e9 100644
--- a/src/pkg/exp/nacl/av/Makefile
+++ b/src/pkg/crypto/openpgp/armor/Makefile
@@ -1,13 +1,12 @@
-# Copyright 2009 The Go Authors. All rights reserved.
+# Copyright 2010 The Go Authors. 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.$(GOARCH)
+include ../../../../Make.inc
-TARG=exp/nacl/av
+TARG=crypto/openpgp/armor
GOFILES=\
- av.go\
- event.go\
- image.go\
+ 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
new file mode 100644
index 000000000..97080f6c6
--- /dev/null
+++ b/src/pkg/crypto/openpgp/armor/armor.go
@@ -0,0 +1,220 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package implements OpenPGP ASCII Armor, see RFC 4880. OpenPGP Armor is
+// very similar to PEM except that it has an additional CRC checksum.
+package armor
+
+import (
+ "bytes"
+ "crypto/openpgp/error"
+ "encoding/base64"
+ "encoding/line"
+ "io"
+ "os"
+)
+
+// A Block represents an OpenPGP armored structure.
+//
+// The encoded form is:
+// -----BEGIN Type-----
+// Headers
+//
+// base64-encoded Bytes
+// '=' base64 encoded checksum
+// -----END Type-----
+// where Headers is a possibly empty sequence of Key: Value lines.
+//
+// Since the armored data can be very large, this package presents a streaming
+// interface.
+type Block struct {
+ Type string // The type, taken from the preamble (i.e. "PGP SIGNATURE").
+ Header map[string]string // Optional headers.
+ Body io.Reader // A Reader from which the contents can be read
+ lReader lineReader
+ oReader openpgpReader
+}
+
+var ArmorCorrupt os.Error = error.StructuralError("armor invalid")
+
+const crc24Init = 0xb704ce
+const crc24Poly = 0x1864cfb
+const crc24Mask = 0xffffff
+
+// crc24 calculates the OpenPGP checksum as specified in RFC 4880, section 6.1
+func crc24(crc uint32, d []byte) uint32 {
+ for _, b := range d {
+ crc ^= uint32(b) << 16
+ for i := 0; i < 8; i++ {
+ crc <<= 1
+ if crc&0x1000000 != 0 {
+ crc ^= crc24Poly
+ }
+ }
+ }
+ return crc
+}
+
+var armorStart = []byte("-----BEGIN ")
+var armorEnd = []byte("-----END ")
+var armorEndOfLine = []byte("-----")
+
+// lineReader wraps a line based reader. It watches for the end of an armor
+// block and records the expected CRC value.
+type lineReader struct {
+ in *line.Reader
+ buf []byte
+ eof bool
+ crc uint32
+}
+
+func (l *lineReader) Read(p []byte) (n int, err os.Error) {
+ if l.eof {
+ return 0, os.EOF
+ }
+
+ if len(l.buf) > 0 {
+ n = copy(p, l.buf)
+ l.buf = l.buf[n:]
+ return
+ }
+
+ line, isPrefix, err := l.in.ReadLine()
+ if err != nil {
+ return
+ }
+ if isPrefix {
+ return 0, ArmorCorrupt
+ }
+
+ if len(line) == 5 && line[0] == '=' {
+ // This is the checksum line
+ var expectedBytes [3]byte
+ var m int
+ m, err = base64.StdEncoding.Decode(expectedBytes[0:], line[1:])
+ if m != 3 || err != nil {
+ return
+ }
+ l.crc = uint32(expectedBytes[0])<<16 |
+ uint32(expectedBytes[1])<<8 |
+ uint32(expectedBytes[2])
+
+ line, _, err = l.in.ReadLine()
+ if err != nil && err != os.EOF {
+ return
+ }
+ if !bytes.HasPrefix(line, armorEnd) {
+ return 0, ArmorCorrupt
+ }
+
+ l.eof = true
+ return 0, os.EOF
+ }
+
+ if len(line) != 64 {
+ return 0, ArmorCorrupt
+ }
+
+ n = copy(p, line)
+ bytesToSave := len(line) - n
+ if bytesToSave > 0 {
+ if cap(l.buf) < bytesToSave {
+ l.buf = make([]byte, 0, bytesToSave)
+ }
+ l.buf = l.buf[0:bytesToSave]
+ copy(l.buf, line[n:])
+ }
+
+ return
+}
+
+// openpgpReader passes Read calls to the underlying base64 decoder, but keeps
+// a running CRC of the resulting data and checks the CRC against the value
+// found by the lineReader at EOF.
+type openpgpReader struct {
+ lReader *lineReader
+ b64Reader io.Reader
+ currentCRC uint32
+}
+
+func (r *openpgpReader) Read(p []byte) (n int, err os.Error) {
+ n, err = r.b64Reader.Read(p)
+ r.currentCRC = crc24(r.currentCRC, p[:n])
+
+ if err == os.EOF {
+ if r.lReader.crc != uint32(r.currentCRC&crc24Mask) {
+ return 0, ArmorCorrupt
+ }
+ }
+
+ return
+}
+
+// Decode reads a PGP armored block from the given Reader. It will ignore
+// leading garbage. If it doesn't find a block, it will return nil, os.EOF. The
+// given Reader is not usable after calling this function: an arbitary amount
+// of data may have been read past the end of the block.
+func Decode(in io.Reader) (p *Block, err os.Error) {
+ r := line.NewReader(in, 100)
+ var line []byte
+ ignoreNext := false
+
+TryNextBlock:
+ p = nil
+
+ // Skip leading garbage
+ for {
+ ignoreThis := ignoreNext
+ line, ignoreNext, err = r.ReadLine()
+ if err != nil {
+ return
+ }
+ if ignoreNext || ignoreThis {
+ continue
+ }
+ line = bytes.TrimSpace(line)
+ if len(line) > len(armorStart)+len(armorEndOfLine) && bytes.HasPrefix(line, armorStart) {
+ break
+ }
+ }
+
+ p = new(Block)
+ p.Type = string(line[len(armorStart) : len(line)-len(armorEndOfLine)])
+ p.Header = make(map[string]string)
+ nextIsContinuation := false
+ var lastKey string
+
+ // Read headers
+ for {
+ isContinuation := nextIsContinuation
+ line, nextIsContinuation, err = r.ReadLine()
+ if err != nil {
+ p = nil
+ return
+ }
+ if isContinuation {
+ p.Header[lastKey] += string(line)
+ continue
+ }
+ line = bytes.TrimSpace(line)
+ if len(line) == 0 {
+ break
+ }
+
+ i := bytes.Index(line, []byte(": "))
+ if i == -1 {
+ goto TryNextBlock
+ }
+ lastKey = string(line[:i])
+ p.Header[lastKey] = string(line[i+2:])
+ }
+
+ p.lReader.in = r
+ p.oReader.currentCRC = crc24Init
+ p.oReader.lReader = &p.lReader
+ p.oReader.b64Reader = base64.NewDecoder(base64.StdEncoding, &p.lReader)
+ p.Body = &p.oReader
+
+ return
+}
diff --git a/src/pkg/crypto/openpgp/armor/armor_test.go b/src/pkg/crypto/openpgp/armor/armor_test.go
new file mode 100644
index 000000000..e4ffd414b
--- /dev/null
+++ b/src/pkg/crypto/openpgp/armor/armor_test.go
@@ -0,0 +1,97 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package armor
+
+import (
+ "bytes"
+ "hash/adler32"
+ "io/ioutil"
+ "testing"
+)
+
+func TestDecodeEncode(t *testing.T) {
+ buf := bytes.NewBuffer([]byte(armorExample1))
+ result, err := Decode(buf)
+ if err != nil {
+ t.Error(err)
+ }
+ expectedType := "PGP SIGNATURE"
+ if result.Type != expectedType {
+ t.Errorf("result.Type: got:%s want:%s", result.Type, expectedType)
+ }
+ if len(result.Header) != 1 {
+ t.Errorf("len(result.Header): got:%d want:1", len(result.Header))
+ }
+ v, ok := result.Header["Version"]
+ if !ok || v != "GnuPG v1.4.10 (GNU/Linux)" {
+ t.Errorf("result.Header: got:%#v", result.Header)
+ }
+
+ contents, err := ioutil.ReadAll(result.Body)
+ if err != nil {
+ t.Error(err)
+ }
+
+ if adler32.Checksum(contents) != 0x789d7f00 {
+ t.Errorf("contents: got: %x", contents)
+ }
+
+ buf = bytes.NewBuffer(nil)
+ w, err := Encode(buf, result.Type, result.Header)
+ if err != nil {
+ t.Error(err)
+ }
+ _, err = w.Write(contents)
+ if err != nil {
+ t.Error(err)
+ }
+ w.Close()
+
+ if !bytes.Equal(buf.Bytes(), []byte(armorExample1)) {
+ t.Errorf("got: %s\nwant: %s", string(buf.Bytes()), armorExample1)
+ }
+}
+
+func TestLongHeader(t *testing.T) {
+ buf := bytes.NewBuffer([]byte(armorLongLine))
+ result, err := Decode(buf)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ value, ok := result.Header["Version"]
+ if !ok {
+ t.Errorf("missing Version header")
+ }
+ if value != longValueExpected {
+ t.Errorf("got: %s want: %s", value, longValueExpected)
+ }
+}
+
+const armorExample1 = `-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v1.4.10 (GNU/Linux)
+
+iQEcBAABAgAGBQJMtFESAAoJEKsQXJGvOPsVj40H/1WW6jaMXv4BW+1ueDSMDwM8
+kx1fLOXbVM5/Kn5LStZNt1jWWnpxdz7eq3uiqeCQjmqUoRde3YbB2EMnnwRbAhpp
+cacnAvy9ZQ78OTxUdNW1mhX5bS6q1MTEJnl+DcyigD70HG/yNNQD7sOPMdYQw0TA
+byQBwmLwmTsuZsrYqB68QyLHI+DUugn+kX6Hd2WDB62DKa2suoIUIHQQCd/ofwB3
+WfCYInXQKKOSxu2YOg2Eb4kLNhSMc1i9uKUWAH+sdgJh7NBgdoE4MaNtBFkHXRvv
+okWuf3+xA9ksp1npSY/mDvgHijmjvtpRDe6iUeqfCn8N9u9CBg8geANgaG8+QA4=
+=wfQG
+-----END PGP SIGNATURE-----`
+
+const armorLongLine = `-----BEGIN PGP SIGNATURE-----
+Version: 0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz
+
+iQEcBAABAgAGBQJMtFESAAoJEKsQXJGvOPsVj40H/1WW6jaMXv4BW+1ueDSMDwM8
+kx1fLOXbVM5/Kn5LStZNt1jWWnpxdz7eq3uiqeCQjmqUoRde3YbB2EMnnwRbAhpp
+cacnAvy9ZQ78OTxUdNW1mhX5bS6q1MTEJnl+DcyigD70HG/yNNQD7sOPMdYQw0TA
+byQBwmLwmTsuZsrYqB68QyLHI+DUugn+kX6Hd2WDB62DKa2suoIUIHQQCd/ofwB3
+WfCYInXQKKOSxu2YOg2Eb4kLNhSMc1i9uKUWAH+sdgJh7NBgdoE4MaNtBFkHXRvv
+okWuf3+xA9ksp1npSY/mDvgHijmjvtpRDe6iUeqfCn8N9u9CBg8geANgaG8+QA4=
+=wfQG
+-----END PGP SIGNATURE-----`
+
+const longValueExpected = "0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz"
diff --git a/src/pkg/crypto/openpgp/armor/encode.go b/src/pkg/crypto/openpgp/armor/encode.go
new file mode 100644
index 000000000..410e73460
--- /dev/null
+++ b/src/pkg/crypto/openpgp/armor/encode.go
@@ -0,0 +1,162 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package armor
+
+import (
+ "encoding/base64"
+ "io"
+ "os"
+)
+
+var armorHeaderSep = []byte(": ")
+var blockEnd = []byte("\n=")
+var newline = []byte("\n")
+var armorEndOfLineOut = []byte("-----\n")
+
+// writeSlices writes its arguments to the given Writer.
+func writeSlices(out io.Writer, slices ...[]byte) (err os.Error) {
+ for _, s := range slices {
+ _, err := out.Write(s)
+ if err != nil {
+ return
+ }
+ }
+ return
+}
+
+// lineBreaker breaks data across several lines, all of the same byte length
+// (except possibly the last). Lines are broken with a single '\n'.
+type lineBreaker struct {
+ lineLength int
+ line []byte
+ used int
+ out io.Writer
+ haveWritten bool
+}
+
+func newLineBreaker(out io.Writer, lineLength int) *lineBreaker {
+ return &lineBreaker{
+ lineLength: lineLength,
+ line: make([]byte, lineLength),
+ used: 0,
+ out: out,
+ }
+}
+
+func (l *lineBreaker) Write(b []byte) (n int, err os.Error) {
+ n = len(b)
+
+ if n == 0 {
+ return
+ }
+
+ if l.used == 0 && l.haveWritten {
+ _, err = l.out.Write([]byte{'\n'})
+ if err != nil {
+ return
+ }
+ }
+
+ if l.used+len(b) < l.lineLength {
+ l.used += copy(l.line[l.used:], b)
+ return
+ }
+
+ l.haveWritten = true
+ _, err = l.out.Write(l.line[0:l.used])
+ if err != nil {
+ return
+ }
+ excess := l.lineLength - l.used
+ l.used = 0
+
+ _, err = l.out.Write(b[0:excess])
+ if err != nil {
+ return
+ }
+
+ _, err = l.Write(b[excess:])
+ return
+}
+
+func (l *lineBreaker) Close() (err os.Error) {
+ if l.used > 0 {
+ _, err = l.out.Write(l.line[0:l.used])
+ if err != nil {
+ return
+ }
+ }
+
+ return
+}
+
+// encoding keeps track of a running CRC24 over the data which has been written
+// to it and outputs a OpenPGP checksum when closed, followed by an armor
+// trailer.
+//
+// It's built into a stack of io.Writers:
+// encoding -> base64 encoder -> lineBreaker -> out
+type encoding struct {
+ out io.Writer
+ breaker *lineBreaker
+ b64 io.WriteCloser
+ crc uint32
+ blockType []byte
+}
+
+func (e *encoding) Write(data []byte) (n int, err os.Error) {
+ e.crc = crc24(e.crc, data)
+ return e.b64.Write(data)
+}
+
+func (e *encoding) Close() (err os.Error) {
+ err = e.b64.Close()
+ if err != nil {
+ return
+ }
+
+ var checksumBytes [3]byte
+ checksumBytes[0] = byte(e.crc >> 16)
+ checksumBytes[1] = byte(e.crc >> 8)
+ checksumBytes[2] = byte(e.crc)
+
+ var b64ChecksumBytes [4]byte
+ base64.StdEncoding.Encode(b64ChecksumBytes[:], checksumBytes[:])
+
+ return writeSlices(e.out, blockEnd, b64ChecksumBytes[:], newline, armorEnd, e.blockType, armorEndOfLine)
+}
+
+// Encode returns a WriteCloser which will encode the data written to it in
+// OpenPGP armor.
+func Encode(out io.Writer, blockType string, headers map[string]string) (w io.WriteCloser, err os.Error) {
+ bType := []byte(blockType)
+ err = writeSlices(out, armorStart, bType, armorEndOfLineOut)
+ if err != nil {
+ return
+ }
+
+ for k, v := range headers {
+ err = writeSlices(out, []byte(k), armorHeaderSep, []byte(v), newline)
+ if err != nil {
+ return
+ }
+ }
+
+ if len(headers) > 0 {
+ _, err := out.Write(newline)
+ if err != nil {
+ return
+ }
+ }
+
+ e := &encoding{
+ out: out,
+ breaker: newLineBreaker(out, 64),
+ crc: crc24Init,
+ blockType: bType,
+ }
+ e.b64 = base64.NewEncoder(base64.StdEncoding, e.breaker)
+ return e, nil
+}
diff --git a/src/pkg/crypto/openpgp/error/Makefile b/src/pkg/crypto/openpgp/error/Makefile
new file mode 100644
index 000000000..8c370a089
--- /dev/null
+++ b/src/pkg/crypto/openpgp/error/Makefile
@@ -0,0 +1,11 @@
+# Copyright 2010 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+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
new file mode 100644
index 000000000..2d80ce373
--- /dev/null
+++ b/src/pkg/crypto/openpgp/error/error.go
@@ -0,0 +1,46 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package contains common error types for the OpenPGP packages.
+package error
+
+// A StructuralError is returned when OpenPGP data is found to be syntactically
+// invalid.
+type StructuralError string
+
+func (s StructuralError) String() string {
+ return "OpenPGP data invalid: " + string(s)
+}
+
+// UnsupportedError indicates that, although the OpenPGP data is valid, it
+// makes use of currently unimplemented features.
+type UnsupportedError string
+
+func (s UnsupportedError) String() string {
+ return "OpenPGP feature unsupported: " + string(s)
+}
+
+// InvalidArgumentError indicates that the caller is in error and passed an
+// incorrect value.
+type InvalidArgumentError string
+
+func (i InvalidArgumentError) String() string {
+ return "OpenPGP argument invalid: " + string(i)
+}
+
+// SignatureError indicates that a syntactically valid signature failed to
+// validate.
+type SignatureError string
+
+func (b SignatureError) String() string {
+ return "OpenPGP signature invalid: " + string(b)
+}
+
+type keyIncorrect int
+
+func (ki keyIncorrect) String() string {
+ return "the given key was incorrect"
+}
+
+var KeyIncorrectError = keyIncorrect(0)
diff --git a/src/pkg/crypto/rand/Makefile b/src/pkg/crypto/rand/Makefile
index 0e7a5536c..88b6d71e3 100644
--- a/src/pkg/crypto/rand/Makefile
+++ b/src/pkg/crypto/rand/Makefile
@@ -2,11 +2,25 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=crypto/rand
GOFILES=\
rand.go\
+GOFILES_freebsd=\
+ rand_unix.go\
+
+GOFILES_darwin=\
+ rand_unix.go\
+
+GOFILES_linux=\
+ 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 01c30316b..42d9da0ef 100644
--- a/src/pkg/crypto/rand/rand.go
+++ b/src/pkg/crypto/rand/rand.go
@@ -7,124 +7,15 @@
package rand
import (
- "crypto/aes"
"io"
"os"
- "sync"
- "time"
)
// Reader is a global, shared instance of a cryptographically
// strong pseudo-random generator.
+// On Unix-like systems, Reader reads from /dev/urandom.
+// On Windows systems, Reader uses the CryptGenRandom API.
var Reader io.Reader
// Read is a helper function that calls Reader.Read.
func Read(b []byte) (n int, err os.Error) { return Reader.Read(b) }
-
-// Easy implementation: read from /dev/urandom.
-// This is sufficient on Linux, OS X, and FreeBSD.
-
-func init() { Reader = &devReader{name: "/dev/urandom"} }
-
-// A devReader satisfies reads by reading the file named name.
-type devReader struct {
- name string
- f *os.File
- mu sync.Mutex
-}
-
-func (r *devReader) Read(b []byte) (n int, err os.Error) {
- r.mu.Lock()
- if r.f == nil {
- f, err := os.Open(r.name, os.O_RDONLY, 0)
- if f == nil {
- return 0, err
- }
- r.f = f
- }
- r.mu.Unlock()
- return r.f.Read(b)
-}
-
-// Alternate pseudo-random implementation for use on
-// systems without a reliable /dev/urandom. So far we
-// haven't needed it.
-
-// newReader returns a new pseudorandom generator that
-// seeds itself by reading from entropy. If entropy == nil,
-// the generator seeds itself by reading from the system's
-// random number generator, typically /dev/random.
-// The Read method on the returned reader always returns
-// the full amount asked for, or else it returns an error.
-//
-// The generator uses the X9.31 algorithm with AES-128,
-// reseeding after every 1 MB of generated data.
-func newReader(entropy io.Reader) io.Reader {
- if entropy == nil {
- entropy = &devReader{name: "/dev/random"}
- }
- return &reader{entropy: entropy}
-}
-
-type reader struct {
- mu sync.Mutex
- budget int // number of bytes that can be generated
- cipher *aes.Cipher
- entropy io.Reader
- time, seed, dst, key [aes.BlockSize]byte
-}
-
-func (r *reader) Read(b []byte) (n int, err os.Error) {
- r.mu.Lock()
- defer r.mu.Unlock()
- n = len(b)
-
- for len(b) > 0 {
- if r.budget == 0 {
- _, err := io.ReadFull(r.entropy, r.seed[0:])
- if err != nil {
- return n - len(b), err
- }
- _, err = io.ReadFull(r.entropy, r.key[0:])
- if err != nil {
- return n - len(b), err
- }
- r.cipher, err = aes.NewCipher(r.key[0:])
- if err != nil {
- return n - len(b), err
- }
- r.budget = 1 << 20 // reseed after generating 1MB
- }
- r.budget -= aes.BlockSize
-
- // ANSI X9.31 (== X9.17) algorithm, but using AES in place of 3DES.
- //
- // single block:
- // t = encrypt(time)
- // dst = encrypt(t^seed)
- // seed = encrypt(t^dst)
- ns := time.Nanoseconds()
- r.time[0] = byte(ns >> 56)
- r.time[1] = byte(ns >> 48)
- r.time[2] = byte(ns >> 40)
- r.time[3] = byte(ns >> 32)
- r.time[4] = byte(ns >> 24)
- r.time[5] = byte(ns >> 16)
- r.time[6] = byte(ns >> 8)
- r.time[7] = byte(ns)
- r.cipher.Encrypt(r.time[0:], r.time[0:])
- for i := 0; i < aes.BlockSize; i++ {
- r.dst[i] = r.time[i] ^ r.seed[i]
- }
- r.cipher.Encrypt(r.dst[0:], r.dst[0:])
- for i := 0; i < aes.BlockSize; i++ {
- r.seed[i] = r.time[i] ^ r.dst[i]
- }
- r.cipher.Encrypt(r.seed[0:], r.seed[0:])
-
- m := copy(b, r.dst[0:])
- b = b[m:]
- }
-
- return n, nil
-}
diff --git a/src/pkg/crypto/rand/rand_unix.go b/src/pkg/crypto/rand/rand_unix.go
new file mode 100644
index 000000000..ff16f2554
--- /dev/null
+++ b/src/pkg/crypto/rand/rand_unix.go
@@ -0,0 +1,125 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Unix cryptographically secure pseudorandom number
+// generator.
+
+package rand
+
+import (
+ "crypto/aes"
+ "io"
+ "os"
+ "sync"
+ "time"
+)
+
+// Easy implementation: read from /dev/urandom.
+// This is sufficient on Linux, OS X, and FreeBSD.
+
+func init() { Reader = &devReader{name: "/dev/urandom"} }
+
+// A devReader satisfies reads by reading the file named name.
+type devReader struct {
+ name string
+ f *os.File
+ mu sync.Mutex
+}
+
+func (r *devReader) Read(b []byte) (n int, err os.Error) {
+ r.mu.Lock()
+ if r.f == nil {
+ f, err := os.Open(r.name, os.O_RDONLY, 0)
+ if f == nil {
+ r.mu.Unlock()
+ return 0, err
+ }
+ r.f = f
+ }
+ r.mu.Unlock()
+ return r.f.Read(b)
+}
+
+// Alternate pseudo-random implementation for use on
+// systems without a reliable /dev/urandom. So far we
+// haven't needed it.
+
+// newReader returns a new pseudorandom generator that
+// seeds itself by reading from entropy. If entropy == nil,
+// the generator seeds itself by reading from the system's
+// random number generator, typically /dev/random.
+// The Read method on the returned reader always returns
+// the full amount asked for, or else it returns an error.
+//
+// The generator uses the X9.31 algorithm with AES-128,
+// reseeding after every 1 MB of generated data.
+func newReader(entropy io.Reader) io.Reader {
+ if entropy == nil {
+ entropy = &devReader{name: "/dev/random"}
+ }
+ return &reader{entropy: entropy}
+}
+
+type reader struct {
+ mu sync.Mutex
+ budget int // number of bytes that can be generated
+ cipher *aes.Cipher
+ entropy io.Reader
+ time, seed, dst, key [aes.BlockSize]byte
+}
+
+func (r *reader) Read(b []byte) (n int, err os.Error) {
+ r.mu.Lock()
+ defer r.mu.Unlock()
+ n = len(b)
+
+ for len(b) > 0 {
+ if r.budget == 0 {
+ _, err := io.ReadFull(r.entropy, r.seed[0:])
+ if err != nil {
+ return n - len(b), err
+ }
+ _, err = io.ReadFull(r.entropy, r.key[0:])
+ if err != nil {
+ return n - len(b), err
+ }
+ r.cipher, err = aes.NewCipher(r.key[0:])
+ if err != nil {
+ return n - len(b), err
+ }
+ r.budget = 1 << 20 // reseed after generating 1MB
+ }
+ r.budget -= aes.BlockSize
+
+ // ANSI X9.31 (== X9.17) algorithm, but using AES in place of 3DES.
+ //
+ // single block:
+ // t = encrypt(time)
+ // dst = encrypt(t^seed)
+ // seed = encrypt(t^dst)
+ ns := time.Nanoseconds()
+ r.time[0] = byte(ns >> 56)
+ r.time[1] = byte(ns >> 48)
+ r.time[2] = byte(ns >> 40)
+ r.time[3] = byte(ns >> 32)
+ r.time[4] = byte(ns >> 24)
+ r.time[5] = byte(ns >> 16)
+ r.time[6] = byte(ns >> 8)
+ r.time[7] = byte(ns)
+ r.cipher.Encrypt(r.time[0:], r.time[0:])
+ for i := 0; i < aes.BlockSize; i++ {
+ r.dst[i] = r.time[i] ^ r.seed[i]
+ }
+ r.cipher.Encrypt(r.dst[0:], r.dst[0:])
+ for i := 0; i < aes.BlockSize; i++ {
+ r.seed[i] = r.time[i] ^ r.dst[i]
+ }
+ r.cipher.Encrypt(r.seed[0:], r.seed[0:])
+
+ m := copy(b, r.dst[0:])
+ b = b[m:]
+ }
+
+ return n, nil
+}
diff --git a/src/pkg/crypto/rand/rand_windows.go b/src/pkg/crypto/rand/rand_windows.go
new file mode 100755
index 000000000..4b2b7a26f
--- /dev/null
+++ b/src/pkg/crypto/rand/rand_windows.go
@@ -0,0 +1,43 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Windows cryptographically secure pseudorandom number
+// generator.
+
+package rand
+
+import (
+ "os"
+ "sync"
+ "syscall"
+)
+
+// Implemented by using Windows CryptoAPI 2.0.
+
+func init() { Reader = &rngReader{} }
+
+// A rngReader satisfies reads by reading from the Windows CryptGenRandom API.
+type rngReader struct {
+ prov uint32
+ mu sync.Mutex
+}
+
+func (r *rngReader) Read(b []byte) (n int, err os.Error) {
+ r.mu.Lock()
+ if r.prov == 0 {
+ const provType = syscall.PROV_RSA_FULL
+ const flags = syscall.CRYPT_VERIFYCONTEXT | syscall.CRYPT_SILENT
+ ok, errno := syscall.CryptAcquireContext(&r.prov, nil, nil, provType, flags)
+ if !ok {
+ r.mu.Unlock()
+ return 0, os.NewSyscallError("CryptAcquireContext", errno)
+ }
+ }
+ r.mu.Unlock()
+ ok, errno := syscall.CryptGenRandom(r.prov, uint32(len(b)), &b[0])
+ if !ok {
+ return 0, os.NewSyscallError("CryptGenRandom", errno)
+ }
+ return len(b), nil
+}
diff --git a/src/pkg/crypto/rc4/Makefile b/src/pkg/crypto/rc4/Makefile
index 7827b0817..50a3b7972 100644
--- a/src/pkg/crypto/rc4/Makefile
+++ b/src/pkg/crypto/rc4/Makefile
@@ -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 ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=crypto/rc4
GOFILES=\
diff --git a/src/pkg/crypto/rc4/rc4.go b/src/pkg/crypto/rc4/rc4.go
index e47a01513..65fd195f3 100644
--- a/src/pkg/crypto/rc4/rc4.go
+++ b/src/pkg/crypto/rc4/rc4.go
@@ -45,14 +45,14 @@ func NewCipher(key []byte) (*Cipher, os.Error) {
return &c, nil
}
-// XORKeyStream will XOR each byte of the given buffer with a byte of the
-// generated keystream.
-func (c *Cipher) XORKeyStream(buf []byte) {
- for i := range buf {
+// XORKeyStream sets dst to the result of XORing src with the key stream.
+// Dst and src may be the same slice but otherwise should not overlap.
+func (c *Cipher) XORKeyStream(dst, src []byte) {
+ for i := range src {
c.i += 1
c.j += c.s[c.i]
c.s[c.i], c.s[c.j] = c.s[c.j], c.s[c.i]
- buf[i] ^= c.s[c.s[c.i]+c.s[c.j]]
+ dst[i] = src[i] ^ c.s[c.s[c.i]+c.s[c.j]]
}
}
diff --git a/src/pkg/crypto/rc4/rc4_test.go b/src/pkg/crypto/rc4/rc4_test.go
index 1d39b2f17..6265d9408 100644
--- a/src/pkg/crypto/rc4/rc4_test.go
+++ b/src/pkg/crypto/rc4/rc4_test.go
@@ -15,25 +15,25 @@ type rc4Test struct {
var golden = []rc4Test{
// Test vectors from the original cypherpunk posting of ARC4:
// http://groups.google.com/group/sci.crypt/msg/10a300c9d21afca0?pli=1
- rc4Test{
+ {
[]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},
[]byte{0x74, 0x94, 0xc2, 0xe7, 0x10, 0x4b, 0x08, 0x79},
},
- rc4Test{
+ {
[]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
[]byte{0xde, 0x18, 0x89, 0x41, 0xa3, 0x37, 0x5d, 0x3a},
},
- rc4Test{
+ {
[]byte{0xef, 0x01, 0x23, 0x45},
[]byte{0xd6, 0xa1, 0x41, 0xa7, 0xec, 0x3c, 0x38, 0xdf, 0xbd, 0x61},
},
// Test vectors from the Wikipedia page: http://en.wikipedia.org/wiki/RC4
- rc4Test{
+ {
[]byte{0x4b, 0x65, 0x79},
[]byte{0xeb, 0x9f, 0x77, 0x81, 0xb7, 0x34, 0xca, 0x72, 0xa7, 0x19},
},
- rc4Test{
+ {
[]byte{0x57, 0x69, 0x6b, 0x69},
[]byte{0x60, 0x44, 0xdb, 0x6d, 0x41, 0xb7},
},
@@ -48,7 +48,7 @@ func TestGolden(t *testing.T) {
return
}
keystream := make([]byte, len(g.keystream))
- c.XORKeyStream(keystream)
+ c.XORKeyStream(keystream, keystream)
for j, v := range keystream {
if g.keystream[j] != v {
t.Errorf("Failed at golden index %d", i)
diff --git a/src/pkg/crypto/ripemd160/Makefile b/src/pkg/crypto/ripemd160/Makefile
index 109e68eda..7e529457d 100644
--- a/src/pkg/crypto/ripemd160/Makefile
+++ b/src/pkg/crypto/ripemd160/Makefile
@@ -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 ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=crypto/ripemd160
GOFILES=\
diff --git a/src/pkg/crypto/ripemd160/ripemd160.go b/src/pkg/crypto/ripemd160/ripemd160.go
index 5d5519842..5614f1360 100644
--- a/src/pkg/crypto/ripemd160/ripemd160.go
+++ b/src/pkg/crypto/ripemd160/ripemd160.go
@@ -72,10 +72,7 @@ func (d *digest) Write(p []byte) (nn int, err os.Error) {
n := _Block(d, p)
p = p[n:]
if len(p) > 0 {
- for i, x := range p {
- d.x[i] = x
- }
- d.nx = len(p)
+ d.nx = copy(d.x[:], p)
}
return
}
diff --git a/src/pkg/crypto/ripemd160/ripemd160_test.go b/src/pkg/crypto/ripemd160/ripemd160_test.go
index eaa3d78c2..f4135f5cf 100644
--- a/src/pkg/crypto/ripemd160/ripemd160_test.go
+++ b/src/pkg/crypto/ripemd160/ripemd160_test.go
@@ -19,14 +19,14 @@ type mdTest struct {
}
var vectors = [...]mdTest{
- mdTest{"9c1185a5c5e9fc54612808977ee8f548b2258d31", ""},
- mdTest{"0bdc9d2d256b3ee9daae347be6f4dc835a467ffe", "a"},
- mdTest{"8eb208f7e05d987a9b044a8e98c6b087f15a0bfc", "abc"},
- mdTest{"5d0689ef49d2fae572b881b123a85ffa21595f36", "message digest"},
- mdTest{"f71c27109c692c1b56bbdceb5b9d2865b3708dbc", "abcdefghijklmnopqrstuvwxyz"},
- mdTest{"12a053384a9c0c88e405a06c27dcf49ada62eb2b", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"},
- mdTest{"b0e20b6e3116640286ed3a87a5713079b21f5189", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"},
- mdTest{"9b752e45573d4b39f4dbd3323cab82bf63326bfb", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"},
+ {"9c1185a5c5e9fc54612808977ee8f548b2258d31", ""},
+ {"0bdc9d2d256b3ee9daae347be6f4dc835a467ffe", "a"},
+ {"8eb208f7e05d987a9b044a8e98c6b087f15a0bfc", "abc"},
+ {"5d0689ef49d2fae572b881b123a85ffa21595f36", "message digest"},
+ {"f71c27109c692c1b56bbdceb5b9d2865b3708dbc", "abcdefghijklmnopqrstuvwxyz"},
+ {"12a053384a9c0c88e405a06c27dcf49ada62eb2b", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"},
+ {"b0e20b6e3116640286ed3a87a5713079b21f5189", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"},
+ {"9b752e45573d4b39f4dbd3323cab82bf63326bfb", "12345678901234567890123456789012345678901234567890123456789012345678901234567890"},
}
func TestVectors(t *testing.T) {
diff --git a/src/pkg/crypto/rsa/Makefile b/src/pkg/crypto/rsa/Makefile
index e4d81bc52..ff26ca6f2 100644
--- a/src/pkg/crypto/rsa/Makefile
+++ b/src/pkg/crypto/rsa/Makefile
@@ -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 ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=crypto/rsa
GOFILES=\
diff --git a/src/pkg/crypto/rsa/pkcs1v15.go b/src/pkg/crypto/rsa/pkcs1v15.go
index 5fd25d58c..714046250 100644
--- a/src/pkg/crypto/rsa/pkcs1v15.go
+++ b/src/pkg/crypto/rsa/pkcs1v15.go
@@ -130,6 +130,9 @@ func nonZeroRandomBytes(s []byte, rand io.Reader) (err os.Error) {
if err != nil {
return
}
+ // In tests, the PRNG may return all zeros so we do
+ // this to break the loop.
+ s[i] ^= 0x42
}
}
@@ -146,6 +149,7 @@ const (
HashSHA256
HashSHA384
HashSHA512
+ HashMD5SHA1 // combined MD5 and SHA1 hash used for RSA signing in TLS.
)
// These are ASN1 DER structures:
@@ -153,20 +157,22 @@ const (
// digestAlgorithm AlgorithmIdentifier,
// digest OCTET STRING
// }
-// For performance, we don't use the generic ASN1 encoding. Rather, we
+// For performance, we don't use the generic ASN1 encoder. Rather, we
// precompute a prefix of the digest value that makes a valid ASN1 DER string
// with the correct contents.
var hashPrefixes = [][]byte{
// HashMD5
- []byte{0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10},
+ {0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10},
// HashSHA1
- []byte{0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14},
+ {0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14},
// HashSHA256
- []byte{0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20},
+ {0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20},
// HashSHA384
- []byte{0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30},
+ {0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30},
// HashSHA512
- []byte{0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40},
+ {0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40},
+ // HashMD5SHA1
+ {}, // A special TLS case which doesn't use an ASN1 prefix.
}
// SignPKCS1v15 calcuates the signature of hashed using RSASSA-PSS-SIGN from RSA PKCS#1 v1.5.
@@ -252,6 +258,8 @@ func pkcs1v15HashInfo(hash PKCS1v15Hash, inLen int) (hashLen int, prefix []byte,
hashLen = 48
case HashSHA512:
hashLen = 64
+ case HashMD5SHA1:
+ hashLen = 36
default:
return 0, nil, os.ErrorString("unknown hash function")
}
diff --git a/src/pkg/crypto/rsa/pkcs1v15_test.go b/src/pkg/crypto/rsa/pkcs1v15_test.go
index bfc12be28..bf6306dc2 100644
--- a/src/pkg/crypto/rsa/pkcs1v15_test.go
+++ b/src/pkg/crypto/rsa/pkcs1v15_test.go
@@ -7,10 +7,10 @@ package rsa
import (
"big"
"bytes"
+ "crypto/rand"
"crypto/sha1"
"encoding/base64"
"encoding/hex"
- "os"
"io"
"testing"
"testing/quick"
@@ -31,19 +31,19 @@ type DecryptPKCS1v15Test struct {
// These test vectors were generated with `openssl rsautl -pkcs -encrypt`
var decryptPKCS1v15Tests = []DecryptPKCS1v15Test{
- DecryptPKCS1v15Test{
+ {
"gIcUIoVkD6ATMBk/u/nlCZCCWRKdkfjCgFdo35VpRXLduiKXhNz1XupLLzTXAybEq15juc+EgY5o0DHv/nt3yg==",
"x",
},
- DecryptPKCS1v15Test{
+ {
"Y7TOCSqofGhkRb+jaVRLzK8xw2cSo1IVES19utzv6hwvx+M8kFsoWQm5DzBeJCZTCVDPkTpavUuEbgp8hnUGDw==",
"testing.",
},
- DecryptPKCS1v15Test{
+ {
"arReP9DJtEVyV2Dg3dDp4c/PSk1O6lxkoJ8HcFupoRorBZG+7+1fDAwT1olNddFnQMjmkb8vxwmNMoTAT/BFjQ==",
"testing.\n",
},
- DecryptPKCS1v15Test{
+ {
"WtaBXIoGC54+vH0NH0CHHE+dRDOsMc/6BrfFu2lEqcKL9+uDuWaf+Xj9mrbQCjjZcpQuX733zyok/jsnqe/Ftw==",
"01234567890123456789012345678901234567890123456789012",
},
@@ -63,10 +63,7 @@ func TestDecryptPKCS1v15(t *testing.T) {
}
func TestEncryptPKCS1v15(t *testing.T) {
- urandom, err := os.Open("/dev/urandom", os.O_RDONLY, 0)
- if err != nil {
- t.Errorf("Failed to open /dev/urandom")
- }
+ random := rand.Reader
k := (rsaPrivateKey.N.BitLen() + 7) / 8
tryEncryptDecrypt := func(in []byte, blind bool) bool {
@@ -74,7 +71,7 @@ func TestEncryptPKCS1v15(t *testing.T) {
in = in[0 : k-11]
}
- ciphertext, err := EncryptPKCS1v15(urandom, &rsaPrivateKey.PublicKey, in)
+ ciphertext, err := EncryptPKCS1v15(random, &rsaPrivateKey.PublicKey, in)
if err != nil {
t.Errorf("error encrypting: %s", err)
return false
@@ -84,7 +81,7 @@ func TestEncryptPKCS1v15(t *testing.T) {
if !blind {
rand = nil
} else {
- rand = urandom
+ rand = random
}
plaintext, err := DecryptPKCS1v15(rand, rsaPrivateKey, ciphertext)
if err != nil {
@@ -104,19 +101,19 @@ func TestEncryptPKCS1v15(t *testing.T) {
// These test vectors were generated with `openssl rsautl -pkcs -encrypt`
var decryptPKCS1v15SessionKeyTests = []DecryptPKCS1v15Test{
- DecryptPKCS1v15Test{
+ {
"e6ukkae6Gykq0fKzYwULpZehX+UPXYzMoB5mHQUDEiclRbOTqas4Y0E6nwns1BBpdvEJcilhl5zsox/6DtGsYg==",
"1234",
},
- DecryptPKCS1v15Test{
+ {
"Dtis4uk/q/LQGGqGk97P59K03hkCIVFMEFZRgVWOAAhxgYpCRG0MX2adptt92l67IqMki6iVQyyt0TtX3IdtEw==",
"FAIL",
},
- DecryptPKCS1v15Test{
+ {
"LIyFyCYCptPxrvTxpol8F3M7ZivlMsf53zs0vHRAv+rDIh2YsHS69ePMoPMe3TkOMZ3NupiL3takPxIs1sK+dw==",
"abcd",
},
- DecryptPKCS1v15Test{
+ {
"bafnobel46bKy76JzqU/RIVOH0uAYvzUtauKmIidKgM0sMlvobYVAVQPeUQ/oTGjbIZ1v/6Gyi5AO4DtHruGdw==",
"FAIL",
},
@@ -137,13 +134,10 @@ func TestEncryptPKCS1v15SessionKey(t *testing.T) {
}
func TestNonZeroRandomBytes(t *testing.T) {
- urandom, err := os.Open("/dev/urandom", os.O_RDONLY, 0)
- if err != nil {
- t.Errorf("Failed to open /dev/urandom")
- }
+ random := rand.Reader
b := make([]byte, 512)
- err = nonZeroRandomBytes(b, urandom)
+ err := nonZeroRandomBytes(b, random)
if err != nil {
t.Errorf("returned error: %s", err)
}
@@ -162,7 +156,7 @@ type signPKCS1v15Test struct {
// These vectors have been tested with
// `openssl rsautl -verify -inkey pk -in signature | hexdump -C`
var signPKCS1v15Tests = []signPKCS1v15Test{
- signPKCS1v15Test{"Test.\n", "a4f3fa6ea93bcdd0c57be020c1193ecbfd6f200a3d95c409769b029578fa0e336ad9a347600e40d3ae823b8c7e6bad88cc07c1d54c3a1523cbbb6d58efc362ae"},
+ {"Test.\n", "a4f3fa6ea93bcdd0c57be020c1193ecbfd6f200a3d95c409769b029578fa0e336ad9a347600e40d3ae823b8c7e6bad88cc07c1d54c3a1523cbbb6d58efc362ae"},
}
func TestSignPKCS1v15(t *testing.T) {
diff --git a/src/pkg/crypto/rsa/rsa_test.go b/src/pkg/crypto/rsa/rsa_test.go
index 172173900..df1f17f17 100644
--- a/src/pkg/crypto/rsa/rsa_test.go
+++ b/src/pkg/crypto/rsa/rsa_test.go
@@ -7,18 +7,15 @@ package rsa
import (
"big"
"bytes"
+ "crypto/rand"
"crypto/sha1"
- "os"
"testing"
)
func TestKeyGeneration(t *testing.T) {
- urandom, err := os.Open("/dev/urandom", os.O_RDONLY, 0)
- if err != nil {
- t.Errorf("failed to open /dev/urandom")
- }
+ random := rand.Reader
- priv, err := GenerateKey(urandom, 1024)
+ priv, err := GenerateKey(random, 1024)
if err != nil {
t.Errorf("failed to generate key")
}
@@ -33,7 +30,7 @@ func TestKeyGeneration(t *testing.T) {
t.Errorf("got:%v, want:%v (%s)", m2, m, priv)
}
- m3, err := decrypt(urandom, priv, c)
+ m3, err := decrypt(random, priv, c)
if err != nil {
t.Errorf("error while decrypting (blind): %s", err)
}
@@ -76,10 +73,7 @@ func TestEncryptOAEP(t *testing.T) {
}
func TestDecryptOAEP(t *testing.T) {
- urandom, err := os.Open("/dev/urandom", os.O_RDONLY, 0)
- if err != nil {
- t.Errorf("Failed to open /dev/urandom")
- }
+ random := rand.Reader
sha1 := sha1.New()
n := new(big.Int)
@@ -98,7 +92,7 @@ func TestDecryptOAEP(t *testing.T) {
}
// Decrypt with blinding.
- out, err = DecryptOAEP(sha1, urandom, &private, message.out, nil)
+ out, err = DecryptOAEP(sha1, random, &private, message.out, nil)
if err != nil {
t.Errorf("#%d,%d (blind) error: %s", i, j, err)
} else if bytes.Compare(out, message.in) != 0 {
@@ -111,12 +105,12 @@ func TestDecryptOAEP(t *testing.T) {
// testEncryptOAEPData contains a subset of the vectors from RSA's "Test vectors for RSA-OAEP".
var testEncryptOAEPData = []testEncryptOAEPStruct{
// Key 1
- testEncryptOAEPStruct{"a8b3b284af8eb50b387034a860f146c4919f318763cd6c5598c8ae4811a1e0abc4c7e0b082d693a5e7fced675cf4668512772c0cbc64a742c6c630f533c8cc72f62ae833c40bf25842e984bb78bdbf97c0107d55bdb662f5c4e0fab9845cb5148ef7392dd3aaff93ae1e6b667bb3d4247616d4f5ba10d4cfd226de88d39f16fb",
+ {"a8b3b284af8eb50b387034a860f146c4919f318763cd6c5598c8ae4811a1e0abc4c7e0b082d693a5e7fced675cf4668512772c0cbc64a742c6c630f533c8cc72f62ae833c40bf25842e984bb78bdbf97c0107d55bdb662f5c4e0fab9845cb5148ef7392dd3aaff93ae1e6b667bb3d4247616d4f5ba10d4cfd226de88d39f16fb",
65537,
"53339cfdb79fc8466a655c7316aca85c55fd8f6dd898fdaf119517ef4f52e8fd8e258df93fee180fa0e4ab29693cd83b152a553d4ac4d1812b8b9fa5af0e7f55fe7304df41570926f3311f15c4d65a732c483116ee3d3d2d0af3549ad9bf7cbfb78ad884f84d5beb04724dc7369b31def37d0cf539e9cfcdd3de653729ead5d1",
[]testEncryptOAEPMessage{
// Example 1.1
- testEncryptOAEPMessage{
+ {
[]byte{0x66, 0x28, 0x19, 0x4e, 0x12, 0x07, 0x3d, 0xb0,
0x3b, 0xa9, 0x4c, 0xda, 0x9e, 0xf9, 0x53, 0x23, 0x97,
0xd5, 0x0d, 0xba, 0x79, 0xb9, 0x87, 0x00, 0x4a, 0xfe,
@@ -144,7 +138,7 @@ var testEncryptOAEPData = []testEncryptOAEPStruct{
},
},
// Example 1.2
- testEncryptOAEPMessage{
+ {
[]byte{0x75, 0x0c, 0x40, 0x47, 0xf5, 0x47, 0xe8, 0xe4,
0x14, 0x11, 0x85, 0x65, 0x23, 0x29, 0x8a, 0xc9, 0xba,
0xe2, 0x45, 0xef, 0xaf, 0x13, 0x97, 0xfb, 0xe5, 0x6f,
@@ -172,7 +166,7 @@ var testEncryptOAEPData = []testEncryptOAEPStruct{
},
},
// Example 1.3
- testEncryptOAEPMessage{
+ {
[]byte{0xd9, 0x4a, 0xe0, 0x83, 0x2e, 0x64, 0x45, 0xce,
0x42, 0x33, 0x1c, 0xb0, 0x6d, 0x53, 0x1a, 0x82, 0xb1,
0xdb, 0x4b, 0xaa, 0xd3, 0x0f, 0x74, 0x6d, 0xc9, 0x16,
@@ -205,12 +199,12 @@ var testEncryptOAEPData = []testEncryptOAEPStruct{
},
},
// Key 10
- testEncryptOAEPStruct{"ae45ed5601cec6b8cc05f803935c674ddbe0d75c4c09fd7951fc6b0caec313a8df39970c518bffba5ed68f3f0d7f22a4029d413f1ae07e4ebe9e4177ce23e7f5404b569e4ee1bdcf3c1fb03ef113802d4f855eb9b5134b5a7c8085adcae6fa2fa1417ec3763be171b0c62b760ede23c12ad92b980884c641f5a8fac26bdad4a03381a22fe1b754885094c82506d4019a535a286afeb271bb9ba592de18dcf600c2aeeae56e02f7cf79fc14cf3bdc7cd84febbbf950ca90304b2219a7aa063aefa2c3c1980e560cd64afe779585b6107657b957857efde6010988ab7de417fc88d8f384c4e6e72c3f943e0c31c0c4a5cc36f879d8a3ac9d7d59860eaada6b83bb",
+ {"ae45ed5601cec6b8cc05f803935c674ddbe0d75c4c09fd7951fc6b0caec313a8df39970c518bffba5ed68f3f0d7f22a4029d413f1ae07e4ebe9e4177ce23e7f5404b569e4ee1bdcf3c1fb03ef113802d4f855eb9b5134b5a7c8085adcae6fa2fa1417ec3763be171b0c62b760ede23c12ad92b980884c641f5a8fac26bdad4a03381a22fe1b754885094c82506d4019a535a286afeb271bb9ba592de18dcf600c2aeeae56e02f7cf79fc14cf3bdc7cd84febbbf950ca90304b2219a7aa063aefa2c3c1980e560cd64afe779585b6107657b957857efde6010988ab7de417fc88d8f384c4e6e72c3f943e0c31c0c4a5cc36f879d8a3ac9d7d59860eaada6b83bb",
65537,
"056b04216fe5f354ac77250a4b6b0c8525a85c59b0bd80c56450a22d5f438e596a333aa875e291dd43f48cb88b9d5fc0d499f9fcd1c397f9afc070cd9e398c8d19e61db7c7410a6b2675dfbf5d345b804d201add502d5ce2dfcb091ce9997bbebe57306f383e4d588103f036f7e85d1934d152a323e4a8db451d6f4a5b1b0f102cc150e02feee2b88dea4ad4c1baccb24d84072d14e1d24a6771f7408ee30564fb86d4393a34bcf0b788501d193303f13a2284b001f0f649eaf79328d4ac5c430ab4414920a9460ed1b7bc40ec653e876d09abc509ae45b525190116a0c26101848298509c1c3bf3a483e7274054e15e97075036e989f60932807b5257751e79",
[]testEncryptOAEPMessage{
// Example 10.1
- testEncryptOAEPMessage{
+ {
[]byte{0x8b, 0xba, 0x6b, 0xf8, 0x2a, 0x6c, 0x0f, 0x86,
0xd5, 0xf1, 0x75, 0x6e, 0x97, 0x95, 0x68, 0x70, 0xb0,
0x89, 0x53, 0xb0, 0x6b, 0x4e, 0xb2, 0x05, 0xbc, 0x16,
diff --git a/src/pkg/crypto/sha1/Makefile b/src/pkg/crypto/sha1/Makefile
index f3422dd84..81ac38c0b 100644
--- a/src/pkg/crypto/sha1/Makefile
+++ b/src/pkg/crypto/sha1/Makefile
@@ -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 ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=crypto/sha1
GOFILES=\
diff --git a/src/pkg/crypto/sha1/sha1.go b/src/pkg/crypto/sha1/sha1.go
index 681870a21..8716c3591 100644
--- a/src/pkg/crypto/sha1/sha1.go
+++ b/src/pkg/crypto/sha1/sha1.go
@@ -70,10 +70,7 @@ func (d *digest) Write(p []byte) (nn int, err os.Error) {
n := _Block(d, p)
p = p[n:]
if len(p) > 0 {
- for i, x := range p {
- d.x[i] = x
- }
- d.nx = len(p)
+ d.nx = copy(d.x[:], p)
}
return
}
diff --git a/src/pkg/crypto/sha1/sha1_test.go b/src/pkg/crypto/sha1/sha1_test.go
index f18c7b096..2712fe35e 100644
--- a/src/pkg/crypto/sha1/sha1_test.go
+++ b/src/pkg/crypto/sha1/sha1_test.go
@@ -18,37 +18,37 @@ type sha1Test struct {
}
var golden = []sha1Test{
- sha1Test{"da39a3ee5e6b4b0d3255bfef95601890afd80709", ""},
- sha1Test{"86f7e437faa5a7fce15d1ddcb9eaeaea377667b8", "a"},
- sha1Test{"da23614e02469a0d7c7bd1bdab5c9c474b1904dc", "ab"},
- sha1Test{"a9993e364706816aba3e25717850c26c9cd0d89d", "abc"},
- sha1Test{"81fe8bfe87576c3ecb22426f8e57847382917acf", "abcd"},
- sha1Test{"03de6c570bfe24bfc328ccd7ca46b76eadaf4334", "abcde"},
- sha1Test{"1f8ac10f23c5b5bc1167bda84b833e5c057a77d2", "abcdef"},
- sha1Test{"2fb5e13419fc89246865e7a324f476ec624e8740", "abcdefg"},
- sha1Test{"425af12a0743502b322e93a015bcf868e324d56a", "abcdefgh"},
- sha1Test{"c63b19f1e4c8b5f76b25c49b8b87f57d8e4872a1", "abcdefghi"},
- sha1Test{"d68c19a0a345b7eab78d5e11e991c026ec60db63", "abcdefghij"},
- sha1Test{"ebf81ddcbe5bf13aaabdc4d65354fdf2044f38a7", "Discard medicine more than two years old."},
- sha1Test{"e5dea09392dd886ca63531aaa00571dc07554bb6", "He who has a shady past knows that nice guys finish last."},
- sha1Test{"45988f7234467b94e3e9494434c96ee3609d8f8f", "I wouldn't marry him with a ten foot pole."},
- sha1Test{"55dee037eb7460d5a692d1ce11330b260e40c988", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
- sha1Test{"b7bc5fb91080c7de6b582ea281f8a396d7c0aee8", "The days of the digital watch are numbered. -Tom Stoppard"},
- sha1Test{"c3aed9358f7c77f523afe86135f06b95b3999797", "Nepal premier won't resign."},
- sha1Test{"6e29d302bf6e3a5e4305ff318d983197d6906bb9", "For every action there is an equal and opposite government program."},
- sha1Test{"597f6a540010f94c15d71806a99a2c8710e747bd", "His money is twice tainted: 'taint yours and 'taint mine."},
- sha1Test{"6859733b2590a8a091cecf50086febc5ceef1e80", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
- sha1Test{"514b2630ec089b8aee18795fc0cf1f4860cdacad", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
- sha1Test{"c5ca0d4a7b6676fc7aa72caa41cc3d5df567ed69", "size: a.out: bad magic"},
- sha1Test{"74c51fa9a04eadc8c1bbeaa7fc442f834b90a00a", "The major problem is with sendmail. -Mark Horton"},
- sha1Test{"0b4c4ce5f52c3ad2821852a8dc00217fa18b8b66", "Give me a rock, paper and scissors and I will move the world. CCFestoon"},
- sha1Test{"3ae7937dd790315beb0f48330e8642237c61550a", "If the enemy is within range, then so are you."},
- sha1Test{"410a2b296df92b9a47412b13281df8f830a9f44b", "It's well we cannot hear the screams/That we create in others' dreams."},
- sha1Test{"841e7c85ca1adcddbdd0187f1289acb5c642f7f5", "You remind me of a TV show, but that's all right: I watch it anyway."},
- sha1Test{"163173b825d03b952601376b25212df66763e1db", "C is as portable as Stonehedge!!"},
- sha1Test{"32b0377f2687eb88e22106f133c586ab314d5279", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
- sha1Test{"0885aaf99b569542fd165fa44e322718f4a984e0", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"},
- sha1Test{"6627d6904d71420b0bf3886ab629623538689f45", "How can you write a big system without C++? -Paul Glick"},
+ {"da39a3ee5e6b4b0d3255bfef95601890afd80709", ""},
+ {"86f7e437faa5a7fce15d1ddcb9eaeaea377667b8", "a"},
+ {"da23614e02469a0d7c7bd1bdab5c9c474b1904dc", "ab"},
+ {"a9993e364706816aba3e25717850c26c9cd0d89d", "abc"},
+ {"81fe8bfe87576c3ecb22426f8e57847382917acf", "abcd"},
+ {"03de6c570bfe24bfc328ccd7ca46b76eadaf4334", "abcde"},
+ {"1f8ac10f23c5b5bc1167bda84b833e5c057a77d2", "abcdef"},
+ {"2fb5e13419fc89246865e7a324f476ec624e8740", "abcdefg"},
+ {"425af12a0743502b322e93a015bcf868e324d56a", "abcdefgh"},
+ {"c63b19f1e4c8b5f76b25c49b8b87f57d8e4872a1", "abcdefghi"},
+ {"d68c19a0a345b7eab78d5e11e991c026ec60db63", "abcdefghij"},
+ {"ebf81ddcbe5bf13aaabdc4d65354fdf2044f38a7", "Discard medicine more than two years old."},
+ {"e5dea09392dd886ca63531aaa00571dc07554bb6", "He who has a shady past knows that nice guys finish last."},
+ {"45988f7234467b94e3e9494434c96ee3609d8f8f", "I wouldn't marry him with a ten foot pole."},
+ {"55dee037eb7460d5a692d1ce11330b260e40c988", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
+ {"b7bc5fb91080c7de6b582ea281f8a396d7c0aee8", "The days of the digital watch are numbered. -Tom Stoppard"},
+ {"c3aed9358f7c77f523afe86135f06b95b3999797", "Nepal premier won't resign."},
+ {"6e29d302bf6e3a5e4305ff318d983197d6906bb9", "For every action there is an equal and opposite government program."},
+ {"597f6a540010f94c15d71806a99a2c8710e747bd", "His money is twice tainted: 'taint yours and 'taint mine."},
+ {"6859733b2590a8a091cecf50086febc5ceef1e80", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
+ {"514b2630ec089b8aee18795fc0cf1f4860cdacad", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
+ {"c5ca0d4a7b6676fc7aa72caa41cc3d5df567ed69", "size: a.out: bad magic"},
+ {"74c51fa9a04eadc8c1bbeaa7fc442f834b90a00a", "The major problem is with sendmail. -Mark Horton"},
+ {"0b4c4ce5f52c3ad2821852a8dc00217fa18b8b66", "Give me a rock, paper and scissors and I will move the world. CCFestoon"},
+ {"3ae7937dd790315beb0f48330e8642237c61550a", "If the enemy is within range, then so are you."},
+ {"410a2b296df92b9a47412b13281df8f830a9f44b", "It's well we cannot hear the screams/That we create in others' dreams."},
+ {"841e7c85ca1adcddbdd0187f1289acb5c642f7f5", "You remind me of a TV show, but that's all right: I watch it anyway."},
+ {"163173b825d03b952601376b25212df66763e1db", "C is as portable as Stonehedge!!"},
+ {"32b0377f2687eb88e22106f133c586ab314d5279", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
+ {"0885aaf99b569542fd165fa44e322718f4a984e0", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"},
+ {"6627d6904d71420b0bf3886ab629623538689f45", "How can you write a big system without C++? -Paul Glick"},
}
func TestGolden(t *testing.T) {
diff --git a/src/pkg/crypto/sha256/Makefile b/src/pkg/crypto/sha256/Makefile
index 9efbc4792..97fe4d8e6 100644
--- a/src/pkg/crypto/sha256/Makefile
+++ b/src/pkg/crypto/sha256/Makefile
@@ -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 ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=crypto/sha256
GOFILES=\
diff --git a/src/pkg/crypto/sha256/sha256.go b/src/pkg/crypto/sha256/sha256.go
index df00a7298..57a8ffa0d 100644
--- a/src/pkg/crypto/sha256/sha256.go
+++ b/src/pkg/crypto/sha256/sha256.go
@@ -112,10 +112,7 @@ func (d *digest) Write(p []byte) (nn int, err os.Error) {
n := _Block(d, p)
p = p[n:]
if len(p) > 0 {
- for i, x := range p {
- d.x[i] = x
- }
- d.nx = len(p)
+ d.nx = copy(d.x[:], p)
}
return
}
diff --git a/src/pkg/crypto/sha256/sha256_test.go b/src/pkg/crypto/sha256/sha256_test.go
index d9b294487..42a3fa7a0 100644
--- a/src/pkg/crypto/sha256/sha256_test.go
+++ b/src/pkg/crypto/sha256/sha256_test.go
@@ -18,71 +18,71 @@ type sha256Test struct {
}
var golden = []sha256Test{
- sha256Test{"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", ""},
- sha256Test{"ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb", "a"},
- sha256Test{"fb8e20fc2e4c3f248c60c39bd652f3c1347298bb977b8b4d5903b85055620603", "ab"},
- sha256Test{"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", "abc"},
- sha256Test{"88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589", "abcd"},
- sha256Test{"36bbe50ed96841d10443bcb670d6554f0a34b761be67ec9c4a8ad2c0c44ca42c", "abcde"},
- sha256Test{"bef57ec7f53a6d40beb640a780a639c83bc29ac8a9816f1fc6c5c6dcd93c4721", "abcdef"},
- sha256Test{"7d1a54127b222502f5b79b5fb0803061152a44f92b37e23c6527baf665d4da9a", "abcdefg"},
- sha256Test{"9c56cc51b374c3ba189210d5b6d4bf57790d351c96c47c02190ecf1e430635ab", "abcdefgh"},
- sha256Test{"19cc02f26df43cc571bc9ed7b0c4d29224a3ec229529221725ef76d021c8326f", "abcdefghi"},
- sha256Test{"72399361da6a7754fec986dca5b7cbaf1c810a28ded4abaf56b2106d06cb78b0", "abcdefghij"},
- sha256Test{"a144061c271f152da4d151034508fed1c138b8c976339de229c3bb6d4bbb4fce", "Discard medicine more than two years old."},
- sha256Test{"6dae5caa713a10ad04b46028bf6dad68837c581616a1589a265a11288d4bb5c4", "He who has a shady past knows that nice guys finish last."},
- sha256Test{"ae7a702a9509039ddbf29f0765e70d0001177914b86459284dab8b348c2dce3f", "I wouldn't marry him with a ten foot pole."},
- sha256Test{"6748450b01c568586715291dfa3ee018da07d36bb7ea6f180c1af6270215c64f", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
- sha256Test{"14b82014ad2b11f661b5ae6a99b75105c2ffac278cd071cd6c05832793635774", "The days of the digital watch are numbered. -Tom Stoppard"},
- sha256Test{"7102cfd76e2e324889eece5d6c41921b1e142a4ac5a2692be78803097f6a48d8", "Nepal premier won't resign."},
- sha256Test{"23b1018cd81db1d67983c5f7417c44da9deb582459e378d7a068552ea649dc9f", "For every action there is an equal and opposite government program."},
- sha256Test{"8001f190dfb527261c4cfcab70c98e8097a7a1922129bc4096950e57c7999a5a", "His money is twice tainted: 'taint yours and 'taint mine."},
- sha256Test{"8c87deb65505c3993eb24b7a150c4155e82eee6960cf0c3a8114ff736d69cad5", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
- sha256Test{"bfb0a67a19cdec3646498b2e0f751bddc41bba4b7f30081b0b932aad214d16d7", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
- sha256Test{"7f9a0b9bf56332e19f5a0ec1ad9c1425a153da1c624868fda44561d6b74daf36", "size: a.out: bad magic"},
- sha256Test{"b13f81b8aad9e3666879af19886140904f7f429ef083286195982a7588858cfc", "The major problem is with sendmail. -Mark Horton"},
- sha256Test{"b26c38d61519e894480c70c8374ea35aa0ad05b2ae3d6674eec5f52a69305ed4", "Give me a rock, paper and scissors and I will move the world. CCFestoon"},
- sha256Test{"049d5e26d4f10222cd841a119e38bd8d2e0d1129728688449575d4ff42b842c1", "If the enemy is within range, then so are you."},
- sha256Test{"0e116838e3cc1c1a14cd045397e29b4d087aa11b0853fc69ec82e90330d60949", "It's well we cannot hear the screams/That we create in others' dreams."},
- sha256Test{"4f7d8eb5bcf11de2a56b971021a444aa4eafd6ecd0f307b5109e4e776cd0fe46", "You remind me of a TV show, but that's all right: I watch it anyway."},
- sha256Test{"61c0cc4c4bd8406d5120b3fb4ebc31ce87667c162f29468b3c779675a85aebce", "C is as portable as Stonehedge!!"},
- sha256Test{"1fb2eb3688093c4a3f80cd87a5547e2ce940a4f923243a79a2a1e242220693ac", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
- sha256Test{"395585ce30617b62c80b93e8208ce866d4edc811a177fdb4b82d3911d8696423", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"},
- sha256Test{"4f9b189a13d030838269dce846b16a1ce9ce81fe63e65de2f636863336a98fe6", "How can you write a big system without C++? -Paul Glick"},
+ {"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", ""},
+ {"ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb", "a"},
+ {"fb8e20fc2e4c3f248c60c39bd652f3c1347298bb977b8b4d5903b85055620603", "ab"},
+ {"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", "abc"},
+ {"88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589", "abcd"},
+ {"36bbe50ed96841d10443bcb670d6554f0a34b761be67ec9c4a8ad2c0c44ca42c", "abcde"},
+ {"bef57ec7f53a6d40beb640a780a639c83bc29ac8a9816f1fc6c5c6dcd93c4721", "abcdef"},
+ {"7d1a54127b222502f5b79b5fb0803061152a44f92b37e23c6527baf665d4da9a", "abcdefg"},
+ {"9c56cc51b374c3ba189210d5b6d4bf57790d351c96c47c02190ecf1e430635ab", "abcdefgh"},
+ {"19cc02f26df43cc571bc9ed7b0c4d29224a3ec229529221725ef76d021c8326f", "abcdefghi"},
+ {"72399361da6a7754fec986dca5b7cbaf1c810a28ded4abaf56b2106d06cb78b0", "abcdefghij"},
+ {"a144061c271f152da4d151034508fed1c138b8c976339de229c3bb6d4bbb4fce", "Discard medicine more than two years old."},
+ {"6dae5caa713a10ad04b46028bf6dad68837c581616a1589a265a11288d4bb5c4", "He who has a shady past knows that nice guys finish last."},
+ {"ae7a702a9509039ddbf29f0765e70d0001177914b86459284dab8b348c2dce3f", "I wouldn't marry him with a ten foot pole."},
+ {"6748450b01c568586715291dfa3ee018da07d36bb7ea6f180c1af6270215c64f", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
+ {"14b82014ad2b11f661b5ae6a99b75105c2ffac278cd071cd6c05832793635774", "The days of the digital watch are numbered. -Tom Stoppard"},
+ {"7102cfd76e2e324889eece5d6c41921b1e142a4ac5a2692be78803097f6a48d8", "Nepal premier won't resign."},
+ {"23b1018cd81db1d67983c5f7417c44da9deb582459e378d7a068552ea649dc9f", "For every action there is an equal and opposite government program."},
+ {"8001f190dfb527261c4cfcab70c98e8097a7a1922129bc4096950e57c7999a5a", "His money is twice tainted: 'taint yours and 'taint mine."},
+ {"8c87deb65505c3993eb24b7a150c4155e82eee6960cf0c3a8114ff736d69cad5", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
+ {"bfb0a67a19cdec3646498b2e0f751bddc41bba4b7f30081b0b932aad214d16d7", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
+ {"7f9a0b9bf56332e19f5a0ec1ad9c1425a153da1c624868fda44561d6b74daf36", "size: a.out: bad magic"},
+ {"b13f81b8aad9e3666879af19886140904f7f429ef083286195982a7588858cfc", "The major problem is with sendmail. -Mark Horton"},
+ {"b26c38d61519e894480c70c8374ea35aa0ad05b2ae3d6674eec5f52a69305ed4", "Give me a rock, paper and scissors and I will move the world. CCFestoon"},
+ {"049d5e26d4f10222cd841a119e38bd8d2e0d1129728688449575d4ff42b842c1", "If the enemy is within range, then so are you."},
+ {"0e116838e3cc1c1a14cd045397e29b4d087aa11b0853fc69ec82e90330d60949", "It's well we cannot hear the screams/That we create in others' dreams."},
+ {"4f7d8eb5bcf11de2a56b971021a444aa4eafd6ecd0f307b5109e4e776cd0fe46", "You remind me of a TV show, but that's all right: I watch it anyway."},
+ {"61c0cc4c4bd8406d5120b3fb4ebc31ce87667c162f29468b3c779675a85aebce", "C is as portable as Stonehedge!!"},
+ {"1fb2eb3688093c4a3f80cd87a5547e2ce940a4f923243a79a2a1e242220693ac", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
+ {"395585ce30617b62c80b93e8208ce866d4edc811a177fdb4b82d3911d8696423", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"},
+ {"4f9b189a13d030838269dce846b16a1ce9ce81fe63e65de2f636863336a98fe6", "How can you write a big system without C++? -Paul Glick"},
}
var golden224 = []sha256Test{
- sha256Test{"d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", ""},
- sha256Test{"abd37534c7d9a2efb9465de931cd7055ffdb8879563ae98078d6d6d5", "a"},
- sha256Test{"db3cda86d4429a1d39c148989566b38f7bda0156296bd364ba2f878b", "ab"},
- sha256Test{"23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", "abc"},
- sha256Test{"a76654d8e3550e9a2d67a0eeb6c67b220e5885eddd3fde135806e601", "abcd"},
- sha256Test{"bdd03d560993e675516ba5a50638b6531ac2ac3d5847c61916cfced6", "abcde"},
- sha256Test{"7043631cb415556a275a4ebecb802c74ee9f6153908e1792a90b6a98", "abcdef"},
- sha256Test{"d1884e711701ad81abe0c77a3b0ea12e19ba9af64077286c72fc602d", "abcdefg"},
- sha256Test{"17eb7d40f0356f8598e89eafad5f6c759b1f822975d9c9b737c8a517", "abcdefgh"},
- sha256Test{"aeb35915346c584db820d2de7af3929ffafef9222a9bcb26516c7334", "abcdefghi"},
- sha256Test{"d35e1e5af29ddb0d7e154357df4ad9842afee527c689ee547f753188", "abcdefghij"},
- sha256Test{"19297f1cef7ddc8a7e947f5c5a341e10f7245045e425db67043988d7", "Discard medicine more than two years old."},
- sha256Test{"0f10c2eb436251f777fbbd125e260d36aecf180411726c7c885f599a", "He who has a shady past knows that nice guys finish last."},
- sha256Test{"4d1842104919f314cad8a3cd20b3cba7e8ed3e7abed62b57441358f6", "I wouldn't marry him with a ten foot pole."},
- sha256Test{"a8ba85c6fe0c48fbffc72bbb2f03fcdbc87ae2dc7a56804d1590fb3b", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
- sha256Test{"5543fbab26e67e8885b1a852d567d1cb8b9bfe42e0899584c50449a9", "The days of the digital watch are numbered. -Tom Stoppard"},
- sha256Test{"65ca107390f5da9efa05d28e57b221657edc7e43a9a18fb15b053ddb", "Nepal premier won't resign."},
- sha256Test{"84953962be366305a9cc9b5cd16ed019edc37ac96c0deb3e12cca116", "For every action there is an equal and opposite government program."},
- sha256Test{"35a189ce987151dfd00b3577583cc6a74b9869eecf894459cb52038d", "His money is twice tainted: 'taint yours and 'taint mine."},
- sha256Test{"2fc333713983edfd4ef2c0da6fb6d6415afb94987c91e4069eb063e6", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
- sha256Test{"cbe32d38d577a1b355960a4bc3c659c2dc4670859a19777a875842c4", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
- sha256Test{"a2dc118ce959e027576413a7b440c875cdc8d40df9141d6ef78a57e1", "size: a.out: bad magic"},
- sha256Test{"d10787e24052bcff26dc484787a54ed819e4e4511c54890ee977bf81", "The major problem is with sendmail. -Mark Horton"},
- sha256Test{"62efcf16ab8a893acdf2f348aaf06b63039ff1bf55508c830532c9fb", "Give me a rock, paper and scissors and I will move the world. CCFestoon"},
- sha256Test{"3e9b7e4613c59f58665104c5fa86c272db5d3a2ff30df5bb194a5c99", "If the enemy is within range, then so are you."},
- sha256Test{"5999c208b8bdf6d471bb7c359ac5b829e73a8211dff686143a4e7f18", "It's well we cannot hear the screams/That we create in others' dreams."},
- sha256Test{"3b2d67ff54eabc4ef737b14edf87c64280ef582bcdf2a6d56908b405", "You remind me of a TV show, but that's all right: I watch it anyway."},
- sha256Test{"d0733595d20e4d3d6b5c565a445814d1bbb2fd08b9a3b8ffb97930c6", "C is as portable as Stonehedge!!"},
- sha256Test{"43fb8aeed8a833175c9295c1165415f98c866ef08a4922959d673507", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
- sha256Test{"ec18e66e93afc4fb1604bc2baedbfd20b44c43d76e65c0996d7851c6", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"},
- sha256Test{"86ed2eaa9c75ba98396e5c9fb2f679ecf0ea2ed1e0ee9ceecb4a9332", "How can you write a big system without C++? -Paul Glick"},
+ {"d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", ""},
+ {"abd37534c7d9a2efb9465de931cd7055ffdb8879563ae98078d6d6d5", "a"},
+ {"db3cda86d4429a1d39c148989566b38f7bda0156296bd364ba2f878b", "ab"},
+ {"23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", "abc"},
+ {"a76654d8e3550e9a2d67a0eeb6c67b220e5885eddd3fde135806e601", "abcd"},
+ {"bdd03d560993e675516ba5a50638b6531ac2ac3d5847c61916cfced6", "abcde"},
+ {"7043631cb415556a275a4ebecb802c74ee9f6153908e1792a90b6a98", "abcdef"},
+ {"d1884e711701ad81abe0c77a3b0ea12e19ba9af64077286c72fc602d", "abcdefg"},
+ {"17eb7d40f0356f8598e89eafad5f6c759b1f822975d9c9b737c8a517", "abcdefgh"},
+ {"aeb35915346c584db820d2de7af3929ffafef9222a9bcb26516c7334", "abcdefghi"},
+ {"d35e1e5af29ddb0d7e154357df4ad9842afee527c689ee547f753188", "abcdefghij"},
+ {"19297f1cef7ddc8a7e947f5c5a341e10f7245045e425db67043988d7", "Discard medicine more than two years old."},
+ {"0f10c2eb436251f777fbbd125e260d36aecf180411726c7c885f599a", "He who has a shady past knows that nice guys finish last."},
+ {"4d1842104919f314cad8a3cd20b3cba7e8ed3e7abed62b57441358f6", "I wouldn't marry him with a ten foot pole."},
+ {"a8ba85c6fe0c48fbffc72bbb2f03fcdbc87ae2dc7a56804d1590fb3b", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
+ {"5543fbab26e67e8885b1a852d567d1cb8b9bfe42e0899584c50449a9", "The days of the digital watch are numbered. -Tom Stoppard"},
+ {"65ca107390f5da9efa05d28e57b221657edc7e43a9a18fb15b053ddb", "Nepal premier won't resign."},
+ {"84953962be366305a9cc9b5cd16ed019edc37ac96c0deb3e12cca116", "For every action there is an equal and opposite government program."},
+ {"35a189ce987151dfd00b3577583cc6a74b9869eecf894459cb52038d", "His money is twice tainted: 'taint yours and 'taint mine."},
+ {"2fc333713983edfd4ef2c0da6fb6d6415afb94987c91e4069eb063e6", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
+ {"cbe32d38d577a1b355960a4bc3c659c2dc4670859a19777a875842c4", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
+ {"a2dc118ce959e027576413a7b440c875cdc8d40df9141d6ef78a57e1", "size: a.out: bad magic"},
+ {"d10787e24052bcff26dc484787a54ed819e4e4511c54890ee977bf81", "The major problem is with sendmail. -Mark Horton"},
+ {"62efcf16ab8a893acdf2f348aaf06b63039ff1bf55508c830532c9fb", "Give me a rock, paper and scissors and I will move the world. CCFestoon"},
+ {"3e9b7e4613c59f58665104c5fa86c272db5d3a2ff30df5bb194a5c99", "If the enemy is within range, then so are you."},
+ {"5999c208b8bdf6d471bb7c359ac5b829e73a8211dff686143a4e7f18", "It's well we cannot hear the screams/That we create in others' dreams."},
+ {"3b2d67ff54eabc4ef737b14edf87c64280ef582bcdf2a6d56908b405", "You remind me of a TV show, but that's all right: I watch it anyway."},
+ {"d0733595d20e4d3d6b5c565a445814d1bbb2fd08b9a3b8ffb97930c6", "C is as portable as Stonehedge!!"},
+ {"43fb8aeed8a833175c9295c1165415f98c866ef08a4922959d673507", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
+ {"ec18e66e93afc4fb1604bc2baedbfd20b44c43d76e65c0996d7851c6", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"},
+ {"86ed2eaa9c75ba98396e5c9fb2f679ecf0ea2ed1e0ee9ceecb4a9332", "How can you write a big system without C++? -Paul Glick"},
}
func TestGolden(t *testing.T) {
diff --git a/src/pkg/crypto/sha512/Makefile b/src/pkg/crypto/sha512/Makefile
index cf52732a4..2f7633fa3 100644
--- a/src/pkg/crypto/sha512/Makefile
+++ b/src/pkg/crypto/sha512/Makefile
@@ -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 ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=crypto/sha512
GOFILES=\
diff --git a/src/pkg/crypto/sha512/sha512.go b/src/pkg/crypto/sha512/sha512.go
index 21b030563..c3cda97d9 100644
--- a/src/pkg/crypto/sha512/sha512.go
+++ b/src/pkg/crypto/sha512/sha512.go
@@ -112,10 +112,7 @@ func (d *digest) Write(p []byte) (nn int, err os.Error) {
n := _Block(d, p)
p = p[n:]
if len(p) > 0 {
- for i, x := range p {
- d.x[i] = x
- }
- d.nx = len(p)
+ d.nx = copy(d.x[:], p)
}
return
}
diff --git a/src/pkg/crypto/sha512/sha512_test.go b/src/pkg/crypto/sha512/sha512_test.go
index 590cf1aec..dd116dc17 100644
--- a/src/pkg/crypto/sha512/sha512_test.go
+++ b/src/pkg/crypto/sha512/sha512_test.go
@@ -18,71 +18,71 @@ type sha512Test struct {
}
var golden = []sha512Test{
- sha512Test{"cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e", ""},
- sha512Test{"1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75", "a"},
- sha512Test{"2d408a0717ec188158278a796c689044361dc6fdde28d6f04973b80896e1823975cdbf12eb63f9e0591328ee235d80e9b5bf1aa6a44f4617ff3caf6400eb172d", "ab"},
- sha512Test{"ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f", "abc"},
- sha512Test{"d8022f2060ad6efd297ab73dcc5355c9b214054b0d1776a136a669d26a7d3b14f73aa0d0ebff19ee333368f0164b6419a96da49e3e481753e7e96b716bdccb6f", "abcd"},
- sha512Test{"878ae65a92e86cac011a570d4c30a7eaec442b85ce8eca0c2952b5e3cc0628c2e79d889ad4d5c7c626986d452dd86374b6ffaa7cd8b67665bef2289a5c70b0a1", "abcde"},
- sha512Test{"e32ef19623e8ed9d267f657a81944b3d07adbb768518068e88435745564e8d4150a0a703be2a7d88b61e3d390c2bb97e2d4c311fdc69d6b1267f05f59aa920e7", "abcdef"},
- sha512Test{"d716a4188569b68ab1b6dfac178e570114cdf0ea3a1cc0e31486c3e41241bc6a76424e8c37ab26f096fc85ef9886c8cb634187f4fddff645fb099f1ff54c6b8c", "abcdefg"},
- sha512Test{"a3a8c81bc97c2560010d7389bc88aac974a104e0e2381220c6e084c4dccd1d2d17d4f86db31c2a851dc80e6681d74733c55dcd03dd96f6062cdda12a291ae6ce", "abcdefgh"},
- sha512Test{"f22d51d25292ca1d0f68f69aedc7897019308cc9db46efb75a03dd494fc7f126c010e8ade6a00a0c1a5f1b75d81e0ed5a93ce98dc9b833db7839247b1d9c24fe", "abcdefghi"},
- sha512Test{"ef6b97321f34b1fea2169a7db9e1960b471aa13302a988087357c520be957ca119c3ba68e6b4982c019ec89de3865ccf6a3cda1fe11e59f98d99f1502c8b9745", "abcdefghij"},
- sha512Test{"2210d99af9c8bdecda1b4beff822136753d8342505ddce37f1314e2cdbb488c6016bdaa9bd2ffa513dd5de2e4b50f031393d8ab61f773b0e0130d7381e0f8a1d", "Discard medicine more than two years old."},
- sha512Test{"a687a8985b4d8d0a24f115fe272255c6afaf3909225838546159c1ed685c211a203796ae8ecc4c81a5b6315919b3a64f10713da07e341fcdbb08541bf03066ce", "He who has a shady past knows that nice guys finish last."},
- sha512Test{"8ddb0392e818b7d585ab22769a50df660d9f6d559cca3afc5691b8ca91b8451374e42bcdabd64589ed7c91d85f626596228a5c8572677eb98bc6b624befb7af8", "I wouldn't marry him with a ten foot pole."},
- sha512Test{"26ed8f6ca7f8d44b6a8a54ae39640fa8ad5c673f70ee9ce074ba4ef0d483eea00bab2f61d8695d6b34df9c6c48ae36246362200ed820448bdc03a720366a87c6", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
- sha512Test{"e5a14bf044be69615aade89afcf1ab0389d5fc302a884d403579d1386a2400c089b0dbb387ed0f463f9ee342f8244d5a38cfbc0e819da9529fbff78368c9a982", "The days of the digital watch are numbered. -Tom Stoppard"},
- sha512Test{"420a1faa48919e14651bed45725abe0f7a58e0f099424c4e5a49194946e38b46c1f8034b18ef169b2e31050d1648e0b982386595f7df47da4b6fd18e55333015", "Nepal premier won't resign."},
- sha512Test{"d926a863beadb20134db07683535c72007b0e695045876254f341ddcccde132a908c5af57baa6a6a9c63e6649bba0c213dc05fadcf9abccea09f23dcfb637fbe", "For every action there is an equal and opposite government program."},
- sha512Test{"9a98dd9bb67d0da7bf83da5313dff4fd60a4bac0094f1b05633690ffa7f6d61de9a1d4f8617937d560833a9aaa9ccafe3fd24db418d0e728833545cadd3ad92d", "His money is twice tainted: 'taint yours and 'taint mine."},
- sha512Test{"d7fde2d2351efade52f4211d3746a0780a26eec3df9b2ed575368a8a1c09ec452402293a8ea4eceb5a4f60064ea29b13cdd86918cd7a4faf366160b009804107", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
- sha512Test{"b0f35ffa2697359c33a56f5c0cf715c7aeed96da9905ca2698acadb08fbc9e669bf566b6bd5d61a3e86dc22999bcc9f2224e33d1d4f32a228cf9d0349e2db518", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
- sha512Test{"3d2e5f91778c9e66f7e061293aaa8a8fc742dd3b2e4f483772464b1144189b49273e610e5cccd7a81a19ca1fa70f16b10f1a100a4d8c1372336be8484c64b311", "size: a.out: bad magic"},
- sha512Test{"b2f68ff58ac015efb1c94c908b0d8c2bf06f491e4de8e6302c49016f7f8a33eac3e959856c7fddbc464de618701338a4b46f76dbfaf9a1e5262b5f40639771c7", "The major problem is with sendmail. -Mark Horton"},
- sha512Test{"d8c92db5fdf52cf8215e4df3b4909d29203ff4d00e9ad0b64a6a4e04dec5e74f62e7c35c7fb881bd5de95442123df8f57a489b0ae616bd326f84d10021121c57", "Give me a rock, paper and scissors and I will move the world. CCFestoon"},
- sha512Test{"19a9f8dc0a233e464e8566ad3ca9b91e459a7b8c4780985b015776e1bf239a19bc233d0556343e2b0a9bc220900b4ebf4f8bdf89ff8efeaf79602d6849e6f72e", "If the enemy is within range, then so are you."},
- sha512Test{"00b4c41f307bde87301cdc5b5ab1ae9a592e8ecbb2021dd7bc4b34e2ace60741cc362560bec566ba35178595a91932b8d5357e2c9cec92d393b0fa7831852476", "It's well we cannot hear the screams/That we create in others' dreams."},
- sha512Test{"91eccc3d5375fd026e4d6787874b1dce201cecd8a27dbded5065728cb2d09c58a3d467bb1faf353bf7ba567e005245d5321b55bc344f7c07b91cb6f26c959be7", "You remind me of a TV show, but that's all right: I watch it anyway."},
- sha512Test{"fabbbe22180f1f137cfdc9556d2570e775d1ae02a597ded43a72a40f9b485d500043b7be128fb9fcd982b83159a0d99aa855a9e7cc4240c00dc01a9bdf8218d7", "C is as portable as Stonehedge!!"},
- sha512Test{"2ecdec235c1fa4fc2a154d8fba1dddb8a72a1ad73838b51d792331d143f8b96a9f6fcb0f34d7caa351fe6d88771c4f105040e0392f06e0621689d33b2f3ba92e", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
- sha512Test{"7ad681f6f96f82f7abfa7ecc0334e8fa16d3dc1cdc45b60b7af43fe4075d2357c0c1d60e98350f1afb1f2fe7a4d7cd2ad55b88e458e06b73c40b437331f5dab4", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"},
- sha512Test{"833f9248ab4a3b9e5131f745fda1ffd2dd435b30e965957e78291c7ab73605fd1912b0794e5c233ab0a12d205a39778d19b83515d6a47003f19cdee51d98c7e0", "How can you write a big system without C++? -Paul Glick"},
+ {"cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e", ""},
+ {"1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75", "a"},
+ {"2d408a0717ec188158278a796c689044361dc6fdde28d6f04973b80896e1823975cdbf12eb63f9e0591328ee235d80e9b5bf1aa6a44f4617ff3caf6400eb172d", "ab"},
+ {"ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f", "abc"},
+ {"d8022f2060ad6efd297ab73dcc5355c9b214054b0d1776a136a669d26a7d3b14f73aa0d0ebff19ee333368f0164b6419a96da49e3e481753e7e96b716bdccb6f", "abcd"},
+ {"878ae65a92e86cac011a570d4c30a7eaec442b85ce8eca0c2952b5e3cc0628c2e79d889ad4d5c7c626986d452dd86374b6ffaa7cd8b67665bef2289a5c70b0a1", "abcde"},
+ {"e32ef19623e8ed9d267f657a81944b3d07adbb768518068e88435745564e8d4150a0a703be2a7d88b61e3d390c2bb97e2d4c311fdc69d6b1267f05f59aa920e7", "abcdef"},
+ {"d716a4188569b68ab1b6dfac178e570114cdf0ea3a1cc0e31486c3e41241bc6a76424e8c37ab26f096fc85ef9886c8cb634187f4fddff645fb099f1ff54c6b8c", "abcdefg"},
+ {"a3a8c81bc97c2560010d7389bc88aac974a104e0e2381220c6e084c4dccd1d2d17d4f86db31c2a851dc80e6681d74733c55dcd03dd96f6062cdda12a291ae6ce", "abcdefgh"},
+ {"f22d51d25292ca1d0f68f69aedc7897019308cc9db46efb75a03dd494fc7f126c010e8ade6a00a0c1a5f1b75d81e0ed5a93ce98dc9b833db7839247b1d9c24fe", "abcdefghi"},
+ {"ef6b97321f34b1fea2169a7db9e1960b471aa13302a988087357c520be957ca119c3ba68e6b4982c019ec89de3865ccf6a3cda1fe11e59f98d99f1502c8b9745", "abcdefghij"},
+ {"2210d99af9c8bdecda1b4beff822136753d8342505ddce37f1314e2cdbb488c6016bdaa9bd2ffa513dd5de2e4b50f031393d8ab61f773b0e0130d7381e0f8a1d", "Discard medicine more than two years old."},
+ {"a687a8985b4d8d0a24f115fe272255c6afaf3909225838546159c1ed685c211a203796ae8ecc4c81a5b6315919b3a64f10713da07e341fcdbb08541bf03066ce", "He who has a shady past knows that nice guys finish last."},
+ {"8ddb0392e818b7d585ab22769a50df660d9f6d559cca3afc5691b8ca91b8451374e42bcdabd64589ed7c91d85f626596228a5c8572677eb98bc6b624befb7af8", "I wouldn't marry him with a ten foot pole."},
+ {"26ed8f6ca7f8d44b6a8a54ae39640fa8ad5c673f70ee9ce074ba4ef0d483eea00bab2f61d8695d6b34df9c6c48ae36246362200ed820448bdc03a720366a87c6", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
+ {"e5a14bf044be69615aade89afcf1ab0389d5fc302a884d403579d1386a2400c089b0dbb387ed0f463f9ee342f8244d5a38cfbc0e819da9529fbff78368c9a982", "The days of the digital watch are numbered. -Tom Stoppard"},
+ {"420a1faa48919e14651bed45725abe0f7a58e0f099424c4e5a49194946e38b46c1f8034b18ef169b2e31050d1648e0b982386595f7df47da4b6fd18e55333015", "Nepal premier won't resign."},
+ {"d926a863beadb20134db07683535c72007b0e695045876254f341ddcccde132a908c5af57baa6a6a9c63e6649bba0c213dc05fadcf9abccea09f23dcfb637fbe", "For every action there is an equal and opposite government program."},
+ {"9a98dd9bb67d0da7bf83da5313dff4fd60a4bac0094f1b05633690ffa7f6d61de9a1d4f8617937d560833a9aaa9ccafe3fd24db418d0e728833545cadd3ad92d", "His money is twice tainted: 'taint yours and 'taint mine."},
+ {"d7fde2d2351efade52f4211d3746a0780a26eec3df9b2ed575368a8a1c09ec452402293a8ea4eceb5a4f60064ea29b13cdd86918cd7a4faf366160b009804107", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
+ {"b0f35ffa2697359c33a56f5c0cf715c7aeed96da9905ca2698acadb08fbc9e669bf566b6bd5d61a3e86dc22999bcc9f2224e33d1d4f32a228cf9d0349e2db518", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
+ {"3d2e5f91778c9e66f7e061293aaa8a8fc742dd3b2e4f483772464b1144189b49273e610e5cccd7a81a19ca1fa70f16b10f1a100a4d8c1372336be8484c64b311", "size: a.out: bad magic"},
+ {"b2f68ff58ac015efb1c94c908b0d8c2bf06f491e4de8e6302c49016f7f8a33eac3e959856c7fddbc464de618701338a4b46f76dbfaf9a1e5262b5f40639771c7", "The major problem is with sendmail. -Mark Horton"},
+ {"d8c92db5fdf52cf8215e4df3b4909d29203ff4d00e9ad0b64a6a4e04dec5e74f62e7c35c7fb881bd5de95442123df8f57a489b0ae616bd326f84d10021121c57", "Give me a rock, paper and scissors and I will move the world. CCFestoon"},
+ {"19a9f8dc0a233e464e8566ad3ca9b91e459a7b8c4780985b015776e1bf239a19bc233d0556343e2b0a9bc220900b4ebf4f8bdf89ff8efeaf79602d6849e6f72e", "If the enemy is within range, then so are you."},
+ {"00b4c41f307bde87301cdc5b5ab1ae9a592e8ecbb2021dd7bc4b34e2ace60741cc362560bec566ba35178595a91932b8d5357e2c9cec92d393b0fa7831852476", "It's well we cannot hear the screams/That we create in others' dreams."},
+ {"91eccc3d5375fd026e4d6787874b1dce201cecd8a27dbded5065728cb2d09c58a3d467bb1faf353bf7ba567e005245d5321b55bc344f7c07b91cb6f26c959be7", "You remind me of a TV show, but that's all right: I watch it anyway."},
+ {"fabbbe22180f1f137cfdc9556d2570e775d1ae02a597ded43a72a40f9b485d500043b7be128fb9fcd982b83159a0d99aa855a9e7cc4240c00dc01a9bdf8218d7", "C is as portable as Stonehedge!!"},
+ {"2ecdec235c1fa4fc2a154d8fba1dddb8a72a1ad73838b51d792331d143f8b96a9f6fcb0f34d7caa351fe6d88771c4f105040e0392f06e0621689d33b2f3ba92e", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
+ {"7ad681f6f96f82f7abfa7ecc0334e8fa16d3dc1cdc45b60b7af43fe4075d2357c0c1d60e98350f1afb1f2fe7a4d7cd2ad55b88e458e06b73c40b437331f5dab4", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"},
+ {"833f9248ab4a3b9e5131f745fda1ffd2dd435b30e965957e78291c7ab73605fd1912b0794e5c233ab0a12d205a39778d19b83515d6a47003f19cdee51d98c7e0", "How can you write a big system without C++? -Paul Glick"},
}
var golden384 = []sha512Test{
- sha512Test{"38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b", ""},
- sha512Test{"54a59b9f22b0b80880d8427e548b7c23abd873486e1f035dce9cd697e85175033caa88e6d57bc35efae0b5afd3145f31", "a"},
- sha512Test{"c7be03ba5bcaa384727076db0018e99248e1a6e8bd1b9ef58a9ec9dd4eeebb3f48b836201221175befa74ddc3d35afdd", "ab"},
- sha512Test{"cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7", "abc"},
- sha512Test{"1165b3406ff0b52a3d24721f785462ca2276c9f454a116c2b2ba20171a7905ea5a026682eb659c4d5f115c363aa3c79b", "abcd"},
- sha512Test{"4c525cbeac729eaf4b4665815bc5db0c84fe6300068a727cf74e2813521565abc0ec57a37ee4d8be89d097c0d2ad52f0", "abcde"},
- sha512Test{"c6a4c65b227e7387b9c3e839d44869c4cfca3ef583dea64117859b808c1e3d8ae689e1e314eeef52a6ffe22681aa11f5", "abcdef"},
- sha512Test{"9f11fc131123f844c1226f429b6a0a6af0525d9f40f056c7fc16cdf1b06bda08e302554417a59fa7dcf6247421959d22", "abcdefg"},
- sha512Test{"9000cd7cada59d1d2eb82912f7f24e5e69cc5517f68283b005fa27c285b61e05edf1ad1a8a9bded6fd29eb87d75ad806", "abcdefgh"},
- sha512Test{"ef54915b60cf062b8dd0c29ae3cad69abe6310de63ac081f46ef019c5c90897caefd79b796cfa81139788a260ded52df", "abcdefghi"},
- sha512Test{"a12070030a02d86b0ddacd0d3a5b598344513d0a051e7355053e556a0055489c1555399b03342845c4adde2dc44ff66c", "abcdefghij"},
- sha512Test{"86f58ec2d74d1b7f8eb0c2ff0967316699639e8d4eb129de54bdf34c96cdbabe200d052149f2dd787f43571ba74670d4", "Discard medicine more than two years old."},
- sha512Test{"ae4a2b639ca9bfa04b1855d5a05fe7f230994f790891c6979103e2605f660c4c1262a48142dcbeb57a1914ba5f7c3fa7", "He who has a shady past knows that nice guys finish last."},
- sha512Test{"40ae213df6436eca952aa6841886fcdb82908ef1576a99c8f49bb9dd5023169f7c53035abdda0b54c302f4974e2105e7", "I wouldn't marry him with a ten foot pole."},
- sha512Test{"e7cf8b873c9bc950f06259aa54309f349cefa72c00d597aebf903e6519a50011dfe355afff064a10701c705693848df9", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
- sha512Test{"c3d4f0f4047181c7d39d34703365f7bf70207183caf2c2f6145f04da895ef69124d9cdeb635da636c3a474e61024e29b", "The days of the digital watch are numbered. -Tom Stoppard"},
- sha512Test{"a097aab567e167d5cf93676ed73252a69f9687cb3179bb2d27c9878119e94bf7b7c4b58dc90582edfaf66e11388ed714", "Nepal premier won't resign."},
- sha512Test{"5026ca45c41fc64712eb65065da92f6467541c78f8966d3fe2c8e3fb769a3ec14215f819654b47bd64f7f0eac17184f3", "For every action there is an equal and opposite government program."},
- sha512Test{"ac1cc0f5ac8d5f5514a7b738ac322b7fb52a161b449c3672e9b6a6ad1a5e4b26b001cf3bad24c56598676ca17d4b445a", "His money is twice tainted: 'taint yours and 'taint mine."},
- sha512Test{"722d10c5de371ec0c8c4b5247ac8a5f1d240d68c73f8da13d8b25f0166d6f309bf9561979a111a0049405771d201941a", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
- sha512Test{"dc2d3ea18bfa10549c63bf2b75b39b5167a80c12aff0e05443168ea87ff149fb0eda5e0bd234eb5d48c7d02ffc5807f1", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
- sha512Test{"1d67c969e2a945ae5346d2139760261504d4ba164c522443afe19ef3e29b152a4c52445489cfc9d7215e5a450e8e1e4e", "size: a.out: bad magic"},
- sha512Test{"5ff8e075e465646e7b73ef36d812c6e9f7d60fa6ea0e533e5569b4f73cde53cdd2cc787f33540af57cca3fe467d32fe0", "The major problem is with sendmail. -Mark Horton"},
- sha512Test{"5bd0a997a67c9ae1979a894eb0cde403dde003c9b6f2c03cf21925c42ff4e1176e6df1ca005381612ef18457b9b7ec3b", "Give me a rock, paper and scissors and I will move the world. CCFestoon"},
- sha512Test{"1eee6da33e7e54fc5be52ae23b94b16ba4d2a947ae4505c6a3edfc7401151ea5205ac01b669b56f27d8ef7f175ed7762", "If the enemy is within range, then so are you."},
- sha512Test{"76b06e9dea66bfbb1a96029426dc0dfd7830bd297eb447ff5358d94a87cd00c88b59df2493fef56ecbb5231073892ea9", "It's well we cannot hear the screams/That we create in others' dreams."},
- sha512Test{"12acaf21452cff586143e3f5db0bfdf7802c057e1adf2a619031c4e1b0ccc4208cf6cef8fe722bbaa2fb46a30d9135d8", "You remind me of a TV show, but that's all right: I watch it anyway."},
- sha512Test{"0fc23d7f4183efd186f0bc4fc5db867e026e2146b06cb3d52f4bdbd57d1740122caa853b41868b197b2ac759db39df88", "C is as portable as Stonehedge!!"},
- sha512Test{"bc805578a7f85d34a86a32976e1c34fe65cf815186fbef76f46ef99cda10723f971f3f1464d488243f5e29db7488598d", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
- sha512Test{"b23918399a12ebf4431559eec3813eaf7412e875fd7464f16d581e473330842d2e96c6be49a7ce3f9bb0b8bc0fcbe0fe", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"},
- sha512Test{"1764b700eb1ead52a2fc33cc28975c2180f1b8faa5038d94cffa8d78154aab16e91dd787e7b0303948ebed62561542c8", "How can you write a big system without C++? -Paul Glick"},
+ {"38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b", ""},
+ {"54a59b9f22b0b80880d8427e548b7c23abd873486e1f035dce9cd697e85175033caa88e6d57bc35efae0b5afd3145f31", "a"},
+ {"c7be03ba5bcaa384727076db0018e99248e1a6e8bd1b9ef58a9ec9dd4eeebb3f48b836201221175befa74ddc3d35afdd", "ab"},
+ {"cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7", "abc"},
+ {"1165b3406ff0b52a3d24721f785462ca2276c9f454a116c2b2ba20171a7905ea5a026682eb659c4d5f115c363aa3c79b", "abcd"},
+ {"4c525cbeac729eaf4b4665815bc5db0c84fe6300068a727cf74e2813521565abc0ec57a37ee4d8be89d097c0d2ad52f0", "abcde"},
+ {"c6a4c65b227e7387b9c3e839d44869c4cfca3ef583dea64117859b808c1e3d8ae689e1e314eeef52a6ffe22681aa11f5", "abcdef"},
+ {"9f11fc131123f844c1226f429b6a0a6af0525d9f40f056c7fc16cdf1b06bda08e302554417a59fa7dcf6247421959d22", "abcdefg"},
+ {"9000cd7cada59d1d2eb82912f7f24e5e69cc5517f68283b005fa27c285b61e05edf1ad1a8a9bded6fd29eb87d75ad806", "abcdefgh"},
+ {"ef54915b60cf062b8dd0c29ae3cad69abe6310de63ac081f46ef019c5c90897caefd79b796cfa81139788a260ded52df", "abcdefghi"},
+ {"a12070030a02d86b0ddacd0d3a5b598344513d0a051e7355053e556a0055489c1555399b03342845c4adde2dc44ff66c", "abcdefghij"},
+ {"86f58ec2d74d1b7f8eb0c2ff0967316699639e8d4eb129de54bdf34c96cdbabe200d052149f2dd787f43571ba74670d4", "Discard medicine more than two years old."},
+ {"ae4a2b639ca9bfa04b1855d5a05fe7f230994f790891c6979103e2605f660c4c1262a48142dcbeb57a1914ba5f7c3fa7", "He who has a shady past knows that nice guys finish last."},
+ {"40ae213df6436eca952aa6841886fcdb82908ef1576a99c8f49bb9dd5023169f7c53035abdda0b54c302f4974e2105e7", "I wouldn't marry him with a ten foot pole."},
+ {"e7cf8b873c9bc950f06259aa54309f349cefa72c00d597aebf903e6519a50011dfe355afff064a10701c705693848df9", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
+ {"c3d4f0f4047181c7d39d34703365f7bf70207183caf2c2f6145f04da895ef69124d9cdeb635da636c3a474e61024e29b", "The days of the digital watch are numbered. -Tom Stoppard"},
+ {"a097aab567e167d5cf93676ed73252a69f9687cb3179bb2d27c9878119e94bf7b7c4b58dc90582edfaf66e11388ed714", "Nepal premier won't resign."},
+ {"5026ca45c41fc64712eb65065da92f6467541c78f8966d3fe2c8e3fb769a3ec14215f819654b47bd64f7f0eac17184f3", "For every action there is an equal and opposite government program."},
+ {"ac1cc0f5ac8d5f5514a7b738ac322b7fb52a161b449c3672e9b6a6ad1a5e4b26b001cf3bad24c56598676ca17d4b445a", "His money is twice tainted: 'taint yours and 'taint mine."},
+ {"722d10c5de371ec0c8c4b5247ac8a5f1d240d68c73f8da13d8b25f0166d6f309bf9561979a111a0049405771d201941a", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
+ {"dc2d3ea18bfa10549c63bf2b75b39b5167a80c12aff0e05443168ea87ff149fb0eda5e0bd234eb5d48c7d02ffc5807f1", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
+ {"1d67c969e2a945ae5346d2139760261504d4ba164c522443afe19ef3e29b152a4c52445489cfc9d7215e5a450e8e1e4e", "size: a.out: bad magic"},
+ {"5ff8e075e465646e7b73ef36d812c6e9f7d60fa6ea0e533e5569b4f73cde53cdd2cc787f33540af57cca3fe467d32fe0", "The major problem is with sendmail. -Mark Horton"},
+ {"5bd0a997a67c9ae1979a894eb0cde403dde003c9b6f2c03cf21925c42ff4e1176e6df1ca005381612ef18457b9b7ec3b", "Give me a rock, paper and scissors and I will move the world. CCFestoon"},
+ {"1eee6da33e7e54fc5be52ae23b94b16ba4d2a947ae4505c6a3edfc7401151ea5205ac01b669b56f27d8ef7f175ed7762", "If the enemy is within range, then so are you."},
+ {"76b06e9dea66bfbb1a96029426dc0dfd7830bd297eb447ff5358d94a87cd00c88b59df2493fef56ecbb5231073892ea9", "It's well we cannot hear the screams/That we create in others' dreams."},
+ {"12acaf21452cff586143e3f5db0bfdf7802c057e1adf2a619031c4e1b0ccc4208cf6cef8fe722bbaa2fb46a30d9135d8", "You remind me of a TV show, but that's all right: I watch it anyway."},
+ {"0fc23d7f4183efd186f0bc4fc5db867e026e2146b06cb3d52f4bdbd57d1740122caa853b41868b197b2ac759db39df88", "C is as portable as Stonehedge!!"},
+ {"bc805578a7f85d34a86a32976e1c34fe65cf815186fbef76f46ef99cda10723f971f3f1464d488243f5e29db7488598d", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
+ {"b23918399a12ebf4431559eec3813eaf7412e875fd7464f16d581e473330842d2e96c6be49a7ce3f9bb0b8bc0fcbe0fe", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"},
+ {"1764b700eb1ead52a2fc33cc28975c2180f1b8faa5038d94cffa8d78154aab16e91dd787e7b0303948ebed62561542c8", "How can you write a big system without C++? -Paul Glick"},
}
func TestGolden(t *testing.T) {
diff --git a/src/pkg/crypto/subtle/Makefile b/src/pkg/crypto/subtle/Makefile
index fa5f7ef42..08d8bbfa0 100644
--- a/src/pkg/crypto/subtle/Makefile
+++ b/src/pkg/crypto/subtle/Makefile
@@ -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 ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=crypto/subtle
GOFILES=\
diff --git a/src/pkg/crypto/subtle/constant_time_test.go b/src/pkg/crypto/subtle/constant_time_test.go
index 25962b9ae..b28b73581 100644
--- a/src/pkg/crypto/subtle/constant_time_test.go
+++ b/src/pkg/crypto/subtle/constant_time_test.go
@@ -15,9 +15,9 @@ type TestConstantTimeCompareStruct struct {
}
var testConstandTimeCompareData = []TestConstantTimeCompareStruct{
- TestConstantTimeCompareStruct{[]byte{}, []byte{}, 1},
- TestConstantTimeCompareStruct{[]byte{0x11}, []byte{0x11}, 1},
- TestConstantTimeCompareStruct{[]byte{0x12}, []byte{0x11}, 0},
+ {[]byte{}, []byte{}, 1},
+ {[]byte{0x11}, []byte{0x11}, 1},
+ {[]byte{0x12}, []byte{0x11}, 0},
}
func TestConstantTimeCompare(t *testing.T) {
@@ -34,11 +34,11 @@ type TestConstantTimeByteEqStruct struct {
}
var testConstandTimeByteEqData = []TestConstantTimeByteEqStruct{
- TestConstantTimeByteEqStruct{0, 0, 1},
- TestConstantTimeByteEqStruct{0, 1, 0},
- TestConstantTimeByteEqStruct{1, 0, 0},
- TestConstantTimeByteEqStruct{0xff, 0xff, 1},
- TestConstantTimeByteEqStruct{0xff, 0xfe, 0},
+ {0, 0, 1},
+ {0, 1, 0},
+ {1, 0, 0},
+ {0xff, 0xff, 1},
+ {0xff, 0xfe, 0},
}
func byteEq(a, b uint8) int {
diff --git a/src/pkg/crypto/tls/Makefile b/src/pkg/crypto/tls/Makefile
index 5e25bd43a..f8ec1511a 100644
--- a/src/pkg/crypto/tls/Makefile
+++ b/src/pkg/crypto/tls/Makefile
@@ -2,17 +2,19 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=crypto/tls
GOFILES=\
alert.go\
ca_set.go\
+ cipher_suites.go\
common.go\
conn.go\
handshake_client.go\
handshake_messages.go\
handshake_server.go\
+ key_agreement.go\
prf.go\
tls.go\
diff --git a/src/pkg/crypto/tls/ca_set.go b/src/pkg/crypto/tls/ca_set.go
index 7f7566e46..ae00ac558 100644
--- a/src/pkg/crypto/tls/ca_set.go
+++ b/src/pkg/crypto/tls/ca_set.go
@@ -7,32 +7,57 @@ package tls
import (
"crypto/x509"
"encoding/pem"
+ "strings"
)
// A CASet is a set of certificates.
type CASet struct {
- bySubjectKeyId map[string]*x509.Certificate
- byName map[string]*x509.Certificate
+ bySubjectKeyId map[string][]*x509.Certificate
+ byName map[string][]*x509.Certificate
}
+// NewCASet returns a new, empty CASet.
func NewCASet() *CASet {
return &CASet{
- make(map[string]*x509.Certificate),
- make(map[string]*x509.Certificate),
+ make(map[string][]*x509.Certificate),
+ make(map[string][]*x509.Certificate),
}
}
func nameToKey(name *x509.Name) string {
- return name.Country + "/" + name.Organization + "/" + name.OrganizationalUnit + "/" + name.CommonName
+ return strings.Join(name.Country, ",") + "/" + strings.Join(name.Organization, ",") + "/" + strings.Join(name.OrganizationalUnit, ",") + "/" + name.CommonName
}
-// FindParent attempts to find the certificate in s which signs the given
-// certificate. If no such certificate can be found, it returns nil.
-func (s *CASet) FindParent(cert *x509.Certificate) (parent *x509.Certificate) {
+// FindVerifiedParent attempts to find the certificate in s which has signed
+// the given certificate. If no such certificate can be found or the signature
+// doesn't match, it returns nil.
+func (s *CASet) FindVerifiedParent(cert *x509.Certificate) (parent *x509.Certificate) {
+ var candidates []*x509.Certificate
+
if len(cert.AuthorityKeyId) > 0 {
- return s.bySubjectKeyId[string(cert.AuthorityKeyId)]
+ candidates = s.bySubjectKeyId[string(cert.AuthorityKeyId)]
+ }
+ if len(candidates) == 0 {
+ candidates = s.byName[nameToKey(&cert.Issuer)]
+ }
+
+ for _, c := range candidates {
+ if cert.CheckSignatureFrom(c) == nil {
+ return c
+ }
}
- return s.byName[nameToKey(&cert.Issuer)]
+
+ return nil
+}
+
+// AddCert adds a certificate to the set
+func (s *CASet) AddCert(cert *x509.Certificate) {
+ if len(cert.SubjectKeyId) > 0 {
+ keyId := string(cert.SubjectKeyId)
+ s.bySubjectKeyId[keyId] = append(s.bySubjectKeyId[keyId], cert)
+ }
+ name := nameToKey(&cert.Subject)
+ s.byName[name] = append(s.byName[name], cert)
}
// SetFromPEM attempts to parse a series of PEM encoded root certificates. It
@@ -56,10 +81,7 @@ func (s *CASet) SetFromPEM(pemCerts []byte) (ok bool) {
continue
}
- if len(cert.SubjectKeyId) > 0 {
- s.bySubjectKeyId[string(cert.SubjectKeyId)] = cert
- }
- s.byName[nameToKey(&cert.Subject)] = cert
+ s.AddCert(cert)
ok = true
}
diff --git a/src/pkg/crypto/tls/cipher_suites.go b/src/pkg/crypto/tls/cipher_suites.go
new file mode 100644
index 000000000..bc7b0d32f
--- /dev/null
+++ b/src/pkg/crypto/tls/cipher_suites.go
@@ -0,0 +1,102 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+ "crypto/aes"
+ "crypto/cipher"
+ "crypto/hmac"
+ "crypto/rc4"
+ "crypto/x509"
+ "hash"
+ "os"
+)
+
+// a keyAgreement implements the client and server side of a TLS key agreement
+// protocol by generating and processing key exchange messages.
+type keyAgreement interface {
+ // On the server side, the first two methods are called in order.
+
+ // In the case that the key agreement protocol doesn't use a
+ // ServerKeyExchange message, generateServerKeyExchange can return nil,
+ // nil.
+ generateServerKeyExchange(*Config, *clientHelloMsg, *serverHelloMsg) (*serverKeyExchangeMsg, os.Error)
+ processClientKeyExchange(*Config, *clientKeyExchangeMsg) ([]byte, os.Error)
+
+ // On the client side, the next two methods are called in order.
+
+ // This method may not be called if the server doesn't send a
+ // ServerKeyExchange message.
+ processServerKeyExchange(*Config, *clientHelloMsg, *serverHelloMsg, *x509.Certificate, *serverKeyExchangeMsg) os.Error
+ generateClientKeyExchange(*Config, *clientHelloMsg, *x509.Certificate) ([]byte, *clientKeyExchangeMsg, os.Error)
+}
+
+// A cipherSuite is a specific combination of key agreement, cipher and MAC
+// function. All cipher suites currently assume RSA key agreement.
+type cipherSuite struct {
+ // the lengths, in bytes, of the key material needed for each component.
+ keyLen int
+ macLen int
+ ivLen int
+ ka func() keyAgreement
+ // If elliptic is set, a server will only consider this ciphersuite if
+ // the ClientHello indicated that the client supports an elliptic curve
+ // and point format that we can handle.
+ elliptic bool
+ cipher func(key, iv []byte, isRead bool) interface{}
+ mac func(macKey []byte) hash.Hash
+}
+
+var cipherSuites = map[uint16]*cipherSuite{
+ TLS_RSA_WITH_RC4_128_SHA: &cipherSuite{16, 20, 0, rsaKA, false, cipherRC4, hmacSHA1},
+ TLS_RSA_WITH_AES_128_CBC_SHA: &cipherSuite{16, 20, 16, rsaKA, false, cipherAES, hmacSHA1},
+ TLS_ECDHE_RSA_WITH_RC4_128_SHA: &cipherSuite{16, 20, 0, ecdheRSAKA, true, cipherRC4, hmacSHA1},
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: &cipherSuite{16, 20, 16, ecdheRSAKA, true, cipherAES, hmacSHA1},
+}
+
+func cipherRC4(key, iv []byte, isRead bool) interface{} {
+ cipher, _ := rc4.NewCipher(key)
+ return cipher
+}
+
+func cipherAES(key, iv []byte, isRead bool) interface{} {
+ block, _ := aes.NewCipher(key)
+ if isRead {
+ return cipher.NewCBCDecrypter(block, iv)
+ }
+ return cipher.NewCBCEncrypter(block, iv)
+}
+
+func hmacSHA1(key []byte) hash.Hash {
+ return hmac.NewSHA1(key)
+}
+
+func rsaKA() keyAgreement {
+ return rsaKeyAgreement{}
+}
+
+func ecdheRSAKA() keyAgreement {
+ return new(ecdheRSAKeyAgreement)
+}
+
+// mutualCipherSuite returns a cipherSuite and its id given a list of supported
+// ciphersuites and the id requested by the peer.
+func mutualCipherSuite(have []uint16, want uint16) (suite *cipherSuite, id uint16) {
+ for _, id := range have {
+ if id == want {
+ return cipherSuites[id], id
+ }
+ }
+ return
+}
+
+// A list of the possible cipher suite ids. Taken from
+// http://www.iana.org/assignments/tls-parameters/tls-parameters.xml
+const (
+ TLS_RSA_WITH_RC4_128_SHA uint16 = 0x0005
+ TLS_RSA_WITH_AES_128_CBC_SHA uint16 = 0x002f
+ TLS_ECDHE_RSA_WITH_RC4_128_SHA uint16 = 0xc011
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA uint16 = 0xc013
+)
diff --git a/src/pkg/crypto/tls/common.go b/src/pkg/crypto/tls/common.go
index 56c22cf7d..7135f3d0f 100644
--- a/src/pkg/crypto/tls/common.go
+++ b/src/pkg/crypto/tls/common.go
@@ -9,7 +9,7 @@ import (
"crypto/rsa"
"io"
"io/ioutil"
- "once"
+ "sync"
"time"
)
@@ -20,7 +20,7 @@ const (
maxHandshake = 65536 // maximum handshake we support (protocol max is 16 MB)
minVersion = 0x0301 // minimum supported version - TLS 1.0
- maxVersion = 0x0302 // maximum supported version - TLS 1.1
+ maxVersion = 0x0301 // maximum supported version - TLS 1.0
)
// TLS record types.
@@ -35,35 +35,65 @@ const (
// TLS handshake message types.
const (
- typeClientHello uint8 = 1
- typeServerHello uint8 = 2
- typeCertificate uint8 = 11
- typeServerHelloDone uint8 = 14
- typeClientKeyExchange uint8 = 16
- typeFinished uint8 = 20
- typeNextProtocol uint8 = 67 // Not IANA assigned
+ typeClientHello uint8 = 1
+ typeServerHello uint8 = 2
+ typeCertificate uint8 = 11
+ typeServerKeyExchange uint8 = 12
+ typeCertificateRequest uint8 = 13
+ typeServerHelloDone uint8 = 14
+ typeCertificateVerify uint8 = 15
+ typeClientKeyExchange uint8 = 16
+ typeFinished uint8 = 20
+ typeCertificateStatus uint8 = 22
+ typeNextProtocol uint8 = 67 // Not IANA assigned
)
-// TLS cipher suites.
+// TLS compression types.
+const (
+ compressionNone uint8 = 0
+)
+
+// TLS extension numbers
var (
- TLS_RSA_WITH_RC4_128_SHA uint16 = 5
+ extensionServerName uint16 = 0
+ extensionStatusRequest uint16 = 5
+ extensionSupportedCurves uint16 = 10
+ extensionSupportedPoints uint16 = 11
+ extensionNextProtoNeg uint16 = 13172 // not IANA assigned
)
-// TLS compression types.
+// TLS Elliptic Curves
+// http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-8
var (
- compressionNone uint8 = 0
+ curveP256 uint16 = 23
+ curveP384 uint16 = 24
+ curveP521 uint16 = 25
)
-// TLS extension numbers
+// TLS Elliptic Curve Point Formats
+// http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-9
var (
- extensionServerName uint16 = 0
- extensionNextProtoNeg uint16 = 13172 // not IANA assigned
+ pointFormatUncompressed uint8 = 0
+)
+
+// TLS CertificateStatusType (RFC 3546)
+const (
+ statusTypeOCSP uint8 = 1
)
+// Certificate types (for certificateRequestMsg)
+const (
+ certTypeRSASign = 1 // A certificate containing an RSA key
+ certTypeDSSSign = 2 // A certificate containing a DSA key
+ certTypeRSAFixedDH = 3 // A certificate containing a static DH key
+ certTypeDSSFixedDH = 4 // A certficiate containing a static DH key
+ // Rest of these are reserved by the TLS spec
+)
+
+// ConnectionState records basic TLS details about the connection.
type ConnectionState struct {
HandshakeComplete bool
- CipherSuite string
- Error alert
+ CipherSuite uint16
NegotiatedProtocol string
}
@@ -71,16 +101,76 @@ type ConnectionState struct {
// has been passed to a TLS function it must not be modified.
type Config struct {
// Rand provides the source of entropy for nonces and RSA blinding.
+ // If Rand is nil, TLS uses the cryptographic random reader in package
+ // crypto/rand.
Rand io.Reader
+
// Time returns the current time as the number of seconds since the epoch.
- Time func() int64
+ // If Time is nil, TLS uses the system time.Seconds.
+ Time func() int64
+
+ // Certificates contains one or more certificate chains
+ // to present to the other side of the connection.
+ // Server configurations must include at least one certificate.
Certificates []Certificate
- RootCAs *CASet
+
+ // RootCAs defines the set of root certificate authorities
+ // that clients use when verifying server certificates.
+ // If RootCAs is nil, TLS uses the host's root CA set.
+ RootCAs *CASet
+
// NextProtos is a list of supported, application level protocols.
// Currently only server-side handling is supported.
NextProtos []string
+
+ // ServerName is included in the client's handshake to support virtual
+ // hosting.
+ ServerName string
+
+ // AuthenticateClient controls whether a server will request a certificate
+ // from the client. It does not require that the client send a
+ // certificate nor does it require that the certificate sent be
+ // anything more than self-signed.
+ AuthenticateClient bool
+
+ // CipherSuites is a list of supported cipher suites. If CipherSuites
+ // is nil, TLS uses a list of suites supported by the implementation.
+ CipherSuites []uint16
+}
+
+func (c *Config) rand() io.Reader {
+ r := c.Rand
+ if r == nil {
+ return rand.Reader
+ }
+ return r
+}
+
+func (c *Config) time() int64 {
+ t := c.Time
+ if t == nil {
+ t = time.Seconds
+ }
+ return t()
+}
+
+func (c *Config) rootCAs() *CASet {
+ s := c.RootCAs
+ if s == nil {
+ s = defaultRoots()
+ }
+ return s
+}
+
+func (c *Config) cipherSuites() []uint16 {
+ s := c.CipherSuites
+ if s == nil {
+ s = defaultCipherSuites()
+ }
+ return s
}
+// A Certificate is a chain of one or more certificates, leaf first.
type Certificate struct {
Certificate [][]byte
PrivateKey *rsa.PrivateKey
@@ -98,11 +188,6 @@ type handshakeMessage interface {
unmarshal([]byte) bool
}
-type encryptor interface {
- // XORKeyStream xors the contents of the slice with bytes from the key stream.
- XORKeyStream(buf []byte)
-}
-
// mutualVersion returns the protocol version to use given the advertised
// version of the peer.
func mutualVersion(vers uint16) (uint16, bool) {
@@ -115,12 +200,10 @@ func mutualVersion(vers uint16) (uint16, bool) {
return vers, true
}
-// The defaultConfig is used in place of a nil *Config in the TLS server and client.
-var varDefaultConfig *Config
+var emptyConfig Config
func defaultConfig() *Config {
- once.Do(initDefaultConfig)
- return varDefaultConfig
+ return &emptyConfig
}
// Possible certificate files; stop after finding one.
@@ -132,7 +215,26 @@ var certFiles = []string{
"/usr/share/curl/curl-ca-bundle.crt", // OS X
}
-func initDefaultConfig() {
+var once sync.Once
+
+func defaultRoots() *CASet {
+ once.Do(initDefaults)
+ return varDefaultRoots
+}
+
+func defaultCipherSuites() []uint16 {
+ once.Do(initDefaults)
+ return varDefaultCipherSuites
+}
+
+func initDefaults() {
+ initDefaultRoots()
+ initDefaultCipherSuites()
+}
+
+var varDefaultRoots *CASet
+
+func initDefaultRoots() {
roots := NewCASet()
for _, file := range certFiles {
data, err := ioutil.ReadFile(file)
@@ -141,10 +243,16 @@ func initDefaultConfig() {
break
}
}
+ varDefaultRoots = roots
+}
+
+var varDefaultCipherSuites []uint16
- varDefaultConfig = &Config{
- Rand: rand.Reader,
- Time: time.Seconds,
- RootCAs: roots,
+func initDefaultCipherSuites() {
+ varDefaultCipherSuites = make([]uint16, len(cipherSuites))
+ i := 0
+ for id, _ := range cipherSuites {
+ varDefaultCipherSuites[i] = id
+ i++
}
}
diff --git a/src/pkg/crypto/tls/conn.go b/src/pkg/crypto/tls/conn.go
index 0798e26f6..d203e8d51 100644
--- a/src/pkg/crypto/tls/conn.go
+++ b/src/pkg/crypto/tls/conn.go
@@ -1,10 +1,16 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
// TLS low level connection and record layer
package tls
import (
"bytes"
+ "crypto/cipher"
"crypto/subtle"
+ "crypto/x509"
"hash"
"io"
"net"
@@ -26,6 +32,8 @@ type Conn struct {
config *Config // configuration passed to constructor
handshakeComplete bool
cipherSuite uint16
+ ocspResponse []byte // stapled OCSP response
+ peerCertificates []*x509.Certificate
clientProtocol string
@@ -96,31 +104,31 @@ func (c *Conn) SetWriteTimeout(nsec int64) os.Error {
// connection, either sending or receiving.
type halfConn struct {
sync.Mutex
- crypt encryptor // encryption state
- mac hash.Hash // MAC algorithm
- seq [8]byte // 64-bit sequence number
- bfree *block // list of free blocks
+ cipher interface{} // cipher algorithm
+ mac hash.Hash // MAC algorithm
+ seq [8]byte // 64-bit sequence number
+ bfree *block // list of free blocks
- nextCrypt encryptor // next encryption state
- nextMac hash.Hash // next MAC algorithm
+ nextCipher interface{} // next encryption state
+ nextMac hash.Hash // next MAC algorithm
}
// prepareCipherSpec sets the encryption and MAC states
// that a subsequent changeCipherSpec will use.
-func (hc *halfConn) prepareCipherSpec(crypt encryptor, mac hash.Hash) {
- hc.nextCrypt = crypt
+func (hc *halfConn) prepareCipherSpec(cipher interface{}, mac hash.Hash) {
+ hc.nextCipher = cipher
hc.nextMac = mac
}
// changeCipherSpec changes the encryption and MAC states
// to the ones previously passed to prepareCipherSpec.
func (hc *halfConn) changeCipherSpec() os.Error {
- if hc.nextCrypt == nil {
+ if hc.nextCipher == nil {
return alertInternalError
}
- hc.crypt = hc.nextCrypt
+ hc.cipher = hc.nextCipher
hc.mac = hc.nextMac
- hc.nextCrypt = nil
+ hc.nextCipher = nil
hc.nextMac = nil
return nil
}
@@ -147,27 +155,102 @@ func (hc *halfConn) resetSeq() {
}
}
+// removePadding returns an unpadded slice, in constant time, which is a prefix
+// of the input. It also returns a byte which is equal to 255 if the padding
+// was valid and 0 otherwise. See RFC 2246, section 6.2.3.2
+func removePadding(payload []byte) ([]byte, byte) {
+ if len(payload) < 1 {
+ return payload, 0
+ }
+
+ paddingLen := payload[len(payload)-1]
+ t := uint(len(payload)-1) - uint(paddingLen)
+ // if len(payload) >= (paddingLen - 1) then the MSB of t is zero
+ good := byte(int32(^t) >> 31)
+
+ toCheck := 255 // the maximum possible padding length
+ // The length of the padded data is public, so we can use an if here
+ if toCheck+1 > len(payload) {
+ toCheck = len(payload) - 1
+ }
+
+ for i := 0; i < toCheck; i++ {
+ t := uint(paddingLen) - uint(i)
+ // if i <= paddingLen then the MSB of t is zero
+ mask := byte(int32(^t) >> 31)
+ b := payload[len(payload)-1-i]
+ good &^= mask&paddingLen ^ mask&b
+ }
+
+ // We AND together the bits of good and replicate the result across
+ // all the bits.
+ good &= good << 4
+ good &= good << 2
+ good &= good << 1
+ good = uint8(int8(good) >> 7)
+
+ toRemove := good&paddingLen + 1
+ return payload[:len(payload)-int(toRemove)], good
+}
+
+func roundUp(a, b int) int {
+ return a + (b-a%b)%b
+}
+
// decrypt checks and strips the mac and decrypts the data in b.
func (hc *halfConn) decrypt(b *block) (bool, alert) {
// pull out payload
payload := b.data[recordHeaderLen:]
+ macSize := 0
+ if hc.mac != nil {
+ macSize = hc.mac.Size()
+ }
+
+ paddingGood := byte(255)
+
// decrypt
- if hc.crypt != nil {
- hc.crypt.XORKeyStream(payload)
+ if hc.cipher != nil {
+ switch c := hc.cipher.(type) {
+ case cipher.Stream:
+ c.XORKeyStream(payload, payload)
+ case cipher.BlockMode:
+ blockSize := c.BlockSize()
+
+ if len(payload)%blockSize != 0 || len(payload) < roundUp(macSize+1, blockSize) {
+ return false, alertBadRecordMAC
+ }
+
+ c.CryptBlocks(payload, payload)
+ payload, paddingGood = removePadding(payload)
+ b.resize(recordHeaderLen + len(payload))
+
+ // note that we still have a timing side-channel in the
+ // MAC check, below. An attacker can align the record
+ // so that a correct padding will cause one less hash
+ // block to be calculated. Then they can iteratively
+ // decrypt a record by breaking each byte. See
+ // "Password Interception in a SSL/TLS Channel", Brice
+ // Canvel et al.
+ //
+ // However, our behaviour matches OpenSSL, so we leak
+ // only as much as they do.
+ default:
+ panic("unknown cipher type")
+ }
}
// check, strip mac
if hc.mac != nil {
- if len(payload) < hc.mac.Size() {
+ if len(payload) < macSize {
return false, alertBadRecordMAC
}
// strip mac off payload, b.data
- n := len(payload) - hc.mac.Size()
+ n := len(payload) - macSize
b.data[3] = byte(n >> 8)
b.data[4] = byte(n)
- b.data = b.data[0 : recordHeaderLen+n]
+ b.resize(recordHeaderLen + n)
remoteMAC := payload[n:]
hc.mac.Reset()
@@ -175,7 +258,7 @@ func (hc *halfConn) decrypt(b *block) (bool, alert) {
hc.incSeq()
hc.mac.Write(b.data)
- if subtle.ConstantTimeCompare(hc.mac.Sum(), remoteMAC) != 1 {
+ if subtle.ConstantTimeCompare(hc.mac.Sum(), remoteMAC) != 1 || paddingGood != 255 {
return false, alertBadRecordMAC
}
}
@@ -183,6 +266,23 @@ func (hc *halfConn) decrypt(b *block) (bool, alert) {
return true, 0
}
+// padToBlockSize calculates the needed padding block, if any, for a payload.
+// On exit, prefix aliases payload and extends to the end of the last full
+// block of payload. finalBlock is a fresh slice which contains the contents of
+// any suffix of payload as well as the needed padding to make finalBlock a
+// full block.
+func padToBlockSize(payload []byte, blockSize int) (prefix, finalBlock []byte) {
+ overrun := len(payload) % blockSize
+ paddingLen := blockSize - overrun
+ prefix = payload[:len(payload)-overrun]
+ finalBlock = make([]byte, blockSize)
+ copy(finalBlock, payload[len(payload)-overrun:])
+ for i := overrun; i < blockSize; i++ {
+ finalBlock[i] = byte(paddingLen - 1)
+ }
+ return
+}
+
// encrypt encrypts and macs the data in b.
func (hc *halfConn) encrypt(b *block) (bool, alert) {
// mac
@@ -195,18 +295,30 @@ func (hc *halfConn) encrypt(b *block) (bool, alert) {
n := len(b.data)
b.resize(n + len(mac))
copy(b.data[n:], mac)
-
- // update length to include mac
- n = len(b.data) - recordHeaderLen
- b.data[3] = byte(n >> 8)
- b.data[4] = byte(n)
}
+ payload := b.data[recordHeaderLen:]
+
// encrypt
- if hc.crypt != nil {
- hc.crypt.XORKeyStream(b.data[recordHeaderLen:])
+ if hc.cipher != nil {
+ switch c := hc.cipher.(type) {
+ case cipher.Stream:
+ c.XORKeyStream(payload, payload)
+ case cipher.BlockMode:
+ prefix, finalBlock := padToBlockSize(payload, c.BlockSize())
+ b.resize(recordHeaderLen + len(prefix) + len(finalBlock))
+ c.CryptBlocks(b.data[recordHeaderLen:], prefix)
+ c.CryptBlocks(b.data[recordHeaderLen+len(prefix):], finalBlock)
+ default:
+ panic("unknown cipher type")
+ }
}
+ // update length to include MAC and any block padding needed.
+ n := len(b.data) - recordHeaderLen
+ b.data[3] = byte(n >> 8)
+ b.data[4] = byte(n)
+
return true, 0
}
@@ -442,7 +554,11 @@ func (c *Conn) sendAlertLocked(err alert) os.Error {
}
c.tmp[1] = byte(err)
c.writeRecord(recordTypeAlert, c.tmp[0:2])
- return c.setError(&net.OpError{Op: "local error", Error: err})
+ // closeNotify is a special case in that it isn't an error:
+ if err != alertCloseNotify {
+ return c.setError(&net.OpError{Op: "local error", Error: err})
+ }
+ return nil
}
// sendAlert sends a TLS alert message.
@@ -531,10 +647,18 @@ func (c *Conn) readHandshake() (interface{}, os.Error) {
m = new(serverHelloMsg)
case typeCertificate:
m = new(certificateMsg)
+ case typeCertificateRequest:
+ m = new(certificateRequestMsg)
+ case typeCertificateStatus:
+ m = new(certificateStatusMsg)
+ case typeServerKeyExchange:
+ m = new(serverKeyExchangeMsg)
case typeServerHelloDone:
m = new(serverHelloDoneMsg)
case typeClientKeyExchange:
m = new(clientKeyExchangeMsg)
+ case typeCertificateVerify:
+ m = new(certificateVerifyMsg)
case typeNextProtocol:
m = new(nextProtoMsg)
case typeFinished:
@@ -547,7 +671,7 @@ func (c *Conn) readHandshake() (interface{}, os.Error) {
// The handshake message unmarshallers
// expect to be able to keep references to data,
// so pass in a fresh copy that won't be overwritten.
- data = bytes.Add(nil, data)
+ data = append([]byte(nil), data...)
if !m.unmarshal(data) {
c.sendAlert(alertUnexpectedMessage)
@@ -585,7 +709,10 @@ func (c *Conn) Read(b []byte) (n int, err os.Error) {
defer c.in.Unlock()
for c.input == nil && c.err == nil {
- c.readRecord(recordTypeApplicationData)
+ if err := c.readRecord(recordTypeApplicationData); err != nil {
+ // Soft error, like EAGAIN
+ return 0, err
+ }
}
if c.err != nil {
return 0, c.err
@@ -608,7 +735,7 @@ func (c *Conn) Close() os.Error {
// Handshake runs the client or server handshake
// protocol if it has not yet been run.
-// Most uses of this packge need not call Handshake
+// Most uses of this package need not call Handshake
// explicitly: the first Read or Write will call it automatically.
func (c *Conn) Handshake() os.Error {
c.handshakeMutex.Lock()
@@ -625,11 +752,50 @@ func (c *Conn) Handshake() os.Error {
return c.serverHandshake()
}
-// If c is a TLS server, ClientConnection returns the protocol
-// requested by the client during the TLS handshake.
-// Handshake must have been called already.
-func (c *Conn) ClientConnection() string {
+// ConnectionState returns basic TLS details about the connection.
+func (c *Conn) ConnectionState() ConnectionState {
+ c.handshakeMutex.Lock()
+ defer c.handshakeMutex.Unlock()
+
+ var state ConnectionState
+ state.HandshakeComplete = c.handshakeComplete
+ if c.handshakeComplete {
+ state.NegotiatedProtocol = c.clientProtocol
+ state.CipherSuite = c.cipherSuite
+ }
+
+ return state
+}
+
+// OCSPResponse returns the stapled OCSP response from the TLS server, if
+// any. (Only valid for client connections.)
+func (c *Conn) OCSPResponse() []byte {
c.handshakeMutex.Lock()
defer c.handshakeMutex.Unlock()
- return c.clientProtocol
+
+ return c.ocspResponse
+}
+
+// PeerCertificates returns the certificate chain that was presented by the
+// other side.
+func (c *Conn) PeerCertificates() []*x509.Certificate {
+ c.handshakeMutex.Lock()
+ defer c.handshakeMutex.Unlock()
+
+ return c.peerCertificates
+}
+
+// VerifyHostname checks that the peer certificate chain is valid for
+// connecting to host. If so, it returns nil; if not, it returns an os.Error
+// describing the problem.
+func (c *Conn) VerifyHostname(host string) os.Error {
+ c.handshakeMutex.Lock()
+ defer c.handshakeMutex.Unlock()
+ if !c.isClient {
+ return os.ErrorString("VerifyHostname called on TLS server connection")
+ }
+ if !c.handshakeComplete {
+ return os.ErrorString("TLS handshake has not yet been performed")
+ }
+ return c.peerCertificates[0].VerifyHostname(host)
}
diff --git a/src/pkg/crypto/tls/conn_test.go b/src/pkg/crypto/tls/conn_test.go
new file mode 100644
index 000000000..f44a50bed
--- /dev/null
+++ b/src/pkg/crypto/tls/conn_test.go
@@ -0,0 +1,52 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+ "testing"
+)
+
+func TestRoundUp(t *testing.T) {
+ if roundUp(0, 16) != 0 ||
+ roundUp(1, 16) != 16 ||
+ roundUp(15, 16) != 16 ||
+ roundUp(16, 16) != 16 ||
+ roundUp(17, 16) != 32 {
+ t.Error("roundUp broken")
+ }
+}
+
+var paddingTests = []struct {
+ in []byte
+ good bool
+ expectedLen int
+}{
+ {[]byte{1, 2, 3, 4, 0}, true, 4},
+ {[]byte{1, 2, 3, 4, 0, 1}, false, 0},
+ {[]byte{1, 2, 3, 4, 99, 99}, false, 0},
+ {[]byte{1, 2, 3, 4, 1, 1}, true, 4},
+ {[]byte{1, 2, 3, 2, 2, 2}, true, 3},
+ {[]byte{1, 2, 3, 3, 3, 3}, true, 2},
+ {[]byte{1, 2, 3, 4, 3, 3}, false, 0},
+ {[]byte{1, 4, 4, 4, 4, 4}, true, 1},
+ {[]byte{5, 5, 5, 5, 5, 5}, true, 0},
+ {[]byte{6, 6, 6, 6, 6, 6}, false, 0},
+}
+
+func TestRemovePadding(t *testing.T) {
+ for i, test := range paddingTests {
+ payload, good := removePadding(test.in)
+ expectedGood := byte(255)
+ if !test.good {
+ expectedGood = 0
+ }
+ if good != expectedGood {
+ t.Errorf("#%d: wrong validity, want:%d got:%d", i, expectedGood, good)
+ }
+ if good == 255 && len(payload) != test.expectedLen {
+ t.Errorf("#%d: got %d, want %d", i, len(payload), test.expectedLen)
+ }
+ }
+}
diff --git a/src/pkg/crypto/tls/generate_cert.go b/src/pkg/crypto/tls/generate_cert.go
new file mode 100644
index 000000000..3e0c63938
--- /dev/null
+++ b/src/pkg/crypto/tls/generate_cert.go
@@ -0,0 +1,70 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Generate a self-signed X.509 certificate for a TLS server. Outputs to
+// 'cert.pem' and 'key.pem' and will overwrite existing files.
+
+package main
+
+import (
+ "crypto/rsa"
+ "crypto/rand"
+ "crypto/x509"
+ "encoding/pem"
+ "flag"
+ "log"
+ "os"
+ "time"
+)
+
+var hostName *string = flag.String("host", "127.0.0.1", "Hostname to generate a certificate for")
+
+func main() {
+ flag.Parse()
+
+ priv, err := rsa.GenerateKey(rand.Reader, 1024)
+ if err != nil {
+ log.Exitf("failed to generate private key: %s", err)
+ return
+ }
+
+ now := time.Seconds()
+
+ template := x509.Certificate{
+ SerialNumber: []byte{0},
+ Subject: x509.Name{
+ CommonName: *hostName,
+ Organization: []string{"Acme Co"},
+ },
+ NotBefore: time.SecondsToUTC(now - 300),
+ NotAfter: time.SecondsToUTC(now + 60*60*24*365), // valid for 1 year.
+
+ SubjectKeyId: []byte{1, 2, 3, 4},
+ KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
+ }
+
+ derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
+ if err != nil {
+ log.Exitf("Failed to create certificate: %s", err)
+ return
+ }
+
+ certOut, err := os.Open("cert.pem", os.O_WRONLY|os.O_CREAT, 0644)
+ if err != nil {
+ log.Exitf("failed to open cert.pem for writing: %s", err)
+ return
+ }
+ pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
+ certOut.Close()
+ log.Print("written cert.pem\n")
+
+ keyOut, err := os.Open("key.pem", os.O_WRONLY|os.O_CREAT, 0600)
+ if err != nil {
+ log.Print("failed to open key.pem for writing:", err)
+ return
+ }
+ pem.Encode(keyOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)})
+ keyOut.Close()
+ log.Print("written key.pem\n")
+}
diff --git a/src/pkg/crypto/tls/handshake_client.go b/src/pkg/crypto/tls/handshake_client.go
index dd3009802..1ca33f59d 100644
--- a/src/pkg/crypto/tls/handshake_client.go
+++ b/src/pkg/crypto/tls/handshake_client.go
@@ -5,10 +5,7 @@
package tls
import (
- "crypto/hmac"
- "crypto/rc4"
"crypto/rsa"
- "crypto/sha1"
"crypto/subtle"
"crypto/x509"
"io"
@@ -18,23 +15,30 @@ import (
func (c *Conn) clientHandshake() os.Error {
finishedHash := newFinishedHash()
- config := defaultConfig()
+ if c.config == nil {
+ c.config = defaultConfig()
+ }
hello := &clientHelloMsg{
vers: maxVersion,
- cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
+ cipherSuites: c.config.cipherSuites(),
compressionMethods: []uint8{compressionNone},
random: make([]byte, 32),
+ ocspStapling: true,
+ serverName: c.config.ServerName,
+ supportedCurves: []uint16{curveP256, curveP384, curveP521},
+ supportedPoints: []uint8{pointFormatUncompressed},
}
- t := uint32(config.Time())
+ t := uint32(c.config.time())
hello.random[0] = byte(t >> 24)
hello.random[1] = byte(t >> 16)
hello.random[2] = byte(t >> 8)
hello.random[3] = byte(t)
- _, err := io.ReadFull(config.Rand, hello.random[4:])
+ _, err := io.ReadFull(c.config.rand(), hello.random[4:])
if err != nil {
- return c.sendAlert(alertInternalError)
+ c.sendAlert(alertInternalError)
+ return os.ErrorString("short read from Rand")
}
finishedHash.Write(hello.marshal())
@@ -57,11 +61,15 @@ func (c *Conn) clientHandshake() os.Error {
c.vers = vers
c.haveVers = true
- if serverHello.cipherSuite != TLS_RSA_WITH_RC4_128_SHA ||
- serverHello.compressionMethod != compressionNone {
+ if serverHello.compressionMethod != compressionNone {
return c.sendAlert(alertUnexpectedMessage)
}
+ suite, suiteId := mutualCipherSuite(c.config.cipherSuites(), serverHello.cipherSuite)
+ if suite == nil {
+ return c.sendAlert(alertHandshakeFailure)
+ }
+
msg, err = c.readHandshake()
if err != nil {
return err
@@ -73,71 +81,189 @@ func (c *Conn) clientHandshake() os.Error {
finishedHash.Write(certMsg.marshal())
certs := make([]*x509.Certificate, len(certMsg.certificates))
+ chain := NewCASet()
for i, asn1Data := range certMsg.certificates {
cert, err := x509.ParseCertificate(asn1Data)
if err != nil {
- return c.sendAlert(alertBadCertificate)
+ c.sendAlert(alertBadCertificate)
+ return os.ErrorString("failed to parse certificate from server: " + err.String())
}
certs[i] = cert
+ chain.AddCert(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 {
- return c.sendAlert(alertBadCertificate)
+ // If we don't have a root CA set configured then anything is accepted.
+ // TODO(rsc): Find certificates for OS X 10.6.
+ for cur := certs[0]; c.config.RootCAs != nil; {
+ parent := c.config.RootCAs.FindVerifiedParent(cur)
+ if parent != nil {
+ break
}
- }
- // TODO(rsc): Find certificates for OS X 10.6.
- if false && config.RootCAs != nil {
- root := config.RootCAs.FindParent(certs[len(certs)-1])
- if root == nil {
- return c.sendAlert(alertBadCertificate)
+ parent = chain.FindVerifiedParent(cur)
+ if parent == nil {
+ c.sendAlert(alertBadCertificate)
+ return os.ErrorString("could not find root certificate for chain")
}
- if certs[len(certs)-1].CheckSignatureFrom(root) != nil {
- return c.sendAlert(alertBadCertificate)
+
+ if !parent.BasicConstraintsValid || !parent.IsCA {
+ c.sendAlert(alertBadCertificate)
+ return os.ErrorString("intermediate certificate does not have CA bit set")
}
+ // KeyUsage status flags are ignored. From Engineering
+ // Security, Peter Gutmann: A European government CA marked its
+ // signing certificates as being valid for encryption only, but
+ // no-one noticed. Another European CA marked its signature
+ // keys as not being valid for signatures. A different CA
+ // marked its own trusted root certificate as being invalid for
+ // certificate signing. Another national CA distributed a
+ // certificate to be used to encrypt data for the country’s tax
+ // authority that was marked as only being usable for digital
+ // signatures but not for encryption. Yet another CA reversed
+ // the order of the bit flags in the keyUsage due to confusion
+ // over encoding endianness, essentially setting a random
+ // keyUsage in certificates that it issued. Another CA created
+ // a self-invalidating certificate by adding a certificate
+ // policy statement stipulating that the certificate had to be
+ // used strictly as specified in the keyUsage, and a keyUsage
+ // containing a flag indicating that the RSA encryption key
+ // could only be used for Diffie-Hellman key agreement.
+
+ cur = parent
}
- pub, ok := certs[0].PublicKey.(*rsa.PublicKey)
- if !ok {
+ if _, ok := certs[0].PublicKey.(*rsa.PublicKey); !ok {
return c.sendAlert(alertUnsupportedCertificate)
}
+ c.peerCertificates = certs
+
+ if serverHello.certStatus {
+ msg, err = c.readHandshake()
+ if err != nil {
+ return err
+ }
+ cs, ok := msg.(*certificateStatusMsg)
+ if !ok {
+ return c.sendAlert(alertUnexpectedMessage)
+ }
+ finishedHash.Write(cs.marshal())
+
+ if cs.statusType == statusTypeOCSP {
+ c.ocspResponse = cs.response
+ }
+ }
+
msg, err = c.readHandshake()
if err != nil {
return err
}
+
+ keyAgreement := suite.ka()
+
+ skx, ok := msg.(*serverKeyExchangeMsg)
+ if ok {
+ finishedHash.Write(skx.marshal())
+ err = keyAgreement.processServerKeyExchange(c.config, hello, serverHello, certs[0], skx)
+ if err != nil {
+ c.sendAlert(alertUnexpectedMessage)
+ return err
+ }
+
+ msg, err = c.readHandshake()
+ if err != nil {
+ return err
+ }
+ }
+
+ transmitCert := false
+ certReq, ok := msg.(*certificateRequestMsg)
+ if ok {
+ // We only accept certificates with RSA keys.
+ rsaAvail := false
+ for _, certType := range certReq.certificateTypes {
+ if certType == certTypeRSASign {
+ rsaAvail = true
+ break
+ }
+ }
+
+ // For now, only send a certificate back if the server gives us an
+ // empty list of certificateAuthorities.
+ //
+ // RFC 4346 on the certificateAuthorities field:
+ // A list of the distinguished names of acceptable certificate
+ // authorities. These distinguished names may specify a desired
+ // distinguished name for a root CA or for a subordinate CA; thus,
+ // this message can be used to describe both known roots and a
+ // desired authorization space. If the certificate_authorities
+ // list is empty then the client MAY send any certificate of the
+ // appropriate ClientCertificateType, unless there is some
+ // external arrangement to the contrary.
+ if rsaAvail && len(certReq.certificateAuthorities) == 0 {
+ transmitCert = true
+ }
+
+ finishedHash.Write(certReq.marshal())
+
+ msg, err = c.readHandshake()
+ if err != nil {
+ return err
+ }
+ }
+
shd, ok := msg.(*serverHelloDoneMsg)
if !ok {
return c.sendAlert(alertUnexpectedMessage)
}
finishedHash.Write(shd.marshal())
- ckx := new(clientKeyExchangeMsg)
- preMasterSecret := make([]byte, 48)
- preMasterSecret[0] = byte(hello.vers >> 8)
- preMasterSecret[1] = byte(hello.vers)
- _, err = io.ReadFull(config.Rand, preMasterSecret[2:])
- if err != nil {
- return c.sendAlert(alertInternalError)
+ var cert *x509.Certificate
+ if transmitCert {
+ certMsg = new(certificateMsg)
+ if len(c.config.Certificates) > 0 {
+ cert, err = x509.ParseCertificate(c.config.Certificates[0].Certificate[0])
+ if err == nil && cert.PublicKeyAlgorithm == x509.RSA {
+ certMsg.certificates = c.config.Certificates[0].Certificate
+ } else {
+ cert = nil
+ }
+ }
+ finishedHash.Write(certMsg.marshal())
+ c.writeRecord(recordTypeHandshake, certMsg.marshal())
}
- ckx.ciphertext, err = rsa.EncryptPKCS1v15(config.Rand, pub, preMasterSecret)
+ preMasterSecret, ckx, err := keyAgreement.generateClientKeyExchange(c.config, hello, certs[0])
if err != nil {
- return c.sendAlert(alertInternalError)
+ c.sendAlert(alertInternalError)
+ return err
+ }
+ if ckx != nil {
+ finishedHash.Write(ckx.marshal())
+ c.writeRecord(recordTypeHandshake, ckx.marshal())
}
- finishedHash.Write(ckx.marshal())
- c.writeRecord(recordTypeHandshake, ckx.marshal())
+ if cert != nil {
+ certVerify := new(certificateVerifyMsg)
+ var digest [36]byte
+ copy(digest[0:16], finishedHash.serverMD5.Sum())
+ copy(digest[16:36], finishedHash.serverSHA1.Sum())
+ signed, err := rsa.SignPKCS1v15(c.config.rand(), c.config.Certificates[0].PrivateKey, rsa.HashMD5SHA1, digest[0:])
+ if err != nil {
+ return c.sendAlert(alertInternalError)
+ }
+ certVerify.signature = signed
- suite := cipherSuites[0]
- masterSecret, clientMAC, serverMAC, clientKey, serverKey :=
- keysFromPreMasterSecret11(preMasterSecret, hello.random, serverHello.random, suite.hashLength, suite.cipherKeyLength)
+ finishedHash.Write(certVerify.marshal())
+ c.writeRecord(recordTypeHandshake, certVerify.marshal())
+ }
- cipher, _ := rc4.NewCipher(clientKey)
+ masterSecret, clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV :=
+ keysFromPreMasterSecret10(preMasterSecret, hello.random, serverHello.random, suite.macLen, suite.keyLen, suite.ivLen)
- c.out.prepareCipherSpec(cipher, hmac.New(sha1.New(), clientMAC))
+ clientCipher := suite.cipher(clientKey, clientIV, false /* not for reading */ )
+ clientHash := suite.mac(clientMAC)
+ c.out.prepareCipherSpec(clientCipher, clientHash)
c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
finished := new(finishedMsg)
@@ -145,8 +271,9 @@ func (c *Conn) clientHandshake() os.Error {
finishedHash.Write(finished.marshal())
c.writeRecord(recordTypeHandshake, finished.marshal())
- cipher2, _ := rc4.NewCipher(serverKey)
- c.in.prepareCipherSpec(cipher2, hmac.New(sha1.New(), serverMAC))
+ serverCipher := suite.cipher(serverKey, serverIV, true /* for reading */ )
+ serverHash := suite.mac(serverMAC)
+ c.in.prepareCipherSpec(serverCipher, serverHash)
c.readRecord(recordTypeChangeCipherSpec)
if c.err != nil {
return c.err
@@ -168,6 +295,6 @@ func (c *Conn) clientHandshake() os.Error {
}
c.handshakeComplete = true
- c.cipherSuite = TLS_RSA_WITH_RC4_128_SHA
+ c.cipherSuite = suiteId
return nil
}
diff --git a/src/pkg/crypto/tls/handshake_client_test.go b/src/pkg/crypto/tls/handshake_client_test.go
new file mode 100644
index 000000000..e5c9684b9
--- /dev/null
+++ b/src/pkg/crypto/tls/handshake_client_test.go
@@ -0,0 +1,211 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+ "bytes"
+ "flag"
+ "io"
+ "net"
+ "testing"
+)
+
+func testClientScript(t *testing.T, name string, clientScript [][]byte, config *Config) {
+ c, s := net.Pipe()
+ cli := Client(c, config)
+ go func() {
+ cli.Write([]byte("hello\n"))
+ cli.Close()
+ }()
+
+ defer c.Close()
+ for i, b := range clientScript {
+ if i%2 == 1 {
+ s.Write(b)
+ continue
+ }
+ bb := make([]byte, len(b))
+ _, err := io.ReadFull(s, bb)
+ if err != nil {
+ t.Fatalf("%s #%d: %s", name, i, err)
+ }
+ if !bytes.Equal(b, bb) {
+ t.Fatalf("%s #%d: mismatch on read: got:%x want:%x", name, i, bb, b)
+ }
+ }
+}
+
+func TestHandshakeClientRC4(t *testing.T) {
+ testClientScript(t, "RC4", rc4ClientScript, testConfig)
+}
+
+var connect = flag.Bool("connect", false, "connect to a TLS server on :10443")
+
+func TestRunClient(t *testing.T) {
+ if !*connect {
+ return
+ }
+
+ testConfig.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_RC4_128_SHA}
+
+ conn, err := Dial("tcp", "", "127.0.0.1:10443", testConfig)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ conn.Write([]byte("hello\n"))
+ conn.Close()
+}
+
+// Script of interaction with gnutls implementation.
+// The values for this test are obtained by building and running in client mode:
+// % gotest -match "TestRunClient" -connect
+// and then:
+// % gnutls-serv -p 10443 --debug 100 --x509keyfile key.pem --x509certfile cert.pem -a > /tmp/log 2>&1
+// % python parse-gnutls-cli-debug-log.py < /tmp/log
+//
+// Where key.pem is:
+// -----BEGIN RSA PRIVATE KEY-----
+// MIIBPAIBAAJBAJ+zw4Qnlf8SMVIPFe9GEcStgOY2Ww/dgNdhjeD8ckUJNP5VZkVD
+// TGiXav6ooKXfX3j/7tdkuD8Ey2//Kv7+ue0CAwEAAQJAN6W31vDEP2DjdqhzCDDu
+// OA4NACqoiFqyblo7yc2tM4h4xMbC3Yx5UKMN9ZkCtX0gzrz6DyF47bdKcWBzNWCj
+// gQIhANEoojVt7hq+SQ6MCN6FTAysGgQf56Q3TYoJMoWvdiXVAiEAw3e3rc+VJpOz
+// rHuDo6bgpjUAAXM+v3fcpsfZSNO6V7kCIQCtbVjanpUwvZkMI9by02oUk9taki3b
+// PzPfAfNPYAbCJQIhAJXNQDWyqwn/lGmR11cqY2y9nZ1+5w3yHGatLrcDnQHxAiEA
+// vnlEGo8K85u+KwIOimM48ZG8oTk7iFdkqLJR1utT3aU=
+// -----END RSA PRIVATE KEY-----
+//
+// and cert.pem is:
+// -----BEGIN CERTIFICATE-----
+// MIIBoDCCAUoCAQAwDQYJKoZIhvcNAQEEBQAwYzELMAkGA1UEBhMCQVUxEzARBgNV
+// BAgTClF1ZWVuc2xhbmQxGjAYBgNVBAoTEUNyeXB0U29mdCBQdHkgTHRkMSMwIQYD
+// VQQDExpTZXJ2ZXIgdGVzdCBjZXJ0ICg1MTIgYml0KTAeFw05NzA5MDkwMzQxMjZa
+// Fw05NzEwMDkwMzQxMjZaMF4xCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0
+// YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxFzAVBgNVBAMT
+// DkVyaWMgdGhlIFlvdW5nMFEwCQYFKw4DAgwFAANEAAJBALVEqPODnpI4rShlY8S7
+// tB713JNvabvn6Gned7zylwLLiXQAo/PAT6mfdWPTyCX9RlId/Aroh1ou893BA32Q
+// sggwDQYJKoZIhvcNAQEEBQADQQCU5SSgapJSdRXJoX+CpCvFy+JVh9HpSjCpSNKO
+// 19raHv98hKAUJuP9HyM+SUsffO6mAIgitUaqW8/wDMePhEC3
+// -----END CERTIFICATE-----
+var rc4ClientScript = [][]byte{
+ {
+ 0x16, 0x03, 0x01, 0x00, 0x4a, 0x01, 0x00, 0x00,
+ 0x46, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x05,
+ 0x01, 0x00, 0x00, 0x1b, 0x00, 0x05, 0x00, 0x05,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
+ 0x08, 0x00, 0x06, 0x00, 0x17, 0x00, 0x18, 0x00,
+ 0x19, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00,
+ },
+
+ {
+ 0x16, 0x03, 0x01, 0x00, 0x4a, 0x02, 0x00, 0x00,
+ 0x46, 0x03, 0x01, 0x4d, 0x0a, 0x56, 0x16, 0xb5,
+ 0x91, 0xd1, 0xcb, 0x80, 0x4d, 0xc7, 0x46, 0xf3,
+ 0x37, 0x0c, 0xef, 0xea, 0x64, 0x11, 0x14, 0x56,
+ 0x97, 0x9b, 0xc5, 0x67, 0x08, 0xb7, 0x13, 0xea,
+ 0xf8, 0xc9, 0xb3, 0x20, 0xe2, 0xfc, 0x41, 0xf6,
+ 0x96, 0x90, 0x9d, 0x43, 0x9b, 0xe9, 0x6e, 0xf8,
+ 0x41, 0x16, 0xcc, 0xf3, 0xc7, 0xde, 0xda, 0x5a,
+ 0xa1, 0x33, 0x69, 0xe2, 0xde, 0x5b, 0xaf, 0x2a,
+ 0x92, 0xe7, 0xd4, 0xa0, 0x00, 0x05, 0x00, 0x16,
+ 0x03, 0x01, 0x01, 0xf7, 0x0b, 0x00, 0x01, 0xf3,
+ 0x00, 0x01, 0xf0, 0x00, 0x01, 0xed, 0x30, 0x82,
+ 0x01, 0xe9, 0x30, 0x82, 0x01, 0x52, 0x02, 0x01,
+ 0x06, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
+ 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x04, 0x05, 0x00,
+ 0x30, 0x5b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
+ 0x55, 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31,
+ 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08,
+ 0x13, 0x0a, 0x51, 0x75, 0x65, 0x65, 0x6e, 0x73,
+ 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x1a, 0x30, 0x18,
+ 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x11, 0x43,
+ 0x72, 0x79, 0x70, 0x74, 0x53, 0x6f, 0x66, 0x74,
+ 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64,
+ 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04,
+ 0x03, 0x13, 0x12, 0x54, 0x65, 0x73, 0x74, 0x20,
+ 0x43, 0x41, 0x20, 0x28, 0x31, 0x30, 0x32, 0x34,
+ 0x20, 0x62, 0x69, 0x74, 0x29, 0x30, 0x1e, 0x17,
+ 0x0d, 0x30, 0x30, 0x31, 0x30, 0x31, 0x36, 0x32,
+ 0x32, 0x33, 0x31, 0x30, 0x33, 0x5a, 0x17, 0x0d,
+ 0x30, 0x33, 0x30, 0x31, 0x31, 0x34, 0x32, 0x32,
+ 0x33, 0x31, 0x30, 0x33, 0x5a, 0x30, 0x63, 0x31,
+ 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
+ 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
+ 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x51,
+ 0x75, 0x65, 0x65, 0x6e, 0x73, 0x6c, 0x61, 0x6e,
+ 0x64, 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55,
+ 0x04, 0x0a, 0x13, 0x11, 0x43, 0x72, 0x79, 0x70,
+ 0x74, 0x53, 0x6f, 0x66, 0x74, 0x20, 0x50, 0x74,
+ 0x79, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x23, 0x30,
+ 0x21, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x1a,
+ 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x74,
+ 0x65, 0x73, 0x74, 0x20, 0x63, 0x65, 0x72, 0x74,
+ 0x20, 0x28, 0x35, 0x31, 0x32, 0x20, 0x62, 0x69,
+ 0x74, 0x29, 0x30, 0x5c, 0x30, 0x0d, 0x06, 0x09,
+ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+ 0x01, 0x05, 0x00, 0x03, 0x4b, 0x00, 0x30, 0x48,
+ 0x02, 0x41, 0x00, 0x9f, 0xb3, 0xc3, 0x84, 0x27,
+ 0x95, 0xff, 0x12, 0x31, 0x52, 0x0f, 0x15, 0xef,
+ 0x46, 0x11, 0xc4, 0xad, 0x80, 0xe6, 0x36, 0x5b,
+ 0x0f, 0xdd, 0x80, 0xd7, 0x61, 0x8d, 0xe0, 0xfc,
+ 0x72, 0x45, 0x09, 0x34, 0xfe, 0x55, 0x66, 0x45,
+ 0x43, 0x4c, 0x68, 0x97, 0x6a, 0xfe, 0xa8, 0xa0,
+ 0xa5, 0xdf, 0x5f, 0x78, 0xff, 0xee, 0xd7, 0x64,
+ 0xb8, 0x3f, 0x04, 0xcb, 0x6f, 0xff, 0x2a, 0xfe,
+ 0xfe, 0xb9, 0xed, 0x02, 0x03, 0x01, 0x00, 0x01,
+ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+ 0xf7, 0x0d, 0x01, 0x01, 0x04, 0x05, 0x00, 0x03,
+ 0x81, 0x81, 0x00, 0x93, 0xd2, 0x0a, 0xc5, 0x41,
+ 0xe6, 0x5a, 0xa9, 0x86, 0xf9, 0x11, 0x87, 0xe4,
+ 0xdb, 0x45, 0xe2, 0xc5, 0x95, 0x78, 0x1a, 0x6c,
+ 0x80, 0x6d, 0x73, 0x1f, 0xb4, 0x6d, 0x44, 0xa3,
+ 0xba, 0x86, 0x88, 0xc8, 0x58, 0xcd, 0x1c, 0x06,
+ 0x35, 0x6c, 0x44, 0x62, 0x88, 0xdf, 0xe4, 0xf6,
+ 0x64, 0x61, 0x95, 0xef, 0x4a, 0xa6, 0x7f, 0x65,
+ 0x71, 0xd7, 0x6b, 0x88, 0x39, 0xf6, 0x32, 0xbf,
+ 0xac, 0x93, 0x67, 0x69, 0x51, 0x8c, 0x93, 0xec,
+ 0x48, 0x5f, 0xc9, 0xb1, 0x42, 0xf9, 0x55, 0xd2,
+ 0x7e, 0x4e, 0xf4, 0xf2, 0x21, 0x6b, 0x90, 0x57,
+ 0xe6, 0xd7, 0x99, 0x9e, 0x41, 0xca, 0x80, 0xbf,
+ 0x1a, 0x28, 0xa2, 0xca, 0x5b, 0x50, 0x4a, 0xed,
+ 0x84, 0xe7, 0x82, 0xc7, 0xd2, 0xcf, 0x36, 0x9e,
+ 0x6a, 0x67, 0xb9, 0x88, 0xa7, 0xf3, 0x8a, 0xd0,
+ 0x04, 0xf8, 0xe8, 0xc6, 0x17, 0xe3, 0xc5, 0x29,
+ 0xbc, 0x17, 0xf1, 0x16, 0x03, 0x01, 0x00, 0x04,
+ 0x0e, 0x00, 0x00, 0x00,
+ },
+
+ {
+ 0x16, 0x03, 0x01, 0x00, 0x46, 0x10, 0x00, 0x00,
+ 0x42, 0x00, 0x40, 0x87, 0xa1, 0x1f, 0x14, 0xe1,
+ 0xfb, 0x91, 0xac, 0x58, 0x2e, 0xf3, 0x71, 0xce,
+ 0x01, 0x85, 0x2c, 0xc7, 0xfe, 0x84, 0x87, 0x82,
+ 0xb7, 0x57, 0xdb, 0x37, 0x4d, 0x46, 0x83, 0x67,
+ 0x52, 0x82, 0x51, 0x01, 0x95, 0x23, 0x68, 0x69,
+ 0x6b, 0xd0, 0xa7, 0xa7, 0xe5, 0x88, 0xd0, 0x47,
+ 0x71, 0xb8, 0xd2, 0x03, 0x05, 0x25, 0x56, 0x5c,
+ 0x10, 0x08, 0xc6, 0x9b, 0xd4, 0x67, 0xcd, 0x28,
+ 0xbe, 0x9c, 0x48, 0x14, 0x03, 0x01, 0x00, 0x01,
+ 0x01, 0x16, 0x03, 0x01, 0x00, 0x24, 0xc1, 0xb8,
+ 0xd3, 0x7f, 0xc5, 0xc2, 0x5a, 0x1d, 0x6d, 0x5b,
+ 0x2d, 0x5c, 0x82, 0x87, 0xc2, 0x6f, 0x0d, 0x63,
+ 0x7b, 0x72, 0x2b, 0xda, 0x69, 0xc4, 0xfe, 0x3c,
+ 0x84, 0xa1, 0x5a, 0x62, 0x38, 0x37, 0xc6, 0x54,
+ 0x25, 0x2a,
+ },
+
+ {
+ 0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03,
+ 0x01, 0x00, 0x24, 0xea, 0x88, 0x9c, 0x00, 0xf6,
+ 0x35, 0xb8, 0x42, 0x7f, 0x15, 0x17, 0x76, 0x5e,
+ 0x4b, 0x24, 0xcb, 0x7e, 0xa0, 0x7b, 0xc3, 0x70,
+ 0x52, 0x0a, 0x88, 0x2a, 0x7a, 0x45, 0x59, 0x90,
+ 0x59, 0xac, 0xc6, 0xb5, 0x56, 0x55, 0x96,
+ },
+}
diff --git a/src/pkg/crypto/tls/handshake_messages.go b/src/pkg/crypto/tls/handshake_messages.go
index f0a48c863..e5e856271 100644
--- a/src/pkg/crypto/tls/handshake_messages.go
+++ b/src/pkg/crypto/tls/handshake_messages.go
@@ -13,6 +13,9 @@ type clientHelloMsg struct {
compressionMethods []uint8
nextProtoNeg bool
serverName string
+ ocspStapling bool
+ supportedCurves []uint16
+ supportedPoints []uint8
}
func (m *clientHelloMsg) marshal() []byte {
@@ -26,10 +29,22 @@ func (m *clientHelloMsg) marshal() []byte {
if m.nextProtoNeg {
numExtensions++
}
+ if m.ocspStapling {
+ extensionsLength += 1 + 2 + 2
+ numExtensions++
+ }
if len(m.serverName) > 0 {
extensionsLength += 5 + len(m.serverName)
numExtensions++
}
+ if len(m.supportedCurves) > 0 {
+ extensionsLength += 2 + 2*len(m.supportedCurves)
+ numExtensions++
+ }
+ if len(m.supportedPoints) > 0 {
+ extensionsLength += 1 + len(m.supportedPoints)
+ numExtensions++
+ }
if numExtensions > 0 {
extensionsLength += 4 * numExtensions
length += 2 + extensionsLength
@@ -95,12 +110,55 @@ func (m *clientHelloMsg) marshal() []byte {
// ServerName server_name_list<1..2^16-1>
// } ServerNameList;
- z[1] = 1
+ z[0] = byte((len(m.serverName) + 3) >> 8)
+ z[1] = byte(len(m.serverName) + 3)
z[3] = byte(len(m.serverName) >> 8)
z[4] = byte(len(m.serverName))
copy(z[5:], []byte(m.serverName))
z = z[l:]
}
+ if m.ocspStapling {
+ // RFC 4366, section 3.6
+ z[0] = byte(extensionStatusRequest >> 8)
+ z[1] = byte(extensionStatusRequest)
+ z[2] = 0
+ z[3] = 5
+ z[4] = 1 // OCSP type
+ // Two zero valued uint16s for the two lengths.
+ z = z[9:]
+ }
+ if len(m.supportedCurves) > 0 {
+ // http://tools.ietf.org/html/rfc4492#section-5.5.1
+ z[0] = byte(extensionSupportedCurves >> 8)
+ z[1] = byte(extensionSupportedCurves)
+ l := 2 + 2*len(m.supportedCurves)
+ z[2] = byte(l >> 8)
+ z[3] = byte(l)
+ l -= 2
+ z[4] = byte(l >> 8)
+ z[5] = byte(l)
+ z = z[6:]
+ for _, curve := range m.supportedCurves {
+ z[0] = byte(curve >> 8)
+ z[1] = byte(curve)
+ z = z[2:]
+ }
+ }
+ if len(m.supportedPoints) > 0 {
+ // http://tools.ietf.org/html/rfc4492#section-5.5.2
+ z[0] = byte(extensionSupportedPoints >> 8)
+ z[1] = byte(extensionSupportedPoints)
+ l := 1 + len(m.supportedPoints)
+ z[2] = byte(l >> 8)
+ z[3] = byte(l)
+ l--
+ z[4] = byte(l)
+ z = z[5:]
+ for _, pointFormat := range m.supportedPoints {
+ z[0] = byte(pointFormat)
+ z = z[1:]
+ }
+ }
m.raw = x
@@ -148,6 +206,7 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
m.nextProtoNeg = false
m.serverName = ""
+ m.ocspStapling = false
if len(data) == 0 {
// ClientHello is optionally followed by extension data
@@ -202,6 +261,35 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
return false
}
m.nextProtoNeg = true
+ case extensionStatusRequest:
+ m.ocspStapling = length > 0 && data[0] == statusTypeOCSP
+ case extensionSupportedCurves:
+ // http://tools.ietf.org/html/rfc4492#section-5.5.1
+ if length < 2 {
+ return false
+ }
+ l := int(data[0])<<8 | int(data[1])
+ if l%2 == 1 || length != l+2 {
+ return false
+ }
+ numCurves := l / 2
+ m.supportedCurves = make([]uint16, numCurves)
+ d := data[2:]
+ for i := 0; i < numCurves; i++ {
+ m.supportedCurves[i] = uint16(d[0])<<8 | uint16(d[1])
+ d = d[2:]
+ }
+ case extensionSupportedPoints:
+ // http://tools.ietf.org/html/rfc4492#section-5.5.2
+ if length < 1 {
+ return false
+ }
+ l := int(data[0])
+ if length != l+1 {
+ return false
+ }
+ m.supportedPoints = make([]uint8, l)
+ copy(m.supportedPoints, data[1:])
}
data = data[length:]
}
@@ -218,6 +306,7 @@ type serverHelloMsg struct {
compressionMethod uint8
nextProtoNeg bool
nextProtos []string
+ certStatus bool
}
func (m *serverHelloMsg) marshal() []byte {
@@ -238,6 +327,9 @@ func (m *serverHelloMsg) marshal() []byte {
nextProtoLen += len(m.nextProtos)
extensionsLength += nextProtoLen
}
+ if m.certStatus {
+ numExtensions++
+ }
if numExtensions > 0 {
extensionsLength += 4 * numExtensions
length += 2 + extensionsLength
@@ -281,25 +373,17 @@ func (m *serverHelloMsg) marshal() []byte {
z = z[1+l:]
}
}
+ if m.certStatus {
+ z[0] = byte(extensionStatusRequest >> 8)
+ z[1] = byte(extensionStatusRequest)
+ z = z[4:]
+ }
m.raw = x
return x
}
-func append(slice []string, elem string) []string {
- if len(slice) < cap(slice) {
- slice = slice[0 : len(slice)+1]
- slice[len(slice)-1] = elem
- return slice
- }
-
- fresh := make([]string, len(slice)+1, cap(slice)*2+1)
- copy(fresh, slice)
- fresh[len(slice)] = elem
- return fresh
-}
-
func (m *serverHelloMsg) unmarshal(data []byte) bool {
if len(data) < 42 {
return false
@@ -322,6 +406,7 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool {
m.nextProtoNeg = false
m.nextProtos = nil
+ m.certStatus = false
if len(data) == 0 {
// ServerHello is optionally followed by extension data
@@ -361,6 +446,11 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool {
m.nextProtos = append(m.nextProtos, string(d[0:l]))
d = d[l:]
}
+ case extensionStatusRequest:
+ if length > 0 {
+ return false
+ }
+ m.certStatus = true
}
data = data[length:]
}
@@ -445,6 +535,91 @@ func (m *certificateMsg) unmarshal(data []byte) bool {
return true
}
+type serverKeyExchangeMsg struct {
+ raw []byte
+ key []byte
+}
+
+func (m *serverKeyExchangeMsg) marshal() []byte {
+ if m.raw != nil {
+ return m.raw
+ }
+ length := len(m.key)
+ x := make([]byte, length+4)
+ x[0] = typeServerKeyExchange
+ x[1] = uint8(length >> 16)
+ x[2] = uint8(length >> 8)
+ x[3] = uint8(length)
+ copy(x[4:], m.key)
+
+ m.raw = x
+ return x
+}
+
+func (m *serverKeyExchangeMsg) unmarshal(data []byte) bool {
+ m.raw = data
+ if len(data) < 4 {
+ return false
+ }
+ m.key = data[4:]
+ return true
+}
+
+type certificateStatusMsg struct {
+ raw []byte
+ statusType uint8
+ response []byte
+}
+
+func (m *certificateStatusMsg) marshal() []byte {
+ if m.raw != nil {
+ return m.raw
+ }
+
+ var x []byte
+ if m.statusType == statusTypeOCSP {
+ x = make([]byte, 4+4+len(m.response))
+ x[0] = typeCertificateStatus
+ l := len(m.response) + 4
+ x[1] = byte(l >> 16)
+ x[2] = byte(l >> 8)
+ x[3] = byte(l)
+ x[4] = statusTypeOCSP
+
+ l -= 4
+ x[5] = byte(l >> 16)
+ x[6] = byte(l >> 8)
+ x[7] = byte(l)
+ copy(x[8:], m.response)
+ } else {
+ x = []byte{typeCertificateStatus, 0, 0, 1, m.statusType}
+ }
+
+ m.raw = x
+ return x
+}
+
+func (m *certificateStatusMsg) unmarshal(data []byte) bool {
+ m.raw = data
+ if len(data) < 5 {
+ return false
+ }
+ m.statusType = data[4]
+
+ m.response = nil
+ if m.statusType == statusTypeOCSP {
+ if len(data) < 8 {
+ return false
+ }
+ respLen := uint32(data[5])<<16 | uint32(data[6])<<8 | uint32(data[7])
+ if uint32(len(data)) != 4+4+respLen {
+ return false
+ }
+ m.response = data[8:]
+ }
+ return true
+}
+
type serverHelloDoneMsg struct{}
func (m *serverHelloDoneMsg) marshal() []byte {
@@ -466,15 +641,13 @@ func (m *clientKeyExchangeMsg) marshal() []byte {
if m.raw != nil {
return m.raw
}
- length := len(m.ciphertext) + 2
+ length := len(m.ciphertext)
x := make([]byte, length+4)
x[0] = typeClientKeyExchange
x[1] = uint8(length >> 16)
x[2] = uint8(length >> 8)
x[3] = uint8(length)
- x[4] = uint8(len(m.ciphertext) >> 8)
- x[5] = uint8(len(m.ciphertext))
- copy(x[6:], m.ciphertext)
+ copy(x[4:], m.ciphertext)
m.raw = x
return x
@@ -482,14 +655,14 @@ func (m *clientKeyExchangeMsg) marshal() []byte {
func (m *clientKeyExchangeMsg) unmarshal(data []byte) bool {
m.raw = data
- if len(data) < 7 {
+ if len(data) < 4 {
return false
}
- cipherTextLen := int(data[4])<<8 | int(data[5])
- if len(data) != 6+cipherTextLen {
+ l := int(data[1])<<16 | int(data[2])<<8 | int(data[3])
+ if l != len(data)-4 {
return false
}
- m.ciphertext = data[6:]
+ m.ciphertext = data[4:]
return true
}
@@ -579,3 +752,153 @@ func (m *nextProtoMsg) unmarshal(data []byte) bool {
return true
}
+
+type certificateRequestMsg struct {
+ raw []byte
+ certificateTypes []byte
+ certificateAuthorities [][]byte
+}
+
+func (m *certificateRequestMsg) marshal() (x []byte) {
+ if m.raw != nil {
+ return m.raw
+ }
+
+ // See http://tools.ietf.org/html/rfc4346#section-7.4.4
+ length := 1 + len(m.certificateTypes) + 2
+ for _, ca := range m.certificateAuthorities {
+ length += 2 + len(ca)
+ }
+
+ x = make([]byte, 4+length)
+ x[0] = typeCertificateRequest
+ x[1] = uint8(length >> 16)
+ x[2] = uint8(length >> 8)
+ x[3] = uint8(length)
+
+ x[4] = uint8(len(m.certificateTypes))
+
+ copy(x[5:], m.certificateTypes)
+ y := x[5+len(m.certificateTypes):]
+
+ numCA := len(m.certificateAuthorities)
+ y[0] = uint8(numCA >> 8)
+ y[1] = uint8(numCA)
+ y = y[2:]
+ for _, ca := range m.certificateAuthorities {
+ y[0] = uint8(len(ca) >> 8)
+ y[1] = uint8(len(ca))
+ y = y[2:]
+ copy(y, ca)
+ y = y[len(ca):]
+ }
+
+ m.raw = x
+
+ return
+}
+
+func (m *certificateRequestMsg) unmarshal(data []byte) bool {
+ m.raw = data
+
+ if len(data) < 5 {
+ return false
+ }
+
+ length := uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3])
+ if uint32(len(data))-4 != length {
+ return false
+ }
+
+ numCertTypes := int(data[4])
+ data = data[5:]
+ if numCertTypes == 0 || len(data) <= numCertTypes {
+ return false
+ }
+
+ m.certificateTypes = make([]byte, numCertTypes)
+ if copy(m.certificateTypes, data) != numCertTypes {
+ return false
+ }
+
+ data = data[numCertTypes:]
+ if len(data) < 2 {
+ return false
+ }
+
+ numCAs := uint16(data[0])<<16 | uint16(data[1])
+ data = data[2:]
+
+ m.certificateAuthorities = make([][]byte, numCAs)
+ for i := uint16(0); i < numCAs; i++ {
+ if len(data) < 2 {
+ return false
+ }
+ caLen := uint16(data[0])<<16 | uint16(data[1])
+
+ data = data[2:]
+ if len(data) < int(caLen) {
+ return false
+ }
+
+ ca := make([]byte, caLen)
+ copy(ca, data)
+ m.certificateAuthorities[i] = ca
+ data = data[caLen:]
+ }
+
+ if len(data) > 0 {
+ return false
+ }
+
+ return true
+}
+
+type certificateVerifyMsg struct {
+ raw []byte
+ signature []byte
+}
+
+func (m *certificateVerifyMsg) marshal() (x []byte) {
+ if m.raw != nil {
+ return m.raw
+ }
+
+ // See http://tools.ietf.org/html/rfc4346#section-7.4.8
+ siglength := len(m.signature)
+ length := 2 + siglength
+ x = make([]byte, 4+length)
+ x[0] = typeCertificateVerify
+ x[1] = uint8(length >> 16)
+ x[2] = uint8(length >> 8)
+ x[3] = uint8(length)
+ x[4] = uint8(siglength >> 8)
+ x[5] = uint8(siglength)
+ copy(x[6:], m.signature)
+
+ m.raw = x
+
+ return
+}
+
+func (m *certificateVerifyMsg) unmarshal(data []byte) bool {
+ m.raw = data
+
+ if len(data) < 6 {
+ return false
+ }
+
+ length := uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3])
+ if uint32(len(data))-4 != length {
+ return false
+ }
+
+ siglength := int(data[4])<<8 + int(data[5])
+ if len(data)-6 != siglength {
+ return false
+ }
+
+ m.signature = data[6:]
+
+ return true
+}
diff --git a/src/pkg/crypto/tls/handshake_messages_test.go b/src/pkg/crypto/tls/handshake_messages_test.go
index 2e422cc6a..21577dd0b 100644
--- a/src/pkg/crypto/tls/handshake_messages_test.go
+++ b/src/pkg/crypto/tls/handshake_messages_test.go
@@ -16,6 +16,9 @@ var tests = []interface{}{
&serverHelloMsg{},
&certificateMsg{},
+ &certificateRequestMsg{},
+ &certificateVerifyMsg{},
+ &certificateStatusMsg{},
&clientKeyExchangeMsg{},
&finishedMsg{},
&nextProtoMsg{},
@@ -111,6 +114,12 @@ func (*clientHelloMsg) Generate(rand *rand.Rand, size int) reflect.Value {
if rand.Intn(10) > 5 {
m.serverName = randomString(rand.Intn(255), rand)
}
+ m.ocspStapling = rand.Intn(10) > 5
+ m.supportedPoints = randomBytes(rand.Intn(5)+1, rand)
+ m.supportedCurves = make([]uint16, rand.Intn(5)+1)
+ for i, _ := range m.supportedCurves {
+ m.supportedCurves[i] = uint16(rand.Intn(30000))
+ }
return reflect.NewValue(m)
}
@@ -146,6 +155,34 @@ func (*certificateMsg) Generate(rand *rand.Rand, size int) reflect.Value {
return reflect.NewValue(m)
}
+func (*certificateRequestMsg) Generate(rand *rand.Rand, size int) reflect.Value {
+ m := &certificateRequestMsg{}
+ m.certificateTypes = randomBytes(rand.Intn(5)+1, rand)
+ numCAs := rand.Intn(100)
+ m.certificateAuthorities = make([][]byte, numCAs)
+ for i := 0; i < numCAs; i++ {
+ m.certificateAuthorities[i] = randomBytes(rand.Intn(15)+1, rand)
+ }
+ return reflect.NewValue(m)
+}
+
+func (*certificateVerifyMsg) Generate(rand *rand.Rand, size int) reflect.Value {
+ m := &certificateVerifyMsg{}
+ m.signature = randomBytes(rand.Intn(15)+1, rand)
+ return reflect.NewValue(m)
+}
+
+func (*certificateStatusMsg) Generate(rand *rand.Rand, size int) reflect.Value {
+ m := &certificateStatusMsg{}
+ if rand.Intn(10) > 5 {
+ m.statusType = statusTypeOCSP
+ m.response = randomBytes(rand.Intn(10)+1, rand)
+ } else {
+ m.statusType = 42
+ }
+ return reflect.NewValue(m)
+}
+
func (*clientKeyExchangeMsg) Generate(rand *rand.Rand, size int) reflect.Value {
m := &clientKeyExchangeMsg{}
m.ciphertext = randomBytes(rand.Intn(1000)+1, rand)
diff --git a/src/pkg/crypto/tls/handshake_server.go b/src/pkg/crypto/tls/handshake_server.go
index ebf956763..955811ada 100644
--- a/src/pkg/crypto/tls/handshake_server.go
+++ b/src/pkg/crypto/tls/handshake_server.go
@@ -4,34 +4,14 @@
package tls
-// The handshake goroutine reads handshake messages from the record processor
-// and outputs messages to be written on another channel. It updates the record
-// processor with the state of the connection via the control channel. In the
-// case of handshake messages that need synchronous processing (because they
-// affect the handling of the next record) the record processor knows about
-// them and either waits for a control message (Finished) or includes a reply
-// channel in the message (ChangeCipherSpec).
-
import (
- "crypto/hmac"
- "crypto/rc4"
"crypto/rsa"
- "crypto/sha1"
"crypto/subtle"
+ "crypto/x509"
"io"
"os"
)
-type cipherSuite struct {
- id uint16 // The number of this suite on the wire.
- hashLength, cipherKeyLength int
- // TODO(agl): need a method to create the cipher and hash interfaces.
-}
-
-var cipherSuites = []cipherSuite{
- cipherSuite{TLS_RSA_WITH_RC4_128_SHA, 20, 16},
-}
-
func (c *Conn) serverHandshake() os.Error {
config := c.config
msg, err := c.readHandshake()
@@ -54,16 +34,38 @@ func (c *Conn) serverHandshake() os.Error {
hello := new(serverHelloMsg)
- // We only support a single ciphersuite so we look for it in the list
- // of client supported suites.
- //
- // TODO(agl): Add additional cipher suites.
- var suite *cipherSuite
+ supportedCurve := false
+Curves:
+ for _, curve := range clientHello.supportedCurves {
+ switch curve {
+ case curveP256, curveP384, curveP521:
+ supportedCurve = true
+ break Curves
+ }
+ }
+ supportedPointFormat := false
+ for _, pointFormat := range clientHello.supportedPoints {
+ if pointFormat == pointFormatUncompressed {
+ supportedPointFormat = true
+ break
+ }
+ }
+
+ ellipticOk := supportedCurve && supportedPointFormat
+
+ var suite *cipherSuite
+ var suiteId uint16
for _, id := range clientHello.cipherSuites {
- for _, supported := range cipherSuites {
- if supported.id == id {
- suite = &supported
+ for _, supported := range config.cipherSuites() {
+ if id == supported {
+ suite = cipherSuites[id]
+ // Don't select a ciphersuite which we can't
+ // support for this client.
+ if suite.elliptic && !ellipticOk {
+ continue
+ }
+ suiteId = id
break
}
}
@@ -83,14 +85,14 @@ func (c *Conn) serverHandshake() os.Error {
}
hello.vers = vers
- hello.cipherSuite = suite.id
- t := uint32(config.Time())
+ hello.cipherSuite = suiteId
+ t := uint32(config.time())
hello.random = make([]byte, 32)
hello.random[0] = byte(t >> 24)
hello.random[1] = byte(t >> 16)
hello.random[2] = byte(t >> 8)
hello.random[3] = byte(t)
- _, err = io.ReadFull(config.Rand, hello.random[4:])
+ _, err = io.ReadFull(config.rand(), hello.random[4:])
if err != nil {
return c.sendAlert(alertInternalError)
}
@@ -112,10 +114,76 @@ func (c *Conn) serverHandshake() os.Error {
finishedHash.Write(certMsg.marshal())
c.writeRecord(recordTypeHandshake, certMsg.marshal())
+ keyAgreement := suite.ka()
+
+ skx, err := keyAgreement.generateServerKeyExchange(config, clientHello, hello)
+ if err != nil {
+ c.sendAlert(alertHandshakeFailure)
+ return err
+ }
+ if skx != nil {
+ finishedHash.Write(skx.marshal())
+ c.writeRecord(recordTypeHandshake, skx.marshal())
+ }
+
+ if config.AuthenticateClient {
+ // Request a client certificate
+ certReq := new(certificateRequestMsg)
+ certReq.certificateTypes = []byte{certTypeRSASign}
+ // An empty list of certificateAuthorities signals to
+ // the client that it may send any certificate in response
+ // to our request.
+
+ finishedHash.Write(certReq.marshal())
+ c.writeRecord(recordTypeHandshake, certReq.marshal())
+ }
+
helloDone := new(serverHelloDoneMsg)
finishedHash.Write(helloDone.marshal())
c.writeRecord(recordTypeHandshake, helloDone.marshal())
+ var pub *rsa.PublicKey
+ if config.AuthenticateClient {
+ // Get client certificate
+ msg, err = c.readHandshake()
+ if err != nil {
+ return err
+ }
+ certMsg, ok = msg.(*certificateMsg)
+ if !ok {
+ return c.sendAlert(alertUnexpectedMessage)
+ }
+ finishedHash.Write(certMsg.marshal())
+
+ certs := make([]*x509.Certificate, len(certMsg.certificates))
+ for i, asn1Data := range certMsg.certificates {
+ cert, err := x509.ParseCertificate(asn1Data)
+ if err != nil {
+ c.sendAlert(alertBadCertificate)
+ return os.ErrorString("could not parse client's certificate: " + err.String())
+ }
+ certs[i] = cert
+ }
+
+ // TODO(agl): do better validation of certs: max path length, name restrictions etc.
+ for i := 1; i < len(certs); i++ {
+ if err := certs[i-1].CheckSignatureFrom(certs[i]); err != nil {
+ c.sendAlert(alertBadCertificate)
+ return os.ErrorString("could not validate certificate signature: " + err.String())
+ }
+ }
+
+ if len(certs) > 0 {
+ key, ok := certs[0].PublicKey.(*rsa.PublicKey)
+ if !ok {
+ return c.sendAlert(alertUnsupportedCertificate)
+ }
+ pub = key
+ c.peerCertificates = certs
+ }
+ }
+
+ // Get client key exchange
msg, err = c.readHandshake()
if err != nil {
return err
@@ -126,28 +194,46 @@ func (c *Conn) serverHandshake() os.Error {
}
finishedHash.Write(ckx.marshal())
- preMasterSecret := make([]byte, 48)
- _, err = io.ReadFull(config.Rand, preMasterSecret[2:])
- if err != nil {
- return c.sendAlert(alertInternalError)
+ // If we received a client cert in response to our certificate request message,
+ // the client will send us a certificateVerifyMsg immediately after the
+ // clientKeyExchangeMsg. This message is a MD5SHA1 digest of all preceeding
+ // handshake-layer messages that is signed using the private key corresponding
+ // to the client's certificate. This allows us to verify that the client is in
+ // posession of the private key of the certificate.
+ if len(c.peerCertificates) > 0 {
+ msg, err = c.readHandshake()
+ if err != nil {
+ return err
+ }
+ certVerify, ok := msg.(*certificateVerifyMsg)
+ if !ok {
+ return c.sendAlert(alertUnexpectedMessage)
+ }
+
+ digest := make([]byte, 36)
+ copy(digest[0:16], finishedHash.serverMD5.Sum())
+ copy(digest[16:36], finishedHash.serverSHA1.Sum())
+ err = rsa.VerifyPKCS1v15(pub, rsa.HashMD5SHA1, digest, certVerify.signature)
+ if err != nil {
+ c.sendAlert(alertBadCertificate)
+ return os.ErrorString("could not validate signature of connection nonces: " + err.String())
+ }
+
+ finishedHash.Write(certVerify.marshal())
}
- err = rsa.DecryptPKCS1v15SessionKey(config.Rand, config.Certificates[0].PrivateKey, ckx.ciphertext, preMasterSecret)
+ preMasterSecret, err := keyAgreement.processClientKeyExchange(config, ckx)
if err != nil {
- return c.sendAlert(alertHandshakeFailure)
+ c.sendAlert(alertHandshakeFailure)
+ return err
}
- // We don't check the version number in the premaster secret. For one,
- // by checking it, we would leak information about the validity of the
- // encrypted pre-master secret. Secondly, it provides only a small
- // benefit against a downgrade attack and some implementations send the
- // wrong version anyway. See the discussion at the end of section
- // 7.4.7.1 of RFC 4346.
- masterSecret, clientMAC, serverMAC, clientKey, serverKey :=
- keysFromPreMasterSecret11(preMasterSecret, clientHello.random, hello.random, suite.hashLength, suite.cipherKeyLength)
+ masterSecret, clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV :=
+ keysFromPreMasterSecret10(preMasterSecret, clientHello.random, hello.random, suite.macLen, suite.keyLen, suite.ivLen)
- cipher, _ := rc4.NewCipher(clientKey)
- c.in.prepareCipherSpec(cipher, hmac.New(sha1.New(), clientMAC))
+ clientCipher := suite.cipher(clientKey, clientIV, true /* for reading */ )
+ clientHash := suite.mac(clientMAC)
+ c.in.prepareCipherSpec(clientCipher, clientHash)
c.readRecord(recordTypeChangeCipherSpec)
if err := c.error(); err != nil {
return err
@@ -183,8 +269,9 @@ func (c *Conn) serverHandshake() os.Error {
finishedHash.Write(clientFinished.marshal())
- cipher2, _ := rc4.NewCipher(serverKey)
- c.out.prepareCipherSpec(cipher2, hmac.New(sha1.New(), serverMAC))
+ serverCipher := suite.cipher(serverKey, serverIV, false /* not for reading */ )
+ serverHash := suite.mac(serverMAC)
+ c.out.prepareCipherSpec(serverCipher, serverHash)
c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
finished := new(finishedMsg)
@@ -192,7 +279,7 @@ func (c *Conn) serverHandshake() os.Error {
c.writeRecord(recordTypeHandshake, finished.marshal())
c.handshakeComplete = true
- c.cipherSuite = TLS_RSA_WITH_RC4_128_SHA
+ c.cipherSuite = suiteId
return nil
}
diff --git a/src/pkg/crypto/tls/handshake_server_test.go b/src/pkg/crypto/tls/handshake_server_test.go
index d31dc497e..5cf3ae049 100644
--- a/src/pkg/crypto/tls/handshake_server_test.go
+++ b/src/pkg/crypto/tls/handshake_server_test.go
@@ -5,8 +5,8 @@
package tls
import (
- // "bytes"
"big"
+ "bytes"
"crypto/rsa"
"encoding/hex"
"flag"
@@ -14,7 +14,6 @@ import (
"net"
"os"
"testing"
- // "testing/script"
)
type zeroSource struct{}
@@ -36,6 +35,7 @@ func init() {
testConfig.Certificates = make([]Certificate, 1)
testConfig.Certificates[0].Certificate = [][]byte{testCertificate}
testConfig.Certificates[0].PrivateKey = testPrivateKey
+ testConfig.CipherSuites = []uint16{TLS_RSA_WITH_RC4_128_SHA}
}
func testClientHelloFailure(t *testing.T, m handshakeMessage, expected os.Error) {
@@ -71,13 +71,13 @@ func TestRejectBadProtocolVersion(t *testing.T) {
}
func TestNoSuiteOverlap(t *testing.T) {
- clientHello := &clientHelloMsg{nil, 0x0301, nil, nil, []uint16{0xff00}, []uint8{0}, false, ""}
+ clientHello := &clientHelloMsg{nil, 0x0301, nil, nil, []uint16{0xff00}, []uint8{0}, false, "", false, nil, nil}
testClientHelloFailure(t, clientHello, alertHandshakeFailure)
}
func TestNoCompressionOverlap(t *testing.T) {
- clientHello := &clientHelloMsg{nil, 0x0301, nil, nil, []uint16{TLS_RSA_WITH_RC4_128_SHA}, []uint8{0xff}, false, ""}
+ clientHello := &clientHelloMsg{nil, 0x0301, nil, nil, []uint16{TLS_RSA_WITH_RC4_128_SHA}, []uint8{0xff}, false, "", false, nil, nil}
testClientHelloFailure(t, clientHello, alertHandshakeFailure)
}
@@ -107,9 +107,9 @@ func TestClose(t *testing.T) {
}
-func TestHandshakeServer(t *testing.T) {
+func testServerScript(t *testing.T, name string, serverScript [][]byte, config *Config) {
c, s := net.Pipe()
- srv := Server(s, testConfig)
+ srv := Server(s, config)
go func() {
srv.Write([]byte("hello, world\n"))
srv.Close()
@@ -124,15 +124,23 @@ func TestHandshakeServer(t *testing.T) {
bb := make([]byte, len(b))
_, err := io.ReadFull(c, bb)
if err != nil {
- t.Fatalf("#%d: %s", i, err)
+ t.Fatalf("%s #%d: %s", name, i, err)
+ }
+ if !bytes.Equal(b, bb) {
+ t.Fatalf("%s #%d: mismatch on read: got:%x want:%x", name, i, bb, b)
}
}
+}
- if !srv.haveVers || srv.vers != 0x0302 {
- t.Errorf("server version incorrect: %v %v", srv.haveVers, srv.vers)
- }
+func TestHandshakeServerRC4(t *testing.T) {
+ testServerScript(t, "RC4", rc4ServerScript, testConfig)
+}
- // TODO: check protocol
+func TestHandshakeServerAES(t *testing.T) {
+ aesConfig := new(Config)
+ *aesConfig = *testConfig
+ aesConfig.CipherSuites = []uint16{TLS_RSA_WITH_AES_128_CBC_SHA}
+ testServerScript(t, "AES", aesServerScript, aesConfig)
}
var serve = flag.Bool("serve", false, "run a TLS server on :10443")
@@ -152,7 +160,11 @@ func TestRunServer(t *testing.T) {
if err != nil {
break
}
- c.Write([]byte("hello, world\n"))
+ _, err = c.Write([]byte("hello, world\n"))
+ if err != nil {
+ t.Errorf("error from TLS: %s", err)
+ break
+ }
c.Close()
}
}
@@ -181,113 +193,324 @@ var testPrivateKey = &rsa.PrivateKey{
}
// Script of interaction with gnutls implementation.
-// The values for this test are obtained by building a test binary (gotest)
-// and then running 6.out -serve to start a server and then
-// gnutls-cli --insecure --debug 100 -p 10443 localhost
-// to dump a session.
-var serverScript = [][]byte{
- // Alternate write and read.
- []byte{
- 0x16, 0x03, 0x02, 0x00, 0x71, 0x01, 0x00, 0x00, 0x6d, 0x03, 0x02, 0x4b, 0xd4, 0xee, 0x6e, 0xab,
- 0x0b, 0xc3, 0x01, 0xd6, 0x8d, 0xe0, 0x72, 0x7e, 0x6c, 0x04, 0xbe, 0x9a, 0x3c, 0xa3, 0xd8, 0x95,
- 0x28, 0x00, 0xb2, 0xe8, 0x1f, 0xdd, 0xb0, 0xec, 0xca, 0x46, 0x1f, 0x00, 0x00, 0x28, 0x00, 0x33,
- 0x00, 0x39, 0x00, 0x16, 0x00, 0x32, 0x00, 0x38, 0x00, 0x13, 0x00, 0x66, 0x00, 0x90, 0x00, 0x91,
- 0x00, 0x8f, 0x00, 0x8e, 0x00, 0x2f, 0x00, 0x35, 0x00, 0x0a, 0x00, 0x05, 0x00, 0x04, 0x00, 0x8c,
- 0x00, 0x8d, 0x00, 0x8b, 0x00, 0x8a, 0x01, 0x00, 0x00, 0x1c, 0x00, 0x09, 0x00, 0x03, 0x02, 0x00,
- 0x01, 0x00, 0x00, 0x00, 0x11, 0x00, 0x0f, 0x00, 0x00, 0x0c, 0x31, 0x39, 0x32, 0x2e, 0x31, 0x36,
- 0x38, 0x2e, 0x30, 0x2e, 0x31, 0x30,
+// The values for this test are obtained by building and running in server mode:
+// % gotest -match "TestRunServer" -serve
+// and then:
+// % gnutls-cli --insecure --debug 100 -p 10443 localhost > /tmp/log 2>&1
+// % python parse-gnutls-cli-debug-log.py < /tmp/log
+var rc4ServerScript = [][]byte{
+ {
+ 0x16, 0x03, 0x02, 0x00, 0x7f, 0x01, 0x00, 0x00,
+ 0x7b, 0x03, 0x02, 0x4d, 0x08, 0x1f, 0x5a, 0x7a,
+ 0x0a, 0x92, 0x2f, 0xf0, 0x73, 0x16, 0x3a, 0x88,
+ 0x14, 0x85, 0x4c, 0x98, 0x15, 0x7b, 0x65, 0xe0,
+ 0x78, 0xd0, 0xed, 0xd0, 0xf3, 0x65, 0x20, 0xeb,
+ 0x80, 0xd1, 0x0b, 0x00, 0x00, 0x34, 0x00, 0x33,
+ 0x00, 0x45, 0x00, 0x39, 0x00, 0x88, 0x00, 0x16,
+ 0x00, 0x32, 0x00, 0x44, 0x00, 0x38, 0x00, 0x87,
+ 0x00, 0x13, 0x00, 0x66, 0x00, 0x90, 0x00, 0x91,
+ 0x00, 0x8f, 0x00, 0x8e, 0x00, 0x2f, 0x00, 0x41,
+ 0x00, 0x35, 0x00, 0x84, 0x00, 0x0a, 0x00, 0x05,
+ 0x00, 0x04, 0x00, 0x8c, 0x00, 0x8d, 0x00, 0x8b,
+ 0x00, 0x8a, 0x01, 0x00, 0x00, 0x1e, 0x00, 0x09,
+ 0x00, 0x03, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x0e, 0x00, 0x0c, 0x00, 0x00, 0x09, 0x6c, 0x6f,
+ 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, 0x74, 0xff,
+ 0x01, 0x00, 0x01, 0x00,
},
- []byte{
- 0x16, 0x03, 0x02, 0x00, 0x2a,
- 0x02, 0x00, 0x00, 0x26, 0x03, 0x02, 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, 0x02, 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, 0x02, 0x00, 0x04,
- 0x0e, 0x00, 0x00, 0x00,
+ {
+ 0x16, 0x03, 0x01, 0x00, 0x2a, 0x02, 0x00, 0x00,
+ 0x26, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x16,
+ 0x03, 0x01, 0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba,
+ 0x00, 0x02, 0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82,
+ 0x02, 0xb0, 0x30, 0x82, 0x02, 0x19, 0xa0, 0x03,
+ 0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0x85, 0xb0,
+ 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d,
+ 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+ 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x45, 0x31,
+ 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
+ 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
+ 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
+ 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
+ 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
+ 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
+ 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
+ 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
+ 0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d,
+ 0x31, 0x30, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39,
+ 0x30, 0x39, 0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31,
+ 0x31, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30,
+ 0x39, 0x33, 0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b,
+ 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+ 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06,
+ 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f,
+ 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65,
+ 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04,
+ 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72,
+ 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67,
+ 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20,
+ 0x4c, 0x74, 0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d,
+ 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+ 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d,
+ 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00,
+ 0xbb, 0x79, 0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf,
+ 0x46, 0x10, 0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b,
+ 0x07, 0x43, 0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a,
+ 0x43, 0x85, 0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65,
+ 0x4c, 0x2c, 0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4,
+ 0x82, 0xe5, 0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62,
+ 0xa5, 0x2c, 0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c,
+ 0x7a, 0x56, 0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58,
+ 0x7b, 0x26, 0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0,
+ 0xc9, 0x21, 0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f,
+ 0x5a, 0xbf, 0xef, 0x42, 0x71, 0x00, 0xfe, 0x18,
+ 0x99, 0x07, 0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1,
+ 0x04, 0x39, 0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9,
+ 0x7c, 0xe3, 0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01,
+ 0xcf, 0xaf, 0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d,
+ 0xdb, 0xdb, 0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79,
+ 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7,
+ 0x30, 0x81, 0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55,
+ 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xb1, 0xad,
+ 0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69,
+ 0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18,
+ 0x88, 0x39, 0x30, 0x75, 0x06, 0x03, 0x55, 0x1d,
+ 0x23, 0x04, 0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1,
+ 0xad, 0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb,
+ 0x69, 0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e,
+ 0x18, 0x88, 0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30,
+ 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
+ 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13,
+ 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13,
+ 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74,
+ 0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06,
+ 0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e,
+ 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57,
+ 0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50,
+ 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x82, 0x09,
+ 0x00, 0x85, 0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8,
+ 0xca, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13,
+ 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30,
+ 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81,
+ 0x81, 0x00, 0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b,
+ 0xb1, 0x59, 0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0,
+ 0x14, 0xd7, 0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5,
+ 0x5a, 0x95, 0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae,
+ 0x12, 0x66, 0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e,
+ 0x60, 0xd3, 0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5,
+ 0x25, 0x13, 0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30,
+ 0x1d, 0xba, 0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7,
+ 0xd7, 0x31, 0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78,
+ 0xea, 0x50, 0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d,
+ 0x5a, 0x5f, 0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75,
+ 0x90, 0x96, 0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd,
+ 0x98, 0x1f, 0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c,
+ 0xa3, 0x1b, 0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57,
+ 0xe9, 0x70, 0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b,
+ 0x26, 0x6e, 0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7,
+ 0xbd, 0xd9, 0x16, 0x03, 0x01, 0x00, 0x04, 0x0e,
+ 0x00, 0x00, 0x00,
},
- []byte{
- 0x16, 0x03, 0x02, 0x00, 0x86, 0x10, 0x00, 0x00, 0x82, 0x00, 0x80, 0x3b, 0x7a, 0x9b, 0x05, 0xfd,
- 0x1b, 0x0d, 0x81, 0xf0, 0xac, 0x59, 0x57, 0x4e, 0xb6, 0xf5, 0x81, 0xed, 0x52, 0x78, 0xc5, 0xff,
- 0x36, 0x33, 0x9c, 0x94, 0x31, 0xc3, 0x14, 0x98, 0x5d, 0xa0, 0x49, 0x23, 0x11, 0x67, 0xdf, 0x73,
- 0x1b, 0x81, 0x0b, 0xdd, 0x10, 0xda, 0xee, 0xb5, 0x68, 0x61, 0xa9, 0xb6, 0x15, 0xae, 0x1a, 0x11,
- 0x31, 0x42, 0x2e, 0xde, 0x01, 0x4b, 0x81, 0x70, 0x03, 0xc8, 0x5b, 0xca, 0x21, 0x88, 0x25, 0xef,
- 0x89, 0xf0, 0xb7, 0xff, 0x24, 0x32, 0xd3, 0x14, 0x76, 0xe2, 0x50, 0x5c, 0x2e, 0x75, 0x9d, 0x5c,
- 0xa9, 0x80, 0x3d, 0x6f, 0xd5, 0x46, 0xd3, 0xdb, 0x42, 0x6e, 0x55, 0x81, 0x88, 0x42, 0x0e, 0x45,
- 0xfe, 0x9e, 0xe4, 0x41, 0x79, 0xcf, 0x71, 0x0e, 0xed, 0x27, 0xa8, 0x20, 0x05, 0xe9, 0x7a, 0x42,
- 0x4f, 0x05, 0x10, 0x2e, 0x52, 0x5d, 0x8c, 0x3c, 0x40, 0x49, 0x4c,
-
- 0x14, 0x03, 0x02, 0x00, 0x01, 0x01,
-
- 0x16, 0x03, 0x02, 0x00, 0x24, 0x8b, 0x12, 0x24, 0x06, 0xaa, 0x92, 0x74, 0xa1, 0x46, 0x6f, 0xc1,
- 0x4e, 0x4a, 0xf7, 0x16, 0xdd, 0xd6, 0xe1, 0x2d, 0x37, 0x0b, 0x44, 0xba, 0xeb, 0xc4, 0x6c, 0xc7,
- 0xa0, 0xb7, 0x8c, 0x9d, 0x24, 0xbd, 0x99, 0x33, 0x1e,
+ {
+ 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,
},
- []byte{
- 0x14, 0x03, 0x02, 0x00, 0x01,
- 0x01,
+ {
+ 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,
+ },
+}
- 0x16, 0x03, 0x02, 0x00, 0x24,
- 0x6e, 0xd1, 0x3e, 0x49, 0x68, 0xc1, 0xa0, 0xa5, 0xb7, 0xaf, 0xb0, 0x7c, 0x52, 0x1f, 0xf7, 0x2d,
- 0x51, 0xf3, 0xa5, 0xb6, 0xf6, 0xd4, 0x18, 0x4b, 0x7a, 0xd5, 0x24, 0x1d, 0x09, 0xb6, 0x41, 0x1c,
- 0x1c, 0x98, 0xf6, 0x90,
+var aesServerScript = [][]byte{
+ {
+ 0x16, 0x03, 0x02, 0x00, 0x7f, 0x01, 0x00, 0x00,
+ 0x7b, 0x03, 0x02, 0x4d, 0x08, 0x2d, 0x0b, 0xb3,
+ 0x57, 0x85, 0x71, 0x4b, 0xfb, 0x34, 0xab, 0x16,
+ 0xd4, 0x92, 0x50, 0x81, 0x16, 0x95, 0x11, 0x28,
+ 0x1a, 0xcb, 0xff, 0x09, 0x4d, 0x23, 0xa6, 0xfe,
+ 0x2e, 0xbb, 0x78, 0x00, 0x00, 0x34, 0x00, 0x33,
+ 0x00, 0x45, 0x00, 0x39, 0x00, 0x88, 0x00, 0x16,
+ 0x00, 0x32, 0x00, 0x44, 0x00, 0x38, 0x00, 0x87,
+ 0x00, 0x13, 0x00, 0x66, 0x00, 0x90, 0x00, 0x91,
+ 0x00, 0x8f, 0x00, 0x8e, 0x00, 0x2f, 0x00, 0x41,
+ 0x00, 0x35, 0x00, 0x84, 0x00, 0x0a, 0x00, 0x05,
+ 0x00, 0x04, 0x00, 0x8c, 0x00, 0x8d, 0x00, 0x8b,
+ 0x00, 0x8a, 0x01, 0x00, 0x00, 0x1e, 0x00, 0x09,
+ 0x00, 0x03, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x0e, 0x00, 0x0c, 0x00, 0x00, 0x09, 0x6c, 0x6f,
+ 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, 0x74, 0xff,
+ 0x01, 0x00, 0x01, 0x00,
+ },
- 0x17, 0x03, 0x02, 0x00, 0x21,
- 0x50, 0xb7, 0x92, 0x4f, 0xd8, 0x78, 0x29, 0xa2, 0xe7, 0xa5, 0xa6, 0xbd, 0x1a, 0x0c, 0xf1, 0x5a,
- 0x6e, 0x6c, 0xeb, 0x38, 0x99, 0x9b, 0x3c, 0xfd, 0xee, 0x53, 0xe8, 0x4d, 0x7b, 0xa5, 0x5b, 0x00,
+ {
+ 0x16, 0x03, 0x01, 0x00, 0x2a, 0x02, 0x00, 0x00,
+ 0x26, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x16,
+ 0x03, 0x01, 0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba,
+ 0x00, 0x02, 0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82,
+ 0x02, 0xb0, 0x30, 0x82, 0x02, 0x19, 0xa0, 0x03,
+ 0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0x85, 0xb0,
+ 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d,
+ 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+ 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x45, 0x31,
+ 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
+ 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,
+ 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53,
+ 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74,
+ 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55,
+ 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,
+ 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,
+ 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79,
+ 0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d,
+ 0x31, 0x30, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39,
+ 0x30, 0x39, 0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31,
+ 0x31, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30,
+ 0x39, 0x33, 0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b,
+ 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+ 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06,
+ 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f,
+ 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65,
+ 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04,
+ 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72,
+ 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67,
+ 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20,
+ 0x4c, 0x74, 0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d,
+ 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+ 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d,
+ 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00,
+ 0xbb, 0x79, 0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf,
+ 0x46, 0x10, 0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b,
+ 0x07, 0x43, 0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a,
+ 0x43, 0x85, 0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65,
+ 0x4c, 0x2c, 0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4,
+ 0x82, 0xe5, 0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62,
+ 0xa5, 0x2c, 0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c,
+ 0x7a, 0x56, 0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58,
+ 0x7b, 0x26, 0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0,
+ 0xc9, 0x21, 0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f,
+ 0x5a, 0xbf, 0xef, 0x42, 0x71, 0x00, 0xfe, 0x18,
+ 0x99, 0x07, 0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1,
+ 0x04, 0x39, 0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9,
+ 0x7c, 0xe3, 0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01,
+ 0xcf, 0xaf, 0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d,
+ 0xdb, 0xdb, 0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79,
+ 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7,
+ 0x30, 0x81, 0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55,
+ 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xb1, 0xad,
+ 0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69,
+ 0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18,
+ 0x88, 0x39, 0x30, 0x75, 0x06, 0x03, 0x55, 0x1d,
+ 0x23, 0x04, 0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1,
+ 0xad, 0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb,
+ 0x69, 0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e,
+ 0x18, 0x88, 0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30,
+ 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
+ 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13,
+ 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13,
+ 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74,
+ 0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06,
+ 0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e,
+ 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57,
+ 0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50,
+ 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x82, 0x09,
+ 0x00, 0x85, 0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8,
+ 0xca, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13,
+ 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30,
+ 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81,
+ 0x81, 0x00, 0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b,
+ 0xb1, 0x59, 0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0,
+ 0x14, 0xd7, 0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5,
+ 0x5a, 0x95, 0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae,
+ 0x12, 0x66, 0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e,
+ 0x60, 0xd3, 0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5,
+ 0x25, 0x13, 0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30,
+ 0x1d, 0xba, 0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7,
+ 0xd7, 0x31, 0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78,
+ 0xea, 0x50, 0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d,
+ 0x5a, 0x5f, 0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75,
+ 0x90, 0x96, 0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd,
+ 0x98, 0x1f, 0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c,
+ 0xa3, 0x1b, 0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57,
+ 0xe9, 0x70, 0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b,
+ 0x26, 0x6e, 0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7,
+ 0xbd, 0xd9, 0x16, 0x03, 0x01, 0x00, 0x04, 0x0e,
+ 0x00, 0x00, 0x00,
+ },
- 0xb9,
+ {
+ 0x16, 0x03, 0x01, 0x00, 0x86, 0x10, 0x00, 0x00,
+ 0x82, 0x00, 0x80, 0x71, 0x9c, 0xe7, 0x23, 0xfc,
+ 0xb9, 0x19, 0x29, 0x82, 0xbf, 0xef, 0x08, 0xf7,
+ 0x99, 0x36, 0xc3, 0x4c, 0x6f, 0x05, 0xd2, 0x8b,
+ 0x62, 0x2b, 0x19, 0x9b, 0x7f, 0xc0, 0xcc, 0x48,
+ 0x30, 0x5f, 0xcd, 0xc3, 0x70, 0x55, 0x53, 0x73,
+ 0xfa, 0x79, 0x74, 0xf3, 0xa3, 0x76, 0x9f, 0xa1,
+ 0x7f, 0x98, 0xc2, 0xc0, 0xe3, 0xc5, 0xa0, 0x31,
+ 0x2f, 0xa6, 0xe8, 0x1e, 0x61, 0x46, 0xb3, 0x9b,
+ 0x4b, 0x16, 0xf1, 0x2d, 0xc7, 0x63, 0x7f, 0x79,
+ 0x22, 0x30, 0xd1, 0xf2, 0xfc, 0x77, 0x98, 0x0a,
+ 0x16, 0x11, 0x63, 0x71, 0x7f, 0x70, 0xef, 0x16,
+ 0xbb, 0x39, 0x87, 0x34, 0xac, 0x49, 0xbd, 0x07,
+ 0x67, 0xcb, 0x9c, 0xcc, 0xde, 0xef, 0xb1, 0xe0,
+ 0xdb, 0x01, 0xb5, 0x35, 0xa9, 0xb3, 0x10, 0x0c,
+ 0x4b, 0xee, 0xb3, 0x4e, 0xfd, 0xbe, 0x15, 0x27,
+ 0xf0, 0x46, 0xb2, 0x38, 0xba, 0x5f, 0xcc, 0x89,
+ 0xec, 0x29, 0x82, 0x14, 0x03, 0x01, 0x00, 0x01,
+ 0x01, 0x16, 0x03, 0x01, 0x00, 0x30, 0x3c, 0xfb,
+ 0xa4, 0x12, 0xcb, 0x00, 0xf9, 0x57, 0x7e, 0x9b,
+ 0xc9, 0xdc, 0x0c, 0xba, 0x9a, 0x81, 0x62, 0xfb,
+ 0x26, 0x13, 0x53, 0xfe, 0xaa, 0xcc, 0x82, 0xbb,
+ 0xb6, 0x67, 0x7f, 0x39, 0xbe, 0x4d, 0xbb, 0xc0,
+ 0x6c, 0x24, 0x31, 0x83, 0xa5, 0x50, 0x3a, 0x75,
+ 0x32, 0x64, 0xb5, 0xdb, 0xbe, 0x0a,
+ },
- 0x15, 0x03, 0x02, 0x00, 0x16,
- 0xc7, 0xc9, 0x5a, 0x72, 0xfb, 0x02, 0xa5, 0x93, 0xdd, 0x69, 0xeb, 0x30, 0x68, 0x5e, 0xbc, 0xe0,
- 0x44, 0xb9, 0x59, 0x33, 0x68, 0xa9,
+ {
+ 0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03,
+ 0x01, 0x00, 0x30, 0x43, 0x24, 0x42, 0x55, 0x08,
+ 0xe4, 0xc2, 0x15, 0xc9, 0xdb, 0x71, 0x69, 0xee,
+ 0x09, 0xc5, 0x1c, 0xfd, 0x46, 0x10, 0xa0, 0x68,
+ 0x21, 0xf2, 0x48, 0xac, 0x6c, 0xc0, 0x2b, 0x62,
+ 0x07, 0x8f, 0x48, 0x33, 0x0a, 0x6b, 0x62, 0x28,
+ 0x2e, 0x2c, 0xad, 0xcb, 0x34, 0x85, 0xca, 0x2e,
+ 0xcd, 0x84, 0xf0,
},
}
diff --git a/src/pkg/crypto/tls/key_agreement.go b/src/pkg/crypto/tls/key_agreement.go
new file mode 100644
index 000000000..861c64f04
--- /dev/null
+++ b/src/pkg/crypto/tls/key_agreement.go
@@ -0,0 +1,246 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+ "big"
+ "crypto/elliptic"
+ "crypto/md5"
+ "crypto/rsa"
+ "crypto/sha1"
+ "crypto/x509"
+ "io"
+ "os"
+)
+
+// rsaKeyAgreement implements the standard TLS key agreement where the client
+// encrypts the pre-master secret to the server's public key.
+type rsaKeyAgreement struct{}
+
+func (ka rsaKeyAgreement) generateServerKeyExchange(config *Config, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, os.Error) {
+ return nil, nil
+}
+
+func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, ckx *clientKeyExchangeMsg) ([]byte, os.Error) {
+ preMasterSecret := make([]byte, 48)
+ _, err := io.ReadFull(config.rand(), preMasterSecret[2:])
+ if err != nil {
+ return nil, err
+ }
+
+ if len(ckx.ciphertext) < 2 {
+ return nil, os.ErrorString("bad ClientKeyExchange")
+ }
+ ciphertextLen := int(ckx.ciphertext[0])<<8 | int(ckx.ciphertext[1])
+ if ciphertextLen != len(ckx.ciphertext)-2 {
+ return nil, os.ErrorString("bad ClientKeyExchange")
+ }
+ ciphertext := ckx.ciphertext[2:]
+
+ err = rsa.DecryptPKCS1v15SessionKey(config.rand(), config.Certificates[0].PrivateKey, ciphertext, preMasterSecret)
+ if err != nil {
+ return nil, err
+ }
+ // We don't check the version number in the premaster secret. For one,
+ // by checking it, we would leak information about the validity of the
+ // encrypted pre-master secret. Secondly, it provides only a small
+ // benefit against a downgrade attack and some implementations send the
+ // wrong version anyway. See the discussion at the end of section
+ // 7.4.7.1 of RFC 4346.
+ return preMasterSecret, nil
+}
+
+func (ka rsaKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) os.Error {
+ return os.ErrorString("unexpected ServerKeyExchange")
+}
+
+func (ka rsaKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, os.Error) {
+ preMasterSecret := make([]byte, 48)
+ preMasterSecret[0] = byte(clientHello.vers >> 8)
+ preMasterSecret[1] = byte(clientHello.vers)
+ _, err := io.ReadFull(config.rand(), preMasterSecret[2:])
+ if err != nil {
+ return nil, nil, err
+ }
+
+ encrypted, err := rsa.EncryptPKCS1v15(config.rand(), cert.PublicKey.(*rsa.PublicKey), preMasterSecret)
+ if err != nil {
+ return nil, nil, err
+ }
+ ckx := new(clientKeyExchangeMsg)
+ ckx.ciphertext = make([]byte, len(encrypted)+2)
+ ckx.ciphertext[0] = byte(len(encrypted) >> 8)
+ ckx.ciphertext[1] = byte(len(encrypted))
+ copy(ckx.ciphertext[2:], encrypted)
+ return preMasterSecret, ckx, nil
+}
+
+
+// md5SHA1Hash implements TLS 1.0's hybrid hash function which consists of the
+// concatenation of an MD5 and SHA1 hash.
+func md5SHA1Hash(slices ...[]byte) []byte {
+ md5sha1 := make([]byte, md5.Size+sha1.Size)
+ hmd5 := md5.New()
+ for _, slice := range slices {
+ hmd5.Write(slice)
+ }
+ copy(md5sha1, hmd5.Sum())
+
+ hsha1 := sha1.New()
+ for _, slice := range slices {
+ hsha1.Write(slice)
+ }
+ copy(md5sha1[md5.Size:], hsha1.Sum())
+ return md5sha1
+}
+
+// ecdheRSAKeyAgreement implements a TLS key agreement where the server
+// generates a ephemeral EC public/private key pair and signs it. The
+// pre-master secret is then calculated using ECDH.
+type ecdheRSAKeyAgreement struct {
+ privateKey []byte
+ curve *elliptic.Curve
+ x, y *big.Int
+}
+
+func (ka *ecdheRSAKeyAgreement) generateServerKeyExchange(config *Config, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, os.Error) {
+ var curveid uint16
+
+Curve:
+ for _, c := range clientHello.supportedCurves {
+ switch c {
+ case curveP256:
+ ka.curve = elliptic.P256()
+ curveid = c
+ break Curve
+ case curveP384:
+ ka.curve = elliptic.P384()
+ curveid = c
+ break Curve
+ case curveP521:
+ ka.curve = elliptic.P521()
+ curveid = c
+ break Curve
+ }
+ }
+
+ var x, y *big.Int
+ var err os.Error
+ ka.privateKey, x, y, err = ka.curve.GenerateKey(config.rand())
+ if err != nil {
+ return nil, err
+ }
+ ecdhePublic := ka.curve.Marshal(x, y)
+
+ // http://tools.ietf.org/html/rfc4492#section-5.4
+ serverECDHParams := make([]byte, 1+2+1+len(ecdhePublic))
+ serverECDHParams[0] = 3 // named curve
+ serverECDHParams[1] = byte(curveid >> 8)
+ serverECDHParams[2] = byte(curveid)
+ serverECDHParams[3] = byte(len(ecdhePublic))
+ copy(serverECDHParams[4:], ecdhePublic)
+
+ md5sha1 := md5SHA1Hash(clientHello.random, hello.random, serverECDHParams)
+ sig, err := rsa.SignPKCS1v15(config.rand(), config.Certificates[0].PrivateKey, rsa.HashMD5SHA1, md5sha1)
+ if err != nil {
+ return nil, os.ErrorString("failed to sign ECDHE parameters: " + err.String())
+ }
+
+ skx := new(serverKeyExchangeMsg)
+ skx.key = make([]byte, len(serverECDHParams)+2+len(sig))
+ copy(skx.key, serverECDHParams)
+ k := skx.key[len(serverECDHParams):]
+ k[0] = byte(len(sig) >> 8)
+ k[1] = byte(len(sig))
+ copy(k[2:], sig)
+
+ return skx, nil
+}
+
+func (ka *ecdheRSAKeyAgreement) processClientKeyExchange(config *Config, ckx *clientKeyExchangeMsg) ([]byte, os.Error) {
+ if len(ckx.ciphertext) == 0 || int(ckx.ciphertext[0]) != len(ckx.ciphertext)-1 {
+ return nil, os.ErrorString("bad ClientKeyExchange")
+ }
+ x, y := ka.curve.Unmarshal(ckx.ciphertext[1:])
+ if x == nil {
+ return nil, os.ErrorString("bad ClientKeyExchange")
+ }
+ x, _ = ka.curve.ScalarMult(x, y, ka.privateKey)
+ preMasterSecret := make([]byte, (ka.curve.BitSize+7)>>3)
+ xBytes := x.Bytes()
+ copy(preMasterSecret[len(preMasterSecret)-len(xBytes):], xBytes)
+
+ return preMasterSecret, nil
+}
+
+func (ka *ecdheRSAKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) os.Error {
+ if len(skx.key) < 4 {
+ goto Error
+ }
+ if skx.key[0] != 3 { // named curve
+ return os.ErrorString("server selected unsupported curve")
+ }
+ curveid := uint16(skx.key[1])<<8 | uint16(skx.key[2])
+
+ switch curveid {
+ case curveP256:
+ ka.curve = elliptic.P256()
+ case curveP384:
+ ka.curve = elliptic.P384()
+ case curveP521:
+ ka.curve = elliptic.P521()
+ default:
+ return os.ErrorString("server selected unsupported curve")
+ }
+
+ publicLen := int(skx.key[3])
+ if publicLen+4 > len(skx.key) {
+ goto Error
+ }
+ ka.x, ka.y = ka.curve.Unmarshal(skx.key[4 : 4+publicLen])
+ if ka.x == nil {
+ goto Error
+ }
+ serverECDHParams := skx.key[:4+publicLen]
+
+ sig := skx.key[4+publicLen:]
+ if len(sig) < 2 {
+ goto Error
+ }
+ sigLen := int(sig[0])<<8 | int(sig[1])
+ if sigLen+2 != len(sig) {
+ goto Error
+ }
+ sig = sig[2:]
+
+ md5sha1 := md5SHA1Hash(clientHello.random, serverHello.random, serverECDHParams)
+ return rsa.VerifyPKCS1v15(cert.PublicKey.(*rsa.PublicKey), rsa.HashMD5SHA1, md5sha1, sig)
+
+Error:
+ return os.ErrorString("invalid ServerKeyExchange")
+}
+
+func (ka *ecdheRSAKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, os.Error) {
+ if ka.curve == nil {
+ return nil, nil, os.ErrorString("missing ServerKeyExchange message")
+ }
+ priv, mx, my, err := ka.curve.GenerateKey(config.rand())
+ if err != nil {
+ return nil, nil, err
+ }
+ x, _ := ka.curve.ScalarMult(ka.x, ka.y, priv)
+ preMasterSecret := make([]byte, (ka.curve.BitSize+7)>>3)
+ xBytes := x.Bytes()
+ copy(preMasterSecret[len(preMasterSecret)-len(xBytes):], xBytes)
+
+ serialised := ka.curve.Marshal(mx, my)
+
+ ckx := new(clientKeyExchangeMsg)
+ ckx.ciphertext = make([]byte, 1+len(serialised))
+ ckx.ciphertext[0] = byte(len(serialised))
+ copy(ckx.ciphertext[1:], serialised)
+
+ return preMasterSecret, ckx, nil
+}
diff --git a/src/pkg/crypto/tls/parse-gnutls-cli-debug-log.py b/src/pkg/crypto/tls/parse-gnutls-cli-debug-log.py
new file mode 100644
index 000000000..c03eaa6ea
--- /dev/null
+++ b/src/pkg/crypto/tls/parse-gnutls-cli-debug-log.py
@@ -0,0 +1,55 @@
+# Copyright 2010 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+# This code is used to parse the debug log from gnutls-cli and generate a
+# script of the handshake. This script is included in handshake_server_test.go.
+# See the comments there for details.
+
+import sys
+
+blocks = []
+
+READ = 1
+WRITE = 2
+
+currentBlockType = 0
+currentBlock = []
+for line in sys.stdin.readlines():
+ line = line[:-1]
+ if line.startswith("|<7>| WRITE: "):
+ if currentBlockType != WRITE:
+ if len(currentBlock) > 0:
+ blocks.append(currentBlock)
+ currentBlock = []
+ currentBlockType = WRITE
+ elif line.startswith("|<7>| READ: "):
+ if currentBlockType != READ:
+ if len(currentBlock) > 0:
+ blocks.append(currentBlock)
+ currentBlock = []
+ currentBlockType = READ
+ elif line.startswith("|<7>| 0"):
+ line = line[13:]
+ line = line.strip()
+ bs = line.split()
+ for b in bs:
+ currentBlock.append(int(b, 16))
+
+if len(currentBlock) > 0:
+ blocks.append(currentBlock)
+
+for block in blocks:
+ sys.stdout.write("\t{\n")
+
+ i = 0
+ for b in block:
+ if i % 8 == 0:
+ sys.stdout.write("\t\t")
+ sys.stdout.write("0x%02x," % b)
+ if i % 8 == 7:
+ sys.stdout.write("\n")
+ else:
+ sys.stdout.write(" ")
+ i += 1
+ sys.stdout.write("\n\t},\n\n")
diff --git a/src/pkg/crypto/tls/prf.go b/src/pkg/crypto/tls/prf.go
index ee6cb780b..478cf65f9 100644
--- a/src/pkg/crypto/tls/prf.go
+++ b/src/pkg/crypto/tls/prf.go
@@ -20,7 +20,7 @@ func splitPreMasterSecret(secret []byte) (s1, s2 []byte) {
}
// pHash implements the P_hash function, as defined in RFC 4346, section 5.
-func pHash(result, secret, seed []byte, hash hash.Hash) {
+func pHash(result, secret, seed []byte, hash func() hash.Hash) {
h := hmac.New(hash, secret)
h.Write(seed)
a := h.Sum()
@@ -44,10 +44,10 @@ func pHash(result, secret, seed []byte, hash hash.Hash) {
}
}
-// pRF11 implements the TLS 1.1 pseudo-random function, as defined in RFC 4346, section 5.
-func pRF11(result, secret, label, seed []byte) {
- hashSHA1 := sha1.New()
- hashMD5 := md5.New()
+// pRF10 implements the TLS 1.0 pseudo-random function, as defined in RFC 2246, section 5.
+func pRF10(result, secret, label, seed []byte) {
+ hashSHA1 := sha1.New
+ hashMD5 := md5.New
labelAndSeed := make([]byte, len(label)+len(seed))
copy(labelAndSeed, label)
@@ -75,25 +75,32 @@ var clientFinishedLabel = []byte("client finished")
var serverFinishedLabel = []byte("server finished")
// keysFromPreMasterSecret generates the connection keys from the pre master
-// secret, given the lengths of the MAC and cipher keys, as defined in RFC
-// 4346, section 6.3.
-func keysFromPreMasterSecret11(preMasterSecret, clientRandom, serverRandom []byte, macLen, keyLen int) (masterSecret, clientMAC, serverMAC, clientKey, serverKey []byte) {
+// secret, given the lengths of the MAC key, cipher key and IV, as defined in
+// RFC 2246, section 6.3.
+func keysFromPreMasterSecret10(preMasterSecret, clientRandom, serverRandom []byte, macLen, keyLen, ivLen int) (masterSecret, clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV []byte) {
var seed [tlsRandomLength * 2]byte
copy(seed[0:len(clientRandom)], clientRandom)
copy(seed[len(clientRandom):], serverRandom)
masterSecret = make([]byte, masterSecretLength)
- pRF11(masterSecret, preMasterSecret, masterSecretLabel, seed[0:])
+ pRF10(masterSecret, preMasterSecret, masterSecretLabel, seed[0:])
copy(seed[0:len(clientRandom)], serverRandom)
copy(seed[len(serverRandom):], clientRandom)
- n := 2*macLen + 2*keyLen
+ n := 2*macLen + 2*keyLen + 2*ivLen
keyMaterial := make([]byte, n)
- pRF11(keyMaterial, masterSecret, keyExpansionLabel, seed[0:])
- clientMAC = keyMaterial[0:macLen]
- serverMAC = keyMaterial[macLen : macLen*2]
- clientKey = keyMaterial[macLen*2 : macLen*2+keyLen]
- serverKey = keyMaterial[macLen*2+keyLen:]
+ pRF10(keyMaterial, masterSecret, keyExpansionLabel, seed[0:])
+ clientMAC = keyMaterial[:macLen]
+ keyMaterial = keyMaterial[macLen:]
+ serverMAC = keyMaterial[:macLen]
+ keyMaterial = keyMaterial[macLen:]
+ clientKey = keyMaterial[:keyLen]
+ keyMaterial = keyMaterial[keyLen:]
+ serverKey = keyMaterial[:keyLen]
+ keyMaterial = keyMaterial[keyLen:]
+ clientIV = keyMaterial[:ivLen]
+ keyMaterial = keyMaterial[ivLen:]
+ serverIV = keyMaterial[:ivLen]
return
}
@@ -125,7 +132,7 @@ func finishedSum(md5, sha1, label, masterSecret []byte) []byte {
copy(seed, md5)
copy(seed[len(md5):], sha1)
out := make([]byte, finishedVerifyLength)
- pRF11(out, masterSecret, label, seed)
+ pRF10(out, masterSecret, label, seed)
return out
}
diff --git a/src/pkg/crypto/tls/prf_test.go b/src/pkg/crypto/tls/prf_test.go
index 5c23f368d..f8c4acb9d 100644
--- a/src/pkg/crypto/tls/prf_test.go
+++ b/src/pkg/crypto/tls/prf_test.go
@@ -14,11 +14,11 @@ type testSplitPreMasterSecretTest struct {
}
var testSplitPreMasterSecretTests = []testSplitPreMasterSecretTest{
- testSplitPreMasterSecretTest{"", "", ""},
- testSplitPreMasterSecretTest{"00", "00", "00"},
- testSplitPreMasterSecretTest{"0011", "00", "11"},
- testSplitPreMasterSecretTest{"001122", "0011", "1122"},
- testSplitPreMasterSecretTest{"00112233", "0011", "2233"},
+ {"", "", ""},
+ {"00", "00", "00"},
+ {"0011", "00", "11"},
+ {"001122", "0011", "1122"},
+ {"00112233", "0011", "2233"},
}
func TestSplitPreMasterSecret(t *testing.T) {
@@ -47,7 +47,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 := keysFromPreMasterSecret11(in, clientRandom, serverRandom, test.macLen, test.keyLen)
+ master, clientMAC, serverMAC, clientKey, serverKey, _, _ := keysFromPreMasterSecret10(in, clientRandom, serverRandom, test.macLen, test.keyLen, 0)
masterString := hex.EncodeToString(master)
clientMACString := hex.EncodeToString(clientMAC)
serverMACString := hex.EncodeToString(serverMAC)
@@ -65,7 +65,7 @@ func TestKeysFromPreMasterSecret(t *testing.T) {
// These test vectors were generated from GnuTLS using `gnutls-cli --insecure -d 9 `
var testKeysFromTests = []testKeysFromTest{
- testKeysFromTest{
+ {
"0302cac83ad4b1db3b9ab49ad05957de2a504a634a386fc600889321e1a971f57479466830ac3e6f468e87f5385fa0c5",
"4ae66303755184a3917fcb44880605fcc53baa01912b22ed94473fc69cebd558",
"4ae663020ec16e6bb5130be918cfcafd4d765979a3136a5d50c593446e4e44db",
@@ -77,7 +77,7 @@ var testKeysFromTests = []testKeysFromTest{
20,
16,
},
- testKeysFromTest{
+ {
"03023f7527316bc12cbcd69e4b9e8275d62c028f27e65c745cfcddc7ce01bd3570a111378b63848127f1c36e5f9e4890",
"4ae66364b5ea56b20ce4e25555aed2d7e67f42788dd03f3fee4adae0459ab106",
"4ae66363ab815cbf6a248b87d6b556184e945e9b97fbdf247858b0bdafacfa1c",
@@ -89,7 +89,7 @@ var testKeysFromTests = []testKeysFromTest{
20,
16,
},
- testKeysFromTest{
+ {
"832d515f1d61eebb2be56ba0ef79879efb9b527504abb386fb4310ed5d0e3b1f220d3bb6b455033a2773e6d8bdf951d278a187482b400d45deb88a5d5a6bb7d6a7a1decc04eb9ef0642876cd4a82d374d3b6ff35f0351dc5d411104de431375355addc39bfb1f6329fb163b0bc298d658338930d07d313cd980a7e3d9196cac1",
"4ae663b2ee389c0de147c509d8f18f5052afc4aaf9699efe8cb05ece883d3a5e",
"4ae664d503fd4cff50cfc1fb8fc606580f87b0fcdac9554ba0e01d785bdf278e",
diff --git a/src/pkg/crypto/tls/tls.go b/src/pkg/crypto/tls/tls.go
index 1a5da3ac4..b11d3225d 100644
--- a/src/pkg/crypto/tls/tls.go
+++ b/src/pkg/crypto/tls/tls.go
@@ -6,23 +6,40 @@
package tls
import (
- "os"
+ "crypto/rsa"
+ "crypto/x509"
+ "encoding/pem"
+ "io/ioutil"
"net"
+ "os"
+ "strings"
)
+// Server returns a new TLS server side connection
+// using conn as the underlying transport.
+// The configuration config must be non-nil and must have
+// at least one certificate.
func Server(conn net.Conn, config *Config) *Conn {
return &Conn{conn: conn, config: config}
}
+// Client returns a new TLS client side connection
+// using conn as the underlying transport.
+// Client interprets a nil configuration as equivalent to
+// the zero configuration; see the documentation of Config
+// for the defaults.
func Client(conn net.Conn, config *Config) *Conn {
return &Conn{conn: conn, config: config, isClient: true}
}
+// A Listener implements a network listener (net.Listener) for TLS connections.
type Listener struct {
listener net.Listener
config *Config
}
+// Accept waits for and returns the next incoming TLS connection.
+// The returned connection c is a *tls.Conn.
func (l *Listener) Accept() (c net.Conn, err os.Error) {
c, err = l.listener.Accept()
if err != nil {
@@ -32,8 +49,10 @@ 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
@@ -47,7 +66,11 @@ func NewListener(listener net.Listener, config *Config) (l *Listener) {
return
}
-func Listen(network, laddr string, config *Config) (net.Listener, os.Error) {
+// Listen creates a TLS listener accepting connections on the
+// given network address using net.Listen.
+// The configuration config must be non-nil and must have
+// at least one certificate.
+func Listen(network, laddr string, config *Config) (*Listener, os.Error) {
if config == nil || len(config.Certificates) == 0 {
return nil, os.NewError("tls.Listen: no certificates in configuration")
}
@@ -58,10 +81,87 @@ func Listen(network, laddr string, config *Config) (net.Listener, os.Error) {
return NewListener(l, config), nil
}
-func Dial(network, laddr, raddr string) (net.Conn, os.Error) {
+// Dial connects to the given network address using net.Dial
+// and then initiates a TLS handshake, returning the resulting
+// TLS connection.
+// Dial interprets a nil configuration as equivalent to
+// the zero configuration; see the documentation of Config
+// for the defaults.
+func Dial(network, laddr, raddr string, config *Config) (*Conn, os.Error) {
c, err := net.Dial(network, laddr, raddr)
if err != nil {
return nil, err
}
- return Client(c, nil), nil
+
+ colonPos := strings.LastIndex(raddr, ":")
+ if colonPos == -1 {
+ colonPos = len(raddr)
+ }
+ hostname := raddr[:colonPos]
+
+ if config == nil {
+ config = defaultConfig()
+ }
+ if config.ServerName != "" {
+ // Make a copy to avoid polluting argument or default.
+ c := *config
+ c.ServerName = hostname
+ config = &c
+ }
+ conn := Client(c, config)
+ if err = conn.Handshake(); err != nil {
+ c.Close()
+ return nil, err
+ }
+ return conn, nil
+}
+
+// LoadX509KeyPair reads and parses a public/private key pair from a pair of
+// files. The files must contain PEM encoded data.
+func LoadX509KeyPair(certFile string, keyFile string) (cert Certificate, err os.Error) {
+ certPEMBlock, err := ioutil.ReadFile(certFile)
+ if err != nil {
+ return
+ }
+
+ certDERBlock, _ := pem.Decode(certPEMBlock)
+ if certDERBlock == nil {
+ err = os.ErrorString("crypto/tls: failed to parse certificate PEM data")
+ return
+ }
+
+ cert.Certificate = [][]byte{certDERBlock.Bytes}
+
+ keyPEMBlock, err := ioutil.ReadFile(keyFile)
+ if err != nil {
+ return
+ }
+
+ keyDERBlock, _ := pem.Decode(keyPEMBlock)
+ if keyDERBlock == nil {
+ err = os.ErrorString("crypto/tls: failed to parse key PEM data")
+ return
+ }
+
+ key, err := x509.ParsePKCS1PrivateKey(keyDERBlock.Bytes)
+ if err != nil {
+ err = os.ErrorString("crypto/tls: failed to parse key")
+ return
+ }
+
+ cert.PrivateKey = key
+
+ // We don't need to parse the public key for TLS, but we so do anyway
+ // to check that it looks sane and matches the private key.
+ x509Cert, err := x509.ParseCertificate(certDERBlock.Bytes)
+ if err != nil {
+ return
+ }
+
+ if x509Cert.PublicKeyAlgorithm != x509.RSA || x509Cert.PublicKey.(*rsa.PublicKey).N.Cmp(key.PublicKey.N) != 0 {
+ err = os.ErrorString("crypto/tls: private key does not match public key")
+ return
+ }
+
+ return
}
diff --git a/src/pkg/crypto/twofish/Makefile b/src/pkg/crypto/twofish/Makefile
new file mode 100644
index 000000000..aec61659d
--- /dev/null
+++ b/src/pkg/crypto/twofish/Makefile
@@ -0,0 +1,11 @@
+# Copyright 2011 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=crypto/twofish
+GOFILES=\
+ twofish.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/crypto/twofish/twofish.go b/src/pkg/crypto/twofish/twofish.go
new file mode 100644
index 000000000..b362c44d2
--- /dev/null
+++ b/src/pkg/crypto/twofish/twofish.go
@@ -0,0 +1,358 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package implements Bruce Schneier's Twofish encryption algorithm.
+package twofish
+
+// Twofish is defined in http://www.schneier.com/paper-twofish-paper.pdf [TWOFISH]
+
+// This code is a port of the LibTom C implementation.
+// See http://libtom.org/?page=features&newsitems=5&whatfile=crypt.
+// LibTomCrypt is free for all purposes under the public domain.
+// It was heavily inspired by the go blowfish package.
+
+import (
+ "os"
+ "strconv"
+)
+
+// BlockSize is the constant block size of Twofish.
+const BlockSize = 16
+
+const mdsPolynomial = 0x169 // x^8 + x^6 + x^5 + x^3 + 1, see [TWOFISH] 4.2
+const rsPolynomial = 0x14d // x^8 + x^6 + x^3 + x^2 + 1, see [TWOFISH] 4.3
+
+// A Cipher is an instance of Twofish encryption using a particular key.
+type Cipher struct {
+ s [4][256]uint32
+ k [40]uint32
+}
+
+type KeySizeError int
+
+func (k KeySizeError) String() string {
+ return "crypto/twofish: invalid key size " + strconv.Itoa(int(k))
+}
+
+// NewCipher creates and returns a Cipher.
+// The key argument should be the Twofish key, 16, 24 or 32 bytes.
+func NewCipher(key []byte) (*Cipher, os.Error) {
+ keylen := len(key)
+
+ if keylen != 16 && keylen != 24 && keylen != 32 {
+ return nil, KeySizeError(keylen)
+ }
+
+ // k is the number of 64 bit words in key
+ k := keylen / 8
+
+ // Create the S[..] words
+ var S [4 * 4]byte
+ for i := 0; i < k; i++ {
+ // Computes [y0 y1 y2 y3] = rs . [x0 x1 x2 x3 x4 x5 x6 x7]
+ for j := 0; j < 4; j++ {
+ for k := 0; k < 8; k++ {
+ S[4*i+j] ^= gfMult(key[8*i+k], rs[j][k], rsPolynomial)
+ }
+ }
+ }
+
+ // Calculate subkeys
+ c := new(Cipher)
+ var tmp [4]byte
+ for i := byte(0); i < 20; i++ {
+ // A = h(p * 2x, Me)
+ for j := 0; j < 4; j++ {
+ tmp[j] = 2 * i
+ }
+ A := h(tmp[:], key, 0)
+
+ // B = rolc(h(p * (2x + 1), Mo), 8)
+ for j := 0; j < 4; j++ {
+ 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 := 0; i <= 255; i++ {
+ 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 := 0; i < 256; i++ {
+ 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 := 0; i < 256; i++ {
+ 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 := 0; i < 40; i++ {
+ c.k[i] = 0
+ }
+ for i := 0; i < 4; i++ {
+ for j := 0; j < 265; j++ {
+ c.s[i][j] = 0
+ }
+ }
+}
+
+// BlockSize returns the Twofish block size, 16 bytes.
+func (c *Cipher) BlockSize() int { return BlockSize }
+
+// store32l stores src in dst in little-endian form.
+func store32l(dst []byte, src uint32) {
+ dst[0] = byte(src)
+ dst[1] = byte(src >> 8)
+ dst[2] = byte(src >> 16)
+ dst[3] = byte(src >> 24)
+ return
+}
+
+// load32l reads a little-endian uint32 from src.
+func load32l(src []byte) uint32 {
+ return uint32(src[0]) | uint32(src[1])<<8 | uint32(src[2])<<16 | uint32(src[3])<<24
+}
+
+// rol returns x after a left circular rotation of y bits.
+func rol(x, y uint32) uint32 {
+ return (x << (y & 31)) | (x >> (32 - (y & 31)))
+}
+
+// ror returns x after a right circular rotation of y bits.
+func ror(x, y uint32) uint32 {
+ return (x >> (y & 31)) | (x << (32 - (y & 31)))
+}
+
+// The RS matrix. See [TWOFISH] 4.3
+var rs = [4][8]byte{
+ {0x01, 0xA4, 0x55, 0x87, 0x5A, 0x58, 0xDB, 0x9E},
+ {0xA4, 0x56, 0x82, 0xF3, 0x1E, 0xC6, 0x68, 0xE5},
+ {0x02, 0xA1, 0xFC, 0xC1, 0x47, 0xAE, 0x3D, 0x19},
+ {0xA4, 0x55, 0x87, 0x5A, 0x58, 0xDB, 0x9E, 0x03},
+}
+
+// sbox tables
+var sbox = [2][256]byte{
+ {
+ 0xa9, 0x67, 0xb3, 0xe8, 0x04, 0xfd, 0xa3, 0x76, 0x9a, 0x92, 0x80, 0x78, 0xe4, 0xdd, 0xd1, 0x38,
+ 0x0d, 0xc6, 0x35, 0x98, 0x18, 0xf7, 0xec, 0x6c, 0x43, 0x75, 0x37, 0x26, 0xfa, 0x13, 0x94, 0x48,
+ 0xf2, 0xd0, 0x8b, 0x30, 0x84, 0x54, 0xdf, 0x23, 0x19, 0x5b, 0x3d, 0x59, 0xf3, 0xae, 0xa2, 0x82,
+ 0x63, 0x01, 0x83, 0x2e, 0xd9, 0x51, 0x9b, 0x7c, 0xa6, 0xeb, 0xa5, 0xbe, 0x16, 0x0c, 0xe3, 0x61,
+ 0xc0, 0x8c, 0x3a, 0xf5, 0x73, 0x2c, 0x25, 0x0b, 0xbb, 0x4e, 0x89, 0x6b, 0x53, 0x6a, 0xb4, 0xf1,
+ 0xe1, 0xe6, 0xbd, 0x45, 0xe2, 0xf4, 0xb6, 0x66, 0xcc, 0x95, 0x03, 0x56, 0xd4, 0x1c, 0x1e, 0xd7,
+ 0xfb, 0xc3, 0x8e, 0xb5, 0xe9, 0xcf, 0xbf, 0xba, 0xea, 0x77, 0x39, 0xaf, 0x33, 0xc9, 0x62, 0x71,
+ 0x81, 0x79, 0x09, 0xad, 0x24, 0xcd, 0xf9, 0xd8, 0xe5, 0xc5, 0xb9, 0x4d, 0x44, 0x08, 0x86, 0xe7,
+ 0xa1, 0x1d, 0xaa, 0xed, 0x06, 0x70, 0xb2, 0xd2, 0x41, 0x7b, 0xa0, 0x11, 0x31, 0xc2, 0x27, 0x90,
+ 0x20, 0xf6, 0x60, 0xff, 0x96, 0x5c, 0xb1, 0xab, 0x9e, 0x9c, 0x52, 0x1b, 0x5f, 0x93, 0x0a, 0xef,
+ 0x91, 0x85, 0x49, 0xee, 0x2d, 0x4f, 0x8f, 0x3b, 0x47, 0x87, 0x6d, 0x46, 0xd6, 0x3e, 0x69, 0x64,
+ 0x2a, 0xce, 0xcb, 0x2f, 0xfc, 0x97, 0x05, 0x7a, 0xac, 0x7f, 0xd5, 0x1a, 0x4b, 0x0e, 0xa7, 0x5a,
+ 0x28, 0x14, 0x3f, 0x29, 0x88, 0x3c, 0x4c, 0x02, 0xb8, 0xda, 0xb0, 0x17, 0x55, 0x1f, 0x8a, 0x7d,
+ 0x57, 0xc7, 0x8d, 0x74, 0xb7, 0xc4, 0x9f, 0x72, 0x7e, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34,
+ 0x6e, 0x50, 0xde, 0x68, 0x65, 0xbc, 0xdb, 0xf8, 0xc8, 0xa8, 0x2b, 0x40, 0xdc, 0xfe, 0x32, 0xa4,
+ 0xca, 0x10, 0x21, 0xf0, 0xd3, 0x5d, 0x0f, 0x00, 0x6f, 0x9d, 0x36, 0x42, 0x4a, 0x5e, 0xc1, 0xe0,
+ },
+ {
+ 0x75, 0xf3, 0xc6, 0xf4, 0xdb, 0x7b, 0xfb, 0xc8, 0x4a, 0xd3, 0xe6, 0x6b, 0x45, 0x7d, 0xe8, 0x4b,
+ 0xd6, 0x32, 0xd8, 0xfd, 0x37, 0x71, 0xf1, 0xe1, 0x30, 0x0f, 0xf8, 0x1b, 0x87, 0xfa, 0x06, 0x3f,
+ 0x5e, 0xba, 0xae, 0x5b, 0x8a, 0x00, 0xbc, 0x9d, 0x6d, 0xc1, 0xb1, 0x0e, 0x80, 0x5d, 0xd2, 0xd5,
+ 0xa0, 0x84, 0x07, 0x14, 0xb5, 0x90, 0x2c, 0xa3, 0xb2, 0x73, 0x4c, 0x54, 0x92, 0x74, 0x36, 0x51,
+ 0x38, 0xb0, 0xbd, 0x5a, 0xfc, 0x60, 0x62, 0x96, 0x6c, 0x42, 0xf7, 0x10, 0x7c, 0x28, 0x27, 0x8c,
+ 0x13, 0x95, 0x9c, 0xc7, 0x24, 0x46, 0x3b, 0x70, 0xca, 0xe3, 0x85, 0xcb, 0x11, 0xd0, 0x93, 0xb8,
+ 0xa6, 0x83, 0x20, 0xff, 0x9f, 0x77, 0xc3, 0xcc, 0x03, 0x6f, 0x08, 0xbf, 0x40, 0xe7, 0x2b, 0xe2,
+ 0x79, 0x0c, 0xaa, 0x82, 0x41, 0x3a, 0xea, 0xb9, 0xe4, 0x9a, 0xa4, 0x97, 0x7e, 0xda, 0x7a, 0x17,
+ 0x66, 0x94, 0xa1, 0x1d, 0x3d, 0xf0, 0xde, 0xb3, 0x0b, 0x72, 0xa7, 0x1c, 0xef, 0xd1, 0x53, 0x3e,
+ 0x8f, 0x33, 0x26, 0x5f, 0xec, 0x76, 0x2a, 0x49, 0x81, 0x88, 0xee, 0x21, 0xc4, 0x1a, 0xeb, 0xd9,
+ 0xc5, 0x39, 0x99, 0xcd, 0xad, 0x31, 0x8b, 0x01, 0x18, 0x23, 0xdd, 0x1f, 0x4e, 0x2d, 0xf9, 0x48,
+ 0x4f, 0xf2, 0x65, 0x8e, 0x78, 0x5c, 0x58, 0x19, 0x8d, 0xe5, 0x98, 0x57, 0x67, 0x7f, 0x05, 0x64,
+ 0xaf, 0x63, 0xb6, 0xfe, 0xf5, 0xb7, 0x3c, 0xa5, 0xce, 0xe9, 0x68, 0x44, 0xe0, 0x4d, 0x43, 0x69,
+ 0x29, 0x2e, 0xac, 0x15, 0x59, 0xa8, 0x0a, 0x9e, 0x6e, 0x47, 0xdf, 0x34, 0x35, 0x6a, 0xcf, 0xdc,
+ 0x22, 0xc9, 0xc0, 0x9b, 0x89, 0xd4, 0xed, 0xab, 0x12, 0xa2, 0x0d, 0x52, 0xbb, 0x02, 0x2f, 0xa9,
+ 0xd7, 0x61, 0x1e, 0xb4, 0x50, 0x04, 0xf6, 0xc2, 0x16, 0x25, 0x86, 0x56, 0x55, 0x09, 0xbe, 0x91,
+ },
+}
+
+// gfMult returns a·b in GF(2^8)/p
+func gfMult(a, b byte, p uint32) byte {
+ B := [2]uint32{0, uint32(b)}
+ P := [2]uint32{0, p}
+ var result uint32
+
+ // branchless GF multiplier
+ for i := 0; i < 7; i++ {
+ result ^= B[a&1]
+ a >>= 1
+ B[1] = P[B[1]>>7] ^ (B[1] << 1)
+ }
+ result ^= B[a&1]
+ return byte(result)
+}
+
+// mdsColumnMult calculates y{col} where [y0 y1 y2 y3] = MDS . [x0]
+func mdsColumnMult(in byte, col int) uint32 {
+ mul01 := in
+ mul5B := gfMult(in, 0x5B, mdsPolynomial)
+ mulEF := gfMult(in, 0xEF, mdsPolynomial)
+
+ switch col {
+ case 0:
+ return uint32(mul01) | uint32(mul5B)<<8 | uint32(mulEF)<<16 | uint32(mulEF)<<24
+ case 1:
+ return uint32(mulEF) | uint32(mulEF)<<8 | uint32(mul5B)<<16 | uint32(mul01)<<24
+ case 2:
+ return uint32(mul5B) | uint32(mulEF)<<8 | uint32(mul01)<<16 | uint32(mulEF)<<24
+ case 3:
+ return uint32(mul5B) | uint32(mul01)<<8 | uint32(mulEF)<<16 | uint32(mul5B)<<24
+ }
+
+ panic("unreachable")
+}
+
+// h implements the S-box generation function. See [TWOFISH] 4.3.5
+func h(in, key []byte, offset int) uint32 {
+ var y [4]byte
+ for x := 0; x < 4; x++ {
+ 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 := 0; i < 4; i++ {
+ mdsMult ^= mdsColumnMult(y[i], i)
+ }
+ return mdsMult
+}
+
+// Encrypt encrypts a 16-byte block from src to dst, which may overlap.
+// Note that for amounts of data larger than a block,
+// it is not safe to just call Encrypt on successive blocks;
+// instead, use an encryption mode like CBC (see crypto/block/cbc.go).
+func (skey *Cipher) Encrypt(dst, src []byte) {
+ S1 := skey.s[0]
+ S2 := skey.s[1]
+ S3 := skey.s[2]
+ S4 := skey.s[3]
+
+ // Load input
+ a := load32l(src[0:4])
+ b := load32l(src[4:8])
+ c := load32l(src[8:12])
+ d := load32l(src[12:16])
+
+ // Pre-whitening
+ a ^= skey.k[0]
+ b ^= skey.k[1]
+ c ^= skey.k[2]
+ d ^= skey.k[3]
+
+ for i := 0; i < 8; i++ {
+ k := skey.k[8+i*4 : 12+i*4]
+ t2 := S2[byte(b)] ^ S3[byte(b>>8)] ^ S4[byte(b>>16)] ^ S1[byte(b>>24)]
+ t1 := S1[byte(a)] ^ S2[byte(a>>8)] ^ S3[byte(a>>16)] ^ S4[byte(a>>24)] + t2
+ c = ror(c^(t1+k[0]), 1)
+ d = rol(d, 1) ^ (t2 + t1 + k[1])
+
+ t2 = S2[byte(d)] ^ S3[byte(d>>8)] ^ S4[byte(d>>16)] ^ S1[byte(d>>24)]
+ t1 = S1[byte(c)] ^ S2[byte(c>>8)] ^ S3[byte(c>>16)] ^ S4[byte(c>>24)] + t2
+ a = ror(a^(t1+k[2]), 1)
+ b = rol(b, 1) ^ (t2 + t1 + k[3])
+ }
+
+ // Output with "undo last swap"
+ ta := c ^ skey.k[4]
+ tb := d ^ skey.k[5]
+ tc := a ^ skey.k[6]
+ td := b ^ skey.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 (skey *Cipher) Decrypt(dst, src []byte) {
+ S1 := skey.s[0]
+ S2 := skey.s[1]
+ S3 := skey.s[2]
+ S4 := skey.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
+ a := tc ^ skey.k[6]
+ b := td ^ skey.k[7]
+ c := ta ^ skey.k[4]
+ d := tb ^ skey.k[5]
+
+ for i := 8; i > 0; i-- {
+ k := skey.k[4+i*4 : 8+i*4]
+ t2 := S2[byte(d)] ^ S3[byte(d>>8)] ^ S4[byte(d>>16)] ^ S1[byte(d>>24)]
+ t1 := S1[byte(c)] ^ S2[byte(c>>8)] ^ S3[byte(c>>16)] ^ S4[byte(c>>24)] + t2
+ a = rol(a, 1) ^ (t1 + k[2])
+ b = ror(b^(t2+t1+k[3]), 1)
+
+ t2 = S2[byte(b)] ^ S3[byte(b>>8)] ^ S4[byte(b>>16)] ^ S1[byte(b>>24)]
+ t1 = S1[byte(a)] ^ S2[byte(a>>8)] ^ S3[byte(a>>16)] ^ S4[byte(a>>24)] + t2
+ c = rol(c, 1) ^ (t1 + k[0])
+ d = ror(d^(t2+t1+k[1]), 1)
+ }
+
+ // Undo pre-whitening
+ a ^= skey.k[0]
+ b ^= skey.k[1]
+ c ^= skey.k[2]
+ d ^= skey.k[3]
+
+ store32l(dst[0:4], a)
+ store32l(dst[4:8], b)
+ store32l(dst[8:12], c)
+ store32l(dst[12:16], d)
+}
diff --git a/src/pkg/crypto/twofish/twofish_test.go b/src/pkg/crypto/twofish/twofish_test.go
new file mode 100644
index 000000000..96ca6797a
--- /dev/null
+++ b/src/pkg/crypto/twofish/twofish_test.go
@@ -0,0 +1,129 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package twofish
+
+import (
+ "bytes"
+ "testing"
+)
+
+var qbox = [2][4][16]byte{
+ {
+ {0x8, 0x1, 0x7, 0xD, 0x6, 0xF, 0x3, 0x2, 0x0, 0xB, 0x5, 0x9, 0xE, 0xC, 0xA, 0x4},
+ {0xE, 0xC, 0xB, 0x8, 0x1, 0x2, 0x3, 0x5, 0xF, 0x4, 0xA, 0x6, 0x7, 0x0, 0x9, 0xD},
+ {0xB, 0xA, 0x5, 0xE, 0x6, 0xD, 0x9, 0x0, 0xC, 0x8, 0xF, 0x3, 0x2, 0x4, 0x7, 0x1},
+ {0xD, 0x7, 0xF, 0x4, 0x1, 0x2, 0x6, 0xE, 0x9, 0xB, 0x3, 0x0, 0x8, 0x5, 0xC, 0xA},
+ },
+ {
+ {0x2, 0x8, 0xB, 0xD, 0xF, 0x7, 0x6, 0xE, 0x3, 0x1, 0x9, 0x4, 0x0, 0xA, 0xC, 0x5},
+ {0x1, 0xE, 0x2, 0xB, 0x4, 0xC, 0x3, 0x7, 0x6, 0xD, 0xA, 0x5, 0xF, 0x9, 0x0, 0x8},
+ {0x4, 0xC, 0x7, 0x5, 0x1, 0x6, 0x9, 0xA, 0x0, 0xE, 0xD, 0x8, 0x2, 0xB, 0x3, 0xF},
+ {0xB, 0x9, 0x5, 0x1, 0xC, 0x3, 0xD, 0xE, 0x6, 0x4, 0x7, 0xF, 0x2, 0x0, 0x8, 0xA},
+ },
+}
+
+// genSbox generates the variable sbox
+func genSbox(qi int, x byte) byte {
+ a0, b0 := x/16, x%16
+ for i := 0; i < 2; i++ {
+ a1 := a0 ^ b0
+ b1 := (a0 ^ ((b0 << 3) | (b0 >> 1)) ^ (a0 << 3)) & 15
+ a0 = qbox[qi][2*i][a1]
+ b0 = qbox[qi][2*i+1][b1]
+ }
+ return (b0 << 4) + a0
+}
+
+func TestSbox(t *testing.T) {
+ for n := 0; n < 2; n++ {
+ for m := 0; m < 256; m++ {
+ 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
index b2ecfdc01..329a61b7c 100644
--- a/src/pkg/crypto/x509/Makefile
+++ b/src/pkg/crypto/x509/Makefile
@@ -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 ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=crypto/x509
GOFILES=\
diff --git a/src/pkg/crypto/x509/x509.go b/src/pkg/crypto/x509/x509.go
index 728116850..6199e8db9 100644
--- a/src/pkg/crypto/x509/x509.go
+++ b/src/pkg/crypto/x509/x509.go
@@ -36,7 +36,7 @@ func rawValueIsInteger(raw *asn1.RawValue) bool {
// 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(&priv, der)
+ rest, err := asn1.Unmarshal(der, &priv)
if len(rest) > 0 {
err = asn1.SyntaxError{"trailing data"}
return
@@ -81,7 +81,7 @@ func MarshalPKCS1PrivateKey(key *rsa.PrivateKey) []byte {
Q: asn1.RawValue{Tag: 2, Bytes: key.Q.Bytes()},
}
- b, _ := asn1.MarshalToMemory(priv)
+ b, _ := asn1.Marshal(priv)
return b
}
@@ -162,9 +162,10 @@ const (
// Name represents an X.509 distinguished name. This only includes the common
// elements of a DN. Additional elements in the name are ignored.
type Name struct {
- Country, Organization, OrganizationalUnit string
- CommonName, SerialNumber, Locality string
- Province, StreetAddress, PostalCode string
+ Country, Organization, OrganizationalUnit []string
+ Locality, Province []string
+ StreetAddress, PostalCode []string
+ SerialNumber, CommonName string
}
func (n *Name) fillFromRDNSequence(rdns *rdnSequence) {
@@ -186,19 +187,19 @@ func (n *Name) fillFromRDNSequence(rdns *rdnSequence) {
case 5:
n.SerialNumber = value
case 6:
- n.Country = value
+ n.Country = append(n.Country, value)
case 7:
- n.Locality = value
+ n.Locality = append(n.Locality, value)
case 8:
- n.Province = value
+ n.Province = append(n.Province, value)
case 9:
- n.StreetAddress = value
+ n.StreetAddress = append(n.StreetAddress, value)
case 10:
- n.Organization = value
+ n.Organization = append(n.Organization, value)
case 11:
- n.OrganizationalUnit = value
+ n.OrganizationalUnit = append(n.OrganizationalUnit, value)
case 17:
- n.PostalCode = value
+ n.PostalCode = append(n.PostalCode, value)
}
}
}
@@ -216,50 +217,40 @@ var (
oidPostalCode = []int{2, 5, 4, 17}
)
-func (n Name) toRDNSequence() (ret rdnSequence) {
- ret = make([]relativeDistinguishedNameSET, 9 /* maximum number of elements */ )
- i := 0
- if len(n.Country) > 0 {
- ret[i] = []attributeTypeAndValue{attributeTypeAndValue{oidCountry, n.Country}}
- i++
- }
- if len(n.Organization) > 0 {
- ret[i] = []attributeTypeAndValue{attributeTypeAndValue{oidOrganization, n.Organization}}
- i++
+// appendRDNs appends a relativeDistinguishedNameSET to the given rdnSequence
+// and returns the new value. The relativeDistinguishedNameSET contains an
+// attributeTypeAndValue for each of the given values. See RFC 5280, A.1, and
+// search for AttributeTypeAndValue.
+func appendRDNs(in rdnSequence, values []string, oid asn1.ObjectIdentifier) rdnSequence {
+ if len(values) == 0 {
+ return in
}
- if len(n.OrganizationalUnit) > 0 {
- ret[i] = []attributeTypeAndValue{attributeTypeAndValue{oidOrganizationalUnit, n.OrganizationalUnit}}
- i++
+
+ s := make([]attributeTypeAndValue, len(values))
+ for i, value := range values {
+ s[i].Type = oid
+ s[i].Value = value
}
+
+ return append(in, s)
+}
+
+func (n Name) toRDNSequence() (ret rdnSequence) {
+ ret = appendRDNs(ret, n.Country, oidCountry)
+ ret = appendRDNs(ret, n.Organization, oidOrganization)
+ ret = appendRDNs(ret, n.OrganizationalUnit, oidOrganizationalUnit)
+ ret = appendRDNs(ret, n.Locality, oidLocatity)
+ ret = appendRDNs(ret, n.Province, oidProvince)
+ ret = appendRDNs(ret, n.StreetAddress, oidStreetAddress)
+ ret = appendRDNs(ret, n.PostalCode, oidPostalCode)
if len(n.CommonName) > 0 {
- ret[i] = []attributeTypeAndValue{attributeTypeAndValue{oidCommonName, n.CommonName}}
- i++
+ ret = appendRDNs(ret, []string{n.CommonName}, oidCommonName)
}
if len(n.SerialNumber) > 0 {
- ret[i] = []attributeTypeAndValue{attributeTypeAndValue{oidSerialNumber, n.SerialNumber}}
- i++
- }
- if len(n.Locality) > 0 {
- ret[i] = []attributeTypeAndValue{attributeTypeAndValue{oidLocatity, n.Locality}}
- i++
- }
- if len(n.Province) > 0 {
- ret[i] = []attributeTypeAndValue{attributeTypeAndValue{oidProvince, n.Province}}
- i++
- }
- if len(n.StreetAddress) > 0 {
- ret[i] = []attributeTypeAndValue{attributeTypeAndValue{oidStreetAddress, n.StreetAddress}}
- i++
- }
- if len(n.PostalCode) > 0 {
- ret[i] = []attributeTypeAndValue{attributeTypeAndValue{oidPostalCode, n.PostalCode}}
- i++
+ ret = appendRDNs(ret, []string{n.SerialNumber}, oidSerialNumber)
}
- // Adding another RDN here? Remember to update the maximum number of
- // elements in the make() at the top of the function.
-
- return ret[0:i]
+ return ret
}
func getSignatureAlgorithmFromOID(oid []int) SignatureAlgorithm {
@@ -338,6 +329,8 @@ type Certificate struct {
// Subject Alternate Name values
DNSNames []string
EmailAddresses []string
+
+ PolicyIdentifiers []asn1.ObjectIdentifier
}
// UnsupportedAlgorithmError results from attempting to perform an operation
@@ -426,19 +419,37 @@ func matchHostnames(pattern, host string) bool {
return true
}
-// IsValidForHost returns true iff c is a valid certificate for the given host.
-func (c *Certificate) IsValidForHost(h string) bool {
+type HostnameError struct {
+ Certificate *Certificate
+ Host string
+}
+
+func (h *HostnameError) String() string {
+ var valid string
+ c := h.Certificate
+ if len(c.DNSNames) > 0 {
+ valid = strings.Join(c.DNSNames, ", ")
+ } else {
+ valid = c.Subject.CommonName
+ }
+ return "certificate is valid for " + valid + ", not " + h.Host
+}
+
+// VerifyHostname returns nil if c is a valid certificate for the named host.
+// Otherwise it returns an os.Error describing the mismatch.
+func (c *Certificate) VerifyHostname(h string) os.Error {
if len(c.DNSNames) > 0 {
for _, match := range c.DNSNames {
if matchHostnames(match, h) {
- return true
+ return nil
}
}
// If Subject Alt Name is given, we ignore the common name.
- return false
+ } else if matchHostnames(c.Subject.CommonName, h) {
+ return nil
}
- return matchHostnames(c.Subject.CommonName, h)
+ return &HostnameError{c, h}
}
type UnhandledCriticalExtension struct{}
@@ -457,11 +468,17 @@ type rsaPublicKey struct {
E int
}
+// RFC 5280 4.2.1.4
+type policyInformation struct {
+ Policy asn1.ObjectIdentifier
+ // policyQualifiers omitted
+}
+
func parsePublicKey(algo PublicKeyAlgorithm, asn1Data []byte) (interface{}, os.Error) {
switch algo {
case RSA:
p := new(rsaPublicKey)
- _, err := asn1.Unmarshal(p, asn1Data)
+ _, err := asn1.Unmarshal(asn1Data, p)
if err != nil {
return nil, err
}
@@ -482,19 +499,6 @@ func parsePublicKey(algo PublicKeyAlgorithm, asn1Data []byte) (interface{}, os.E
panic("unreachable")
}
-func appendString(in []string, v string) (out []string) {
- if cap(in)-len(in) < 1 {
- out = make([]string, len(in)+1, len(in)*2+1)
- for i, v := range in {
- out[i] = v
- }
- } else {
- out = in[0 : len(in)+1]
- }
- out[len(in)] = v
- return out
-}
-
func parseCertificate(in *certificate) (*Certificate, os.Error) {
out := new(Certificate)
out.Raw = in.TBSCertificate.Raw
@@ -511,7 +515,7 @@ func parseCertificate(in *certificate) (*Certificate, os.Error) {
return nil, err
}
- out.Version = in.TBSCertificate.Version
+ out.Version = in.TBSCertificate.Version + 1
out.SerialNumber = in.TBSCertificate.SerialNumber.Bytes
out.Issuer.fillFromRDNSequence(&in.TBSCertificate.Issuer)
out.Subject.fillFromRDNSequence(&in.TBSCertificate.Subject)
@@ -524,7 +528,7 @@ func parseCertificate(in *certificate) (*Certificate, os.Error) {
case 15:
// RFC 5280, 4.2.1.3
var usageBits asn1.BitString
- _, err := asn1.Unmarshal(&usageBits, e.Value)
+ _, err := asn1.Unmarshal(e.Value, &usageBits)
if err == nil {
var usage int
@@ -539,7 +543,7 @@ func parseCertificate(in *certificate) (*Certificate, os.Error) {
case 19:
// RFC 5280, 4.2.1.9
var constriants basicConstraints
- _, err := asn1.Unmarshal(&constriants, e.Value)
+ _, err := asn1.Unmarshal(e.Value, &constriants)
if err == nil {
out.BasicConstraintsValid = true
@@ -565,7 +569,7 @@ func parseCertificate(in *certificate) (*Certificate, os.Error) {
// iPAddress [7] OCTET STRING,
// registeredID [8] OBJECT IDENTIFIER }
var seq asn1.RawValue
- _, err := asn1.Unmarshal(&seq, e.Value)
+ _, err := asn1.Unmarshal(e.Value, &seq)
if err != nil {
return nil, err
}
@@ -578,16 +582,16 @@ func parseCertificate(in *certificate) (*Certificate, os.Error) {
rest := seq.Bytes
for len(rest) > 0 {
var v asn1.RawValue
- rest, err = asn1.Unmarshal(&v, rest)
+ rest, err = asn1.Unmarshal(rest, &v)
if err != nil {
return nil, err
}
switch v.Tag {
case 1:
- out.EmailAddresses = appendString(out.EmailAddresses, string(v.Bytes))
+ out.EmailAddresses = append(out.EmailAddresses, string(v.Bytes))
parsedName = true
case 2:
- out.DNSNames = appendString(out.DNSNames, string(v.Bytes))
+ out.DNSNames = append(out.DNSNames, string(v.Bytes))
parsedName = true
}
}
@@ -601,7 +605,7 @@ func parseCertificate(in *certificate) (*Certificate, os.Error) {
case 35:
// RFC 5280, 4.2.1.1
var a authKeyId
- _, err = asn1.Unmarshal(&a, e.Value)
+ _, err = asn1.Unmarshal(e.Value, &a)
if err != nil {
return nil, err
}
@@ -610,8 +614,24 @@ func parseCertificate(in *certificate) (*Certificate, os.Error) {
case 14:
// RFC 5280, 4.2.1.2
- out.SubjectKeyId = e.Value
+ var keyid []byte
+ _, err = asn1.Unmarshal(e.Value, &keyid)
+ if err != nil {
+ return nil, err
+ }
+ out.SubjectKeyId = keyid
continue
+
+ case 32:
+ // RFC 5280 4.2.1.4: Certificate Policies
+ var policies []policyInformation
+ if _, err = asn1.Unmarshal(e.Value, &policies); err != nil {
+ return nil, err
+ }
+ out.PolicyIdentifiers = make([]asn1.ObjectIdentifier, len(policies))
+ for i, policy := range policies {
+ out.PolicyIdentifiers[i] = policy.Policy
+ }
}
}
@@ -626,7 +646,7 @@ 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) {
var cert certificate
- rest, err := asn1.Unmarshal(&cert, asn1Data)
+ rest, err := asn1.Unmarshal(asn1Data, &cert)
if err != nil {
return nil, err
}
@@ -645,7 +665,7 @@ func ParseCertificates(asn1Data []byte) ([]*Certificate, os.Error) {
for len(asn1Data) > 0 {
cert := new(certificate)
var err os.Error
- asn1Data, err = asn1.Unmarshal(cert, asn1Data)
+ asn1Data, err = asn1.Unmarshal(asn1Data, cert)
if err != nil {
return nil, err
}
@@ -672,15 +692,16 @@ func reverseBitsInAByte(in byte) byte {
}
var (
- oidExtensionSubjectKeyId = []int{2, 5, 29, 14}
- oidExtensionKeyUsage = []int{2, 5, 29, 15}
- oidExtensionAuthorityKeyId = []int{2, 5, 29, 35}
- oidExtensionBasicConstraints = []int{2, 5, 29, 19}
- oidExtensionSubjectAltName = []int{2, 5, 29, 17}
+ oidExtensionSubjectKeyId = []int{2, 5, 29, 14}
+ oidExtensionKeyUsage = []int{2, 5, 29, 15}
+ oidExtensionAuthorityKeyId = []int{2, 5, 29, 35}
+ oidExtensionBasicConstraints = []int{2, 5, 29, 19}
+ oidExtensionSubjectAltName = []int{2, 5, 29, 17}
+ oidExtensionCertificatePolicies = []int{2, 5, 29, 32}
)
func buildExtensions(template *Certificate) (ret []extension, err os.Error) {
- ret = make([]extension, 5 /* maximum number of elements. */ )
+ ret = make([]extension, 6 /* maximum number of elements. */ )
n := 0
if template.KeyUsage != 0 {
@@ -696,7 +717,7 @@ func buildExtensions(template *Certificate) (ret []extension, err os.Error) {
l = 2
}
- ret[n].Value, err = asn1.MarshalToMemory(asn1.BitString{Bytes: a[0:l], BitLength: l * 8})
+ ret[n].Value, err = asn1.Marshal(asn1.BitString{Bytes: a[0:l], BitLength: l * 8})
if err != nil {
return
}
@@ -705,7 +726,7 @@ func buildExtensions(template *Certificate) (ret []extension, err os.Error) {
if template.BasicConstraintsValid {
ret[n].Id = oidExtensionBasicConstraints
- ret[n].Value, err = asn1.MarshalToMemory(basicConstraints{template.IsCA, template.MaxPathLen})
+ ret[n].Value, err = asn1.Marshal(basicConstraints{template.IsCA, template.MaxPathLen})
ret[n].Critical = true
if err != nil {
return
@@ -715,7 +736,7 @@ func buildExtensions(template *Certificate) (ret []extension, err os.Error) {
if len(template.SubjectKeyId) > 0 {
ret[n].Id = oidExtensionSubjectKeyId
- ret[n].Value, err = asn1.MarshalToMemory(template.SubjectKeyId)
+ ret[n].Value, err = asn1.Marshal(template.SubjectKeyId)
if err != nil {
return
}
@@ -724,7 +745,7 @@ func buildExtensions(template *Certificate) (ret []extension, err os.Error) {
if len(template.AuthorityKeyId) > 0 {
ret[n].Id = oidExtensionAuthorityKeyId
- ret[n].Value, err = asn1.MarshalToMemory(authKeyId{template.AuthorityKeyId})
+ ret[n].Value, err = asn1.Marshal(authKeyId{template.AuthorityKeyId})
if err != nil {
return
}
@@ -737,7 +758,20 @@ func buildExtensions(template *Certificate) (ret []extension, err os.Error) {
for i, name := range template.DNSNames {
rawValues[i] = asn1.RawValue{Tag: 2, Class: 2, Bytes: []byte(name)}
}
- ret[n].Value, err = asn1.MarshalToMemory(rawValues)
+ ret[n].Value, err = asn1.Marshal(rawValues)
+ if err != nil {
+ return
+ }
+ n++
+ }
+
+ if len(template.PolicyIdentifiers) > 0 {
+ ret[n].Id = oidExtensionCertificatePolicies
+ policies := make([]policyInformation, len(template.PolicyIdentifiers))
+ for i, policy := range template.PolicyIdentifiers {
+ policies[i].Policy = policy
+ }
+ ret[n].Value, err = asn1.Marshal(policies)
if err != nil {
return
}
@@ -766,7 +800,7 @@ var (
//
// The returned slice is the certificate in DER encoding.
func CreateCertificate(rand io.Reader, template, parent *Certificate, pub *rsa.PublicKey, priv *rsa.PrivateKey) (cert []byte, err os.Error) {
- asn1PublicKey, err := asn1.MarshalToMemory(rsaPublicKey{
+ asn1PublicKey, err := asn1.Marshal(rsaPublicKey{
N: asn1.RawValue{Tag: 2, Bytes: pub.N.Bytes()},
E: pub.E,
})
@@ -785,7 +819,7 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub *rsa.P
encodedPublicKey := asn1.BitString{BitLength: len(asn1PublicKey) * 8, Bytes: asn1PublicKey}
c := tbsCertificate{
- Version: 3,
+ Version: 2,
SerialNumber: asn1.RawValue{Bytes: template.SerialNumber, Tag: 2},
SignatureAlgorithm: algorithmIdentifier{oidSHA1WithRSA},
Issuer: parent.Subject.toRDNSequence(),
@@ -795,7 +829,7 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub *rsa.P
Extensions: extensions,
}
- tbsCertContents, err := asn1.MarshalToMemory(c)
+ tbsCertContents, err := asn1.Marshal(c)
if err != nil {
return
}
@@ -811,7 +845,7 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub *rsa.P
return
}
- cert, err = asn1.MarshalToMemory(certificate{
+ cert, err = asn1.Marshal(certificate{
c,
algorithmIdentifier{oidSHA1WithRSA},
asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
diff --git a/src/pkg/crypto/x509/x509_test.go b/src/pkg/crypto/x509/x509_test.go
index 23ce1ad11..2fe47fdbe 100644
--- a/src/pkg/crypto/x509/x509_test.go
+++ b/src/pkg/crypto/x509/x509_test.go
@@ -5,11 +5,12 @@
package x509
import (
+ "asn1"
"big"
+ "crypto/rand"
"crypto/rsa"
"encoding/hex"
"encoding/pem"
- "os"
"reflect"
"testing"
"time"
@@ -59,16 +60,16 @@ type matchHostnamesTest struct {
}
var matchHostnamesTests = []matchHostnamesTest{
- matchHostnamesTest{"a.b.c", "a.b.c", true},
- matchHostnamesTest{"a.b.c", "b.b.c", false},
- matchHostnamesTest{"", "b.b.c", false},
- matchHostnamesTest{"a.b.c", "", false},
- matchHostnamesTest{"example.com", "example.com", true},
- matchHostnamesTest{"example.com", "www.example.com", false},
- matchHostnamesTest{"*.example.com", "www.example.com", true},
- matchHostnamesTest{"*.example.com", "xyz.www.example.com", false},
- matchHostnamesTest{"*.*.example.com", "xyz.www.example.com", true},
- matchHostnamesTest{"*.www.*.com", "xyz.www.example.com", true},
+ {"a.b.c", "a.b.c", true},
+ {"a.b.c", "b.b.c", false},
+ {"", "b.b.c", false},
+ {"a.b.c", "", false},
+ {"example.com", "example.com", true},
+ {"example.com", "www.example.com", false},
+ {"*.example.com", "www.example.com", true},
+ {"*.example.com", "xyz.www.example.com", false},
+ {"*.*.example.com", "xyz.www.example.com", true},
+ {"*.www.*.com", "xyz.www.example.com", true},
}
func TestMatchHostnames(t *testing.T) {
@@ -96,8 +97,8 @@ func TestCertificateParse(t *testing.T) {
t.Error(err)
}
- if !certs[0].IsValidForHost("mail.google.com") {
- t.Errorf("cert not valid for host")
+ if err := certs[0].VerifyHostname("mail.google.com"); err != nil {
+ t.Error(err)
}
}
@@ -145,10 +146,7 @@ var certBytes = "308203223082028ba00302010202106edf0d9499fd4533dd1297fc42a93be13
"36dcd585d6ace53f546f961e05af"
func TestCreateSelfSignedCertificate(t *testing.T) {
- urandom, err := os.Open("/dev/urandom", os.O_RDONLY, 0)
- if err != nil {
- t.Errorf("failed to open /dev/urandom")
- }
+ random := rand.Reader
block, _ := pem.Decode([]byte(pemPrivateKey))
priv, err := ParsePKCS1PrivateKey(block.Bytes)
@@ -161,7 +159,7 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
SerialNumber: []byte{1},
Subject: Name{
CommonName: "test.example.com",
- Organization: "Acme Co",
+ Organization: []string{"Acme Co"},
},
NotBefore: time.SecondsToUTC(1000),
NotAfter: time.SecondsToUTC(100000),
@@ -172,9 +170,11 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
BasicConstraintsValid: true,
IsCA: true,
DNSNames: []string{"test.example.com"},
+
+ PolicyIdentifiers: []asn1.ObjectIdentifier{[]int{1, 2, 3}},
}
- derBytes, err := CreateCertificate(urandom, &template, &template, &priv.PublicKey, priv)
+ derBytes, err := CreateCertificate(random, &template, &template, &priv.PublicKey, priv)
if err != nil {
t.Errorf("Failed to create certificate: %s", err)
return
@@ -185,6 +185,11 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
t.Errorf("Failed to parse certificate: %s", err)
return
}
+
+ if len(cert.PolicyIdentifiers) != 1 || !cert.PolicyIdentifiers[0].Equal(template.PolicyIdentifiers[0]) {
+ t.Errorf("Failed to parse policy identifiers: got:%#v want:%#v", cert.PolicyIdentifiers, template.PolicyIdentifiers)
+ }
+
err = cert.CheckSignatureFrom(cert)
if err != nil {
t.Errorf("Signature verification failed: %s", err)
diff --git a/src/pkg/crypto/xtea/Makefile b/src/pkg/crypto/xtea/Makefile
index 74cc1b0dc..301621168 100644
--- a/src/pkg/crypto/xtea/Makefile
+++ b/src/pkg/crypto/xtea/Makefile
@@ -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 ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=crypto/xtea
GOFILES=\
diff --git a/src/pkg/crypto/xtea/block.go b/src/pkg/crypto/xtea/block.go
index dfb82e1e2..3ac36d038 100644
--- a/src/pkg/crypto/xtea/block.go
+++ b/src/pkg/crypto/xtea/block.go
@@ -36,7 +36,7 @@ func uint32ToBlock(v0, v1 uint32, dst []byte) {
}
// encryptBlock encrypts a single 8 byte block using XTEA.
-func encryptBlock(c *Cipher, src, dst []byte) {
+func encryptBlock(c *Cipher, dst, src []byte) {
v0, v1 := blockToUint32(src)
// Two rounds of XTEA applied per loop
@@ -51,7 +51,7 @@ func encryptBlock(c *Cipher, src, dst []byte) {
}
// decryptBlock decrypt a single 8 byte block using XTEA.
-func decryptBlock(c *Cipher, src, dst []byte) {
+func decryptBlock(c *Cipher, dst, src []byte) {
v0, v1 := blockToUint32(src)
// Two rounds of XTEA applied per loop
diff --git a/src/pkg/crypto/xtea/cipher.go b/src/pkg/crypto/xtea/cipher.go
index 144fe9434..b0fa2a184 100644
--- a/src/pkg/crypto/xtea/cipher.go
+++ b/src/pkg/crypto/xtea/cipher.go
@@ -55,10 +55,10 @@ func (c *Cipher) BlockSize() int { return BlockSize }
// Note that for amounts of data larger than a block,
// it is not safe to just call Encrypt on successive blocks;
// instead, use an encryption mode like CBC (see crypto/block/cbc.go).
-func (c *Cipher) Encrypt(src, dst []byte) { encryptBlock(c, src, dst) }
+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(src, dst []byte) { decryptBlock(c, src, 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() {
diff --git a/src/pkg/crypto/xtea/xtea_test.go b/src/pkg/crypto/xtea/xtea_test.go
index 94756f79f..03934f169 100644
--- a/src/pkg/crypto/xtea/xtea_test.go
+++ b/src/pkg/crypto/xtea/xtea_test.go
@@ -94,7 +94,7 @@ func TestEncodeDecode(t *testing.T) {
}
// Encrypt the input block
- c.Encrypt(input, output)
+ c.Encrypt(output, input)
// Check that the output does not match the input
differs := false
@@ -112,7 +112,7 @@ func TestEncodeDecode(t *testing.T) {
// Decrypt the block we just encrypted
input = output
output = make([]byte, BlockSize)
- c.Decrypt(input, output)
+ c.Decrypt(output, input)
// Check that the output from decrypt matches our initial input
for i := 0; i < len(input); i++ {
@@ -132,54 +132,54 @@ type CryptTest struct {
var CryptTests = []CryptTest{
// These were sourced from http://www.freemedialibrary.com/index.php/XTEA_test_vectors
- CryptTest{
+ {
[]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},
},
- CryptTest{
+ {
[]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},
},
- CryptTest{
+ {
[]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},
},
- CryptTest{
+ {
[]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},
},
- CryptTest{
+ {
[]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},
},
- CryptTest{
+ {
[]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
- CryptTest{
+ {
[]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},
},
- CryptTest{
+ {
[]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},
},
- CryptTest{
+ {
[]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},
},
- CryptTest{
+ {
[]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},
@@ -196,7 +196,7 @@ func TestCipherEncrypt(t *testing.T) {
}
out := make([]byte, len(tt.plainText))
- c.Encrypt(tt.plainText, out)
+ c.Encrypt(out, tt.plainText)
for j := 0; j < len(out); j++ {
if out[j] != tt.cipherText[j] {
@@ -217,7 +217,7 @@ func TestCipherDecrypt(t *testing.T) {
}
out := make([]byte, len(tt.cipherText))
- c.Decrypt(tt.cipherText, out)
+ c.Decrypt(out, tt.cipherText)
for j := 0; j < len(out); j++ {
if out[j] != tt.plainText[j] {
diff --git a/src/pkg/debug/dwarf/Makefile b/src/pkg/debug/dwarf/Makefile
index a626513c7..c4203188e 100644
--- a/src/pkg/debug/dwarf/Makefile
+++ b/src/pkg/debug/dwarf/Makefile
@@ -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 ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=debug/dwarf
GOFILES=\
diff --git a/src/pkg/debug/dwarf/type.go b/src/pkg/debug/dwarf/type.go
index 5d4a51653..902a545f8 100644
--- a/src/pkg/debug/dwarf/type.go
+++ b/src/pkg/debug/dwarf/type.go
@@ -451,16 +451,7 @@ func (d *Data) Type(off Offset) (Type, os.Error) {
f.ByteSize, _ = kid.Val(AttrByteSize).(int64)
f.BitOffset, _ = kid.Val(AttrBitOffset).(int64)
f.BitSize, _ = kid.Val(AttrBitSize).(int64)
- n := len(t.Field)
- if n >= cap(t.Field) {
- fld := make([]*StructField, n, n*2)
- for i, f := range t.Field {
- fld[i] = f
- }
- t.Field = fld
- }
- t.Field = t.Field[0 : n+1]
- t.Field[n] = f
+ t.Field = append(t.Field, f)
}
}
@@ -505,9 +496,7 @@ func (d *Data) Type(off Offset) (Type, os.Error) {
n := len(t.Val)
if n >= cap(t.Val) {
val := make([]*EnumValue, n, n*2)
- for i, f := range t.Val {
- val[i] = f
- }
+ copy(val, t.Val)
t.Val = val
}
t.Val = t.Val[0 : n+1]
@@ -558,16 +547,7 @@ func (d *Data) Type(off Offset) (Type, os.Error) {
case TagUnspecifiedParameters:
tkid = &DotDotDotType{}
}
- n := len(t.ParamType)
- if n >= cap(t.ParamType) {
- param := make([]Type, n, n*2)
- for i, t := range t.ParamType {
- param[i] = t
- }
- t.ParamType = param
- }
- t.ParamType = t.ParamType[0 : n+1]
- t.ParamType[n] = tkid
+ t.ParamType = append(t.ParamType, tkid)
}
case TagTypedef:
diff --git a/src/pkg/debug/elf/Makefile b/src/pkg/debug/elf/Makefile
index 931f9d24d..dd431f653 100644
--- a/src/pkg/debug/elf/Makefile
+++ b/src/pkg/debug/elf/Makefile
@@ -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 ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=debug/elf
GOFILES=\
diff --git a/src/pkg/debug/elf/elf.go b/src/pkg/debug/elf/elf.go
index 394a7cc87..74e979986 100644
--- a/src/pkg/debug/elf/elf.go
+++ b/src/pkg/debug/elf/elf.go
@@ -69,8 +69,8 @@ const (
)
var versionStrings = []intName{
- intName{0, "EV_NONE"},
- intName{1, "EV_CURRENT"},
+ {0, "EV_NONE"},
+ {1, "EV_CURRENT"},
}
func (i Version) String() string { return stringName(uint32(i), versionStrings, false) }
@@ -86,9 +86,9 @@ const (
)
var classStrings = []intName{
- intName{0, "ELFCLASSNONE"},
- intName{1, "ELFCLASS32"},
- intName{2, "ELFCLASS64"},
+ {0, "ELFCLASSNONE"},
+ {1, "ELFCLASS32"},
+ {2, "ELFCLASS64"},
}
func (i Class) String() string { return stringName(uint32(i), classStrings, false) }
@@ -104,9 +104,9 @@ const (
)
var dataStrings = []intName{
- intName{0, "ELFDATANONE"},
- intName{1, "ELFDATA2LSB"},
- intName{2, "ELFDATA2MSB"},
+ {0, "ELFDATANONE"},
+ {1, "ELFDATA2LSB"},
+ {2, "ELFDATA2MSB"},
}
func (i Data) String() string { return stringName(uint32(i), dataStrings, false) }
@@ -136,23 +136,23 @@ const (
)
var osabiStrings = []intName{
- intName{0, "ELFOSABI_NONE"},
- intName{1, "ELFOSABI_HPUX"},
- intName{2, "ELFOSABI_NETBSD"},
- intName{3, "ELFOSABI_LINUX"},
- intName{4, "ELFOSABI_HURD"},
- intName{5, "ELFOSABI_86OPEN"},
- intName{6, "ELFOSABI_SOLARIS"},
- intName{7, "ELFOSABI_AIX"},
- intName{8, "ELFOSABI_IRIX"},
- intName{9, "ELFOSABI_FREEBSD"},
- intName{10, "ELFOSABI_TRU64"},
- intName{11, "ELFOSABI_MODESTO"},
- intName{12, "ELFOSABI_OPENBSD"},
- intName{13, "ELFOSABI_OPENVMS"},
- intName{14, "ELFOSABI_NSK"},
- intName{97, "ELFOSABI_ARM"},
- intName{255, "ELFOSABI_STANDALONE"},
+ {0, "ELFOSABI_NONE"},
+ {1, "ELFOSABI_HPUX"},
+ {2, "ELFOSABI_NETBSD"},
+ {3, "ELFOSABI_LINUX"},
+ {4, "ELFOSABI_HURD"},
+ {5, "ELFOSABI_86OPEN"},
+ {6, "ELFOSABI_SOLARIS"},
+ {7, "ELFOSABI_AIX"},
+ {8, "ELFOSABI_IRIX"},
+ {9, "ELFOSABI_FREEBSD"},
+ {10, "ELFOSABI_TRU64"},
+ {11, "ELFOSABI_MODESTO"},
+ {12, "ELFOSABI_OPENBSD"},
+ {13, "ELFOSABI_OPENVMS"},
+ {14, "ELFOSABI_NSK"},
+ {97, "ELFOSABI_ARM"},
+ {255, "ELFOSABI_STANDALONE"},
}
func (i OSABI) String() string { return stringName(uint32(i), osabiStrings, false) }
@@ -174,15 +174,15 @@ const (
)
var typeStrings = []intName{
- intName{0, "ET_NONE"},
- intName{1, "ET_REL"},
- intName{2, "ET_EXEC"},
- intName{3, "ET_DYN"},
- intName{4, "ET_CORE"},
- intName{0xfe00, "ET_LOOS"},
- intName{0xfeff, "ET_HIOS"},
- intName{0xff00, "ET_LOPROC"},
- intName{0xffff, "ET_HIPROC"},
+ {0, "ET_NONE"},
+ {1, "ET_REL"},
+ {2, "ET_EXEC"},
+ {3, "ET_DYN"},
+ {4, "ET_CORE"},
+ {0xfe00, "ET_LOOS"},
+ {0xfeff, "ET_HIOS"},
+ {0xff00, "ET_LOPROC"},
+ {0xffff, "ET_HIPROC"},
}
func (i Type) String() string { return stringName(uint32(i), typeStrings, false) }
@@ -244,55 +244,55 @@ const (
)
var machineStrings = []intName{
- intName{0, "EM_NONE"},
- intName{1, "EM_M32"},
- intName{2, "EM_SPARC"},
- intName{3, "EM_386"},
- intName{4, "EM_68K"},
- intName{5, "EM_88K"},
- intName{7, "EM_860"},
- intName{8, "EM_MIPS"},
- intName{9, "EM_S370"},
- intName{10, "EM_MIPS_RS3_LE"},
- intName{15, "EM_PARISC"},
- intName{17, "EM_VPP500"},
- intName{18, "EM_SPARC32PLUS"},
- intName{19, "EM_960"},
- intName{20, "EM_PPC"},
- intName{21, "EM_PPC64"},
- intName{22, "EM_S390"},
- intName{36, "EM_V800"},
- intName{37, "EM_FR20"},
- intName{38, "EM_RH32"},
- intName{39, "EM_RCE"},
- intName{40, "EM_ARM"},
- intName{42, "EM_SH"},
- intName{43, "EM_SPARCV9"},
- intName{44, "EM_TRICORE"},
- intName{45, "EM_ARC"},
- intName{46, "EM_H8_300"},
- intName{47, "EM_H8_300H"},
- intName{48, "EM_H8S"},
- intName{49, "EM_H8_500"},
- intName{50, "EM_IA_64"},
- intName{51, "EM_MIPS_X"},
- intName{52, "EM_COLDFIRE"},
- intName{53, "EM_68HC12"},
- intName{54, "EM_MMA"},
- intName{55, "EM_PCP"},
- intName{56, "EM_NCPU"},
- intName{57, "EM_NDR1"},
- intName{58, "EM_STARCORE"},
- intName{59, "EM_ME16"},
- intName{60, "EM_ST100"},
- intName{61, "EM_TINYJ"},
- intName{62, "EM_X86_64"},
+ {0, "EM_NONE"},
+ {1, "EM_M32"},
+ {2, "EM_SPARC"},
+ {3, "EM_386"},
+ {4, "EM_68K"},
+ {5, "EM_88K"},
+ {7, "EM_860"},
+ {8, "EM_MIPS"},
+ {9, "EM_S370"},
+ {10, "EM_MIPS_RS3_LE"},
+ {15, "EM_PARISC"},
+ {17, "EM_VPP500"},
+ {18, "EM_SPARC32PLUS"},
+ {19, "EM_960"},
+ {20, "EM_PPC"},
+ {21, "EM_PPC64"},
+ {22, "EM_S390"},
+ {36, "EM_V800"},
+ {37, "EM_FR20"},
+ {38, "EM_RH32"},
+ {39, "EM_RCE"},
+ {40, "EM_ARM"},
+ {42, "EM_SH"},
+ {43, "EM_SPARCV9"},
+ {44, "EM_TRICORE"},
+ {45, "EM_ARC"},
+ {46, "EM_H8_300"},
+ {47, "EM_H8_300H"},
+ {48, "EM_H8S"},
+ {49, "EM_H8_500"},
+ {50, "EM_IA_64"},
+ {51, "EM_MIPS_X"},
+ {52, "EM_COLDFIRE"},
+ {53, "EM_68HC12"},
+ {54, "EM_MMA"},
+ {55, "EM_PCP"},
+ {56, "EM_NCPU"},
+ {57, "EM_NDR1"},
+ {58, "EM_STARCORE"},
+ {59, "EM_ME16"},
+ {60, "EM_ST100"},
+ {61, "EM_TINYJ"},
+ {62, "EM_X86_64"},
/* Non-standard or deprecated. */
- intName{6, "EM_486"},
- intName{10, "EM_MIPS_RS4_BE"},
- intName{41, "EM_ALPHA_STD"},
- intName{0x9026, "EM_ALPHA"},
+ {6, "EM_486"},
+ {10, "EM_MIPS_RS4_BE"},
+ {41, "EM_ALPHA_STD"},
+ {0x9026, "EM_ALPHA"},
}
func (i Machine) String() string { return stringName(uint32(i), machineStrings, false) }
@@ -315,12 +315,12 @@ const (
)
var shnStrings = []intName{
- intName{0, "SHN_UNDEF"},
- intName{0xff00, "SHN_LOPROC"},
- intName{0xff20, "SHN_LOOS"},
- intName{0xfff1, "SHN_ABS"},
- intName{0xfff2, "SHN_COMMON"},
- intName{0xffff, "SHN_XINDEX"},
+ {0, "SHN_UNDEF"},
+ {0xff00, "SHN_LOPROC"},
+ {0xff20, "SHN_LOOS"},
+ {0xfff1, "SHN_ABS"},
+ {0xfff2, "SHN_COMMON"},
+ {0xffff, "SHN_XINDEX"},
}
func (i SectionIndex) String() string { return stringName(uint32(i), shnStrings, false) }
@@ -356,29 +356,29 @@ const (
)
var shtStrings = []intName{
- intName{0, "SHT_NULL"},
- intName{1, "SHT_PROGBITS"},
- intName{2, "SHT_SYMTAB"},
- intName{3, "SHT_STRTAB"},
- intName{4, "SHT_RELA"},
- intName{5, "SHT_HASH"},
- intName{6, "SHT_DYNAMIC"},
- intName{7, "SHT_NOTE"},
- intName{8, "SHT_NOBITS"},
- intName{9, "SHT_REL"},
- intName{10, "SHT_SHLIB"},
- intName{11, "SHT_DYNSYM"},
- intName{14, "SHT_INIT_ARRAY"},
- intName{15, "SHT_FINI_ARRAY"},
- intName{16, "SHT_PREINIT_ARRAY"},
- intName{17, "SHT_GROUP"},
- intName{18, "SHT_SYMTAB_SHNDX"},
- intName{0x60000000, "SHT_LOOS"},
- intName{0x6fffffff, "SHT_HIOS"},
- intName{0x70000000, "SHT_LOPROC"},
- intName{0x7fffffff, "SHT_HIPROC"},
- intName{0x80000000, "SHT_LOUSER"},
- intName{0xffffffff, "SHT_HIUSER"},
+ {0, "SHT_NULL"},
+ {1, "SHT_PROGBITS"},
+ {2, "SHT_SYMTAB"},
+ {3, "SHT_STRTAB"},
+ {4, "SHT_RELA"},
+ {5, "SHT_HASH"},
+ {6, "SHT_DYNAMIC"},
+ {7, "SHT_NOTE"},
+ {8, "SHT_NOBITS"},
+ {9, "SHT_REL"},
+ {10, "SHT_SHLIB"},
+ {11, "SHT_DYNSYM"},
+ {14, "SHT_INIT_ARRAY"},
+ {15, "SHT_FINI_ARRAY"},
+ {16, "SHT_PREINIT_ARRAY"},
+ {17, "SHT_GROUP"},
+ {18, "SHT_SYMTAB_SHNDX"},
+ {0x60000000, "SHT_LOOS"},
+ {0x6fffffff, "SHT_HIOS"},
+ {0x70000000, "SHT_LOPROC"},
+ {0x7fffffff, "SHT_HIPROC"},
+ {0x80000000, "SHT_LOUSER"},
+ {0xffffffff, "SHT_HIUSER"},
}
func (i SectionType) String() string { return stringName(uint32(i), shtStrings, false) }
@@ -403,16 +403,16 @@ const (
)
var shfStrings = []intName{
- intName{0x1, "SHF_WRITE"},
- intName{0x2, "SHF_ALLOC"},
- intName{0x4, "SHF_EXECINSTR"},
- intName{0x10, "SHF_MERGE"},
- intName{0x20, "SHF_STRINGS"},
- intName{0x40, "SHF_INFO_LINK"},
- intName{0x80, "SHF_LINK_ORDER"},
- intName{0x100, "SHF_OS_NONCONFORMING"},
- intName{0x200, "SHF_GROUP"},
- intName{0x400, "SHF_TLS"},
+ {0x1, "SHF_WRITE"},
+ {0x2, "SHF_ALLOC"},
+ {0x4, "SHF_EXECINSTR"},
+ {0x10, "SHF_MERGE"},
+ {0x20, "SHF_STRINGS"},
+ {0x40, "SHF_INFO_LINK"},
+ {0x80, "SHF_LINK_ORDER"},
+ {0x100, "SHF_OS_NONCONFORMING"},
+ {0x200, "SHF_GROUP"},
+ {0x400, "SHF_TLS"},
}
func (i SectionFlag) String() string { return flagName(uint32(i), shfStrings, false) }
@@ -437,18 +437,18 @@ const (
)
var ptStrings = []intName{
- intName{0, "PT_NULL"},
- intName{1, "PT_LOAD"},
- intName{2, "PT_DYNAMIC"},
- intName{3, "PT_INTERP"},
- intName{4, "PT_NOTE"},
- intName{5, "PT_SHLIB"},
- intName{6, "PT_PHDR"},
- intName{7, "PT_TLS"},
- intName{0x60000000, "PT_LOOS"},
- intName{0x6fffffff, "PT_HIOS"},
- intName{0x70000000, "PT_LOPROC"},
- intName{0x7fffffff, "PT_HIPROC"},
+ {0, "PT_NULL"},
+ {1, "PT_LOAD"},
+ {2, "PT_DYNAMIC"},
+ {3, "PT_INTERP"},
+ {4, "PT_NOTE"},
+ {5, "PT_SHLIB"},
+ {6, "PT_PHDR"},
+ {7, "PT_TLS"},
+ {0x60000000, "PT_LOOS"},
+ {0x6fffffff, "PT_HIOS"},
+ {0x70000000, "PT_LOPROC"},
+ {0x7fffffff, "PT_HIPROC"},
}
func (i ProgType) String() string { return stringName(uint32(i), ptStrings, false) }
@@ -466,9 +466,9 @@ const (
)
var pfStrings = []intName{
- intName{0x1, "PF_X"},
- intName{0x2, "PF_W"},
- intName{0x4, "PF_R"},
+ {0x1, "PF_X"},
+ {0x2, "PF_W"},
+ {0x4, "PF_R"},
}
func (i ProgFlag) String() string { return flagName(uint32(i), pfStrings, false) }
@@ -523,44 +523,44 @@ const (
)
var dtStrings = []intName{
- intName{0, "DT_NULL"},
- intName{1, "DT_NEEDED"},
- intName{2, "DT_PLTRELSZ"},
- intName{3, "DT_PLTGOT"},
- intName{4, "DT_HASH"},
- intName{5, "DT_STRTAB"},
- intName{6, "DT_SYMTAB"},
- intName{7, "DT_RELA"},
- intName{8, "DT_RELASZ"},
- intName{9, "DT_RELAENT"},
- intName{10, "DT_STRSZ"},
- intName{11, "DT_SYMENT"},
- intName{12, "DT_INIT"},
- intName{13, "DT_FINI"},
- intName{14, "DT_SONAME"},
- intName{15, "DT_RPATH"},
- intName{16, "DT_SYMBOLIC"},
- intName{17, "DT_REL"},
- intName{18, "DT_RELSZ"},
- intName{19, "DT_RELENT"},
- intName{20, "DT_PLTREL"},
- intName{21, "DT_DEBUG"},
- intName{22, "DT_TEXTREL"},
- intName{23, "DT_JMPREL"},
- intName{24, "DT_BIND_NOW"},
- intName{25, "DT_INIT_ARRAY"},
- intName{26, "DT_FINI_ARRAY"},
- intName{27, "DT_INIT_ARRAYSZ"},
- intName{28, "DT_FINI_ARRAYSZ"},
- intName{29, "DT_RUNPATH"},
- intName{30, "DT_FLAGS"},
- intName{32, "DT_ENCODING"},
- intName{32, "DT_PREINIT_ARRAY"},
- intName{33, "DT_PREINIT_ARRAYSZ"},
- intName{0x6000000d, "DT_LOOS"},
- intName{0x6ffff000, "DT_HIOS"},
- intName{0x70000000, "DT_LOPROC"},
- intName{0x7fffffff, "DT_HIPROC"},
+ {0, "DT_NULL"},
+ {1, "DT_NEEDED"},
+ {2, "DT_PLTRELSZ"},
+ {3, "DT_PLTGOT"},
+ {4, "DT_HASH"},
+ {5, "DT_STRTAB"},
+ {6, "DT_SYMTAB"},
+ {7, "DT_RELA"},
+ {8, "DT_RELASZ"},
+ {9, "DT_RELAENT"},
+ {10, "DT_STRSZ"},
+ {11, "DT_SYMENT"},
+ {12, "DT_INIT"},
+ {13, "DT_FINI"},
+ {14, "DT_SONAME"},
+ {15, "DT_RPATH"},
+ {16, "DT_SYMBOLIC"},
+ {17, "DT_REL"},
+ {18, "DT_RELSZ"},
+ {19, "DT_RELENT"},
+ {20, "DT_PLTREL"},
+ {21, "DT_DEBUG"},
+ {22, "DT_TEXTREL"},
+ {23, "DT_JMPREL"},
+ {24, "DT_BIND_NOW"},
+ {25, "DT_INIT_ARRAY"},
+ {26, "DT_FINI_ARRAY"},
+ {27, "DT_INIT_ARRAYSZ"},
+ {28, "DT_FINI_ARRAYSZ"},
+ {29, "DT_RUNPATH"},
+ {30, "DT_FLAGS"},
+ {32, "DT_ENCODING"},
+ {32, "DT_PREINIT_ARRAY"},
+ {33, "DT_PREINIT_ARRAYSZ"},
+ {0x6000000d, "DT_LOOS"},
+ {0x6ffff000, "DT_HIOS"},
+ {0x70000000, "DT_LOPROC"},
+ {0x7fffffff, "DT_HIPROC"},
}
func (i DynTag) String() string { return stringName(uint32(i), dtStrings, false) }
@@ -585,11 +585,11 @@ const (
)
var dflagStrings = []intName{
- intName{0x0001, "DF_ORIGIN"},
- intName{0x0002, "DF_SYMBOLIC"},
- intName{0x0004, "DF_TEXTREL"},
- intName{0x0008, "DF_BIND_NOW"},
- intName{0x0010, "DF_STATIC_TLS"},
+ {0x0001, "DF_ORIGIN"},
+ {0x0002, "DF_SYMBOLIC"},
+ {0x0004, "DF_TEXTREL"},
+ {0x0008, "DF_BIND_NOW"},
+ {0x0010, "DF_STATIC_TLS"},
}
func (i DynFlag) String() string { return flagName(uint32(i), dflagStrings, false) }
@@ -605,9 +605,9 @@ const (
)
var ntypeStrings = []intName{
- intName{1, "NT_PRSTATUS"},
- intName{2, "NT_FPREGSET"},
- intName{3, "NT_PRPSINFO"},
+ {1, "NT_PRSTATUS"},
+ {2, "NT_FPREGSET"},
+ {3, "NT_PRPSINFO"},
}
func (i NType) String() string { return stringName(uint32(i), ntypeStrings, false) }
@@ -627,13 +627,13 @@ const (
)
var stbStrings = []intName{
- intName{0, "STB_LOCAL"},
- intName{1, "STB_GLOBAL"},
- intName{2, "STB_WEAK"},
- intName{10, "STB_LOOS"},
- intName{12, "STB_HIOS"},
- intName{13, "STB_LOPROC"},
- intName{15, "STB_HIPROC"},
+ {0, "STB_LOCAL"},
+ {1, "STB_GLOBAL"},
+ {2, "STB_WEAK"},
+ {10, "STB_LOOS"},
+ {12, "STB_HIOS"},
+ {13, "STB_LOPROC"},
+ {15, "STB_HIPROC"},
}
func (i SymBind) String() string { return stringName(uint32(i), stbStrings, false) }
@@ -657,17 +657,17 @@ const (
)
var sttStrings = []intName{
- intName{0, "STT_NOTYPE"},
- intName{1, "STT_OBJECT"},
- intName{2, "STT_FUNC"},
- intName{3, "STT_SECTION"},
- intName{4, "STT_FILE"},
- intName{5, "STT_COMMON"},
- intName{6, "STT_TLS"},
- intName{10, "STT_LOOS"},
- intName{12, "STT_HIOS"},
- intName{13, "STT_LOPROC"},
- intName{15, "STT_HIPROC"},
+ {0, "STT_NOTYPE"},
+ {1, "STT_OBJECT"},
+ {2, "STT_FUNC"},
+ {3, "STT_SECTION"},
+ {4, "STT_FILE"},
+ {5, "STT_COMMON"},
+ {6, "STT_TLS"},
+ {10, "STT_LOOS"},
+ {12, "STT_HIOS"},
+ {13, "STT_LOPROC"},
+ {15, "STT_HIPROC"},
}
func (i SymType) String() string { return stringName(uint32(i), sttStrings, false) }
@@ -684,10 +684,10 @@ const (
)
var stvStrings = []intName{
- intName{0x0, "STV_DEFAULT"},
- intName{0x1, "STV_INTERNAL"},
- intName{0x2, "STV_HIDDEN"},
- intName{0x3, "STV_PROTECTED"},
+ {0x0, "STV_DEFAULT"},
+ {0x1, "STV_INTERNAL"},
+ {0x2, "STV_HIDDEN"},
+ {0x3, "STV_PROTECTED"},
}
func (i SymVis) String() string { return stringName(uint32(i), stvStrings, false) }
@@ -728,30 +728,30 @@ const (
)
var rx86_64Strings = []intName{
- intName{0, "R_X86_64_NONE"},
- intName{1, "R_X86_64_64"},
- intName{2, "R_X86_64_PC32"},
- intName{3, "R_X86_64_GOT32"},
- intName{4, "R_X86_64_PLT32"},
- intName{5, "R_X86_64_COPY"},
- intName{6, "R_X86_64_GLOB_DAT"},
- intName{7, "R_X86_64_JMP_SLOT"},
- intName{8, "R_X86_64_RELATIVE"},
- intName{9, "R_X86_64_GOTPCREL"},
- intName{10, "R_X86_64_32"},
- intName{11, "R_X86_64_32S"},
- intName{12, "R_X86_64_16"},
- intName{13, "R_X86_64_PC16"},
- intName{14, "R_X86_64_8"},
- intName{15, "R_X86_64_PC8"},
- intName{16, "R_X86_64_DTPMOD64"},
- intName{17, "R_X86_64_DTPOFF64"},
- intName{18, "R_X86_64_TPOFF64"},
- intName{19, "R_X86_64_TLSGD"},
- intName{20, "R_X86_64_TLSLD"},
- intName{21, "R_X86_64_DTPOFF32"},
- intName{22, "R_X86_64_GOTTPOFF"},
- intName{23, "R_X86_64_TPOFF32"},
+ {0, "R_X86_64_NONE"},
+ {1, "R_X86_64_64"},
+ {2, "R_X86_64_PC32"},
+ {3, "R_X86_64_GOT32"},
+ {4, "R_X86_64_PLT32"},
+ {5, "R_X86_64_COPY"},
+ {6, "R_X86_64_GLOB_DAT"},
+ {7, "R_X86_64_JMP_SLOT"},
+ {8, "R_X86_64_RELATIVE"},
+ {9, "R_X86_64_GOTPCREL"},
+ {10, "R_X86_64_32"},
+ {11, "R_X86_64_32S"},
+ {12, "R_X86_64_16"},
+ {13, "R_X86_64_PC16"},
+ {14, "R_X86_64_8"},
+ {15, "R_X86_64_PC8"},
+ {16, "R_X86_64_DTPMOD64"},
+ {17, "R_X86_64_DTPOFF64"},
+ {18, "R_X86_64_TPOFF64"},
+ {19, "R_X86_64_TLSGD"},
+ {20, "R_X86_64_TLSLD"},
+ {21, "R_X86_64_DTPOFF32"},
+ {22, "R_X86_64_GOTTPOFF"},
+ {23, "R_X86_64_TPOFF32"},
}
func (i R_X86_64) String() string { return stringName(uint32(i), rx86_64Strings, false) }
@@ -792,34 +792,34 @@ const (
)
var ralphaStrings = []intName{
- intName{0, "R_ALPHA_NONE"},
- intName{1, "R_ALPHA_REFLONG"},
- intName{2, "R_ALPHA_REFQUAD"},
- intName{3, "R_ALPHA_GPREL32"},
- intName{4, "R_ALPHA_LITERAL"},
- intName{5, "R_ALPHA_LITUSE"},
- intName{6, "R_ALPHA_GPDISP"},
- intName{7, "R_ALPHA_BRADDR"},
- intName{8, "R_ALPHA_HINT"},
- intName{9, "R_ALPHA_SREL16"},
- intName{10, "R_ALPHA_SREL32"},
- intName{11, "R_ALPHA_SREL64"},
- intName{12, "R_ALPHA_OP_PUSH"},
- intName{13, "R_ALPHA_OP_STORE"},
- intName{14, "R_ALPHA_OP_PSUB"},
- intName{15, "R_ALPHA_OP_PRSHIFT"},
- intName{16, "R_ALPHA_GPVALUE"},
- intName{17, "R_ALPHA_GPRELHIGH"},
- intName{18, "R_ALPHA_GPRELLOW"},
- intName{19, "R_ALPHA_IMMED_GP_16"},
- intName{20, "R_ALPHA_IMMED_GP_HI32"},
- intName{21, "R_ALPHA_IMMED_SCN_HI32"},
- intName{22, "R_ALPHA_IMMED_BR_HI32"},
- intName{23, "R_ALPHA_IMMED_LO32"},
- intName{24, "R_ALPHA_COPY"},
- intName{25, "R_ALPHA_GLOB_DAT"},
- intName{26, "R_ALPHA_JMP_SLOT"},
- intName{27, "R_ALPHA_RELATIVE"},
+ {0, "R_ALPHA_NONE"},
+ {1, "R_ALPHA_REFLONG"},
+ {2, "R_ALPHA_REFQUAD"},
+ {3, "R_ALPHA_GPREL32"},
+ {4, "R_ALPHA_LITERAL"},
+ {5, "R_ALPHA_LITUSE"},
+ {6, "R_ALPHA_GPDISP"},
+ {7, "R_ALPHA_BRADDR"},
+ {8, "R_ALPHA_HINT"},
+ {9, "R_ALPHA_SREL16"},
+ {10, "R_ALPHA_SREL32"},
+ {11, "R_ALPHA_SREL64"},
+ {12, "R_ALPHA_OP_PUSH"},
+ {13, "R_ALPHA_OP_STORE"},
+ {14, "R_ALPHA_OP_PSUB"},
+ {15, "R_ALPHA_OP_PRSHIFT"},
+ {16, "R_ALPHA_GPVALUE"},
+ {17, "R_ALPHA_GPRELHIGH"},
+ {18, "R_ALPHA_GPRELLOW"},
+ {19, "R_ALPHA_IMMED_GP_16"},
+ {20, "R_ALPHA_IMMED_GP_HI32"},
+ {21, "R_ALPHA_IMMED_SCN_HI32"},
+ {22, "R_ALPHA_IMMED_BR_HI32"},
+ {23, "R_ALPHA_IMMED_LO32"},
+ {24, "R_ALPHA_COPY"},
+ {25, "R_ALPHA_GLOB_DAT"},
+ {26, "R_ALPHA_JMP_SLOT"},
+ {27, "R_ALPHA_RELATIVE"},
}
func (i R_ALPHA) String() string { return stringName(uint32(i), ralphaStrings, false) }
@@ -865,39 +865,39 @@ const (
)
var rarmStrings = []intName{
- intName{0, "R_ARM_NONE"},
- intName{1, "R_ARM_PC24"},
- intName{2, "R_ARM_ABS32"},
- intName{3, "R_ARM_REL32"},
- intName{4, "R_ARM_PC13"},
- intName{5, "R_ARM_ABS16"},
- intName{6, "R_ARM_ABS12"},
- intName{7, "R_ARM_THM_ABS5"},
- intName{8, "R_ARM_ABS8"},
- intName{9, "R_ARM_SBREL32"},
- intName{10, "R_ARM_THM_PC22"},
- intName{11, "R_ARM_THM_PC8"},
- intName{12, "R_ARM_AMP_VCALL9"},
- intName{13, "R_ARM_SWI24"},
- intName{14, "R_ARM_THM_SWI8"},
- intName{15, "R_ARM_XPC25"},
- intName{16, "R_ARM_THM_XPC22"},
- intName{20, "R_ARM_COPY"},
- intName{21, "R_ARM_GLOB_DAT"},
- intName{22, "R_ARM_JUMP_SLOT"},
- intName{23, "R_ARM_RELATIVE"},
- intName{24, "R_ARM_GOTOFF"},
- intName{25, "R_ARM_GOTPC"},
- intName{26, "R_ARM_GOT32"},
- intName{27, "R_ARM_PLT32"},
- intName{100, "R_ARM_GNU_VTENTRY"},
- intName{101, "R_ARM_GNU_VTINHERIT"},
- intName{250, "R_ARM_RSBREL32"},
- intName{251, "R_ARM_THM_RPC22"},
- intName{252, "R_ARM_RREL32"},
- intName{253, "R_ARM_RABS32"},
- intName{254, "R_ARM_RPC24"},
- intName{255, "R_ARM_RBASE"},
+ {0, "R_ARM_NONE"},
+ {1, "R_ARM_PC24"},
+ {2, "R_ARM_ABS32"},
+ {3, "R_ARM_REL32"},
+ {4, "R_ARM_PC13"},
+ {5, "R_ARM_ABS16"},
+ {6, "R_ARM_ABS12"},
+ {7, "R_ARM_THM_ABS5"},
+ {8, "R_ARM_ABS8"},
+ {9, "R_ARM_SBREL32"},
+ {10, "R_ARM_THM_PC22"},
+ {11, "R_ARM_THM_PC8"},
+ {12, "R_ARM_AMP_VCALL9"},
+ {13, "R_ARM_SWI24"},
+ {14, "R_ARM_THM_SWI8"},
+ {15, "R_ARM_XPC25"},
+ {16, "R_ARM_THM_XPC22"},
+ {20, "R_ARM_COPY"},
+ {21, "R_ARM_GLOB_DAT"},
+ {22, "R_ARM_JUMP_SLOT"},
+ {23, "R_ARM_RELATIVE"},
+ {24, "R_ARM_GOTOFF"},
+ {25, "R_ARM_GOTPC"},
+ {26, "R_ARM_GOT32"},
+ {27, "R_ARM_PLT32"},
+ {100, "R_ARM_GNU_VTENTRY"},
+ {101, "R_ARM_GNU_VTINHERIT"},
+ {250, "R_ARM_RSBREL32"},
+ {251, "R_ARM_THM_RPC22"},
+ {252, "R_ARM_RREL32"},
+ {253, "R_ARM_RABS32"},
+ {254, "R_ARM_RPC24"},
+ {255, "R_ARM_RBASE"},
}
func (i R_ARM) String() string { return stringName(uint32(i), rarmStrings, false) }
@@ -941,37 +941,37 @@ const (
)
var r386Strings = []intName{
- intName{0, "R_386_NONE"},
- intName{1, "R_386_32"},
- intName{2, "R_386_PC32"},
- intName{3, "R_386_GOT32"},
- intName{4, "R_386_PLT32"},
- intName{5, "R_386_COPY"},
- intName{6, "R_386_GLOB_DAT"},
- intName{7, "R_386_JMP_SLOT"},
- intName{8, "R_386_RELATIVE"},
- intName{9, "R_386_GOTOFF"},
- intName{10, "R_386_GOTPC"},
- intName{14, "R_386_TLS_TPOFF"},
- intName{15, "R_386_TLS_IE"},
- intName{16, "R_386_TLS_GOTIE"},
- intName{17, "R_386_TLS_LE"},
- intName{18, "R_386_TLS_GD"},
- intName{19, "R_386_TLS_LDM"},
- intName{24, "R_386_TLS_GD_32"},
- intName{25, "R_386_TLS_GD_PUSH"},
- intName{26, "R_386_TLS_GD_CALL"},
- intName{27, "R_386_TLS_GD_POP"},
- intName{28, "R_386_TLS_LDM_32"},
- intName{29, "R_386_TLS_LDM_PUSH"},
- intName{30, "R_386_TLS_LDM_CALL"},
- intName{31, "R_386_TLS_LDM_POP"},
- intName{32, "R_386_TLS_LDO_32"},
- intName{33, "R_386_TLS_IE_32"},
- intName{34, "R_386_TLS_LE_32"},
- intName{35, "R_386_TLS_DTPMOD32"},
- intName{36, "R_386_TLS_DTPOFF32"},
- intName{37, "R_386_TLS_TPOFF32"},
+ {0, "R_386_NONE"},
+ {1, "R_386_32"},
+ {2, "R_386_PC32"},
+ {3, "R_386_GOT32"},
+ {4, "R_386_PLT32"},
+ {5, "R_386_COPY"},
+ {6, "R_386_GLOB_DAT"},
+ {7, "R_386_JMP_SLOT"},
+ {8, "R_386_RELATIVE"},
+ {9, "R_386_GOTOFF"},
+ {10, "R_386_GOTPC"},
+ {14, "R_386_TLS_TPOFF"},
+ {15, "R_386_TLS_IE"},
+ {16, "R_386_TLS_GOTIE"},
+ {17, "R_386_TLS_LE"},
+ {18, "R_386_TLS_GD"},
+ {19, "R_386_TLS_LDM"},
+ {24, "R_386_TLS_GD_32"},
+ {25, "R_386_TLS_GD_PUSH"},
+ {26, "R_386_TLS_GD_CALL"},
+ {27, "R_386_TLS_GD_POP"},
+ {28, "R_386_TLS_LDM_32"},
+ {29, "R_386_TLS_LDM_PUSH"},
+ {30, "R_386_TLS_LDM_CALL"},
+ {31, "R_386_TLS_LDM_POP"},
+ {32, "R_386_TLS_LDO_32"},
+ {33, "R_386_TLS_IE_32"},
+ {34, "R_386_TLS_LE_32"},
+ {35, "R_386_TLS_DTPMOD32"},
+ {36, "R_386_TLS_DTPOFF32"},
+ {37, "R_386_TLS_TPOFF32"},
}
func (i R_386) String() string { return stringName(uint32(i), r386Strings, false) }
@@ -1061,85 +1061,85 @@ const (
)
var rppcStrings = []intName{
- intName{0, "R_PPC_NONE"},
- intName{1, "R_PPC_ADDR32"},
- intName{2, "R_PPC_ADDR24"},
- intName{3, "R_PPC_ADDR16"},
- intName{4, "R_PPC_ADDR16_LO"},
- intName{5, "R_PPC_ADDR16_HI"},
- intName{6, "R_PPC_ADDR16_HA"},
- intName{7, "R_PPC_ADDR14"},
- intName{8, "R_PPC_ADDR14_BRTAKEN"},
- intName{9, "R_PPC_ADDR14_BRNTAKEN"},
- intName{10, "R_PPC_REL24"},
- intName{11, "R_PPC_REL14"},
- intName{12, "R_PPC_REL14_BRTAKEN"},
- intName{13, "R_PPC_REL14_BRNTAKEN"},
- intName{14, "R_PPC_GOT16"},
- intName{15, "R_PPC_GOT16_LO"},
- intName{16, "R_PPC_GOT16_HI"},
- intName{17, "R_PPC_GOT16_HA"},
- intName{18, "R_PPC_PLTREL24"},
- intName{19, "R_PPC_COPY"},
- intName{20, "R_PPC_GLOB_DAT"},
- intName{21, "R_PPC_JMP_SLOT"},
- intName{22, "R_PPC_RELATIVE"},
- intName{23, "R_PPC_LOCAL24PC"},
- intName{24, "R_PPC_UADDR32"},
- intName{25, "R_PPC_UADDR16"},
- intName{26, "R_PPC_REL32"},
- intName{27, "R_PPC_PLT32"},
- intName{28, "R_PPC_PLTREL32"},
- intName{29, "R_PPC_PLT16_LO"},
- intName{30, "R_PPC_PLT16_HI"},
- intName{31, "R_PPC_PLT16_HA"},
- intName{32, "R_PPC_SDAREL16"},
- intName{33, "R_PPC_SECTOFF"},
- intName{34, "R_PPC_SECTOFF_LO"},
- intName{35, "R_PPC_SECTOFF_HI"},
- intName{36, "R_PPC_SECTOFF_HA"},
-
- intName{67, "R_PPC_TLS"},
- intName{68, "R_PPC_DTPMOD32"},
- intName{69, "R_PPC_TPREL16"},
- intName{70, "R_PPC_TPREL16_LO"},
- intName{71, "R_PPC_TPREL16_HI"},
- intName{72, "R_PPC_TPREL16_HA"},
- intName{73, "R_PPC_TPREL32"},
- intName{74, "R_PPC_DTPREL16"},
- intName{75, "R_PPC_DTPREL16_LO"},
- intName{76, "R_PPC_DTPREL16_HI"},
- intName{77, "R_PPC_DTPREL16_HA"},
- intName{78, "R_PPC_DTPREL32"},
- intName{79, "R_PPC_GOT_TLSGD16"},
- intName{80, "R_PPC_GOT_TLSGD16_LO"},
- intName{81, "R_PPC_GOT_TLSGD16_HI"},
- intName{82, "R_PPC_GOT_TLSGD16_HA"},
- intName{83, "R_PPC_GOT_TLSLD16"},
- intName{84, "R_PPC_GOT_TLSLD16_LO"},
- intName{85, "R_PPC_GOT_TLSLD16_HI"},
- intName{86, "R_PPC_GOT_TLSLD16_HA"},
- intName{87, "R_PPC_GOT_TPREL16"},
- intName{88, "R_PPC_GOT_TPREL16_LO"},
- intName{89, "R_PPC_GOT_TPREL16_HI"},
- intName{90, "R_PPC_GOT_TPREL16_HA"},
-
- intName{101, "R_PPC_EMB_NADDR32"},
- intName{102, "R_PPC_EMB_NADDR16"},
- intName{103, "R_PPC_EMB_NADDR16_LO"},
- intName{104, "R_PPC_EMB_NADDR16_HI"},
- intName{105, "R_PPC_EMB_NADDR16_HA"},
- intName{106, "R_PPC_EMB_SDAI16"},
- intName{107, "R_PPC_EMB_SDA2I16"},
- intName{108, "R_PPC_EMB_SDA2REL"},
- intName{109, "R_PPC_EMB_SDA21"},
- intName{110, "R_PPC_EMB_MRKREF"},
- intName{111, "R_PPC_EMB_RELSEC16"},
- intName{112, "R_PPC_EMB_RELST_LO"},
- intName{113, "R_PPC_EMB_RELST_HI"},
- intName{114, "R_PPC_EMB_RELST_HA"},
- intName{115, "R_PPC_EMB_BIT_FLD"},
- intName{116, "R_PPC_EMB_RELSDA"},
+ {0, "R_PPC_NONE"},
+ {1, "R_PPC_ADDR32"},
+ {2, "R_PPC_ADDR24"},
+ {3, "R_PPC_ADDR16"},
+ {4, "R_PPC_ADDR16_LO"},
+ {5, "R_PPC_ADDR16_HI"},
+ {6, "R_PPC_ADDR16_HA"},
+ {7, "R_PPC_ADDR14"},
+ {8, "R_PPC_ADDR14_BRTAKEN"},
+ {9, "R_PPC_ADDR14_BRNTAKEN"},
+ {10, "R_PPC_REL24"},
+ {11, "R_PPC_REL14"},
+ {12, "R_PPC_REL14_BRTAKEN"},
+ {13, "R_PPC_REL14_BRNTAKEN"},
+ {14, "R_PPC_GOT16"},
+ {15, "R_PPC_GOT16_LO"},
+ {16, "R_PPC_GOT16_HI"},
+ {17, "R_PPC_GOT16_HA"},
+ {18, "R_PPC_PLTREL24"},
+ {19, "R_PPC_COPY"},
+ {20, "R_PPC_GLOB_DAT"},
+ {21, "R_PPC_JMP_SLOT"},
+ {22, "R_PPC_RELATIVE"},
+ {23, "R_PPC_LOCAL24PC"},
+ {24, "R_PPC_UADDR32"},
+ {25, "R_PPC_UADDR16"},
+ {26, "R_PPC_REL32"},
+ {27, "R_PPC_PLT32"},
+ {28, "R_PPC_PLTREL32"},
+ {29, "R_PPC_PLT16_LO"},
+ {30, "R_PPC_PLT16_HI"},
+ {31, "R_PPC_PLT16_HA"},
+ {32, "R_PPC_SDAREL16"},
+ {33, "R_PPC_SECTOFF"},
+ {34, "R_PPC_SECTOFF_LO"},
+ {35, "R_PPC_SECTOFF_HI"},
+ {36, "R_PPC_SECTOFF_HA"},
+
+ {67, "R_PPC_TLS"},
+ {68, "R_PPC_DTPMOD32"},
+ {69, "R_PPC_TPREL16"},
+ {70, "R_PPC_TPREL16_LO"},
+ {71, "R_PPC_TPREL16_HI"},
+ {72, "R_PPC_TPREL16_HA"},
+ {73, "R_PPC_TPREL32"},
+ {74, "R_PPC_DTPREL16"},
+ {75, "R_PPC_DTPREL16_LO"},
+ {76, "R_PPC_DTPREL16_HI"},
+ {77, "R_PPC_DTPREL16_HA"},
+ {78, "R_PPC_DTPREL32"},
+ {79, "R_PPC_GOT_TLSGD16"},
+ {80, "R_PPC_GOT_TLSGD16_LO"},
+ {81, "R_PPC_GOT_TLSGD16_HI"},
+ {82, "R_PPC_GOT_TLSGD16_HA"},
+ {83, "R_PPC_GOT_TLSLD16"},
+ {84, "R_PPC_GOT_TLSLD16_LO"},
+ {85, "R_PPC_GOT_TLSLD16_HI"},
+ {86, "R_PPC_GOT_TLSLD16_HA"},
+ {87, "R_PPC_GOT_TPREL16"},
+ {88, "R_PPC_GOT_TPREL16_LO"},
+ {89, "R_PPC_GOT_TPREL16_HI"},
+ {90, "R_PPC_GOT_TPREL16_HA"},
+
+ {101, "R_PPC_EMB_NADDR32"},
+ {102, "R_PPC_EMB_NADDR16"},
+ {103, "R_PPC_EMB_NADDR16_LO"},
+ {104, "R_PPC_EMB_NADDR16_HI"},
+ {105, "R_PPC_EMB_NADDR16_HA"},
+ {106, "R_PPC_EMB_SDAI16"},
+ {107, "R_PPC_EMB_SDA2I16"},
+ {108, "R_PPC_EMB_SDA2REL"},
+ {109, "R_PPC_EMB_SDA21"},
+ {110, "R_PPC_EMB_MRKREF"},
+ {111, "R_PPC_EMB_RELSEC16"},
+ {112, "R_PPC_EMB_RELST_LO"},
+ {113, "R_PPC_EMB_RELST_HI"},
+ {114, "R_PPC_EMB_RELST_HA"},
+ {115, "R_PPC_EMB_BIT_FLD"},
+ {116, "R_PPC_EMB_RELSDA"},
}
func (i R_PPC) String() string { return stringName(uint32(i), rppcStrings, false) }
@@ -1208,62 +1208,62 @@ const (
)
var rsparcStrings = []intName{
- intName{0, "R_SPARC_NONE"},
- intName{1, "R_SPARC_8"},
- intName{2, "R_SPARC_16"},
- intName{3, "R_SPARC_32"},
- intName{4, "R_SPARC_DISP8"},
- intName{5, "R_SPARC_DISP16"},
- intName{6, "R_SPARC_DISP32"},
- intName{7, "R_SPARC_WDISP30"},
- intName{8, "R_SPARC_WDISP22"},
- intName{9, "R_SPARC_HI22"},
- intName{10, "R_SPARC_22"},
- intName{11, "R_SPARC_13"},
- intName{12, "R_SPARC_LO10"},
- intName{13, "R_SPARC_GOT10"},
- intName{14, "R_SPARC_GOT13"},
- intName{15, "R_SPARC_GOT22"},
- intName{16, "R_SPARC_PC10"},
- intName{17, "R_SPARC_PC22"},
- intName{18, "R_SPARC_WPLT30"},
- intName{19, "R_SPARC_COPY"},
- intName{20, "R_SPARC_GLOB_DAT"},
- intName{21, "R_SPARC_JMP_SLOT"},
- intName{22, "R_SPARC_RELATIVE"},
- intName{23, "R_SPARC_UA32"},
- intName{24, "R_SPARC_PLT32"},
- intName{25, "R_SPARC_HIPLT22"},
- intName{26, "R_SPARC_LOPLT10"},
- intName{27, "R_SPARC_PCPLT32"},
- intName{28, "R_SPARC_PCPLT22"},
- intName{29, "R_SPARC_PCPLT10"},
- intName{30, "R_SPARC_10"},
- intName{31, "R_SPARC_11"},
- intName{32, "R_SPARC_64"},
- intName{33, "R_SPARC_OLO10"},
- intName{34, "R_SPARC_HH22"},
- intName{35, "R_SPARC_HM10"},
- intName{36, "R_SPARC_LM22"},
- intName{37, "R_SPARC_PC_HH22"},
- intName{38, "R_SPARC_PC_HM10"},
- intName{39, "R_SPARC_PC_LM22"},
- intName{40, "R_SPARC_WDISP16"},
- intName{41, "R_SPARC_WDISP19"},
- intName{42, "R_SPARC_GLOB_JMP"},
- intName{43, "R_SPARC_7"},
- intName{44, "R_SPARC_5"},
- intName{45, "R_SPARC_6"},
- intName{46, "R_SPARC_DISP64"},
- intName{47, "R_SPARC_PLT64"},
- intName{48, "R_SPARC_HIX22"},
- intName{49, "R_SPARC_LOX10"},
- intName{50, "R_SPARC_H44"},
- intName{51, "R_SPARC_M44"},
- intName{52, "R_SPARC_L44"},
- intName{53, "R_SPARC_REGISTER"},
- intName{54, "R_SPARC_UA64"},
- intName{55, "R_SPARC_UA16"},
+ {0, "R_SPARC_NONE"},
+ {1, "R_SPARC_8"},
+ {2, "R_SPARC_16"},
+ {3, "R_SPARC_32"},
+ {4, "R_SPARC_DISP8"},
+ {5, "R_SPARC_DISP16"},
+ {6, "R_SPARC_DISP32"},
+ {7, "R_SPARC_WDISP30"},
+ {8, "R_SPARC_WDISP22"},
+ {9, "R_SPARC_HI22"},
+ {10, "R_SPARC_22"},
+ {11, "R_SPARC_13"},
+ {12, "R_SPARC_LO10"},
+ {13, "R_SPARC_GOT10"},
+ {14, "R_SPARC_GOT13"},
+ {15, "R_SPARC_GOT22"},
+ {16, "R_SPARC_PC10"},
+ {17, "R_SPARC_PC22"},
+ {18, "R_SPARC_WPLT30"},
+ {19, "R_SPARC_COPY"},
+ {20, "R_SPARC_GLOB_DAT"},
+ {21, "R_SPARC_JMP_SLOT"},
+ {22, "R_SPARC_RELATIVE"},
+ {23, "R_SPARC_UA32"},
+ {24, "R_SPARC_PLT32"},
+ {25, "R_SPARC_HIPLT22"},
+ {26, "R_SPARC_LOPLT10"},
+ {27, "R_SPARC_PCPLT32"},
+ {28, "R_SPARC_PCPLT22"},
+ {29, "R_SPARC_PCPLT10"},
+ {30, "R_SPARC_10"},
+ {31, "R_SPARC_11"},
+ {32, "R_SPARC_64"},
+ {33, "R_SPARC_OLO10"},
+ {34, "R_SPARC_HH22"},
+ {35, "R_SPARC_HM10"},
+ {36, "R_SPARC_LM22"},
+ {37, "R_SPARC_PC_HH22"},
+ {38, "R_SPARC_PC_HM10"},
+ {39, "R_SPARC_PC_LM22"},
+ {40, "R_SPARC_WDISP16"},
+ {41, "R_SPARC_WDISP19"},
+ {42, "R_SPARC_GLOB_JMP"},
+ {43, "R_SPARC_7"},
+ {44, "R_SPARC_5"},
+ {45, "R_SPARC_6"},
+ {46, "R_SPARC_DISP64"},
+ {47, "R_SPARC_PLT64"},
+ {48, "R_SPARC_HIX22"},
+ {49, "R_SPARC_LOX10"},
+ {50, "R_SPARC_H44"},
+ {51, "R_SPARC_M44"},
+ {52, "R_SPARC_L44"},
+ {53, "R_SPARC_REGISTER"},
+ {54, "R_SPARC_UA64"},
+ {55, "R_SPARC_UA16"},
}
func (i R_SPARC) String() string { return stringName(uint32(i), rsparcStrings, false) }
@@ -1356,9 +1356,12 @@ type Sym32 struct {
const Sym32Size = 16
-func ST_BIND(info uint8) SymBind { return SymBind(info >> 4) }
-func ST_TYPE(bind SymBind, typ SymType) uint8 { return uint8(bind)<<4 | uint8(typ)&0xf }
-func ST_VISIBILITY(other uint8) SymVis { return SymVis(other & 3) }
+func ST_BIND(info uint8) SymBind { return SymBind(info >> 4) }
+func ST_TYPE(info uint8) SymType { return SymType(info & 0xF) }
+func ST_INFO(bind SymBind, typ SymType) uint8 {
+ return uint8(bind)<<4 | uint8(typ)&0xf
+}
+func ST_VISIBILITY(other uint8) SymVis { return SymVis(other & 3) }
/*
* ELF64
diff --git a/src/pkg/debug/elf/elf_test.go b/src/pkg/debug/elf/elf_test.go
index 6f827faf0..67b961b5c 100644
--- a/src/pkg/debug/elf/elf_test.go
+++ b/src/pkg/debug/elf/elf_test.go
@@ -15,28 +15,28 @@ type nameTest struct {
}
var nameTests = []nameTest{
- nameTest{ELFOSABI_LINUX, "ELFOSABI_LINUX"},
- nameTest{ET_EXEC, "ET_EXEC"},
- nameTest{EM_860, "EM_860"},
- nameTest{SHN_LOPROC, "SHN_LOPROC"},
- nameTest{SHT_PROGBITS, "SHT_PROGBITS"},
- nameTest{SHF_MERGE + SHF_TLS, "SHF_MERGE+SHF_TLS"},
- nameTest{PT_LOAD, "PT_LOAD"},
- nameTest{PF_W + PF_R + 0x50, "PF_W+PF_R+0x50"},
- nameTest{DT_SYMBOLIC, "DT_SYMBOLIC"},
- nameTest{DF_BIND_NOW, "DF_BIND_NOW"},
- nameTest{NT_FPREGSET, "NT_FPREGSET"},
- nameTest{STB_GLOBAL, "STB_GLOBAL"},
- nameTest{STT_COMMON, "STT_COMMON"},
- nameTest{STV_HIDDEN, "STV_HIDDEN"},
- nameTest{R_X86_64_PC32, "R_X86_64_PC32"},
- nameTest{R_ALPHA_OP_PUSH, "R_ALPHA_OP_PUSH"},
- nameTest{R_ARM_THM_ABS5, "R_ARM_THM_ABS5"},
- nameTest{R_386_GOT32, "R_386_GOT32"},
- nameTest{R_PPC_GOT16_HI, "R_PPC_GOT16_HI"},
- nameTest{R_SPARC_GOT22, "R_SPARC_GOT22"},
- nameTest{ET_LOOS + 5, "ET_LOOS+5"},
- nameTest{ProgFlag(0x50), "0x50"},
+ {ELFOSABI_LINUX, "ELFOSABI_LINUX"},
+ {ET_EXEC, "ET_EXEC"},
+ {EM_860, "EM_860"},
+ {SHN_LOPROC, "SHN_LOPROC"},
+ {SHT_PROGBITS, "SHT_PROGBITS"},
+ {SHF_MERGE + SHF_TLS, "SHF_MERGE+SHF_TLS"},
+ {PT_LOAD, "PT_LOAD"},
+ {PF_W + PF_R + 0x50, "PF_W+PF_R+0x50"},
+ {DT_SYMBOLIC, "DT_SYMBOLIC"},
+ {DF_BIND_NOW, "DF_BIND_NOW"},
+ {NT_FPREGSET, "NT_FPREGSET"},
+ {STB_GLOBAL, "STB_GLOBAL"},
+ {STT_COMMON, "STT_COMMON"},
+ {STV_HIDDEN, "STV_HIDDEN"},
+ {R_X86_64_PC32, "R_X86_64_PC32"},
+ {R_ALPHA_OP_PUSH, "R_ALPHA_OP_PUSH"},
+ {R_ARM_THM_ABS5, "R_ARM_THM_ABS5"},
+ {R_386_GOT32, "R_386_GOT32"},
+ {R_PPC_GOT16_HI, "R_PPC_GOT16_HI"},
+ {R_SPARC_GOT22, "R_SPARC_GOT22"},
+ {ET_LOOS + 5, "ET_LOOS+5"},
+ {ProgFlag(0x50), "0x50"},
}
func TestNames(t *testing.T) {
diff --git a/src/pkg/debug/elf/file.go b/src/pkg/debug/elf/file.go
index 568370b85..e69317a75 100644
--- a/src/pkg/debug/elf/file.go
+++ b/src/pkg/debug/elf/file.go
@@ -75,6 +75,15 @@ func (s *Section) Data() ([]byte, os.Error) {
return dat[0:n], err
}
+// stringTable reads and returns the string table given by the
+// specified link value.
+func (f *File) stringTable(link uint32) ([]byte, os.Error) {
+ if link <= 0 || link >= uint32(len(f.Sections)) {
+ return nil, os.ErrorString("section has invalid string table link")
+ }
+ return f.Sections[link].Data()
+}
+
// Open returns a new ReadSeeker reading the ELF section.
func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) }
@@ -108,9 +117,9 @@ func (p *Prog) Open() io.ReadSeeker { return io.NewSectionReader(p.sr, 0, 1<<63-
// A Symbol represents an entry in an ELF symbol table section.
type Symbol struct {
- Name uint32
+ Name string
Info, Other byte
- Section uint32
+ Section SectionIndex
Value, Size uint64
}
@@ -160,6 +169,17 @@ func (f *File) Close() os.Error {
return err
}
+// SectionByType returns the first section in f with the
+// given type, or nil if there is no such section.
+func (f *File) SectionByType(typ SectionType) *Section {
+ for _, s := range f.Sections {
+ if s.Type == typ {
+ return s
+ }
+ }
+ return nil
+}
+
// NewFile creates a new File for accessing an ELF binary in an underlying reader.
// The ELF binary is expected to start at position 0 in the ReaderAt.
func NewFile(r io.ReaderAt) (*File, os.Error) {
@@ -293,9 +313,8 @@ func NewFile(r io.ReaderAt) (*File, os.Error) {
}
// Load section header string table.
- s := f.Sections[shstrndx]
- shstrtab := make([]byte, s.Size)
- if _, err := r.ReadAt(shstrtab, int64(s.Offset)); err != nil {
+ shstrtab, err := f.Sections[shstrndx].Data()
+ if err != nil {
return nil, err
}
for i, s := range f.Sections {
@@ -309,25 +328,65 @@ func NewFile(r io.ReaderAt) (*File, os.Error) {
return f, nil
}
-func (f *File) getSymbols() ([]Symbol, os.Error) {
+// getSymbols returns a slice of Symbols from parsing the symbol table
+// with the given type.
+func (f *File) getSymbols(typ SectionType) ([]Symbol, os.Error) {
switch f.Class {
case ELFCLASS64:
- return f.getSymbols64()
+ return f.getSymbols64(typ)
+
+ case ELFCLASS32:
+ return f.getSymbols32(typ)
}
return nil, os.ErrorString("not implemented")
}
-// GetSymbols returns a slice of Symbols from parsing the symbol table.
-func (f *File) getSymbols64() ([]Symbol, os.Error) {
- var symtabSection *Section
- for _, section := range f.Sections {
- if section.Type == SHT_SYMTAB {
- symtabSection = section
- break
- }
+func (f *File) getSymbols32(typ SectionType) ([]Symbol, os.Error) {
+ symtabSection := f.SectionByType(typ)
+ if symtabSection == nil {
+ return nil, os.ErrorString("no symbol section")
+ }
+
+ data, err := symtabSection.Data()
+ if err != nil {
+ return nil, os.ErrorString("cannot load symbol section")
+ }
+ symtab := bytes.NewBuffer(data)
+ if symtab.Len()%Sym32Size != 0 {
+ return nil, os.ErrorString("length of symbol section is not a multiple of SymSize")
+ }
+
+ strdata, err := f.stringTable(symtabSection.Link)
+ if err != nil {
+ return nil, os.ErrorString("cannot load string table section")
+ }
+
+ // The first entry is all zeros.
+ var skip [Sym32Size]byte
+ symtab.Read(skip[0:])
+
+ symbols := make([]Symbol, symtab.Len()/Sym32Size)
+
+ i := 0
+ var sym Sym32
+ for symtab.Len() > 0 {
+ binary.Read(symtab, f.ByteOrder, &sym)
+ str, _ := getString(strdata, int(sym.Name))
+ symbols[i].Name = str
+ symbols[i].Info = sym.Info
+ symbols[i].Other = sym.Other
+ symbols[i].Section = SectionIndex(sym.Shndx)
+ symbols[i].Value = uint64(sym.Value)
+ symbols[i].Size = uint64(sym.Size)
+ i++
}
+ return symbols, nil
+}
+
+func (f *File) getSymbols64(typ SectionType) ([]Symbol, os.Error) {
+ symtabSection := f.SectionByType(typ)
if symtabSection == nil {
return nil, os.ErrorString("no symbol section")
}
@@ -341,6 +400,11 @@ func (f *File) getSymbols64() ([]Symbol, os.Error) {
return nil, os.ErrorString("length of symbol section is not a multiple of Sym64Size")
}
+ strdata, err := f.stringTable(symtabSection.Link)
+ if err != nil {
+ return nil, os.ErrorString("cannot load string table section")
+ }
+
// The first entry is all zeros.
var skip [Sym64Size]byte
symtab.Read(skip[0:])
@@ -351,10 +415,11 @@ func (f *File) getSymbols64() ([]Symbol, os.Error) {
var sym Sym64
for symtab.Len() > 0 {
binary.Read(symtab, f.ByteOrder, &sym)
- symbols[i].Name = sym.Name
+ str, _ := getString(strdata, int(sym.Name))
+ symbols[i].Name = str
symbols[i].Info = sym.Info
symbols[i].Other = sym.Other
- symbols[i].Section = uint32(sym.Shndx)
+ symbols[i].Section = SectionIndex(sym.Shndx)
symbols[i].Value = sym.Value
symbols[i].Size = sym.Size
i++
@@ -403,7 +468,7 @@ func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) os.Error {
return os.ErrorString("length of relocation section is not a multiple of Sym64Size")
}
- symbols, err := f.getSymbols()
+ symbols, err := f.getSymbols(SHT_SYMTAB)
if err != nil {
return err
}
@@ -478,3 +543,63 @@ func (f *File) DWARF() (*dwarf.Data, os.Error) {
abbrev, info, str := dat[0], dat[1], dat[2]
return dwarf.New(abbrev, nil, nil, info, nil, nil, nil, str)
}
+
+// ImportedSymbols returns the names of all symbols
+// referred to by the binary f that are expected to be
+// satisfied by other libraries at dynamic load time.
+// It does not return weak symbols.
+func (f *File) ImportedSymbols() ([]string, os.Error) {
+ sym, err := f.getSymbols(SHT_DYNSYM)
+ if err != nil {
+ return nil, err
+ }
+ var all []string
+ for _, s := range sym {
+ if ST_BIND(s.Info) == STB_GLOBAL && s.Section == SHN_UNDEF {
+ all = append(all, s.Name)
+ }
+ }
+ return all, nil
+}
+
+// ImportedLibraries returns the names of all libraries
+// referred to by the binary f that are expected to be
+// linked with the binary at dynamic link time.
+func (f *File) ImportedLibraries() ([]string, os.Error) {
+ ds := f.SectionByType(SHT_DYNAMIC)
+ if ds == nil {
+ // not dynamic, so no libraries
+ return nil, nil
+ }
+ d, err := ds.Data()
+ if err != nil {
+ return nil, err
+ }
+ str, err := f.stringTable(ds.Link)
+ if err != nil {
+ return nil, err
+ }
+ var all []string
+ for len(d) > 0 {
+ var tag DynTag
+ var value uint64
+ switch f.Class {
+ case ELFCLASS32:
+ tag = DynTag(f.ByteOrder.Uint32(d[0:4]))
+ value = uint64(f.ByteOrder.Uint32(d[4:8]))
+ d = d[8:]
+ case ELFCLASS64:
+ tag = DynTag(f.ByteOrder.Uint64(d[0:8]))
+ value = f.ByteOrder.Uint64(d[8:16])
+ d = d[16:]
+ }
+ if tag == DT_NEEDED {
+ s, ok := getString(str, int(value))
+ if ok {
+ all = append(all, s)
+ }
+ }
+ }
+
+ return all, nil
+}
diff --git a/src/pkg/debug/elf/file_test.go b/src/pkg/debug/elf/file_test.go
index 49adc4dc7..84068ea12 100644
--- a/src/pkg/debug/elf/file_test.go
+++ b/src/pkg/debug/elf/file_test.go
@@ -18,83 +18,83 @@ type fileTest struct {
}
var fileTests = []fileTest{
- fileTest{
+ {
"testdata/gcc-386-freebsd-exec",
FileHeader{ELFCLASS32, ELFDATA2LSB, EV_CURRENT, ELFOSABI_FREEBSD, 0, binary.LittleEndian, ET_EXEC, EM_386},
[]SectionHeader{
- SectionHeader{"", SHT_NULL, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
- SectionHeader{".interp", SHT_PROGBITS, SHF_ALLOC, 0x80480d4, 0xd4, 0x15, 0x0, 0x0, 0x1, 0x0},
- SectionHeader{".hash", SHT_HASH, SHF_ALLOC, 0x80480ec, 0xec, 0x90, 0x3, 0x0, 0x4, 0x4},
- SectionHeader{".dynsym", SHT_DYNSYM, SHF_ALLOC, 0x804817c, 0x17c, 0x110, 0x4, 0x1, 0x4, 0x10},
- SectionHeader{".dynstr", SHT_STRTAB, SHF_ALLOC, 0x804828c, 0x28c, 0xbb, 0x0, 0x0, 0x1, 0x0},
- SectionHeader{".rel.plt", SHT_REL, SHF_ALLOC, 0x8048348, 0x348, 0x20, 0x3, 0x7, 0x4, 0x8},
- SectionHeader{".init", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x8048368, 0x368, 0x11, 0x0, 0x0, 0x4, 0x0},
- SectionHeader{".plt", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x804837c, 0x37c, 0x50, 0x0, 0x0, 0x4, 0x4},
- SectionHeader{".text", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x80483cc, 0x3cc, 0x180, 0x0, 0x0, 0x4, 0x0},
- SectionHeader{".fini", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x804854c, 0x54c, 0xc, 0x0, 0x0, 0x4, 0x0},
- SectionHeader{".rodata", SHT_PROGBITS, SHF_ALLOC, 0x8048558, 0x558, 0xa3, 0x0, 0x0, 0x1, 0x0},
- SectionHeader{".data", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80495fc, 0x5fc, 0xc, 0x0, 0x0, 0x4, 0x0},
- SectionHeader{".eh_frame", SHT_PROGBITS, SHF_ALLOC, 0x8049608, 0x608, 0x4, 0x0, 0x0, 0x4, 0x0},
- SectionHeader{".dynamic", SHT_DYNAMIC, SHF_WRITE + SHF_ALLOC, 0x804960c, 0x60c, 0x98, 0x4, 0x0, 0x4, 0x8},
- SectionHeader{".ctors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496a4, 0x6a4, 0x8, 0x0, 0x0, 0x4, 0x0},
- SectionHeader{".dtors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496ac, 0x6ac, 0x8, 0x0, 0x0, 0x4, 0x0},
- SectionHeader{".jcr", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496b4, 0x6b4, 0x4, 0x0, 0x0, 0x4, 0x0},
- SectionHeader{".got", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496b8, 0x6b8, 0x1c, 0x0, 0x0, 0x4, 0x4},
- SectionHeader{".bss", SHT_NOBITS, SHF_WRITE + SHF_ALLOC, 0x80496d4, 0x6d4, 0x20, 0x0, 0x0, 0x4, 0x0},
- SectionHeader{".comment", SHT_PROGBITS, 0x0, 0x0, 0x6d4, 0x12d, 0x0, 0x0, 0x1, 0x0},
- SectionHeader{".debug_aranges", SHT_PROGBITS, 0x0, 0x0, 0x801, 0x20, 0x0, 0x0, 0x1, 0x0},
- SectionHeader{".debug_pubnames", SHT_PROGBITS, 0x0, 0x0, 0x821, 0x1b, 0x0, 0x0, 0x1, 0x0},
- SectionHeader{".debug_info", SHT_PROGBITS, 0x0, 0x0, 0x83c, 0x11d, 0x0, 0x0, 0x1, 0x0},
- SectionHeader{".debug_abbrev", SHT_PROGBITS, 0x0, 0x0, 0x959, 0x41, 0x0, 0x0, 0x1, 0x0},
- SectionHeader{".debug_line", SHT_PROGBITS, 0x0, 0x0, 0x99a, 0x35, 0x0, 0x0, 0x1, 0x0},
- SectionHeader{".debug_frame", SHT_PROGBITS, 0x0, 0x0, 0x9d0, 0x30, 0x0, 0x0, 0x4, 0x0},
- SectionHeader{".debug_str", SHT_PROGBITS, 0x0, 0x0, 0xa00, 0xd, 0x0, 0x0, 0x1, 0x0},
- SectionHeader{".shstrtab", SHT_STRTAB, 0x0, 0x0, 0xa0d, 0xf8, 0x0, 0x0, 0x1, 0x0},
- SectionHeader{".symtab", SHT_SYMTAB, 0x0, 0x0, 0xfb8, 0x4b0, 0x1d, 0x38, 0x4, 0x10},
- SectionHeader{".strtab", SHT_STRTAB, 0x0, 0x0, 0x1468, 0x206, 0x0, 0x0, 0x1, 0x0},
+ {"", SHT_NULL, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
+ {".interp", SHT_PROGBITS, SHF_ALLOC, 0x80480d4, 0xd4, 0x15, 0x0, 0x0, 0x1, 0x0},
+ {".hash", SHT_HASH, SHF_ALLOC, 0x80480ec, 0xec, 0x90, 0x3, 0x0, 0x4, 0x4},
+ {".dynsym", SHT_DYNSYM, SHF_ALLOC, 0x804817c, 0x17c, 0x110, 0x4, 0x1, 0x4, 0x10},
+ {".dynstr", SHT_STRTAB, SHF_ALLOC, 0x804828c, 0x28c, 0xbb, 0x0, 0x0, 0x1, 0x0},
+ {".rel.plt", SHT_REL, SHF_ALLOC, 0x8048348, 0x348, 0x20, 0x3, 0x7, 0x4, 0x8},
+ {".init", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x8048368, 0x368, 0x11, 0x0, 0x0, 0x4, 0x0},
+ {".plt", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x804837c, 0x37c, 0x50, 0x0, 0x0, 0x4, 0x4},
+ {".text", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x80483cc, 0x3cc, 0x180, 0x0, 0x0, 0x4, 0x0},
+ {".fini", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x804854c, 0x54c, 0xc, 0x0, 0x0, 0x4, 0x0},
+ {".rodata", SHT_PROGBITS, SHF_ALLOC, 0x8048558, 0x558, 0xa3, 0x0, 0x0, 0x1, 0x0},
+ {".data", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80495fc, 0x5fc, 0xc, 0x0, 0x0, 0x4, 0x0},
+ {".eh_frame", SHT_PROGBITS, SHF_ALLOC, 0x8049608, 0x608, 0x4, 0x0, 0x0, 0x4, 0x0},
+ {".dynamic", SHT_DYNAMIC, SHF_WRITE + SHF_ALLOC, 0x804960c, 0x60c, 0x98, 0x4, 0x0, 0x4, 0x8},
+ {".ctors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496a4, 0x6a4, 0x8, 0x0, 0x0, 0x4, 0x0},
+ {".dtors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496ac, 0x6ac, 0x8, 0x0, 0x0, 0x4, 0x0},
+ {".jcr", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496b4, 0x6b4, 0x4, 0x0, 0x0, 0x4, 0x0},
+ {".got", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x80496b8, 0x6b8, 0x1c, 0x0, 0x0, 0x4, 0x4},
+ {".bss", SHT_NOBITS, SHF_WRITE + SHF_ALLOC, 0x80496d4, 0x6d4, 0x20, 0x0, 0x0, 0x4, 0x0},
+ {".comment", SHT_PROGBITS, 0x0, 0x0, 0x6d4, 0x12d, 0x0, 0x0, 0x1, 0x0},
+ {".debug_aranges", SHT_PROGBITS, 0x0, 0x0, 0x801, 0x20, 0x0, 0x0, 0x1, 0x0},
+ {".debug_pubnames", SHT_PROGBITS, 0x0, 0x0, 0x821, 0x1b, 0x0, 0x0, 0x1, 0x0},
+ {".debug_info", SHT_PROGBITS, 0x0, 0x0, 0x83c, 0x11d, 0x0, 0x0, 0x1, 0x0},
+ {".debug_abbrev", SHT_PROGBITS, 0x0, 0x0, 0x959, 0x41, 0x0, 0x0, 0x1, 0x0},
+ {".debug_line", SHT_PROGBITS, 0x0, 0x0, 0x99a, 0x35, 0x0, 0x0, 0x1, 0x0},
+ {".debug_frame", SHT_PROGBITS, 0x0, 0x0, 0x9d0, 0x30, 0x0, 0x0, 0x4, 0x0},
+ {".debug_str", SHT_PROGBITS, 0x0, 0x0, 0xa00, 0xd, 0x0, 0x0, 0x1, 0x0},
+ {".shstrtab", SHT_STRTAB, 0x0, 0x0, 0xa0d, 0xf8, 0x0, 0x0, 0x1, 0x0},
+ {".symtab", SHT_SYMTAB, 0x0, 0x0, 0xfb8, 0x4b0, 0x1d, 0x38, 0x4, 0x10},
+ {".strtab", SHT_STRTAB, 0x0, 0x0, 0x1468, 0x206, 0x0, 0x0, 0x1, 0x0},
},
},
- fileTest{
+ {
"testdata/gcc-amd64-linux-exec",
FileHeader{ELFCLASS64, ELFDATA2LSB, EV_CURRENT, ELFOSABI_NONE, 0, binary.LittleEndian, ET_EXEC, EM_X86_64},
[]SectionHeader{
- SectionHeader{"", SHT_NULL, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
- SectionHeader{".interp", SHT_PROGBITS, SHF_ALLOC, 0x400200, 0x200, 0x1c, 0x0, 0x0, 0x1, 0x0},
- SectionHeader{".note.ABI-tag", SHT_NOTE, SHF_ALLOC, 0x40021c, 0x21c, 0x20, 0x0, 0x0, 0x4, 0x0},
- SectionHeader{".hash", SHT_HASH, SHF_ALLOC, 0x400240, 0x240, 0x24, 0x5, 0x0, 0x8, 0x4},
- SectionHeader{".gnu.hash", SHT_LOOS + 268435446, SHF_ALLOC, 0x400268, 0x268, 0x1c, 0x5, 0x0, 0x8, 0x0},
- SectionHeader{".dynsym", SHT_DYNSYM, SHF_ALLOC, 0x400288, 0x288, 0x60, 0x6, 0x1, 0x8, 0x18},
- SectionHeader{".dynstr", SHT_STRTAB, SHF_ALLOC, 0x4002e8, 0x2e8, 0x3d, 0x0, 0x0, 0x1, 0x0},
- SectionHeader{".gnu.version", SHT_HIOS, SHF_ALLOC, 0x400326, 0x326, 0x8, 0x5, 0x0, 0x2, 0x2},
- SectionHeader{".gnu.version_r", SHT_LOOS + 268435454, SHF_ALLOC, 0x400330, 0x330, 0x20, 0x6, 0x1, 0x8, 0x0},
- SectionHeader{".rela.dyn", SHT_RELA, SHF_ALLOC, 0x400350, 0x350, 0x18, 0x5, 0x0, 0x8, 0x18},
- SectionHeader{".rela.plt", SHT_RELA, SHF_ALLOC, 0x400368, 0x368, 0x30, 0x5, 0xc, 0x8, 0x18},
- SectionHeader{".init", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x400398, 0x398, 0x18, 0x0, 0x0, 0x4, 0x0},
- SectionHeader{".plt", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x4003b0, 0x3b0, 0x30, 0x0, 0x0, 0x4, 0x10},
- SectionHeader{".text", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x4003e0, 0x3e0, 0x1b4, 0x0, 0x0, 0x10, 0x0},
- SectionHeader{".fini", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x400594, 0x594, 0xe, 0x0, 0x0, 0x4, 0x0},
- SectionHeader{".rodata", SHT_PROGBITS, SHF_ALLOC, 0x4005a4, 0x5a4, 0x11, 0x0, 0x0, 0x4, 0x0},
- SectionHeader{".eh_frame_hdr", SHT_PROGBITS, SHF_ALLOC, 0x4005b8, 0x5b8, 0x24, 0x0, 0x0, 0x4, 0x0},
- SectionHeader{".eh_frame", SHT_PROGBITS, SHF_ALLOC, 0x4005e0, 0x5e0, 0xa4, 0x0, 0x0, 0x8, 0x0},
- SectionHeader{".ctors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600688, 0x688, 0x10, 0x0, 0x0, 0x8, 0x0},
- SectionHeader{".dtors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600698, 0x698, 0x10, 0x0, 0x0, 0x8, 0x0},
- SectionHeader{".jcr", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x6006a8, 0x6a8, 0x8, 0x0, 0x0, 0x8, 0x0},
- SectionHeader{".dynamic", SHT_DYNAMIC, SHF_WRITE + SHF_ALLOC, 0x6006b0, 0x6b0, 0x1a0, 0x6, 0x0, 0x8, 0x10},
- SectionHeader{".got", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600850, 0x850, 0x8, 0x0, 0x0, 0x8, 0x8},
- SectionHeader{".got.plt", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600858, 0x858, 0x28, 0x0, 0x0, 0x8, 0x8},
- SectionHeader{".data", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600880, 0x880, 0x18, 0x0, 0x0, 0x8, 0x0},
- SectionHeader{".bss", SHT_NOBITS, SHF_WRITE + SHF_ALLOC, 0x600898, 0x898, 0x8, 0x0, 0x0, 0x4, 0x0},
- SectionHeader{".comment", SHT_PROGBITS, 0x0, 0x0, 0x898, 0x126, 0x0, 0x0, 0x1, 0x0},
- SectionHeader{".debug_aranges", SHT_PROGBITS, 0x0, 0x0, 0x9c0, 0x90, 0x0, 0x0, 0x10, 0x0},
- SectionHeader{".debug_pubnames", SHT_PROGBITS, 0x0, 0x0, 0xa50, 0x25, 0x0, 0x0, 0x1, 0x0},
- SectionHeader{".debug_info", SHT_PROGBITS, 0x0, 0x0, 0xa75, 0x1a7, 0x0, 0x0, 0x1, 0x0},
- SectionHeader{".debug_abbrev", SHT_PROGBITS, 0x0, 0x0, 0xc1c, 0x6f, 0x0, 0x0, 0x1, 0x0},
- SectionHeader{".debug_line", SHT_PROGBITS, 0x0, 0x0, 0xc8b, 0x13f, 0x0, 0x0, 0x1, 0x0},
- SectionHeader{".debug_str", SHT_PROGBITS, SHF_MERGE + SHF_STRINGS, 0x0, 0xdca, 0xb1, 0x0, 0x0, 0x1, 0x1},
- SectionHeader{".debug_ranges", SHT_PROGBITS, 0x0, 0x0, 0xe80, 0x90, 0x0, 0x0, 0x10, 0x0},
- SectionHeader{".shstrtab", SHT_STRTAB, 0x0, 0x0, 0xf10, 0x149, 0x0, 0x0, 0x1, 0x0},
- SectionHeader{".symtab", SHT_SYMTAB, 0x0, 0x0, 0x19a0, 0x6f0, 0x24, 0x39, 0x8, 0x18},
- SectionHeader{".strtab", SHT_STRTAB, 0x0, 0x0, 0x2090, 0x1fc, 0x0, 0x0, 0x1, 0x0},
+ {"", SHT_NULL, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
+ {".interp", SHT_PROGBITS, SHF_ALLOC, 0x400200, 0x200, 0x1c, 0x0, 0x0, 0x1, 0x0},
+ {".note.ABI-tag", SHT_NOTE, SHF_ALLOC, 0x40021c, 0x21c, 0x20, 0x0, 0x0, 0x4, 0x0},
+ {".hash", SHT_HASH, SHF_ALLOC, 0x400240, 0x240, 0x24, 0x5, 0x0, 0x8, 0x4},
+ {".gnu.hash", SHT_LOOS + 268435446, SHF_ALLOC, 0x400268, 0x268, 0x1c, 0x5, 0x0, 0x8, 0x0},
+ {".dynsym", SHT_DYNSYM, SHF_ALLOC, 0x400288, 0x288, 0x60, 0x6, 0x1, 0x8, 0x18},
+ {".dynstr", SHT_STRTAB, SHF_ALLOC, 0x4002e8, 0x2e8, 0x3d, 0x0, 0x0, 0x1, 0x0},
+ {".gnu.version", SHT_HIOS, SHF_ALLOC, 0x400326, 0x326, 0x8, 0x5, 0x0, 0x2, 0x2},
+ {".gnu.version_r", SHT_LOOS + 268435454, SHF_ALLOC, 0x400330, 0x330, 0x20, 0x6, 0x1, 0x8, 0x0},
+ {".rela.dyn", SHT_RELA, SHF_ALLOC, 0x400350, 0x350, 0x18, 0x5, 0x0, 0x8, 0x18},
+ {".rela.plt", SHT_RELA, SHF_ALLOC, 0x400368, 0x368, 0x30, 0x5, 0xc, 0x8, 0x18},
+ {".init", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x400398, 0x398, 0x18, 0x0, 0x0, 0x4, 0x0},
+ {".plt", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x4003b0, 0x3b0, 0x30, 0x0, 0x0, 0x4, 0x10},
+ {".text", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x4003e0, 0x3e0, 0x1b4, 0x0, 0x0, 0x10, 0x0},
+ {".fini", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR, 0x400594, 0x594, 0xe, 0x0, 0x0, 0x4, 0x0},
+ {".rodata", SHT_PROGBITS, SHF_ALLOC, 0x4005a4, 0x5a4, 0x11, 0x0, 0x0, 0x4, 0x0},
+ {".eh_frame_hdr", SHT_PROGBITS, SHF_ALLOC, 0x4005b8, 0x5b8, 0x24, 0x0, 0x0, 0x4, 0x0},
+ {".eh_frame", SHT_PROGBITS, SHF_ALLOC, 0x4005e0, 0x5e0, 0xa4, 0x0, 0x0, 0x8, 0x0},
+ {".ctors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600688, 0x688, 0x10, 0x0, 0x0, 0x8, 0x0},
+ {".dtors", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600698, 0x698, 0x10, 0x0, 0x0, 0x8, 0x0},
+ {".jcr", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x6006a8, 0x6a8, 0x8, 0x0, 0x0, 0x8, 0x0},
+ {".dynamic", SHT_DYNAMIC, SHF_WRITE + SHF_ALLOC, 0x6006b0, 0x6b0, 0x1a0, 0x6, 0x0, 0x8, 0x10},
+ {".got", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600850, 0x850, 0x8, 0x0, 0x0, 0x8, 0x8},
+ {".got.plt", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600858, 0x858, 0x28, 0x0, 0x0, 0x8, 0x8},
+ {".data", SHT_PROGBITS, SHF_WRITE + SHF_ALLOC, 0x600880, 0x880, 0x18, 0x0, 0x0, 0x8, 0x0},
+ {".bss", SHT_NOBITS, SHF_WRITE + SHF_ALLOC, 0x600898, 0x898, 0x8, 0x0, 0x0, 0x4, 0x0},
+ {".comment", SHT_PROGBITS, 0x0, 0x0, 0x898, 0x126, 0x0, 0x0, 0x1, 0x0},
+ {".debug_aranges", SHT_PROGBITS, 0x0, 0x0, 0x9c0, 0x90, 0x0, 0x0, 0x10, 0x0},
+ {".debug_pubnames", SHT_PROGBITS, 0x0, 0x0, 0xa50, 0x25, 0x0, 0x0, 0x1, 0x0},
+ {".debug_info", SHT_PROGBITS, 0x0, 0x0, 0xa75, 0x1a7, 0x0, 0x0, 0x1, 0x0},
+ {".debug_abbrev", SHT_PROGBITS, 0x0, 0x0, 0xc1c, 0x6f, 0x0, 0x0, 0x1, 0x0},
+ {".debug_line", SHT_PROGBITS, 0x0, 0x0, 0xc8b, 0x13f, 0x0, 0x0, 0x1, 0x0},
+ {".debug_str", SHT_PROGBITS, SHF_MERGE + SHF_STRINGS, 0x0, 0xdca, 0xb1, 0x0, 0x0, 0x1, 0x1},
+ {".debug_ranges", SHT_PROGBITS, 0x0, 0x0, 0xe80, 0x90, 0x0, 0x0, 0x10, 0x0},
+ {".shstrtab", SHT_STRTAB, 0x0, 0x0, 0xf10, 0x149, 0x0, 0x0, 0x1, 0x0},
+ {".symtab", SHT_SYMTAB, 0x0, 0x0, 0x19a0, 0x6f0, 0x24, 0x39, 0x8, 0x18},
+ {".strtab", SHT_STRTAB, 0x0, 0x0, 0x2090, 0x1fc, 0x0, 0x0, 0x1, 0x0},
},
},
}
@@ -135,17 +135,17 @@ type relocationTest struct {
}
var relocationTests = []relocationTest{
- relocationTest{
+ {
"testdata/go-relocation-test-gcc441-x86-64.o",
- &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{dwarf.Field{Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1"}, dwarf.Field{Attr: dwarf.AttrLanguage, Val: int64(1)}, dwarf.Field{Attr: dwarf.AttrName, Val: "go-relocation-test.c"}, dwarf.Field{Attr: dwarf.AttrCompDir, Val: "/tmp"}, dwarf.Field{Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, dwarf.Field{Attr: dwarf.AttrHighpc, Val: uint64(0x6)}, dwarf.Field{Attr: dwarf.AttrStmtList, Val: int64(0)}}},
+ &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1"}, {Attr: dwarf.AttrLanguage, Val: int64(1)}, {Attr: dwarf.AttrName, Val: "go-relocation-test.c"}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, {Attr: dwarf.AttrHighpc, Val: uint64(0x6)}, {Attr: dwarf.AttrStmtList, Val: int64(0)}}},
},
- relocationTest{
+ {
"testdata/go-relocation-test-gcc441-x86.o",
- &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{dwarf.Field{Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1"}, dwarf.Field{Attr: dwarf.AttrLanguage, Val: int64(1)}, dwarf.Field{Attr: dwarf.AttrName, Val: "t.c"}, dwarf.Field{Attr: dwarf.AttrCompDir, Val: "/tmp"}, dwarf.Field{Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, dwarf.Field{Attr: dwarf.AttrHighpc, Val: uint64(0x5)}, dwarf.Field{Attr: dwarf.AttrStmtList, Val: int64(0)}}},
+ &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1"}, {Attr: dwarf.AttrLanguage, Val: int64(1)}, {Attr: dwarf.AttrName, Val: "t.c"}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, {Attr: dwarf.AttrHighpc, Val: uint64(0x5)}, {Attr: dwarf.AttrStmtList, Val: int64(0)}}},
},
- relocationTest{
+ {
"testdata/go-relocation-test-gcc424-x86-64.o",
- &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{dwarf.Field{Attr: dwarf.AttrProducer, Val: "GNU C 4.2.4 (Ubuntu 4.2.4-1ubuntu4)"}, dwarf.Field{Attr: dwarf.AttrLanguage, Val: int64(1)}, dwarf.Field{Attr: dwarf.AttrName, Val: "go-relocation-test-gcc424.c"}, dwarf.Field{Attr: dwarf.AttrCompDir, Val: "/tmp"}, dwarf.Field{Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, dwarf.Field{Attr: dwarf.AttrHighpc, Val: uint64(0x6)}, dwarf.Field{Attr: dwarf.AttrStmtList, Val: int64(0)}}},
+ &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.2.4 (Ubuntu 4.2.4-1ubuntu4)"}, {Attr: dwarf.AttrLanguage, Val: int64(1)}, {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc424.c"}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, {Attr: dwarf.AttrHighpc, Val: uint64(0x6)}, {Attr: dwarf.AttrStmtList, Val: int64(0)}}},
},
}
diff --git a/src/pkg/debug/gosym/Makefile b/src/pkg/debug/gosym/Makefile
index ac16b4cee..3c0d8c440 100644
--- a/src/pkg/debug/gosym/Makefile
+++ b/src/pkg/debug/gosym/Makefile
@@ -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 ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=debug/gosym
GOFILES=\
diff --git a/src/pkg/debug/gosym/pclinetest.s b/src/pkg/debug/gosym/pclinetest.s
index 519656b63..6305435b0 100644
--- a/src/pkg/debug/gosym/pclinetest.s
+++ b/src/pkg/debug/gosym/pclinetest.s
@@ -51,39 +51,8 @@ TEXT main(SB),7,$0
CALL pcfromline(SB)
// Keep the linker happy
-TEXT runtime·morestack(SB),7,$0
+TEXT main·main(SB),7,$0
RET
-TEXT runtime·morestack00(SB),7,$0
+TEXT main·init(SB),7,$0
RET
-
-TEXT runtime·morestack10(SB),7,$0
- RET
-
-TEXT runtime·morestack01(SB),7,$0
- RET
-
-TEXT runtime·morestack11(SB),7,$0
- RET
-
-TEXT runtime·morestack8(SB),7,$0
- RET
-
-TEXT runtime·morestack16(SB),7,$0
- RET
-
-TEXT runtime·morestack24(SB),7,$0
- RET
-
-TEXT runtime·morestack32(SB),7,$0
- RET
-
-TEXT runtime·morestack40(SB),7,$0
- RET
-
-TEXT runtime·morestack48(SB),7,$0
- RET
-
-TEXT runtime·morestack8(SB),7,$0
- RET
-
diff --git a/src/pkg/debug/gosym/pclntab_test.go b/src/pkg/debug/gosym/pclntab_test.go
index 8752e3c9f..908702173 100644
--- a/src/pkg/debug/gosym/pclntab_test.go
+++ b/src/pkg/debug/gosym/pclntab_test.go
@@ -143,7 +143,7 @@ func TestLineAline(t *testing.T) {
}
}
-// gotest: if [ "$(uname)-$(uname -m)" = Linux-x86_64 ]; then
+// gotest: if [ "$(uname)-$(uname -m)" = Linux-x86_64 -a "$GOARCH" = amd64 ]; then
// gotest: mkdir -p _test && $AS pclinetest.s && $LD -E main -o _test/pclinetest pclinetest.$O
// gotest: fi
func TestPCLine(t *testing.T) {
diff --git a/src/pkg/debug/macho/Makefile b/src/pkg/debug/macho/Makefile
index d34aacf54..5fbbf1efe 100644
--- a/src/pkg/debug/macho/Makefile
+++ b/src/pkg/debug/macho/Makefile
@@ -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 ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=debug/macho
GOFILES=\
diff --git a/src/pkg/debug/macho/file.go b/src/pkg/debug/macho/file.go
index 246dad8e7..fd8da9449 100644
--- a/src/pkg/debug/macho/file.go
+++ b/src/pkg/debug/macho/file.go
@@ -24,6 +24,9 @@ type File struct {
Loads []Load
Sections []*Section
+ Symtab *Symtab
+ Dysymtab *Dysymtab
+
closer io.Closer
}
@@ -112,6 +115,28 @@ func (s *Section) Data() ([]byte, os.Error) {
// Open returns a new ReadSeeker reading the Mach-O section.
func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) }
+// A Dylib represents a Mach-O load dynamic library command.
+type Dylib struct {
+ LoadBytes
+ Name string
+ Time uint32
+ CurrentVersion uint32
+ CompatVersion uint32
+}
+
+// A Symtab represents a Mach-O symbol table command.
+type Symtab struct {
+ LoadBytes
+ SymtabCmd
+ Syms []Symbol
+}
+
+// A Dysymtab represents a Mach-O dynamic symbol table command.
+type Dysymtab struct {
+ LoadBytes
+ DysymtabCmd
+ IndirectSyms []uint32 // indices into Symtab.Syms
+}
/*
* Mach-O reader
@@ -217,6 +242,71 @@ func NewFile(r io.ReaderAt) (*File, os.Error) {
default:
f.Loads[i] = LoadBytes(cmddat)
+ case LoadCmdDylib:
+ var hdr DylibCmd
+ b := bytes.NewBuffer(cmddat)
+ if err := binary.Read(b, bo, &hdr); err != nil {
+ return nil, err
+ }
+ l := new(Dylib)
+ if hdr.Name >= uint32(len(cmddat)) {
+ return nil, &FormatError{offset, "invalid name in dynamic library command", hdr.Name}
+ }
+ l.Name = cstring(cmddat[hdr.Name:])
+ l.Time = hdr.Time
+ l.CurrentVersion = hdr.CurrentVersion
+ l.CompatVersion = hdr.CompatVersion
+ l.LoadBytes = LoadBytes(cmddat)
+ f.Loads[i] = l
+
+ case LoadCmdSymtab:
+ var hdr SymtabCmd
+ b := bytes.NewBuffer(cmddat)
+ if err := binary.Read(b, bo, &hdr); err != nil {
+ return nil, err
+ }
+ strtab := make([]byte, hdr.Strsize)
+ if _, err := r.ReadAt(strtab, int64(hdr.Stroff)); err != nil {
+ return nil, err
+ }
+ var symsz int
+ if f.Magic == Magic64 {
+ symsz = 16
+ } else {
+ symsz = 12
+ }
+ symdat := make([]byte, int(hdr.Nsyms)*symsz)
+ if _, err := r.ReadAt(symdat, int64(hdr.Symoff)); err != nil {
+ return nil, err
+ }
+ st, err := f.parseSymtab(symdat, strtab, cmddat, &hdr, offset)
+ if err != nil {
+ return nil, err
+ }
+ f.Loads[i] = st
+ f.Symtab = st
+
+ case LoadCmdDysymtab:
+ var hdr DysymtabCmd
+ b := bytes.NewBuffer(cmddat)
+ if err := binary.Read(b, bo, &hdr); err != nil {
+ return nil, err
+ }
+ dat := make([]byte, hdr.Nindirectsyms*4)
+ if _, err := r.ReadAt(dat, int64(hdr.Indirectsymoff)); err != nil {
+ return nil, err
+ }
+ x := make([]uint32, hdr.Nindirectsyms)
+ if err := binary.Read(bytes.NewBuffer(dat), bo, x); err != nil {
+ return nil, err
+ }
+ st := new(Dysymtab)
+ st.LoadBytes = LoadBytes(cmddat)
+ st.DysymtabCmd = hdr
+ st.IndirectSyms = x
+ f.Loads[i] = st
+ f.Dysymtab = st
+
case LoadCmdSegment:
var seg32 Segment32
b := bytes.NewBuffer(cmddat)
@@ -301,18 +391,45 @@ func NewFile(r io.ReaderAt) (*File, os.Error) {
return f, nil
}
-func (f *File) pushSection(sh *Section, r io.ReaderAt) {
- n := len(f.Sections)
- if n >= cap(f.Sections) {
- m := (n + 1) * 2
- new := make([]*Section, n, m)
- for i, sh := range f.Sections {
- new[i] = sh
+func (f *File) parseSymtab(symdat, strtab, cmddat []byte, hdr *SymtabCmd, offset int64) (*Symtab, os.Error) {
+ bo := f.ByteOrder
+ symtab := make([]Symbol, hdr.Nsyms)
+ b := bytes.NewBuffer(symdat)
+ for i := range symtab {
+ var n Nlist64
+ if f.Magic == Magic64 {
+ if err := binary.Read(b, bo, &n); err != nil {
+ return nil, err
+ }
+ } else {
+ var n32 Nlist32
+ if err := binary.Read(b, bo, &n32); err != nil {
+ return nil, err
+ }
+ n.Name = n32.Name
+ n.Type = n32.Type
+ n.Sect = n32.Sect
+ n.Desc = n32.Desc
+ n.Value = uint64(n32.Value)
+ }
+ sym := &symtab[i]
+ if n.Name >= uint32(len(strtab)) {
+ return nil, &FormatError{offset, "invalid name in symbol table", n.Name}
}
- f.Sections = new
+ sym.Name = cstring(strtab[n.Name:])
+ sym.Type = n.Type
+ sym.Sect = n.Sect
+ sym.Desc = n.Desc
+ sym.Value = n.Value
}
- f.Sections = f.Sections[0 : n+1]
- f.Sections[n] = sh
+ st := new(Symtab)
+ st.LoadBytes = LoadBytes(cmddat)
+ st.Syms = symtab
+ return st, nil
+}
+
+func (f *File) pushSection(sh *Section, r io.ReaderAt) {
+ f.Sections = append(f.Sections, sh)
sh.sr = io.NewSectionReader(r, int64(sh.Offset), int64(sh.Size))
sh.ReaderAt = sh.sr
}
@@ -368,3 +485,33 @@ func (f *File) DWARF() (*dwarf.Data, os.Error) {
abbrev, info, str := dat[0], dat[1], dat[2]
return dwarf.New(abbrev, nil, nil, info, nil, nil, nil, str)
}
+
+// ImportedSymbols returns the names of all symbols
+// referred to by the binary f that are expected to be
+// satisfied by other libraries at dynamic load time.
+func (f *File) ImportedSymbols() ([]string, os.Error) {
+ if f.Dysymtab == nil || f.Symtab == nil {
+ return nil, &FormatError{0, "missing symbol table", nil}
+ }
+
+ st := f.Symtab
+ dt := f.Dysymtab
+ var all []string
+ for _, s := range st.Syms[dt.Iundefsym : dt.Iundefsym+dt.Nundefsym] {
+ all = append(all, s.Name)
+ }
+ return all, nil
+}
+
+// ImportedLibraries returns the paths of all libraries
+// referred to by the binary f that are expected to be
+// linked with the binary at dynamic link time.
+func (f *File) ImportedLibraries() ([]string, os.Error) {
+ var all []string
+ for _, l := range f.Loads {
+ if lib, ok := l.(*Dylib); ok {
+ all = append(all, lib.Name)
+ }
+ }
+ return all, nil
+}
diff --git a/src/pkg/debug/macho/file_test.go b/src/pkg/debug/macho/file_test.go
index d4f3fc19c..56d8a20be 100644
--- a/src/pkg/debug/macho/file_test.go
+++ b/src/pkg/debug/macho/file_test.go
@@ -17,7 +17,7 @@ type fileTest struct {
}
var fileTests = []fileTest{
- fileTest{
+ {
"testdata/gcc-386-darwin-exec",
FileHeader{0xfeedface, Cpu386, 0x3, 0x2, 0xc, 0x3c0, 0x85},
[]*SegmentHeader{
@@ -42,7 +42,7 @@ var fileTests = []fileTest{
&SectionHeader{"__jump_table", "__IMPORT", 0x3000, 0xa, 0x2000, 0x6, 0x0, 0x0, 0x4000008},
},
},
- fileTest{
+ {
"testdata/gcc-amd64-darwin-exec",
FileHeader{0xfeedfacf, CpuAmd64, 0x80000003, 0x2, 0xb, 0x568, 0x85},
[]*SegmentHeader{
@@ -69,7 +69,7 @@ var fileTests = []fileTest{
&SectionHeader{"__la_symbol_ptr", "__DATA", 0x100001058, 0x10, 0x1058, 0x2, 0x0, 0x0, 0x7},
},
},
- fileTest{
+ {
"testdata/gcc-amd64-darwin-exec-debug",
FileHeader{0xfeedfacf, CpuAmd64, 0x80000003, 0xa, 0x4, 0x5a0, 0},
[]*SegmentHeader{
diff --git a/src/pkg/debug/macho/macho.go b/src/pkg/debug/macho/macho.go
index 41962d562..1386f5acf 100644
--- a/src/pkg/debug/macho/macho.go
+++ b/src/pkg/debug/macho/macho.go
@@ -47,8 +47,8 @@ const (
)
var cpuStrings = []intName{
- intName{uint32(Cpu386), "Cpu386"},
- intName{uint32(CpuAmd64), "CpuAmd64"},
+ {uint32(Cpu386), "Cpu386"},
+ {uint32(CpuAmd64), "CpuAmd64"},
}
func (i Cpu) String() string { return stringName(uint32(i), cpuStrings, false) }
@@ -59,16 +59,21 @@ type LoadCmd uint32
const (
LoadCmdSegment LoadCmd = 1
- LoadCmdSegment64 LoadCmd = 25
+ LoadCmdSymtab LoadCmd = 2
LoadCmdThread LoadCmd = 4
LoadCmdUnixThread LoadCmd = 5 // thread+stack
+ LoadCmdDysymtab LoadCmd = 11
+ LoadCmdDylib LoadCmd = 12
+ LoadCmdDylinker LoadCmd = 15
+ LoadCmdSegment64 LoadCmd = 25
)
var cmdStrings = []intName{
- intName{uint32(LoadCmdSegment), "LoadCmdSegment"},
- intName{uint32(LoadCmdSegment64), "LoadCmdSegment64"},
- intName{uint32(LoadCmdThread), "LoadCmdThread"},
- intName{uint32(LoadCmdUnixThread), "LoadCmdUnixThread"},
+ {uint32(LoadCmdSegment), "LoadCmdSegment"},
+ {uint32(LoadCmdThread), "LoadCmdThread"},
+ {uint32(LoadCmdUnixThread), "LoadCmdUnixThread"},
+ {uint32(LoadCmdDylib), "LoadCmdDylib"},
+ {uint32(LoadCmdSegment64), "LoadCmdSegment64"},
}
func (i LoadCmd) String() string { return stringName(uint32(i), cmdStrings, false) }
@@ -104,6 +109,16 @@ type Segment32 struct {
Flag uint32
}
+// A DylibCmd is a Mach-O load dynamic library command.
+type DylibCmd struct {
+ Cmd LoadCmd
+ Len uint32
+ Name uint32
+ Time uint32
+ CurrentVersion uint32
+ CompatVersion uint32
+}
+
// A Section32 is a 32-bit Mach-O section header.
type Section32 struct {
Name [16]byte
@@ -135,6 +150,67 @@ type Section64 struct {
Reserve3 uint32
}
+// A SymtabCmd is a Mach-O symbol table command.
+type SymtabCmd struct {
+ Cmd LoadCmd
+ Len uint32
+ Symoff uint32
+ Nsyms uint32
+ Stroff uint32
+ Strsize uint32
+}
+
+// A DysymtabCmd is a Mach-O dynamic symbol table command.
+type DysymtabCmd struct {
+ Cmd LoadCmd
+ Len uint32
+ Ilocalsym uint32
+ Nlocalsym uint32
+ Iextdefsym uint32
+ Nextdefsym uint32
+ Iundefsym uint32
+ Nundefsym uint32
+ Tocoffset uint32
+ Ntoc uint32
+ Modtaboff uint32
+ Nmodtab uint32
+ Extrefsymoff uint32
+ Nextrefsyms uint32
+ Indirectsymoff uint32
+ Nindirectsyms uint32
+ Extreloff uint32
+ Nextrel uint32
+ Locreloff uint32
+ Nlocrel uint32
+}
+
+// An Nlist32 is a Mach-O 32-bit symbol table entry.
+type Nlist32 struct {
+ Name uint32
+ Type uint8
+ Sect uint8
+ Desc uint16
+ Value uint32
+}
+
+// An Nlist64 is a Mach-O 64-bit symbol table entry.
+type Nlist64 struct {
+ Name uint32
+ Type uint8
+ Sect uint8
+ Desc uint16
+ Value uint64
+}
+
+// A Symbol is a Mach-O 32-bit or 64-bit symbol table entry.
+type Symbol struct {
+ Name string
+ Type uint8
+ Sect uint8
+ Desc uint16
+ Value uint64
+}
+
// A Thread is a Mach-O thread state command.
type Thread struct {
Cmd LoadCmd
diff --git a/src/pkg/exp/nacl/srpc/Makefile b/src/pkg/debug/pe/Makefile
index 7dda292f5..998e6a418 100644
--- a/src/pkg/exp/nacl/srpc/Makefile
+++ b/src/pkg/debug/pe/Makefile
@@ -2,12 +2,11 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../../../Make.$(GOARCH)
+include ../../../Make.inc
-TARG=exp/nacl/srpc
+TARG=debug/pe
GOFILES=\
- client.go\
- msg.go\
- server.go\
+ pe.go\
+ file.go\
-include ../../../../Make.pkg
+include ../../../Make.pkg
diff --git a/src/pkg/debug/pe/file.go b/src/pkg/debug/pe/file.go
new file mode 100644
index 000000000..904d2f863
--- /dev/null
+++ b/src/pkg/debug/pe/file.go
@@ -0,0 +1,231 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package pe implements access to PE (Microsoft Windows Portable Executable) files.
+package pe
+
+import (
+ "debug/dwarf"
+ "encoding/binary"
+ "fmt"
+ "io"
+ "os"
+ "strconv"
+)
+
+// A File represents an open PE file.
+type File struct {
+ FileHeader
+ Sections []*Section
+
+ closer io.Closer
+}
+
+type SectionHeader struct {
+ Name string
+ VirtualSize uint32
+ VirtualAddress uint32
+ Size uint32
+ Offset uint32
+ PointerToRelocations uint32
+ PointerToLineNumbers uint32
+ NumberOfRelocations uint16
+ NumberOfLineNumbers uint16
+ Characteristics uint32
+}
+
+
+type Section struct {
+ SectionHeader
+
+ // Embed ReaderAt for ReadAt method.
+ // Do not embed SectionReader directly
+ // to avoid having Read and Seek.
+ // If a client wants Read and Seek it must use
+ // Open() to avoid fighting over the seek offset
+ // with other clients.
+ io.ReaderAt
+ sr *io.SectionReader
+}
+
+// Data reads and returns the contents of the PE section.
+func (s *Section) Data() ([]byte, os.Error) {
+ dat := make([]byte, s.sr.Size())
+ n, err := s.sr.ReadAt(dat, 0)
+ return dat[0:n], err
+}
+
+// Open returns a new ReadSeeker reading the PE section.
+func (s *Section) Open() io.ReadSeeker { return io.NewSectionReader(s.sr, 0, 1<<63-1) }
+
+
+type FormatError struct {
+ off int64
+ msg string
+ val interface{}
+}
+
+func (e *FormatError) String() string {
+ msg := e.msg
+ if e.val != nil {
+ msg += fmt.Sprintf(" '%v'", e.val)
+ }
+ msg += fmt.Sprintf(" in record at byte %#x", e.off)
+ return msg
+}
+
+// Open opens the named file using os.Open and prepares it for use as a PE binary.
+func Open(name string) (*File, os.Error) {
+ f, err := os.Open(name, os.O_RDONLY, 0)
+ if err != nil {
+ return nil, err
+ }
+ ff, err := NewFile(f)
+ if err != nil {
+ f.Close()
+ return nil, err
+ }
+ ff.closer = f
+ return ff, nil
+}
+
+// Close closes the File.
+// If the File was created using NewFile directly instead of Open,
+// Close has no effect.
+func (f *File) Close() os.Error {
+ var err os.Error
+ if f.closer != nil {
+ err = f.closer.Close()
+ f.closer = nil
+ }
+ return err
+}
+
+// NewFile creates a new File for acecssing a PE binary in an underlying reader.
+func NewFile(r io.ReaderAt) (*File, os.Error) {
+ f := new(File)
+ sr := io.NewSectionReader(r, 0, 1<<63-1)
+
+ var dosheader [96]byte
+ if _, err := r.ReadAt(dosheader[0:], 0); err != nil {
+ return nil, err
+ }
+ var base int64
+ if dosheader[0] == 'M' && dosheader[1] == 'Z' {
+ var sign [4]byte
+ r.ReadAt(sign[0:], int64(dosheader[0x3c]))
+ if !(sign[0] == 'P' && sign[1] == 'E' && sign[2] == 0 && sign[3] == 0) {
+ return nil, os.NewError("Invalid PE File Format.")
+ }
+ base = int64(dosheader[0x3c]) + 4
+ } else {
+ base = int64(0)
+ }
+ sr.Seek(base, 0)
+ if err := binary.Read(sr, binary.LittleEndian, &f.FileHeader); err != nil {
+ return nil, err
+ }
+ if f.FileHeader.Machine != IMAGE_FILE_MACHINE_UNKNOWN && f.FileHeader.Machine != IMAGE_FILE_MACHINE_AMD64 && f.FileHeader.Machine != IMAGE_FILE_MACHINE_I386 {
+ return nil, os.NewError("Invalid PE File Format.")
+ }
+ // get symbol string table
+ sr.Seek(int64(f.FileHeader.PointerToSymbolTable+18*f.FileHeader.NumberOfSymbols), 0)
+ var l uint32
+ if err := binary.Read(sr, binary.LittleEndian, &l); err != nil {
+ return nil, err
+ }
+ ss := make([]byte, l)
+ if _, err := r.ReadAt(ss, int64(f.FileHeader.PointerToSymbolTable+18*f.FileHeader.NumberOfSymbols)); err != nil {
+ return nil, err
+ }
+ sr.Seek(base, 0)
+ binary.Read(sr, binary.LittleEndian, &f.FileHeader)
+ sr.Seek(int64(f.FileHeader.SizeOfOptionalHeader), 1) //Skip OptionalHeader
+ f.Sections = make([]*Section, f.FileHeader.NumberOfSections)
+ for i := 0; i < int(f.FileHeader.NumberOfSections); i++ {
+ sh := new(SectionHeader32)
+ if err := binary.Read(sr, binary.LittleEndian, sh); err != nil {
+ return nil, err
+ }
+ var name string
+ if sh.Name[0] == '\x2F' {
+ si, _ := strconv.Atoi(cstring(sh.Name[1:]))
+ name, _ = getString(ss, si)
+ } else {
+ name = cstring(sh.Name[0:])
+ }
+ s := new(Section)
+ s.SectionHeader = SectionHeader{
+ Name: name,
+ VirtualSize: uint32(sh.VirtualSize),
+ VirtualAddress: uint32(sh.VirtualAddress),
+ Size: uint32(sh.SizeOfRawData),
+ Offset: uint32(sh.PointerToRawData),
+ PointerToRelocations: uint32(sh.PointerToRelocations),
+ PointerToLineNumbers: uint32(sh.PointerToLineNumbers),
+ NumberOfRelocations: uint16(sh.NumberOfRelocations),
+ NumberOfLineNumbers: uint16(sh.NumberOfLineNumbers),
+ Characteristics: uint32(sh.Characteristics),
+ }
+ s.sr = io.NewSectionReader(r, int64(s.SectionHeader.Offset), int64(s.SectionHeader.Size))
+ s.ReaderAt = s.sr
+ f.Sections[i] = s
+ }
+ return f, nil
+}
+
+func cstring(b []byte) string {
+ var i int
+ for i = 0; i < len(b) && b[i] != 0; i++ {
+ }
+ return string(b[0:i])
+}
+
+// getString extracts a string from symbol string table.
+func getString(section []byte, start int) (string, bool) {
+ if start < 0 || start >= len(section) {
+ return "", false
+ }
+
+ for end := start; end < len(section); end++ {
+ if section[end] == 0 {
+ return string(section[start:end]), true
+ }
+ }
+ return "", false
+}
+
+// Section returns the first section with the given name, or nil if no such
+// section exists.
+func (f *File) Section(name string) *Section {
+ for _, s := range f.Sections {
+ if s.Name == name {
+ return s
+ }
+ }
+ return nil
+}
+
+func (f *File) DWARF() (*dwarf.Data, os.Error) {
+ // There are many other DWARF sections, but these
+ // are the required ones, and the debug/dwarf package
+ // does not use the others, so don't bother loading them.
+ var names = [...]string{"abbrev", "info", "str"}
+ var dat [len(names)][]byte
+ for i, name := range names {
+ name = ".debug_" + name
+ s := f.Section(name)
+ if s == nil {
+ continue
+ }
+ b, err := s.Data()
+ if err != nil && uint32(len(b)) < s.Size {
+ return nil, err
+ }
+ dat[i] = b
+ }
+
+ abbrev, info, str := dat[0], dat[1], dat[2]
+ return dwarf.New(abbrev, nil, nil, info, nil, nil, nil, str)
+}
diff --git a/src/pkg/debug/pe/file_test.go b/src/pkg/debug/pe/file_test.go
new file mode 100644
index 000000000..2c5c25b8c
--- /dev/null
+++ b/src/pkg/debug/pe/file_test.go
@@ -0,0 +1,99 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package pe
+
+import (
+ "reflect"
+ "testing"
+)
+
+type fileTest struct {
+ file string
+ hdr FileHeader
+ sections []*SectionHeader
+}
+
+var fileTests = []fileTest{
+ {
+ "testdata/gcc-386-mingw-obj",
+ FileHeader{0x014c, 0x000c, 0x0, 0x64a, 0x1e, 0x0, 0x104},
+ []*SectionHeader{
+ &SectionHeader{".text", 0, 0, 36, 500, 1440, 0, 3, 0, 0x60300020},
+ &SectionHeader{".data", 0, 0, 0, 0, 0, 0, 0, 0, 3224371264},
+ &SectionHeader{".bss", 0, 0, 0, 0, 0, 0, 0, 0, 3224371328},
+ &SectionHeader{".debug_abbrev", 0, 0, 137, 536, 0, 0, 0, 0, 0x42100000},
+ &SectionHeader{".debug_info", 0, 0, 418, 673, 1470, 0, 7, 0, 1108344832},
+ &SectionHeader{".debug_line", 0, 0, 128, 1091, 1540, 0, 1, 0, 1108344832},
+ &SectionHeader{".rdata", 0, 0, 16, 1219, 0, 0, 0, 0, 1076887616},
+ &SectionHeader{".debug_frame", 0, 0, 52, 1235, 1550, 0, 2, 0, 1110441984},
+ &SectionHeader{".debug_loc", 0, 0, 56, 1287, 0, 0, 0, 0, 1108344832},
+ &SectionHeader{".debug_pubnames", 0, 0, 27, 1343, 1570, 0, 1, 0, 1108344832},
+ &SectionHeader{".debug_pubtypes", 0, 0, 38, 1370, 1580, 0, 1, 0, 1108344832},
+ &SectionHeader{".debug_aranges", 0, 0, 32, 1408, 1590, 0, 2, 0, 1108344832},
+ },
+ },
+ {
+ "testdata/gcc-386-mingw-exec",
+ FileHeader{0x014c, 0x000f, 0x4c6a1b60, 0x3c00, 0x282, 0xe0, 0x107},
+ []*SectionHeader{
+ &SectionHeader{Name: ".text", VirtualSize: 0xcd8, VirtualAddress: 0x1000, Size: 0xe00, Offset: 0x400, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x60500060},
+ &SectionHeader{Name: ".data", VirtualSize: 0x10, VirtualAddress: 0x2000, Size: 0x200, Offset: 0x1200, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0300040},
+ &SectionHeader{Name: ".rdata", VirtualSize: 0x120, VirtualAddress: 0x3000, Size: 0x200, Offset: 0x1400, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x40300040},
+ &SectionHeader{Name: ".bss", VirtualSize: 0xdc, VirtualAddress: 0x4000, Size: 0x0, Offset: 0x0, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0400080},
+ &SectionHeader{Name: ".idata", VirtualSize: 0x3c8, VirtualAddress: 0x5000, Size: 0x400, Offset: 0x1600, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0300040},
+ &SectionHeader{Name: ".CRT", VirtualSize: 0x18, VirtualAddress: 0x6000, Size: 0x200, Offset: 0x1a00, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0300040},
+ &SectionHeader{Name: ".tls", VirtualSize: 0x20, VirtualAddress: 0x7000, Size: 0x200, Offset: 0x1c00, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0xc0300040},
+ &SectionHeader{Name: ".debug_aranges", VirtualSize: 0x20, VirtualAddress: 0x8000, Size: 0x200, Offset: 0x1e00, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
+ &SectionHeader{Name: ".debug_pubnames", VirtualSize: 0x51, VirtualAddress: 0x9000, Size: 0x200, Offset: 0x2000, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
+ &SectionHeader{Name: ".debug_pubtypes", VirtualSize: 0x91, VirtualAddress: 0xa000, Size: 0x200, Offset: 0x2200, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
+ &SectionHeader{Name: ".debug_info", VirtualSize: 0xe22, VirtualAddress: 0xb000, Size: 0x1000, Offset: 0x2400, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
+ &SectionHeader{Name: ".debug_abbrev", VirtualSize: 0x157, VirtualAddress: 0xc000, Size: 0x200, Offset: 0x3400, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
+ &SectionHeader{Name: ".debug_line", VirtualSize: 0x144, VirtualAddress: 0xd000, Size: 0x200, Offset: 0x3600, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
+ &SectionHeader{Name: ".debug_frame", VirtualSize: 0x34, VirtualAddress: 0xe000, Size: 0x200, Offset: 0x3800, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42300000},
+ &SectionHeader{Name: ".debug_loc", VirtualSize: 0x38, VirtualAddress: 0xf000, Size: 0x200, Offset: 0x3a00, PointerToRelocations: 0x0, PointerToLineNumbers: 0x0, NumberOfRelocations: 0x0, NumberOfLineNumbers: 0x0, Characteristics: 0x42100000},
+ },
+ },
+}
+
+func TestOpen(t *testing.T) {
+ for i := range fileTests {
+ tt := &fileTests[i]
+
+ f, err := Open(tt.file)
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+ if !reflect.DeepEqual(f.FileHeader, tt.hdr) {
+ t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.FileHeader, tt.hdr)
+ continue
+ }
+
+ for i, sh := range f.Sections {
+ if i >= len(tt.sections) {
+ break
+ }
+ have := &sh.SectionHeader
+ want := tt.sections[i]
+ if !reflect.DeepEqual(have, want) {
+ t.Errorf("open %s, section %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want)
+ }
+ }
+ tn := len(tt.sections)
+ fn := len(f.Sections)
+ if tn != fn {
+ t.Errorf("open %s: len(Sections) = %d, want %d", tt.file, fn, tn)
+ }
+
+ }
+}
+
+func TestOpenFailure(t *testing.T) {
+ filename := "file.go" // not a PE file
+ _, err := Open(filename) // don't crash
+ if err == nil {
+ t.Errorf("open %s: succeeded unexpectedly", filename)
+ }
+}
diff --git a/src/pkg/debug/pe/pe.go b/src/pkg/debug/pe/pe.go
new file mode 100644
index 000000000..b3dab739a
--- /dev/null
+++ b/src/pkg/debug/pe/pe.go
@@ -0,0 +1,51 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package pe
+
+type FileHeader struct {
+ Machine uint16
+ NumberOfSections uint16
+ TimeDateStamp uint32
+ PointerToSymbolTable uint32
+ NumberOfSymbols uint32
+ SizeOfOptionalHeader uint16
+ Characteristics uint16
+}
+
+type SectionHeader32 struct {
+ Name [8]uint8
+ VirtualSize uint32
+ VirtualAddress uint32
+ SizeOfRawData uint32
+ PointerToRawData uint32
+ PointerToRelocations uint32
+ PointerToLineNumbers uint32
+ NumberOfRelocations uint16
+ NumberOfLineNumbers uint16
+ Characteristics uint32
+}
+
+const (
+ IMAGE_FILE_MACHINE_UNKNOWN = 0x0
+ IMAGE_FILE_MACHINE_AM33 = 0x1d3
+ IMAGE_FILE_MACHINE_AMD64 = 0x8664
+ IMAGE_FILE_MACHINE_ARM = 0x1c0
+ IMAGE_FILE_MACHINE_EBC = 0xebc
+ IMAGE_FILE_MACHINE_I386 = 0x14c
+ IMAGE_FILE_MACHINE_IA64 = 0x200
+ IMAGE_FILE_MACHINE_M32R = 0x9041
+ IMAGE_FILE_MACHINE_MIPS16 = 0x266
+ IMAGE_FILE_MACHINE_MIPSFPU = 0x366
+ IMAGE_FILE_MACHINE_MIPSFPU16 = 0x466
+ IMAGE_FILE_MACHINE_POWERPC = 0x1f0
+ IMAGE_FILE_MACHINE_POWERPCFP = 0x1f1
+ IMAGE_FILE_MACHINE_R4000 = 0x166
+ IMAGE_FILE_MACHINE_SH3 = 0x1a2
+ IMAGE_FILE_MACHINE_SH3DSP = 0x1a3
+ IMAGE_FILE_MACHINE_SH4 = 0x1a6
+ IMAGE_FILE_MACHINE_SH5 = 0x1a8
+ IMAGE_FILE_MACHINE_THUMB = 0x1c2
+ IMAGE_FILE_MACHINE_WCEMIPSV2 = 0x169
+)
diff --git a/src/pkg/debug/pe/testdata/gcc-386-mingw-exec b/src/pkg/debug/pe/testdata/gcc-386-mingw-exec
new file mode 100644
index 000000000..4b808d043
--- /dev/null
+++ b/src/pkg/debug/pe/testdata/gcc-386-mingw-exec
Binary files differ
diff --git a/src/pkg/debug/pe/testdata/gcc-386-mingw-obj b/src/pkg/debug/pe/testdata/gcc-386-mingw-obj
new file mode 100644
index 000000000..0c84d898d
--- /dev/null
+++ b/src/pkg/debug/pe/testdata/gcc-386-mingw-obj
Binary files differ
diff --git a/src/pkg/debug/pe/testdata/hello.c b/src/pkg/debug/pe/testdata/hello.c
new file mode 100644
index 000000000..a689d3644
--- /dev/null
+++ b/src/pkg/debug/pe/testdata/hello.c
@@ -0,0 +1,8 @@
+#include <stdio.h>
+
+int
+main(void)
+{
+ printf("hello, world\n");
+ return 0;
+}
diff --git a/src/pkg/debug/proc/Makefile b/src/pkg/debug/proc/Makefile
index 5444ec0db..c6d879836 100644
--- a/src/pkg/debug/proc/Makefile
+++ b/src/pkg/debug/proc/Makefile
@@ -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 ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=debug/proc
GOFILES=\
diff --git a/src/pkg/debug/proc/proc_linux.go b/src/pkg/debug/proc/proc_linux.go
index 5253ea846..f0cc43a10 100644
--- a/src/pkg/debug/proc/proc_linux.go
+++ b/src/pkg/debug/proc/proc_linux.go
@@ -153,7 +153,7 @@ type process struct {
debugEvents chan *debugEvent
debugReqs chan *debugReq
stopReq chan os.Error
- transitionHandlers *vector.Vector
+ transitionHandlers vector.Vector
err os.Error
}
@@ -297,7 +297,7 @@ func (t *thread) logTrace(format string, args ...interface{}) {
}
}
fmt.Fprint(os.Stderr, ": ")
- fmt.Fprintf(os.Stderr, format, args)
+ fmt.Fprintf(os.Stderr, format, args...)
fmt.Fprint(os.Stderr, "\n")
}
@@ -305,7 +305,7 @@ func (t *thread) warn(format string, args ...interface{}) {
logLock.Lock()
defer logLock.Unlock()
fmt.Fprintf(os.Stderr, "Thread %d: WARNING ", t.tid)
- fmt.Fprintf(os.Stderr, format, args)
+ fmt.Fprintf(os.Stderr, format, args...)
fmt.Fprint(os.Stderr, "\n")
}
@@ -316,7 +316,7 @@ func (p *process) logTrace(format string, args ...interface{}) {
logLock.Lock()
defer logLock.Unlock()
fmt.Fprintf(os.Stderr, "Process %d: ", p.pid)
- fmt.Fprintf(os.Stderr, format, args)
+ fmt.Fprintf(os.Stderr, format, args...)
fmt.Fprint(os.Stderr, "\n")
}
@@ -472,8 +472,8 @@ func (t *thread) setState(newState threadState) {
return
}
- t.proc.transitionHandlers = new(vector.Vector)
- for _, h := range handlers.Data() {
+ t.proc.transitionHandlers = nil
+ for _, h := range handlers {
h := h.(*transitionHandler)
h.handle(t, oldState, newState)
}
@@ -738,7 +738,7 @@ func (p *process) monitor() {
// Abort waiting handlers
// TODO(austin) How do I stop the wait threads?
- for _, h := range p.transitionHandlers.Data() {
+ for _, h := range p.transitionHandlers {
h := h.(*transitionHandler)
h.onErr(err)
}
@@ -1249,14 +1249,13 @@ func (p *process) attachAllThreads() os.Error {
// newProcess creates a new process object and starts its monitor thread.
func newProcess(pid int) *process {
p := &process{
- pid: pid,
- threads: make(map[int]*thread),
- breakpoints: make(map[uintptr]*breakpoint),
- ready: make(chan bool, 1),
- debugEvents: make(chan *debugEvent),
- debugReqs: make(chan *debugReq),
- stopReq: make(chan os.Error),
- transitionHandlers: new(vector.Vector),
+ pid: pid,
+ threads: make(map[int]*thread),
+ breakpoints: make(map[uintptr]*breakpoint),
+ ready: make(chan bool, 1),
+ debugEvents: make(chan *debugEvent),
+ debugReqs: make(chan *debugReq),
+ stopReq: make(chan os.Error),
}
go p.monitor()
diff --git a/src/pkg/debug/proc/proc_nacl.go b/src/pkg/debug/proc/proc_nacl.go
deleted file mode 100644
index be26bbf18..000000000
--- a/src/pkg/debug/proc/proc_nacl.go
+++ /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.
-
-package proc
-
-import (
- "os"
- "syscall"
-)
-
-// Process tracing is not supported on Native Client.
-
-func Attach(pid int) (Process, os.Error) {
- return nil, os.NewSyscallError("ptrace", syscall.ENACL)
-}
-
-func ForkExec(argv0 string, argv []string, envv []string, dir string, fd []*os.File) (Process, os.Error) {
- return nil, os.NewSyscallError("fork/exec", syscall.ENACL)
-}
diff --git a/src/pkg/debug/proc/regs_linux_386.go b/src/pkg/debug/proc/regs_linux_386.go
index 7cebfa64a..b4a9769db 100644
--- a/src/pkg/debug/proc/regs_linux_386.go
+++ b/src/pkg/debug/proc/regs_linux_386.go
@@ -80,17 +80,17 @@ func (r *_386Regs) Get(i int) Word {
case 9:
return Word(uint32(r.Eflags))
case 10:
- return Word(r.Cs)
+ return Word(r.Xcs)
case 11:
- return Word(r.Ss)
+ return Word(r.Xss)
case 12:
- return Word(r.Ds)
+ return Word(r.Xds)
case 13:
- return Word(r.Es)
+ return Word(r.Xes)
case 14:
- return Word(r.Fs)
+ return Word(r.Xfs)
case 15:
- return Word(r.Gs)
+ return Word(r.Xgs)
}
panic("invalid register index " + strconv.Itoa(i))
}
@@ -118,17 +118,17 @@ func (r *_386Regs) Set(i int, val Word) os.Error {
case 9:
r.Eflags = int32(val)
case 10:
- r.Cs = uint16(val)
+ r.Xcs = int32(val)
case 11:
- r.Ss = uint16(val)
+ r.Xss = int32(val)
case 12:
- r.Ds = uint16(val)
+ r.Xds = int32(val)
case 13:
- r.Es = uint16(val)
+ r.Xes = int32(val)
case 14:
- r.Fs = uint16(val)
+ r.Xfs = int32(val)
case 15:
- r.Gs = uint16(val)
+ r.Xgs = int32(val)
default:
panic("invalid register index " + strconv.Itoa(i))
}
diff --git a/src/pkg/debug/proc/regs_linux_amd64.go b/src/pkg/debug/proc/regs_linux_amd64.go
index a9f3569d3..381be29b1 100644
--- a/src/pkg/debug/proc/regs_linux_amd64.go
+++ b/src/pkg/debug/proc/regs_linux_amd64.go
@@ -71,7 +71,7 @@ func (r *amd64Regs) SetSP(val Word) os.Error {
return r.setter(&r.PtraceRegs)
}
-func (r *amd64Regs) Names() []string { return &names }
+func (r *amd64Regs) Names() []string { return names[0:] }
func (r *amd64Regs) Get(i int) Word {
switch i {
diff --git a/src/pkg/deps.bash b/src/pkg/deps.bash
index c8406d39c..a8e3dfc3a 100755
--- a/src/pkg/deps.bash
+++ b/src/pkg/deps.bash
@@ -3,6 +3,8 @@
# 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"
@@ -12,8 +14,8 @@ if [ -f $OUT ] && ! [ -w $OUT ]; then
fi
# Get list of directories from Makefile
-dirs=$(sed '1,/^DIRS=/d; /^$/,$d; s/\\//g' Makefile)
-dirpat=$(echo $dirs | sed 's/ /|/g; s/.*/^(&)$/')
+dirs=$(gomake --no-print-directory echo-dirs)
+dirpat=$(echo $dirs C | sed 's/ /|/g; s/.*/^(&)$/')
for dir in $dirs; do (
cd $dir || exit 1
@@ -31,6 +33,7 @@ for dir in $dirs; do (
egrep "$dirpat" |
grep -v "^$dir\$" |
sed 's/$/.install/' |
+ sed 's;^C\.install;runtime/cgo.install;' |
sort -u
)
diff --git a/src/pkg/ebnf/Makefile b/src/pkg/ebnf/Makefile
index 4a75c7432..f5555d272 100644
--- a/src/pkg/ebnf/Makefile
+++ b/src/pkg/ebnf/Makefile
@@ -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 ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=ebnf
GOFILES=\
diff --git a/src/pkg/ebnf/ebnf.go b/src/pkg/ebnf/ebnf.go
index 898a48173..e5aabd582 100644
--- a/src/pkg/ebnf/ebnf.go
+++ b/src/pkg/ebnf/ebnf.go
@@ -23,7 +23,6 @@
package ebnf
import (
- "container/vector"
"go/scanner"
"go/token"
"os"
@@ -39,7 +38,7 @@ type (
// An Expression node represents a production expression.
Expression interface {
// Pos is the position of the first character of the syntactic construct
- Pos() token.Position
+ Pos() token.Pos
}
// An Alternative node represents a non-empty list of alternative expressions.
@@ -50,14 +49,14 @@ type (
// A Name node represents a production name.
Name struct {
- token.Position
- String string
+ StringPos token.Pos
+ String string
}
// A Token node represents a literal.
Token struct {
- token.Position
- String string
+ StringPos token.Pos
+ String string
}
// A List node represents a range of characters.
@@ -67,20 +66,20 @@ type (
// A Group node represents a grouped expression.
Group struct {
- token.Position
- Body Expression // (body)
+ Lparen token.Pos
+ Body Expression // (body)
}
// An Option node represents an optional expression.
Option struct {
- token.Position
- Body Expression // [body]
+ Lbrack token.Pos
+ Body Expression // [body]
}
// A Repetition node represents a repeated expression.
Repetition struct {
- token.Position
- Body Expression // {body}
+ Lbrace token.Pos
+ Body Expression // {body}
}
// A Production node represents an EBNF production.
@@ -96,20 +95,15 @@ type (
)
-func (x Alternative) Pos() token.Position {
- return x[0].Pos() // the parser always generates non-empty Alternative
-}
-
-
-func (x Sequence) Pos() token.Position {
- return x[0].Pos() // the parser always generates non-empty Sequences
-}
-
-
-func (x Range) Pos() token.Position { return x.Begin.Pos() }
-
-
-func (p *Production) Pos() token.Position { return p.Name.Pos() }
+func (x Alternative) Pos() token.Pos { return x[0].Pos() } // the parser always generates non-empty Alternative
+func (x Sequence) Pos() token.Pos { return x[0].Pos() } // the parser always generates non-empty Sequences
+func (x *Name) Pos() token.Pos { return x.StringPos }
+func (x *Token) Pos() token.Pos { return x.StringPos }
+func (x *Range) Pos() token.Pos { return x.Begin.Pos() }
+func (x *Group) Pos() token.Pos { return x.Lparen }
+func (x *Option) Pos() token.Pos { return x.Lbrack }
+func (x *Repetition) Pos() token.Pos { return x.Lbrace }
+func (x *Production) Pos() token.Pos { return x.Name.Pos() }
// ----------------------------------------------------------------------------
@@ -122,17 +116,23 @@ func isLexical(name string) bool {
type verifier struct {
+ fset *token.FileSet
scanner.ErrorVector
- worklist vector.Vector
+ 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.Push(prod)
+ v.worklist = append(v.worklist, prod)
v.reached[name] = prod
}
}
@@ -141,7 +141,7 @@ func (v *verifier) push(prod *Production) {
func (v *verifier) verifyChar(x *Token) int {
s := x.String
if utf8.RuneCountInString(s) != 1 {
- v.Error(x.Pos(), "single char expected, found "+s)
+ v.error(x.Pos(), "single char expected, found "+s)
return 0
}
ch, _ := utf8.DecodeRuneInString(s)
@@ -167,12 +167,12 @@ func (v *verifier) verifyExpr(expr Expression, lexical bool) {
if prod, found := v.grammar[x.String]; found {
v.push(prod)
} else {
- v.Error(x.Pos(), "missing production "+x.String)
+ 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)
+ v.error(x.Pos(), "reference to non-lexical production "+x.String)
}
case *Token:
// nothing to do for now
@@ -180,7 +180,7 @@ func (v *verifier) verifyExpr(expr Expression, lexical bool) {
i := v.verifyChar(x.Begin)
j := v.verifyChar(x.End)
if i >= j {
- v.Error(x.Pos(), "decreasing character range")
+ v.error(x.Pos(), "decreasing character range")
}
case *Group:
v.verifyExpr(x.Body, lexical)
@@ -194,25 +194,32 @@ func (v *verifier) verifyExpr(expr Expression, lexical bool) {
}
-func (v *verifier) verify(grammar Grammar, start string) {
+func (v *verifier) verify(fset *token.FileSet, grammar Grammar, start string) {
// find root production
root, found := grammar[start]
if !found {
- var noPos token.Position
- v.Error(noPos, "no start production "+start)
+ // 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.Resize(0, 0)
+ v.worklist = v.worklist[0:0]
v.reached = make(Grammar)
v.grammar = grammar
// work through the worklist
v.push(root)
- for v.worklist.Len() > 0 {
- prod := v.worklist.Pop().(*Production)
+ 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))
}
@@ -220,7 +227,7 @@ func (v *verifier) verify(grammar Grammar, start string) {
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")
+ v.error(prod.Pos(), name+" is unreachable")
}
}
}
@@ -232,8 +239,10 @@ func (v *verifier) verify(grammar Grammar, start string) {
// - all productions defined are used when beginning at start
// - lexical productions refer only to other lexical productions
//
-func Verify(grammar Grammar, start string) os.Error {
+// 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(grammar, start)
+ 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
index a88d19bed..bbe530c27 100644
--- a/src/pkg/ebnf/ebnf_test.go
+++ b/src/pkg/ebnf/ebnf_test.go
@@ -5,11 +5,15 @@
package ebnf
import (
+ "go/token"
"io/ioutil"
"testing"
)
+var fset = token.NewFileSet()
+
+
var grammars = []string{
`Program = .
`,
@@ -40,11 +44,11 @@ var grammars = []string{
func check(t *testing.T, filename string, src []byte) {
- grammar, err := Parse(filename, src)
+ grammar, err := Parse(fset, filename, src)
if err != nil {
t.Errorf("Parse(%s) failed: %v", src, err)
}
- if err = Verify(grammar, "Program"); err != nil {
+ if err = Verify(fset, grammar, "Program"); err != nil {
t.Errorf("Verify(%s) failed: %v", src, err)
}
}
diff --git a/src/pkg/ebnf/parser.go b/src/pkg/ebnf/parser.go
index 649587879..ef72d91fd 100644
--- a/src/pkg/ebnf/parser.go
+++ b/src/pkg/ebnf/parser.go
@@ -5,7 +5,6 @@
package ebnf
import (
- "container/vector"
"go/scanner"
"go/token"
"os"
@@ -14,11 +13,12 @@ import (
type parser struct {
+ fset *token.FileSet
scanner.ErrorVector
scanner scanner.Scanner
- pos token.Position // token position
- tok token.Token // one token look-ahead
- lit []byte // token literal
+ pos token.Pos // token position
+ tok token.Token // one token look-ahead
+ lit []byte // token literal
}
@@ -32,9 +32,14 @@ func (p *parser) next() {
}
-func (p *parser) errorExpected(pos token.Position, msg string) {
+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.Offset == p.pos.Offset {
+ if pos == p.pos {
// the error happened at the current position;
// make the error message more specific
msg += ", found '" + p.tok.String() + "'"
@@ -42,11 +47,11 @@ func (p *parser) errorExpected(pos token.Position, msg string) {
msg += " " + string(p.lit)
}
}
- p.Error(pos, msg)
+ p.error(pos, msg)
}
-func (p *parser) expect(tok token.Token) token.Position {
+func (p *parser) expect(tok token.Token) token.Pos {
pos := p.pos
if p.tok != tok {
p.errorExpected(pos, "'"+tok.String()+"'")
@@ -116,36 +121,30 @@ func (p *parser) parseTerm() (x Expression) {
func (p *parser) parseSequence() Expression {
- var list vector.Vector
+ var list Sequence
for x := p.parseTerm(); x != nil; x = p.parseTerm() {
- list.Push(x)
+ list = append(list, x)
}
// no need for a sequence if list.Len() < 2
- switch list.Len() {
+ switch len(list) {
case 0:
return nil
case 1:
- return list.At(0).(Expression)
+ return list[0]
}
- // convert list into a sequence
- seq := make(Sequence, list.Len())
- for i := 0; i < list.Len(); i++ {
- seq[i] = list.At(i).(Expression)
- }
- return seq
+ return list
}
func (p *parser) parseExpression() Expression {
- var list vector.Vector
+ var list Alternative
for {
- x := p.parseSequence()
- if x != nil {
- list.Push(x)
+ if x := p.parseSequence(); x != nil {
+ list = append(list, x)
}
if p.tok != token.OR {
break
@@ -154,19 +153,14 @@ func (p *parser) parseExpression() Expression {
}
// no need for an Alternative node if list.Len() < 2
- switch list.Len() {
+ switch len(list) {
case 0:
return nil
case 1:
- return list.At(0).(Expression)
+ return list[0]
}
- // convert list into an Alternative node
- alt := make(Alternative, list.Len())
- for i := 0; i < list.Len(); i++ {
- alt[i] = list.At(i).(Expression)
- }
- return alt
+ return list
}
@@ -179,10 +173,11 @@ func (p *parser) parseProduction() *Production {
}
-func (p *parser) parse(filename string, src []byte) Grammar {
+func (p *parser) parse(fset *token.FileSet, filename string, src []byte) Grammar {
// initialize parser
+ p.fset = fset
p.ErrorVector.Reset()
- p.scanner.Init(filename, src, p, 0)
+ p.scanner.Init(fset, filename, src, p, 0)
p.next() // initializes pos, tok, lit
grammar := make(Grammar)
@@ -192,7 +187,7 @@ func (p *parser) parse(filename string, src []byte) Grammar {
if _, found := grammar[name]; !found {
grammar[name] = prod
} else {
- p.Error(prod.Pos(), name+" declared already")
+ p.error(prod.Pos(), name+" declared already")
}
}
@@ -203,10 +198,11 @@ func (p *parser) parse(filename string, src []byte) 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.
+// more than once. Position information is recorded relative
+// to the file set fset.
//
-func Parse(filename string, src []byte) (Grammar, os.Error) {
+func Parse(fset *token.FileSet, filename string, src []byte) (Grammar, os.Error) {
var p parser
- grammar := p.parse(filename, src)
+ 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
index 7ec14bd1a..412383efd 100644
--- a/src/pkg/encoding/ascii85/Makefile
+++ b/src/pkg/encoding/ascii85/Makefile
@@ -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 ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=encoding/ascii85
GOFILES=\
diff --git a/src/pkg/encoding/ascii85/ascii85_test.go b/src/pkg/encoding/ascii85/ascii85_test.go
index 738e1cc1b..fdfeb889f 100644
--- a/src/pkg/encoding/ascii85/ascii85_test.go
+++ b/src/pkg/encoding/ascii85/ascii85_test.go
@@ -17,7 +17,7 @@ type testpair struct {
var pairs = []testpair{
// Wikipedia example
- testpair{
+ {
"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 " +
@@ -34,7 +34,7 @@ var bigtest = pairs[len(pairs)-1]
func testEqual(t *testing.T, msg string, args ...interface{}) bool {
if args[len(args)-2] != args[len(args)-1] {
- t.Errorf(msg, args)
+ t.Errorf(msg, args...)
return false
}
return true
@@ -138,8 +138,8 @@ func TestDecodeCorrupt(t *testing.T) {
p int
}
examples := []corrupt{
- corrupt{"v", 0},
- corrupt{"!z!!!!!!!!!", 1},
+ {"v", 0},
+ {"!z!!!!!!!!!", 1},
}
for _, e := range examples {
diff --git a/src/pkg/encoding/base64/Makefile b/src/pkg/encoding/base64/Makefile
index 8503b1663..2f54ed839 100644
--- a/src/pkg/encoding/base64/Makefile
+++ b/src/pkg/encoding/base64/Makefile
@@ -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 ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=encoding/base64
GOFILES=\
diff --git a/src/pkg/encoding/base64/base64_test.go b/src/pkg/encoding/base64/base64_test.go
index c14785f1b..de41e704b 100644
--- a/src/pkg/encoding/base64/base64_test.go
+++ b/src/pkg/encoding/base64/base64_test.go
@@ -17,28 +17,28 @@ type testpair struct {
var pairs = []testpair{
// RFC 3548 examples
- testpair{"\x14\xfb\x9c\x03\xd9\x7e", "FPucA9l+"},
- testpair{"\x14\xfb\x9c\x03\xd9", "FPucA9k="},
- testpair{"\x14\xfb\x9c\x03", "FPucAw=="},
+ {"\x14\xfb\x9c\x03\xd9\x7e", "FPucA9l+"},
+ {"\x14\xfb\x9c\x03\xd9", "FPucA9k="},
+ {"\x14\xfb\x9c\x03", "FPucAw=="},
// RFC 4648 examples
- testpair{"", ""},
- testpair{"f", "Zg=="},
- testpair{"fo", "Zm8="},
- testpair{"foo", "Zm9v"},
- testpair{"foob", "Zm9vYg=="},
- testpair{"fooba", "Zm9vYmE="},
- testpair{"foobar", "Zm9vYmFy"},
+ {"", ""},
+ {"f", "Zg=="},
+ {"fo", "Zm8="},
+ {"foo", "Zm9v"},
+ {"foob", "Zm9vYg=="},
+ {"fooba", "Zm9vYmE="},
+ {"foobar", "Zm9vYmFy"},
// Wikipedia examples
- testpair{"sure.", "c3VyZS4="},
- testpair{"sure", "c3VyZQ=="},
- testpair{"sur", "c3Vy"},
- testpair{"su", "c3U="},
- testpair{"leasure.", "bGVhc3VyZS4="},
- testpair{"easure.", "ZWFzdXJlLg=="},
- testpair{"asure.", "YXN1cmUu"},
- testpair{"sure.", "c3VyZS4="},
+ {"sure.", "c3VyZS4="},
+ {"sure", "c3VyZQ=="},
+ {"sur", "c3Vy"},
+ {"su", "c3U="},
+ {"leasure.", "bGVhc3VyZS4="},
+ {"easure.", "ZWFzdXJlLg=="},
+ {"asure.", "YXN1cmUu"},
+ {"sure.", "c3VyZS4="},
}
var bigtest = testpair{
@@ -48,7 +48,7 @@ var bigtest = testpair{
func testEqual(t *testing.T, msg string, args ...interface{}) bool {
if args[len(args)-2] != args[len(args)-1] {
- t.Errorf(msg, args)
+ t.Errorf(msg, args...)
return false
}
return true
@@ -142,12 +142,12 @@ func TestDecodeCorrupt(t *testing.T) {
p int
}
examples := []corrupt{
- corrupt{"!!!!", 0},
- corrupt{"x===", 1},
- corrupt{"AA=A", 2},
- corrupt{"AAA=AAAA", 3},
- corrupt{"AAAAA", 4},
- corrupt{"AAAAAA", 4},
+ {"!!!!", 0},
+ {"x===", 1},
+ {"AA=A", 2},
+ {"AAA=AAAA", 3},
+ {"AAAAA", 4},
+ {"AAAAAA", 4},
}
for _, e := range examples {
diff --git a/src/pkg/encoding/binary/Makefile b/src/pkg/encoding/binary/Makefile
index 23d4d6d43..dc46abe90 100644
--- a/src/pkg/encoding/binary/Makefile
+++ b/src/pkg/encoding/binary/Makefile
@@ -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 ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=encoding/binary
GOFILES=\
diff --git a/src/pkg/encoding/binary/binary.go b/src/pkg/encoding/binary/binary.go
index 5a92faa21..6bbe7eb89 100644
--- a/src/pkg/encoding/binary/binary.go
+++ b/src/pkg/encoding/binary/binary.go
@@ -29,8 +29,11 @@ type ByteOrder interface {
// allowing, e.g., order == binary.LittleEndian.
type unused byte
-var LittleEndian ByteOrder = littleEndian(0)
-var BigEndian ByteOrder = bigEndian(0)
+// 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
@@ -115,11 +118,11 @@ 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 integer
-// (int8, uint8, int16, uint16, ...) 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.
+// A fixed-size value is either a fixed-size arithmetic
+// type (int8, uint8, int16, float32, complex64, ...)
+// or an array or struct containing only fixed-size values.
+// Bytes read from r are decoded using the specified byte order
+// and written to successive fields of the data.
func Read(r io.Reader, order ByteOrder, data interface{}) os.Error {
var v reflect.Value
switch d := reflect.NewValue(data).(type) {
@@ -145,11 +148,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 integer
-// (int8, uint8, int16, uint16, ...) or an array or struct
-// containing only fixed-size values. Bytes written to
-// w are encoded using the specified byte order and read
-// from successive fields of the data.
+// A fixed-size value is either a fixed-size arithmetic
+// type (int8, uint8, int16, float32, complex64, ...)
+// or an array or struct containing only fixed-size values.
+// Bytes written to w are encoded using the specified byte order
+// and read from successive fields of the data.
func Write(w io.Writer, order ByteOrder, data interface{}) os.Error {
v := reflect.Indirect(reflect.NewValue(data))
size := TotalSize(v)
@@ -194,7 +197,11 @@ func sizeof(v reflect.Type) int {
}
return sum
- case *reflect.UintType, *reflect.IntType, *reflect.FloatType:
+ case *reflect.UintType, *reflect.IntType, *reflect.FloatType, *reflect.ComplexType:
+ switch t := t.Kind(); t {
+ case reflect.Int, reflect.Uint, reflect.Uintptr, reflect.Float, reflect.Complex:
+ return -1
+ }
return int(v.Size())
}
return -1
@@ -320,6 +327,20 @@ func (d *decoder) value(v reflect.Value) {
case reflect.Float64:
v.Set(math.Float64frombits(d.uint64()))
}
+
+ case *reflect.ComplexValue:
+ switch v.Type().Kind() {
+ case reflect.Complex64:
+ v.Set(cmplx(
+ float64(math.Float32frombits(d.uint32())),
+ float64(math.Float32frombits(d.uint32())),
+ ))
+ case reflect.Complex128:
+ v.Set(cmplx(
+ math.Float64frombits(d.uint64()),
+ math.Float64frombits(d.uint64()),
+ ))
+ }
}
}
@@ -372,5 +393,17 @@ func (e *encoder) value(v reflect.Value) {
case reflect.Float64:
e.uint64(math.Float64bits(v.Get()))
}
+
+ case *reflect.ComplexValue:
+ switch v.Type().Kind() {
+ case reflect.Complex64:
+ x := v.Get()
+ e.uint32(math.Float32bits(float32(real(x))))
+ e.uint32(math.Float32bits(float32(imag(x))))
+ case reflect.Complex128:
+ x := v.Get()
+ e.uint64(math.Float64bits(real(x)))
+ e.uint64(math.Float64bits(imag(x)))
+ }
}
}
diff --git a/src/pkg/encoding/binary/binary_test.go b/src/pkg/encoding/binary/binary_test.go
index 12d192d1e..c378413f1 100644
--- a/src/pkg/encoding/binary/binary_test.go
+++ b/src/pkg/encoding/binary/binary_test.go
@@ -13,16 +13,28 @@ import (
)
type Struct struct {
- Int8 int8
- Int16 int16
- Int32 int32
- Int64 int64
- Uint8 uint8
- Uint16 uint16
- Uint32 uint32
- Uint64 uint64
- Float64 float64
- Array [4]uint8
+ Int8 int8
+ Int16 int16
+ Int32 int32
+ Int64 int64
+ Uint8 uint8
+ Uint16 uint16
+ Uint32 uint32
+ Uint64 uint64
+ Float32 float32
+ Float64 float64
+ Complex64 complex64
+ Complex128 complex128
+ Array [4]uint8
+}
+
+type T struct {
+ Int int
+ Uint uint
+ Float float
+ Complex complex
+ Uintptr uintptr
+ Array [4]int
}
var s = Struct{
@@ -34,8 +46,19 @@ var s = Struct{
0x1112,
0x13141516,
0x1718191a1b1c1d1e,
- math.Float64frombits(0x1f20212223242526),
- [4]uint8{0x27, 0x28, 0x29, 0x2a},
+
+ math.Float32frombits(0x1f202122),
+ math.Float64frombits(0x232425262728292a),
+ cmplx(
+ math.Float32frombits(0x2b2c2d2e),
+ math.Float32frombits(0x2f303132),
+ ),
+ cmplx(
+ math.Float64frombits(0x333435363738393a),
+ math.Float64frombits(0x3b3c3d3e3f404142),
+ ),
+
+ [4]uint8{0x43, 0x44, 0x45, 0x46},
}
var big = []byte{
@@ -47,8 +70,13 @@ var big = []byte{
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,
+
+ 31, 32, 33, 34,
+ 35, 36, 37, 38, 39, 40, 41, 42,
+ 43, 44, 45, 46, 47, 48, 49, 50,
+ 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66,
+
+ 67, 68, 69, 70,
}
var little = []byte{
@@ -60,8 +88,13 @@ var little = []byte{
18, 17,
22, 21, 20, 19,
30, 29, 28, 27, 26, 25, 24, 23,
- 38, 37, 36, 35, 34, 33, 32, 31,
- 39, 40, 41, 42,
+
+ 34, 33, 32, 31,
+ 42, 41, 40, 39, 38, 37, 36, 35,
+ 46, 45, 44, 43, 50, 49, 48, 47,
+ 58, 57, 56, 55, 54, 53, 52, 51, 66, 65, 64, 63, 62, 61, 60, 59,
+
+ 67, 68, 69, 70,
}
var src = []byte{1, 2, 3, 4, 5, 6, 7, 8}
@@ -112,3 +145,20 @@ func TestWriteSlice(t *testing.T) {
err := Write(buf, BigEndian, res)
checkResult(t, "WriteSlice", BigEndian, err, buf.Bytes(), src)
}
+
+func TestWriteT(t *testing.T) {
+ buf := new(bytes.Buffer)
+ ts := T{}
+ err := Write(buf, BigEndian, ts)
+ if err == nil {
+ t.Errorf("WriteT: have nil, want non-nil")
+ }
+
+ tv := reflect.Indirect(reflect.NewValue(ts)).(*reflect.StructValue)
+ for i, n := 0, tv.NumField(); i < n; i++ {
+ err = Write(buf, BigEndian, tv.Field(i).Interface())
+ if err == nil {
+ t.Errorf("WriteT.%v: have nil, want non-nil", tv.Field(i).Type())
+ }
+ }
+}
diff --git a/src/pkg/encoding/git85/Makefile b/src/pkg/encoding/git85/Makefile
index 09dd96f32..fbd003454 100644
--- a/src/pkg/encoding/git85/Makefile
+++ b/src/pkg/encoding/git85/Makefile
@@ -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 ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=encoding/git85
GOFILES=\
diff --git a/src/pkg/encoding/git85/git_test.go b/src/pkg/encoding/git85/git_test.go
index a31f14d3c..c76385c35 100644
--- a/src/pkg/encoding/git85/git_test.go
+++ b/src/pkg/encoding/git85/git_test.go
@@ -17,7 +17,7 @@ type testpair struct {
func testEqual(t *testing.T, msg string, args ...interface{}) bool {
if args[len(args)-2] != args[len(args)-1] {
- t.Errorf(msg, args)
+ t.Errorf(msg, args...)
return false
}
return true
@@ -40,7 +40,7 @@ func TestGitTable(t *testing.T) {
var gitPairs = []testpair{
// Wikipedia example, adapted.
- testpair{
+ {
"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 " +
@@ -144,8 +144,8 @@ func TestDecodeCorrupt(t *testing.T) {
p int
}
examples := []corrupt{
- corrupt{"v", 0},
- corrupt{"!z!!!!!!!!!", 0},
+ {"v", 0},
+ {"!z!!!!!!!!!", 0},
}
for _, e := range examples {
diff --git a/src/pkg/encoding/hex/Makefile b/src/pkg/encoding/hex/Makefile
index d6849d9a5..22049f43b 100644
--- a/src/pkg/encoding/hex/Makefile
+++ b/src/pkg/encoding/hex/Makefile
@@ -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 ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=encoding/hex
GOFILES=\
diff --git a/src/pkg/encoding/hex/hex.go b/src/pkg/encoding/hex/hex.go
index 1c52885e2..292d917eb 100644
--- a/src/pkg/encoding/hex/hex.go
+++ b/src/pkg/encoding/hex/hex.go
@@ -71,7 +71,7 @@ func Decode(dst, src []byte) (int, os.Error) {
// fromHexChar converts a hex character into its value and a success flag.
func fromHexChar(c byte) (byte, bool) {
switch {
- case 0 <= c && c <= '9':
+ case '0' <= c && c <= '9':
return c - '0', true
case 'a' <= c && c <= 'f':
return c - 'a' + 10, true
diff --git a/src/pkg/encoding/hex/hex_test.go b/src/pkg/encoding/hex/hex_test.go
index d741e595a..a14c9d4f4 100644
--- a/src/pkg/encoding/hex/hex_test.go
+++ b/src/pkg/encoding/hex/hex_test.go
@@ -14,26 +14,26 @@ type encodeTest struct {
}
var encodeTests = []encodeTest{
- encodeTest{[]byte{}, []byte{}},
- encodeTest{[]byte{0x01}, []byte{'0', '1'}},
- encodeTest{[]byte{0xff}, []byte{'f', 'f'}},
- encodeTest{[]byte{0xff, 00}, []byte{'f', 'f', '0', '0'}},
- encodeTest{[]byte{0}, []byte{'0', '0'}},
- encodeTest{[]byte{1}, []byte{'0', '1'}},
- encodeTest{[]byte{2}, []byte{'0', '2'}},
- encodeTest{[]byte{3}, []byte{'0', '3'}},
- encodeTest{[]byte{4}, []byte{'0', '4'}},
- encodeTest{[]byte{5}, []byte{'0', '5'}},
- encodeTest{[]byte{6}, []byte{'0', '6'}},
- encodeTest{[]byte{7}, []byte{'0', '7'}},
- encodeTest{[]byte{8}, []byte{'0', '8'}},
- encodeTest{[]byte{9}, []byte{'0', '9'}},
- encodeTest{[]byte{10}, []byte{'0', 'a'}},
- encodeTest{[]byte{11}, []byte{'0', 'b'}},
- encodeTest{[]byte{12}, []byte{'0', 'c'}},
- encodeTest{[]byte{13}, []byte{'0', 'd'}},
- encodeTest{[]byte{14}, []byte{'0', 'e'}},
- encodeTest{[]byte{15}, []byte{'0', 'f'}},
+ {[]byte{}, []byte{}},
+ {[]byte{0x01}, []byte{'0', '1'}},
+ {[]byte{0xff}, []byte{'f', 'f'}},
+ {[]byte{0xff, 00}, []byte{'f', 'f', '0', '0'}},
+ {[]byte{0}, []byte{'0', '0'}},
+ {[]byte{1}, []byte{'0', '1'}},
+ {[]byte{2}, []byte{'0', '2'}},
+ {[]byte{3}, []byte{'0', '3'}},
+ {[]byte{4}, []byte{'0', '4'}},
+ {[]byte{5}, []byte{'0', '5'}},
+ {[]byte{6}, []byte{'0', '6'}},
+ {[]byte{7}, []byte{'0', '7'}},
+ {[]byte{8}, []byte{'0', '8'}},
+ {[]byte{9}, []byte{'0', '9'}},
+ {[]byte{10}, []byte{'0', 'a'}},
+ {[]byte{11}, []byte{'0', 'b'}},
+ {[]byte{12}, []byte{'0', 'c'}},
+ {[]byte{13}, []byte{'0', 'd'}},
+ {[]byte{14}, []byte{'0', 'e'}},
+ {[]byte{15}, []byte{'0', 'f'}},
}
func TestEncode(t *testing.T) {
@@ -55,31 +55,32 @@ type decodeTest struct {
}
var decodeTests = []decodeTest{
- decodeTest{[]byte{}, []byte{}, true},
- decodeTest{[]byte{'0'}, []byte{}, false},
- decodeTest{[]byte{'0', 'g'}, []byte{}, false},
- decodeTest{[]byte{'0', '0'}, []byte{0}, true},
- decodeTest{[]byte{'0', '1'}, []byte{1}, true},
- decodeTest{[]byte{'0', '2'}, []byte{2}, true},
- decodeTest{[]byte{'0', '3'}, []byte{3}, true},
- decodeTest{[]byte{'0', '4'}, []byte{4}, true},
- decodeTest{[]byte{'0', '5'}, []byte{5}, true},
- decodeTest{[]byte{'0', '6'}, []byte{6}, true},
- decodeTest{[]byte{'0', '7'}, []byte{7}, true},
- decodeTest{[]byte{'0', '8'}, []byte{8}, true},
- decodeTest{[]byte{'0', '9'}, []byte{9}, true},
- decodeTest{[]byte{'0', 'a'}, []byte{10}, true},
- decodeTest{[]byte{'0', 'b'}, []byte{11}, true},
- decodeTest{[]byte{'0', 'c'}, []byte{12}, true},
- decodeTest{[]byte{'0', 'd'}, []byte{13}, true},
- decodeTest{[]byte{'0', 'e'}, []byte{14}, true},
- decodeTest{[]byte{'0', 'f'}, []byte{15}, true},
- decodeTest{[]byte{'0', 'A'}, []byte{10}, true},
- decodeTest{[]byte{'0', 'B'}, []byte{11}, true},
- decodeTest{[]byte{'0', 'C'}, []byte{12}, true},
- decodeTest{[]byte{'0', 'D'}, []byte{13}, true},
- decodeTest{[]byte{'0', 'E'}, []byte{14}, true},
- decodeTest{[]byte{'0', 'F'}, []byte{15}, true},
+ {[]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) {
@@ -104,10 +105,10 @@ type encodeStringTest struct {
}
var encodeStringTests = []encodeStringTest{
- encodeStringTest{[]byte{}, ""},
- encodeStringTest{[]byte{0}, "00"},
- encodeStringTest{[]byte{0, 1}, "0001"},
- encodeStringTest{[]byte{0, 1, 255}, "0001ff"},
+ {[]byte{}, ""},
+ {[]byte{0}, "00"},
+ {[]byte{0, 1}, "0001"},
+ {[]byte{0, 1, 255}, "0001ff"},
}
func TestEncodeToString(t *testing.T) {
@@ -126,12 +127,13 @@ type decodeStringTest struct {
}
var decodeStringTests = []decodeStringTest{
- decodeStringTest{"", []byte{}, true},
- decodeStringTest{"0", []byte{}, false},
- decodeStringTest{"00", []byte{0}, true},
- decodeStringTest{"0g", []byte{}, false},
- decodeStringTest{"00ff00", []byte{0, 255, 0}, true},
- decodeStringTest{"0000ff", []byte{0, 0, 255}, true},
+ {"", []byte{}, true},
+ {"0", []byte{}, false},
+ {"00", []byte{0}, true},
+ {"0\x01", []byte{}, false},
+ {"0g", []byte{}, false},
+ {"00ff00", []byte{0, 255, 0}, true},
+ {"0000ff", []byte{0, 0, 255}, true},
}
func TestDecodeString(t *testing.T) {
diff --git a/src/pkg/encoding/line/Makefile b/src/pkg/encoding/line/Makefile
new file mode 100644
index 000000000..1af355c27
--- /dev/null
+++ b/src/pkg/encoding/line/Makefile
@@ -0,0 +1,11 @@
+# Copyright 2010 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=encoding/line
+GOFILES=\
+ line.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/encoding/line/line.go b/src/pkg/encoding/line/line.go
new file mode 100644
index 000000000..92dddcb99
--- /dev/null
+++ b/src/pkg/encoding/line/line.go
@@ -0,0 +1,95 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This package implements a Reader which handles reading \r and \r\n
+// deliminated lines.
+package line
+
+import (
+ "io"
+ "os"
+)
+
+// Reader reads lines from an io.Reader (which may use either '\n' or
+// '\r\n').
+type Reader struct {
+ buf []byte
+ consumed int
+ in io.Reader
+ err os.Error
+}
+
+func NewReader(in io.Reader, maxLineLength int) *Reader {
+ return &Reader{
+ buf: make([]byte, 0, maxLineLength),
+ consumed: 0,
+ in: in,
+ }
+}
+
+// ReadLine tries to return a single line, not including the end-of-line bytes.
+// If the line was found to be longer than the maximum length then isPrefix is
+// set and the beginning of the line is returned. The rest of the line will be
+// returned from future calls. isPrefix will be false when returning the last
+// fragment of the line. The returned buffer points into the internal state of
+// the Reader and is only valid until the next call to ReadLine. ReadLine
+// either returns a non-nil line or it returns an error, never both.
+func (l *Reader) ReadLine() (line []byte, isPrefix bool, err os.Error) {
+ if l.consumed > 0 {
+ n := copy(l.buf, l.buf[l.consumed:])
+ l.buf = l.buf[:n]
+ l.consumed = 0
+ }
+
+ if len(l.buf) == 0 && l.err != nil {
+ err = l.err
+ return
+ }
+
+ scannedTo := 0
+
+ for {
+ i := scannedTo
+ for ; i < len(l.buf); i++ {
+ if l.buf[i] == '\r' && len(l.buf) > i+1 && l.buf[i+1] == '\n' {
+ line = l.buf[:i]
+ l.consumed = i + 2
+ return
+ } else if l.buf[i] == '\n' {
+ line = l.buf[:i]
+ l.consumed = i + 1
+ return
+ }
+ }
+
+ if i == cap(l.buf) {
+ line = l.buf[:i]
+ l.consumed = i
+ isPrefix = true
+ return
+ }
+
+ if l.err != nil {
+ line = l.buf
+ l.consumed = i
+ return
+ }
+
+ // We don't want to rescan the input that we just scanned.
+ // However, we need to back up one byte because the last byte
+ // could have been a '\r' and we do need to rescan that.
+ scannedTo = i
+ if scannedTo > 0 {
+ scannedTo--
+ }
+ oldLen := len(l.buf)
+ l.buf = l.buf[:cap(l.buf)]
+ n, readErr := l.in.Read(l.buf[oldLen:])
+ l.buf = l.buf[:oldLen+n]
+ if readErr != nil {
+ l.err = readErr
+ }
+ }
+ panic("unreachable")
+}
diff --git a/src/pkg/encoding/line/line_test.go b/src/pkg/encoding/line/line_test.go
new file mode 100644
index 000000000..68d13b586
--- /dev/null
+++ b/src/pkg/encoding/line/line_test.go
@@ -0,0 +1,89 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package line
+
+import (
+ "bytes"
+ "os"
+ "testing"
+)
+
+var testOutput = []byte("0123456789abcdefghijklmnopqrstuvwxy")
+var testInput = []byte("012\n345\n678\n9ab\ncde\nfgh\nijk\nlmn\nopq\nrst\nuvw\nxy")
+var testInputrn = []byte("012\r\n345\r\n678\r\n9ab\r\ncde\r\nfgh\r\nijk\r\nlmn\r\nopq\r\nrst\r\nuvw\r\nxy\r\n\n\r\n")
+
+// TestReader wraps a []byte and returns reads of a specific length.
+type testReader struct {
+ data []byte
+ stride int
+}
+
+func (t *testReader) Read(buf []byte) (n int, err os.Error) {
+ n = t.stride
+ if n > len(t.data) {
+ n = len(t.data)
+ }
+ if n > len(buf) {
+ n = len(buf)
+ }
+ copy(buf, t.data)
+ t.data = t.data[n:]
+ if len(t.data) == 0 {
+ err = os.EOF
+ }
+ return
+}
+
+func testLineReader(t *testing.T, input []byte) {
+ for stride := 1; stride < len(input); stride++ {
+ done := 0
+ reader := testReader{input, stride}
+ l := NewReader(&reader, len(input)+1)
+ for {
+ line, isPrefix, err := l.ReadLine()
+ if len(line) > 0 && err != nil {
+ t.Errorf("ReadLine returned both data and error: %s", err)
+ }
+ if isPrefix {
+ t.Errorf("ReadLine returned prefix")
+ }
+ if err != nil {
+ if err != os.EOF {
+ t.Fatalf("Got unknown error: %s", err)
+ }
+ break
+ }
+ if want := testOutput[done : done+len(line)]; !bytes.Equal(want, line) {
+ t.Errorf("Bad line at stride %d: want: %x got: %x", stride, want, line)
+ }
+ done += len(line)
+ }
+ if done != len(testOutput) {
+ t.Error("ReadLine didn't return everything")
+ }
+ }
+}
+
+func TestReader(t *testing.T) {
+ testLineReader(t, testInput)
+ testLineReader(t, testInputrn)
+}
+
+func TestLineTooLong(t *testing.T) {
+ buf := bytes.NewBuffer([]byte("aaabbbcc\n"))
+ l := NewReader(buf, 3)
+ line, isPrefix, err := l.ReadLine()
+ if !isPrefix || !bytes.Equal(line, []byte("aaa")) || err != nil {
+ t.Errorf("bad result for first line: %x %s", line, err)
+ }
+ line, isPrefix, err = l.ReadLine()
+ if !isPrefix || !bytes.Equal(line, []byte("bbb")) || err != nil {
+ t.Errorf("bad result for second line: %x", line)
+ }
+ line, isPrefix, err = l.ReadLine()
+ if isPrefix || !bytes.Equal(line, []byte("cc")) || err != nil {
+ t.Errorf("bad result for third line: %x", line)
+ }
+}
diff --git a/src/pkg/encoding/pem/Makefile b/src/pkg/encoding/pem/Makefile
index 79490a57d..527670380 100644
--- a/src/pkg/encoding/pem/Makefile
+++ b/src/pkg/encoding/pem/Makefile
@@ -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 ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=encoding/pem
GOFILES=\
diff --git a/src/pkg/encoding/pem/pem.go b/src/pkg/encoding/pem/pem.go
index f39540756..5653aeb77 100644
--- a/src/pkg/encoding/pem/pem.go
+++ b/src/pkg/encoding/pem/pem.go
@@ -218,14 +218,13 @@ func Encode(out io.Writer, b *Block) (err os.Error) {
return
}
- for k, v := range b.Headers {
- _, err = out.Write([]byte(k + ": " + v + "\n"))
- if err != nil {
- return
+ if len(b.Headers) > 0 {
+ for k, v := range b.Headers {
+ _, err = out.Write([]byte(k + ": " + v + "\n"))
+ if err != nil {
+ return
+ }
}
- }
-
- if len(b.Headers) > 1 {
_, err = out.Write([]byte{'\n'})
if err != nil {
return
diff --git a/src/pkg/encoding/pem/pem_test.go b/src/pkg/encoding/pem/pem_test.go
index 42bd573d7..11efe5544 100644
--- a/src/pkg/encoding/pem/pem_test.go
+++ b/src/pkg/encoding/pem/pem_test.go
@@ -15,14 +15,14 @@ type GetLineTest struct {
}
var getLineTests = []GetLineTest{
- GetLineTest{"abc", "abc", ""},
- GetLineTest{"abc\r", "abc\r", ""},
- GetLineTest{"abc\n", "abc", ""},
- GetLineTest{"abc\r\n", "abc", ""},
- GetLineTest{"abc\nd", "abc", "d"},
- GetLineTest{"abc\r\nd", "abc", "d"},
- GetLineTest{"\nabc", "", "abc"},
- GetLineTest{"\r\nabc", "", "abc"},
+ {"abc", "abc", ""},
+ {"abc\r", "abc\r", ""},
+ {"abc\n", "abc", ""},
+ {"abc\r\n", "abc", ""},
+ {"abc\nd", "abc", "d"},
+ {"abc\r\nd", "abc", "d"},
+ {"\nabc", "", "abc"},
+ {"\r\nabc", "", "abc"},
}
func TestGetLine(t *testing.T) {
@@ -63,12 +63,12 @@ type lineBreakerTest struct {
const sixtyFourCharString = "0123456789012345678901234567890123456789012345678901234567890123"
var lineBreakerTests = []lineBreakerTest{
- lineBreakerTest{"", ""},
- lineBreakerTest{"a", "a\n"},
- lineBreakerTest{"ab", "ab\n"},
- lineBreakerTest{sixtyFourCharString, sixtyFourCharString + "\n"},
- lineBreakerTest{sixtyFourCharString + "X", sixtyFourCharString + "\nX\n"},
- lineBreakerTest{sixtyFourCharString + sixtyFourCharString, sixtyFourCharString + "\n" + sixtyFourCharString + "\n"},
+ {"", ""},
+ {"a", "a\n"},
+ {"ab", "ab\n"},
+ {sixtyFourCharString, sixtyFourCharString + "\n"},
+ {sixtyFourCharString + "X", sixtyFourCharString + "\nX\n"},
+ {sixtyFourCharString + sixtyFourCharString, sixtyFourCharString + "\n" + sixtyFourCharString + "\n"},
}
func TestLineBreaker(t *testing.T) {
diff --git a/src/pkg/exec/Makefile b/src/pkg/exec/Makefile
index 9d88b8d8a..262ecac85 100644
--- a/src/pkg/exec/Makefile
+++ b/src/pkg/exec/Makefile
@@ -2,10 +2,24 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=exec
GOFILES=\
exec.go\
+GOFILES_freebsd=\
+ lp_unix.go\
+
+GOFILES_darwin=\
+ lp_unix.go\
+
+GOFILES_linux=\
+ lp_unix.go\
+
+GOFILES_windows=\
+ lp_windows.go\
+
+GOFILES+=$(GOFILES_$(GOOS))
+
include ../../Make.pkg
diff --git a/src/pkg/exec/exec.go b/src/pkg/exec/exec.go
index ee3cec686..ba9bd2472 100644
--- a/src/pkg/exec/exec.go
+++ b/src/pkg/exec/exec.go
@@ -7,7 +7,6 @@ package exec
import (
"os"
- "strings"
)
// Arguments to Run.
@@ -39,7 +38,7 @@ func modeToFiles(mode, fd int) (*os.File, *os.File, os.Error) {
if fd == 0 {
rw = os.O_RDONLY
}
- f, err := os.Open("/dev/null", rw, 0)
+ f, err := os.Open(os.DevNull, rw, 0)
return f, nil, err
case PassThrough:
switch fd {
@@ -63,7 +62,7 @@ func modeToFiles(mode, fd int) (*os.File, *os.File, os.Error) {
return nil, nil, os.EINVAL
}
-// Run starts the binary prog running with
+// Run starts the named binary running with
// arguments argv and environment envv.
// It returns a pointer to a new Cmd representing
// the command or an error.
@@ -78,7 +77,7 @@ func modeToFiles(mode, fd int) (*os.File, *os.File, os.Error) {
// If a parameter is Pipe, then the corresponding field (Stdin, Stdout, Stderr)
// of the returned Cmd is the other end of the pipe.
// Otherwise the field in Cmd is nil.
-func Run(argv0 string, argv, envv []string, dir string, stdin, stdout, stderr int) (p *Cmd, err os.Error) {
+func Run(name string, argv, envv []string, dir string, stdin, stdout, stderr int) (p *Cmd, err os.Error) {
p = new(Cmd)
var fd [3]*os.File
@@ -95,7 +94,7 @@ func Run(argv0 string, argv, envv []string, dir string, stdin, stdout, stderr in
}
// Run command.
- p.Pid, err = os.ForkExec(argv0, argv, envv, dir, fd[0:])
+ p.Pid, err = os.ForkExec(name, argv, envv, dir, fd[0:])
if err != nil {
goto Error
}
@@ -182,40 +181,3 @@ func (p *Cmd) Close() os.Error {
}
return err
}
-
-func canExec(file string) bool {
- d, err := os.Stat(file)
- if err != nil {
- return false
- }
- return d.IsRegular() && d.Permission()&0111 != 0
-}
-
-// LookPath searches for an executable binary named file
-// in the directories named by the PATH environment variable.
-// If file contains a slash, it is tried directly and the PATH is not consulted.
-//
-// TODO(rsc): Does LookPath belong in os instead?
-func LookPath(file string) (string, os.Error) {
- // NOTE(rsc): I wish we could use the Plan 9 behavior here
- // (only bypass the path if file begins with / or ./ or ../)
- // but that would not match all the Unix shells.
-
- if strings.Index(file, "/") >= 0 {
- if canExec(file) {
- return file, nil
- }
- return "", os.ENOENT
- }
- pathenv := os.Getenv("PATH")
- for _, dir := range strings.Split(pathenv, ":", -1) {
- if dir == "" {
- // Unix shell semantics: path element "" means "."
- dir = "."
- }
- if canExec(dir + "/" + file) {
- return dir + "/" + file, nil
- }
- }
- return "", os.ENOENT
-}
diff --git a/src/pkg/exec/exec_test.go b/src/pkg/exec/exec_test.go
index 3e4ab7d78..3a3d3b1a5 100644
--- a/src/pkg/exec/exec_test.go
+++ b/src/pkg/exec/exec_test.go
@@ -8,11 +8,24 @@ import (
"io"
"io/ioutil"
"testing"
+ "os"
+ "runtime"
)
+func run(argv []string, stdin, stdout, stderr int) (p *Cmd, err os.Error) {
+ if runtime.GOOS == "windows" {
+ argv = append([]string{"cmd", "/c"}, argv...)
+ }
+ exe, err := LookPath(argv[0])
+ if err != nil {
+ return nil, err
+ }
+ p, err = Run(exe, argv, nil, "", stdin, stdout, stderr)
+ return p, err
+}
+
func TestRunCat(t *testing.T) {
- cmd, err := Run("/bin/cat", []string{"cat"}, nil, "",
- Pipe, Pipe, DevNull)
+ cmd, err := run([]string{"cat"}, Pipe, Pipe, DevNull)
if err != nil {
t.Fatal("run:", err)
}
@@ -31,7 +44,7 @@ func TestRunCat(t *testing.T) {
}
func TestRunEcho(t *testing.T) {
- cmd, err := Run("/bin/echo", []string{"echo", "hello", "world"}, nil, "",
+ cmd, err := run([]string{"sh", "-c", "echo hello world"},
DevNull, Pipe, DevNull)
if err != nil {
t.Fatal("run:", err)
@@ -49,7 +62,7 @@ func TestRunEcho(t *testing.T) {
}
func TestStderr(t *testing.T) {
- cmd, err := Run("/bin/sh", []string{"sh", "-c", "echo hello world 1>&2"}, nil, "",
+ cmd, err := run([]string{"sh", "-c", "echo hello world 1>&2"},
DevNull, DevNull, Pipe)
if err != nil {
t.Fatal("run:", err)
@@ -66,9 +79,8 @@ func TestStderr(t *testing.T) {
}
}
-
func TestMergeWithStdout(t *testing.T) {
- cmd, err := Run("/bin/sh", []string{"sh", "-c", "echo hello world 1>&2"}, nil, "",
+ cmd, err := run([]string{"sh", "-c", "echo hello world 1>&2"},
DevNull, Pipe, MergeWithStdout)
if err != nil {
t.Fatal("run:", err)
@@ -84,3 +96,25 @@ func TestMergeWithStdout(t *testing.T) {
t.Fatal("close:", err)
}
}
+
+func TestAddEnvVar(t *testing.T) {
+ err := os.Setenv("NEWVAR", "hello world")
+ if err != nil {
+ t.Fatal("setenv:", err)
+ }
+ cmd, err := run([]string{"sh", "-c", "echo $NEWVAR"},
+ DevNull, Pipe, DevNull)
+ if err != nil {
+ t.Fatal("run:", err)
+ }
+ buf, err := ioutil.ReadAll(cmd.Stdout)
+ if err != nil {
+ t.Fatal("read:", err)
+ }
+ if string(buf) != "hello world\n" {
+ t.Fatalf("read: got %q", buf)
+ }
+ if err = cmd.Close(); err != nil {
+ t.Fatal("close:", err)
+ }
+}
diff --git a/src/pkg/exec/lp_unix.go b/src/pkg/exec/lp_unix.go
new file mode 100644
index 000000000..292e24fcc
--- /dev/null
+++ b/src/pkg/exec/lp_unix.go
@@ -0,0 +1,45 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package exec
+
+import (
+ "os"
+ "strings"
+)
+
+func canExec(file string) bool {
+ d, err := os.Stat(file)
+ if err != nil {
+ return false
+ }
+ return d.IsRegular() && d.Permission()&0111 != 0
+}
+
+// LookPath searches for an executable binary named file
+// in the directories named by the PATH environment variable.
+// If file contains a slash, it is tried directly and the PATH is not consulted.
+func LookPath(file string) (string, os.Error) {
+ // NOTE(rsc): I wish we could use the Plan 9 behavior here
+ // (only bypass the path if file begins with / or ./ or ../)
+ // but that would not match all the Unix shells.
+
+ if strings.Contains(file, "/") {
+ if canExec(file) {
+ return file, nil
+ }
+ return "", &os.PathError{"lookpath", file, os.ENOENT}
+ }
+ pathenv := os.Getenv("PATH")
+ for _, dir := range strings.Split(pathenv, ":", -1) {
+ if dir == "" {
+ // Unix shell semantics: path element "" means "."
+ dir = "."
+ }
+ if canExec(dir + "/" + file) {
+ return dir + "/" + file, nil
+ }
+ }
+ return "", &os.PathError{"lookpath", file, os.ENOENT}
+}
diff --git a/src/pkg/exec/lp_windows.go b/src/pkg/exec/lp_windows.go
new file mode 100644
index 000000000..7b56afa85
--- /dev/null
+++ b/src/pkg/exec/lp_windows.go
@@ -0,0 +1,66 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package exec
+
+import (
+ "os"
+ "strings"
+)
+
+func chkStat(file string) bool {
+ d, err := os.Stat(file)
+ if err != nil {
+ return false
+ }
+ return d.IsRegular()
+}
+
+func canExec(file string, exts []string) (string, bool) {
+ if len(exts) == 0 {
+ return file, chkStat(file)
+ }
+ f := strings.ToLower(file)
+ for _, e := range exts {
+ if strings.HasSuffix(f, e) {
+ return file, chkStat(file)
+ }
+ }
+ for _, e := range exts {
+ if f := file + e; chkStat(f) {
+ return f, true
+ }
+ }
+ return ``, false
+}
+
+func LookPath(file string) (string, os.Error) {
+ exts := []string{}
+ if x := os.Getenv(`PATHEXT`); x != `` {
+ exts = strings.Split(strings.ToLower(x), `;`, -1)
+ for i, e := range exts {
+ if e == `` || e[0] != '.' {
+ exts[i] = `.` + e
+ }
+ }
+ }
+ if strings.Contains(file, `\`) || strings.Contains(file, `/`) {
+ if f, ok := canExec(file, exts); ok {
+ return f, nil
+ }
+ return ``, &os.PathError{"lookpath", file, os.ENOENT}
+ }
+ if pathenv := os.Getenv(`PATH`); pathenv == `` {
+ if f, ok := canExec(`.\`+file, exts); ok {
+ return f, nil
+ }
+ } else {
+ for _, dir := range strings.Split(pathenv, `;`, -1) {
+ if f, ok := canExec(dir+`\`+file, exts); ok {
+ return f, nil
+ }
+ }
+ }
+ return ``, &os.PathError{"lookpath", file, os.ENOENT}
+}
diff --git a/src/pkg/exp/4s/4s.go b/src/pkg/exp/4s/4s.go
deleted file mode 100644
index 271af78e2..000000000
--- a/src/pkg/exp/4s/4s.go
+++ /dev/null
@@ -1,79 +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 is a simple demo of Go running under Native Client.
-// It is a tetris clone built on top of the exp/nacl/av and exp/draw
-// packages.
-//
-// See ../nacl/README for how to run it.
-package main
-
-import (
- "exp/nacl/av"
- "exp/nacl/srpc"
- "log"
- "runtime"
- "os"
-)
-
-var sndc chan []uint16
-
-func main() {
- // Native Client requires that some calls are issued
- // consistently by the same OS thread.
- runtime.LockOSThread()
-
- if srpc.Enabled() {
- go srpc.ServeRuntime()
- }
-
- args := os.Args
- p := pieces4
- if len(args) > 1 && args[1] == "-5" {
- p = pieces5
- }
- dx, dy := 500, 500
- w, err := av.Init(av.SubsystemVideo|av.SubsystemAudio, dx, dy)
- if err != nil {
- log.Exit(err)
- }
-
- sndc = make(chan []uint16, 10)
- go audioServer()
- Play(p, w)
-}
-
-func audioServer() {
- // Native Client requires that all audio calls
- // original from a single OS thread.
- runtime.LockOSThread()
-
- n, err := av.AudioStream(nil)
- if err != nil {
- log.Exit(err)
- }
- for {
- b := <-sndc
- for len(b)*2 >= n {
- var a []uint16
- a, b = b[0:n/2], b[n/2:]
- n, err = av.AudioStream(a)
- if err != nil {
- log.Exit(err)
- }
- println(n, len(b)*2)
- }
- a := make([]uint16, n/2)
- for i := range b {
- a[i] = b[i]
- }
- n, err = av.AudioStream(a)
- }
-}
-
-func PlaySound(b []uint16) { sndc <- b }
-
-var whoosh = []uint16{
-// Insert your favorite sound samples here.
-}
diff --git a/src/pkg/exp/4s/4s.html b/src/pkg/exp/4s/4s.html
deleted file mode 100644
index 924f8b118..000000000
--- a/src/pkg/exp/4s/4s.html
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-<h1>games/4s</h1>
-<table><tr><td valign=top>
-<embed name="nacl_module" id="pluginobj" src="8.out" type="application/x-nacl-srpc" width=400 height=600>
-<td valign=top>
-This is a simple block stacking game, a port of Plan 9's
-<a href="http://plan9.bell-labs.com/magic/man2html/1/games">games/4s</a>
-<br><br>
-To play using the keyboard:
-as the blocks fall, the <i>a</i>, <i>s</i>, <i>d</i>, and <i>f</i> keys
-move the block left, rotate the block left, rotate the block right,
-anad move the block right, respectively.
-To drop a block, type the space key.
-<b>You may need to click on the game window to
-focus the keyboard on it.</b>
-<br><br>
-To play using the mouse:
-as the blocks fall, moving the mouse horizontally positions
-the block; left or right clicks rotate the block left or right.
-A middle click drops the block.
-(Unfortunately, some environments seem to intercept
-the middle click before it gets to Native Client.)
-<br><br>
-To pause the game, type <i>z</i>, <i>p</i>, or the escape key.
-</table>
diff --git a/src/pkg/exp/4s/5s.go b/src/pkg/exp/4s/5s.go
deleted file mode 100644
index efeb6f116..000000000
--- a/src/pkg/exp/4s/5s.go
+++ /dev/null
@@ -1,9 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Hack to produce a binary that defaults to 5s.
-
-package main
-
-func init() { pieces4 = pieces5 }
diff --git a/src/pkg/exp/4s/5s.html b/src/pkg/exp/4s/5s.html
deleted file mode 100644
index 5fa110753..000000000
--- a/src/pkg/exp/4s/5s.html
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-<h1>games/5s</h1>
-<table><tr><td valign=top>
-<embed name="nacl_module" id="pluginobj" src="8.5s" type="application/x-nacl-srpc" width=400 height=600>
-<td valign=top>
-This is a simple block stacking game, a port of Plan 9's
-<a href="http://plan9.bell-labs.com/magic/man2html/1/games">games/5s</a>
-<br><br>
-To play using the keyboard:
-as the blocks fall, the <i>a</i>, <i>s</i>, <i>d</i>, and <i>f</i> keys
-move the block left, rotate the block left, rotate the block right,
-anad move the block right, respectively.
-To drop a block, type the space key.
-<b>You may need to click on the game window to
-focus the keyboard on it.</b>
-<br><br>
-To play using the mouse:
-as the blocks fall, moving the mouse horizontally positions
-the block; left or right clicks rotate the block left or right.
-A middle click drops the block.
-(Unfortunately, some environments seem to intercept
-the middle click before it gets to Native Client.)
-<br><br>
-To pause the game, type <i>z</i>, <i>p</i>, or the escape key.
-</table>
diff --git a/src/pkg/exp/4s/Makefile b/src/pkg/exp/4s/Makefile
deleted file mode 100644
index 8ad390591..000000000
--- a/src/pkg/exp/4s/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.
-
-all: 8.out 8.5s
-
-4s.8: 4s.go data.go xs.go
- 8g 4s.go data.go xs.go
-
-5s.8: 5s.go 4s.go data.go xs.go
- 8g 5s.go 4s.go data.go xs.go
-
-8.out: 4s.8
- 8l 4s.8
-
-8.5s: 5s.8
- 8l -o 8.5s 5s.8
-
-clean:
- rm -f *.8 8.out
diff --git a/src/pkg/exp/4s/data.go b/src/pkg/exp/4s/data.go
deleted file mode 100644
index ac30fabf7..000000000
--- a/src/pkg/exp/4s/data.go
+++ /dev/null
@@ -1,142 +0,0 @@
-// games/4s - a tetris clone
-//
-// Derived from Plan 9's /sys/src/games/xs.c
-// http://plan9.bell-labs.com/sources/plan9/sys/src/games/xs.c
-//
-// Copyright (C) 2003, Lucent Technologies Inc. and others. All Rights Reserved.
-// Portions Copyright 2009 The Go Authors. All Rights Reserved.
-// Distributed under the terms of the Lucent Public License Version 1.02
-// See http://plan9.bell-labs.com/plan9/license.html
-
-package main
-
-import . "exp/draw"
-
-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},
-
- Piece{0, 3, Point{2, 2}, []Point{Point{0, 1}, Point{1, 0}, Point{0, -1}, Point{-1, 0}}, nil, nil},
- Piece{1, 3, Point{2, 2}, []Point{Point{0, 1}, Point{1, 0}, Point{0, -1}, Point{-1, 0}}, nil, nil},
- Piece{2, 3, Point{2, 2}, []Point{Point{0, 1}, Point{1, 0}, Point{0, -1}, Point{-1, 0}}, nil, nil},
- Piece{3, 3, Point{2, 2}, []Point{Point{0, 1}, Point{1, 0}, Point{0, -1}, Point{-1, 0}}, nil, nil},
-
- Piece{0, 1, Point{3, 2}, []Point{Point{0, 0}, Point{1, 0}, Point{1, 0}, Point{0, 1}}, nil, nil},
- Piece{1, 1, Point{2, 3}, []Point{Point{1, 0}, Point{0, 1}, Point{0, 1}, Point{-1, 0}}, nil, nil},
- Piece{2, 1, Point{3, 2}, []Point{Point{0, 0}, Point{0, 1}, Point{1, 0}, Point{1, 0}}, nil, nil},
- Piece{3, 1, Point{2, 3}, []Point{Point{0, 0}, Point{1, 0}, Point{-1, 1}, Point{0, 1}}, nil, nil},
-
- Piece{0, 2, Point{3, 2}, []Point{Point{0, 1}, Point{1, 0}, Point{1, 0}, Point{0, -1}}, nil, nil},
- Piece{1, 2, Point{2, 3}, []Point{Point{0, 0}, Point{0, 1}, Point{0, 1}, Point{1, 0}}, nil, nil},
- Piece{2, 2, Point{3, 2}, []Point{Point{0, 0}, Point{1, 0}, Point{1, 0}, Point{-2, 1}}, nil, nil},
- Piece{3, 2, Point{2, 3}, []Point{Point{0, 0}, Point{1, 0}, Point{0, 1}, Point{0, 1}}, nil, nil},
-
- Piece{0, 4, Point{3, 2}, []Point{Point{0, 0}, Point{1, 0}, Point{1, 0}, Point{-1, 1}}, nil, nil},
- Piece{1, 4, Point{2, 3}, []Point{Point{1, 0}, Point{-1, 1}, Point{1, 0}, Point{0, 1}}, nil, nil},
- Piece{2, 4, Point{3, 2}, []Point{Point{1, 0}, Point{-1, 1}, Point{1, 0}, Point{1, 0}}, nil, nil},
- Piece{3, 4, Point{2, 3}, []Point{Point{0, 0}, Point{0, 1}, Point{0, 1}, Point{1, -1}}, nil, nil},
-
- Piece{0, 5, Point{3, 2}, []Point{Point{0, 0}, Point{1, 0}, Point{0, 1}, Point{1, 0}}, nil, nil},
- Piece{1, 5, Point{2, 3}, []Point{Point{1, 0}, Point{0, 1}, Point{-1, 0}, Point{0, 1}}, nil, nil},
- Piece{2, 5, Point{3, 2}, []Point{Point{0, 0}, Point{1, 0}, Point{0, 1}, Point{1, 0}}, nil, nil},
- Piece{3, 5, Point{2, 3}, []Point{Point{1, 0}, Point{0, 1}, Point{-1, 0}, Point{0, 1}}, nil, nil},
-
- Piece{0, 6, Point{3, 2}, []Point{Point{0, 1}, Point{1, 0}, Point{0, -1}, Point{1, 0}}, nil, nil},
- Piece{1, 6, Point{2, 3}, []Point{Point{0, 0}, Point{0, 1}, Point{1, 0}, Point{0, 1}}, nil, nil},
- Piece{2, 6, Point{3, 2}, []Point{Point{0, 1}, Point{1, 0}, Point{0, -1}, Point{1, 0}}, nil, nil},
- Piece{3, 6, Point{2, 3}, []Point{Point{0, 0}, Point{0, 1}, Point{1, 0}, Point{0, 1}}, nil, nil},
-}
-
-var pieces5 = []Piece{
- Piece{0, 1, Point{5, 1}, []Point{Point{0, 0}, Point{1, 0}, Point{1, 0}, Point{1, 0}, Point{1, 0}}, nil, nil},
- Piece{1, 1, Point{1, 5}, []Point{Point{0, 0}, Point{0, 1}, Point{0, 1}, Point{0, 1}, Point{0, 1}}, nil, nil},
- Piece{2, 1, Point{5, 1}, []Point{Point{0, 0}, Point{1, 0}, Point{1, 0}, Point{1, 0}, Point{1, 0}}, nil, nil},
- Piece{3, 1, Point{1, 5}, []Point{Point{0, 0}, Point{0, 1}, Point{0, 1}, Point{0, 1}, Point{0, 1}}, nil, nil},
-
- Piece{0, 0, Point{4, 2}, []Point{Point{0, 0}, Point{1, 0}, Point{1, 0}, Point{1, 0}, Point{0, 1}}, nil, nil},
- Piece{1, 0, Point{2, 4}, []Point{Point{1, 0}, Point{0, 1}, Point{0, 1}, Point{0, 1}, Point{-1, 0}}, nil, nil},
- Piece{2, 0, Point{4, 2}, []Point{Point{0, 0}, Point{0, 1}, Point{1, 0}, Point{1, 0}, Point{1, 0}}, nil, nil},
- Piece{3, 0, Point{2, 4}, []Point{Point{0, 0}, Point{1, 0}, Point{-1, 1}, Point{0, 1}, Point{0, 1}}, nil, nil},
-
- Piece{0, 2, Point{4, 2}, []Point{Point{0, 0}, Point{0, 1}, Point{1, -1}, Point{1, 0}, Point{1, 0}}, nil, nil},
- Piece{1, 2, Point{2, 4}, []Point{Point{0, 0}, Point{1, 0}, Point{0, 1}, Point{0, 1}, Point{0, 1}}, nil, nil},
- Piece{2, 2, Point{4, 2}, []Point{Point{0, 1}, Point{1, 0}, Point{1, 0}, Point{1, 0}, Point{0, -1}}, nil, nil},
- Piece{3, 2, Point{2, 4}, []Point{Point{0, 0}, Point{0, 1}, Point{0, 1}, Point{0, 1}, Point{1, 0}}, nil, nil},
-
- Piece{0, 7, Point{3, 3}, []Point{Point{0, 0}, Point{1, 0}, Point{1, 0}, Point{0, 1}, Point{0, 1}}, nil, nil},
- Piece{1, 7, Point{3, 3}, []Point{Point{0, 2}, Point{1, 0}, Point{1, 0}, Point{0, -1}, Point{0, -1}}, nil, nil},
- Piece{2, 7, Point{3, 3}, []Point{Point{0, 0}, Point{0, 1}, Point{0, 1}, Point{1, 0}, Point{1, 0}}, nil, nil},
- Piece{3, 7, Point{3, 3}, []Point{Point{0, 2}, Point{0, -1}, Point{0, -1}, Point{1, 0}, Point{1, 0}}, nil, nil},
-
- Piece{0, 3, Point{3, 2}, []Point{Point{0, 0}, Point{1, 0}, Point{1, 0}, Point{-2, 1}, Point{1, 0}}, nil, nil},
- Piece{1, 3, Point{2, 3}, []Point{Point{0, 0}, Point{1, 0}, Point{-1, 1}, Point{1, 0}, Point{0, 1}}, nil, nil},
- Piece{2, 3, Point{3, 2}, []Point{Point{1, 0}, Point{1, 0}, Point{-2, 1}, Point{1, 0}, Point{1, 0}}, nil, nil},
- Piece{3, 3, Point{2, 3}, []Point{Point{0, 0}, Point{0, 1}, Point{1, 0}, Point{-1, 1}, Point{1, 0}}, nil, nil},
-
- Piece{0, 4, Point{3, 2}, []Point{Point{0, 0}, Point{1, 0}, Point{1, 0}, Point{-1, 1}, Point{1, 0}}, nil, nil},
- Piece{1, 4, Point{2, 3}, []Point{Point{1, 0}, Point{-1, 1}, Point{1, 0}, Point{-1, 1}, Point{1, 0}}, nil, nil},
- Piece{2, 4, Point{3, 2}, []Point{Point{0, 0}, Point{1, 0}, Point{-1, 1}, Point{1, 0}, Point{1, 0}}, nil, nil},
- Piece{3, 4, Point{2, 3}, []Point{Point{0, 0}, Point{1, 0}, Point{-1, 1}, Point{1, 0}, Point{-1, 1}}, nil, nil},
-
- Piece{0, 7, Point{3, 2}, []Point{Point{0, 0}, Point{2, 0}, Point{-2, 1}, Point{1, 0}, Point{1, 0}}, nil, nil},
- Piece{1, 7, Point{2, 3}, []Point{Point{0, 0}, Point{1, 0}, Point{-1, 1}, Point{0, 1}, Point{1, 0}}, nil, nil},
- Piece{2, 7, Point{3, 2}, []Point{Point{0, 0}, Point{1, 0}, Point{1, 0}, Point{-2, 1}, Point{2, 0}}, nil, nil},
- Piece{3, 7, Point{2, 3}, []Point{Point{0, 0}, Point{1, 0}, Point{0, 1}, Point{-1, 1}, Point{1, 0}}, nil, nil},
-
- Piece{0, 5, Point{3, 3}, []Point{Point{0, 0}, Point{1, 0}, Point{0, 1}, Point{1, 0}, Point{-1, 1}}, nil, nil},
- Piece{1, 5, Point{3, 3}, []Point{Point{2, 0}, Point{-2, 1}, Point{1, 0}, Point{1, 0}, Point{-1, 1}}, nil, nil},
- Piece{2, 5, Point{3, 3}, []Point{Point{1, 0}, Point{-1, 1}, Point{1, 0}, Point{0, 1}, Point{1, 0}}, nil, nil},
- Piece{3, 5, Point{3, 3}, []Point{Point{1, 0}, Point{-1, 1}, Point{1, 0}, Point{1, 0}, Point{-2, 1}}, nil, nil},
-
- Piece{0, 6, Point{3, 3}, []Point{Point{1, 0}, Point{1, 0}, Point{-2, 1}, Point{1, 0}, Point{0, 1}}, nil, nil},
- Piece{1, 6, Point{3, 3}, []Point{Point{1, 0}, Point{-1, 1}, Point{1, 0}, Point{1, 0}, Point{0, 1}}, nil, nil},
- Piece{2, 6, Point{3, 3}, []Point{Point{1, 0}, Point{0, 1}, Point{1, 0}, Point{-2, 1}, Point{1, 0}}, nil, nil},
- Piece{3, 6, Point{3, 3}, []Point{Point{0, 0}, Point{0, 1}, Point{1, 0}, Point{1, 0}, Point{-1, 1}}, nil, nil},
-
- Piece{0, 0, Point{4, 2}, []Point{Point{0, 0}, Point{1, 0}, Point{1, 0}, Point{1, 0}, Point{-2, 1}}, nil, nil},
- Piece{1, 0, Point{2, 4}, []Point{Point{1, 0}, Point{-1, 1}, Point{1, 0}, Point{0, 1}, Point{0, 1}}, nil, nil},
- Piece{2, 0, Point{4, 2}, []Point{Point{2, 0}, Point{-2, 1}, Point{1, 0}, Point{1, 0}, Point{1, 0}}, nil, nil},
- Piece{3, 0, Point{2, 4}, []Point{Point{0, 0}, Point{0, 1}, Point{0, 1}, Point{1, 0}, Point{-1, 1}}, nil, nil},
-
- Piece{0, 2, Point{4, 2}, []Point{Point{0, 0}, Point{1, 0}, Point{1, 0}, Point{1, 0}, Point{-1, 1}}, nil, nil},
- Piece{1, 2, Point{2, 4}, []Point{Point{1, 0}, Point{0, 1}, Point{-1, 1}, Point{1, 0}, Point{0, 1}}, nil, nil},
- Piece{2, 2, Point{4, 2}, []Point{Point{1, 0}, Point{-1, 1}, Point{1, 0}, Point{1, 0}, Point{1, 0}}, nil, nil},
- Piece{3, 2, Point{2, 4}, []Point{Point{0, 0}, Point{0, 1}, Point{1, 0}, Point{-1, 1}, Point{0, 1}}, nil, nil},
-
- Piece{0, 1, Point{3, 3}, []Point{Point{0, 0}, Point{1, 0}, Point{0, 1}, Point{1, 0}, Point{0, 1}}, nil, nil},
- Piece{1, 1, Point{3, 3}, []Point{Point{2, 0}, Point{-1, 1}, Point{1, 0}, Point{-2, 1}, Point{1, 0}}, nil, nil},
- Piece{2, 1, Point{3, 3}, []Point{Point{0, 0}, Point{0, 1}, Point{1, 0}, Point{0, 1}, Point{1, 0}}, nil, nil},
- Piece{3, 1, Point{3, 3}, []Point{Point{1, 0}, Point{1, 0}, Point{-2, 1}, Point{1, 0}, Point{-1, 1}}, nil, nil},
-
- Piece{0, 3, Point{3, 3}, []Point{Point{0, 0}, Point{1, 0}, Point{1, 0}, Point{-1, 1}, Point{0, 1}}, nil, nil},
- Piece{1, 3, Point{3, 3}, []Point{Point{2, 0}, Point{-2, 1}, Point{1, 0}, Point{1, 0}, Point{0, 1}}, nil, nil},
- Piece{2, 3, Point{3, 3}, []Point{Point{1, 0}, Point{0, 1}, Point{-1, 1}, Point{1, 0}, Point{1, 0}}, nil, nil},
- Piece{3, 3, Point{3, 3}, []Point{Point{0, 0}, Point{0, 1}, Point{1, 0}, Point{1, 0}, Point{-2, 1}}, nil, nil},
-
- Piece{0, 4, Point{3, 3}, []Point{Point{1, 0}, Point{-1, 1}, Point{1, 0}, Point{1, 0}, Point{-1, 1}}, nil, nil},
- Piece{1, 4, Point{3, 3}, []Point{Point{1, 0}, Point{-1, 1}, Point{1, 0}, Point{1, 0}, Point{-1, 1}}, nil, nil},
- Piece{2, 4, Point{3, 3}, []Point{Point{1, 0}, Point{-1, 1}, Point{1, 0}, Point{1, 0}, Point{-1, 1}}, nil, nil},
- Piece{3, 4, Point{3, 3}, []Point{Point{1, 0}, Point{-1, 1}, Point{1, 0}, Point{1, 0}, Point{-1, 1}}, nil, nil},
-
- Piece{0, 8, Point{4, 2}, []Point{Point{0, 0}, Point{1, 0}, Point{0, 1}, Point{1, 0}, Point{1, 0}}, nil, nil},
- Piece{1, 8, Point{2, 4}, []Point{Point{1, 0}, Point{-1, 1}, Point{1, 0}, Point{-1, 1}, Point{0, 1}}, nil, nil},
- Piece{2, 8, Point{4, 2}, []Point{Point{0, 0}, Point{1, 0}, Point{1, 0}, Point{0, 1}, Point{1, 0}}, nil, nil},
- Piece{3, 8, Point{2, 4}, []Point{Point{1, 0}, Point{0, 1}, Point{-1, 1}, Point{1, 0}, Point{-1, 1}}, nil, nil},
-
- Piece{0, 9, Point{4, 2}, []Point{Point{2, 0}, Point{1, 0}, Point{-3, 1}, Point{1, 0}, Point{1, 0}}, nil, nil},
- Piece{1, 9, Point{2, 4}, []Point{Point{0, 0}, Point{0, 1}, Point{0, 1}, Point{1, 0}, Point{0, 1}}, nil, nil},
- Piece{2, 9, Point{4, 2}, []Point{Point{1, 0}, Point{1, 0}, Point{1, 0}, Point{-3, 1}, Point{1, 0}}, nil, nil},
- Piece{3, 9, Point{2, 4}, []Point{Point{0, 0}, Point{0, 1}, Point{1, 0}, Point{0, 1}, Point{0, 1}}, nil, nil},
-
- Piece{0, 5, Point{3, 3}, []Point{Point{0, 0}, Point{0, 1}, Point{1, 0}, Point{1, 0}, Point{0, 1}}, nil, nil},
- Piece{1, 5, Point{3, 3}, []Point{Point{1, 0}, Point{1, 0}, Point{-1, 1}, Point{-1, 1}, Point{1, 0}}, nil, nil},
- Piece{2, 5, Point{3, 3}, []Point{Point{0, 0}, Point{0, 1}, Point{1, 0}, Point{1, 0}, Point{0, 1}}, nil, nil},
- Piece{3, 5, Point{3, 3}, []Point{Point{1, 0}, Point{1, 0}, Point{-1, 1}, Point{-1, 1}, Point{1, 0}}, nil, nil},
-
- Piece{0, 6, Point{3, 3}, []Point{Point{2, 0}, Point{-2, 1}, Point{1, 0}, Point{1, 0}, Point{-2, 1}}, nil, nil},
- Piece{1, 6, Point{3, 3}, []Point{Point{0, 0}, Point{1, 0}, Point{0, 1}, Point{0, 1}, Point{1, 0}}, nil, nil},
- Piece{2, 6, Point{3, 3}, []Point{Point{2, 0}, Point{-2, 1}, Point{1, 0}, Point{1, 0}, Point{-2, 1}}, nil, nil},
- Piece{3, 6, Point{3, 3}, []Point{Point{0, 0}, Point{1, 0}, Point{0, 1}, Point{0, 1}, Point{1, 0}}, nil, nil},
-}
diff --git a/src/pkg/exp/4s/xs.go b/src/pkg/exp/4s/xs.go
deleted file mode 100644
index c5493e719..000000000
--- a/src/pkg/exp/4s/xs.go
+++ /dev/null
@@ -1,742 +0,0 @@
-// games/4s - a tetris clone
-//
-// Derived from Plan 9's /sys/src/games/xs.c
-// http://plan9.bell-labs.com/sources/plan9/sys/src/games/xs.c
-//
-// Copyright (C) 2003, Lucent Technologies Inc. and others. All Rights Reserved.
-// Portions Copyright 2009 The Go Authors. All Rights Reserved.
-// Distributed under the terms of the Lucent Public License Version 1.02
-// See http://plan9.bell-labs.com/plan9/license.html
-
-/*
- * engine for 4s, 5s, etc
- */
-
-package main
-
-import (
- "exp/draw"
- "image"
- "log"
- "os"
- "rand"
- "time"
-)
-
-/*
-Cursor whitearrow = {
- {0, 0},
- {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFC,
- 0xFF, 0xF0, 0xFF, 0xF0, 0xFF, 0xF8, 0xFF, 0xFC,
- 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFC,
- 0xF3, 0xF8, 0xF1, 0xF0, 0xE0, 0xE0, 0xC0, 0x40, },
- {0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x06, 0xC0, 0x1C,
- 0xC0, 0x30, 0xC0, 0x30, 0xC0, 0x38, 0xC0, 0x1C,
- 0xC0, 0x0E, 0xC0, 0x07, 0xCE, 0x0E, 0xDF, 0x1C,
- 0xD3, 0xB8, 0xF1, 0xF0, 0xE0, 0xE0, 0xC0, 0x40, }
-};
-*/
-
-const (
- CNone = 0
- CBounds = 1
- CPiece = 2
- NX = 10
- NY = 20
-
- NCOL = 10
-
- MAXN = 5
-)
-
-var (
- N int
- display draw.Context
- screen draw.Image
- screenr draw.Rectangle
- board [NY][NX]byte
- rboard draw.Rectangle
- pscore draw.Point
- scoresz draw.Point
- pcsz = 32
- pos draw.Point
- bbr, bb2r draw.Rectangle
- bb, bbmask, bb2, bb2mask *image.RGBA
- whitemask image.Image
- br, br2 draw.Rectangle
- points int
- dt int
- DY int
- DMOUSE int
- lastmx int
- mouse draw.Mouse
- newscreen bool
- timerc <-chan int64
- suspc chan bool
- mousec chan draw.Mouse
- resizec <-chan bool
- kbdc chan int
- suspended bool
- tsleep int
- piece *Piece
- pieces []Piece
-)
-
-type Piece struct {
- rot int
- tx int
- sz draw.Point
- d []draw.Point
- left *Piece
- right *Piece
-}
-
-var txbits = [NCOL][32]byte{
- [32]byte{0xDD, 0xDD, 0xFF, 0xFF, 0x77, 0x77, 0xFF, 0xFF,
- 0xDD, 0xDD, 0xFF, 0xFF, 0x77, 0x77, 0xFF, 0xFF,
- 0xDD, 0xDD, 0xFF, 0xFF, 0x77, 0x77, 0xFF, 0xFF,
- 0xDD, 0xDD, 0xFF, 0xFF, 0x77, 0x77, 0xFF, 0xFF,
- },
- [32]byte{0xDD, 0xDD, 0x77, 0x77, 0xDD, 0xDD, 0x77, 0x77,
- 0xDD, 0xDD, 0x77, 0x77, 0xDD, 0xDD, 0x77, 0x77,
- 0xDD, 0xDD, 0x77, 0x77, 0xDD, 0xDD, 0x77, 0x77,
- 0xDD, 0xDD, 0x77, 0x77, 0xDD, 0xDD, 0x77, 0x77,
- },
- [32]byte{0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55,
- 0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55,
- 0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55,
- 0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55,
- },
- [32]byte{0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55,
- 0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55,
- 0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55,
- 0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55,
- },
- [32]byte{0x22, 0x22, 0x88, 0x88, 0x22, 0x22, 0x88, 0x88,
- 0x22, 0x22, 0x88, 0x88, 0x22, 0x22, 0x88, 0x88,
- 0x22, 0x22, 0x88, 0x88, 0x22, 0x22, 0x88, 0x88,
- 0x22, 0x22, 0x88, 0x88, 0x22, 0x22, 0x88, 0x88,
- },
- [32]byte{0x22, 0x22, 0x00, 0x00, 0x88, 0x88, 0x00, 0x00,
- 0x22, 0x22, 0x00, 0x00, 0x88, 0x88, 0x00, 0x00,
- 0x22, 0x22, 0x00, 0x00, 0x88, 0x88, 0x00, 0x00,
- 0x22, 0x22, 0x00, 0x00, 0x88, 0x88, 0x00, 0x00,
- },
- [32]byte{0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
- 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
- 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
- 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
- },
- [32]byte{0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
- 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
- 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
- 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
- },
- [32]byte{0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
- 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
- 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
- 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
- },
- [32]byte{0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33,
- 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33,
- 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33,
- 0xCC, 0xCC, 0xCC, 0xCC, 0x33, 0x33, 0x33, 0x33,
- },
-}
-
-var txpix = [NCOL]draw.Color{
- draw.Yellow, /* yellow */
- draw.Cyan, /* cyan */
- draw.Green, /* lime green */
- draw.GreyBlue, /* slate */
- draw.Red, /* red */
- draw.GreyGreen, /* olive green */
- draw.Blue, /* blue */
- draw.Color(0xFF55AAFF), /* pink */
- draw.Color(0xFFAAFFFF), /* lavender */
- draw.Color(0xBB005DFF), /* maroon */
-}
-
-func movemouse() int {
- //mouse.draw.Point = draw.Pt(rboard.Min.X + rboard.Dx()/2, rboard.Min.Y + rboard.Dy()/2);
- //moveto(mousectl, mouse.Xy);
- return mouse.X
-}
-
-func warp(p draw.Point, x int) int {
- if !suspended && piece != nil {
- x = pos.X + piece.sz.X*pcsz/2
- if p.Y < rboard.Min.Y {
- p.Y = rboard.Min.Y
- }
- if p.Y >= rboard.Max.Y {
- p.Y = rboard.Max.Y - 1
- }
- //moveto(mousectl, draw.Pt(x, p.Y));
- }
- return x
-}
-
-func initPieces() {
- for i := range pieces {
- p := &pieces[i]
- if p.rot == 3 {
- p.right = &pieces[i-3]
- } else {
- p.right = &pieces[i+1]
- }
- if p.rot == 0 {
- p.left = &pieces[i+3]
- } else {
- p.left = &pieces[i-1]
- }
- }
-}
-
-func collide(pt draw.Point, p *Piece) bool {
- pt.X = (pt.X - rboard.Min.X) / pcsz
- pt.Y = (pt.Y - rboard.Min.Y) / pcsz
- for _, q := range p.d {
- pt.X += q.X
- pt.Y += q.Y
- if pt.X < 0 || pt.X >= NX || pt.Y < 0 || pt.Y >= NY {
- return true
- continue
- }
- if board[pt.Y][pt.X] != 0 {
- return true
- }
- }
- return false
-}
-
-func collider(pt, pmax draw.Point) bool {
- pi := (pt.X - rboard.Min.X) / pcsz
- pj := (pt.Y - rboard.Min.Y) / pcsz
- n := pmax.X / pcsz
- m := pmax.Y/pcsz + 1
- for i := pi; i < pi+n && i < NX; i++ {
- for j := pj; j < pj+m && j < NY; j++ {
- if board[j][i] != 0 {
- return true
- }
- }
- }
- return false
-}
-
-func setpiece(p *Piece) {
- draw.Draw(bb, bbr, draw.White, draw.ZP)
- draw.Draw(bbmask, bbr, draw.Transparent, draw.ZP)
- br = draw.Rect(0, 0, 0, 0)
- br2 = br
- piece = p
- if p == nil {
- return
- }
- var op draw.Point
- var r draw.Rectangle
- r.Min = bbr.Min
- for i, pt := range p.d {
- r.Min.X += pt.X * pcsz
- r.Min.Y += pt.Y * pcsz
- r.Max.X = r.Min.X + pcsz
- r.Max.Y = r.Min.Y + pcsz
- if i == 0 {
- draw.Draw(bb, r, draw.Black, draw.ZP)
- draw.Draw(bb, r.Inset(1), txpix[piece.tx], draw.ZP)
- draw.Draw(bbmask, r, draw.Opaque, draw.ZP)
- op = r.Min
- } else {
- draw.Draw(bb, r, bb, op)
- draw.Draw(bbmask, r, bbmask, op)
- }
- if br.Max.X < r.Max.X {
- br.Max.X = r.Max.X
- }
- if br.Max.Y < r.Max.Y {
- br.Max.Y = r.Max.Y
- }
- }
- br.Max = br.Max.Sub(bbr.Min)
- delta := draw.Pt(0, DY)
- br2.Max = br.Max.Add(delta)
- r = br.Add(bb2r.Min)
- r2 := br2.Add(bb2r.Min)
- draw.Draw(bb2, r2, draw.White, draw.ZP)
- draw.Draw(bb2, r.Add(delta), bb, bbr.Min)
- draw.Draw(bb2mask, r2, draw.Transparent, draw.ZP)
- draw.DrawMask(bb2mask, r, draw.Opaque, bbr.Min, bbmask, draw.ZP, draw.Over)
- draw.DrawMask(bb2mask, r.Add(delta), draw.Opaque, bbr.Min, bbmask, draw.ZP, draw.Over)
-}
-
-func drawpiece() {
- draw.DrawMask(screen, br.Add(pos), bb, bbr.Min, bbmask, draw.ZP, draw.Over)
- if suspended {
- draw.DrawMask(screen, br.Add(pos), draw.White, draw.ZP, whitemask, draw.ZP, draw.Over)
- }
-}
-
-func undrawpiece() {
- var mask image.Image
- if collider(pos, br.Max) {
- mask = bbmask
- }
- draw.DrawMask(screen, br.Add(pos), draw.White, bbr.Min, mask, bbr.Min, draw.Over)
-}
-
-func rest() {
- pt := pos.Sub(rboard.Min).Div(pcsz)
- for _, p := range piece.d {
- pt.X += p.X
- pt.Y += p.Y
- board[pt.Y][pt.X] = byte(piece.tx + 16)
- }
-}
-
-func canfit(p *Piece) bool {
- var dx = [...]int{0, -1, 1, -2, 2, -3, 3, 4, -4}
- j := N + 1
- if j >= 4 {
- j = p.sz.X
- if j < p.sz.Y {
- j = p.sz.Y
- }
- j = 2*j - 1
- }
- for i := 0; i < j; i++ {
- var z draw.Point
- z.X = pos.X + dx[i]*pcsz
- z.Y = pos.Y
- if !collide(z, p) {
- z.Y = pos.Y + pcsz - 1
- if !collide(z, p) {
- undrawpiece()
- pos.X = z.X
- return true
- }
- }
- }
- return false
-}
-
-func score(p int) {
- points += p
- // snprint(buf, sizeof(buf), "%.6ld", points);
- // draw.Draw(screen, draw.Rpt(pscore, pscore.Add(scoresz)), draw.White, draw.ZP);
- // string(screen, pscore, draw.Black, draw.ZP, font, buf);
-}
-
-func drawsq(b draw.Image, p draw.Point, ptx int) {
- var r draw.Rectangle
- r.Min = p
- r.Max.X = r.Min.X + pcsz
- r.Max.Y = r.Min.Y + pcsz
- draw.Draw(b, r, draw.Black, draw.ZP)
- draw.Draw(b, r.Inset(1), txpix[ptx], draw.ZP)
-}
-
-func drawboard() {
- draw.Border(screen, rboard.Inset(-2), 2, draw.Black, draw.ZP)
- draw.Draw(screen, draw.Rect(rboard.Min.X, rboard.Min.Y-2, rboard.Max.X, rboard.Min.Y),
- draw.White, draw.ZP)
- for i := 0; i < NY; i++ {
- for j := 0; j < NX; j++ {
- if board[i][j] != 0 {
- drawsq(screen, draw.Pt(rboard.Min.X+j*pcsz, rboard.Min.Y+i*pcsz), int(board[i][j]-16))
- }
- }
- }
- score(0)
- if suspended {
- draw.DrawMask(screen, screenr, draw.White, draw.ZP, whitemask, draw.ZP, draw.Over)
- }
-}
-
-func choosepiece() {
- for {
- i := rand.Intn(len(pieces))
- setpiece(&pieces[i])
- pos = rboard.Min
- pos.X += rand.Intn(NX) * pcsz
- if !collide(draw.Pt(pos.X, pos.Y+pcsz-DY), piece) {
- break
- }
- }
- drawpiece()
- display.FlushImage()
-}
-
-func movepiece() bool {
- var mask image.Image
- if collide(draw.Pt(pos.X, pos.Y+pcsz), piece) {
- return false
- }
- if collider(pos, br2.Max) {
- mask = bb2mask
- }
- draw.DrawMask(screen, br2.Add(pos), bb2, bb2r.Min, mask, bb2r.Min, draw.Over)
- pos.Y += DY
- display.FlushImage()
- return true
-}
-
-func suspend(s bool) {
- suspended = s
- /*
- if suspended {
- setcursor(mousectl, &whitearrow);
- } else {
- setcursor(mousectl, nil);
- }
- */
- if !suspended {
- drawpiece()
- }
- drawboard()
- display.FlushImage()
-}
-
-func pause(t int) {
- display.FlushImage()
- for {
- select {
- case s := <-suspc:
- if !suspended && s {
- suspend(true)
- } else if suspended && !s {
- suspend(false)
- lastmx = warp(mouse.Point, lastmx)
- }
- case <-timerc:
- if suspended {
- break
- }
- t -= tsleep
- if t < 0 {
- return
- }
- case <-resizec:
- //redraw(true);
- case mouse = <-mousec:
- case <-kbdc:
- }
- }
-}
-
-func horiz() bool {
- var lev [MAXN]int
- h := 0
- for i := 0; i < NY; i++ {
- for j := 0; board[i][j] != 0; j++ {
- if j == NX-1 {
- lev[h] = i
- h++
- break
- }
- }
- }
- if h == 0 {
- return false
- }
- r := rboard
- newscreen = false
- for j := 0; j < h; j++ {
- r.Min.Y = rboard.Min.Y + lev[j]*pcsz
- r.Max.Y = r.Min.Y + pcsz
- draw.DrawMask(screen, r, draw.White, draw.ZP, whitemask, draw.ZP, draw.Over)
- display.FlushImage()
- }
- PlaySound(whoosh)
- for i := 0; i < 3; i++ {
- pause(250)
- if newscreen {
- drawboard()
- break
- }
- for j := 0; j < h; j++ {
- r.Min.Y = rboard.Min.Y + lev[j]*pcsz
- r.Max.Y = r.Min.Y + pcsz
- draw.DrawMask(screen, r, draw.White, draw.ZP, whitemask, draw.ZP, draw.Over)
- }
- display.FlushImage()
- }
- r = rboard
- for j := 0; j < h; j++ {
- i := NY - lev[j] - 1
- score(250 + 10*i*i)
- r.Min.Y = rboard.Min.Y
- r.Max.Y = rboard.Min.Y + lev[j]*pcsz
- draw.Draw(screen, r.Add(draw.Pt(0, pcsz)), screen, r.Min)
- r.Max.Y = rboard.Min.Y + pcsz
- draw.Draw(screen, r, draw.White, draw.ZP)
- for k := lev[j] - 1; k >= 0; k-- {
- board[k+1] = board[k]
- }
- board[0] = [NX]byte{}
- }
- display.FlushImage()
- return true
-}
-
-func mright() {
- if !collide(draw.Pt(pos.X+pcsz, pos.Y), piece) &&
- !collide(draw.Pt(pos.X+pcsz, pos.Y+pcsz-DY), piece) {
- undrawpiece()
- pos.X += pcsz
- drawpiece()
- display.FlushImage()
- }
-}
-
-func mleft() {
- if !collide(draw.Pt(pos.X-pcsz, pos.Y), piece) &&
- !collide(draw.Pt(pos.X-pcsz, pos.Y+pcsz-DY), piece) {
- undrawpiece()
- pos.X -= pcsz
- drawpiece()
- display.FlushImage()
- }
-}
-
-func rright() {
- if canfit(piece.right) {
- setpiece(piece.right)
- drawpiece()
- display.FlushImage()
- }
-}
-
-func rleft() {
- if canfit(piece.left) {
- setpiece(piece.left)
- drawpiece()
- display.FlushImage()
- }
-}
-
-var fusst = 0
-
-func drop(f bool) bool {
- if f {
- score(5 * (rboard.Max.Y - pos.Y) / pcsz)
- for movepiece() {
- }
- }
- fusst = 0
- rest()
- if pos.Y == rboard.Min.Y && !horiz() {
- return true
- }
- horiz()
- setpiece(nil)
- pause(1500)
- choosepiece()
- lastmx = warp(mouse.Point, lastmx)
- return false
-}
-
-func play() {
- var om draw.Mouse
- dt = 64
- lastmx = -1
- lastmx = movemouse()
- choosepiece()
- lastmx = warp(mouse.Point, lastmx)
- for {
- select {
- case mouse = <-mousec:
- if suspended {
- om = mouse
- break
- }
- if lastmx < 0 {
- lastmx = mouse.X
- }
- if mouse.X > lastmx+DMOUSE {
- mright()
- lastmx = mouse.X
- }
- if mouse.X < lastmx-DMOUSE {
- mleft()
- lastmx = mouse.X
- }
- if mouse.Buttons&^om.Buttons&1 == 1 {
- rleft()
- }
- if mouse.Buttons&^om.Buttons&2 == 2 {
- if drop(true) {
- return
- }
- }
- if mouse.Buttons&^om.Buttons&4 == 4 {
- rright()
- }
- om = mouse
-
- case s := <-suspc:
- if !suspended && s {
- suspend(true)
- } else if suspended && !s {
- suspend(false)
- lastmx = warp(mouse.Point, lastmx)
- }
-
- case <-resizec:
- //redraw(true);
-
- case r := <-kbdc:
- if suspended {
- break
- }
- switch r {
- case 'f', ';':
- mright()
- case 'a', 'j':
- mleft()
- case 'd', 'l':
- rright()
- case 's', 'k':
- rleft()
- case ' ':
- if drop(true) {
- return
- }
- }
-
- case <-timerc:
- if suspended {
- break
- }
- dt -= tsleep
- if dt < 0 {
- i := 1
- dt = 16 * (points + rand.Intn(10000) - 5000) / 10000
- if dt >= 32 {
- i += (dt - 32) / 16
- dt = 32
- }
- dt = 52 - dt
- for ; i > 0; i-- {
- if movepiece() {
- continue
- }
- fusst++
- if fusst == 40 {
- if drop(false) {
- return
- }
- break
- }
- }
- }
- }
- }
-}
-
-func suspproc() {
- mc := display.MouseChan()
- kc := display.KeyboardChan()
-
- s := false
- for {
- select {
- case mouse = <-mc:
- mousec <- mouse
- case r := <-kc:
- switch r {
- case 'q', 'Q', 0x04, 0x7F:
- os.Exit(0)
- default:
- if s {
- s = false
- suspc <- s
- break
- }
- switch r {
- case 'z', 'Z', 'p', 'P', 0x1B:
- s = true
- suspc <- s
- default:
- kbdc <- r
- }
- }
- }
- }
-}
-
-func redraw(new bool) {
- // if new && getwindow(display, Refmesg) < 0 {
- // sysfatal("can't reattach to window");
- // }
- r := draw.Rect(0, 0, screen.Width(), screen.Height())
- pos.X = (pos.X - rboard.Min.X) / pcsz
- pos.Y = (pos.Y - rboard.Min.Y) / pcsz
- dx := r.Max.X - r.Min.X
- dy := r.Max.Y - r.Min.Y - 2*32
- DY = dx / NX
- if DY > dy/NY {
- DY = dy / NY
- }
- DY /= 8
- if DY > 4 {
- DY = 4
- }
- pcsz = DY * 8
- DMOUSE = pcsz / 3
- if pcsz < 8 {
- log.Exitf("screen too small: %d", pcsz)
- }
- rboard = screenr
- rboard.Min.X += (dx - pcsz*NX) / 2
- rboard.Min.Y += (dy-pcsz*NY)/2 + 32
- rboard.Max.X = rboard.Min.X + NX*pcsz
- rboard.Max.Y = rboard.Min.Y + NY*pcsz
- pscore.X = rboard.Min.X + 8
- pscore.Y = rboard.Min.Y - 32
- // scoresz = stringsize(font, "000000");
- pos.X = pos.X*pcsz + rboard.Min.X
- pos.Y = pos.Y*pcsz + rboard.Min.Y
- bbr = draw.Rect(0, 0, N*pcsz, N*pcsz)
- bb = image.NewRGBA(bbr.Max.X, bbr.Max.Y)
- bbmask = image.NewRGBA(bbr.Max.X, bbr.Max.Y) // actually just a bitmap
- bb2r = draw.Rect(0, 0, N*pcsz, N*pcsz+DY)
- bb2 = image.NewRGBA(bb2r.Dx(), bb2r.Dy())
- bb2mask = image.NewRGBA(bb2r.Dx(), bb2r.Dy()) // actually just a bitmap
- draw.Draw(screen, screenr, draw.White, draw.ZP)
- drawboard()
- setpiece(piece)
- if piece != nil {
- drawpiece()
- }
- lastmx = movemouse()
- newscreen = true
- display.FlushImage()
-}
-
-func quitter(c <-chan bool) {
- <-c
- os.Exit(0)
-}
-
-func Play(pp []Piece, ctxt draw.Context) {
- display = ctxt
- screen = ctxt.Screen()
- screenr = draw.Rect(0, 0, screen.Width(), screen.Height())
- pieces = pp
- N = len(pieces[0].d)
- initPieces()
- rand.Seed(int64(time.Nanoseconds() % (1e9 - 1)))
- whitemask = draw.White.SetAlpha(0x7F)
- tsleep = 50
- timerc = time.Tick(int64(tsleep/2) * 1e6)
- suspc = make(chan bool)
- mousec = make(chan draw.Mouse)
- resizec = ctxt.ResizeChan()
- kbdc = make(chan int)
- go quitter(ctxt.QuitChan())
- go suspproc()
- points = 0
- redraw(false)
- play()
-}
diff --git a/src/pkg/exp/bignum/Makefile b/src/pkg/exp/bignum/Makefile
deleted file mode 100644
index 064cf1eb9..000000000
--- a/src/pkg/exp/bignum/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.$(GOARCH)
-
-TARG=exp/bignum
-GOFILES=\
- arith.go\
- bignum.go\
- integer.go\
- rational.go\
-
-include ../../../Make.pkg
diff --git a/src/pkg/exp/bignum/arith.go b/src/pkg/exp/bignum/arith.go
deleted file mode 100644
index aa65dbd7a..000000000
--- a/src/pkg/exp/bignum/arith.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.
-
-// Fast versions of the routines in this file are in fast.arith.s.
-// Simply replace this file with arith.s (renamed from fast.arith.s)
-// and the bignum package will build and run on a platform that
-// supports the assembly routines.
-
-package bignum
-
-import "unsafe"
-
-// z1<<64 + z0 = x*y
-func Mul128(x, y uint64) (z1, z0 uint64) {
- // Split x and y into 2 halfwords each, multiply
- // the halfwords separately while avoiding overflow,
- // and return the product as 2 words.
-
- const (
- W = uint(unsafe.Sizeof(x)) * 8
- W2 = W / 2
- B2 = 1 << W2
- M2 = B2 - 1
- )
-
- if x < y {
- x, y = y, x
- }
-
- if x < B2 {
- // y < B2 because y <= x
- // sub-digits of x and y are (0, x) and (0, y)
- // z = z[0] = x*y
- z0 = x * y
- return
- }
-
- if y < B2 {
- // sub-digits of x and y are (x1, x0) and (0, y)
- // x = (x1*B2 + x0)
- // y = (y1*B2 + y0)
- x1, x0 := x>>W2, x&M2
-
- // x*y = t2*B2*B2 + t1*B2 + t0
- t0 := x0 * y
- t1 := x1 * y
-
- // compute result digits but avoid overflow
- // z = z[1]*B + z[0] = x*y
- z0 = t1<<W2 + t0
- z1 = (t1 + t0>>W2) >> W2
- return
- }
-
- // general case
- // sub-digits of x and y are (x1, x0) and (y1, y0)
- // x = (x1*B2 + x0)
- // y = (y1*B2 + y0)
- x1, x0 := x>>W2, x&M2
- y1, y0 := y>>W2, y&M2
-
- // x*y = t2*B2*B2 + t1*B2 + t0
- t0 := x0 * y0
- t1 := x1*y0 + x0*y1
- t2 := x1 * y1
-
- // compute result digits but avoid overflow
- // z = z[1]*B + z[0] = x*y
- z0 = t1<<W2 + t0
- z1 = t2 + (t1+t0>>W2)>>W2
- return
-}
-
-
-// z1<<64 + z0 = x*y + c
-func MulAdd128(x, y, c uint64) (z1, z0 uint64) {
- // Split x and y into 2 halfwords each, multiply
- // the halfwords separately while avoiding overflow,
- // and return the product as 2 words.
-
- const (
- W = uint(unsafe.Sizeof(x)) * 8
- W2 = W / 2
- B2 = 1 << W2
- M2 = B2 - 1
- )
-
- // TODO(gri) Should implement special cases for faster execution.
-
- // general case
- // sub-digits of x, y, and c are (x1, x0), (y1, y0), (c1, c0)
- // x = (x1*B2 + x0)
- // y = (y1*B2 + y0)
- x1, x0 := x>>W2, x&M2
- y1, y0 := y>>W2, y&M2
- c1, c0 := c>>W2, c&M2
-
- // x*y + c = t2*B2*B2 + t1*B2 + t0
- t0 := x0*y0 + c0
- t1 := x1*y0 + x0*y1 + c1
- t2 := x1 * y1
-
- // compute result digits but avoid overflow
- // z = z[1]*B + z[0] = x*y
- z0 = t1<<W2 + t0
- z1 = t2 + (t1+t0>>W2)>>W2
- return
-}
-
-
-// q = (x1<<64 + x0)/y + r
-func Div128(x1, x0, y uint64) (q, r uint64) {
- if x1 == 0 {
- q, r = x0/y, x0%y
- return
- }
-
- // TODO(gri) Implement general case.
- panic("Div128 not implemented for x > 1<<64-1")
-}
diff --git a/src/pkg/exp/bignum/arith_amd64.s b/src/pkg/exp/bignum/arith_amd64.s
deleted file mode 100644
index 37d5a30de..000000000
--- a/src/pkg/exp/bignum/arith_amd64.s
+++ /dev/null
@@ -1,41 +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 provides fast assembly versions
-// of the routines in arith.go.
-
-// func Mul128(x, y uint64) (z1, z0 uint64)
-// z1<<64 + z0 = x*y
-//
-TEXT ·Mul128(SB),7,$0
- MOVQ a+0(FP), AX
- MULQ a+8(FP)
- MOVQ DX, a+16(FP)
- MOVQ AX, a+24(FP)
- RET
-
-
-// func MulAdd128(x, y, c uint64) (z1, z0 uint64)
-// z1<<64 + z0 = x*y + c
-//
-TEXT ·MulAdd128(SB),7,$0
- MOVQ a+0(FP), AX
- MULQ a+8(FP)
- ADDQ a+16(FP), AX
- ADCQ $0, DX
- MOVQ DX, a+24(FP)
- MOVQ AX, a+32(FP)
- RET
-
-
-// func Div128(x1, x0, y uint64) (q, r uint64)
-// q = (x1<<64 + x0)/y + r
-//
-TEXT ·Div128(SB),7,$0
- MOVQ a+0(FP), DX
- MOVQ a+8(FP), AX
- DIVQ a+16(FP)
- MOVQ AX, a+24(FP)
- MOVQ DX, a+32(FP)
- RET
diff --git a/src/pkg/exp/bignum/bignum.go b/src/pkg/exp/bignum/bignum.go
deleted file mode 100644
index 485583199..000000000
--- a/src/pkg/exp/bignum/bignum.go
+++ /dev/null
@@ -1,1024 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// A package for arbitrary precision arithmethic.
-// It implements the following numeric types:
-//
-// - Natural unsigned integers
-// - Integer signed integers
-// - Rational rational numbers
-//
-// This package has been designed for ease of use but the functions it provides
-// are likely to be quite slow. It may be deprecated eventually. Use package
-// big instead, if possible.
-//
-package bignum
-
-import (
- "fmt"
-)
-
-// TODO(gri) Complete the set of in-place operations.
-
-// ----------------------------------------------------------------------------
-// Internal representation
-//
-// A natural number of the form
-//
-// x = x[n-1]*B^(n-1) + x[n-2]*B^(n-2) + ... + x[1]*B + x[0]
-//
-// with 0 <= x[i] < B and 0 <= i < n is stored in a slice of length n,
-// with the digits x[i] as the slice elements.
-//
-// A natural number is normalized if the slice contains no leading 0 digits.
-// During arithmetic operations, denormalized values may occur but are
-// always normalized before returning the final result. The normalized
-// representation of 0 is the empty slice (length = 0).
-//
-// The operations for all other numeric types are implemented on top of
-// the operations for natural numbers.
-//
-// The base B is chosen as large as possible on a given platform but there
-// are a few constraints besides the size of the largest unsigned integer
-// type available:
-//
-// 1) To improve conversion speed between strings and numbers, the base B
-// is chosen such that division and multiplication by 10 (for decimal
-// string representation) can be done without using extended-precision
-// arithmetic. This makes addition, subtraction, and conversion routines
-// twice as fast. It requires a ``buffer'' of 4 bits per operand digit.
-// That is, the size of B must be 4 bits smaller then the size of the
-// type (digit) in which these operations are performed. Having this
-// buffer also allows for trivial (single-bit) carry computation in
-// addition and subtraction (optimization suggested by Ken Thompson).
-//
-// 2) Long division requires extended-precision (2-digit) division per digit.
-// Instead of sacrificing the largest base type for all other operations,
-// for division the operands are unpacked into ``half-digits'', and the
-// results are packed again. For faster unpacking/packing, the base size
-// in bits must be even.
-
-type (
- digit uint64
- digit2 uint32 // half-digits for division
-)
-
-
-const (
- logW = 64 // word width
- logH = 4 // bits for a hex digit (= small number)
- logB = logW - logH // largest bit-width available
-
- // half-digits
- _W2 = logB / 2 // width
- _B2 = 1 << _W2 // base
- _M2 = _B2 - 1 // mask
-
- // full digits
- _W = _W2 * 2 // width
- _B = 1 << _W // base
- _M = _B - 1 // mask
-)
-
-
-// ----------------------------------------------------------------------------
-// Support functions
-
-func assert(p bool) {
- if !p {
- panic("assert failed")
- }
-}
-
-
-func isSmall(x digit) bool { return x < 1<<logH }
-
-
-// For debugging. Keep around.
-/*
-func dump(x Natural) {
- print("[", len(x), "]");
- for i := len(x) - 1; i >= 0; i-- {
- print(" ", x[i]);
- }
- println();
-}
-*/
-
-
-// ----------------------------------------------------------------------------
-// Natural numbers
-
-// Natural represents an unsigned integer value of arbitrary precision.
-//
-type Natural []digit
-
-
-// Nat creates a small natural number with value x.
-//
-func Nat(x uint64) Natural {
- if x == 0 {
- return nil // len == 0
- }
-
- // single-digit values
- // (note: cannot re-use preallocated values because
- // the in-place operations may overwrite them)
- if x < _B {
- return Natural{digit(x)}
- }
-
- // compute number of digits required to represent x
- // (this is usually 1 or 2, but the algorithm works
- // for any base)
- n := 0
- for t := x; t > 0; t >>= _W {
- n++
- }
-
- // split x into digits
- z := make(Natural, n)
- for i := 0; i < n; i++ {
- z[i] = digit(x & _M)
- x >>= _W
- }
-
- return z
-}
-
-
-// Value returns the lowest 64bits of x.
-//
-func (x Natural) Value() uint64 {
- // single-digit values
- n := len(x)
- switch n {
- case 0:
- return 0
- case 1:
- return uint64(x[0])
- }
-
- // multi-digit values
- // (this is usually 1 or 2, but the algorithm works
- // for any base)
- z := uint64(0)
- s := uint(0)
- for i := 0; i < n && s < 64; i++ {
- z += uint64(x[i]) << s
- s += _W
- }
-
- return z
-}
-
-
-// Predicates
-
-// IsEven returns true iff x is divisible by 2.
-//
-func (x Natural) IsEven() bool { return len(x) == 0 || x[0]&1 == 0 }
-
-
-// IsOdd returns true iff x is not divisible by 2.
-//
-func (x Natural) IsOdd() bool { return len(x) > 0 && x[0]&1 != 0 }
-
-
-// IsZero returns true iff x == 0.
-//
-func (x Natural) IsZero() bool { return len(x) == 0 }
-
-
-// Operations
-//
-// Naming conventions
-//
-// c carry
-// x, y operands
-// z result
-// n, m len(x), len(y)
-
-func normalize(x Natural) Natural {
- n := len(x)
- for n > 0 && x[n-1] == 0 {
- n--
- }
- return x[0:n]
-}
-
-
-// nalloc returns a Natural of n digits. If z is large
-// enough, z is resized and returned. Otherwise, a new
-// Natural is allocated.
-//
-func nalloc(z Natural, n int) Natural {
- size := n
- if size <= 0 {
- size = 4
- }
- if size <= cap(z) {
- return z[0:n]
- }
- return make(Natural, n, size)
-}
-
-
-// Nadd sets *zp to the sum x + y.
-// *zp may be x or y.
-//
-func Nadd(zp *Natural, x, y Natural) {
- n := len(x)
- m := len(y)
- if n < m {
- Nadd(zp, y, x)
- return
- }
-
- z := nalloc(*zp, n+1)
- c := digit(0)
- i := 0
- for i < m {
- t := c + x[i] + y[i]
- c, z[i] = t>>_W, t&_M
- i++
- }
- for i < n {
- t := c + x[i]
- c, z[i] = t>>_W, t&_M
- i++
- }
- if c != 0 {
- z[i] = c
- i++
- }
- *zp = z[0:i]
-}
-
-
-// Add returns the sum z = x + y.
-//
-func (x Natural) Add(y Natural) Natural {
- var z Natural
- Nadd(&z, x, y)
- return z
-}
-
-
-// Nsub sets *zp to the difference x - y for x >= y.
-// If x < y, an underflow run-time error occurs (use Cmp to test if x >= y).
-// *zp may be x or y.
-//
-func Nsub(zp *Natural, x, y Natural) {
- n := len(x)
- m := len(y)
- if n < m {
- panic("underflow")
- }
-
- z := nalloc(*zp, n)
- c := digit(0)
- i := 0
- for i < m {
- t := c + x[i] - y[i]
- c, z[i] = digit(int64(t)>>_W), t&_M // requires arithmetic shift!
- i++
- }
- for i < n {
- t := c + x[i]
- c, z[i] = digit(int64(t)>>_W), t&_M // requires arithmetic shift!
- i++
- }
- if int64(c) < 0 {
- panic("underflow")
- }
- *zp = normalize(z)
-}
-
-
-// Sub returns the difference x - y for x >= y.
-// If x < y, an underflow run-time error occurs (use Cmp to test if x >= y).
-//
-func (x Natural) Sub(y Natural) Natural {
- var z Natural
- Nsub(&z, x, y)
- return z
-}
-
-
-// Returns z1 = (x*y + c) div B, z0 = (x*y + c) mod B.
-//
-func muladd11(x, y, c digit) (digit, digit) {
- z1, z0 := MulAdd128(uint64(x), uint64(y), uint64(c))
- return digit(z1<<(64-logB) | z0>>logB), digit(z0 & _M)
-}
-
-
-func mul1(z, x Natural, y digit) (c digit) {
- for i := 0; i < len(x); i++ {
- c, z[i] = muladd11(x[i], y, c)
- }
- return
-}
-
-
-// Nscale sets *z to the scaled value (*z) * d.
-//
-func Nscale(z *Natural, d uint64) {
- switch {
- case d == 0:
- *z = Nat(0)
- return
- case d == 1:
- return
- case d >= _B:
- *z = z.Mul1(d)
- return
- }
-
- c := mul1(*z, *z, digit(d))
-
- if c != 0 {
- n := len(*z)
- if n >= cap(*z) {
- zz := make(Natural, n+1)
- for i, d := range *z {
- zz[i] = d
- }
- *z = zz
- } else {
- *z = (*z)[0 : n+1]
- }
- (*z)[n] = c
- }
-}
-
-
-// Computes x = x*d + c for small d's.
-//
-func muladd1(x Natural, d, c digit) Natural {
- assert(isSmall(d-1) && isSmall(c))
- n := len(x)
- z := make(Natural, n+1)
-
- for i := 0; i < n; i++ {
- t := c + x[i]*d
- c, z[i] = t>>_W, t&_M
- }
- z[n] = c
-
- return normalize(z)
-}
-
-
-// Mul1 returns the product x * d.
-//
-func (x Natural) Mul1(d uint64) Natural {
- switch {
- case d == 0:
- return Nat(0)
- case d == 1:
- return x
- case isSmall(digit(d)):
- muladd1(x, digit(d), 0)
- case d >= _B:
- return x.Mul(Nat(d))
- }
-
- z := make(Natural, len(x)+1)
- c := mul1(z, x, digit(d))
- z[len(x)] = c
- return normalize(z)
-}
-
-
-// Mul returns the product x * y.
-//
-func (x Natural) Mul(y Natural) Natural {
- n := len(x)
- m := len(y)
- if n < m {
- return y.Mul(x)
- }
-
- if m == 0 {
- return Nat(0)
- }
-
- if m == 1 && y[0] < _B {
- return x.Mul1(uint64(y[0]))
- }
-
- z := make(Natural, n+m)
- for j := 0; j < m; j++ {
- d := y[j]
- if d != 0 {
- c := digit(0)
- for i := 0; i < n; i++ {
- c, z[i+j] = muladd11(x[i], d, z[i+j]+c)
- }
- z[n+j] = c
- }
- }
-
- return normalize(z)
-}
-
-
-// DivMod needs multi-precision division, which is not available if digit
-// is already using the largest uint size. Instead, unpack each operand
-// into operands with twice as many digits of half the size (digit2), do
-// DivMod, and then pack the results again.
-
-func unpack(x Natural) []digit2 {
- n := len(x)
- z := make([]digit2, n*2+1) // add space for extra digit (used by DivMod)
- for i := 0; i < n; i++ {
- t := x[i]
- z[i*2] = digit2(t & _M2)
- z[i*2+1] = digit2(t >> _W2 & _M2)
- }
-
- // normalize result
- k := 2 * n
- for k > 0 && z[k-1] == 0 {
- k--
- }
- return z[0:k] // trim leading 0's
-}
-
-
-func pack(x []digit2) Natural {
- n := (len(x) + 1) / 2
- z := make(Natural, n)
- if len(x)&1 == 1 {
- // handle odd len(x)
- n--
- z[n] = digit(x[n*2])
- }
- for i := 0; i < n; i++ {
- z[i] = digit(x[i*2+1])<<_W2 | digit(x[i*2])
- }
- return normalize(z)
-}
-
-
-func mul21(z, x []digit2, y digit2) digit2 {
- c := digit(0)
- f := digit(y)
- for i := 0; i < len(x); i++ {
- t := c + digit(x[i])*f
- c, z[i] = t>>_W2, digit2(t&_M2)
- }
- return digit2(c)
-}
-
-
-func div21(z, x []digit2, y digit2) digit2 {
- c := digit(0)
- d := digit(y)
- for i := len(x) - 1; i >= 0; i-- {
- t := c<<_W2 + digit(x[i])
- c, z[i] = t%d, digit2(t/d)
- }
- return digit2(c)
-}
-
-
-// divmod returns q and r with x = y*q + r and 0 <= r < y.
-// x and y are destroyed in the process.
-//
-// The algorithm used here is based on 1). 2) describes the same algorithm
-// in C. A discussion and summary of the relevant theorems can be found in
-// 3). 3) also describes an easier way to obtain the trial digit - however
-// it relies on tripple-precision arithmetic which is why Knuth's method is
-// used here.
-//
-// 1) D. Knuth, The Art of Computer Programming. Volume 2. Seminumerical
-// Algorithms. Addison-Wesley, Reading, 1969.
-// (Algorithm D, Sec. 4.3.1)
-//
-// 2) Henry S. Warren, Jr., Hacker's Delight. Addison-Wesley, 2003.
-// (9-2 Multiword Division, p.140ff)
-//
-// 3) P. Brinch Hansen, ``Multiple-length division revisited: A tour of the
-// minefield''. Software - Practice and Experience 24, (June 1994),
-// 579-601. John Wiley & Sons, Ltd.
-
-func divmod(x, y []digit2) ([]digit2, []digit2) {
- n := len(x)
- m := len(y)
- if m == 0 {
- panic("division by zero")
- }
- assert(n+1 <= cap(x)) // space for one extra digit
- x = x[0 : n+1]
- assert(x[n] == 0)
-
- if m == 1 {
- // division by single digit
- // result is shifted left by 1 in place!
- x[0] = div21(x[1:n+1], x[0:n], y[0])
-
- } else if m > n {
- // y > x => quotient = 0, remainder = x
- // TODO in this case we shouldn't even unpack x and y
- m = n
-
- } else {
- // general case
- assert(2 <= m && m <= n)
-
- // normalize x and y
- // TODO Instead of multiplying, it would be sufficient to
- // shift y such that the normalization condition is
- // satisfied (as done in Hacker's Delight).
- f := _B2 / (digit(y[m-1]) + 1)
- if f != 1 {
- mul21(x, x, digit2(f))
- mul21(y, y, digit2(f))
- }
- assert(_B2/2 <= y[m-1] && y[m-1] < _B2) // incorrect scaling
-
- y1, y2 := digit(y[m-1]), digit(y[m-2])
- for i := n - m; i >= 0; i-- {
- k := i + m
-
- // compute trial digit (Knuth)
- var q digit
- {
- x0, x1, x2 := digit(x[k]), digit(x[k-1]), digit(x[k-2])
- if x0 != y1 {
- q = (x0<<_W2 + x1) / y1
- } else {
- q = _B2 - 1
- }
- for y2*q > (x0<<_W2+x1-y1*q)<<_W2+x2 {
- q--
- }
- }
-
- // subtract y*q
- c := digit(0)
- for j := 0; j < m; j++ {
- t := c + digit(x[i+j]) - digit(y[j])*q
- c, x[i+j] = digit(int64(t)>>_W2), digit2(t&_M2) // requires arithmetic shift!
- }
- x[k] = digit2((c + digit(x[k])) & _M2)
-
- // correct if trial digit was too large
- if x[k] != 0 {
- // add y
- c := digit(0)
- for j := 0; j < m; j++ {
- t := c + digit(x[i+j]) + digit(y[j])
- c, x[i+j] = t>>_W2, digit2(t&_M2)
- }
- x[k] = digit2((c + digit(x[k])) & _M2)
- assert(x[k] == 0)
- // correct trial digit
- q--
- }
-
- x[k] = digit2(q)
- }
-
- // undo normalization for remainder
- if f != 1 {
- c := div21(x[0:m], x[0:m], digit2(f))
- assert(c == 0)
- }
- }
-
- return x[m : n+1], x[0:m]
-}
-
-
-// Div returns the quotient q = x / y for y > 0,
-// with x = y*q + r and 0 <= r < y.
-// If y == 0, a division-by-zero run-time error occurs.
-//
-func (x Natural) Div(y Natural) Natural {
- q, _ := divmod(unpack(x), unpack(y))
- return pack(q)
-}
-
-
-// Mod returns the modulus r of the division x / y for y > 0,
-// with x = y*q + r and 0 <= r < y.
-// If y == 0, a division-by-zero run-time error occurs.
-//
-func (x Natural) Mod(y Natural) Natural {
- _, r := divmod(unpack(x), unpack(y))
- return pack(r)
-}
-
-
-// DivMod returns the pair (x.Div(y), x.Mod(y)) for y > 0.
-// If y == 0, a division-by-zero run-time error occurs.
-//
-func (x Natural) DivMod(y Natural) (Natural, Natural) {
- q, r := divmod(unpack(x), unpack(y))
- return pack(q), pack(r)
-}
-
-
-func shl(z, x Natural, s uint) digit {
- assert(s <= _W)
- n := len(x)
- c := digit(0)
- for i := 0; i < n; i++ {
- c, z[i] = x[i]>>(_W-s), x[i]<<s&_M|c
- }
- return c
-}
-
-
-// Shl implements ``shift left'' x << s. It returns x * 2^s.
-//
-func (x Natural) Shl(s uint) Natural {
- n := uint(len(x))
- m := n + s/_W
- z := make(Natural, m+1)
-
- z[m] = shl(z[m-n:m], x, s%_W)
-
- return normalize(z)
-}
-
-
-func shr(z, x Natural, s uint) digit {
- assert(s <= _W)
- n := len(x)
- c := digit(0)
- for i := n - 1; i >= 0; i-- {
- c, z[i] = x[i]<<(_W-s)&_M, x[i]>>s|c
- }
- return c
-}
-
-
-// Shr implements ``shift right'' x >> s. It returns x / 2^s.
-//
-func (x Natural) Shr(s uint) Natural {
- n := uint(len(x))
- m := n - s/_W
- if m > n { // check for underflow
- m = 0
- }
- z := make(Natural, m)
-
- shr(z, x[n-m:n], s%_W)
-
- return normalize(z)
-}
-
-
-// And returns the ``bitwise and'' x & y for the 2's-complement representation of x and y.
-//
-func (x Natural) And(y Natural) Natural {
- n := len(x)
- m := len(y)
- if n < m {
- return y.And(x)
- }
-
- z := make(Natural, m)
- for i := 0; i < m; i++ {
- z[i] = x[i] & y[i]
- }
- // upper bits are 0
-
- return normalize(z)
-}
-
-
-func copy(z, x Natural) {
- for i, e := range x {
- z[i] = e
- }
-}
-
-
-// AndNot returns the ``bitwise clear'' x &^ y for the 2's-complement representation of x and y.
-//
-func (x Natural) AndNot(y Natural) Natural {
- n := len(x)
- m := len(y)
- if n < m {
- m = n
- }
-
- z := make(Natural, n)
- for i := 0; i < m; i++ {
- z[i] = x[i] &^ y[i]
- }
- copy(z[m:n], x[m:n])
-
- return normalize(z)
-}
-
-
-// Or returns the ``bitwise or'' x | y for the 2's-complement representation of x and y.
-//
-func (x Natural) Or(y Natural) Natural {
- n := len(x)
- m := len(y)
- if n < m {
- return y.Or(x)
- }
-
- z := make(Natural, n)
- for i := 0; i < m; i++ {
- z[i] = x[i] | y[i]
- }
- copy(z[m:n], x[m:n])
-
- return z
-}
-
-
-// Xor returns the ``bitwise exclusive or'' x ^ y for the 2's-complement representation of x and y.
-//
-func (x Natural) Xor(y Natural) Natural {
- n := len(x)
- m := len(y)
- if n < m {
- return y.Xor(x)
- }
-
- z := make(Natural, n)
- for i := 0; i < m; i++ {
- z[i] = x[i] ^ y[i]
- }
- copy(z[m:n], x[m:n])
-
- return normalize(z)
-}
-
-
-// Cmp compares x and y. The result is an int value
-//
-// < 0 if x < y
-// == 0 if x == y
-// > 0 if x > y
-//
-func (x Natural) Cmp(y Natural) int {
- n := len(x)
- m := len(y)
-
- if n != m || n == 0 {
- return n - m
- }
-
- i := n - 1
- for i > 0 && x[i] == y[i] {
- i--
- }
-
- d := 0
- switch {
- case x[i] < y[i]:
- d = -1
- case x[i] > y[i]:
- d = 1
- }
-
- return d
-}
-
-
-// log2 computes the binary logarithm of x for x > 0.
-// The result is the integer n for which 2^n <= x < 2^(n+1).
-// If x == 0 a run-time error occurs.
-//
-func log2(x uint64) uint {
- assert(x > 0)
- n := uint(0)
- for x > 0 {
- x >>= 1
- n++
- }
- return n - 1
-}
-
-
-// Log2 computes the binary logarithm of x for x > 0.
-// The result is the integer n for which 2^n <= x < 2^(n+1).
-// If x == 0 a run-time error occurs.
-//
-func (x Natural) Log2() uint {
- n := len(x)
- if n > 0 {
- return (uint(n)-1)*_W + log2(uint64(x[n-1]))
- }
- panic("Log2(0)")
-}
-
-
-// Computes x = x div d in place (modifies x) for small d's.
-// Returns updated x and x mod d.
-//
-func divmod1(x Natural, d digit) (Natural, digit) {
- assert(0 < d && isSmall(d-1))
-
- c := digit(0)
- for i := len(x) - 1; i >= 0; i-- {
- t := c<<_W + x[i]
- c, x[i] = t%d, t/d
- }
-
- return normalize(x), c
-}
-
-
-// ToString converts x to a string for a given base, with 2 <= base <= 16.
-//
-func (x Natural) ToString(base uint) string {
- if len(x) == 0 {
- return "0"
- }
-
- // allocate buffer for conversion
- assert(2 <= base && base <= 16)
- n := (x.Log2()+1)/log2(uint64(base)) + 1 // +1: round up
- s := make([]byte, n)
-
- // don't destroy x
- t := make(Natural, len(x))
- copy(t, x)
-
- // convert
- i := n
- for !t.IsZero() {
- i--
- var d digit
- t, d = divmod1(t, digit(base))
- s[i] = "0123456789abcdef"[d]
- }
-
- return string(s[i:n])
-}
-
-
-// String converts x to its decimal string representation.
-// x.String() is the same as x.ToString(10).
-//
-func (x Natural) String() string { return x.ToString(10) }
-
-
-func fmtbase(c int) uint {
- switch c {
- case 'b':
- return 2
- case 'o':
- return 8
- case 'x':
- return 16
- }
- return 10
-}
-
-
-// Format is a support routine for fmt.Formatter. It accepts
-// the formats 'b' (binary), 'o' (octal), and 'x' (hexadecimal).
-//
-func (x Natural) Format(h fmt.State, c int) { fmt.Fprintf(h, "%s", x.ToString(fmtbase(c))) }
-
-
-func hexvalue(ch byte) uint {
- d := uint(1 << logH)
- switch {
- case '0' <= ch && ch <= '9':
- d = uint(ch - '0')
- case 'a' <= ch && ch <= 'f':
- d = uint(ch-'a') + 10
- case 'A' <= ch && ch <= 'F':
- d = uint(ch-'A') + 10
- }
- return d
-}
-
-
-// NatFromString returns the natural number corresponding to the
-// longest possible prefix of s representing a natural number in a
-// given conversion base, the actual conversion base used, and the
-// prefix length. The syntax of natural numbers follows the syntax
-// of unsigned integer literals in Go.
-//
-// If the base argument is 0, the string prefix determines the actual
-// conversion base. A prefix of ``0x'' or ``0X'' selects base 16; the
-// ``0'' prefix selects base 8. Otherwise the selected base is 10.
-//
-func NatFromString(s string, base uint) (Natural, uint, int) {
- // determine base if necessary
- i, n := 0, len(s)
- if base == 0 {
- base = 10
- if n > 0 && s[0] == '0' {
- if n > 1 && (s[1] == 'x' || s[1] == 'X') {
- base, i = 16, 2
- } else {
- base, i = 8, 1
- }
- }
- }
-
- // convert string
- assert(2 <= base && base <= 16)
- x := Nat(0)
- for ; i < n; i++ {
- d := hexvalue(s[i])
- if d < base {
- x = muladd1(x, digit(base), digit(d))
- } else {
- break
- }
- }
-
- return x, base, i
-}
-
-
-// Natural number functions
-
-func pop1(x digit) uint {
- n := uint(0)
- for x != 0 {
- x &= x - 1
- n++
- }
- return n
-}
-
-
-// Pop computes the ``population count'' of (the number of 1 bits in) x.
-//
-func (x Natural) Pop() uint {
- n := uint(0)
- for i := len(x) - 1; i >= 0; i-- {
- n += pop1(x[i])
- }
- return n
-}
-
-
-// Pow computes x to the power of n.
-//
-func (xp Natural) Pow(n uint) Natural {
- z := Nat(1)
- x := xp
- for n > 0 {
- // z * x^n == x^n0
- if n&1 == 1 {
- z = z.Mul(x)
- }
- x, n = x.Mul(x), n/2
- }
- return z
-}
-
-
-// MulRange computes the product of all the unsigned integers
-// in the range [a, b] inclusively.
-//
-func MulRange(a, b uint) Natural {
- switch {
- case a > b:
- return Nat(1)
- case a == b:
- return Nat(uint64(a))
- case a+1 == b:
- return Nat(uint64(a)).Mul(Nat(uint64(b)))
- }
- m := (a + b) >> 1
- assert(a <= m && m < b)
- return MulRange(a, m).Mul(MulRange(m+1, b))
-}
-
-
-// Fact computes the factorial of n (Fact(n) == MulRange(2, n)).
-//
-func Fact(n uint) Natural {
- // Using MulRange() instead of the basic for-loop
- // lead to faster factorial computation.
- return MulRange(2, n)
-}
-
-
-// Binomial computes the binomial coefficient of (n, k).
-//
-func Binomial(n, k uint) Natural { return MulRange(n-k+1, n).Div(MulRange(1, k)) }
-
-
-// Gcd computes the gcd of x and y.
-//
-func (x Natural) Gcd(y Natural) Natural {
- // Euclidean algorithm.
- a, b := x, y
- for !b.IsZero() {
- a, b = b, a.Mod(b)
- }
- return a
-}
diff --git a/src/pkg/exp/bignum/bignum_test.go b/src/pkg/exp/bignum/bignum_test.go
deleted file mode 100644
index 8db93aa96..000000000
--- a/src/pkg/exp/bignum/bignum_test.go
+++ /dev/null
@@ -1,681 +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 bignum
-
-import (
- "fmt"
- "testing"
-)
-
-const (
- sa = "991"
- sb = "2432902008176640000" // 20!
- sc = "933262154439441526816992388562667004907159682643816214685929" +
- "638952175999932299156089414639761565182862536979208272237582" +
- "51185210916864000000000000000000000000" // 100!
- sp = "170141183460469231731687303715884105727" // prime
-)
-
-func natFromString(s string, base uint, slen *int) Natural {
- x, _, len := NatFromString(s, base)
- if slen != nil {
- *slen = len
- }
- return x
-}
-
-
-func intFromString(s string, base uint, slen *int) *Integer {
- x, _, len := IntFromString(s, base)
- if slen != nil {
- *slen = len
- }
- return x
-}
-
-
-func ratFromString(s string, base uint, slen *int) *Rational {
- x, _, len := RatFromString(s, base)
- if slen != nil {
- *slen = len
- }
- return x
-}
-
-
-var (
- nat_zero = Nat(0)
- nat_one = Nat(1)
- nat_two = Nat(2)
- a = natFromString(sa, 10, nil)
- b = natFromString(sb, 10, nil)
- c = natFromString(sc, 10, nil)
- p = natFromString(sp, 10, nil)
- int_zero = Int(0)
- int_one = Int(1)
- int_two = Int(2)
- ip = intFromString(sp, 10, nil)
- rat_zero = Rat(0, 1)
- rat_half = Rat(1, 2)
- rat_one = Rat(1, 1)
- rat_two = Rat(2, 1)
-)
-
-
-var test_msg string
-var tester *testing.T
-
-func test(n uint, b bool) {
- if !b {
- tester.Fatalf("TEST failed: %s (%d)", test_msg, n)
- }
-}
-
-
-func nat_eq(n uint, x, y Natural) {
- if x.Cmp(y) != 0 {
- tester.Fatalf("TEST failed: %s (%d)\nx = %v\ny = %v", test_msg, n, &x, &y)
- }
-}
-
-
-func int_eq(n uint, x, y *Integer) {
- if x.Cmp(y) != 0 {
- tester.Fatalf("TEST failed: %s (%d)\nx = %v\ny = %v", test_msg, n, x, y)
- }
-}
-
-
-func rat_eq(n uint, x, y *Rational) {
- if x.Cmp(y) != 0 {
- tester.Fatalf("TEST failed: %s (%d)\nx = %v\ny = %v", test_msg, n, x, y)
- }
-}
-
-
-func TestNatConv(t *testing.T) {
- tester = t
- test_msg = "NatConvA"
- type entry1 struct {
- x uint64
- s string
- }
- tab := []entry1{
- entry1{0, "0"},
- entry1{255, "255"},
- entry1{65535, "65535"},
- entry1{4294967295, "4294967295"},
- entry1{18446744073709551615, "18446744073709551615"},
- }
- for i, e := range tab {
- test(100+uint(i), Nat(e.x).String() == e.s)
- test(200+uint(i), natFromString(e.s, 0, nil).Value() == e.x)
- }
-
- test_msg = "NatConvB"
- for i := uint(0); i < 100; i++ {
- test(i, Nat(uint64(i)).String() == fmt.Sprintf("%d", i))
- }
-
- test_msg = "NatConvC"
- z := uint64(7)
- for i := uint(0); i <= 64; i++ {
- test(i, Nat(z).Value() == z)
- z <<= 1
- }
-
- test_msg = "NatConvD"
- nat_eq(0, a, Nat(991))
- nat_eq(1, b, Fact(20))
- nat_eq(2, c, Fact(100))
- test(3, a.String() == sa)
- test(4, b.String() == sb)
- test(5, c.String() == sc)
-
- test_msg = "NatConvE"
- var slen int
- nat_eq(10, natFromString("0", 0, nil), nat_zero)
- nat_eq(11, natFromString("123", 0, nil), Nat(123))
- nat_eq(12, natFromString("077", 0, nil), Nat(7*8+7))
- nat_eq(13, natFromString("0x1f", 0, nil), Nat(1*16+15))
- nat_eq(14, natFromString("0x1fg", 0, &slen), Nat(1*16+15))
- test(4, slen == 4)
-
- test_msg = "NatConvF"
- tmp := c.Mul(c)
- for base := uint(2); base <= 16; base++ {
- nat_eq(base, natFromString(tmp.ToString(base), base, nil), tmp)
- }
-
- test_msg = "NatConvG"
- x := Nat(100)
- y, _, _ := NatFromString(fmt.Sprintf("%b", &x), 2)
- nat_eq(100, y, x)
-}
-
-
-func abs(x int64) uint64 {
- if x < 0 {
- x = -x
- }
- return uint64(x)
-}
-
-
-func TestIntConv(t *testing.T) {
- tester = t
- test_msg = "IntConvA"
- type entry2 struct {
- x int64
- s string
- }
- tab := []entry2{
- entry2{0, "0"},
- entry2{-128, "-128"},
- entry2{127, "127"},
- entry2{-32768, "-32768"},
- entry2{32767, "32767"},
- entry2{-2147483648, "-2147483648"},
- entry2{2147483647, "2147483647"},
- entry2{-9223372036854775808, "-9223372036854775808"},
- entry2{9223372036854775807, "9223372036854775807"},
- }
- for i, e := range tab {
- test(100+uint(i), Int(e.x).String() == e.s)
- test(200+uint(i), intFromString(e.s, 0, nil).Value() == e.x)
- test(300+uint(i), Int(e.x).Abs().Value() == abs(e.x))
- }
-
- test_msg = "IntConvB"
- var slen int
- int_eq(0, intFromString("0", 0, nil), int_zero)
- int_eq(1, intFromString("-0", 0, nil), int_zero)
- int_eq(2, intFromString("123", 0, nil), Int(123))
- int_eq(3, intFromString("-123", 0, nil), Int(-123))
- int_eq(4, intFromString("077", 0, nil), Int(7*8+7))
- int_eq(5, intFromString("-077", 0, nil), Int(-(7*8 + 7)))
- int_eq(6, intFromString("0x1f", 0, nil), Int(1*16+15))
- int_eq(7, intFromString("-0x1f", 0, &slen), Int(-(1*16 + 15)))
- test(7, slen == 5)
- int_eq(8, intFromString("+0x1f", 0, &slen), Int(+(1*16 + 15)))
- test(8, slen == 5)
- int_eq(9, intFromString("0x1fg", 0, &slen), Int(1*16+15))
- test(9, slen == 4)
- int_eq(10, intFromString("-0x1fg", 0, &slen), Int(-(1*16 + 15)))
- test(10, slen == 5)
-}
-
-
-func TestRatConv(t *testing.T) {
- tester = t
- test_msg = "RatConv"
- var slen int
- rat_eq(0, ratFromString("0", 0, nil), rat_zero)
- rat_eq(1, ratFromString("0/1", 0, nil), rat_zero)
- rat_eq(2, ratFromString("0/01", 0, nil), rat_zero)
- rat_eq(3, ratFromString("0x14/10", 0, &slen), rat_two)
- test(4, slen == 7)
- rat_eq(5, ratFromString("0.", 0, nil), rat_zero)
- rat_eq(6, ratFromString("0.001f", 10, nil), Rat(1, 1000))
- rat_eq(7, ratFromString(".1", 0, nil), Rat(1, 10))
- rat_eq(8, ratFromString("10101.0101", 2, nil), Rat(0x155, 1<<4))
- rat_eq(9, ratFromString("-0003.145926", 10, &slen), Rat(-3145926, 1000000))
- test(10, slen == 12)
- rat_eq(11, ratFromString("1e2", 0, nil), Rat(100, 1))
- rat_eq(12, ratFromString("1e-2", 0, nil), Rat(1, 100))
- rat_eq(13, ratFromString("1.1e2", 0, nil), Rat(110, 1))
- rat_eq(14, ratFromString(".1e2x", 0, &slen), Rat(10, 1))
- test(15, slen == 4)
-}
-
-
-func add(x, y Natural) Natural {
- z1 := x.Add(y)
- z2 := y.Add(x)
- if z1.Cmp(z2) != 0 {
- tester.Fatalf("addition not symmetric:\n\tx = %v\n\ty = %t", x, y)
- }
- return z1
-}
-
-
-func sum(n uint64, scale Natural) Natural {
- s := nat_zero
- for ; n > 0; n-- {
- s = add(s, Nat(n).Mul(scale))
- }
- return s
-}
-
-
-func TestNatAdd(t *testing.T) {
- tester = t
- test_msg = "NatAddA"
- nat_eq(0, add(nat_zero, nat_zero), nat_zero)
- nat_eq(1, add(nat_zero, c), c)
-
- test_msg = "NatAddB"
- for i := uint64(0); i < 100; i++ {
- t := Nat(i)
- nat_eq(uint(i), sum(i, c), t.Mul(t).Add(t).Shr(1).Mul(c))
- }
-}
-
-
-func mul(x, y Natural) Natural {
- z1 := x.Mul(y)
- z2 := y.Mul(x)
- if z1.Cmp(z2) != 0 {
- tester.Fatalf("multiplication not symmetric:\n\tx = %v\n\ty = %t", x, y)
- }
- if !x.IsZero() && z1.Div(x).Cmp(y) != 0 {
- tester.Fatalf("multiplication/division not inverse (A):\n\tx = %v\n\ty = %t", x, y)
- }
- if !y.IsZero() && z1.Div(y).Cmp(x) != 0 {
- tester.Fatalf("multiplication/division not inverse (B):\n\tx = %v\n\ty = %t", x, y)
- }
- return z1
-}
-
-
-func TestNatSub(t *testing.T) {
- tester = t
- test_msg = "NatSubA"
- nat_eq(0, nat_zero.Sub(nat_zero), nat_zero)
- nat_eq(1, c.Sub(nat_zero), c)
-
- test_msg = "NatSubB"
- for i := uint64(0); i < 100; i++ {
- t := sum(i, c)
- for j := uint64(0); j <= i; j++ {
- t = t.Sub(mul(Nat(j), c))
- }
- nat_eq(uint(i), t, nat_zero)
- }
-}
-
-
-func TestNatMul(t *testing.T) {
- tester = t
- test_msg = "NatMulA"
- nat_eq(0, mul(c, nat_zero), nat_zero)
- nat_eq(1, mul(c, nat_one), c)
-
- test_msg = "NatMulB"
- nat_eq(0, b.Mul(MulRange(0, 100)), nat_zero)
- nat_eq(1, b.Mul(MulRange(21, 100)), c)
-
- test_msg = "NatMulC"
- const n = 100
- p := b.Mul(c).Shl(n)
- for i := uint(0); i < n; i++ {
- nat_eq(i, mul(b.Shl(i), c.Shl(n-i)), p)
- }
-}
-
-
-func TestNatDiv(t *testing.T) {
- tester = t
- test_msg = "NatDivA"
- nat_eq(0, c.Div(nat_one), c)
- nat_eq(1, c.Div(Nat(100)), Fact(99))
- nat_eq(2, b.Div(c), nat_zero)
- nat_eq(4, nat_one.Shl(100).Div(nat_one.Shl(90)), nat_one.Shl(10))
- nat_eq(5, c.Div(b), MulRange(21, 100))
-
- test_msg = "NatDivB"
- const n = 100
- p := Fact(n)
- for i := uint(0); i < n; i++ {
- nat_eq(100+i, p.Div(MulRange(1, i)), MulRange(i+1, n))
- }
-
- // a specific test case that exposed a bug in package big
- test_msg = "NatDivC"
- x := natFromString("69720375229712477164533808935312303556800", 10, nil)
- y := natFromString("3099044504245996706400", 10, nil)
- q := natFromString("22497377864108980962", 10, nil)
- r := natFromString("0", 10, nil)
- qc, rc := x.DivMod(y)
- nat_eq(0, q, qc)
- nat_eq(1, r, rc)
-}
-
-
-func TestIntQuoRem(t *testing.T) {
- tester = t
- test_msg = "IntQuoRem"
- type T struct {
- x, y, q, r int64
- }
- a := []T{
- T{+8, +3, +2, +2},
- T{+8, -3, -2, +2},
- T{-8, +3, -2, -2},
- T{-8, -3, +2, -2},
- T{+1, +2, 0, +1},
- T{+1, -2, 0, +1},
- T{-1, +2, 0, -1},
- T{-1, -2, 0, -1},
- }
- for i := uint(0); i < uint(len(a)); i++ {
- e := &a[i]
- x, y := Int(e.x).Mul(ip), Int(e.y).Mul(ip)
- q, r := Int(e.q), Int(e.r).Mul(ip)
- qq, rr := x.QuoRem(y)
- int_eq(4*i+0, x.Quo(y), q)
- int_eq(4*i+1, x.Rem(y), r)
- int_eq(4*i+2, qq, q)
- int_eq(4*i+3, rr, r)
- }
-}
-
-
-func TestIntDivMod(t *testing.T) {
- tester = t
- test_msg = "IntDivMod"
- type T struct {
- x, y, q, r int64
- }
- a := []T{
- T{+8, +3, +2, +2},
- T{+8, -3, -2, +2},
- T{-8, +3, -3, +1},
- T{-8, -3, +3, +1},
- T{+1, +2, 0, +1},
- T{+1, -2, 0, +1},
- T{-1, +2, -1, +1},
- T{-1, -2, +1, +1},
- }
- for i := uint(0); i < uint(len(a)); i++ {
- e := &a[i]
- x, y := Int(e.x).Mul(ip), Int(e.y).Mul(ip)
- q, r := Int(e.q), Int(e.r).Mul(ip)
- qq, rr := x.DivMod(y)
- int_eq(4*i+0, x.Div(y), q)
- int_eq(4*i+1, x.Mod(y), r)
- int_eq(4*i+2, qq, q)
- int_eq(4*i+3, rr, r)
- }
-}
-
-
-func TestNatMod(t *testing.T) {
- tester = t
- test_msg = "NatModA"
- for i := uint(0); ; i++ {
- d := nat_one.Shl(i)
- if d.Cmp(c) < 0 {
- nat_eq(i, c.Add(d).Mod(c), d)
- } else {
- nat_eq(i, c.Add(d).Div(c), nat_two)
- nat_eq(i, c.Add(d).Mod(c), d.Sub(c))
- break
- }
- }
-}
-
-
-func TestNatShift(t *testing.T) {
- tester = t
- test_msg = "NatShift1L"
- test(0, b.Shl(0).Cmp(b) == 0)
- test(1, c.Shl(1).Cmp(c) > 0)
-
- test_msg = "NatShift1R"
- test(3, b.Shr(0).Cmp(b) == 0)
- test(4, c.Shr(1).Cmp(c) < 0)
-
- test_msg = "NatShift2"
- for i := uint(0); i < 100; i++ {
- test(i, c.Shl(i).Shr(i).Cmp(c) == 0)
- }
-
- test_msg = "NatShift3L"
- {
- const m = 3
- p := b
- f := Nat(1 << m)
- for i := uint(0); i < 100; i++ {
- nat_eq(i, b.Shl(i*m), p)
- p = mul(p, f)
- }
- }
-
- test_msg = "NatShift3R"
- {
- p := c
- for i := uint(0); !p.IsZero(); i++ {
- nat_eq(i, c.Shr(i), p)
- p = p.Shr(1)
- }
- }
-}
-
-
-func TestIntShift(t *testing.T) {
- tester = t
- test_msg = "IntShift1L"
- test(0, ip.Shl(0).Cmp(ip) == 0)
- test(1, ip.Shl(1).Cmp(ip) > 0)
-
- test_msg = "IntShift1R"
- test(0, ip.Shr(0).Cmp(ip) == 0)
- test(1, ip.Shr(1).Cmp(ip) < 0)
-
- test_msg = "IntShift2"
- for i := uint(0); i < 100; i++ {
- test(i, ip.Shl(i).Shr(i).Cmp(ip) == 0)
- }
-
- test_msg = "IntShift3L"
- {
- const m = 3
- p := ip
- f := Int(1 << m)
- for i := uint(0); i < 100; i++ {
- int_eq(i, ip.Shl(i*m), p)
- p = p.Mul(f)
- }
- }
-
- test_msg = "IntShift3R"
- {
- p := ip
- for i := uint(0); p.IsPos(); i++ {
- int_eq(i, ip.Shr(i), p)
- p = p.Shr(1)
- }
- }
-
- test_msg = "IntShift4R"
- int_eq(0, Int(-43).Shr(1), Int(-43>>1))
- int_eq(0, Int(-1024).Shr(100), Int(-1))
- int_eq(1, ip.Neg().Shr(10), ip.Neg().Div(Int(1).Shl(10)))
-}
-
-
-func TestNatBitOps(t *testing.T) {
- tester = t
-
- x := uint64(0xf08e6f56bd8c3941)
- y := uint64(0x3984ef67834bc)
-
- bx := Nat(x)
- by := Nat(y)
-
- test_msg = "NatAnd"
- bz := Nat(x & y)
- for i := uint(0); i < 100; i++ {
- nat_eq(i, bx.Shl(i).And(by.Shl(i)), bz.Shl(i))
- }
-
- test_msg = "NatAndNot"
- bz = Nat(x &^ y)
- for i := uint(0); i < 100; i++ {
- nat_eq(i, bx.Shl(i).AndNot(by.Shl(i)), bz.Shl(i))
- }
-
- test_msg = "NatOr"
- bz = Nat(x | y)
- for i := uint(0); i < 100; i++ {
- nat_eq(i, bx.Shl(i).Or(by.Shl(i)), bz.Shl(i))
- }
-
- test_msg = "NatXor"
- bz = Nat(x ^ y)
- for i := uint(0); i < 100; i++ {
- nat_eq(i, bx.Shl(i).Xor(by.Shl(i)), bz.Shl(i))
- }
-}
-
-
-func TestIntBitOps1(t *testing.T) {
- tester = t
- test_msg = "IntBitOps1"
- type T struct {
- x, y int64
- }
- a := []T{
- T{+7, +3},
- T{+7, -3},
- T{-7, +3},
- T{-7, -3},
- }
- for i := uint(0); i < uint(len(a)); i++ {
- e := &a[i]
- int_eq(4*i+0, Int(e.x).And(Int(e.y)), Int(e.x&e.y))
- int_eq(4*i+1, Int(e.x).AndNot(Int(e.y)), Int(e.x&^e.y))
- int_eq(4*i+2, Int(e.x).Or(Int(e.y)), Int(e.x|e.y))
- int_eq(4*i+3, Int(e.x).Xor(Int(e.y)), Int(e.x^e.y))
- }
-}
-
-
-func TestIntBitOps2(t *testing.T) {
- tester = t
-
- test_msg = "IntNot"
- int_eq(0, Int(-2).Not(), Int(1))
- int_eq(0, Int(-1).Not(), Int(0))
- int_eq(0, Int(0).Not(), Int(-1))
- int_eq(0, Int(1).Not(), Int(-2))
- int_eq(0, Int(2).Not(), Int(-3))
-
- test_msg = "IntAnd"
- for x := int64(-15); x < 5; x++ {
- bx := Int(x)
- for y := int64(-5); y < 15; y++ {
- by := Int(y)
- for i := uint(50); i < 70; i++ { // shift across 64bit boundary
- int_eq(i, bx.Shl(i).And(by.Shl(i)), Int(x&y).Shl(i))
- }
- }
- }
-
- test_msg = "IntAndNot"
- for x := int64(-15); x < 5; x++ {
- bx := Int(x)
- for y := int64(-5); y < 15; y++ {
- by := Int(y)
- for i := uint(50); i < 70; i++ { // shift across 64bit boundary
- int_eq(2*i+0, bx.Shl(i).AndNot(by.Shl(i)), Int(x&^y).Shl(i))
- int_eq(2*i+1, bx.Shl(i).And(by.Shl(i).Not()), Int(x&^y).Shl(i))
- }
- }
- }
-
- test_msg = "IntOr"
- for x := int64(-15); x < 5; x++ {
- bx := Int(x)
- for y := int64(-5); y < 15; y++ {
- by := Int(y)
- for i := uint(50); i < 70; i++ { // shift across 64bit boundary
- int_eq(i, bx.Shl(i).Or(by.Shl(i)), Int(x|y).Shl(i))
- }
- }
- }
-
- test_msg = "IntXor"
- for x := int64(-15); x < 5; x++ {
- bx := Int(x)
- for y := int64(-5); y < 15; y++ {
- by := Int(y)
- for i := uint(50); i < 70; i++ { // shift across 64bit boundary
- int_eq(i, bx.Shl(i).Xor(by.Shl(i)), Int(x^y).Shl(i))
- }
- }
- }
-}
-
-
-func TestNatCmp(t *testing.T) {
- tester = t
- test_msg = "NatCmp"
- test(0, a.Cmp(a) == 0)
- test(1, a.Cmp(b) < 0)
- test(2, b.Cmp(a) > 0)
- test(3, a.Cmp(c) < 0)
- d := c.Add(b)
- test(4, c.Cmp(d) < 0)
- test(5, d.Cmp(c) > 0)
-}
-
-
-func TestNatLog2(t *testing.T) {
- tester = t
- test_msg = "NatLog2A"
- test(0, nat_one.Log2() == 0)
- test(1, nat_two.Log2() == 1)
- test(2, Nat(3).Log2() == 1)
- test(3, Nat(4).Log2() == 2)
-
- test_msg = "NatLog2B"
- for i := uint(0); i < 100; i++ {
- test(i, nat_one.Shl(i).Log2() == i)
- }
-}
-
-
-func TestNatGcd(t *testing.T) {
- tester = t
- test_msg = "NatGcdA"
- f := Nat(99991)
- nat_eq(0, b.Mul(f).Gcd(c.Mul(f)), MulRange(1, 20).Mul(f))
-}
-
-
-func TestNatPow(t *testing.T) {
- tester = t
- test_msg = "NatPowA"
- nat_eq(0, nat_two.Pow(0), nat_one)
-
- test_msg = "NatPowB"
- for i := uint(0); i < 100; i++ {
- nat_eq(i, nat_two.Pow(i), nat_one.Shl(i))
- }
-}
-
-
-func TestNatPop(t *testing.T) {
- tester = t
- test_msg = "NatPopA"
- test(0, nat_zero.Pop() == 0)
- test(1, nat_one.Pop() == 1)
- test(2, Nat(10).Pop() == 2)
- test(3, Nat(30).Pop() == 4)
- test(4, Nat(0x1248f).Shl(33).Pop() == 8)
-
- test_msg = "NatPopB"
- for i := uint(0); i < 100; i++ {
- test(i, nat_one.Shl(i).Sub(nat_one).Pop() == i)
- }
-}
-
-
-func TestIssue571(t *testing.T) {
- const min_float = "4.940656458412465441765687928682213723651e-324"
- RatFromString(min_float, 10) // this must not crash
-}
diff --git a/src/pkg/exp/bignum/integer.go b/src/pkg/exp/bignum/integer.go
deleted file mode 100644
index a8d26829d..000000000
--- a/src/pkg/exp/bignum/integer.go
+++ /dev/null
@@ -1,520 +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.
-
-// Integer numbers
-//
-// Integers are normalized if the mantissa is normalized and the sign is
-// false for mant == 0. Use MakeInt to create normalized Integers.
-
-package bignum
-
-import (
- "fmt"
-)
-
-// TODO(gri) Complete the set of in-place operations.
-
-// Integer represents a signed integer value of arbitrary precision.
-//
-type Integer struct {
- sign bool
- mant Natural
-}
-
-
-// MakeInt makes an integer given a sign and a mantissa.
-// The number is positive (>= 0) if sign is false or the
-// mantissa is zero; it is negative otherwise.
-//
-func MakeInt(sign bool, mant Natural) *Integer {
- if mant.IsZero() {
- sign = false // normalize
- }
- return &Integer{sign, mant}
-}
-
-
-// Int creates a small integer with value x.
-//
-func Int(x int64) *Integer {
- var ux uint64
- if x < 0 {
- // For the most negative x, -x == x, and
- // the bit pattern has the correct value.
- ux = uint64(-x)
- } else {
- ux = uint64(x)
- }
- return MakeInt(x < 0, Nat(ux))
-}
-
-
-// Value returns the value of x, if x fits into an int64;
-// otherwise the result is undefined.
-//
-func (x *Integer) Value() int64 {
- z := int64(x.mant.Value())
- if x.sign {
- z = -z
- }
- return z
-}
-
-
-// Abs returns the absolute value of x.
-//
-func (x *Integer) Abs() Natural { return x.mant }
-
-
-// Predicates
-
-// IsEven returns true iff x is divisible by 2.
-//
-func (x *Integer) IsEven() bool { return x.mant.IsEven() }
-
-
-// IsOdd returns true iff x is not divisible by 2.
-//
-func (x *Integer) IsOdd() bool { return x.mant.IsOdd() }
-
-
-// IsZero returns true iff x == 0.
-//
-func (x *Integer) IsZero() bool { return x.mant.IsZero() }
-
-
-// IsNeg returns true iff x < 0.
-//
-func (x *Integer) IsNeg() bool { return x.sign && !x.mant.IsZero() }
-
-
-// IsPos returns true iff x >= 0.
-//
-func (x *Integer) IsPos() bool { return !x.sign && !x.mant.IsZero() }
-
-
-// Operations
-
-// Neg returns the negated value of x.
-//
-func (x *Integer) Neg() *Integer { return MakeInt(!x.sign, x.mant) }
-
-
-// Iadd sets z to the sum x + y.
-// z must exist and may be x or y.
-//
-func Iadd(z, x, y *Integer) {
- if x.sign == y.sign {
- // x + y == x + y
- // (-x) + (-y) == -(x + y)
- z.sign = x.sign
- Nadd(&z.mant, x.mant, y.mant)
- } else {
- // x + (-y) == x - y == -(y - x)
- // (-x) + y == y - x == -(x - y)
- if x.mant.Cmp(y.mant) >= 0 {
- z.sign = x.sign
- Nsub(&z.mant, x.mant, y.mant)
- } else {
- z.sign = !x.sign
- Nsub(&z.mant, y.mant, x.mant)
- }
- }
-}
-
-
-// Add returns the sum x + y.
-//
-func (x *Integer) Add(y *Integer) *Integer {
- var z Integer
- Iadd(&z, x, y)
- return &z
-}
-
-
-func Isub(z, x, y *Integer) {
- if x.sign != y.sign {
- // x - (-y) == x + y
- // (-x) - y == -(x + y)
- z.sign = x.sign
- Nadd(&z.mant, x.mant, y.mant)
- } else {
- // x - y == x - y == -(y - x)
- // (-x) - (-y) == y - x == -(x - y)
- if x.mant.Cmp(y.mant) >= 0 {
- z.sign = x.sign
- Nsub(&z.mant, x.mant, y.mant)
- } else {
- z.sign = !x.sign
- Nsub(&z.mant, y.mant, x.mant)
- }
- }
-}
-
-
-// Sub returns the difference x - y.
-//
-func (x *Integer) Sub(y *Integer) *Integer {
- var z Integer
- Isub(&z, x, y)
- return &z
-}
-
-
-// Nscale sets *z to the scaled value (*z) * d.
-//
-func Iscale(z *Integer, d int64) {
- f := uint64(d)
- if d < 0 {
- f = uint64(-d)
- }
- z.sign = z.sign != (d < 0)
- Nscale(&z.mant, f)
-}
-
-
-// Mul1 returns the product x * d.
-//
-func (x *Integer) Mul1(d int64) *Integer {
- f := uint64(d)
- if d < 0 {
- f = uint64(-d)
- }
- return MakeInt(x.sign != (d < 0), x.mant.Mul1(f))
-}
-
-
-// Mul returns the product x * y.
-//
-func (x *Integer) Mul(y *Integer) *Integer {
- // x * y == x * y
- // x * (-y) == -(x * y)
- // (-x) * y == -(x * y)
- // (-x) * (-y) == x * y
- return MakeInt(x.sign != y.sign, x.mant.Mul(y.mant))
-}
-
-
-// MulNat returns the product x * y, where y is a (unsigned) natural number.
-//
-func (x *Integer) MulNat(y Natural) *Integer {
- // x * y == x * y
- // (-x) * y == -(x * y)
- return MakeInt(x.sign, x.mant.Mul(y))
-}
-
-
-// Quo returns the quotient q = x / y for y != 0.
-// If y == 0, a division-by-zero run-time error occurs.
-//
-// Quo and Rem implement T-division and modulus (like C99):
-//
-// q = x.Quo(y) = trunc(x/y) (truncation towards zero)
-// r = x.Rem(y) = x - y*q
-//
-// (Daan Leijen, ``Division and Modulus for Computer Scientists''.)
-//
-func (x *Integer) Quo(y *Integer) *Integer {
- // x / y == x / y
- // x / (-y) == -(x / y)
- // (-x) / y == -(x / y)
- // (-x) / (-y) == x / y
- return MakeInt(x.sign != y.sign, x.mant.Div(y.mant))
-}
-
-
-// Rem returns the remainder r of the division x / y for y != 0,
-// with r = x - y*x.Quo(y). Unless r is zero, its sign corresponds
-// to the sign of x.
-// If y == 0, a division-by-zero run-time error occurs.
-//
-func (x *Integer) Rem(y *Integer) *Integer {
- // x % y == x % y
- // x % (-y) == x % y
- // (-x) % y == -(x % y)
- // (-x) % (-y) == -(x % y)
- return MakeInt(x.sign, x.mant.Mod(y.mant))
-}
-
-
-// QuoRem returns the pair (x.Quo(y), x.Rem(y)) for y != 0.
-// If y == 0, a division-by-zero run-time error occurs.
-//
-func (x *Integer) QuoRem(y *Integer) (*Integer, *Integer) {
- q, r := x.mant.DivMod(y.mant)
- return MakeInt(x.sign != y.sign, q), MakeInt(x.sign, r)
-}
-
-
-// Div returns the quotient q = x / y for y != 0.
-// If y == 0, a division-by-zero run-time error occurs.
-//
-// Div and Mod implement Euclidian division and modulus:
-//
-// q = x.Div(y)
-// r = x.Mod(y) with: 0 <= r < |q| and: x = y*q + r
-//
-// (Raymond T. Boute, ``The Euclidian definition of the functions
-// div and mod''. ACM Transactions on Programming Languages and
-// Systems (TOPLAS), 14(2):127-144, New York, NY, USA, 4/1992.
-// ACM press.)
-//
-func (x *Integer) Div(y *Integer) *Integer {
- q, r := x.QuoRem(y)
- if r.IsNeg() {
- if y.IsPos() {
- q = q.Sub(Int(1))
- } else {
- q = q.Add(Int(1))
- }
- }
- return q
-}
-
-
-// Mod returns the modulus r of the division x / y for y != 0,
-// with r = x - y*x.Div(y). r is always positive.
-// If y == 0, a division-by-zero run-time error occurs.
-//
-func (x *Integer) Mod(y *Integer) *Integer {
- r := x.Rem(y)
- if r.IsNeg() {
- if y.IsPos() {
- r = r.Add(y)
- } else {
- r = r.Sub(y)
- }
- }
- return r
-}
-
-
-// DivMod returns the pair (x.Div(y), x.Mod(y)).
-//
-func (x *Integer) DivMod(y *Integer) (*Integer, *Integer) {
- q, r := x.QuoRem(y)
- if r.IsNeg() {
- if y.IsPos() {
- q = q.Sub(Int(1))
- r = r.Add(y)
- } else {
- q = q.Add(Int(1))
- r = r.Sub(y)
- }
- }
- return q, r
-}
-
-
-// Shl implements ``shift left'' x << s. It returns x * 2^s.
-//
-func (x *Integer) Shl(s uint) *Integer { return MakeInt(x.sign, x.mant.Shl(s)) }
-
-
-// The bitwise operations on integers are defined on the 2's-complement
-// representation of integers. From
-//
-// -x == ^x + 1 (1) 2's complement representation
-//
-// follows:
-//
-// -(x) == ^(x) + 1
-// -(-x) == ^(-x) + 1
-// x-1 == ^(-x)
-// ^(x-1) == -x (2)
-//
-// Using (1) and (2), operations on negative integers of the form -x are
-// converted to operations on negated positive integers of the form ~(x-1).
-
-
-// Shr implements ``shift right'' x >> s. It returns x / 2^s.
-//
-func (x *Integer) Shr(s uint) *Integer {
- if x.sign {
- // (-x) >> s == ^(x-1) >> s == ^((x-1) >> s) == -(((x-1) >> s) + 1)
- return MakeInt(true, x.mant.Sub(Nat(1)).Shr(s).Add(Nat(1)))
- }
-
- return MakeInt(false, x.mant.Shr(s))
-}
-
-
-// Not returns the ``bitwise not'' ^x for the 2's-complement representation of x.
-func (x *Integer) Not() *Integer {
- if x.sign {
- // ^(-x) == ^(^(x-1)) == x-1
- return MakeInt(false, x.mant.Sub(Nat(1)))
- }
-
- // ^x == -x-1 == -(x+1)
- return MakeInt(true, x.mant.Add(Nat(1)))
-}
-
-
-// And returns the ``bitwise and'' x & y for the 2's-complement representation of x and y.
-//
-func (x *Integer) And(y *Integer) *Integer {
- if x.sign == y.sign {
- if x.sign {
- // (-x) & (-y) == ^(x-1) & ^(y-1) == ^((x-1) | (y-1)) == -(((x-1) | (y-1)) + 1)
- return MakeInt(true, x.mant.Sub(Nat(1)).Or(y.mant.Sub(Nat(1))).Add(Nat(1)))
- }
-
- // x & y == x & y
- return MakeInt(false, x.mant.And(y.mant))
- }
-
- // x.sign != y.sign
- if x.sign {
- x, y = y, x // & is symmetric
- }
-
- // x & (-y) == x & ^(y-1) == x &^ (y-1)
- return MakeInt(false, x.mant.AndNot(y.mant.Sub(Nat(1))))
-}
-
-
-// AndNot returns the ``bitwise clear'' x &^ y for the 2's-complement representation of x and y.
-//
-func (x *Integer) AndNot(y *Integer) *Integer {
- if x.sign == y.sign {
- if x.sign {
- // (-x) &^ (-y) == ^(x-1) &^ ^(y-1) == ^(x-1) & (y-1) == (y-1) &^ (x-1)
- return MakeInt(false, y.mant.Sub(Nat(1)).AndNot(x.mant.Sub(Nat(1))))
- }
-
- // x &^ y == x &^ y
- return MakeInt(false, x.mant.AndNot(y.mant))
- }
-
- if x.sign {
- // (-x) &^ y == ^(x-1) &^ y == ^(x-1) & ^y == ^((x-1) | y) == -(((x-1) | y) + 1)
- return MakeInt(true, x.mant.Sub(Nat(1)).Or(y.mant).Add(Nat(1)))
- }
-
- // x &^ (-y) == x &^ ^(y-1) == x & (y-1)
- return MakeInt(false, x.mant.And(y.mant.Sub(Nat(1))))
-}
-
-
-// Or returns the ``bitwise or'' x | y for the 2's-complement representation of x and y.
-//
-func (x *Integer) Or(y *Integer) *Integer {
- if x.sign == y.sign {
- if x.sign {
- // (-x) | (-y) == ^(x-1) | ^(y-1) == ^((x-1) & (y-1)) == -(((x-1) & (y-1)) + 1)
- return MakeInt(true, x.mant.Sub(Nat(1)).And(y.mant.Sub(Nat(1))).Add(Nat(1)))
- }
-
- // x | y == x | y
- return MakeInt(false, x.mant.Or(y.mant))
- }
-
- // x.sign != y.sign
- if x.sign {
- x, y = y, x // | or symmetric
- }
-
- // x | (-y) == x | ^(y-1) == ^((y-1) &^ x) == -(^((y-1) &^ x) + 1)
- return MakeInt(true, y.mant.Sub(Nat(1)).AndNot(x.mant).Add(Nat(1)))
-}
-
-
-// Xor returns the ``bitwise xor'' x | y for the 2's-complement representation of x and y.
-//
-func (x *Integer) Xor(y *Integer) *Integer {
- if x.sign == y.sign {
- if x.sign {
- // (-x) ^ (-y) == ^(x-1) ^ ^(y-1) == (x-1) ^ (y-1)
- return MakeInt(false, x.mant.Sub(Nat(1)).Xor(y.mant.Sub(Nat(1))))
- }
-
- // x ^ y == x ^ y
- return MakeInt(false, x.mant.Xor(y.mant))
- }
-
- // x.sign != y.sign
- if x.sign {
- x, y = y, x // ^ is symmetric
- }
-
- // x ^ (-y) == x ^ ^(y-1) == ^(x ^ (y-1)) == -((x ^ (y-1)) + 1)
- return MakeInt(true, x.mant.Xor(y.mant.Sub(Nat(1))).Add(Nat(1)))
-}
-
-
-// Cmp compares x and y. The result is an int value that is
-//
-// < 0 if x < y
-// == 0 if x == y
-// > 0 if x > y
-//
-func (x *Integer) Cmp(y *Integer) int {
- // x cmp y == x cmp y
- // x cmp (-y) == x
- // (-x) cmp y == y
- // (-x) cmp (-y) == -(x cmp y)
- var r int
- switch {
- case x.sign == y.sign:
- r = x.mant.Cmp(y.mant)
- if x.sign {
- r = -r
- }
- case x.sign:
- r = -1
- case y.sign:
- r = 1
- }
- return r
-}
-
-
-// ToString converts x to a string for a given base, with 2 <= base <= 16.
-//
-func (x *Integer) ToString(base uint) string {
- if x.mant.IsZero() {
- return "0"
- }
- var s string
- if x.sign {
- s = "-"
- }
- return s + x.mant.ToString(base)
-}
-
-
-// String converts x to its decimal string representation.
-// x.String() is the same as x.ToString(10).
-//
-func (x *Integer) String() string { return x.ToString(10) }
-
-
-// Format is a support routine for fmt.Formatter. It accepts
-// the formats 'b' (binary), 'o' (octal), and 'x' (hexadecimal).
-//
-func (x *Integer) Format(h fmt.State, c int) { fmt.Fprintf(h, "%s", x.ToString(fmtbase(c))) }
-
-
-// IntFromString returns the integer corresponding to the
-// longest possible prefix of s representing an integer in a
-// given conversion base, the actual conversion base used, and
-// the prefix length. The syntax of integers follows the syntax
-// of signed integer literals in Go.
-//
-// If the base argument is 0, the string prefix determines the actual
-// conversion base. A prefix of ``0x'' or ``0X'' selects base 16; the
-// ``0'' prefix selects base 8. Otherwise the selected base is 10.
-//
-func IntFromString(s string, base uint) (*Integer, uint, int) {
- // skip sign, if any
- i0 := 0
- if len(s) > 0 && (s[0] == '-' || s[0] == '+') {
- i0 = 1
- }
-
- mant, base, slen := NatFromString(s[i0:], base)
-
- return MakeInt(i0 > 0 && s[0] == '-', mant), base, i0 + slen
-}
diff --git a/src/pkg/exp/bignum/nrdiv_test.go b/src/pkg/exp/bignum/nrdiv_test.go
deleted file mode 100644
index 725b1acea..000000000
--- a/src/pkg/exp/bignum/nrdiv_test.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.
-
-// This file implements Newton-Raphson division and uses
-// it as an additional test case for bignum.
-//
-// Division of x/y is achieved by computing r = 1/y to
-// obtain the quotient q = x*r = x*(1/y) = x/y. The
-// reciprocal r is the solution for f(x) = 1/x - y and
-// the solution is approximated through iteration. The
-// iteration does not require division.
-
-package bignum
-
-import "testing"
-
-
-// An fpNat is a Natural scaled by a power of two
-// (an unsigned floating point representation). The
-// value of an fpNat x is x.m * 2^x.e .
-//
-type fpNat struct {
- m Natural
- e int
-}
-
-
-// sub computes x - y.
-func (x fpNat) sub(y fpNat) fpNat {
- switch d := x.e - y.e; {
- case d < 0:
- return fpNat{x.m.Sub(y.m.Shl(uint(-d))), x.e}
- case d > 0:
- return fpNat{x.m.Shl(uint(d)).Sub(y.m), y.e}
- }
- return fpNat{x.m.Sub(y.m), x.e}
-}
-
-
-// mul2 computes x*2.
-func (x fpNat) mul2() fpNat { return fpNat{x.m, x.e + 1} }
-
-
-// mul computes x*y.
-func (x fpNat) mul(y fpNat) fpNat { return fpNat{x.m.Mul(y.m), x.e + y.e} }
-
-
-// mant computes the (possibly truncated) Natural representation
-// of an fpNat x.
-//
-func (x fpNat) mant() Natural {
- switch {
- case x.e > 0:
- return x.m.Shl(uint(x.e))
- case x.e < 0:
- return x.m.Shr(uint(-x.e))
- }
- return x.m
-}
-
-
-// nrDivEst computes an estimate of the quotient q = x0/y0 and returns q.
-// q may be too small (usually by 1).
-//
-func nrDivEst(x0, y0 Natural) Natural {
- if y0.IsZero() {
- panic("division by zero")
- return nil
- }
- // y0 > 0
-
- if y0.Cmp(Nat(1)) == 0 {
- return x0
- }
- // y0 > 1
-
- switch d := x0.Cmp(y0); {
- case d < 0:
- return Nat(0)
- case d == 0:
- return Nat(1)
- }
- // x0 > y0 > 1
-
- // Determine maximum result length.
- maxLen := int(x0.Log2() - y0.Log2() + 1)
-
- // In the following, each number x is represented
- // as a mantissa x.m and an exponent x.e such that
- // x = xm * 2^x.e.
- x := fpNat{x0, 0}
- y := fpNat{y0, 0}
-
- // Determine a scale factor f = 2^e such that
- // 0.5 <= y/f == y*(2^-e) < 1.0
- // and scale y accordingly.
- e := int(y.m.Log2()) + 1
- y.e -= e
-
- // t1
- var c = 2.9142
- const n = 14
- t1 := fpNat{Nat(uint64(c * (1 << n))), -n}
-
- // Compute initial value r0 for the reciprocal of y/f.
- // r0 = t1 - 2*y
- r := t1.sub(y.mul2())
- two := fpNat{Nat(2), 0}
-
- // Newton-Raphson iteration
- p := Nat(0)
- for i := 0; ; i++ {
- // check if we are done
- // TODO: Need to come up with a better test here
- // as it will reduce computation time significantly.
- // q = x*r/f
- q := x.mul(r)
- q.e -= e
- res := q.mant()
- if res.Cmp(p) == 0 {
- return res
- }
- p = res
-
- // r' = r*(2 - y*r)
- r = r.mul(two.sub(y.mul(r)))
-
- // reduce mantissa size
- // TODO: Find smaller bound as it will reduce
- // computation time massively.
- d := int(r.m.Log2()+1) - maxLen
- if d > 0 {
- r = fpNat{r.m.Shr(uint(d)), r.e + d}
- }
- }
-
- panic("unreachable")
- return nil
-}
-
-
-func nrdiv(x, y Natural) (q, r Natural) {
- q = nrDivEst(x, y)
- r = x.Sub(y.Mul(q))
- // if r is too large, correct q and r
- // (usually one iteration)
- for r.Cmp(y) >= 0 {
- q = q.Add(Nat(1))
- r = r.Sub(y)
- }
- return
-}
-
-
-func div(t *testing.T, x, y Natural) {
- q, r := nrdiv(x, y)
- qx, rx := x.DivMod(y)
- if q.Cmp(qx) != 0 {
- t.Errorf("x = %s, y = %s, got q = %s, want q = %s", x, y, q, qx)
- }
- if r.Cmp(rx) != 0 {
- t.Errorf("x = %s, y = %s, got r = %s, want r = %s", x, y, r, rx)
- }
-}
-
-
-func idiv(t *testing.T, x0, y0 uint64) { div(t, Nat(x0), Nat(y0)) }
-
-
-func TestNRDiv(t *testing.T) {
- idiv(t, 17, 18)
- idiv(t, 17, 17)
- idiv(t, 17, 1)
- idiv(t, 17, 16)
- idiv(t, 17, 10)
- idiv(t, 17, 9)
- idiv(t, 17, 8)
- idiv(t, 17, 5)
- idiv(t, 17, 3)
- idiv(t, 1025, 512)
- idiv(t, 7489595, 2)
- idiv(t, 5404679459, 78495)
- idiv(t, 7484890589595, 7484890589594)
- div(t, Fact(100), Fact(91))
- div(t, Fact(1000), Fact(991))
- //div(t, Fact(10000), Fact(9991)); // takes too long - disabled for now
-}
diff --git a/src/pkg/exp/bignum/rational.go b/src/pkg/exp/bignum/rational.go
deleted file mode 100644
index 378585e5f..000000000
--- a/src/pkg/exp/bignum/rational.go
+++ /dev/null
@@ -1,205 +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.
-
-// Rational numbers
-
-package bignum
-
-import "fmt"
-
-
-// Rational represents a quotient a/b of arbitrary precision.
-//
-type Rational struct {
- a *Integer // numerator
- b Natural // denominator
-}
-
-
-// MakeRat makes a rational number given a numerator a and a denominator b.
-//
-func MakeRat(a *Integer, b Natural) *Rational {
- f := a.mant.Gcd(b) // f > 0
- if f.Cmp(Nat(1)) != 0 {
- a = MakeInt(a.sign, a.mant.Div(f))
- b = b.Div(f)
- }
- return &Rational{a, b}
-}
-
-
-// Rat creates a small rational number with value a0/b0.
-//
-func Rat(a0 int64, b0 int64) *Rational {
- a, b := Int(a0), Int(b0)
- if b.sign {
- a = a.Neg()
- }
- return MakeRat(a, b.mant)
-}
-
-
-// Value returns the numerator and denominator of x.
-//
-func (x *Rational) Value() (numerator *Integer, denominator Natural) {
- return x.a, x.b
-}
-
-
-// Predicates
-
-// IsZero returns true iff x == 0.
-//
-func (x *Rational) IsZero() bool { return x.a.IsZero() }
-
-
-// IsNeg returns true iff x < 0.
-//
-func (x *Rational) IsNeg() bool { return x.a.IsNeg() }
-
-
-// IsPos returns true iff x > 0.
-//
-func (x *Rational) IsPos() bool { return x.a.IsPos() }
-
-
-// IsInt returns true iff x can be written with a denominator 1
-// in the form x == x'/1; i.e., if x is an integer value.
-//
-func (x *Rational) IsInt() bool { return x.b.Cmp(Nat(1)) == 0 }
-
-
-// Operations
-
-// Neg returns the negated value of x.
-//
-func (x *Rational) Neg() *Rational { return MakeRat(x.a.Neg(), x.b) }
-
-
-// Add returns the sum x + y.
-//
-func (x *Rational) Add(y *Rational) *Rational {
- return MakeRat((x.a.MulNat(y.b)).Add(y.a.MulNat(x.b)), x.b.Mul(y.b))
-}
-
-
-// Sub returns the difference x - y.
-//
-func (x *Rational) Sub(y *Rational) *Rational {
- return MakeRat((x.a.MulNat(y.b)).Sub(y.a.MulNat(x.b)), x.b.Mul(y.b))
-}
-
-
-// Mul returns the product x * y.
-//
-func (x *Rational) Mul(y *Rational) *Rational { return MakeRat(x.a.Mul(y.a), x.b.Mul(y.b)) }
-
-
-// Quo returns the quotient x / y for y != 0.
-// If y == 0, a division-by-zero run-time error occurs.
-//
-func (x *Rational) Quo(y *Rational) *Rational {
- a := x.a.MulNat(y.b)
- b := y.a.MulNat(x.b)
- if b.IsNeg() {
- a = a.Neg()
- }
- return MakeRat(a, b.mant)
-}
-
-
-// Cmp compares x and y. The result is an int value
-//
-// < 0 if x < y
-// == 0 if x == y
-// > 0 if x > y
-//
-func (x *Rational) Cmp(y *Rational) int { return (x.a.MulNat(y.b)).Cmp(y.a.MulNat(x.b)) }
-
-
-// ToString converts x to a string for a given base, with 2 <= base <= 16.
-// The string representation is of the form "n" if x is an integer; otherwise
-// it is of form "n/d".
-//
-func (x *Rational) ToString(base uint) string {
- s := x.a.ToString(base)
- if !x.IsInt() {
- s += "/" + x.b.ToString(base)
- }
- return s
-}
-
-
-// String converts x to its decimal string representation.
-// x.String() is the same as x.ToString(10).
-//
-func (x *Rational) String() string { return x.ToString(10) }
-
-
-// Format is a support routine for fmt.Formatter. It accepts
-// the formats 'b' (binary), 'o' (octal), and 'x' (hexadecimal).
-//
-func (x *Rational) Format(h fmt.State, c int) { fmt.Fprintf(h, "%s", x.ToString(fmtbase(c))) }
-
-
-// RatFromString returns the rational number corresponding to the
-// longest possible prefix of s representing a rational number in a
-// given conversion base, the actual conversion base used, and the
-// prefix length. The syntax of a rational number is:
-//
-// rational = mantissa [exponent] .
-// mantissa = integer ('/' natural | '.' natural) .
-// exponent = ('e'|'E') integer .
-//
-// If the base argument is 0, the string prefix determines the actual
-// conversion base for the mantissa. A prefix of ``0x'' or ``0X'' selects
-// base 16; the ``0'' prefix selects base 8. Otherwise the selected base is 10.
-// If the mantissa is represented via a division, both the numerator and
-// denominator may have different base prefixes; in that case the base of
-// of the numerator is returned. If the mantissa contains a decimal point,
-// the base for the fractional part is the same as for the part before the
-// decimal point and the fractional part does not accept a base prefix.
-// The base for the exponent is always 10.
-//
-func RatFromString(s string, base uint) (*Rational, uint, int) {
- // read numerator
- a, abase, alen := IntFromString(s, base)
- b := Nat(1)
-
- // read denominator or fraction, if any
- var blen int
- if alen < len(s) {
- ch := s[alen]
- if ch == '/' {
- alen++
- b, base, blen = NatFromString(s[alen:], base)
- } else if ch == '.' {
- alen++
- b, base, blen = NatFromString(s[alen:], abase)
- assert(base == abase)
- f := Nat(uint64(base)).Pow(uint(blen))
- a = MakeInt(a.sign, a.mant.Mul(f).Add(b))
- b = f
- }
- }
-
- // read exponent, if any
- rlen := alen + blen
- if rlen < len(s) {
- ch := s[rlen]
- if ch == 'e' || ch == 'E' {
- rlen++
- e, _, elen := IntFromString(s[rlen:], 10)
- rlen += elen
- m := Nat(10).Pow(uint(e.mant.Value()))
- if e.sign {
- b = b.Mul(m)
- } else {
- a = a.MulNat(m)
- }
- }
- }
-
- return MakeRat(a, b), base, rlen
-}
diff --git a/src/pkg/exp/datafmt/Makefile b/src/pkg/exp/datafmt/Makefile
index 40543b195..aa9453897 100644
--- a/src/pkg/exp/datafmt/Makefile
+++ b/src/pkg/exp/datafmt/Makefile
@@ -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 ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=exp/datafmt
GOFILES=\
diff --git a/src/pkg/exp/datafmt/datafmt.go b/src/pkg/exp/datafmt/datafmt.go
index e77f445b5..46c412342 100644
--- a/src/pkg/exp/datafmt/datafmt.go
+++ b/src/pkg/exp/datafmt/datafmt.go
@@ -656,7 +656,7 @@ func (s *State) eval(fexpr expr, value reflect.Value, index int) bool {
// Eval formats each argument according to the format
// f and returns the resulting []byte and os.Error. If
-// an error occured, the []byte contains the partially
+// an error occurred, the []byte contains the partially
// formatted result. An environment env may be passed
// in which is available in custom formatters through
// the state parameter.
@@ -697,7 +697,7 @@ func (f Format) Eval(env Environment, args ...interface{}) ([]byte, os.Error) {
// written and an os.Error, if any.
//
func (f Format) Fprint(w io.Writer, env Environment, args ...interface{}) (int, os.Error) {
- data, err := f.Eval(env, args)
+ data, err := f.Eval(env, args...)
if err != nil {
// TODO should we print partial result in case of error?
return 0, err
@@ -711,7 +711,7 @@ func (f Format) Fprint(w io.Writer, env Environment, args ...interface{}) (int,
// number of bytes written and an os.Error, if any.
//
func (f Format) Print(args ...interface{}) (int, os.Error) {
- return f.Fprint(os.Stdout, nil, args)
+ return f.Fprint(os.Stdout, nil, args...)
}
@@ -722,7 +722,7 @@ func (f Format) Print(args ...interface{}) (int, os.Error) {
//
func (f Format) Sprint(args ...interface{}) string {
var buf bytes.Buffer
- _, err := f.Fprint(&buf, nil, args)
+ _, err := f.Fprint(&buf, nil, args...)
if err != nil {
var i interface{} = args
fmt.Fprintf(&buf, "--- Sprint(%s) failed: %v", fmt.Sprint(i), err)
diff --git a/src/pkg/exp/datafmt/datafmt_test.go b/src/pkg/exp/datafmt/datafmt_test.go
index 908894717..f6a09f820 100644
--- a/src/pkg/exp/datafmt/datafmt_test.go
+++ b/src/pkg/exp/datafmt/datafmt_test.go
@@ -7,11 +7,15 @@ package datafmt
import (
"fmt"
"testing"
+ "go/token"
)
+var fset = token.NewFileSet()
+
+
func parse(t *testing.T, form string, fmap FormatterMap) Format {
- f, err := Parse("", []byte(form), fmap)
+ f, err := Parse(fset, "", []byte(form), fmap)
if err != nil {
t.Errorf("Parse(%s): %v", form, err)
return nil
@@ -24,7 +28,7 @@ func verify(t *testing.T, f Format, expected string, args ...interface{}) {
if f == nil {
return // allow other tests to run
}
- result := f.Sprint(args)
+ result := f.Sprint(args...)
if result != expected {
t.Errorf(
"result : `%s`\nexpected: `%s`\n\n",
@@ -97,7 +101,7 @@ func check(t *testing.T, form, expected string, args ...interface{}) {
if f == nil {
return // allow other tests to run
}
- result := f.Sprint(args)
+ result := f.Sprint(args...)
if result != expected {
t.Errorf(
"format : %s\nresult : `%s`\nexpected: `%s`\n\n",
diff --git a/src/pkg/exp/datafmt/parser.go b/src/pkg/exp/datafmt/parser.go
index de1f1c2a6..a01378ea5 100644
--- a/src/pkg/exp/datafmt/parser.go
+++ b/src/pkg/exp/datafmt/parser.go
@@ -19,9 +19,10 @@ import (
type parser struct {
scanner.ErrorVector
scanner scanner.Scanner
- pos token.Position // token position
- tok token.Token // one token look-ahead
- lit []byte // token literal
+ file *token.File
+ pos token.Pos // token position
+ tok token.Token // one token look-ahead
+ lit []byte // token literal
packs map[string]string // PackageName -> ImportPath
rules map[string]expr // RuleName -> Expression
@@ -39,18 +40,23 @@ func (p *parser) next() {
}
-func (p *parser) init(filename string, src []byte) {
+func (p *parser) init(fset *token.FileSet, filename string, src []byte) {
p.ErrorVector.Reset()
- p.scanner.Init(filename, src, p, scanner.AllowIllegalChars) // return '@' as token.ILLEGAL w/o error message
- p.next() // initializes pos, tok, lit
+ p.file = p.scanner.Init(fset, filename, src, p, scanner.AllowIllegalChars) // return '@' as token.ILLEGAL w/o error message
+ p.next() // initializes pos, tok, lit
p.packs = make(map[string]string)
p.rules = make(map[string]expr)
}
-func (p *parser) errorExpected(pos token.Position, msg string) {
+func (p *parser) error(pos token.Pos, msg string) {
+ p.Error(p.file.Position(pos), msg)
+}
+
+
+func (p *parser) errorExpected(pos token.Pos, msg string) {
msg = "expected " + msg
- if pos.Offset == p.pos.Offset {
+ if pos == p.pos {
// the error happened at the current position;
// make the error message more specific
msg += ", found '" + p.tok.String() + "'"
@@ -58,11 +64,11 @@ func (p *parser) errorExpected(pos token.Position, msg string) {
msg += " " + string(p.lit)
}
}
- p.Error(pos, msg)
+ p.error(pos, msg)
}
-func (p *parser) expect(tok token.Token) token.Position {
+func (p *parser) expect(tok token.Token) token.Pos {
pos := p.pos
if p.tok != tok {
p.errorExpected(pos, "'"+tok.String()+"'")
@@ -87,7 +93,7 @@ func (p *parser) parseTypeName() (string, bool) {
if importPath, found := p.packs[name]; found {
name = importPath
} else {
- p.Error(pos, "package not declared: "+name)
+ p.error(pos, "package not declared: "+name)
}
p.next()
name, isIdent = name+"."+p.parseIdentifier(), false
@@ -303,11 +309,11 @@ func (p *parser) parseFormat() {
// add package declaration
if !isIdent {
- p.Error(pos, "illegal package name: "+name)
+ p.error(pos, "illegal package name: "+name)
} else if _, found := p.packs[name]; !found {
p.packs[name] = importPath
} else {
- p.Error(pos, "package already declared: "+name)
+ p.error(pos, "package already declared: "+name)
}
case token.ASSIGN:
@@ -319,7 +325,7 @@ func (p *parser) parseFormat() {
if _, found := p.rules[name]; !found {
p.rules[name] = x
} else {
- p.Error(pos, "format rule already declared: "+name)
+ p.error(pos, "format rule already declared: "+name)
}
default:
@@ -358,10 +364,10 @@ func remap(p *parser, name string) string {
// there are no errors, the result is a Format and the error is nil.
// Otherwise the format is nil and a non-empty ErrorList is returned.
//
-func Parse(filename string, src []byte, fmap FormatterMap) (Format, os.Error) {
+func Parse(fset *token.FileSet, filename string, src []byte, fmap FormatterMap) (Format, os.Error) {
// parse source
var p parser
- p.init(filename, src)
+ p.init(fset, filename, src)
p.parseFormat()
// add custom formatters, if any
diff --git a/src/pkg/exp/draw/Makefile b/src/pkg/exp/draw/Makefile
index 7ab574482..6f0f0b2f5 100644
--- a/src/pkg/exp/draw/Makefile
+++ b/src/pkg/exp/draw/Makefile
@@ -2,12 +2,10 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=exp/draw
GOFILES=\
- arith.go\
- color.go\
draw.go\
event.go\
diff --git a/src/pkg/exp/draw/arith.go b/src/pkg/exp/draw/arith.go
deleted file mode 100644
index b72242aaa..000000000
--- a/src/pkg/exp/draw/arith.go
+++ /dev/null
@@ -1,155 +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 draw
-
-// A Point is an X, Y coordinate pair.
-type Point struct {
- X, Y int
-}
-
-// ZP is the zero Point.
-var ZP Point
-
-// A Rectangle contains the Points with Min.X <= X < Max.X, Min.Y <= Y < Max.Y.
-type Rectangle struct {
- Min, Max Point
-}
-
-// ZR is the zero Rectangle.
-var ZR Rectangle
-
-// Pt is shorthand for Point{X, Y}.
-func Pt(X, Y int) Point { return Point{X, Y} }
-
-// Rect is shorthand for Rectangle{Pt(x0, y0), Pt(x1, y1)}.
-func Rect(x0, y0, x1, y1 int) Rectangle { return Rectangle{Point{x0, y0}, Point{x1, y1}} }
-
-// Rpt is shorthand for Rectangle{min, max}.
-func Rpt(min, max Point) Rectangle { return Rectangle{min, max} }
-
-// Add returns the sum of p and q: Pt(p.X+q.X, p.Y+q.Y).
-func (p Point) Add(q Point) Point { return Point{p.X + q.X, p.Y + q.Y} }
-
-// Sub returns the difference of p and q: Pt(p.X-q.X, p.Y-q.Y).
-func (p Point) Sub(q Point) Point { return Point{p.X - q.X, p.Y - q.Y} }
-
-// Mul returns p scaled by k: Pt(p.X*k p.Y*k).
-func (p Point) Mul(k int) Point { return Point{p.X * k, p.Y * k} }
-
-// Div returns p divided by k: Pt(p.X/k, p.Y/k).
-func (p Point) Div(k int) Point { return Point{p.X / k, p.Y / k} }
-
-// Eq returns true if p and q are equal.
-func (p Point) Eq(q Point) bool { return p.X == q.X && p.Y == q.Y }
-
-// In returns true if p is within r.
-func (p Point) In(r Rectangle) bool {
- return p.X >= r.Min.X && p.X < r.Max.X &&
- p.Y >= r.Min.Y && p.Y < r.Max.Y
-}
-
-// Inset returns the rectangle r inset by n: Rect(r.Min.X+n, r.Min.Y+n, r.Max.X-n, r.Max.Y-n).
-func (r Rectangle) Inset(n int) Rectangle {
- return Rectangle{Point{r.Min.X + n, r.Min.Y + n}, Point{r.Max.X - n, r.Max.Y - n}}
-}
-
-// Add returns the rectangle r translated by p: Rpt(r.Min.Add(p), r.Max.Add(p)).
-func (r Rectangle) Add(p Point) Rectangle { return Rectangle{r.Min.Add(p), r.Max.Add(p)} }
-
-// Sub returns the rectangle r translated by -p: Rpt(r.Min.Sub(p), r.Max.Sub(p)).
-func (r Rectangle) Sub(p Point) Rectangle { return Rectangle{r.Min.Sub(p), r.Max.Sub(p)} }
-
-// Canon returns a canonical version of r: the returned rectangle
-// has Min.X <= Max.X and Min.Y <= Max.Y.
-func (r Rectangle) Canon() Rectangle {
- if r.Max.X < r.Min.X {
- r.Min.X, r.Max.X = r.Max.X, r.Min.X
- }
- if r.Max.Y < r.Min.Y {
- r.Min.Y, r.Max.Y = r.Max.Y, r.Min.Y
- }
- return r
-}
-
-// Overlaps returns true if r and r1 cross; that is, it returns true if they share any point.
-func (r Rectangle) Overlaps(r1 Rectangle) bool {
- return r.Min.X < r1.Max.X && r1.Min.X < r.Max.X &&
- r.Min.Y < r1.Max.Y && r1.Min.Y < r.Max.Y
-}
-
-// Empty retruns true if r contains no points.
-func (r Rectangle) Empty() bool { return r.Max.X <= r.Min.X || r.Max.Y <= r.Min.Y }
-
-// InRect returns true if all the points in r are also in r1.
-func (r Rectangle) In(r1 Rectangle) bool {
- if r.Empty() {
- return true
- }
- if r1.Empty() {
- return false
- }
- return r1.Min.X <= r.Min.X && r.Max.X <= r1.Max.X &&
- r1.Min.Y <= r.Min.Y && r.Max.Y <= r1.Max.Y
-}
-
-// Combine returns the smallest rectangle containing all points from r and from r1.
-func (r Rectangle) Combine(r1 Rectangle) Rectangle {
- if r.Empty() {
- return r1
- }
- if r1.Empty() {
- return r
- }
- if r.Min.X > r1.Min.X {
- r.Min.X = r1.Min.X
- }
- if r.Min.Y > r1.Min.Y {
- r.Min.Y = r1.Min.Y
- }
- if r.Max.X < r1.Max.X {
- r.Max.X = r1.Max.X
- }
- if r.Max.Y < r1.Max.Y {
- r.Max.Y = r1.Max.Y
- }
- return r
-}
-
-// Clip returns the largest rectangle containing only points shared by r and r1.
-func (r Rectangle) Clip(r1 Rectangle) Rectangle {
- if r.Empty() {
- return r
- }
- if r1.Empty() {
- return r1
- }
- if !r.Overlaps(r1) {
- return Rectangle{r.Min, r.Min}
- }
- if r.Min.X < r1.Min.X {
- r.Min.X = r1.Min.X
- }
- if r.Min.Y < r1.Min.Y {
- r.Min.Y = r1.Min.Y
- }
- if r.Max.X > r1.Max.X {
- r.Max.X = r1.Max.X
- }
- if r.Max.Y > r1.Max.Y {
- r.Max.Y = r1.Max.Y
- }
- return r
-}
-
-// Dx returns the width of the rectangle r: r.Max.X - r.Min.X.
-func (r Rectangle) Dx() int { return r.Max.X - r.Min.X }
-
-// Dy returns the width of the rectangle r: r.Max.Y - r.Min.Y.
-func (r Rectangle) Dy() int { return r.Max.Y - r.Min.Y }
-
-// Eq returns true if r and r1 are equal.
-func (r Rectangle) Eq(r1 Rectangle) bool {
- return r.Min.Eq(r1.Min) && r.Max.Eq(r1.Max)
-}
diff --git a/src/pkg/exp/draw/color.go b/src/pkg/exp/draw/color.go
deleted file mode 100644
index 3fe7b4abc..000000000
--- a/src/pkg/exp/draw/color.go
+++ /dev/null
@@ -1,105 +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 draw
-
-import "image"
-
-// A Color represents a color with 8-bit R, G, B, and A values,
-// packed into a uint32—0xRRGGBBAA—so that comparison
-// is defined on colors.
-// Color implements image.Color.
-// Color also implements image.Image: it is a
-// 10⁹x10⁹-pixel image of uniform color.
-type Color uint32
-
-// Check that Color implements image.Color and image.Image
-var _ image.Color = Black
-var _ image.Image = Black
-
-var (
- Opaque Color = 0xFFFFFFFF
- Transparent Color = 0x00000000
- Black Color = 0x000000FF
- White Color = 0xFFFFFFFF
- Red Color = 0xFF0000FF
- Green Color = 0x00FF00FF
- Blue Color = 0x0000FFFF
- Cyan Color = 0x00FFFFFF
- Magenta Color = 0xFF00FFFF
- Yellow Color = 0xFFFF00FF
- PaleYellow Color = 0xFFFFAAFF
- DarkYellow Color = 0xEEEE9EFF
- DarkGreen Color = 0x448844FF
- PaleGreen Color = 0xAAFFAAFF
- MedGreen Color = 0x88CC88FF
- DarkBlue Color = 0x000055FF
- PaleBlueGreen Color = 0xAAFFFFFF
- PaleBlue Color = 0x0000BBFF
- BlueGreen Color = 0x008888FF
- GreyGreen Color = 0x55AAAAFF
- PaleGreyGreen Color = 0x9EEEEEFF
- YellowGreen Color = 0x99994CFF
- MedBlue Color = 0x000099FF
- GreyBlue Color = 0x005DBBFF
- PaleGreyBlue Color = 0x4993DDFF
- PurpleBlue Color = 0x8888CCFF
-)
-
-func (c Color) RGBA() (r, g, b, a uint32) {
- x := uint32(c)
- r, g, b, a = x>>24, (x>>16)&0xFF, (x>>8)&0xFF, x&0xFF
- r |= r << 8
- g |= g << 8
- b |= b << 8
- a |= a << 8
- return
-}
-
-// SetAlpha returns the color obtained by changing
-// c's alpha value to a and scaling r, g, and b appropriately.
-func (c Color) SetAlpha(a uint8) Color {
- r, g, b, oa := c>>24, (c>>16)&0xFF, (c>>8)&0xFF, c&0xFF
- if oa == 0 {
- return 0
- }
- r = r * Color(a) / oa
- if r < 0 {
- r = 0
- }
- if r > 0xFF {
- r = 0xFF
- }
- g = g * Color(a) / oa
- if g < 0 {
- g = 0
- }
- if g > 0xFF {
- g = 0xFF
- }
- b = b * Color(a) / oa
- if b < 0 {
- b = 0
- }
- if b > 0xFF {
- b = 0xFF
- }
- return r<<24 | g<<16 | b<<8 | Color(a)
-}
-
-func (c Color) Width() int { return 1e9 }
-
-func (c Color) Height() int { return 1e9 }
-
-func (c Color) At(x, y int) image.Color { return c }
-
-func toColor(color image.Color) image.Color {
- if c, ok := color.(Color); ok {
- return c
- }
- r, g, b, a := color.RGBA()
- return Color(r>>8<<24 | g>>8<<16 | b>>8<<8 | a>>8)
-}
-
-func (c Color) ColorModel() image.ColorModel { return image.ColorModelFunc(toColor) }
diff --git a/src/pkg/exp/draw/draw.go b/src/pkg/exp/draw/draw.go
index 415dd99ac..1d0729d92 100644
--- a/src/pkg/exp/draw/draw.go
+++ b/src/pkg/exp/draw/draw.go
@@ -8,8 +8,6 @@
// and the X Render extension.
package draw
-// BUG(rsc): This is a toy library and not ready for production use.
-
import "image"
// m is the maximum color value returned by image.Color.RGBA.
@@ -34,22 +32,22 @@ type Image interface {
}
// Draw calls DrawMask with a nil mask and an Over op.
-func Draw(dst Image, r Rectangle, src image.Image, sp Point) {
- DrawMask(dst, r, src, sp, nil, ZP, Over)
+func Draw(dst Image, r image.Rectangle, src image.Image, sp image.Point) {
+ DrawMask(dst, r, src, sp, nil, image.ZP, Over)
}
// DrawMask aligns r.Min in dst with sp in src and mp in mask and then replaces the rectangle r
// in dst with the result of a Porter-Duff composition. A nil mask is treated as opaque.
-// The implementation is simple and slow.
-// TODO(nigeltao): Optimize this.
-func DrawMask(dst Image, r Rectangle, src image.Image, sp Point, mask image.Image, mp Point, op Op) {
- dx, dy := src.Width()-sp.X, src.Height()-sp.Y
+func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mask image.Image, mp image.Point, op Op) {
+ sb := src.Bounds()
+ dx, dy := sb.Max.X-sp.X, sb.Max.Y-sp.Y
if mask != nil {
- if dx > mask.Width()-mp.X {
- dx = mask.Width() - mp.X
+ mb := mask.Bounds()
+ if dx > mb.Max.X-mp.X {
+ dx = mb.Max.X - mp.X
}
- if dy > mask.Height()-mp.Y {
- dy = mask.Height() - mp.Y
+ if dy > mb.Max.Y-mp.Y {
+ dy = mb.Max.Y - mp.Y
}
}
if r.Dx() > dx {
@@ -58,45 +56,38 @@ func DrawMask(dst Image, r Rectangle, src image.Image, sp Point, mask image.Imag
if r.Dy() > dy {
r.Max.Y = r.Min.Y + dy
}
-
- // TODO(nigeltao): Clip r to dst's bounding box, and handle the case when sp or mp has negative X or Y.
- // TODO(nigeltao): Ensure that r is well formed, i.e. r.Max.X >= r.Min.X and likewise for Y.
+ r = r.Intersect(dst.Bounds())
+ if r.Empty() {
+ return
+ }
// Fast paths for special cases. If none of them apply, then we fall back to a general but slow implementation.
if dst0, ok := dst.(*image.RGBA); ok {
if op == Over {
if mask == nil {
- if src0, ok := src.(image.ColorImage); ok {
+ if src0, ok := src.(*image.ColorImage); ok {
drawFillOver(dst0, r, src0)
return
}
if src0, ok := src.(*image.RGBA); ok {
- if dst0 == src0 && r.Overlaps(r.Add(sp.Sub(r.Min))) {
- // TODO(nigeltao): Implement a fast path for the overlapping case.
- } else {
- drawCopyOver(dst0, r, src0, sp)
- return
- }
+ drawCopyOver(dst0, r, src0, sp)
+ return
}
} else if mask0, ok := mask.(*image.Alpha); ok {
- if src0, ok := src.(image.ColorImage); ok {
+ if src0, ok := src.(*image.ColorImage); ok {
drawGlyphOver(dst0, r, src0, mask0, mp)
return
}
}
} else {
if mask == nil {
- if src0, ok := src.(image.ColorImage); ok {
+ if src0, ok := src.(*image.ColorImage); ok {
drawFillSrc(dst0, r, src0)
return
}
if src0, ok := src.(*image.RGBA); ok {
- if dst0 == src0 && r.Overlaps(r.Add(sp.Sub(r.Min))) {
- // TODO(nigeltao): Implement a fast path for the overlapping case.
- } else {
- drawCopySrc(dst0, r, src0, sp)
- return
- }
+ drawCopySrc(dst0, r, src0, sp)
+ return
}
}
}
@@ -158,66 +149,96 @@ func DrawMask(dst Image, r Rectangle, src image.Image, sp Point, mask image.Imag
}
}
-func drawFillOver(dst *image.RGBA, r Rectangle, src image.ColorImage) {
+func drawFillOver(dst *image.RGBA, r image.Rectangle, src *image.ColorImage) {
cr, cg, cb, ca := src.RGBA()
// The 0x101 is here for the same reason as in drawRGBA.
a := (m - ca) * 0x101
x0, x1 := r.Min.X, r.Max.X
y0, y1 := r.Min.Y, r.Max.Y
for y := y0; y != y1; y++ {
- dpix := dst.Pixel[y]
- for x := x0; x != x1; x++ {
- rgba := dpix[x]
+ dbase := y * dst.Stride
+ dpix := dst.Pix[dbase+x0 : dbase+x1]
+ for i, rgba := range dpix {
dr := (uint32(rgba.R)*a)/m + cr
dg := (uint32(rgba.G)*a)/m + cg
db := (uint32(rgba.B)*a)/m + cb
da := (uint32(rgba.A)*a)/m + ca
- dpix[x] = image.RGBAColor{uint8(dr >> 8), uint8(dg >> 8), uint8(db >> 8), uint8(da >> 8)}
+ dpix[i] = image.RGBAColor{uint8(dr >> 8), uint8(dg >> 8), uint8(db >> 8), uint8(da >> 8)}
}
}
}
-func drawCopyOver(dst *image.RGBA, r Rectangle, src *image.RGBA, sp Point) {
- x0, x1 := r.Min.X, r.Max.X
- y0, y1 := r.Min.Y, r.Max.Y
- for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
- dpix := dst.Pixel[y]
- spix := src.Pixel[sy]
- for x, sx := x0, sp.X; x != x1; x, sx = x+1, sx+1 {
- // For unknown reasons, even though both dpix[x] and spix[sx] are
+func drawCopyOver(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.Point) {
+ dx0, dx1 := r.Min.X, r.Max.X
+ dy0, dy1 := r.Min.Y, r.Max.Y
+ nrows := dy1 - dy0
+ sx0, sx1 := sp.X, sp.X+dx1-dx0
+ d0 := dy0*dst.Stride + dx0
+ d1 := dy0*dst.Stride + dx1
+ s0 := sp.Y*src.Stride + sx0
+ s1 := sp.Y*src.Stride + sx1
+ var (
+ ddelta, sdelta int
+ i0, i1, idelta int
+ )
+ if r.Min.Y < sp.Y || r.Min.Y == sp.Y && r.Min.X <= sp.X {
+ ddelta = dst.Stride
+ sdelta = src.Stride
+ i0, i1, idelta = 0, d1-d0, +1
+ } else {
+ // If the source start point is higher than the destination start point, or equal height but to the left,
+ // then we compose the rows in right-to-left, bottom-up order instead of left-to-right, top-down.
+ d0 += (nrows - 1) * dst.Stride
+ d1 += (nrows - 1) * dst.Stride
+ s0 += (nrows - 1) * src.Stride
+ s1 += (nrows - 1) * src.Stride
+ ddelta = -dst.Stride
+ sdelta = -src.Stride
+ i0, i1, idelta = d1-d0-1, -1, -1
+ }
+ for ; nrows > 0; nrows-- {
+ dpix := dst.Pix[d0:d1]
+ spix := src.Pix[s0:s1]
+ for i := i0; i != i1; i += idelta {
+ // For unknown reasons, even though both dpix[i] and spix[i] are
// image.RGBAColors, on an x86 CPU it seems fastest to call RGBA
// for the source but to do it manually for the destination.
- sr, sg, sb, sa := spix[sx].RGBA()
- drgba := dpix[x]
- dr := uint32(drgba.R)
- dg := uint32(drgba.G)
- db := uint32(drgba.B)
- da := uint32(drgba.A)
+ sr, sg, sb, sa := spix[i].RGBA()
+ rgba := dpix[i]
+ dr := uint32(rgba.R)
+ dg := uint32(rgba.G)
+ db := uint32(rgba.B)
+ da := uint32(rgba.A)
// The 0x101 is here for the same reason as in drawRGBA.
a := (m - sa) * 0x101
dr = (dr*a)/m + sr
dg = (dg*a)/m + sg
db = (db*a)/m + sb
da = (da*a)/m + sa
- dpix[x] = image.RGBAColor{uint8(dr >> 8), uint8(dg >> 8), uint8(db >> 8), uint8(da >> 8)}
+ dpix[i] = image.RGBAColor{uint8(dr >> 8), uint8(dg >> 8), uint8(db >> 8), uint8(da >> 8)}
}
+ d0 += ddelta
+ d1 += ddelta
+ s0 += sdelta
+ s1 += sdelta
}
}
-func drawGlyphOver(dst *image.RGBA, r Rectangle, src image.ColorImage, mask *image.Alpha, mp Point) {
+func drawGlyphOver(dst *image.RGBA, r image.Rectangle, src *image.ColorImage, mask *image.Alpha, mp image.Point) {
x0, x1 := r.Min.X, r.Max.X
y0, y1 := r.Min.Y, r.Max.Y
cr, cg, cb, ca := src.RGBA()
for y, my := y0, mp.Y; y != y1; y, my = y+1, my+1 {
- dpix := dst.Pixel[y]
- mpix := mask.Pixel[my]
- for x, mx := x0, mp.X; x != x1; x, mx = x+1, mx+1 {
- ma := uint32(mpix[mx].A)
+ dbase := y * dst.Stride
+ dpix := dst.Pix[dbase+x0 : dbase+x1]
+ mbase := my * mask.Stride
+ mpix := mask.Pix[mbase+mp.X:]
+ for i, rgba := range dpix {
+ ma := uint32(mpix[i].A)
if ma == 0 {
continue
}
ma |= ma << 8
- rgba := dpix[x]
dr := uint32(rgba.R)
dg := uint32(rgba.G)
db := uint32(rgba.B)
@@ -228,12 +249,12 @@ func drawGlyphOver(dst *image.RGBA, r Rectangle, src image.ColorImage, mask *ima
dg = (dg*a + cg*ma) / m
db = (db*a + cb*ma) / m
da = (da*a + ca*ma) / m
- dpix[x] = image.RGBAColor{uint8(dr >> 8), uint8(dg >> 8), uint8(db >> 8), uint8(da >> 8)}
+ dpix[i] = image.RGBAColor{uint8(dr >> 8), uint8(dg >> 8), uint8(db >> 8), uint8(da >> 8)}
}
}
}
-func drawFillSrc(dst *image.RGBA, r Rectangle, src image.ColorImage) {
+func drawFillSrc(dst *image.RGBA, r image.Rectangle, src *image.ColorImage) {
if r.Dy() < 1 {
return
}
@@ -244,26 +265,53 @@ func drawFillSrc(dst *image.RGBA, r Rectangle, src image.ColorImage) {
// then use the first row as the slice source for the remaining rows.
dx0, dx1 := r.Min.X, r.Max.X
dy0, dy1 := r.Min.Y, r.Max.Y
- firstRow := dst.Pixel[dy0]
- for x := dx0; x < dx1; x++ {
- firstRow[x] = color
+ dbase := dy0 * dst.Stride
+ i0, i1 := dbase+dx0, dbase+dx1
+ firstRow := dst.Pix[i0:i1]
+ for i := range firstRow {
+ firstRow[i] = color
}
- copySrc := firstRow[dx0:dx1]
for y := dy0 + 1; y < dy1; y++ {
- copy(dst.Pixel[y][dx0:dx1], copySrc)
+ i0 += dst.Stride
+ i1 += dst.Stride
+ copy(dst.Pix[i0:i1], firstRow)
}
}
-func drawCopySrc(dst *image.RGBA, r Rectangle, src *image.RGBA, sp Point) {
+func drawCopySrc(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.Point) {
dx0, dx1 := r.Min.X, r.Max.X
dy0, dy1 := r.Min.Y, r.Max.Y
+ nrows := dy1 - dy0
sx0, sx1 := sp.X, sp.X+dx1-dx0
- for y, sy := dy0, sp.Y; y < dy1; y, sy = y+1, sy+1 {
- copy(dst.Pixel[y][dx0:dx1], src.Pixel[sy][sx0:sx1])
+ d0 := dy0*dst.Stride + dx0
+ d1 := dy0*dst.Stride + dx1
+ s0 := sp.Y*src.Stride + sx0
+ s1 := sp.Y*src.Stride + sx1
+ var ddelta, sdelta int
+ if r.Min.Y <= sp.Y {
+ ddelta = dst.Stride
+ sdelta = src.Stride
+ } else {
+ // If the source start point is higher than the destination start point, then we compose the rows
+ // in bottom-up order instead of top-down. Unlike the drawCopyOver function, we don't have to
+ // check the x co-ordinates because the built-in copy function can handle overlapping slices.
+ d0 += (nrows - 1) * dst.Stride
+ d1 += (nrows - 1) * dst.Stride
+ s0 += (nrows - 1) * src.Stride
+ s1 += (nrows - 1) * src.Stride
+ ddelta = -dst.Stride
+ sdelta = -src.Stride
+ }
+ for ; nrows > 0; nrows-- {
+ copy(dst.Pix[d0:d1], src.Pix[s0:s1])
+ d0 += ddelta
+ d1 += ddelta
+ s0 += sdelta
+ s1 += sdelta
}
}
-func drawRGBA(dst *image.RGBA, r Rectangle, src image.Image, sp Point, mask image.Image, mp Point, op Op) {
+func drawRGBA(dst *image.RGBA, r image.Rectangle, src image.Image, sp image.Point, mask image.Image, mp image.Point, op Op) {
x0, x1, dx := r.Min.X, r.Max.X, 1
y0, y1, dy := r.Min.Y, r.Max.Y, 1
if image.Image(dst) == src && r.Overlaps(r.Add(sp.Sub(r.Min))) {
@@ -278,7 +326,7 @@ func drawRGBA(dst *image.RGBA, r Rectangle, src image.Image, sp Point, mask imag
for y := y0; y != y1; y, sy, my = y+dy, sy+dy, my+dy {
sx := sp.X + x0 - r.Min.X
mx := mp.X + x0 - r.Min.X
- dpix := dst.Pixel[y]
+ dpix := dst.Pix[y*dst.Stride : (y+1)*dst.Stride]
for x := x0; x != x1; x, sx, mx = x+dx, sx+dx, mx+dx {
ma := uint32(m)
if mask != nil {
@@ -313,26 +361,3 @@ func drawRGBA(dst *image.RGBA, r Rectangle, src image.Image, sp Point, mask imag
}
}
}
-
-// Border aligns r.Min in dst with sp in src and then replaces pixels
-// in a w-pixel border around r in dst with the result of the Porter-Duff compositing
-// operation ``src over dst.'' If w is positive, the border extends w pixels inside r.
-// If w is negative, the border extends w pixels outside r.
-func Border(dst Image, r Rectangle, w int, src image.Image, sp Point) {
- i := w
- if i > 0 {
- // inside r
- Draw(dst, Rect(r.Min.X, r.Min.Y, r.Max.X, r.Min.Y+i), src, sp) // top
- Draw(dst, Rect(r.Min.X, r.Min.Y+i, r.Min.X+i, r.Max.Y-i), src, sp.Add(Pt(0, i))) // left
- Draw(dst, Rect(r.Max.X-i, r.Min.Y+i, r.Max.X, r.Max.Y-i), src, sp.Add(Pt(r.Dx()-i, i))) // right
- Draw(dst, Rect(r.Min.X, r.Max.Y-i, r.Max.X, r.Max.Y), src, sp.Add(Pt(0, r.Dy()-i))) // bottom
- return
- }
-
- // outside r;
- i = -i
- Draw(dst, Rect(r.Min.X-i, r.Min.Y-i, r.Max.X+i, r.Min.Y), src, sp.Add(Pt(-i, -i))) // top
- Draw(dst, Rect(r.Min.X-i, r.Min.Y, r.Min.X, r.Max.Y), src, sp.Add(Pt(-i, 0))) // left
- Draw(dst, Rect(r.Max.X, r.Min.Y, r.Max.X+i, r.Max.Y), src, sp.Add(Pt(r.Dx(), 0))) // right
- Draw(dst, Rect(r.Min.X-i, r.Max.Y, r.Max.X+i, r.Max.Y+i), src, sp.Add(Pt(-i, 0))) // bottom
-}
diff --git a/src/pkg/exp/draw/draw_test.go b/src/pkg/exp/draw/draw_test.go
index e9fde2535..90c9e823d 100644
--- a/src/pkg/exp/draw/draw_test.go
+++ b/src/pkg/exp/draw/draw_test.go
@@ -16,11 +16,11 @@ func eq(c0, c1 image.Color) bool {
}
func fillBlue(alpha int) image.Image {
- return image.ColorImage{image.RGBAColor{0, 0, uint8(alpha), uint8(alpha)}}
+ return image.NewColorImage(image.RGBAColor{0, 0, uint8(alpha), uint8(alpha)})
}
func fillAlpha(alpha int) image.Image {
- return image.ColorImage{image.AlphaColor{uint8(alpha)}}
+ return image.NewColorImage(image.AlphaColor{uint8(alpha)})
}
func vgradGreen(alpha int) image.Image {
@@ -53,6 +53,16 @@ func hgradRed(alpha int) Image {
return m
}
+func gradYellow(alpha int) Image {
+ m := image.NewRGBA(16, 16)
+ for y := 0; y < 16; y++ {
+ for x := 0; x < 16; x++ {
+ m.Set(x, y, image.RGBAColor{uint8(x * alpha / 15), uint8(y * alpha / 15), 0, uint8(alpha)})
+ }
+ }
+ return m
+}
+
type drawTest struct {
desc string
src image.Image
@@ -63,54 +73,62 @@ type drawTest struct {
var drawTests = []drawTest{
// Uniform mask (0% opaque).
- drawTest{"nop", vgradGreen(255), fillAlpha(0), Over, image.RGBAColor{136, 0, 0, 255}},
- drawTest{"clear", vgradGreen(255), fillAlpha(0), Src, image.RGBAColor{0, 0, 0, 0}},
+ {"nop", vgradGreen(255), fillAlpha(0), Over, image.RGBAColor{136, 0, 0, 255}},
+ {"clear", vgradGreen(255), fillAlpha(0), Src, image.RGBAColor{0, 0, 0, 0}},
// Uniform mask (100%, 75%, nil) and uniform source.
// At (x, y) == (8, 8):
// The destination pixel is {136, 0, 0, 255}.
// The source pixel is {0, 0, 90, 90}.
- drawTest{"fill", fillBlue(90), fillAlpha(255), Over, image.RGBAColor{88, 0, 90, 255}},
- drawTest{"fillSrc", fillBlue(90), fillAlpha(255), Src, image.RGBAColor{0, 0, 90, 90}},
- drawTest{"fillAlpha", fillBlue(90), fillAlpha(192), Over, image.RGBAColor{100, 0, 68, 255}},
- drawTest{"fillAlphaSrc", fillBlue(90), fillAlpha(192), Src, image.RGBAColor{0, 0, 68, 68}},
- drawTest{"fillNil", fillBlue(90), nil, Over, image.RGBAColor{88, 0, 90, 255}},
- drawTest{"fillNilSrc", fillBlue(90), nil, Src, image.RGBAColor{0, 0, 90, 90}},
+ {"fill", fillBlue(90), fillAlpha(255), Over, image.RGBAColor{88, 0, 90, 255}},
+ {"fillSrc", fillBlue(90), fillAlpha(255), Src, image.RGBAColor{0, 0, 90, 90}},
+ {"fillAlpha", fillBlue(90), fillAlpha(192), Over, image.RGBAColor{100, 0, 68, 255}},
+ {"fillAlphaSrc", fillBlue(90), fillAlpha(192), Src, image.RGBAColor{0, 0, 68, 68}},
+ {"fillNil", fillBlue(90), nil, Over, image.RGBAColor{88, 0, 90, 255}},
+ {"fillNilSrc", fillBlue(90), nil, Src, image.RGBAColor{0, 0, 90, 90}},
// Uniform mask (100%, 75%, nil) and variable source.
// At (x, y) == (8, 8):
// The destination pixel is {136, 0, 0, 255}.
// The source pixel is {0, 48, 0, 90}.
- drawTest{"copy", vgradGreen(90), fillAlpha(255), Over, image.RGBAColor{88, 48, 0, 255}},
- drawTest{"copySrc", vgradGreen(90), fillAlpha(255), Src, image.RGBAColor{0, 48, 0, 90}},
- drawTest{"copyAlpha", vgradGreen(90), fillAlpha(192), Over, image.RGBAColor{100, 36, 0, 255}},
- drawTest{"copyAlphaSrc", vgradGreen(90), fillAlpha(192), Src, image.RGBAColor{0, 36, 0, 68}},
- drawTest{"copyNil", vgradGreen(90), nil, Over, image.RGBAColor{88, 48, 0, 255}},
- drawTest{"copyNilSrc", vgradGreen(90), nil, Src, image.RGBAColor{0, 48, 0, 90}},
+ {"copy", vgradGreen(90), fillAlpha(255), Over, image.RGBAColor{88, 48, 0, 255}},
+ {"copySrc", vgradGreen(90), fillAlpha(255), Src, image.RGBAColor{0, 48, 0, 90}},
+ {"copyAlpha", vgradGreen(90), fillAlpha(192), Over, image.RGBAColor{100, 36, 0, 255}},
+ {"copyAlphaSrc", vgradGreen(90), fillAlpha(192), Src, image.RGBAColor{0, 36, 0, 68}},
+ {"copyNil", vgradGreen(90), nil, Over, image.RGBAColor{88, 48, 0, 255}},
+ {"copyNilSrc", vgradGreen(90), nil, Src, image.RGBAColor{0, 48, 0, 90}},
// Variable mask and variable source.
// At (x, y) == (8, 8):
// The destination pixel is {136, 0, 0, 255}.
// The source pixel is {0, 0, 255, 255}.
// The mask pixel's alpha is 102, or 40%.
- drawTest{"generic", fillBlue(255), vgradAlpha(192), Over, image.RGBAColor{81, 0, 102, 255}},
- drawTest{"genericSrc", fillBlue(255), vgradAlpha(192), Src, image.RGBAColor{0, 0, 102, 102}},
+ {"generic", fillBlue(255), vgradAlpha(192), Over, image.RGBAColor{81, 0, 102, 255}},
+ {"genericSrc", fillBlue(255), vgradAlpha(192), Src, image.RGBAColor{0, 0, 102, 102}},
}
-func makeGolden(dst image.Image, t drawTest) image.Image {
+func makeGolden(dst, src, mask image.Image, op Op) image.Image {
// Since golden is a newly allocated image, we don't have to check if the
// input source and mask images and the output golden image overlap.
- golden := image.NewRGBA(dst.Width(), dst.Height())
- for y := 0; y < golden.Height(); y++ {
- my, sy := y, y
- for x := 0; x < golden.Width(); x++ {
- mx, sx := x, x
+ b := dst.Bounds()
+ sx0 := src.Bounds().Min.X - b.Min.X
+ sy0 := src.Bounds().Min.Y - b.Min.Y
+ var mx0, my0 int
+ if mask != nil {
+ mx0 = mask.Bounds().Min.X - b.Min.X
+ my0 = mask.Bounds().Min.Y - b.Min.Y
+ }
+ golden := image.NewRGBA(b.Max.X, b.Max.Y)
+ for y := b.Min.Y; y < b.Max.Y; y++ {
+ my, sy := my0+y, sy0+y
+ for x := b.Min.X; x < b.Max.X; x++ {
+ mx, sx := mx0+x, sx0+x
const M = 1<<16 - 1
var dr, dg, db, da uint32
- if t.op == Over {
+ if op == Over {
dr, dg, db, da = dst.At(x, y).RGBA()
}
- sr, sg, sb, sa := t.src.At(sx, sy).RGBA()
+ sr, sg, sb, sa := src.At(sx, sy).RGBA()
ma := uint32(M)
- if t.mask != nil {
- _, _, _, ma = t.mask.At(mx, my).RGBA()
+ if mask != nil {
+ _, _, _, ma = mask.At(mx, my).RGBA()
}
a := M - (sa * ma / M)
golden.Set(x, y, image.RGBA64Color{
@@ -121,6 +139,7 @@ func makeGolden(dst image.Image, t drawTest) image.Image {
})
}
}
+ golden.Rect = b
return golden
}
@@ -129,9 +148,14 @@ loop:
for _, test := range drawTests {
dst := hgradRed(255)
// Draw the (src, mask, op) onto a copy of dst using a slow but obviously correct implementation.
- golden := makeGolden(dst, test)
+ golden := makeGolden(dst, test.src, test.mask, test.op)
+ b := dst.Bounds()
+ if !b.Eq(golden.Bounds()) {
+ t.Errorf("draw %s: bounds %v versus %v", test.desc, dst.Bounds(), golden.Bounds())
+ continue
+ }
// Draw the same combination onto the actual dst using the optimized DrawMask implementation.
- DrawMask(dst, Rect(0, 0, dst.Width(), dst.Height()), test.src, ZP, test.mask, ZP, test.op)
+ DrawMask(dst, b, test.src, image.ZP, test.mask, image.ZP, test.op)
// Check that the resultant pixel at (8, 8) matches what we expect
// (the expected value can be verified by hand).
if !eq(dst.At(8, 8), test.expected) {
@@ -139,8 +163,8 @@ loop:
continue
}
// Check that the resultant dst image matches the golden output.
- for y := 0; y < golden.Height(); y++ {
- for x := 0; x < golden.Width(); x++ {
+ for y := b.Min.Y; y < b.Max.Y; y++ {
+ for x := b.Min.X; x < b.Max.X; x++ {
if !eq(dst.At(x, y), golden.At(x, y)) {
t.Errorf("draw %s: at (%d, %d), %v versus golden %v", test.desc, x, y, dst.At(x, y), golden.At(x, y))
continue loop
@@ -150,6 +174,45 @@ loop:
}
}
+func TestDrawOverlap(t *testing.T) {
+ for _, op := range []Op{Over, Src} {
+ for yoff := -2; yoff <= 2; yoff++ {
+ loop:
+ for xoff := -2; xoff <= 2; xoff++ {
+ m := gradYellow(127).(*image.RGBA)
+ dst := &image.RGBA{
+ Pix: m.Pix,
+ Stride: m.Stride,
+ Rect: image.Rect(5, 5, 10, 10),
+ }
+ src := &image.RGBA{
+ Pix: m.Pix,
+ Stride: m.Stride,
+ Rect: image.Rect(5+xoff, 5+yoff, 10+xoff, 10+yoff),
+ }
+ // Draw the (src, mask, op) onto a copy of dst using a slow but obviously correct implementation.
+ golden := makeGolden(dst, src, nil, op)
+ b := dst.Bounds()
+ if !b.Eq(golden.Bounds()) {
+ t.Errorf("drawOverlap xoff=%d,yoff=%d: bounds %v versus %v", xoff, yoff, dst.Bounds(), golden.Bounds())
+ continue
+ }
+ // Draw the same combination onto the actual dst using the optimized DrawMask implementation.
+ DrawMask(dst, b, src, src.Bounds().Min, nil, image.ZP, op)
+ // Check that the resultant dst image matches the golden output.
+ for y := b.Min.Y; y < b.Max.Y; y++ {
+ for x := b.Min.X; x < b.Max.X; x++ {
+ if !eq(dst.At(x, y), golden.At(x, y)) {
+ t.Errorf("drawOverlap xoff=%d,yoff=%d: at (%d, %d), %v versus golden %v", xoff, yoff, x, y, dst.At(x, y), golden.At(x, y))
+ continue loop
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
// TestIssue836 verifies http://code.google.com/p/go/issues/detail?id=836.
func TestIssue836(t *testing.T) {
a := image.NewRGBA(1, 1)
@@ -158,7 +221,7 @@ func TestIssue836(t *testing.T) {
b.Set(1, 0, image.RGBAColor{0, 0, 5, 5})
b.Set(0, 1, image.RGBAColor{0, 5, 0, 5})
b.Set(1, 1, image.RGBAColor{5, 0, 0, 5})
- Draw(a, Rect(0, 0, 1, 1), b, Pt(1, 1))
+ Draw(a, image.Rect(0, 0, 1, 1), b, image.Pt(1, 1))
if !eq(image.RGBAColor{5, 0, 0, 5}, a.At(0, 0)) {
t.Errorf("Issue 836: want %v got %v", image.RGBAColor{5, 0, 0, 5}, a.At(0, 0))
}
diff --git a/src/pkg/exp/draw/event.go b/src/pkg/exp/draw/event.go
index 155922d1c..b777d912e 100644
--- a/src/pkg/exp/draw/event.go
+++ b/src/pkg/exp/draw/event.go
@@ -4,43 +4,53 @@
package draw
-// A Context represents a single graphics window.
-type Context interface {
- // Screen returns an editable Image of window.
+import (
+ "image"
+ "os"
+)
+
+// A Window represents a single graphics window.
+type Window interface {
+ // Screen returns an editable Image for the window.
Screen() Image
-
// FlushImage flushes changes made to Screen() back to screen.
FlushImage()
+ // EventChan returns a channel carrying UI events such as key presses,
+ // mouse movements and window resizes.
+ EventChan() <-chan interface{}
+ // Close closes the window.
+ Close() os.Error
+}
- // KeyboardChan returns a channel carrying keystrokes.
- // An event is sent each time a key is pressed or released.
+// 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 character represent themselves.
- KeyboardChan() <-chan int
-
- // MouseChan returns a channel carrying mouse events.
- // A new event is sent each time the mouse moves or a
- // button is pressed or released.
- MouseChan() <-chan Mouse
+ // but ordinary characters represent themselves.
+ Key int
+}
- // ResizeChan returns a channel carrying resize events.
- // An event is sent each time the window is resized;
- // the client should respond by calling Screen() to obtain
- // the new screen image.
- // The value sent on the channel is always ``true'' and can be ignored.
- ResizeChan() <-chan bool
+// 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
+}
- // QuitChan returns a channel carrying quit requests.
- // After reading a value from the quit channel, the application
- // should exit.
- QuitChan() <-chan bool
+// 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
}
-// A Mouse represents the state of the mouse.
-type Mouse struct {
- Buttons int // bit mask of buttons: 1<<0 is left, 1<<1 middle, 1<<2 right
- Point // location of cursor
- Nsec int64 // time stamp
+// An ErrEvent is sent when an error occurs.
+type ErrEvent struct {
+ Err os.Error
}
diff --git a/src/pkg/exp/draw/x11/Makefile b/src/pkg/exp/draw/x11/Makefile
index d4e65ca73..205b3a65b 100644
--- a/src/pkg/exp/draw/x11/Makefile
+++ b/src/pkg/exp/draw/x11/Makefile
@@ -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 ../../../../Make.$(GOARCH)
+include ../../../../Make.inc
TARG=exp/draw/x11
GOFILES=\
diff --git a/src/pkg/exp/draw/x11/conn.go b/src/pkg/exp/draw/x11/conn.go
index 979ce2b7d..da2181536 100644
--- a/src/pkg/exp/draw/x11/conn.go
+++ b/src/pkg/exp/draw/x11/conn.go
@@ -8,17 +8,17 @@
// A summary of the wire format can be found in XCB's xproto.xml.
package x11
-// BUG(nigeltao): This is a toy library and not ready for production use.
-
import (
"bufio"
"exp/draw"
"image"
"io"
+ "log"
"net"
"os"
"strconv"
"strings"
+ "time"
)
type resID uint32 // X resource IDs.
@@ -35,9 +35,6 @@ const (
)
type conn struct {
- // TODO(nigeltao): Figure out which goroutine should be responsible for closing c,
- // or if there is a race condition if one goroutine calls c.Close whilst another one
- // is reading from r, or writing to w.
c io.Closer
r *bufio.Reader
w *bufio.Writer
@@ -45,11 +42,8 @@ type conn struct {
gc, window, root, visual resID
img *image.RGBA
- kbd chan int
- mouse chan draw.Mouse
- resize chan bool
- quit chan bool
- mouseState draw.Mouse
+ eventc chan interface{}
+ mouseState draw.MouseEvent
buf [256]byte // General purpose scratch buffer.
@@ -58,25 +52,24 @@ type conn struct {
flushBuf1 [4 * 1024]byte
}
-// flusher runs in its own goroutine, serving both FlushImage calls directly from the exp/draw client
-// and indirectly from X expose events. It paints c.img to the X server via PutImage requests.
-func (c *conn) flusher() {
- for {
- _ = <-c.flush
- if closed(c.flush) {
- return
+// writeSocket runs in its own goroutine, serving both FlushImage calls
+// directly from the exp/draw client and indirectly from X expose events.
+// It paints c.img to the X server via PutImage requests.
+func (c *conn) writeSocket() {
+ defer c.c.Close()
+ for _ = range c.flush {
+ b := c.img.Bounds()
+ if b.Empty() {
+ continue
}
-
// Each X request has a 16-bit length (in terms of 4-byte units). To avoid going over
// this limit, we send PutImage for each row of the image, rather than trying to paint
// the entire image in one X request. This approach could easily be optimized (or the
// X protocol may have an escape sequence to delimit very large requests).
// TODO(nigeltao): See what XCB's xcb_put_image does in this situation.
- w, h := c.img.Width(), c.img.Height()
- units := 6 + w
- if units > 0xffff || h > 0xffff {
- // This window is too large for X.
- close(c.flush)
+ units := 6 + b.Dx()
+ if units > 0xffff || b.Dy() > 0xffff {
+ log.Print("x11: window is too large for PutImage")
return
}
@@ -86,19 +79,20 @@ func (c *conn) flusher() {
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(w))
+ setU32LE(c.flushBuf0[12:16], 1<<16|uint32(b.Dx()))
c.flushBuf0[21] = 0x18 // depth = 24 bits.
- for y := 0; y < h; y++ {
+ for y := b.Min.Y; y < b.Max.Y; y++ {
setU32LE(c.flushBuf0[16:20], uint32(y<<16))
- _, err := c.w.Write(c.flushBuf0[0:24])
- if err != nil {
- close(c.flush)
+ if _, err := c.w.Write(c.flushBuf0[0:24]); err != nil {
+ if err != os.EOF {
+ log.Println("x11:", err.String())
+ }
return
}
- p := c.img.Pixel[y]
- for x := 0; x < w; {
- nx := w - x
+ p := c.img.Pix[y*c.img.Stride : (y+1)*c.img.Stride]
+ for x := b.Min.X; x < b.Max.X; {
+ nx := b.Max.X - x
if nx > len(c.flushBuf1)/4 {
nx = len(c.flushBuf1) / 4
}
@@ -108,15 +102,18 @@ func (c *conn) flusher() {
c.flushBuf1[4*i+2] = rgba.R
}
x += nx
- _, err := c.w.Write(c.flushBuf1[0 : 4*nx])
- if err != nil {
- close(c.flush)
+ if _, err := c.w.Write(c.flushBuf1[0 : 4*nx]); err != nil {
+ if err != os.EOF {
+ log.Println("x11:", err.String())
+ }
return
}
}
}
- if c.w.Flush() != nil {
- close(c.flush)
+ if err := c.w.Flush(); err != nil {
+ if err != os.EOF {
+ log.Println("x11:", err.String())
+ }
return
}
}
@@ -131,32 +128,32 @@ func (c *conn) FlushImage() {
_ = c.flush <- false
}
-func (c *conn) KeyboardChan() <-chan int { return c.kbd }
-
-func (c *conn) MouseChan() <-chan draw.Mouse { return c.mouse }
-
-func (c *conn) ResizeChan() <-chan bool { return c.resize }
+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) QuitChan() <-chan bool { return c.quit }
+func (c *conn) EventChan() <-chan interface{} { return c.eventc }
-// pumper runs in its own goroutine, reading X events and demuxing them over the kbd / mouse / resize / quit chans.
-func (c *conn) pumper() {
+// readSocket runs in its own goroutine, reading X events and sending draw
+// events on c's EventChan.
+func (c *conn) readSocket() {
var (
keymap [256][]int
keysymsPerKeycode int
)
- defer close(c.flush)
- // TODO(nigeltao): Is this the right place for defer c.c.Close()?
- // TODO(nigeltao): Should we explicitly defer close our kbd/mouse/resize/quit chans?
+ defer close(c.eventc)
for {
// X events are always 32 bytes long.
- _, err := io.ReadFull(c.r, c.buf[0:32])
- if err != nil {
- // TODO(nigeltao): should draw.Context expose err?
- // TODO(nigeltao): should we do c.quit<-true? Should c.quit be a buffered channel?
- // Or is c.quit only for non-exceptional closing (e.g. when the window manager destroys
- // our window), and not for e.g. an I/O error?
- os.Stderr.Write([]byte(err.String()))
+ if _, err := io.ReadFull(c.r, c.buf[0:32]); err != nil {
+ if err != os.EOF {
+ c.eventc <- draw.ErrEvent{err}
+ }
return
}
switch c.buf[0] {
@@ -165,7 +162,7 @@ func (c *conn) pumper() {
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.
- os.Stderr.Write([]byte("exp/draw/x11: unexpected cookie\n"))
+ c.eventc <- draw.ErrEvent{os.NewError("x11: unexpected cookie")}
return
}
keysymsPerKeycode = int(c.buf[1])
@@ -178,7 +175,9 @@ func (c *conn) pumper() {
for j := range m {
u, err := readU32LE(c.r, c.buf[0:4])
if err != nil {
- os.Stderr.Write([]byte(err.String()))
+ if err != os.EOF {
+ c.eventc <- draw.ErrEvent{err}
+ }
return
}
m[j] = int(u)
@@ -199,14 +198,14 @@ func (c *conn) pumper() {
if keysym == 0 {
keysym = keymap[keycode][0]
}
- // TODO(nigeltao): Should we send KeyboardChan ints for Shift/Ctrl/Alt? Should Shift-A send
+ // TODO(nigeltao): Should we send KeyEvents for Shift/Ctrl/Alt? Should Shift-A send
// the same int down the channel as the sent on just the A key?
// TODO(nigeltao): How should IME events (e.g. key presses that should generate CJK text) work? Or
- // is that outside the scope of the draw.Context interface?
+ // is that outside the scope of the draw.Window interface?
if c.buf[0] == 0x03 {
keysym = -keysym
}
- c.kbd <- keysym
+ c.eventc <- draw.KeyEvent{keysym}
case 0x04, 0x05: // Button press, button release.
mask := 1 << (c.buf[1] - 1)
if c.buf[0] == 0x04 {
@@ -214,22 +213,21 @@ func (c *conn) pumper() {
} else {
c.mouseState.Buttons &^= mask
}
- // TODO(nigeltao): update mouseState's timestamp.
- c.mouse <- c.mouseState
+ c.mouseState.Nsec = time.Nanoseconds()
+ c.eventc <- c.mouseState
case 0x06: // Motion notify.
- c.mouseState.Point.X = int(c.buf[25])<<8 | int(c.buf[24])
- c.mouseState.Point.Y = int(c.buf[27])<<8 | int(c.buf[26])
- // TODO(nigeltao): update mouseState's timestamp.
- c.mouse <- c.mouseState
+ 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 count (in bytes 16-17) of the number of additional expose events coming.
+ // 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.
- count := int(c.buf[17])<<8 | int(c.buf[16])
- if count == 0 {
+ 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
@@ -491,16 +489,13 @@ func (c *conn) handshake() os.Error {
if err != nil {
return err
}
- // Read the vendor length.
+ // Read the vendor length and round it up to a multiple of 4,
+ // for X11 protocol alignment reasons.
vendorLen, err := readU16LE(c.r, c.buf[0:2])
if err != nil {
return err
}
- if vendorLen != 20 {
- // For now, assume the vendor is "The X.Org Foundation". Supporting different
- // vendors would require figuring out how much padding we need to read.
- return os.NewError("unsupported X vendor")
- }
+ vendorLen = (vendorLen + 3) &^ 3
// Read the maximum request length.
maxReqLen, err := readU16LE(c.r, c.buf[0:2])
if err != nil {
@@ -519,10 +514,13 @@ func (c *conn) handshake() os.Error {
if err != nil {
return err
}
- // Ignore some things that we don't care about (totalling 30 bytes):
+ // Ignore some things that we don't care about (totalling 10 + vendorLen bytes):
// imageByteOrder(1), bitmapFormatBitOrder(1), bitmapFormatScanlineUnit(1) bitmapFormatScanlinePad(1),
- // minKeycode(1), maxKeycode(1), padding(4), vendor(20, hard-coded above).
- _, err = io.ReadFull(c.r, c.buf[0:30])
+ // minKeycode(1), maxKeycode(1), padding(4), vendor (vendorLen).
+ if 10+int(vendorLen) > cap(c.buf) {
+ return os.NewError("unsupported X vendor")
+ }
+ _, err = io.ReadFull(c.r, c.buf[0:10+int(vendorLen)])
if err != nil {
return err
}
@@ -550,7 +548,7 @@ func (c *conn) handshake() os.Error {
}
// NewWindow calls NewWindowDisplay with $DISPLAY.
-func NewWindow() (draw.Context, os.Error) {
+func NewWindow() (draw.Window, os.Error) {
display := os.Getenv("DISPLAY")
if len(display) == 0 {
return nil, os.NewError("$DISPLAY not set")
@@ -558,10 +556,10 @@ func NewWindow() (draw.Context, os.Error) {
return NewWindowDisplay(display)
}
-// NewWindowDisplay returns a new draw.Context, backed by a newly created and
+// NewWindowDisplay returns a new draw.Window, backed by a newly created and
// mapped X11 window. The X server to connect to is specified by the display
// string, such as ":1".
-func NewWindowDisplay(display string) (draw.Context, os.Error) {
+func NewWindowDisplay(display string) (draw.Window, os.Error) {
socket, displayStr, err := connect(display)
if err != nil {
return nil, err
@@ -616,13 +614,9 @@ func NewWindowDisplay(display string) (draw.Context, os.Error) {
}
c.img = image.NewRGBA(windowWidth, windowHeight)
- // TODO(nigeltao): Should these channels be buffered?
- c.kbd = make(chan int)
- c.mouse = make(chan draw.Mouse)
- c.resize = make(chan bool)
- c.quit = make(chan bool)
+ c.eventc = make(chan interface{}, 16)
c.flush = make(chan bool, 1)
- go c.flusher()
- go c.pumper()
+ go c.readSocket()
+ go c.writeSocket()
return c, nil
}
diff --git a/src/pkg/exp/eval/Makefile b/src/pkg/exp/eval/Makefile
index eac844f1e..2b716b14c 100644
--- a/src/pkg/exp/eval/Makefile
+++ b/src/pkg/exp/eval/Makefile
@@ -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 ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=exp/eval
GOFILES=\
@@ -16,14 +16,22 @@ GOFILES=\
stmt.go\
type.go\
typec.go\
- util.go\
value.go\
world.go\
include ../../../Make.pkg
main.$O: main.go $(pkgdir)/$(TARG).a
- $(QUOTED_GOBIN)/$(GC) $<
+ $(GC) $<
eval: main.$O
- $(QUOTED_GOBIN)/$(LD) -o $@ $<
+ $(LD) -o $@ $<
+
+gen.$O: gen.go
+ $(GC) $<
+
+generate: gen.$O $(pkgdir)/$(TARG).a
+ $(LD) -o $@ $<;\
+ ./generate > expr1.go;\
+ gofmt -w expr1.go
+
diff --git a/src/pkg/exp/eval/bridge.go b/src/pkg/exp/eval/bridge.go
index c53febc8a..3fa498d68 100644
--- a/src/pkg/exp/eval/bridge.go
+++ b/src/pkg/exp/eval/bridge.go
@@ -29,7 +29,7 @@ func TypeFromNative(t reflect.Type) Type {
var nt *NamedType
if t.Name() != "" {
name := t.PkgPath() + "·" + t.Name()
- nt = &NamedType{token.Position{}, name, nil, true, make(map[string]Method)}
+ nt = &NamedType{token.NoPos, name, nil, true, make(map[string]Method)}
evalTypes[t] = nt
}
@@ -79,7 +79,7 @@ func TypeFromNative(t reflect.Type) Type {
case *reflect.ArrayType:
et = NewArrayType(int64(t.Len()), TypeFromNative(t.Elem()))
case *reflect.ChanType:
- log.Crashf("%T not implemented", t)
+ log.Panicf("%T not implemented", t)
case *reflect.FuncType:
nin := t.NumIn()
// Variadic functions have DotDotDotType at the end
@@ -97,9 +97,9 @@ func TypeFromNative(t reflect.Type) Type {
}
et = NewFuncType(in, variadic, out)
case *reflect.InterfaceType:
- log.Crashf("%T not implemented", t)
+ log.Panicf("%T not implemented", t)
case *reflect.MapType:
- log.Crashf("%T not implemented", t)
+ log.Panicf("%T not implemented", t)
case *reflect.PtrType:
et = NewPtrType(TypeFromNative(t.Elem()))
case *reflect.SliceType:
@@ -116,9 +116,9 @@ func TypeFromNative(t reflect.Type) Type {
}
et = NewStructType(fields)
case *reflect.UnsafePointerType:
- log.Crashf("%T not implemented", t)
+ log.Panicf("%T not implemented", t)
default:
- log.Crashf("unexpected reflect.Type: %T", t)
+ log.Panicf("unexpected reflect.Type: %T", t)
}
if nt != nil {
diff --git a/src/pkg/exp/eval/compiler.go b/src/pkg/exp/eval/compiler.go
index 3e37bfbaa..9d2923bfc 100644
--- a/src/pkg/exp/eval/compiler.go
+++ b/src/pkg/exp/eval/compiler.go
@@ -11,24 +11,20 @@ import (
)
-type positioned interface {
- Pos() token.Position
-}
-
-
// A compiler captures information used throughout an entire
// compilation. Currently it includes only the error handler.
//
// TODO(austin) This might actually represent package level, in which
// case it should be package compiler.
type compiler struct {
+ fset *token.FileSet
errors scanner.ErrorHandler
numErrors int
silentErrors int
}
-func (a *compiler) diagAt(pos positioned, format string, args ...interface{}) {
- a.errors.Error(pos.Pos(), fmt.Sprintf(format, args))
+func (a *compiler) diagAt(pos token.Pos, format string, args ...interface{}) {
+ a.errors.Error(a.fset.Position(pos), fmt.Sprintf(format, args...))
a.numErrors++
}
@@ -64,9 +60,9 @@ type label struct {
continuePC *uint
// The position where this label was resolved. If it has not
// been resolved yet, an invalid position.
- resolved token.Position
+ resolved token.Pos
// The position where this label was first jumped to.
- used token.Position
+ used token.Pos
}
// A funcCompiler captures information used throughout the compilation
diff --git a/src/pkg/exp/eval/eval_test.go b/src/pkg/exp/eval/eval_test.go
index 1dfdfe1fd..6bfe9089d 100644
--- a/src/pkg/exp/eval/eval_test.go
+++ b/src/pkg/exp/eval/eval_test.go
@@ -5,15 +5,20 @@
package eval
import (
- "exp/bignum"
+ "big"
"flag"
"fmt"
+ "go/token"
"log"
"os"
"reflect"
+ "regexp"
"testing"
)
+// All tests are done using the same file set.
+var fset = token.NewFileSet()
+
// Print each statement or expression before parsing it
var noisy = false
@@ -48,7 +53,7 @@ func (a test) run(t *testing.T, name string) {
println("code:", src)
}
- code, err := w.Compile(src)
+ code, err := w.Compile(fset, src)
if err != nil {
if j.cerr == "" {
t.Errorf("%s: Compile %s: %v", name, src, err)
@@ -89,9 +94,9 @@ func (a test) run(t *testing.T, name string) {
}
func match(t *testing.T, err os.Error, pat string) bool {
- ok, errstr := testing.MatchString(pat, err.String())
- if errstr != "" {
- t.Fatalf("compile regexp %s: %v", pat, errstr)
+ ok, err1 := regexp.MatchString(pat, err.String())
+ if err1 != nil {
+ t.Fatalf("compile regexp %s: %v", pat, err1)
}
return ok
}
@@ -102,40 +107,40 @@ func match(t *testing.T, err os.Error, pat string) bool {
*/
// Expression compile error
-func CErr(expr string, cerr string) test { return test([]job{job{code: expr, cerr: cerr}}) }
+func CErr(expr string, cerr string) test { return test([]job{{code: expr, cerr: cerr}}) }
// Expression runtime error
-func RErr(expr string, rterr string) test { return test([]job{job{code: expr, rterr: rterr}}) }
+func RErr(expr string, rterr string) test { return test([]job{{code: expr, rterr: rterr}}) }
// Expression value
func Val(expr string, val interface{}) test {
- return test([]job{job{code: expr, val: toValue(val)}})
+ return test([]job{{code: expr, val: toValue(val)}})
}
// Statement runs without error
-func Run(stmts string) test { return test([]job{job{code: stmts, noval: true}}) }
+func Run(stmts string) test { return test([]job{{code: stmts, noval: true}}) }
// Two statements without error.
// TODO(rsc): Should be possible with Run but the parser
// won't let us do both top-level and non-top-level statements.
func Run2(stmt1, stmt2 string) test {
- return test([]job{job{code: stmt1, noval: true}, job{code: stmt2, noval: true}})
+ return test([]job{{code: stmt1, noval: true}, {code: stmt2, noval: true}})
}
// Statement runs and test one expression's value
func Val1(stmts string, expr1 string, val1 interface{}) test {
return test([]job{
- job{code: stmts, noval: true},
- job{code: expr1, val: toValue(val1)},
+ {code: stmts, noval: true},
+ {code: expr1, val: toValue(val1)},
})
}
// Statement runs and test two expressions' values
func Val2(stmts string, expr1 string, val1 interface{}, expr2 string, val2 interface{}) test {
return test([]job{
- job{code: stmts, noval: true},
- job{code: expr1, val: toValue(val1)},
- job{code: expr2, val: toValue(val2)},
+ {code: stmts, noval: true},
+ {code: expr1, val: toValue(val1)},
+ {code: expr2, val: toValue(val2)},
})
}
@@ -166,12 +171,12 @@ func toValue(val interface{}) Value {
case int:
r := intV(val)
return &r
- case *bignum.Integer:
+ case *big.Int:
return &idealIntV{val}
case float:
r := floatV(val)
return &r
- case *bignum.Rational:
+ case *big.Rat:
return &idealFloatV{val}
case string:
r := stringV(val)
@@ -195,7 +200,7 @@ func toValue(val interface{}) Value {
case Func:
return &funcV{val}
}
- log.Crashf("toValue(%T) not implemented", val)
+ log.Panicf("toValue(%T) not implemented", val)
panic("unreachable")
}
@@ -205,7 +210,7 @@ func toValue(val interface{}) Value {
type testFunc struct{}
-func (*testFunc) NewFrame() *Frame { return &Frame{nil, &[2]Value{}} }
+func (*testFunc) NewFrame() *Frame { return &Frame{nil, make([]Value, 2)} }
func (*testFunc) Call(t *Thread) {
n := t.f.Vars[0].(IntValue).Get(t)
@@ -217,7 +222,7 @@ func (*testFunc) Call(t *Thread) {
type oneTwoFunc struct{}
-func (*oneTwoFunc) NewFrame() *Frame { return &Frame{nil, &[2]Value{}} }
+func (*oneTwoFunc) NewFrame() *Frame { return &Frame{nil, make([]Value, 2)} }
func (*oneTwoFunc) Call(t *Thread) {
t.f.Vars[0].(IntValue).Set(t, 1)
@@ -235,13 +240,13 @@ func newTestWorld() *World {
def := func(name string, t Type, val interface{}) { w.DefineVar(name, t, toValue(val)) }
- w.DefineConst("c", IdealIntType, toValue(bignum.Int(1)))
+ w.DefineConst("c", IdealIntType, toValue(big.NewInt(1)))
def("i", IntType, 1)
def("i2", IntType, 2)
def("u", UintType, uint(1))
def("f", FloatType, 1.0)
def("s", StringType, "abc")
- def("t", NewStructType([]StructField{StructField{"a", IntType, false}}), vstruct{1})
+ def("t", NewStructType([]StructField{{"a", IntType, false}}), vstruct{1})
def("ai", NewArrayType(2, IntType), varray{1, 2})
def("aai", NewArrayType(2, NewArrayType(2, IntType)), varray{varray{1, 2}, varray{3, 4}})
def("aai2", NewArrayType(2, NewArrayType(2, IntType)), varray{varray{5, 6}, varray{7, 8}})
diff --git a/src/pkg/exp/eval/expr.go b/src/pkg/exp/eval/expr.go
index ea8117d06..70f63cf2d 100644
--- a/src/pkg/exp/eval/expr.go
+++ b/src/pkg/exp/eval/expr.go
@@ -5,7 +5,7 @@
package eval
import (
- "exp/bignum"
+ "big"
"fmt"
"go/ast"
"go/token"
@@ -15,6 +15,11 @@ import (
"os"
)
+var (
+ idealZero = big.NewInt(0)
+ idealOne = big.NewInt(1)
+)
+
// An expr is the result of compiling an expression. It stores the
// type of the expression and its evaluator function.
type expr struct {
@@ -52,7 +57,7 @@ type expr struct {
// compiled from it.
type exprInfo struct {
*compiler
- pos token.Position
+ pos token.Pos
}
func (a *exprInfo) newExpr(t Type, desc string) *expr {
@@ -60,7 +65,7 @@ func (a *exprInfo) newExpr(t Type, desc string) *expr {
}
func (a *exprInfo) diag(format string, args ...interface{}) {
- a.diagAt(&a.pos, format, args)
+ a.diagAt(a.pos, format, args...)
}
func (a *exprInfo) diagOpType(op token.Token, vt Type) {
@@ -82,10 +87,10 @@ func (a *exprInfo) diagOpTypes(op token.Token, lt Type, rt Type) {
// TODO(austin) Rename to resolveIdeal or something?
func (a *expr) convertTo(t Type) *expr {
if !a.t.isIdeal() {
- log.Crashf("attempted to convert from %v, expected ideal", a.t)
+ log.Panicf("attempted to convert from %v, expected ideal", a.t)
}
- var rat *bignum.Rational
+ var rat *big.Rat
// XXX(Spec) The spec says "It is erroneous".
//
@@ -97,24 +102,24 @@ func (a *expr) convertTo(t Type) *expr {
case IdealFloatType:
rat = a.asIdealFloat()()
if t.isInteger() && !rat.IsInt() {
- a.diag("constant %v truncated to integer", ratToString(rat))
+ a.diag("constant %v truncated to integer", rat.FloatString(6))
return nil
}
case IdealIntType:
i := a.asIdealInt()()
- rat = bignum.MakeRat(i, bignum.Nat(1))
+ rat = new(big.Rat).SetInt(i)
default:
- log.Crashf("unexpected ideal type %v", a.t)
+ log.Panicf("unexpected ideal type %v", a.t)
}
// Check bounds
if t, ok := t.lit().(BoundedType); ok {
if rat.Cmp(t.minVal()) < 0 {
- a.diag("constant %v underflows %v", ratToString(rat), t)
+ a.diag("constant %v underflows %v", rat.FloatString(6), t)
return nil
}
if rat.Cmp(t.maxVal()) > 0 {
- a.diag("constant %v overflows %v", ratToString(rat), t)
+ a.diag("constant %v overflows %v", rat.FloatString(6), t)
return nil
}
}
@@ -123,27 +128,28 @@ func (a *expr) convertTo(t Type) *expr {
res := a.newExpr(t, a.desc)
switch t := t.lit().(type) {
case *uintType:
- n, d := rat.Value()
- f := n.Quo(bignum.MakeInt(false, d))
- v := f.Abs().Value()
+ n, d := rat.Num(), rat.Denom()
+ f := new(big.Int).Quo(n, d)
+ f = f.Abs(f)
+ v := uint64(f.Int64())
res.eval = func(*Thread) uint64 { return v }
case *intType:
- n, d := rat.Value()
- f := n.Quo(bignum.MakeInt(false, d))
- v := f.Value()
+ n, d := rat.Num(), rat.Denom()
+ f := new(big.Int).Quo(n, d)
+ v := f.Int64()
res.eval = func(*Thread) int64 { return v }
case *idealIntType:
- n, d := rat.Value()
- f := n.Quo(bignum.MakeInt(false, d))
- res.eval = func() *bignum.Integer { return f }
+ n, d := rat.Num(), rat.Denom()
+ f := new(big.Int).Quo(n, d)
+ res.eval = func() *big.Int { return f }
case *floatType:
- n, d := rat.Value()
- v := float64(n.Value()) / float64(d.Value())
+ n, d := rat.Num(), rat.Denom()
+ v := float64(n.Int64()) / float64(d.Int64())
res.eval = func(*Thread) float64 { return v }
case *idealFloatType:
- res.eval = func() *bignum.Rational { return rat }
+ res.eval = func() *big.Rat { return rat }
default:
- log.Crashf("cannot convert to type %T", t)
+ log.Panicf("cannot convert to type %T", t)
}
return res
@@ -158,7 +164,7 @@ func (a *expr) convertToInt(max int64, negErr string, errOp string) *expr {
switch a.t.lit().(type) {
case *idealIntType:
val := a.asIdealInt()()
- if negErr != "" && val.IsNeg() {
+ if negErr != "" && val.Sign() < 0 {
a.diag("negative %s: %s", negErr, val)
return nil
}
@@ -166,7 +172,7 @@ func (a *expr) convertToInt(max int64, negErr string, errOp string) *expr {
if negErr == "slice" {
bound++
}
- if max != -1 && val.Cmp(bignum.Int(bound)) >= 0 {
+ if max != -1 && val.Cmp(big.NewInt(bound)) >= 0 {
a.diag("index %s exceeds length %d", val, max)
return nil
}
@@ -196,7 +202,7 @@ func (a *expr) derefArray() *expr {
if _, ok := pt.Elem.lit().(*ArrayType); ok {
deref := a.compileStarExpr(a)
if deref == nil {
- log.Crashf("failed to dereference *array")
+ log.Panicf("failed to dereference *array")
}
return deref
}
@@ -223,7 +229,7 @@ func (a *expr) derefArray() *expr {
// multi-valued type.
type assignCompiler struct {
*compiler
- pos token.Position
+ pos token.Pos
// The RHS expressions. This may include nil's for
// expressions that failed to compile.
rs []*expr
@@ -248,7 +254,7 @@ type assignCompiler struct {
// assignCompiler with rmt set, but if type checking fails, slots in
// the MultiType may be nil. If rs contains nil's, type checking will
// fail and these expressions given a nil type.
-func (a *compiler) checkAssign(pos token.Position, rs []*expr, errOp, errPosName string) (*assignCompiler, bool) {
+func (a *compiler) checkAssign(pos token.Pos, rs []*expr, errOp, errPosName string) (*assignCompiler, bool) {
c := &assignCompiler{
compiler: a,
pos: pos,
@@ -325,7 +331,7 @@ func (a *assignCompiler) compile(b *block, lt Type) func(Value, *Thread) {
pos = a.rs[lcount-1].pos
}
}
- a.diagAt(&pos, "%s %ss for %s\n\t%s\n\t%s", msg, a.errPosName, a.errOp, lt, rmt)
+ a.diagAt(pos, "%s %ss for %s\n\t%s\n\t%s", msg, a.errPosName, a.errOp, lt, rmt)
return nil
}
@@ -364,7 +370,7 @@ func (a *assignCompiler) compile(b *block, lt Type) func(Value, *Thread) {
a.rs = make([]*expr, len(a.rmt.Elems))
for i, t := range a.rmt.Elems {
if t.isIdeal() {
- log.Crashf("Right side of unpack contains ideal: %s", rmt)
+ log.Panicf("Right side of unpack contains ideal: %s", rmt)
}
a.rs[i] = orig.newExpr(t, orig.desc)
index := i
@@ -447,7 +453,7 @@ func (a *assignCompiler) compile(b *block, lt Type) func(Value, *Thread) {
// compileAssign compiles an assignment operation without the full
// generality of an assignCompiler. See assignCompiler for a
// description of the arguments.
-func (a *compiler) compileAssign(pos token.Position, b *block, lt Type, rs []*expr, errOp, errPosName string) func(Value, *Thread) {
+func (a *compiler) compileAssign(pos token.Pos, b *block, lt Type, rs []*expr, errOp, errPosName string) func(Value, *Thread) {
ac, ok := a.checkAssign(pos, rs, errOp, errPosName)
if !ok {
return nil
@@ -490,7 +496,7 @@ func (a *exprCompiler) compile(x ast.Expr, callCtx bool) *expr {
case token.STRING:
return ei.compileStringLit(string(x.Value))
default:
- log.Crashf("unexpected basic literal type %v", x.Kind)
+ log.Panicf("unexpected basic literal type %v", x.Kind)
}
case *ast.CompositeLit:
@@ -508,7 +514,7 @@ func (a *exprCompiler) compile(x ast.Expr, callCtx bool) *expr {
return nil
}
if a.constant {
- a.diagAt(x, "function literal used in constant expression")
+ a.diagAt(x.Pos(), "function literal used in constant expression")
return nil
}
return ei.compileFuncLit(decl, fn)
@@ -565,12 +571,12 @@ func (a *exprCompiler) compile(x ast.Expr, callCtx bool) *expr {
return nil
}
if a.constant {
- a.diagAt(x, "function call in constant context")
+ a.diagAt(x.Pos(), "function call in constant context")
return nil
}
if l.valType != nil {
- a.diagAt(x, "type conversions not implemented")
+ a.diagAt(x.Pos(), "type conversions not implemented")
return nil
} else if ft, ok := l.t.(*FuncType); ok && ft.builtin != "" {
return ei.compileBuiltinCallExpr(a.block, ft, args)
@@ -579,7 +585,7 @@ func (a *exprCompiler) compile(x ast.Expr, callCtx bool) *expr {
}
case *ast.Ident:
- return ei.compileIdent(a.block, a.constant, callCtx, x.Name())
+ return ei.compileIdent(a.block, a.constant, callCtx, x.Name)
case *ast.IndexExpr:
l, r := a.compile(x.X, false), a.compile(x.Index, false)
@@ -589,15 +595,21 @@ func (a *exprCompiler) compile(x ast.Expr, callCtx bool) *expr {
return ei.compileIndexExpr(l, r)
case *ast.SliceExpr:
- var hi *expr
+ var lo, hi *expr
arr := a.compile(x.X, false)
- lo := a.compile(x.Index, false)
- if x.End == nil {
+ if x.Low == nil {
+ // beginning was omitted, so we need to provide it
+ ei := &exprInfo{a.compiler, x.Pos()}
+ lo = ei.compileIntLit("0")
+ } else {
+ lo = a.compile(x.Low, false)
+ }
+ if x.High == nil {
// End was omitted, so we need to compute len(x.X)
ei := &exprInfo{a.compiler, x.Pos()}
hi = ei.compileBuiltinCallExpr(a.block, lenType, []*expr{arr})
} else {
- hi = a.compile(x.End, false)
+ hi = a.compile(x.High, false)
}
if arr == nil || lo == nil || hi == nil {
return nil
@@ -615,7 +627,7 @@ func (a *exprCompiler) compile(x ast.Expr, callCtx bool) *expr {
if v == nil {
return nil
}
- return ei.compileSelectorExpr(v, x.Sel.Name())
+ return ei.compileSelectorExpr(v, x.Sel.Name)
case *ast.StarExpr:
// We pass down our call context because this could be
@@ -643,18 +655,18 @@ func (a *exprCompiler) compile(x ast.Expr, callCtx bool) *expr {
}
return ei.compileUnaryExpr(x.Op, v)
}
- log.Crashf("unexpected ast node type %T", x)
+ log.Panicf("unexpected ast node type %T", x)
panic("unreachable")
typeexpr:
if !callCtx {
- a.diagAt(x, "type used as expression")
+ a.diagAt(x.Pos(), "type used as expression")
return nil
}
return ei.exprFromType(a.compileType(a.block, x))
notimpl:
- a.diagAt(x, "%T expression node not implemented", x)
+ a.diagAt(x.Pos(), "%T expression node not implemented", x)
return nil
}
@@ -705,7 +717,7 @@ func (a *exprInfo) compileIdent(b *block, constant bool, callCtx bool, name stri
a.diag("type %v used as expression", name)
return nil
}
- log.Crashf("name %s has unknown type %T", name, def)
+ log.Panicf("name %s has unknown type %T", name, def)
panic("unreachable")
}
@@ -735,14 +747,14 @@ func (a *exprInfo) compileGlobalVariable(v *Variable) *expr {
return expr
}
-func (a *exprInfo) compileIdealInt(i *bignum.Integer, desc string) *expr {
+func (a *exprInfo) compileIdealInt(i *big.Int, desc string) *expr {
expr := a.newExpr(IdealIntType, desc)
- expr.eval = func() *bignum.Integer { return i }
+ expr.eval = func() *big.Int { return i }
return expr
}
func (a *exprInfo) compileIntLit(lit string) *expr {
- i, _, _ := bignum.IntFromString(lit, 0)
+ i, _ := new(big.Int).SetString(lit, 0)
return a.compileIdealInt(i, "integer literal")
}
@@ -758,16 +770,16 @@ func (a *exprInfo) compileCharLit(lit string) *expr {
a.silentErrors++
return nil
}
- return a.compileIdealInt(bignum.Int(int64(v)), "character literal")
+ return a.compileIdealInt(big.NewInt(int64(v)), "character literal")
}
func (a *exprInfo) compileFloatLit(lit string) *expr {
- f, _, n := bignum.RatFromString(lit, 10)
- if n != len(lit) {
- log.Crashf("malformed float literal %s at %v passed parser", lit, a.pos)
+ f, ok := new(big.Rat).SetString(lit)
+ if !ok {
+ log.Panicf("malformed float literal %s at %v passed parser", lit, a.pos)
}
expr := a.newExpr(IdealFloatType, "float literal")
- expr.eval = func() *bignum.Rational { return f }
+ expr.eval = func() *big.Rat { return f }
return expr
}
@@ -822,7 +834,7 @@ func (a *exprInfo) compileSelectorExpr(v *expr, name string) *expr {
ambig = true
default:
- log.Crashf("Marked field at depth %d, but already found one at depth %d", depth, bestDepth)
+ log.Panicf("Marked field at depth %d, but already found one at depth %d", depth, bestDepth)
}
amberr += "\n\t" + pathName[1:]
}
@@ -864,7 +876,7 @@ func (a *exprInfo) compileSelectorExpr(v *expr, name string) *expr {
_, ok := ti.methods[name]
if ok {
mark(depth, pathName+"."+name)
- log.Crash("Methods not implemented")
+ log.Panic("Methods not implemented")
}
t = ti.Def
}
@@ -996,7 +1008,7 @@ func (a *exprInfo) compileSliceExpr(arr, lo, hi *expr) *expr {
}
default:
- log.Crashf("unexpected left operand type %T", arr.t.lit())
+ log.Panicf("unexpected left operand type %T", arr.t.lit())
}
return expr
@@ -1120,7 +1132,7 @@ func (a *exprInfo) compileIndexExpr(l, r *expr) *expr {
}
default:
- log.Crashf("unexpected left operand type %T", l.t.lit())
+ log.Panicf("unexpected left operand type %T", l.t.lit())
}
return expr
@@ -1168,12 +1180,8 @@ func (a *exprInfo) compileCallExpr(b *block, l *expr, as []*expr) *expr {
// Gather argument and out types to initialize frame variables
vts := make([]Type, nin+nout)
- for i, t := range lt.In {
- vts[i] = t
- }
- for i, t := range lt.Out {
- vts[i+nin] = t
- }
+ copy(vts, lt.In)
+ copy(vts[nin:], lt.Out)
// Compile
lf := l.asFunc()
@@ -1233,6 +1241,38 @@ func (a *exprInfo) compileBuiltinCallExpr(b *block, ft *FuncType, as []*expr) *e
}
return expr
+ case copyType:
+ if !checkCount(2, 2) {
+ return nil
+ }
+ src := as[1]
+ dst := as[0]
+ if src.t != dst.t {
+ a.diag("arguments to built-in function 'copy' must have same type\nsrc: %s\ndst: %s\n", src.t, dst.t)
+ return nil
+ }
+ if _, ok := src.t.lit().(*SliceType); !ok {
+ a.diag("src argument to 'copy' must be a slice (got: %s)", src.t)
+ return nil
+ }
+ if _, ok := dst.t.lit().(*SliceType); !ok {
+ a.diag("dst argument to 'copy' must be a slice (got: %s)", dst.t)
+ return nil
+ }
+ expr := a.newExpr(IntType, "function call")
+ srcf := src.asSlice()
+ dstf := dst.asSlice()
+ expr.eval = func(t *Thread) int64 {
+ src, dst := srcf(t), dstf(t)
+ nelems := src.Len
+ if nelems > dst.Len {
+ nelems = dst.Len
+ }
+ dst.Base.Sub(0, nelems).Assign(t, src.Base.Sub(0, nelems))
+ return nelems
+ }
+ return expr
+
case lenType:
if !checkCount(1, 1) {
return nil
@@ -1425,7 +1465,7 @@ func (a *exprInfo) compileBuiltinCallExpr(b *block, ft *FuncType, as []*expr) *e
return expr
}
- log.Crashf("unexpected built-in function '%s'", ft.builtin)
+ log.Panicf("unexpected built-in function '%s'", ft.builtin)
panic("unreachable")
}
@@ -1492,10 +1532,10 @@ func (a *exprInfo) compileUnaryExpr(op token.Token, v *expr) *expr {
t = NewPtrType(v.t)
case token.ARROW:
- log.Crashf("Unary op %v not implemented", op)
+ log.Panicf("Unary op %v not implemented", op)
default:
- log.Crashf("unknown unary operator %v", op)
+ log.Panicf("unknown unary operator %v", op)
}
desc, ok := unaryOpDescs[op]
@@ -1526,7 +1566,7 @@ func (a *exprInfo) compileUnaryExpr(op token.Token, v *expr) *expr {
expr.eval = func(t *Thread) Value { return vf(t) }
default:
- log.Crashf("Compilation of unary op %v not implemented", op)
+ log.Panicf("Compilation of unary op %v not implemented", op)
}
return expr
@@ -1650,7 +1690,7 @@ func (a *exprInfo) compileBinaryExpr(op token.Token, l, r *expr) *expr {
if l.t.isIdeal() && !r.t.isInteger() {
r = r.convertTo(IdealIntType)
if r == nil {
- log.Crashf("conversion to uintType succeeded, but conversion to idealIntType failed")
+ log.Panicf("conversion to uintType succeeded, but conversion to idealIntType failed")
}
}
} else if _, ok := r.t.lit().(*uintType); !ok {
@@ -1693,7 +1733,7 @@ func (a *exprInfo) compileBinaryExpr(op token.Token, l, r *expr) *expr {
// The operands in channel sends differ in type: one
// is always a channel and the other is a variable or
// value of the channel's element type.
- log.Crash("Binary op <- not implemented")
+ log.Panic("Binary op <- not implemented")
t = BoolType
case token.LSS, token.GTR, token.LEQ, token.GEQ:
@@ -1761,7 +1801,7 @@ func (a *exprInfo) compileBinaryExpr(op token.Token, l, r *expr) *expr {
t = BoolType
default:
- log.Crashf("unknown binary operator %v", op)
+ log.Panicf("unknown binary operator %v", op)
}
desc, ok := binOpDescs[op]
@@ -1774,8 +1814,8 @@ func (a *exprInfo) compileBinaryExpr(op token.Token, l, r *expr) *expr {
switch op {
case token.QUO, token.REM:
if r.t.isIdeal() {
- if (r.t.isInteger() && r.asIdealInt()().IsZero()) ||
- (r.t.isFloat() && r.asIdealFloat()().IsZero()) {
+ if (r.t.isInteger() && r.asIdealInt()().Sign() == 0) ||
+ (r.t.isFloat() && r.asIdealFloat()().Sign() == 0) {
a.diag("divide by zero")
return nil
}
@@ -1817,13 +1857,13 @@ func (a *exprInfo) compileBinaryExpr(op token.Token, l, r *expr) *expr {
lv := l.asIdealInt()()
rv := r.asIdealInt()()
const maxShift = 99999
- if rv.Cmp(bignum.Int(maxShift)) > 0 {
+ if rv.Cmp(big.NewInt(maxShift)) > 0 {
a.diag("left shift by %v; exceeds implementation limit of %v", rv, maxShift)
expr.t = nil
return nil
}
- val := lv.Shl(uint(rv.Value()))
- expr.eval = func() *bignum.Integer { return val }
+ val := new(big.Int).Lsh(lv, uint(rv.Int64()))
+ expr.eval = func() *big.Int { return val }
} else {
expr.genBinOpShl(l, r)
}
@@ -1832,8 +1872,8 @@ func (a *exprInfo) compileBinaryExpr(op token.Token, l, r *expr) *expr {
if l.t.isIdeal() {
lv := l.asIdealInt()()
rv := r.asIdealInt()()
- val := lv.Shr(uint(rv.Value()))
- expr.eval = func() *bignum.Integer { return val }
+ val := new(big.Int).Rsh(lv, uint(rv.Int64()))
+ expr.eval = func() *big.Int { return val }
} else {
expr.genBinOpShr(l, r)
}
@@ -1863,7 +1903,7 @@ func (a *exprInfo) compileBinaryExpr(op token.Token, l, r *expr) *expr {
expr.genBinOpLogOr(l, r)
default:
- log.Crashf("Compilation of binary op %v not implemented", op)
+ log.Panicf("Compilation of binary op %v not implemented", op)
}
return expr
@@ -1886,7 +1926,7 @@ func (a *compiler) compileArrayLen(b *block, expr ast.Expr) (int64, bool) {
}
if !lenExpr.t.isInteger() {
- a.diagAt(expr, "array size must be an integer")
+ a.diagAt(expr.Pos(), "array size must be an integer")
return 0, false
}
@@ -1896,7 +1936,7 @@ func (a *compiler) compileArrayLen(b *block, expr ast.Expr) (int64, bool) {
case *uintType:
return int64(lenExpr.asUint()(nil)), true
}
- log.Crashf("unexpected integer type %T", lenExpr.t)
+ log.Panicf("unexpected integer type %T", lenExpr.t)
return 0, false
}
@@ -1905,7 +1945,7 @@ func (a *compiler) compileExpr(b *block, constant bool, expr ast.Expr) *expr {
nerr := a.numError()
e := ec.compile(expr, false)
if e == nil && nerr == a.numError() {
- log.Crashf("expression compilation failed without reporting errors")
+ log.Panicf("expression compilation failed without reporting errors")
}
return e
}
@@ -1943,7 +1983,7 @@ func (a *expr) extractEffect(b *block, errOp string) (func(*Thread), *expr) {
case tempType.isFloat():
tempType = FloatType
default:
- log.Crashf("unexpected ideal type %v", tempType)
+ log.Panicf("unexpected ideal type %v", tempType)
}
}
temp := b.DefineTemp(tempType)
@@ -1952,7 +1992,7 @@ func (a *expr) extractEffect(b *block, errOp string) (func(*Thread), *expr) {
// Create "temp := rhs"
assign := ac.compile(b, tempType)
if assign == nil {
- log.Crashf("compileAssign type check failed")
+ log.Panicf("compileAssign type check failed")
}
effect := func(t *Thread) {
diff --git a/src/pkg/exp/eval/expr1.go b/src/pkg/exp/eval/expr1.go
index f0a78ac4d..ae0cfc723 100644..100755
--- a/src/pkg/exp/eval/expr1.go
+++ b/src/pkg/exp/eval/expr1.go
@@ -4,13 +4,13 @@
package eval
import (
- "exp/bignum"
+ "big"
"log"
)
/*
- * "As" functions. These retrieve evaluator functions from an
- * expr, panicking if the requested evaluator has the wrong type.
+* "As" functions. These retrieve evaluator functions from an
+* expr, panicking if the requested evaluator has the wrong type.
*/
func (a *expr) asBool() func(*Thread) bool {
return a.eval.(func(*Thread) bool)
@@ -21,14 +21,14 @@ func (a *expr) asUint() func(*Thread) uint64 {
func (a *expr) asInt() func(*Thread) int64 {
return a.eval.(func(*Thread) int64)
}
-func (a *expr) asIdealInt() func() *bignum.Integer {
- return a.eval.(func() *bignum.Integer)
+func (a *expr) asIdealInt() func() *big.Int {
+ return a.eval.(func() *big.Int)
}
func (a *expr) asFloat() func(*Thread) float64 {
return a.eval.(func(*Thread) float64)
}
-func (a *expr) asIdealFloat() func() *bignum.Rational {
- return a.eval.(func() *bignum.Rational)
+func (a *expr) asIdealFloat() func() *big.Rat {
+ return a.eval.(func() *big.Rat)
}
func (a *expr) asString() func(*Thread) string {
return a.eval.(func(*Thread) string)
@@ -63,11 +63,11 @@ func (a *expr) asInterface() func(*Thread) interface{} {
return func(t *Thread) interface{} { return sf(t) }
case func(t *Thread) int64:
return func(t *Thread) interface{} { return sf(t) }
- case func() *bignum.Integer:
+ case func() *big.Int:
return func(*Thread) interface{} { return sf() }
case func(t *Thread) float64:
return func(t *Thread) interface{} { return sf(t) }
- case func() *bignum.Rational:
+ case func() *big.Rat:
return func(*Thread) interface{} { return sf() }
case func(t *Thread) string:
return func(t *Thread) interface{} { return sf(t) }
@@ -84,13 +84,13 @@ func (a *expr) asInterface() func(*Thread) interface{} {
case func(t *Thread) Map:
return func(t *Thread) interface{} { return sf(t) }
default:
- log.Crashf("unexpected expression node type %T at %v", a.eval, a.pos)
+ log.Panicf("unexpected expression node type %T at %v", a.eval, a.pos)
}
panic("fail")
}
/*
- * Operator generators.
+* Operator generators.
*/
func (a *expr) genConstant(v Value) {
@@ -103,12 +103,12 @@ func (a *expr) genConstant(v Value) {
a.eval = func(t *Thread) int64 { return v.(IntValue).Get(t) }
case *idealIntType:
val := v.(IdealIntValue).Get()
- a.eval = func() *bignum.Integer { return val }
+ a.eval = func() *big.Int { return val }
case *floatType:
a.eval = func(t *Thread) float64 { return v.(FloatValue).Get(t) }
case *idealFloatType:
val := v.(IdealFloatValue).Get()
- a.eval = func() *bignum.Rational { return val }
+ a.eval = func() *big.Rat { return val }
case *stringType:
a.eval = func(t *Thread) string { return v.(StringValue).Get(t) }
case *ArrayType:
@@ -124,7 +124,7 @@ func (a *expr) genConstant(v Value) {
case *MapType:
a.eval = func(t *Thread) Map { return v.(MapValue).Get(t) }
default:
- log.Crashf("unexpected constant type %v at %v", a.t, a.pos)
+ log.Panicf("unexpected constant type %v at %v", a.t, a.pos)
}
}
@@ -154,7 +154,7 @@ func (a *expr) genIdentOp(level, index int) {
case *MapType:
a.eval = func(t *Thread) Map { return t.f.Get(level, index).(MapValue).Get(t) }
default:
- log.Crashf("unexpected identifier type %v at %v", a.t, a.pos)
+ log.Panicf("unexpected identifier type %v at %v", a.t, a.pos)
}
}
@@ -186,7 +186,7 @@ func (a *expr) genFuncCall(call func(t *Thread) []Value) {
case *MultiType:
a.eval = func(t *Thread) []Value { return call(t) }
default:
- log.Crashf("unexpected result type %v at %v", a.t, a.pos)
+ log.Panicf("unexpected result type %v at %v", a.t, a.pos)
}
}
@@ -216,7 +216,7 @@ func (a *expr) genValue(vf func(*Thread) Value) {
case *MapType:
a.eval = func(t *Thread) Map { return vf(t).(MapValue).Get(t) }
default:
- log.Crashf("unexpected result type %v at %v", a.t, a.pos)
+ log.Panicf("unexpected result type %v at %v", a.t, a.pos)
}
}
@@ -229,18 +229,18 @@ func (a *expr) genUnaryOpNeg(v *expr) {
vf := v.asInt()
a.eval = func(t *Thread) int64 { v := vf(t); return -v }
case *idealIntType:
- v := v.asIdealInt()()
- val := v.Neg()
- a.eval = func() *bignum.Integer { return val }
+ val := v.asIdealInt()()
+ val.Neg(val)
+ a.eval = func() *big.Int { return val }
case *floatType:
vf := v.asFloat()
a.eval = func(t *Thread) float64 { v := vf(t); return -v }
case *idealFloatType:
- v := v.asIdealFloat()()
- val := v.Neg()
- a.eval = func() *bignum.Rational { return val }
+ val := v.asIdealFloat()()
+ val.Neg(val)
+ a.eval = func() *big.Rat { return val }
default:
- log.Crashf("unexpected type %v at %v", a.t, a.pos)
+ log.Panicf("unexpected type %v at %v", a.t, a.pos)
}
}
@@ -250,7 +250,7 @@ func (a *expr) genUnaryOpNot(v *expr) {
vf := v.asBool()
a.eval = func(t *Thread) bool { v := vf(t); return !v }
default:
- log.Crashf("unexpected type %v at %v", a.t, a.pos)
+ log.Panicf("unexpected type %v at %v", a.t, a.pos)
}
}
@@ -263,11 +263,11 @@ func (a *expr) genUnaryOpXor(v *expr) {
vf := v.asInt()
a.eval = func(t *Thread) int64 { v := vf(t); return ^v }
case *idealIntType:
- v := v.asIdealInt()()
- val := v.Neg().Sub(bignum.Int(1))
- a.eval = func() *bignum.Integer { return val }
+ val := v.asIdealInt()()
+ val.Not(val)
+ a.eval = func() *big.Int { return val }
default:
- log.Crashf("unexpected type %v at %v", a.t, a.pos)
+ log.Panicf("unexpected type %v at %v", a.t, a.pos)
}
}
@@ -325,7 +325,7 @@ func (a *expr) genBinOpAdd(l, r *expr) {
return uint64(uint(ret))
}
default:
- log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+ log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
}
case *intType:
lf := l.asInt()
@@ -367,13 +367,13 @@ func (a *expr) genBinOpAdd(l, r *expr) {
return int64(int(ret))
}
default:
- log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+ log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
}
case *idealIntType:
l := l.asIdealInt()()
r := r.asIdealInt()()
- val := l.Add(r)
- a.eval = func() *bignum.Integer { return val }
+ val := l.Add(l, r)
+ a.eval = func() *big.Int { return val }
case *floatType:
lf := l.asFloat()
rf := r.asFloat()
@@ -400,13 +400,13 @@ func (a *expr) genBinOpAdd(l, r *expr) {
return float64(float(ret))
}
default:
- log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+ log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
}
case *idealFloatType:
l := l.asIdealFloat()()
r := r.asIdealFloat()()
- val := l.Add(r)
- a.eval = func() *bignum.Rational { return val }
+ val := l.Add(l, r)
+ a.eval = func() *big.Rat { return val }
case *stringType:
lf := l.asString()
rf := r.asString()
@@ -415,7 +415,7 @@ func (a *expr) genBinOpAdd(l, r *expr) {
return l + r
}
default:
- log.Crashf("unexpected type %v at %v", l.t, a.pos)
+ log.Panicf("unexpected type %v at %v", l.t, a.pos)
}
}
@@ -461,7 +461,7 @@ func (a *expr) genBinOpSub(l, r *expr) {
return uint64(uint(ret))
}
default:
- log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+ log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
}
case *intType:
lf := l.asInt()
@@ -503,13 +503,13 @@ func (a *expr) genBinOpSub(l, r *expr) {
return int64(int(ret))
}
default:
- log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+ log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
}
case *idealIntType:
l := l.asIdealInt()()
r := r.asIdealInt()()
- val := l.Sub(r)
- a.eval = func() *bignum.Integer { return val }
+ val := l.Sub(l, r)
+ a.eval = func() *big.Int { return val }
case *floatType:
lf := l.asFloat()
rf := r.asFloat()
@@ -536,15 +536,15 @@ func (a *expr) genBinOpSub(l, r *expr) {
return float64(float(ret))
}
default:
- log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+ log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
}
case *idealFloatType:
l := l.asIdealFloat()()
r := r.asIdealFloat()()
- val := l.Sub(r)
- a.eval = func() *bignum.Rational { return val }
+ val := l.Sub(l, r)
+ a.eval = func() *big.Rat { return val }
default:
- log.Crashf("unexpected type %v at %v", l.t, a.pos)
+ log.Panicf("unexpected type %v at %v", l.t, a.pos)
}
}
@@ -590,7 +590,7 @@ func (a *expr) genBinOpMul(l, r *expr) {
return uint64(uint(ret))
}
default:
- log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+ log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
}
case *intType:
lf := l.asInt()
@@ -632,13 +632,13 @@ func (a *expr) genBinOpMul(l, r *expr) {
return int64(int(ret))
}
default:
- log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+ log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
}
case *idealIntType:
l := l.asIdealInt()()
r := r.asIdealInt()()
- val := l.Mul(r)
- a.eval = func() *bignum.Integer { return val }
+ val := l.Mul(l, r)
+ a.eval = func() *big.Int { return val }
case *floatType:
lf := l.asFloat()
rf := r.asFloat()
@@ -665,15 +665,15 @@ func (a *expr) genBinOpMul(l, r *expr) {
return float64(float(ret))
}
default:
- log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+ log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
}
case *idealFloatType:
l := l.asIdealFloat()()
r := r.asIdealFloat()()
- val := l.Mul(r)
- a.eval = func() *bignum.Rational { return val }
+ val := l.Mul(l, r)
+ a.eval = func() *big.Rat { return val }
default:
- log.Crashf("unexpected type %v at %v", l.t, a.pos)
+ log.Panicf("unexpected type %v at %v", l.t, a.pos)
}
}
@@ -734,7 +734,7 @@ func (a *expr) genBinOpQuo(l, r *expr) {
return uint64(uint(ret))
}
default:
- log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+ log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
}
case *intType:
lf := l.asInt()
@@ -791,13 +791,13 @@ func (a *expr) genBinOpQuo(l, r *expr) {
return int64(int(ret))
}
default:
- log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+ log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
}
case *idealIntType:
l := l.asIdealInt()()
r := r.asIdealInt()()
- val := l.Quo(r)
- a.eval = func() *bignum.Integer { return val }
+ val := l.Quo(l, r)
+ a.eval = func() *big.Int { return val }
case *floatType:
lf := l.asFloat()
rf := r.asFloat()
@@ -833,15 +833,15 @@ func (a *expr) genBinOpQuo(l, r *expr) {
return float64(float(ret))
}
default:
- log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+ log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
}
case *idealFloatType:
l := l.asIdealFloat()()
r := r.asIdealFloat()()
- val := l.Quo(r)
- a.eval = func() *bignum.Rational { return val }
+ val := l.Quo(l, r)
+ a.eval = func() *big.Rat { return val }
default:
- log.Crashf("unexpected type %v at %v", l.t, a.pos)
+ log.Panicf("unexpected type %v at %v", l.t, a.pos)
}
}
@@ -902,7 +902,7 @@ func (a *expr) genBinOpRem(l, r *expr) {
return uint64(uint(ret))
}
default:
- log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+ log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
}
case *intType:
lf := l.asInt()
@@ -959,15 +959,15 @@ func (a *expr) genBinOpRem(l, r *expr) {
return int64(int(ret))
}
default:
- log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+ log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
}
case *idealIntType:
l := l.asIdealInt()()
r := r.asIdealInt()()
- val := l.Rem(r)
- a.eval = func() *bignum.Integer { return val }
+ val := l.Rem(l, r)
+ a.eval = func() *big.Int { return val }
default:
- log.Crashf("unexpected type %v at %v", l.t, a.pos)
+ log.Panicf("unexpected type %v at %v", l.t, a.pos)
}
}
@@ -1013,7 +1013,7 @@ func (a *expr) genBinOpAnd(l, r *expr) {
return uint64(uint(ret))
}
default:
- log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+ log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
}
case *intType:
lf := l.asInt()
@@ -1055,15 +1055,15 @@ func (a *expr) genBinOpAnd(l, r *expr) {
return int64(int(ret))
}
default:
- log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+ log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
}
case *idealIntType:
l := l.asIdealInt()()
r := r.asIdealInt()()
- val := l.And(r)
- a.eval = func() *bignum.Integer { return val }
+ val := l.And(l, r)
+ a.eval = func() *big.Int { return val }
default:
- log.Crashf("unexpected type %v at %v", l.t, a.pos)
+ log.Panicf("unexpected type %v at %v", l.t, a.pos)
}
}
@@ -1109,7 +1109,7 @@ func (a *expr) genBinOpOr(l, r *expr) {
return uint64(uint(ret))
}
default:
- log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+ log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
}
case *intType:
lf := l.asInt()
@@ -1151,15 +1151,15 @@ func (a *expr) genBinOpOr(l, r *expr) {
return int64(int(ret))
}
default:
- log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+ log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
}
case *idealIntType:
l := l.asIdealInt()()
r := r.asIdealInt()()
- val := l.Or(r)
- a.eval = func() *bignum.Integer { return val }
+ val := l.Or(l, r)
+ a.eval = func() *big.Int { return val }
default:
- log.Crashf("unexpected type %v at %v", l.t, a.pos)
+ log.Panicf("unexpected type %v at %v", l.t, a.pos)
}
}
@@ -1205,7 +1205,7 @@ func (a *expr) genBinOpXor(l, r *expr) {
return uint64(uint(ret))
}
default:
- log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+ log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
}
case *intType:
lf := l.asInt()
@@ -1247,15 +1247,15 @@ func (a *expr) genBinOpXor(l, r *expr) {
return int64(int(ret))
}
default:
- log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+ log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
}
case *idealIntType:
l := l.asIdealInt()()
r := r.asIdealInt()()
- val := l.Xor(r)
- a.eval = func() *bignum.Integer { return val }
+ val := l.Xor(l, r)
+ a.eval = func() *big.Int { return val }
default:
- log.Crashf("unexpected type %v at %v", l.t, a.pos)
+ log.Panicf("unexpected type %v at %v", l.t, a.pos)
}
}
@@ -1301,7 +1301,7 @@ func (a *expr) genBinOpAndNot(l, r *expr) {
return uint64(uint(ret))
}
default:
- log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+ log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
}
case *intType:
lf := l.asInt()
@@ -1343,15 +1343,15 @@ func (a *expr) genBinOpAndNot(l, r *expr) {
return int64(int(ret))
}
default:
- log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+ log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
}
case *idealIntType:
l := l.asIdealInt()()
r := r.asIdealInt()()
- val := l.AndNot(r)
- a.eval = func() *bignum.Integer { return val }
+ val := l.AndNot(l, r)
+ a.eval = func() *big.Int { return val }
default:
- log.Crashf("unexpected type %v at %v", l.t, a.pos)
+ log.Panicf("unexpected type %v at %v", l.t, a.pos)
}
}
@@ -1397,7 +1397,7 @@ func (a *expr) genBinOpShl(l, r *expr) {
return uint64(uint(ret))
}
default:
- log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+ log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
}
case *intType:
lf := l.asInt()
@@ -1439,10 +1439,10 @@ func (a *expr) genBinOpShl(l, r *expr) {
return int64(int(ret))
}
default:
- log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+ log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
}
default:
- log.Crashf("unexpected type %v at %v", l.t, a.pos)
+ log.Panicf("unexpected type %v at %v", l.t, a.pos)
}
}
@@ -1488,7 +1488,7 @@ func (a *expr) genBinOpShr(l, r *expr) {
return uint64(uint(ret))
}
default:
- log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+ log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
}
case *intType:
lf := l.asInt()
@@ -1530,10 +1530,10 @@ func (a *expr) genBinOpShr(l, r *expr) {
return int64(int(ret))
}
default:
- log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
+ log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
}
default:
- log.Crashf("unexpected type %v at %v", l.t, a.pos)
+ log.Panicf("unexpected type %v at %v", l.t, a.pos)
}
}
@@ -1578,7 +1578,7 @@ func (a *expr) genBinOpLss(l, r *expr) {
return l < r
}
default:
- log.Crashf("unexpected type %v at %v", l.t, a.pos)
+ log.Panicf("unexpected type %v at %v", l.t, a.pos)
}
}
@@ -1623,7 +1623,7 @@ func (a *expr) genBinOpGtr(l, r *expr) {
return l > r
}
default:
- log.Crashf("unexpected type %v at %v", l.t, a.pos)
+ log.Panicf("unexpected type %v at %v", l.t, a.pos)
}
}
@@ -1668,7 +1668,7 @@ func (a *expr) genBinOpLeq(l, r *expr) {
return l <= r
}
default:
- log.Crashf("unexpected type %v at %v", l.t, a.pos)
+ log.Panicf("unexpected type %v at %v", l.t, a.pos)
}
}
@@ -1713,7 +1713,7 @@ func (a *expr) genBinOpGeq(l, r *expr) {
return l >= r
}
default:
- log.Crashf("unexpected type %v at %v", l.t, a.pos)
+ log.Panicf("unexpected type %v at %v", l.t, a.pos)
}
}
@@ -1786,7 +1786,7 @@ func (a *expr) genBinOpEql(l, r *expr) {
return l == r
}
default:
- log.Crashf("unexpected type %v at %v", l.t, a.pos)
+ log.Panicf("unexpected type %v at %v", l.t, a.pos)
}
}
@@ -1859,7 +1859,7 @@ func (a *expr) genBinOpNeq(l, r *expr) {
return l != r
}
default:
- log.Crashf("unexpected type %v at %v", l.t, a.pos)
+ log.Panicf("unexpected type %v at %v", l.t, a.pos)
}
}
@@ -1899,7 +1899,7 @@ func genAssign(lt Type, r *expr) func(lv Value, t *Thread) {
rf := r.asMap()
return func(lv Value, t *Thread) { lv.(MapValue).Set(t, rf(t)) }
default:
- log.Crashf("unexpected left operand type %v at %v", lt, r.pos)
+ log.Panicf("unexpected left operand type %v at %v", lt, r.pos)
}
panic("fail")
}
diff --git a/src/pkg/exp/eval/expr_test.go b/src/pkg/exp/eval/expr_test.go
index b36554183..0dbce4315 100644
--- a/src/pkg/exp/eval/expr_test.go
+++ b/src/pkg/exp/eval/expr_test.go
@@ -5,7 +5,7 @@
package eval
import (
- "exp/bignum"
+ "big"
"testing"
)
@@ -22,7 +22,7 @@ var implLimit = "implementation limit"
var mustBeUnsigned = "must be unsigned"
var divByZero = "divide by zero"
-var hugeInteger = bignum.Int(1).Shl(64)
+var hugeInteger = new(big.Int).Lsh(idealOne, 64)
var exprTests = []test{
Val("i", 1),
@@ -30,9 +30,9 @@ var exprTests = []test{
// TODO(austin) Test variable in constant context
//CErr("t", typeAsExpr),
- Val("'a'", bignum.Int('a')),
- Val("'\\uffff'", bignum.Int('\uffff')),
- Val("'\\n'", bignum.Int('\n')),
+ Val("'a'", big.NewInt('a')),
+ Val("'\\uffff'", big.NewInt('\uffff')),
+ Val("'\\n'", big.NewInt('\n')),
CErr("''+x", badCharLit),
// Produces two parse errors
//CErr("'''", ""),
@@ -40,10 +40,10 @@ var exprTests = []test{
CErr("'\\z'", unknownEscape),
CErr("'ab'", badCharLit),
- Val("1.0", bignum.Rat(1, 1)),
- Val("1.", bignum.Rat(1, 1)),
- Val(".1", bignum.Rat(1, 10)),
- Val("1e2", bignum.Rat(100, 1)),
+ Val("1.0", big.NewRat(1, 1)),
+ Val("1.", big.NewRat(1, 1)),
+ Val(".1", big.NewRat(1, 10)),
+ Val("1e2", big.NewRat(100, 1)),
Val("\"abc\"", "abc"),
Val("\"\"", ""),
@@ -140,12 +140,12 @@ var exprTests = []test{
CErr("&c", badAddrOf),
Val("*(&ai[0])", 1),
- Val("+1", bignum.Int(+1)),
- Val("+1.0", bignum.Rat(1, 1)),
- Val("01.5", bignum.Rat(15, 10)),
+ Val("+1", big.NewInt(+1)),
+ Val("+1.0", big.NewRat(1, 1)),
+ Val("01.5", big.NewRat(15, 10)),
CErr("+\"x\"", opTypes),
- Val("-42", bignum.Int(-42)),
+ Val("-42", big.NewInt(-42)),
Val("-i", -1),
Val("-f", -1.0),
// 6g bug?
@@ -154,8 +154,8 @@ var exprTests = []test{
// TODO(austin) Test unary !
- Val("^2", bignum.Int(^2)),
- Val("^(-2)", bignum.Int(^(-2))),
+ Val("^2", big.NewInt(^2)),
+ Val("^(-2)", big.NewInt(^(-2))),
CErr("^2.0", opTypes),
CErr("^2.5", opTypes),
Val("^i", ^1),
@@ -165,67 +165,66 @@ var exprTests = []test{
Val("1+i", 2),
Val("1+u", uint(2)),
Val("3.0+i", 4),
- Val("1+1", bignum.Int(2)),
+ Val("1+1", big.NewInt(2)),
Val("f+f", 2.0),
Val("1+f", 2.0),
- Val("1.0+1", bignum.Rat(2, 1)),
+ Val("1.0+1", big.NewRat(2, 1)),
Val("\"abc\" + \"def\"", "abcdef"),
CErr("i+u", opTypes),
CErr("-1+u", constantUnderflows),
// TODO(austin) Test named types
- Val("2-1", bignum.Int(1)),
- Val("2.0-1", bignum.Rat(1, 1)),
+ Val("2-1", big.NewInt(1)),
+ Val("2.0-1", big.NewRat(1, 1)),
Val("f-2", -1.0),
- // TOOD(austin) bignum can't do negative 0?
- //Val("-0.0", XXX),
- Val("2*2", bignum.Int(4)),
+ Val("-0.0", big.NewRat(0, 1)),
+ Val("2*2", big.NewInt(4)),
Val("2*i", 2),
- Val("3/2", bignum.Int(1)),
+ Val("3/2", big.NewInt(1)),
Val("3/i", 3),
CErr("1/0", divByZero),
CErr("1.0/0", divByZero),
RErr("i/0", divByZero),
- Val("3%2", bignum.Int(1)),
+ Val("3%2", big.NewInt(1)),
Val("i%2", 1),
CErr("3%0", divByZero),
CErr("3.0%0", opTypes),
RErr("i%0", divByZero),
// Examples from "Arithmetic operators"
- Val("5/3", bignum.Int(1)),
+ Val("5/3", big.NewInt(1)),
Val("(i+4)/(i+2)", 1),
- Val("5%3", bignum.Int(2)),
+ Val("5%3", big.NewInt(2)),
Val("(i+4)%(i+2)", 2),
- Val("-5/3", bignum.Int(-1)),
+ Val("-5/3", big.NewInt(-1)),
Val("(i-6)/(i+2)", -1),
- Val("-5%3", bignum.Int(-2)),
+ Val("-5%3", big.NewInt(-2)),
Val("(i-6)%(i+2)", -2),
- Val("5/-3", bignum.Int(-1)),
+ Val("5/-3", big.NewInt(-1)),
Val("(i+4)/(i-4)", -1),
- Val("5%-3", bignum.Int(2)),
+ Val("5%-3", big.NewInt(2)),
Val("(i+4)%(i-4)", 2),
- Val("-5/-3", bignum.Int(1)),
+ Val("-5/-3", big.NewInt(1)),
Val("(i-6)/(i-4)", 1),
- Val("-5%-3", bignum.Int(-2)),
+ Val("-5%-3", big.NewInt(-2)),
Val("(i-6)%(i-4)", -2),
// Examples from "Arithmetic operators"
- Val("11/4", bignum.Int(2)),
+ Val("11/4", big.NewInt(2)),
Val("(i+10)/4", 2),
- Val("11%4", bignum.Int(3)),
+ Val("11%4", big.NewInt(3)),
Val("(i+10)%4", 3),
- Val("11>>2", bignum.Int(2)),
+ Val("11>>2", big.NewInt(2)),
Val("(i+10)>>2", 2),
- Val("11&3", bignum.Int(3)),
+ Val("11&3", big.NewInt(3)),
Val("(i+10)&3", 3),
- Val("-11/4", bignum.Int(-2)),
+ Val("-11/4", big.NewInt(-2)),
Val("(i-12)/4", -2),
- Val("-11%4", bignum.Int(-3)),
+ Val("-11%4", big.NewInt(-3)),
Val("(i-12)%4", -3),
- Val("-11>>2", bignum.Int(-3)),
+ Val("-11>>2", big.NewInt(-3)),
Val("(i-12)>>2", -3),
- Val("-11&3", bignum.Int(1)),
+ Val("-11&3", big.NewInt(1)),
Val("(i-12)&3", 1),
// TODO(austin) Test bit ops
@@ -234,29 +233,29 @@ var exprTests = []test{
// ideal int, negative ideal int, big ideal int, ideal
// fractional float, ideal non-fractional float, int, uint,
// and float.
- Val("2<<2", bignum.Int(2<<2)),
+ Val("2<<2", big.NewInt(2<<2)),
CErr("2<<(-1)", constantUnderflows),
CErr("2<<0x10000000000000000", constantOverflows),
CErr("2<<2.5", constantTruncated),
- Val("2<<2.0", bignum.Int(2<<2.0)),
+ Val("2<<2.0", big.NewInt(2<<2.0)),
CErr("2<<i", mustBeUnsigned),
Val("2<<u", 2<<1),
CErr("2<<f", opTypes),
- Val("-2<<2", bignum.Int(-2<<2)),
+ Val("-2<<2", big.NewInt(-2<<2)),
CErr("-2<<(-1)", constantUnderflows),
CErr("-2<<0x10000000000000000", constantOverflows),
CErr("-2<<2.5", constantTruncated),
- Val("-2<<2.0", bignum.Int(-2<<2.0)),
+ Val("-2<<2.0", big.NewInt(-2<<2.0)),
CErr("-2<<i", mustBeUnsigned),
Val("-2<<u", -2<<1),
CErr("-2<<f", opTypes),
- Val("0x10000000000000000<<2", hugeInteger.Shl(2)),
+ Val("0x10000000000000000<<2", new(big.Int).Lsh(hugeInteger, 2)),
CErr("0x10000000000000000<<(-1)", constantUnderflows),
CErr("0x10000000000000000<<0x10000000000000000", constantOverflows),
CErr("0x10000000000000000<<2.5", constantTruncated),
- Val("0x10000000000000000<<2.0", hugeInteger.Shl(2)),
+ Val("0x10000000000000000<<2.0", new(big.Int).Lsh(hugeInteger, 2)),
CErr("0x10000000000000000<<i", mustBeUnsigned),
CErr("0x10000000000000000<<u", constantOverflows),
CErr("0x10000000000000000<<f", opTypes),
diff --git a/src/pkg/exp/eval/func.go b/src/pkg/exp/eval/func.go
index e672d0783..cb1b579e4 100644
--- a/src/pkg/exp/eval/func.go
+++ b/src/pkg/exp/eval/func.go
@@ -43,16 +43,7 @@ type codeBuf struct {
func newCodeBuf() *codeBuf { return &codeBuf{make(code, 0, 16)} }
func (b *codeBuf) push(instr func(*Thread)) {
- n := len(b.instrs)
- if n >= cap(b.instrs) {
- a := make(code, n, n*2)
- for i := range b.instrs {
- a[i] = b.instrs[i]
- }
- b.instrs = a
- }
- b.instrs = b.instrs[0 : n+1]
- b.instrs[n] = instr
+ b.instrs = append(b.instrs, instr)
}
func (b *codeBuf) nextPC() uint { return uint(len(b.instrs)) }
@@ -60,9 +51,7 @@ func (b *codeBuf) nextPC() uint { return uint(len(b.instrs)) }
func (b *codeBuf) get() code {
// Freeze this buffer into an array of exactly the right size
a := make(code, len(b.instrs))
- for i := range b.instrs {
- a[i] = b.instrs[i]
- }
+ copy(a, b.instrs)
return code(a)
}
diff --git a/src/pkg/exp/eval/gen.go b/src/pkg/exp/eval/gen.go
index 969d65586..81863dd6f 100644
--- a/src/pkg/exp/eval/gen.go
+++ b/src/pkg/exp/eval/gen.go
@@ -40,16 +40,16 @@ type Type struct {
var (
boolType = &Type{Repr: "*boolType", Value: "BoolValue", Native: "bool", As: "asBool"}
uintType = &Type{Repr: "*uintType", Value: "UintValue", Native: "uint64", As: "asUint",
- Sizes: []Size{Size{8, "uint8"}, Size{16, "uint16"}, Size{32, "uint32"}, Size{64, "uint64"}, Size{0, "uint"}},
+ Sizes: []Size{{8, "uint8"}, {16, "uint16"}, {32, "uint32"}, {64, "uint64"}, {0, "uint"}},
}
intType = &Type{Repr: "*intType", Value: "IntValue", Native: "int64", As: "asInt",
- Sizes: []Size{Size{8, "int8"}, Size{16, "int16"}, Size{32, "int32"}, Size{64, "int64"}, Size{0, "int"}},
+ Sizes: []Size{{8, "int8"}, {16, "int16"}, {32, "int32"}, {64, "int64"}, {0, "int"}},
}
- idealIntType = &Type{Repr: "*idealIntType", Value: "IdealIntValue", Native: "*bignum.Integer", As: "asIdealInt", IsIdeal: true}
+ idealIntType = &Type{Repr: "*idealIntType", Value: "IdealIntValue", Native: "*big.Int", As: "asIdealInt", IsIdeal: true}
floatType = &Type{Repr: "*floatType", Value: "FloatValue", Native: "float64", As: "asFloat",
- Sizes: []Size{Size{32, "float32"}, Size{64, "float64"}, Size{0, "float"}},
+ Sizes: []Size{{32, "float32"}, {64, "float64"}, {0, "float"}},
}
- idealFloatType = &Type{Repr: "*idealFloatType", Value: "IdealFloatValue", Native: "*bignum.Rational", As: "asIdealFloat", IsIdeal: true}
+ idealFloatType = &Type{Repr: "*idealFloatType", Value: "IdealFloatValue", Native: "*big.Rat", As: "asIdealFloat", IsIdeal: true}
stringType = &Type{Repr: "*stringType", Value: "StringValue", Native: "string", As: "asString"}
arrayType = &Type{Repr: "*ArrayType", Value: "ArrayValue", Native: "ArrayValue", As: "asArray", HasAssign: true}
structType = &Type{Repr: "*StructType", Value: "StructValue", Native: "StructValue", As: "asStruct", HasAssign: true}
@@ -93,41 +93,41 @@ var (
)
var unOps = []Op{
- Op{Name: "Neg", Expr: "-v", ConstExpr: "v.Neg()", Types: numbers},
- Op{Name: "Not", Expr: "!v", Types: bools},
- Op{Name: "Xor", Expr: "^v", ConstExpr: "v.Neg().Sub(bignum.Int(1))", Types: integers},
+ {Name: "Neg", Expr: "-v", ConstExpr: "val.Neg(val)", Types: numbers},
+ {Name: "Not", Expr: "!v", Types: bools},
+ {Name: "Xor", Expr: "^v", ConstExpr: "val.Not(val)", Types: integers},
}
var binOps = []Op{
- Op{Name: "Add", Expr: "l + r", ConstExpr: "l.Add(r)", Types: addable},
- Op{Name: "Sub", Expr: "l - r", ConstExpr: "l.Sub(r)", Types: numbers},
- Op{Name: "Mul", Expr: "l * r", ConstExpr: "l.Mul(r)", Types: numbers},
- Op{Name: "Quo",
+ {Name: "Add", Expr: "l + r", ConstExpr: "l.Add(l, r)", Types: addable},
+ {Name: "Sub", Expr: "l - r", ConstExpr: "l.Sub(l, r)", Types: numbers},
+ {Name: "Mul", Expr: "l * r", ConstExpr: "l.Mul(l, r)", Types: numbers},
+ {Name: "Quo",
Body: "if r == 0 { t.Abort(DivByZeroError{}) }; ret = l / r",
- ConstExpr: "l.Quo(r)",
+ ConstExpr: "l.Quo(l, r)",
Types: numbers,
},
- Op{Name: "Rem",
+ {Name: "Rem",
Body: "if r == 0 { t.Abort(DivByZeroError{}) }; ret = l % r",
- ConstExpr: "l.Rem(r)",
+ ConstExpr: "l.Rem(l, r)",
Types: integers,
},
- Op{Name: "And", Expr: "l & r", ConstExpr: "l.And(r)", Types: integers},
- Op{Name: "Or", Expr: "l | r", ConstExpr: "l.Or(r)", Types: integers},
- Op{Name: "Xor", Expr: "l ^ r", ConstExpr: "l.Xor(r)", Types: integers},
- Op{Name: "AndNot", Expr: "l &^ r", ConstExpr: "l.AndNot(r)", Types: integers},
- Op{Name: "Shl", Expr: "l << r", ConstExpr: "l.Shl(uint(r.Value()))",
+ {Name: "And", Expr: "l & r", ConstExpr: "l.And(l, r)", Types: integers},
+ {Name: "Or", Expr: "l | r", ConstExpr: "l.Or(l, r)", Types: integers},
+ {Name: "Xor", Expr: "l ^ r", ConstExpr: "l.Xor(l, r)", Types: integers},
+ {Name: "AndNot", Expr: "l &^ r", ConstExpr: "l.AndNot(l, r)", Types: integers},
+ {Name: "Shl", Expr: "l << r", ConstExpr: "l.Lsh(l, uint(r.Value()))",
AsRightName: "asUint", Types: shiftable,
},
- Op{Name: "Shr", Expr: "l >> r", ConstExpr: "l.Shr(uint(r.Value()))",
+ {Name: "Shr", Expr: "l >> r", ConstExpr: "new(big.Int).Rsh(l, uint(r.Value()))",
AsRightName: "asUint", Types: shiftable,
},
- Op{Name: "Lss", Expr: "l < r", ConstExpr: "l.Cmp(r) < 0", ReturnType: "bool", Types: addable},
- Op{Name: "Gtr", Expr: "l > r", ConstExpr: "l.Cmp(r) > 0", ReturnType: "bool", Types: addable},
- Op{Name: "Leq", Expr: "l <= r", ConstExpr: "l.Cmp(r) <= 0", ReturnType: "bool", Types: addable},
- Op{Name: "Geq", Expr: "l >= r", ConstExpr: "l.Cmp(r) >= 0", ReturnType: "bool", Types: addable},
- Op{Name: "Eql", Expr: "l == r", ConstExpr: "l.Cmp(r) == 0", ReturnType: "bool", Types: cmpable},
- Op{Name: "Neq", Expr: "l != r", ConstExpr: "l.Cmp(r) != 0", ReturnType: "bool", Types: cmpable},
+ {Name: "Lss", Expr: "l < r", ConstExpr: "l.Cmp(r) < 0", ReturnType: "bool", Types: addable},
+ {Name: "Gtr", Expr: "l > r", ConstExpr: "l.Cmp(r) > 0", ReturnType: "bool", Types: addable},
+ {Name: "Leq", Expr: "l <= r", ConstExpr: "l.Cmp(r) <= 0", ReturnType: "bool", Types: addable},
+ {Name: "Geq", Expr: "l >= r", ConstExpr: "l.Cmp(r) >= 0", ReturnType: "bool", Types: addable},
+ {Name: "Eql", Expr: "l == r", ConstExpr: "l.Cmp(r) == 0", ReturnType: "bool", Types: cmpable},
+ {Name: "Neq", Expr: "l != r", ConstExpr: "l.Cmp(r) != 0", ReturnType: "bool", Types: cmpable},
}
type Data struct {
@@ -149,8 +149,8 @@ const templateStr = `
package eval
import (
- "bignum";
- "log";
+ "big"
+ "log"
)
/*
@@ -184,9 +184,9 @@ func (a *expr) asInterface() (func(*Thread) interface{}) {
«.end»
«.end»
default:
- log.Crashf("unexpected expression node type %T at %v", a.eval, a.pos);
+ log.Panicf("unexpected expression node type %T at %v", a.eval, a.pos)
}
- panic("fail");
+ panic("fail")
}
/*
@@ -198,19 +198,19 @@ func (a *expr) genConstant(v Value) {
«.repeated section Types»
case «Repr»:
«.section IsIdeal»
- val := v.(«Value»).Get();
+ val := v.(«Value»).Get()
a.eval = func() «Native» { return val }
«.or»
a.eval = func(t *Thread) «Native» { return v.(«Value»).Get(t) }
«.end»
«.end»
default:
- log.Crashf("unexpected constant type %v at %v", a.t, a.pos);
+ log.Panicf("unexpected constant type %v at %v", a.t, a.pos)
}
}
func (a *expr) genIdentOp(level, index int) {
- a.evalAddr = func(t *Thread) Value { return t.f.Get(level, index) };
+ a.evalAddr = func(t *Thread) Value { return t.f.Get(level, index) }
switch a.t.lit().(type) {
«.repeated section Types»
«.section IsIdeal»
@@ -220,12 +220,12 @@ func (a *expr) genIdentOp(level, index int) {
«.end»
«.end»
default:
- log.Crashf("unexpected identifier type %v at %v", a.t, a.pos);
+ log.Panicf("unexpected identifier type %v at %v", a.t, a.pos)
}
}
func (a *expr) genFuncCall(call func(t *Thread) []Value) {
- a.exec = func(t *Thread) { call(t)};
+ a.exec = func(t *Thread) { call(t)}
switch a.t.lit().(type) {
«.repeated section Types»
«.section IsIdeal»
@@ -237,12 +237,12 @@ func (a *expr) genFuncCall(call func(t *Thread) []Value) {
case *MultiType:
a.eval = func(t *Thread) []Value { return call(t) }
default:
- log.Crashf("unexpected result type %v at %v", a.t, a.pos);
+ log.Panicf("unexpected result type %v at %v", a.t, a.pos)
}
}
func (a *expr) genValue(vf func(*Thread) Value) {
- a.evalAddr = vf;
+ a.evalAddr = vf
switch a.t.lit().(type) {
«.repeated section Types»
«.section IsIdeal»
@@ -252,7 +252,7 @@ func (a *expr) genValue(vf func(*Thread) Value) {
«.end»
«.end»
default:
- log.Crashf("unexpected result type %v at %v", a.t, a.pos);
+ log.Panicf("unexpected result type %v at %v", a.t, a.pos)
}
}
@@ -262,29 +262,29 @@ func (a *expr) genUnaryOp«Name»(v *expr) {
«.repeated section Types»
case «Repr»:
«.section IsIdeal»
- v := v.«As»()();
- val := «ConstExpr»;
+ val := v.«As»()()
+ «ConstExpr»
a.eval = func() «Native» { return val }
«.or»
- vf := v.«As»();
+ vf := v.«As»()
a.eval = func(t *Thread) «Native» { v := vf(t); return «Expr» }
«.end»
«.end»
default:
- log.Crashf("unexpected type %v at %v", a.t, a.pos);
+ log.Panicf("unexpected type %v at %v", a.t, a.pos)
}
}
«.end»
func (a *expr) genBinOpLogAnd(l, r *expr) {
- lf := l.asBool();
- rf := r.asBool();
+ lf := l.asBool()
+ rf := r.asBool()
a.eval = func(t *Thread) bool { return lf(t) && rf(t) }
}
func (a *expr) genBinOpLogOr(l, r *expr) {
- lf := l.asBool();
- rf := r.asBool();
+ lf := l.asBool()
+ rf := r.asBool()
a.eval = func(t *Thread) bool { return lf(t) || rf(t) }
}
@@ -294,20 +294,20 @@ func (a *expr) genBinOp«Name»(l, r *expr) {
«.repeated section Types»
case «Repr»:
«.section IsIdeal»
- l := l.«As»()();
- r := r.«As»()();
- val := «ConstExpr»;
+ l := l.«As»()()
+ r := r.«As»()()
+ val := «ConstExpr»
«.section ReturnType»
a.eval = func(t *Thread) «ReturnType» { return val }
«.or»
a.eval = func() «Native» { return val }
«.end»
«.or»
- lf := l.«As»();
- rf := r.«.section AsRightName»«@»«.or»«As»«.end»();
+ lf := l.«As»()
+ rf := r.«.section AsRightName»«@»«.or»«As»«.end»()
«.section ReturnType»
a.eval = func(t *Thread) «@» {
- l, r := lf(t), rf(t);
+ l, r := lf(t), rf(t)
return «Expr»
}
«.or»
@@ -316,22 +316,22 @@ func (a *expr) genBinOp«Name»(l, r *expr) {
«.repeated section @»
case «Bits»:
a.eval = func(t *Thread) «Native» {
- l, r := lf(t), rf(t);
- var ret «Native»;
+ l, r := lf(t), rf(t)
+ var ret «Native»
«.section Body»
- «Body»;
+ «Body»
«.or»
- ret = «Expr»;
+ ret = «Expr»
«.end»
return «Native»(«Sized»(ret))
}
«.end»
default:
- log.Crashf("unexpected size %d in type %v at %v", t.Bits, t, a.pos);
+ log.Panicf("unexpected size %d in type %v at %v", t.Bits, t, a.pos)
}
«.or»
a.eval = func(t *Thread) «Native» {
- l, r := lf(t), rf(t);
+ l, r := lf(t), rf(t)
return «Expr»
}
«.end»
@@ -339,7 +339,7 @@ func (a *expr) genBinOp«Name»(l, r *expr) {
«.end»
«.end»
default:
- log.Crashf("unexpected type %v at %v", l.t, a.pos);
+ log.Panicf("unexpected type %v at %v", l.t, a.pos)
}
}
@@ -350,14 +350,14 @@ func genAssign(lt Type, r *expr) (func(lv Value, t *Thread)) {
«.section IsIdeal»
«.or»
case «Repr»:
- rf := r.«As»();
+ rf := r.«As»()
return func(lv Value, t *Thread) { «.section HasAssign»lv.Assign(t, rf(t))«.or»lv.(«Value»).Set(t, rf(t))«.end» }
«.end»
«.end»
default:
- log.Crashf("unexpected left operand type %v at %v", lt, r.pos);
+ log.Panicf("unexpected left operand type %v at %v", lt, r.pos)
}
- panic("fail");
+ panic("fail")
}
`
diff --git a/src/pkg/exp/eval/main.go b/src/pkg/exp/eval/main.go
index 6033088a3..d87e8f240 100644
--- a/src/pkg/exp/eval/main.go
+++ b/src/pkg/exp/eval/main.go
@@ -10,10 +10,12 @@ import (
"flag"
"go/parser"
"go/scanner"
+ "go/token"
"io/ioutil"
"os"
)
+var fset = token.NewFileSet()
var filename = flag.String("f", "", "file to run")
func main() {
@@ -25,12 +27,12 @@ func main() {
println(err.String())
os.Exit(1)
}
- file, err := parser.ParseFile(*filename, data, nil, 0)
+ file, err := parser.ParseFile(fset, *filename, data, 0)
if err != nil {
println(err.String())
os.Exit(1)
}
- code, err := w.CompileDeclList(file.Decls)
+ code, err := w.CompileDeclList(fset, file.Decls)
if err != nil {
if list, ok := err.(scanner.ErrorList); ok {
for _, e := range list {
@@ -46,7 +48,7 @@ func main() {
println(err.String())
os.Exit(1)
}
- code, err = w.Compile("init()")
+ code, err = w.Compile(fset, "init()")
if code != nil {
_, err := code.Run()
if err != nil {
@@ -54,7 +56,7 @@ func main() {
os.Exit(1)
}
}
- code, err = w.Compile("main()")
+ code, err = w.Compile(fset, "main()")
if err != nil {
println(err.String())
os.Exit(1)
@@ -74,7 +76,7 @@ func main() {
if err != nil {
break
}
- code, err := w.Compile(line)
+ code, err := w.Compile(fset, line)
if err != nil {
println(err.String())
continue
diff --git a/src/pkg/exp/eval/scope.go b/src/pkg/exp/eval/scope.go
index 74ce32b59..66305de25 100644
--- a/src/pkg/exp/eval/scope.go
+++ b/src/pkg/exp/eval/scope.go
@@ -15,11 +15,11 @@ import (
// A definition can be a *Variable, *Constant, or Type.
type Def interface {
- Pos() token.Position
+ Pos() token.Pos
}
type Variable struct {
- token.Position
+ VarPos token.Pos
// Index of this variable in the Frame structure
Index int
// Static type of this variable
@@ -30,10 +30,18 @@ type Variable struct {
Init Value
}
+func (v *Variable) Pos() token.Pos {
+ return v.VarPos
+}
+
type Constant struct {
- token.Position
- Type Type
- Value Value
+ ConstPos token.Pos
+ Type Type
+ Value Value
+}
+
+func (c *Constant) Pos() token.Pos {
+ return c.ConstPos
}
// A block represents a definition block in which a name may not be
@@ -74,7 +82,7 @@ type Scope struct {
func (b *block) enterChild() *block {
if b.inner != nil && b.inner.scope == b.scope {
- log.Crash("Failed to exit child block before entering another child")
+ log.Panic("Failed to exit child block before entering another child")
}
sub := &block{
outer: b,
@@ -88,14 +96,14 @@ func (b *block) enterChild() *block {
func (b *block) exit() {
if b.outer == nil {
- log.Crash("Cannot exit top-level block")
+ log.Panic("Cannot exit top-level block")
}
if b.outer.scope == b.scope {
if b.outer.inner != b {
- log.Crash("Already exited block")
+ log.Panic("Already exited block")
}
if b.inner != nil && b.inner.scope == b.scope {
- log.Crash("Exit of parent block without exit of child block")
+ log.Panic("Exit of parent block without exit of child block")
}
}
b.outer.inner = nil
@@ -103,7 +111,7 @@ func (b *block) exit() {
func (b *block) ChildScope() *Scope {
if b.inner != nil && b.inner.scope == b.scope {
- log.Crash("Failed to exit child block before entering a child scope")
+ log.Panic("Failed to exit child block before entering a child scope")
}
sub := b.enterChild()
sub.offset = 0
@@ -111,12 +119,12 @@ func (b *block) ChildScope() *Scope {
return sub.scope
}
-func (b *block) DefineVar(name string, pos token.Position, t Type) (*Variable, Def) {
+func (b *block) DefineVar(name string, pos token.Pos, t Type) (*Variable, Def) {
if prev, ok := b.defs[name]; ok {
return nil, prev
}
v := b.defineSlot(t, false)
- v.Position = pos
+ v.VarPos = pos
b.defs[name] = v
return v, nil
}
@@ -125,7 +133,7 @@ func (b *block) DefineTemp(t Type) *Variable { return b.defineSlot(t, true) }
func (b *block) defineSlot(t Type, temp bool) *Variable {
if b.inner != nil && b.inner.scope == b.scope {
- log.Crash("Failed to exit child block before defining variable")
+ log.Panic("Failed to exit child block before defining variable")
}
index := -1
if !b.global || temp {
@@ -135,11 +143,11 @@ func (b *block) defineSlot(t Type, temp bool) *Variable {
b.scope.maxVars = index + 1
}
}
- v := &Variable{token.Position{}, index, t, nil}
+ v := &Variable{token.NoPos, index, t, nil}
return v
}
-func (b *block) DefineConst(name string, pos token.Position, t Type, v Value) (*Constant, Def) {
+func (b *block) DefineConst(name string, pos token.Pos, t Type, v Value) (*Constant, Def) {
if prev, ok := b.defs[name]; ok {
return nil, prev
}
@@ -148,7 +156,7 @@ func (b *block) DefineConst(name string, pos token.Position, t Type, v Value) (*
return c, nil
}
-func (b *block) DefineType(name string, pos token.Position, t Type) Type {
+func (b *block) DefineType(name string, pos token.Pos, t Type) Type {
if _, ok := b.defs[name]; ok {
return nil
}
diff --git a/src/pkg/exp/eval/stmt.go b/src/pkg/exp/eval/stmt.go
index bcd81f04c..b9ffa94fa 100644
--- a/src/pkg/exp/eval/stmt.go
+++ b/src/pkg/exp/eval/stmt.go
@@ -5,7 +5,7 @@
package eval
import (
- "exp/bignum"
+ "big"
"log"
"go/ast"
"go/token"
@@ -22,13 +22,13 @@ const (
type stmtCompiler struct {
*blockCompiler
- pos token.Position
+ pos token.Pos
// This statement's label, or nil if it is not labeled.
stmtLabel *label
}
func (a *stmtCompiler) diag(format string, args ...interface{}) {
- a.diagAt(&a.pos, format, args)
+ a.diagAt(a.pos, format, args...)
}
/*
@@ -65,7 +65,7 @@ type flowBuf struct {
ents map[uint]*flowEnt
// gotos is a map from goto positions to information on the
// block at the point of the goto.
- gotos map[*token.Position]*flowBlock
+ gotos map[token.Pos]*flowBlock
// labels is a map from label name to information on the block
// at the point of the label. labels are tracked by name,
// since mutliple labels at the same PC can have different
@@ -74,7 +74,7 @@ type flowBuf struct {
}
func newFlowBuf(cb *codeBuf) *flowBuf {
- return &flowBuf{cb, make(map[uint]*flowEnt), make(map[*token.Position]*flowBlock), make(map[string]*flowBlock)}
+ return &flowBuf{cb, make(map[uint]*flowEnt), make(map[token.Pos]*flowBlock), make(map[string]*flowBlock)}
}
// put creates a flow control point for the next PC in the code buffer.
@@ -82,7 +82,7 @@ func newFlowBuf(cb *codeBuf) *flowBuf {
func (f *flowBuf) put(cond bool, term bool, jumps []*uint) {
pc := f.cb.nextPC()
if ent, ok := f.ents[pc]; ok {
- log.Crashf("Flow entry already exists at PC %d: %+v", pc, ent)
+ log.Panicf("Flow entry already exists at PC %d: %+v", pc, ent)
}
f.ents[pc] = &flowEnt{cond, term, jumps, false}
}
@@ -123,8 +123,8 @@ func newFlowBlock(target string, b *block) *flowBlock {
// putGoto captures the block at a goto statement. This should be
// called in addition to putting a flow control point.
-func (f *flowBuf) putGoto(pos token.Position, target string, b *block) {
- f.gotos[&pos] = newFlowBlock(target, b)
+func (f *flowBuf) putGoto(pos token.Pos, target string, b *block) {
+ f.gotos[pos] = newFlowBlock(target, b)
}
// putLabel captures the block at a label.
@@ -138,7 +138,7 @@ func (f *flowBuf) putLabel(name string, b *block) {
func (f *flowBuf) reachesEnd(pc uint) bool {
endPC := f.cb.nextPC()
if pc > endPC {
- log.Crashf("Reached bad PC %d past end PC %d", pc, endPC)
+ log.Panicf("Reached bad PC %d past end PC %d", pc, endPC)
}
for ; pc < endPC; pc++ {
@@ -210,15 +210,12 @@ func (f *flowBuf) gotosObeyScopes(a *compiler) {
*/
func (a *stmtCompiler) defineVar(ident *ast.Ident, t Type) *Variable {
- v, prev := a.block.DefineVar(ident.Name(), ident.Pos(), t)
+ v, prev := a.block.DefineVar(ident.Name, ident.Pos(), t)
if prev != nil {
- // TODO(austin) It's silly that we have to capture
- // Pos() in a variable.
- pos := prev.Pos()
- if pos.IsValid() {
- a.diagAt(ident, "variable %s redeclared in this block\n\tprevious declaration at %s", ident.Name(), &pos)
+ if prev.Pos().IsValid() {
+ a.diagAt(ident.Pos(), "variable %s redeclared in this block\n\tprevious declaration at %s", ident.Name, a.fset.Position(prev.Pos()))
} else {
- a.diagAt(ident, "variable %s redeclared in this block", ident.Name())
+ a.diagAt(ident.Pos(), "variable %s redeclared in this block", ident.Name)
}
return nil
}
@@ -239,7 +236,7 @@ func (a *stmtCompiler) defineVar(ident *ast.Ident, t Type) *Variable {
func (a *stmtCompiler) compile(s ast.Stmt) {
if a.block.inner != nil {
- log.Crash("Child scope still entered")
+ log.Panic("Child scope still entered")
}
notimpl := false
@@ -309,7 +306,7 @@ func (a *stmtCompiler) compile(s ast.Stmt) {
notimpl = true
default:
- log.Crashf("unexpected ast node type %T", s)
+ log.Panicf("unexpected ast node type %T", s)
}
if notimpl {
@@ -317,7 +314,7 @@ func (a *stmtCompiler) compile(s ast.Stmt) {
}
if a.block.inner != nil {
- log.Crash("Forgot to exit child scope")
+ log.Panic("Forgot to exit child scope")
}
}
@@ -329,16 +326,16 @@ func (a *stmtCompiler) compileDeclStmt(s *ast.DeclStmt) {
case *ast.FuncDecl:
if !a.block.global {
- log.Crash("FuncDecl at statement level")
+ log.Panic("FuncDecl at statement level")
}
case *ast.GenDecl:
if decl.Tok == token.IMPORT && !a.block.global {
- log.Crash("import at statement level")
+ log.Panic("import at statement level")
}
default:
- log.Crashf("Unexpected Decl type %T", s.Decl)
+ log.Panicf("Unexpected Decl type %T", s.Decl)
}
a.compileDecl(s.Decl)
}
@@ -350,7 +347,7 @@ func (a *stmtCompiler) compileVarDecl(decl *ast.GenDecl) {
// Declaration without assignment
if spec.Type == nil {
// Parser should have caught
- log.Crash("Type and Values nil")
+ log.Panic("Type and Values nil")
}
t := a.compileType(a.block, spec.Type)
// Define placeholders even if type compile failed
@@ -381,13 +378,13 @@ func (a *stmtCompiler) compileDecl(decl ast.Decl) {
}
// Declare and initialize v before compiling func
// so that body can refer to itself.
- c, prev := a.block.DefineConst(d.Name.Name(), a.pos, decl.Type, decl.Type.Zero())
+ c, prev := a.block.DefineConst(d.Name.Name, a.pos, decl.Type, decl.Type.Zero())
if prev != nil {
pos := prev.Pos()
if pos.IsValid() {
- a.diagAt(d.Name, "identifier %s redeclared in this block\n\tprevious declaration at %s", d.Name.Name(), &pos)
+ a.diagAt(d.Name.Pos(), "identifier %s redeclared in this block\n\tprevious declaration at %s", d.Name.Name, a.fset.Position(pos))
} else {
- a.diagAt(d.Name, "identifier %s redeclared in this block", d.Name.Name())
+ a.diagAt(d.Name.Pos(), "identifier %s redeclared in this block", d.Name.Name)
}
}
fn := a.compileFunc(a.block, decl, d.Body)
@@ -400,9 +397,9 @@ func (a *stmtCompiler) compileDecl(decl ast.Decl) {
case *ast.GenDecl:
switch d.Tok {
case token.IMPORT:
- log.Crashf("%v not implemented", d.Tok)
+ log.Panicf("%v not implemented", d.Tok)
case token.CONST:
- log.Crashf("%v not implemented", d.Tok)
+ log.Panicf("%v not implemented", d.Tok)
case token.TYPE:
a.compileTypeDecl(a.block, d)
case token.VAR:
@@ -410,20 +407,20 @@ func (a *stmtCompiler) compileDecl(decl ast.Decl) {
}
default:
- log.Crashf("Unexpected Decl type %T", decl)
+ log.Panicf("Unexpected Decl type %T", decl)
}
}
func (a *stmtCompiler) compileLabeledStmt(s *ast.LabeledStmt) {
// Define label
- l, ok := a.labels[s.Label.Name()]
+ l, ok := a.labels[s.Label.Name]
if ok {
if l.resolved.IsValid() {
- a.diag("label %s redeclared in this block\n\tprevious declaration at %s", s.Label.Name(), &l.resolved)
+ a.diag("label %s redeclared in this block\n\tprevious declaration at %s", s.Label.Name, a.fset.Position(l.resolved))
}
} else {
pc := badPC
- l = &label{name: s.Label.Name(), gotoPC: &pc}
+ l = &label{name: s.Label.Name, gotoPC: &pc}
a.labels[l.name] = l
}
l.desc = "regular label"
@@ -486,14 +483,14 @@ func (a *stmtCompiler) compileIncDecStmt(s *ast.IncDecStmt) {
op = token.SUB
desc = "decrement statement"
default:
- log.Crashf("Unexpected IncDec token %v", s.Tok)
+ log.Panicf("Unexpected IncDec token %v", s.Tok)
}
effect, l := l.extractEffect(bc.block, desc)
one := l.newExpr(IdealIntType, "constant")
one.pos = s.Pos()
- one.eval = func() *bignum.Integer { return bignum.Int(1) }
+ one.eval = func() *big.Int { return big.NewInt(1) }
binop := l.compileBinaryExpr(op, l, one)
if binop == nil {
@@ -502,7 +499,7 @@ func (a *stmtCompiler) compileIncDecStmt(s *ast.IncDecStmt) {
assign := a.compileAssign(s.Pos(), bc.block, l.t, []*expr{binop}, "", "")
if assign == nil {
- log.Crashf("compileAssign type check failed")
+ log.Panicf("compileAssign type check failed")
}
lf := l.evalAddr
@@ -555,14 +552,14 @@ func (a *stmtCompiler) doAssign(lhs []ast.Expr, rhs []ast.Expr, tok token.Token,
// Check that it's an identifier
ident, ok = le.(*ast.Ident)
if !ok {
- a.diagAt(le, "left side of := must be a name")
+ a.diagAt(le.Pos(), "left side of := must be a name")
// Suppress new defitions errors
nDefs++
continue
}
// Is this simply an assignment?
- if _, ok := a.block.defs[ident.Name()]; ok {
+ if _, ok := a.block.defs[ident.Name]; ok {
ident = nil
break
}
@@ -607,7 +604,7 @@ func (a *stmtCompiler) doAssign(lhs []ast.Expr, rhs []ast.Expr, tok token.Token,
case ac.rmt.Elems[i].isFloat():
lt = FloatType
default:
- log.Crashf("unexpected ideal type %v", rs[i].t)
+ log.Panicf("unexpected ideal type %v", rs[i].t)
}
default:
@@ -780,7 +777,7 @@ func (a *stmtCompiler) doAssignOp(s *ast.AssignStmt) {
assign := a.compileAssign(s.Pos(), bc.block, l.t, []*expr{binop}, "assignment", "value")
if assign == nil {
- log.Crashf("compileAssign type check failed")
+ log.Panicf("compileAssign type check failed")
}
lf := l.evalAddr
@@ -861,7 +858,7 @@ func (a *stmtCompiler) findLexicalLabel(name *ast.Ident, pred func(*label) bool,
if name == nil && pred(l) {
return l
}
- if name != nil && l.name == name.Name() {
+ if name != nil && l.name == name.Name {
if !pred(l) {
a.diag("cannot %s to %s %s", errOp, l.desc, l.name)
return nil
@@ -872,7 +869,7 @@ func (a *stmtCompiler) findLexicalLabel(name *ast.Ident, pred func(*label) bool,
if name == nil {
a.diag("%s outside %s", errOp, errCtx)
} else {
- a.diag("%s label %s not defined", errOp, name.Name())
+ a.diag("%s label %s not defined", errOp, name.Name)
}
return nil
}
@@ -896,10 +893,10 @@ func (a *stmtCompiler) compileBranchStmt(s *ast.BranchStmt) {
pc = l.continuePC
case token.GOTO:
- l, ok := a.labels[s.Label.Name()]
+ l, ok := a.labels[s.Label.Name]
if !ok {
pc := badPC
- l = &label{name: s.Label.Name(), desc: "unresolved label", gotoPC: &pc, used: s.Pos()}
+ l = &label{name: s.Label.Name, desc: "unresolved label", gotoPC: &pc, used: s.Pos()}
a.labels[l.name] = l
}
@@ -911,7 +908,7 @@ func (a *stmtCompiler) compileBranchStmt(s *ast.BranchStmt) {
return
default:
- log.Crash("Unexpected branch token %v", s.Tok)
+ log.Panic("Unexpected branch token %v", s.Tok)
}
a.flow.put1(false, pc)
@@ -1012,12 +1009,12 @@ func (a *stmtCompiler) compileSwitchStmt(s *ast.SwitchStmt) {
for _, c := range s.Body.List {
clause, ok := c.(*ast.CaseClause)
if !ok {
- a.diagAt(clause, "switch statement must contain case clauses")
+ a.diagAt(clause.Pos(), "switch statement must contain case clauses")
continue
}
if clause.Values == nil {
if hasDefault {
- a.diagAt(clause, "switch statement contains more than one default case")
+ a.diagAt(clause.Pos(), "switch statement contains more than one default case")
}
hasDefault = true
} else {
@@ -1039,7 +1036,7 @@ func (a *stmtCompiler) compileSwitchStmt(s *ast.SwitchStmt) {
case e == nil:
// Error reported by compileExpr
case cond == nil && !e.t.isBoolean():
- a.diagAt(v, "'case' condition must be boolean")
+ a.diagAt(v.Pos(), "'case' condition must be boolean")
case cond == nil:
cases[i] = e.asBool()
case cond != nil:
@@ -1104,7 +1101,7 @@ func (a *stmtCompiler) compileSwitchStmt(s *ast.SwitchStmt) {
// empty blocks to be empty
// statements.
if _, ok := s2.(*ast.EmptyStmt); !ok {
- a.diagAt(s, "fallthrough statement must be final statement in case")
+ a.diagAt(s.Pos(), "fallthrough statement must be final statement in case")
break
}
}
@@ -1235,14 +1232,14 @@ func (a *compiler) compileFunc(b *block, decl *FuncDecl, body *ast.BlockStmt) fu
defer bodyScope.exit()
for i, t := range decl.Type.In {
if decl.InNames[i] != nil {
- bodyScope.DefineVar(decl.InNames[i].Name(), decl.InNames[i].Pos(), t)
+ bodyScope.DefineVar(decl.InNames[i].Name, decl.InNames[i].Pos(), t)
} else {
bodyScope.DefineTemp(t)
}
}
for i, t := range decl.Type.Out {
if decl.OutNames[i] != nil {
- bodyScope.DefineVar(decl.OutNames[i].Name(), decl.OutNames[i].Pos(), t)
+ bodyScope.DefineVar(decl.OutNames[i].Name, decl.OutNames[i].Pos(), t)
} else {
bodyScope.DefineTemp(t)
}
@@ -1275,7 +1272,7 @@ func (a *compiler) compileFunc(b *block, decl *FuncDecl, body *ast.BlockStmt) fu
// this if there were no errors compiling the body.
if len(decl.Type.Out) > 0 && fc.flow.reachesEnd(0) {
// XXX(Spec) Not specified.
- a.diagAt(&body.Rbrace, "function ends without a return statement")
+ a.diagAt(body.Rbrace, "function ends without a return statement")
return nil
}
@@ -1290,7 +1287,7 @@ func (a *funcCompiler) checkLabels() {
nerr := a.numError()
for _, l := range a.labels {
if !l.resolved.IsValid() {
- a.diagAt(&l.used, "label %s not defined", l.name)
+ a.diagAt(l.used, "label %s not defined", l.name)
}
}
if nerr != a.numError() {
diff --git a/src/pkg/exp/eval/test.bash b/src/pkg/exp/eval/test.bash
index 5d9ba1ae7..50b61fd00 100755
--- a/src/pkg/exp/eval/test.bash
+++ b/src/pkg/exp/eval/test.bash
@@ -10,10 +10,8 @@
set -e
-GOBIN="${GOBIN:-$HOME/bin}"
-
-"$GOBIN"/gomake
-"$GOBIN"/6g main.go && "$GOBIN"/6l main.6
+gomake
+6g main.go && 6l main.6
(
for i in $(egrep -l '// \$G (\$D/)?\$F\.go \&\& \$L \$F\.\$A && \./\$A\.out' "$GOROOT"/test/*.go "$GOROOT"/test/*/*.go)
do
diff --git a/src/pkg/exp/eval/type.go b/src/pkg/exp/eval/type.go
index b0fbe2156..db77ab198 100644
--- a/src/pkg/exp/eval/type.go
+++ b/src/pkg/exp/eval/type.go
@@ -5,7 +5,7 @@
package eval
import (
- "exp/bignum"
+ "big"
"go/ast"
"go/token"
"log"
@@ -54,18 +54,18 @@ type Type interface {
// String returns the string representation of this type.
String() string
// The position where this type was defined, if any.
- Pos() token.Position
+ Pos() token.Pos
}
type BoundedType interface {
Type
// minVal returns the smallest value of this type.
- minVal() *bignum.Rational
+ minVal() *big.Rat
// maxVal returns the largest value of this type.
- maxVal() *bignum.Rational
+ maxVal() *big.Rat
}
-var universePos = token.Position{"<universe>", 0, 0, 0}
+var universePos = token.NoPos
/*
* Type array maps. These are used to memoize composite types.
@@ -140,7 +140,7 @@ func (commonType) isFloat() bool { return false }
func (commonType) isIdeal() bool { return false }
-func (commonType) Pos() token.Position { return token.Position{} }
+func (commonType) Pos() token.Pos { return token.NoPos }
/*
* Bool
@@ -234,9 +234,9 @@ func (t *uintType) Zero() Value {
panic("unexpected uint bit count")
}
-func (t *uintType) minVal() *bignum.Rational { return bignum.Rat(0, 1) }
+func (t *uintType) minVal() *big.Rat { return big.NewRat(0, 1) }
-func (t *uintType) maxVal() *bignum.Rational {
+func (t *uintType) maxVal() *big.Rat {
bits := t.Bits
if bits == 0 {
if t.Ptr {
@@ -245,7 +245,10 @@ func (t *uintType) maxVal() *bignum.Rational {
bits = uint(8 * unsafe.Sizeof(uint(0)))
}
}
- return bignum.MakeRat(bignum.Int(1).Shl(bits).Add(bignum.Int(-1)), bignum.Nat(1))
+ numer := big.NewInt(1)
+ numer.Lsh(numer, bits)
+ numer.Sub(numer, idealOne)
+ return new(big.Rat).SetInt(numer)
}
/*
@@ -307,20 +310,25 @@ func (t *intType) Zero() Value {
panic("unexpected int bit count")
}
-func (t *intType) minVal() *bignum.Rational {
+func (t *intType) minVal() *big.Rat {
bits := t.Bits
if bits == 0 {
bits = uint(8 * unsafe.Sizeof(int(0)))
}
- return bignum.MakeRat(bignum.Int(-1).Shl(bits-1), bignum.Nat(1))
+ numer := big.NewInt(-1)
+ numer.Lsh(numer, bits-1)
+ return new(big.Rat).SetInt(numer)
}
-func (t *intType) maxVal() *bignum.Rational {
+func (t *intType) maxVal() *big.Rat {
bits := t.Bits
if bits == 0 {
bits = uint(8 * unsafe.Sizeof(int(0)))
}
- return bignum.MakeRat(bignum.Int(1).Shl(bits-1).Add(bignum.Int(-1)), bignum.Nat(1))
+ numer := big.NewInt(1)
+ numer.Lsh(numer, bits-1)
+ numer.Sub(numer, idealOne)
+ return new(big.Rat).SetInt(numer)
}
/*
@@ -346,7 +354,7 @@ func (t *idealIntType) isIdeal() bool { return true }
func (t *idealIntType) String() string { return "ideal integer" }
-func (t *idealIntType) Zero() Value { return &idealIntV{bignum.Int(0)} }
+func (t *idealIntType) Zero() Value { return &idealIntV{idealZero} }
/*
* Float
@@ -393,12 +401,12 @@ func (t *floatType) Zero() Value {
panic("unexpected float bit count")
}
-var maxFloat32Val = bignum.MakeRat(bignum.Int(0xffffff).Shl(127-23), bignum.Nat(1))
-var maxFloat64Val = bignum.MakeRat(bignum.Int(0x1fffffffffffff).Shl(1023-52), bignum.Nat(1))
-var minFloat32Val = maxFloat32Val.Neg()
-var minFloat64Val = maxFloat64Val.Neg()
+var maxFloat32Val *big.Rat
+var maxFloat64Val *big.Rat
+var minFloat32Val *big.Rat
+var minFloat64Val *big.Rat
-func (t *floatType) minVal() *bignum.Rational {
+func (t *floatType) minVal() *big.Rat {
bits := t.Bits
if bits == 0 {
bits = uint(8 * unsafe.Sizeof(float(0)))
@@ -409,11 +417,11 @@ func (t *floatType) minVal() *bignum.Rational {
case 64:
return minFloat64Val
}
- log.Crashf("unexpected floating point bit count: %d", bits)
+ log.Panicf("unexpected floating point bit count: %d", bits)
panic("unreachable")
}
-func (t *floatType) maxVal() *bignum.Rational {
+func (t *floatType) maxVal() *big.Rat {
bits := t.Bits
if bits == 0 {
bits = uint(8 * unsafe.Sizeof(float(0)))
@@ -424,7 +432,7 @@ func (t *floatType) maxVal() *bignum.Rational {
case 64:
return maxFloat64Val
}
- log.Crashf("unexpected floating point bit count: %d", bits)
+ log.Panicf("unexpected floating point bit count: %d", bits)
panic("unreachable")
}
@@ -451,7 +459,7 @@ func (t *idealFloatType) isIdeal() bool { return true }
func (t *idealFloatType) String() string { return "ideal float" }
-func (t *idealFloatType) Zero() Value { return &idealFloatV{bignum.Rat(1, 0)} }
+func (t *idealFloatType) Zero() Value { return &idealFloatV{big.NewRat(0, 1)} }
/*
* String
@@ -704,6 +712,7 @@ var (
panicType = &FuncType{builtin: "panic"}
printType = &FuncType{builtin: "print"}
printlnType = &FuncType{builtin: "println"}
+ copyType = &FuncType{builtin: "copy"}
)
// Two function types are identical if they have the same number of
@@ -763,7 +772,7 @@ func typeListString(ts []Type, ns []*ast.Ident) string {
s += ", "
}
if ns != nil && ns[i] != nil {
- s += ns[i].Name() + " "
+ s += ns[i].Name + " "
}
if t == nil {
// Some places use nil types to represent errors
@@ -807,7 +816,7 @@ type FuncDecl struct {
func (t *FuncDecl) String() string {
s := "func"
if t.Name != nil {
- s += " " + t.Name.Name()
+ s += " " + t.Name.Name
}
s += funcTypeString(t.Type, t.InNames, t.OutNames)
return s
@@ -861,9 +870,7 @@ func NewInterfaceType(methods []IMethod, embeds []*InterfaceType) *InterfaceType
// Combine methods
allMethods := make([]IMethod, nMethods)
- for i, m := range methods {
- allMethods[i] = m
- }
+ copy(allMethods, methods)
n := len(methods)
for _, e := range embeds {
for _, m := range e.methods {
@@ -1093,8 +1100,8 @@ type Method struct {
}
type NamedType struct {
- token.Position
- Name string
+ NamePos token.Pos
+ Name string
// Underlying type. If incomplete is true, this will be nil.
// If incomplete is false and this is still nil, then this is
// a placeholder type representing an error.
@@ -1107,12 +1114,16 @@ type NamedType struct {
// TODO(austin) This is temporarily needed by the debugger's remote
// type parser. This should only be possible with block.DefineType.
func NewNamedType(name string) *NamedType {
- return &NamedType{token.Position{}, name, nil, true, make(map[string]Method)}
+ return &NamedType{token.NoPos, name, nil, true, make(map[string]Method)}
+}
+
+func (t *NamedType) Pos() token.Pos {
+ return t.NamePos
}
func (t *NamedType) Complete(def Type) {
if !t.incomplete {
- log.Crashf("cannot complete already completed NamedType %+v", *t)
+ log.Panicf("cannot complete already completed NamedType %+v", *t)
}
// We strip the name from def because multiple levels of
// naming are useless.
@@ -1221,6 +1232,15 @@ func (t *MultiType) Zero() Value {
*/
func init() {
+ numer := big.NewInt(0xffffff)
+ numer.Lsh(numer, 127-23)
+ maxFloat32Val = new(big.Rat).SetInt(numer)
+ numer.SetInt64(0x1fffffffffffff)
+ numer.Lsh(numer, 1023-52)
+ maxFloat64Val = new(big.Rat).SetInt(numer)
+ minFloat32Val = new(big.Rat).Neg(maxFloat32Val)
+ minFloat64Val = new(big.Rat).Neg(maxFloat64Val)
+
// To avoid portability issues all numeric types are distinct
// except byte, which is an alias for uint8.
@@ -1232,6 +1252,7 @@ func init() {
universe.DefineConst("cap", universePos, capType, nil)
universe.DefineConst("close", universePos, closeType, nil)
universe.DefineConst("closed", universePos, closedType, nil)
+ universe.DefineConst("copy", universePos, copyType, nil)
universe.DefineConst("len", universePos, lenType, nil)
universe.DefineConst("make", universePos, makeType, nil)
universe.DefineConst("new", universePos, newType, nil)
diff --git a/src/pkg/exp/eval/typec.go b/src/pkg/exp/eval/typec.go
index 80ac078a2..de90cf664 100644
--- a/src/pkg/exp/eval/typec.go
+++ b/src/pkg/exp/eval/typec.go
@@ -26,21 +26,21 @@ type typeCompiler struct {
}
func (a *typeCompiler) compileIdent(x *ast.Ident, allowRec bool) Type {
- _, _, def := a.block.Lookup(x.Name())
+ _, _, def := a.block.Lookup(x.Name)
if def == nil {
- a.diagAt(x, "%s: undefined", x.Name())
+ a.diagAt(x.Pos(), "%s: undefined", x.Name)
return nil
}
switch def := def.(type) {
case *Constant:
- a.diagAt(x, "constant %v used as type", x.Name())
+ a.diagAt(x.Pos(), "constant %v used as type", x.Name)
return nil
case *Variable:
- a.diagAt(x, "variable %v used as type", x.Name())
+ a.diagAt(x.Pos(), "variable %v used as type", x.Name)
return nil
case *NamedType:
if !allowRec && def.incomplete {
- a.diagAt(x, "illegal recursive type")
+ a.diagAt(x.Pos(), "illegal recursive type")
return nil
}
if !def.incomplete && def.Def == nil {
@@ -51,7 +51,7 @@ func (a *typeCompiler) compileIdent(x *ast.Ident, allowRec bool) Type {
case Type:
return def
}
- log.Crashf("name %s has unknown type %T", x.Name(), def)
+ log.Panicf("name %s has unknown type %T", x.Name, def)
return nil
}
@@ -68,7 +68,7 @@ func (a *typeCompiler) compileArrayType(x *ast.ArrayType, allowRec bool) Type {
}
if _, ok := x.Len.(*ast.Ellipsis); ok {
- a.diagAt(x.Len, "... array initailizers not implemented")
+ a.diagAt(x.Len.Pos(), "... array initailizers not implemented")
return nil
}
l, ok := a.compileArrayLen(a.block, x.Len)
@@ -76,7 +76,7 @@ func (a *typeCompiler) compileArrayType(x *ast.ArrayType, allowRec bool) Type {
return nil
}
if l < 0 {
- a.diagAt(x.Len, "array length must be non-negative")
+ a.diagAt(x.Len.Pos(), "array length must be non-negative")
return nil
}
if elem == nil {
@@ -86,11 +86,11 @@ func (a *typeCompiler) compileArrayType(x *ast.ArrayType, allowRec bool) Type {
return NewArrayType(l, elem)
}
-func (a *typeCompiler) compileFields(fields *ast.FieldList, allowRec bool) ([]Type, []*ast.Ident, []token.Position, bool) {
+func (a *typeCompiler) compileFields(fields *ast.FieldList, allowRec bool) ([]Type, []*ast.Ident, []token.Pos, bool) {
n := fields.NumFields()
ts := make([]Type, n)
ns := make([]*ast.Ident, n)
- ps := make([]token.Position, n)
+ ps := make([]token.Pos, n)
bad := false
if fields != nil {
@@ -132,12 +132,12 @@ func (a *typeCompiler) compileStructType(x *ast.StructType, allowRec bool) Type
// uniqueness of field names inherited from anonymous fields
// at use time.
fields := make([]StructField, len(ts))
- nameSet := make(map[string]token.Position, len(ts))
+ nameSet := make(map[string]token.Pos, len(ts))
for i := range fields {
// Compute field name and check anonymous fields
var name string
if names[i] != nil {
- name = names[i].Name()
+ name = names[i].Name
} else {
if ts[i] == nil {
continue
@@ -162,7 +162,7 @@ func (a *typeCompiler) compileStructType(x *ast.StructType, allowRec bool) Type
// *T, and T itself, may not be a pointer or
// interface type.
if nt == nil {
- a.diagAt(&poss[i], "embedded type must T or *T, where T is a named type")
+ a.diagAt(poss[i], "embedded type must T or *T, where T is a named type")
bad = true
continue
}
@@ -172,7 +172,7 @@ func (a *typeCompiler) compileStructType(x *ast.StructType, allowRec bool) Type
lateCheck := a.lateCheck
a.lateCheck = func() bool {
if _, ok := nt.lit().(*PtrType); ok {
- a.diagAt(&poss[i], "embedded type %v is a pointer type", nt)
+ a.diagAt(poss[i], "embedded type %v is a pointer type", nt)
return false
}
return lateCheck()
@@ -181,7 +181,7 @@ func (a *typeCompiler) compileStructType(x *ast.StructType, allowRec bool) Type
// Check name uniqueness
if prev, ok := nameSet[name]; ok {
- a.diagAt(&poss[i], "field %s redeclared\n\tprevious declaration at %s", name, &prev)
+ a.diagAt(poss[i], "field %s redeclared\n\tprevious declaration at %s", name, a.fset.Position(prev))
bad = true
continue
}
@@ -227,7 +227,7 @@ func (a *typeCompiler) compileInterfaceType(x *ast.InterfaceType, allowRec bool)
ts, names, poss, bad := a.compileFields(x.Methods, allowRec)
methods := make([]IMethod, len(ts))
- nameSet := make(map[string]token.Position, len(ts))
+ nameSet := make(map[string]token.Pos, len(ts))
embeds := make([]*InterfaceType, len(ts))
var nm, ne int
@@ -237,12 +237,12 @@ func (a *typeCompiler) compileInterfaceType(x *ast.InterfaceType, allowRec bool)
}
if names[i] != nil {
- name := names[i].Name()
+ name := names[i].Name
methods[nm].Name = name
methods[nm].Type = ts[i].(*FuncType)
nm++
if prev, ok := nameSet[name]; ok {
- a.diagAt(&poss[i], "method %s redeclared\n\tprevious declaration at %s", name, &prev)
+ a.diagAt(poss[i], "method %s redeclared\n\tprevious declaration at %s", name, a.fset.Position(prev))
bad = true
continue
}
@@ -251,7 +251,7 @@ func (a *typeCompiler) compileInterfaceType(x *ast.InterfaceType, allowRec bool)
// Embedded interface
it, ok := ts[i].lit().(*InterfaceType)
if !ok {
- a.diagAt(&poss[i], "embedded type must be an interface")
+ a.diagAt(poss[i], "embedded type must be an interface")
bad = true
continue
}
@@ -259,7 +259,7 @@ func (a *typeCompiler) compileInterfaceType(x *ast.InterfaceType, allowRec bool)
ne++
for _, m := range it.methods {
if prev, ok := nameSet[m.Name]; ok {
- a.diagAt(&poss[i], "method %s redeclared\n\tprevious declaration at %s", m.Name, &prev)
+ a.diagAt(poss[i], "method %s redeclared\n\tprevious declaration at %s", m.Name, a.fset.Position(prev))
bad = true
continue
}
@@ -288,13 +288,13 @@ func (a *typeCompiler) compileMapType(x *ast.MapType) Type {
// that can be map keys except for function types.
switch key.lit().(type) {
case *StructType:
- a.diagAt(x, "map key cannot be a struct type")
+ a.diagAt(x.Pos(), "map key cannot be a struct type")
return nil
case *ArrayType:
- a.diagAt(x, "map key cannot be an array type")
+ a.diagAt(x.Pos(), "map key cannot be an array type")
return nil
case *SliceType:
- a.diagAt(x, "map key cannot be a slice type")
+ a.diagAt(x.Pos(), "map key cannot be a slice type")
return nil
}
return NewMapType(key, val)
@@ -339,14 +339,14 @@ func (a *typeCompiler) compileType(x ast.Expr, allowRec bool) Type {
return a.compileType(x.X, allowRec)
case *ast.Ellipsis:
- a.diagAt(x, "illegal use of ellipsis")
+ a.diagAt(x.Pos(), "illegal use of ellipsis")
return nil
}
- a.diagAt(x, "expression used as type")
+ a.diagAt(x.Pos(), "expression used as type")
return nil
notimpl:
- a.diagAt(x, "compileType: %T not implemented", x)
+ a.diagAt(x.Pos(), "compileType: %T not implemented", x)
return nil
}
@@ -370,7 +370,7 @@ func (a *compiler) compileTypeDecl(b *block, decl *ast.GenDecl) bool {
for _, spec := range decl.Specs {
spec := spec.(*ast.TypeSpec)
// Create incomplete type for this type
- nt := b.DefineType(spec.Name.Name(), spec.Name.Pos(), nil)
+ nt := b.DefineType(spec.Name.Name, spec.Name.Pos(), nil)
if nt != nil {
nt.(*NamedType).incomplete = true
}
diff --git a/src/pkg/exp/eval/util.go b/src/pkg/exp/eval/util.go
deleted file mode 100644
index ffe13e170..000000000
--- a/src/pkg/exp/eval/util.go
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package eval
-
-import (
- "exp/bignum"
-)
-
-// TODO(austin): Maybe add to bignum in more general form
-func ratToString(rat *bignum.Rational) string {
- n, dnat := rat.Value()
- d := bignum.MakeInt(false, dnat)
- w, frac := n.QuoRem(d)
- out := w.String()
- if frac.IsZero() {
- return out
- }
-
- r := frac.Abs()
- r = r.Mul(bignum.Nat(1e6))
- dec, tail := r.DivMod(dnat)
- // Round last digit
- if tail.Cmp(dnat.Div(bignum.Nat(2))) >= 0 {
- dec = dec.Add(bignum.Nat(1))
- }
- // Strip zeros
- ten := bignum.Nat(10)
- for !dec.IsZero() {
- dec2, r2 := dec.DivMod(ten)
- if !r2.IsZero() {
- break
- }
- dec = dec2
- }
- out += "." + dec.String()
- return out
-}
diff --git a/src/pkg/exp/eval/value.go b/src/pkg/exp/eval/value.go
index dce4bfcf3..cace2fd37 100644
--- a/src/pkg/exp/eval/value.go
+++ b/src/pkg/exp/eval/value.go
@@ -5,7 +5,7 @@
package eval
import (
- "exp/bignum"
+ "big"
"fmt"
)
@@ -40,7 +40,7 @@ type IntValue interface {
// because ideals are not l-values.
type IdealIntValue interface {
Value
- Get() *bignum.Integer
+ Get() *big.Int
}
type FloatValue interface {
@@ -51,7 +51,7 @@ type FloatValue interface {
type IdealFloatValue interface {
Value
- Get() *bignum.Rational
+ Get() *big.Rat
}
type StringValue interface {
@@ -272,7 +272,7 @@ func (v *intV) Set(t *Thread, x int64) { *v = intV(x) }
*/
type idealIntV struct {
- V *bignum.Integer
+ V *big.Int
}
func (v *idealIntV) String() string { return v.V.String() }
@@ -281,7 +281,7 @@ func (v *idealIntV) Assign(t *Thread, o Value) {
v.V = o.(IdealIntValue).Get()
}
-func (v *idealIntV) Get() *bignum.Integer { return v.V }
+func (v *idealIntV) Get() *big.Int { return v.V }
/*
* Float
@@ -322,16 +322,16 @@ func (v *floatV) Set(t *Thread, x float64) { *v = floatV(x) }
*/
type idealFloatV struct {
- V *bignum.Rational
+ V *big.Rat
}
-func (v *idealFloatV) String() string { return ratToString(v.V) }
+func (v *idealFloatV) String() string { return v.V.FloatString(6) }
func (v *idealFloatV) Assign(t *Thread, o Value) {
v.V = o.(IdealFloatValue).Get()
}
-func (v *idealFloatV) Get() *bignum.Rational { return v.V }
+func (v *idealFloatV) Get() *big.Rat { return v.V }
/*
* String
@@ -586,8 +586,6 @@ func (v multiV) Assign(t *Thread, o Value) {
* Universal constants
*/
-// TODO(austin) Nothing complains if I accidentally define init with
-// arguments. Is this intentional?
func init() {
s := universe
diff --git a/src/pkg/exp/eval/world.go b/src/pkg/exp/eval/world.go
index edeb39a5f..02d18bd79 100644
--- a/src/pkg/exp/eval/world.go
+++ b/src/pkg/exp/eval/world.go
@@ -41,14 +41,14 @@ type stmtCode struct {
code code
}
-func (w *World) CompileStmtList(stmts []ast.Stmt) (Code, os.Error) {
+func (w *World) CompileStmtList(fset *token.FileSet, stmts []ast.Stmt) (Code, os.Error) {
if len(stmts) == 1 {
if s, ok := stmts[0].(*ast.ExprStmt); ok {
- return w.CompileExpr(s.X)
+ return w.CompileExpr(fset, s.X)
}
}
errors := new(scanner.ErrorVector)
- cc := &compiler{errors, 0, 0}
+ cc := &compiler{fset, errors, 0, 0}
cb := newCodeBuf()
fc := &funcCompiler{
compiler: cc,
@@ -73,12 +73,12 @@ func (w *World) CompileStmtList(stmts []ast.Stmt) (Code, os.Error) {
return &stmtCode{w, fc.get()}, nil
}
-func (w *World) CompileDeclList(decls []ast.Decl) (Code, os.Error) {
+func (w *World) CompileDeclList(fset *token.FileSet, decls []ast.Decl) (Code, os.Error) {
stmts := make([]ast.Stmt, len(decls))
for i, d := range decls {
stmts[i] = &ast.DeclStmt{d}
}
- return w.CompileStmtList(stmts)
+ return w.CompileStmtList(fset, stmts)
}
func (s *stmtCode) Type() Type { return nil }
@@ -95,9 +95,9 @@ type exprCode struct {
eval func(Value, *Thread)
}
-func (w *World) CompileExpr(e ast.Expr) (Code, os.Error) {
+func (w *World) CompileExpr(fset *token.FileSet, e ast.Expr) (Code, os.Error) {
errors := new(scanner.ErrorVector)
- cc := &compiler{errors, 0, 0}
+ cc := &compiler{fset, errors, 0, 0}
ec := cc.compileExpr(w.scope.block, false, e)
if ec == nil {
@@ -135,16 +135,16 @@ func (e *exprCode) Run() (Value, os.Error) {
return v, err
}
-func (w *World) Compile(text string) (Code, os.Error) {
- stmts, err := parser.ParseStmtList("input", text, nil)
+func (w *World) Compile(fset *token.FileSet, text string) (Code, os.Error) {
+ stmts, err := parser.ParseStmtList(fset, "input", text)
if err == nil {
- return w.CompileStmtList(stmts)
+ return w.CompileStmtList(fset, stmts)
}
// Otherwise try as DeclList.
- decls, err1 := parser.ParseDeclList("input", text, nil)
+ decls, err1 := parser.ParseDeclList(fset, "input", text)
if err1 == nil {
- return w.CompileDeclList(decls)
+ return w.CompileDeclList(fset, decls)
}
// Have to pick an error.
@@ -162,13 +162,16 @@ func (e *RedefinitionError) String() string {
res := "identifier " + e.Name + " redeclared"
pos := e.Prev.Pos()
if pos.IsValid() {
- res += "; previous declaration at " + pos.String()
+ // TODO: fix this - currently this code is not reached by the tests
+ // need to get a file set (fset) from somewhere
+ //res += "; previous declaration at " + fset.Position(pos).String()
+ panic(0)
}
return res
}
func (w *World) DefineConst(name string, t Type, val Value) os.Error {
- _, prev := w.scope.DefineConst(name, token.Position{}, t, val)
+ _, prev := w.scope.DefineConst(name, token.NoPos, t, val)
if prev != nil {
return &RedefinitionError{name, prev}
}
@@ -176,7 +179,7 @@ func (w *World) DefineConst(name string, t Type, val Value) os.Error {
}
func (w *World) DefineVar(name string, t Type, val Value) os.Error {
- v, prev := w.scope.DefineVar(name, token.Position{}, t)
+ v, prev := w.scope.DefineVar(name, token.NoPos, t)
if prev != nil {
return &RedefinitionError{name, prev}
}
diff --git a/src/pkg/exp/iterable/array.go b/src/pkg/exp/iterable/array.go
deleted file mode 100644
index b5c7b5c6e..000000000
--- a/src/pkg/exp/iterable/array.go
+++ /dev/null
@@ -1,59 +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 iterable
-
-// This file implements the Iterable interface on some primitive types.
-
-type ByteArray []byte
-
-func (a ByteArray) Iter() <-chan interface{} {
- ch := make(chan interface{})
- go func() {
- for _, e := range a {
- ch <- e
- }
- close(ch)
- }()
- return ch
-}
-
-type IntArray []int
-
-func (a IntArray) Iter() <-chan interface{} {
- ch := make(chan interface{})
- go func() {
- for _, e := range a {
- ch <- e
- }
- close(ch)
- }()
- return ch
-}
-
-type FloatArray []float
-
-func (a FloatArray) Iter() <-chan interface{} {
- ch := make(chan interface{})
- go func() {
- for _, e := range a {
- ch <- e
- }
- close(ch)
- }()
- return ch
-}
-
-type StringArray []string
-
-func (a StringArray) Iter() <-chan interface{} {
- ch := make(chan interface{})
- go func() {
- for _, e := range a {
- ch <- e
- }
- close(ch)
- }()
- return ch
-}
diff --git a/src/pkg/exp/iterable/iterable.go b/src/pkg/exp/iterable/iterable.go
deleted file mode 100644
index aefff9427..000000000
--- a/src/pkg/exp/iterable/iterable.go
+++ /dev/null
@@ -1,344 +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.
-
-// The iterable package provides several traversal and searching methods.
-// It can be used on anything that satisfies the Iterable interface,
-// including vector, though certain functions, such as Map, can also be used on
-// something that would produce an infinite amount of data.
-package iterable
-
-import (
- "container/list"
- "container/vector"
-)
-
-type Iterable interface {
- // Iter should return a fresh channel each time it is called.
- Iter() <-chan interface{}
-}
-
-func not(f func(interface{}) bool) func(interface{}) bool {
- return func(e interface{}) bool { return !f(e) }
-}
-
-// All tests whether f is true for every element of iter.
-func All(iter Iterable, f func(interface{}) bool) bool {
- for e := range iter.Iter() {
- if !f(e) {
- return false
- }
- }
- return true
-}
-
-// Any tests whether f is true for at least one element of iter.
-func Any(iter Iterable, f func(interface{}) bool) bool {
- return !All(iter, not(f))
-}
-
-// Data returns a slice containing the elements of iter.
-func Data(iter Iterable) []interface{} {
- vec := new(vector.Vector)
- for e := range iter.Iter() {
- vec.Push(e)
- }
- return vec.Data()
-}
-
-// filteredIterable is a struct that implements Iterable with each element
-// passed through a filter.
-type filteredIterable struct {
- it Iterable
- f func(interface{}) bool
-}
-
-func (f *filteredIterable) iterate(out chan<- interface{}) {
- for e := range f.it.Iter() {
- if f.f(e) {
- out <- e
- }
- }
- close(out)
-}
-
-func (f *filteredIterable) Iter() <-chan interface{} {
- ch := make(chan interface{})
- go f.iterate(ch)
- return ch
-}
-
-// Filter returns an Iterable that returns the elements of iter that satisfy f.
-func Filter(iter Iterable, f func(interface{}) bool) Iterable {
- return &filteredIterable{iter, f}
-}
-
-// Find returns the first element of iter that satisfies f.
-// Returns nil if no such element is found.
-func Find(iter Iterable, f func(interface{}) bool) interface{} {
- for e := range Filter(iter, f).Iter() {
- return e
- }
- return nil
-}
-
-// Injector is a type representing a function that takes two arguments,
-// an accumulated value and an element, and returns the next accumulated value.
-// See the Inject function.
-type Injector func(interface{}, interface{}) interface{}
-
-// Inject combines the elements of iter by repeatedly calling f with an
-// accumulated value and each element in order. The starting accumulated value
-// is initial, and after each call the accumulated value is set to the return
-// value of f. For instance, to compute a sum:
-// var arr IntArray = []int{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
-// sum := iterable.Inject(arr, 0,
-// func(ax interface {}, x interface {}) interface {} {
-// return ax.(int) + x.(int) }).(int)
-func Inject(iter Iterable, initial interface{}, f Injector) interface{} {
- acc := initial
- for e := range iter.Iter() {
- acc = f(acc, e)
- }
- return acc
-}
-
-// mappedIterable is a helper struct that implements Iterable, returned by Map.
-type mappedIterable struct {
- it Iterable
- f func(interface{}) interface{}
-}
-
-func (m *mappedIterable) iterate(out chan<- interface{}) {
- for e := range m.it.Iter() {
- out <- m.f(e)
- }
- close(out)
-}
-
-func (m *mappedIterable) Iter() <-chan interface{} {
- ch := make(chan interface{})
- go m.iterate(ch)
- return ch
-}
-
-// Map returns an Iterable that returns the result of applying f to each
-// element of iter.
-func Map(iter Iterable, f func(interface{}) interface{}) Iterable {
- return &mappedIterable{iter, f}
-}
-
-// Partition(iter, f) returns Filter(iter, f) and Filter(iter, !f).
-func Partition(iter Iterable, f func(interface{}) bool) (Iterable, Iterable) {
- return Filter(iter, f), Filter(iter, not(f))
-}
-
-// A Func is a function that, when called, sends the
-// iterable values on a channel.
-type Func func(chan<- interface{})
-
-// Iter creates and returns a new channel; it starts a
-// goroutine running f to send values to the channel.
-func (f Func) Iter() <-chan interface{} {
- ch := make(chan interface{})
- go f(ch)
- return ch
-}
-
-// Take returns an Iterable that contains the first n elements of iter.
-func Take(iter Iterable, n int) Iterable { return Slice(iter, 0, n) }
-
-// TakeWhile returns an Iterable that contains elements from iter while f is true.
-func TakeWhile(iter Iterable, f func(interface{}) bool) Iterable {
- return Func(func(ch chan<- interface{}) {
- for v := range iter.Iter() {
- if !f(v) {
- break
- }
- ch <- v
- }
- close(ch)
- })
-}
-
-// Drop returns an Iterable that returns each element of iter after the first n elements.
-func Drop(iter Iterable, n int) Iterable {
- return Func(func(ch chan<- interface{}) {
- m := n
- for v := range iter.Iter() {
- if m > 0 {
- m--
- continue
- }
- ch <- v
- }
- close(ch)
- })
-}
-
-// DropWhile returns an Iterable that returns each element of iter after the initial sequence for which f returns true.
-func DropWhile(iter Iterable, f func(interface{}) bool) Iterable {
- return Func(func(ch chan<- interface{}) {
- drop := true
- for v := range iter.Iter() {
- if drop {
- if f(v) {
- continue
- }
- drop = false
- }
- ch <- v
- }
- close(ch)
- })
-}
-
-// Cycle repeats the values of iter in order infinitely.
-func Cycle(iter Iterable) Iterable {
- return Func(func(ch chan<- interface{}) {
- for {
- for v := range iter.Iter() {
- ch <- v
- }
- }
- })
-}
-
-// Chain returns an Iterable that concatentates all values from the specified Iterables.
-func Chain(args []Iterable) Iterable {
- return Func(func(ch chan<- interface{}) {
- for _, e := range args {
- for v := range e.Iter() {
- ch <- v
- }
- }
- close(ch)
- })
-}
-
-// Zip returns an Iterable of []interface{} consisting of the next element from
-// each input Iterable. The length of the returned Iterable is the minimum of
-// the lengths of the input Iterables.
-func Zip(args []Iterable) Iterable {
- return Func(func(ch chan<- interface{}) {
- defer close(ch)
- if len(args) == 0 {
- return
- }
- iters := make([]<-chan interface{}, len(args))
- for i := 0; i < len(iters); i++ {
- iters[i] = args[i].Iter()
- }
- for {
- out := make([]interface{}, len(args))
- for i, v := range iters {
- out[i] = <-v
- if closed(v) {
- return
- }
- }
- ch <- out
- }
- })
-}
-
-// ZipWith returns an Iterable containing the result of executing f using arguments read from a and b.
-func ZipWith2(f func(c, d interface{}) interface{}, a, b Iterable) Iterable {
- return Map(Zip([]Iterable{a, b}), func(a1 interface{}) interface{} {
- arr := a1.([]interface{})
- return f(arr[0], arr[1])
- })
-}
-
-// ZipWith returns an Iterable containing the result of executing f using arguments read from a, b and c.
-func ZipWith3(f func(d, e, f interface{}) interface{}, a, b, c Iterable) Iterable {
- return Map(Zip([]Iterable{a, b, c}), func(a1 interface{}) interface{} {
- arr := a1.([]interface{})
- return f(arr[0], arr[1], arr[2])
- })
-}
-
-// Slice returns an Iterable that contains the elements from iter
-// with indexes in [start, stop).
-func Slice(iter Iterable, start, stop int) Iterable {
- return Func(func(ch chan<- interface{}) {
- defer close(ch)
- i := 0
- for v := range iter.Iter() {
- switch {
- case i >= stop:
- return
- case i >= start:
- ch <- v
- }
- i++
- }
- })
-}
-
-// Repeat generates an infinite stream of v.
-func Repeat(v interface{}) Iterable {
- return Func(func(ch chan<- interface{}) {
- for {
- ch <- v
- }
- })
-}
-
-// RepeatTimes generates a stream of n copies of v.
-func RepeatTimes(v interface{}, n int) Iterable {
- return Func(func(ch chan<- interface{}) {
- for i := 0; i < n; i++ {
- ch <- v
- }
- close(ch)
- })
-}
-
-// Group is the type for elements returned by the GroupBy function.
-type Group struct {
- Key interface{} // key value for matching items
- Vals Iterable // Iterable for receiving values in the group
-}
-
-// Key defines the interface required by the GroupBy function.
-type Grouper interface {
- // Return the key for the given value
- Key(interface{}) interface{}
-
- // Compute equality for the given keys
- Equal(a, b interface{}) bool
-}
-
-// GroupBy combines sequences of logically identical values from iter using k
-// to generate a key to compare values. Each value emitted by the returned
-// Iterable is of type Group, which contains the key used for matching the
-// values for the group, and an Iterable for retrieving all the values in the
-// group.
-func GroupBy(iter Iterable, k Grouper) Iterable {
- return Func(func(ch chan<- interface{}) {
- var curkey interface{}
- var lst *list.List
- // Basic strategy is to read one group at a time into a list prior to emitting the Group value
- for v := range iter.Iter() {
- kv := k.Key(v)
- if lst == nil || !k.Equal(curkey, kv) {
- if lst != nil {
- ch <- Group{curkey, lst}
- }
- lst = list.New()
- curkey = kv
- }
- lst.PushBack(v)
- }
- if lst != nil {
- ch <- Group{curkey, lst}
- }
- close(ch)
- })
-}
-
-// Unique removes duplicate values which occur consecutively using id to compute keys.
-func Unique(iter Iterable, id Grouper) Iterable {
- return Map(GroupBy(iter, id), func(v interface{}) interface{} { return v.(Group).Key })
-}
diff --git a/src/pkg/exp/iterable/iterable_test.go b/src/pkg/exp/iterable/iterable_test.go
deleted file mode 100644
index 1d60d4b91..000000000
--- a/src/pkg/exp/iterable/iterable_test.go
+++ /dev/null
@@ -1,387 +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 iterable
-
-import (
- "container/vector"
- "testing"
-)
-
-func TestArrayTypes(t *testing.T) {
- // Test that conversion works correctly.
- bytes := ByteArray([]byte{1, 2, 3})
- if x := Data(bytes)[1].(byte); x != 2 {
- t.Error("Data(bytes)[1].(byte) = %v, want 2", x)
- }
- ints := IntArray([]int{1, 2, 3})
- if x := Data(ints)[2].(int); x != 3 {
- t.Error("Data(ints)[2].(int) = %v, want 3", x)
- }
- floats := FloatArray([]float{1, 2, 3})
- if x := Data(floats)[0].(float); x != 1 {
- t.Error("Data(floats)[0].(float) = %v, want 1", x)
- }
- strings := StringArray([]string{"a", "b", "c"})
- if x := Data(strings)[1].(string); x != "b" {
- t.Error(`Data(strings)[1].(string) = %q, want "b"`, x)
- }
-}
-
-var (
- oneToFive = IntArray{1, 2, 3, 4, 5}
- sixToTen = IntArray{6, 7, 8, 9, 10}
- elevenToTwenty = IntArray{11, 12, 13, 14, 15, 16, 17, 18, 19, 20}
-)
-
-func isNegative(n interface{}) bool { return n.(int) < 0 }
-func isPositive(n interface{}) bool { return n.(int) > 0 }
-func isAbove3(n interface{}) bool { return n.(int) > 3 }
-func isEven(n interface{}) bool { return n.(int)%2 == 0 }
-func doubler(n interface{}) interface{} { return n.(int) * 2 }
-func addOne(n interface{}) interface{} { return n.(int) + 1 }
-func adder(acc interface{}, n interface{}) interface{} {
- return acc.(int) + n.(int)
-}
-
-// A stream of the natural numbers: 0, 1, 2, 3, ...
-type integerStream struct{}
-
-func (i integerStream) Iter() <-chan interface{} {
- ch := make(chan interface{})
- go func() {
- for i := 0; ; i++ {
- ch <- i
- }
- }()
- return ch
-}
-
-func TestAll(t *testing.T) {
- if !All(oneToFive, isPositive) {
- t.Error("All(oneToFive, isPositive) == false")
- }
- if All(oneToFive, isAbove3) {
- t.Error("All(oneToFive, isAbove3) == true")
- }
-}
-
-func TestAny(t *testing.T) {
- if Any(oneToFive, isNegative) {
- t.Error("Any(oneToFive, isNegative) == true")
- }
- if !Any(oneToFive, isEven) {
- t.Error("Any(oneToFive, isEven) == false")
- }
-}
-
-func assertArraysAreEqual(t *testing.T, res []interface{}, expected []int) {
- if len(res) != len(expected) {
- t.Errorf("len(res) = %v, want %v", len(res), len(expected))
- goto missing
- }
- for i := range res {
- if v := res[i].(int); v != expected[i] {
- t.Errorf("res[%v] = %v, want %v", i, v, expected[i])
- goto missing
- }
- }
- return
-missing:
- t.Errorf("res = %v\nwant %v", res, expected)
-}
-
-func TestFilter(t *testing.T) {
- ints := integerStream{}
- moreInts := Filter(ints, isAbove3).Iter()
- res := make([]interface{}, 3)
- for i := 0; i < 3; i++ {
- res[i] = <-moreInts
- }
- assertArraysAreEqual(t, res, []int{4, 5, 6})
-}
-
-func TestFind(t *testing.T) {
- ints := integerStream{}
- first := Find(ints, isAbove3)
- if first.(int) != 4 {
- t.Errorf("Find(ints, isAbove3) = %v, want 4", first)
- }
-}
-
-func TestInject(t *testing.T) {
- res := Inject(oneToFive, 0, adder)
- if res.(int) != 15 {
- t.Errorf("Inject(oneToFive, 0, adder) = %v, want 15", res)
- }
-}
-
-func TestMap(t *testing.T) {
- res := Data(Map(Map(oneToFive, doubler), addOne))
- assertArraysAreEqual(t, res, []int{3, 5, 7, 9, 11})
-}
-
-func TestPartition(t *testing.T) {
- ti, fi := Partition(oneToFive, isEven)
- assertArraysAreEqual(t, Data(ti), []int{2, 4})
- assertArraysAreEqual(t, Data(fi), []int{1, 3, 5})
-}
-
-func TestTake(t *testing.T) {
- res := Take(oneToFive, 2)
- assertArraysAreEqual(t, Data(res), []int{1, 2})
- assertArraysAreEqual(t, Data(res), []int{1, 2}) // second test to ensure that .Iter() returns a new channel
-
- // take none
- res = Take(oneToFive, 0)
- assertArraysAreEqual(t, Data(res), []int{})
-
- // try to take more than available
- res = Take(oneToFive, 20)
- assertArraysAreEqual(t, Data(res), oneToFive)
-}
-
-func TestTakeWhile(t *testing.T) {
- // take some
- res := TakeWhile(oneToFive, func(v interface{}) bool { return v.(int) <= 3 })
- assertArraysAreEqual(t, Data(res), []int{1, 2, 3})
- assertArraysAreEqual(t, Data(res), []int{1, 2, 3}) // second test to ensure that .Iter() returns a new channel
-
- // take none
- res = TakeWhile(oneToFive, func(v interface{}) bool { return v.(int) > 3000 })
- assertArraysAreEqual(t, Data(res), []int{})
-
- // take all
- res = TakeWhile(oneToFive, func(v interface{}) bool { return v.(int) < 3000 })
- assertArraysAreEqual(t, Data(res), oneToFive)
-}
-
-func TestDrop(t *testing.T) {
- // drop none
- res := Drop(oneToFive, 0)
- assertArraysAreEqual(t, Data(res), oneToFive)
- assertArraysAreEqual(t, Data(res), oneToFive) // second test to ensure that .Iter() returns a new channel
-
- // drop some
- res = Drop(oneToFive, 2)
- assertArraysAreEqual(t, Data(res), []int{3, 4, 5})
- assertArraysAreEqual(t, Data(res), []int{3, 4, 5}) // second test to ensure that .Iter() returns a new channel
-
- // drop more than available
- res = Drop(oneToFive, 88)
- assertArraysAreEqual(t, Data(res), []int{})
-}
-
-func TestDropWhile(t *testing.T) {
- // drop some
- res := DropWhile(oneToFive, func(v interface{}) bool { return v.(int) < 3 })
- assertArraysAreEqual(t, Data(res), []int{3, 4, 5})
- assertArraysAreEqual(t, Data(res), []int{3, 4, 5}) // second test to ensure that .Iter() returns a new channel
-
- // test case where all elements are dropped
- res = DropWhile(oneToFive, func(v interface{}) bool { return v.(int) < 100 })
- assertArraysAreEqual(t, Data(res), []int{})
-
- // test case where none are dropped
- res = DropWhile(oneToFive, func(v interface{}) bool { return v.(int) > 1000 })
- assertArraysAreEqual(t, Data(res), oneToFive)
-}
-
-func TestCycle(t *testing.T) {
- res := Cycle(oneToFive)
- exp := []int{1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4}
-
- // read the first nineteen values from the iterable
- out := make([]interface{}, 19)
- for i, it := 0, res.Iter(); i < 19; i++ {
- out[i] = <-it
- }
- assertArraysAreEqual(t, out, exp)
-
- res2 := Cycle(sixToTen)
- exp2 := []int{6, 7, 8, 9, 10, 6, 7, 8, 9, 10, 6, 7, 8, 9, 10, 6, 7, 8, 9}
- for i, it := 0, res2.Iter(); i < 19; i++ {
- out[i] = <-it
- }
- assertArraysAreEqual(t, out, exp2)
-
- // ensure first iterator was not harmed
- for i, it := 0, res.Iter(); i < 19; i++ {
- out[i] = <-it
- }
- assertArraysAreEqual(t, out, exp)
-}
-
-func TestChain(t *testing.T) {
-
- exp := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}
- res := Chain([]Iterable{oneToFive, sixToTen, elevenToTwenty})
- assertArraysAreEqual(t, Data(res), exp)
-
- // reusing the same iterator should produce the same result again
- assertArraysAreEqual(t, Data(res), exp)
-
- // test short read from Chain
- i := 0
- out := make([]interface{}, 4)
- for v := range res.Iter() {
- out[i] = v
- i++
- if i == len(out) {
- break
- }
- }
- assertArraysAreEqual(t, out, exp[0:4])
-
- // test zero length array
- res = Chain([]Iterable{})
- assertArraysAreEqual(t, Data(res), []int{})
-}
-
-func TestZipWith(t *testing.T) {
- exp := []int{7, 9, 11, 13, 15}
-
- // f with 2 args and 1 return value
- f := func(a, b interface{}) interface{} { return a.(int) + b.(int) }
- res := ZipWith2(f, oneToFive, sixToTen)
- assertArraysAreEqual(t, Data(res), exp)
-
- // test again to make sure returns new iter each time
- assertArraysAreEqual(t, Data(res), exp)
-
- // test a function with 3 args
- f2 := func(a, b, c interface{}) interface{} { return a.(int) + b.(int) + c.(int) }
- res = ZipWith3(f2, oneToFive, sixToTen, oneToFive)
- exp = []int{8, 11, 14, 17, 20}
- assertArraysAreEqual(t, Data(res), exp)
-
- // test a function with multiple values returned
- f3 := func(a, b interface{}) interface{} { return ([]interface{}{a.(int) + 1, b.(int) + 1}) }
- res = ZipWith2(f3, oneToFive, sixToTen)
-
- exp2 := [][]int{[]int{2, 7}, []int{3, 8}, []int{4, 9}, []int{5, 10}, []int{6, 11}}
- i := 0
- for v := range res.Iter() {
- out := v.([]interface{})
- assertArraysAreEqual(t, out, exp2[i])
- i++
- }
-
- // test different length iterators--should stop after shortest is exhausted
- res = ZipWith2(f, elevenToTwenty, oneToFive)
- exp = []int{12, 14, 16, 18, 20}
- assertArraysAreEqual(t, Data(res), exp)
-}
-
-func TestSlice(t *testing.T) {
- out := Data(Slice(elevenToTwenty, 2, 6))
- exp := []int{13, 14, 15, 16}
- assertArraysAreEqual(t, out, exp)
-
- // entire iterable
- out = Data(Slice(elevenToTwenty, 0, len(elevenToTwenty)))
- exp = []int{11, 12, 13, 14, 15, 16, 17, 18, 19, 20}
- assertArraysAreEqual(t, out, exp)
-
- // empty slice at offset 0
- exp = []int{}
- out = Data(Slice(elevenToTwenty, 0, 0))
- assertArraysAreEqual(t, out, exp)
-
- // slice upper bound exceeds length of iterable
- exp = []int{1, 2, 3, 4, 5}
- out = Data(Slice(oneToFive, 0, 88))
- assertArraysAreEqual(t, out, exp)
-
- // slice upper bounce is lower than lower bound
- exp = []int{}
- out = Data(Slice(oneToFive, 93, 4))
- assertArraysAreEqual(t, out, exp)
-
- // slice lower bound is greater than len of iterable
- exp = []int{}
- out = Data(Slice(oneToFive, 93, 108))
- assertArraysAreEqual(t, out, exp)
-}
-
-func TestRepeat(t *testing.T) {
- res := Repeat(42)
- i := 0
- for v := range res.Iter() {
- if v.(int) != 42 {
- t.Fatal("Repeat returned the wrong value")
- }
- if i == 9 {
- break
- }
- i++
- }
-}
-
-func TestRepeatTimes(t *testing.T) {
- res := RepeatTimes(84, 9)
- exp := []int{84, 84, 84, 84, 84, 84, 84, 84, 84}
- assertArraysAreEqual(t, Data(res), exp)
- assertArraysAreEqual(t, Data(res), exp) // second time to ensure new iter is returned
-
- // 0 repeat
- res = RepeatTimes(7, 0)
- exp = []int{}
- assertArraysAreEqual(t, Data(res), exp)
-
- // negative repeat
- res = RepeatTimes(7, -3)
- exp = []int{}
- assertArraysAreEqual(t, Data(res), exp)
-}
-
-// a type that implements Key for ints
-type intkey struct{}
-
-func (v intkey) Key(a interface{}) interface{} {
- return a
-}
-func (v intkey) Equal(a, b interface{}) bool { return a.(int) == b.(int) }
-
-func TestGroupBy(t *testing.T) {
- in := IntArray{1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5}
- exp := [][]int{[]int{1}, []int{2, 2}, []int{3, 3, 3}, []int{4, 4, 4, 4}, []int{5, 5, 5, 5, 5}}
- i := 0
- for x := range GroupBy(in, intkey{}).Iter() {
- gr := x.(Group)
- if gr.Key.(int) != i+1 {
- t.Fatal("group key wrong; expected", i+1, "but got", gr.Key.(int))
- }
- vals := Data(gr.Vals)
- assertArraysAreEqual(t, vals, exp[i])
- i++
- }
- if i != 5 {
- t.Fatal("did not return expected number of groups")
- }
-
- // test 0 length Iterable
- for _ = range GroupBy(IntArray([]int{}), &intkey{}).Iter() {
- t.Fatal("iterator should be empty")
- }
-
- // test case with only uniques
- var out vector.Vector
- for x := range GroupBy(elevenToTwenty, intkey{}).Iter() {
- out.Push(x.(Group).Key)
- }
- assertArraysAreEqual(t, out.Data(), elevenToTwenty)
-}
-
-func TestUnique(t *testing.T) {
- in := IntArray([]int{1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5})
- exp := []int{1, 2, 3, 4, 5}
- res := Unique(in, intkey{})
- assertArraysAreEqual(t, Data(res), exp)
- assertArraysAreEqual(t, Data(res), exp) // second time to ensure new iter is returned
-
- // test case with only uniques
- res = Unique(elevenToTwenty, intkey{})
- assertArraysAreEqual(t, Data(res), elevenToTwenty)
-}
diff --git a/src/pkg/exp/nacl/README b/src/pkg/exp/nacl/README
deleted file mode 100644
index ec18f1d32..000000000
--- a/src/pkg/exp/nacl/README
+++ /dev/null
@@ -1,36 +0,0 @@
-Native Client support is still incomplete:
-Native Client does not yet allow runtime code generation,
-so Go's many uses of closures do not work.
-
-To try Native Client by running 4s (tetris) or 5s or Spacewar:
-
-1. Build the Go distribution for your native system.
-
-2. Download Native Client and install it.
- http://nativeclient.googlecode.com/svn/trunk/src/native_client/documentation/getting_started.html
- * You can stop after step 4 on those instructions
- (the ./scons --prebuilt firefox_install).
-
-3. (optional) Install "./build/native_client/scons-out/opt-*/staging/sel_ldr"
- from the Native Client distribution somewhere in your path as "nacl".
- This will let you run binaries using "nacl 8.out".
-
-4. Build the Go distribution again, this time for Native Client:
- cd $GOROOT/src
- ./all-nacl.bash
- * If you didn't do step 3, the tests at the end will fail, but that's okay.
- * If you are on a Mac, your dock will flicker as the "nacl" binary
- starts and stops while the tests run. You can stop the tests at any time.
-
-5. Run "godoc --http=:5103".
- * This will run the godoc built for your host OS, not Native Client,
- because all-nacl.bash doesn't install a nacl godoc.
- * Note that there is a colon before the 5103 in the argument
- (shorthand for 0.0.0.0:5103).
- * The port must be 5103: that's the only port that Native Client
- trusts to run binaries from.
-
-6. Open Firefox and visit one of:
- * http://localhost:5103/src/pkg/exp/4s/4s.html
- * http://localhost:5103/src/pkg/exp/4s/5s.html [sic]
- * http://localhost:5103/src/pkg/exp/spacewar/spacewar.html
diff --git a/src/pkg/exp/nacl/av/av.go b/src/pkg/exp/nacl/av/av.go
deleted file mode 100644
index 5c8728292..000000000
--- a/src/pkg/exp/nacl/av/av.go
+++ /dev/null
@@ -1,299 +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.
-
-// Native Client audio/video
-
-// Package av implements audio and video access for Native Client
-// binaries running standalone or embedded in a web browser window.
-//
-// The C version of the API is documented at
-// http://nativeclient.googlecode.com/svn/data/docs_tarball/nacl/googleclient/native_client/scons-out/doc/html/group__audio__video.html
-package av
-
-import (
- "exp/draw"
- "exp/nacl/srpc"
- "log"
- "os"
- "syscall"
- "unsafe"
-)
-
-var srpcEnabled = srpc.Enabled()
-
-// native_client/src/trusted/service_runtime/include/sys/audio_video.h
-
-// Subsystem values for Init.
-const (
- SubsystemVideo = 1 << iota
- SubsystemAudio
- SubsystemEmbed
-)
-// SubsystemRawEvents;
-
-// Audio formats.
-const (
- AudioFormatStereo44K = iota
- AudioFormatStereo48K
-)
-
-// A Window represents a connection to the Native Client window.
-// It implements draw.Context.
-type Window struct {
- Embedded bool // running as part of a web page?
- *Image // screen image
-
- mousec chan draw.Mouse
- kbdc chan int
- quitc chan bool
- resizec chan bool
-}
-
-// *Window implements draw.Context
-var _ draw.Context = (*Window)(nil)
-
-func (w *Window) KeyboardChan() <-chan int { return w.kbdc }
-
-func (w *Window) MouseChan() <-chan draw.Mouse {
- return w.mousec
-}
-
-func (w *Window) QuitChan() <-chan bool { return w.quitc }
-
-func (w *Window) ResizeChan() <-chan bool { return w.resizec }
-
-func (w *Window) Screen() draw.Image { return w.Image }
-
-// Init initializes the Native Client subsystems specified by subsys.
-// Init must be called before using any of the other functions
-// in this package, and it must be called only once.
-//
-// If the SubsystemVideo flag is set, Init requests a window of size dx×dy.
-// When embedded in a web page, the web page's window specification
-// overrides the parameters to Init, so the returned Window may have
-// a different size than requested.
-//
-// If the SubsystemAudio flag is set, Init requests a connection to the
-// audio device carrying 44 kHz 16-bit stereo PCM audio samples.
-func Init(subsys int, dx, dy int) (*Window, os.Error) {
- xsubsys := subsys
- if srpcEnabled {
- waitBridge()
- xsubsys &^= SubsystemVideo | SubsystemEmbed
- }
-
- if xsubsys&SubsystemEmbed != 0 {
- return nil, os.NewError("not embedded")
- }
-
- w := new(Window)
- err := multimediaInit(xsubsys)
- if err != nil {
- return nil, err
- }
-
- if subsys&SubsystemVideo != 0 {
- if dx, dy, err = videoInit(dx, dy); err != nil {
- return nil, err
- }
- w.Image = newImage(dx, dy, bridge.pixel)
- w.resizec = make(chan bool, 64)
- w.kbdc = make(chan int, 64)
- w.mousec = make(chan draw.Mouse, 64)
- w.quitc = make(chan bool)
- }
-
- if subsys&SubsystemAudio != 0 {
- var n int
- if n, err = audioInit(AudioFormatStereo44K, 2048); err != nil {
- return nil, err
- }
- println("audio", n)
- }
-
- if subsys&SubsystemVideo != 0 {
- go w.readEvents()
- }
-
- return w, nil
-}
-
-func (w *Window) FlushImage() {
- if w.Image == nil {
- return
- }
- videoUpdate(w.Image.Linear)
-}
-
-func multimediaInit(subsys int) (err os.Error) {
- return os.NewSyscallError("multimedia_init", syscall.MultimediaInit(subsys))
-}
-
-func videoInit(dx, dy int) (ndx, ndy int, err os.Error) {
- if srpcEnabled {
- bridge.share.ready = 1
- return int(bridge.share.width), int(bridge.share.height), nil
- }
- if e := syscall.VideoInit(dx, dy); e != 0 {
- return 0, 0, os.NewSyscallError("video_init", int(e))
- }
- return dx, dy, nil
-}
-
-func videoUpdate(data []Color) (err os.Error) {
- if srpcEnabled {
- bridge.flushRPC.Call("upcall", nil)
- return
- }
- return os.NewSyscallError("video_update", syscall.VideoUpdate((*uint32)(&data[0])))
-}
-
-var noEvents = os.NewError("no events")
-
-func videoPollEvent(ev []byte) (err os.Error) {
- if srpcEnabled {
- r := bridge.share.eq.ri
- if r == bridge.share.eq.wi {
- return noEvents
- }
- copy(ev, bridge.share.eq.event[r][0:])
- bridge.share.eq.ri = (r + 1) % eqsize
- return nil
- }
- return os.NewSyscallError("video_poll_event", syscall.VideoPollEvent(&ev[0]))
-}
-
-func audioInit(fmt int, want int) (got int, err os.Error) {
- var x int
- e := syscall.AudioInit(fmt, want, &x)
- if e == 0 {
- return x, nil
- }
- return 0, os.NewSyscallError("audio_init", e)
-}
-
-var audioSize uintptr
-
-// AudioStream provides access to the audio device.
-// Each call to AudioStream writes the given data,
-// which should be a slice of 16-bit stereo PCM audio samples,
-// and returns the number of samples required by the next
-// call to AudioStream.
-//
-// To find out the initial number of samples to write, call AudioStream(nil).
-//
-func AudioStream(data []uint16) (nextSize int, err os.Error) {
- if audioSize == 0 {
- e := os.NewSyscallError("audio_stream", syscall.AudioStream(nil, &audioSize))
- return int(audioSize), e
- }
- if data == nil {
- return int(audioSize), nil
- }
- if uintptr(len(data))*2 != audioSize {
- log.Stdoutf("invalid audio size want %d got %d", audioSize, len(data))
- }
- e := os.NewSyscallError("audio_stream", syscall.AudioStream(&data[0], &audioSize))
- return int(audioSize), e
-}
-
-// Synchronization structure to wait for bridge to become ready.
-var bridge struct {
- c chan bool
- displayFd int
- rpcFd int
- share *videoShare
- pixel []Color
- client *srpc.Client
- flushRPC *srpc.RPC
-}
-
-// Wait for bridge to become ready.
-// When chan is first created, there is nothing in it,
-// so this blocks. Once the bridge is ready, multimediaBridge.Run
-// will drop a value into the channel. Then any calls
-// to waitBridge will finish, taking the value out and immediately putting it back.
-func waitBridge() { bridge.c <- <-bridge.c }
-
-const eqsize = 64
-
-// Data structure shared with host via mmap.
-type videoShare struct {
- revision int32 // definition below is rev 100 unless noted
- mapSize int32
-
- // event queue
- eq struct {
- ri uint32 // read index [0,eqsize)
- wi uint32 // write index [0,eqsize)
- eof int32
- event [eqsize][64]byte
- }
-
- // now unused
- _, _, _, _ int32
-
- // video backing store information
- width, height, _, size int32
- ready int32 // rev 0x101
-}
-
-// The frame buffer data is videoShareSize bytes after
-// the videoShare begins.
-const videoShareSize = 16 * 1024
-
-type multimediaBridge struct{}
-
-// If using SRPC, the runtime will call this method to pass in two file descriptors,
-// one to mmap to get the display memory, and another to use for SRPCs back
-// to the main process.
-func (multimediaBridge) Run(arg, ret []interface{}, size []int) srpc.Errno {
- bridge.displayFd = arg[0].(int)
- bridge.rpcFd = arg[1].(int)
-
- var st syscall.Stat_t
- if errno := syscall.Fstat(bridge.displayFd, &st); errno != 0 {
- log.Exitf("mmbridge stat display: %s", os.Errno(errno))
- }
-
- addr, _, errno := syscall.Syscall6(syscall.SYS_MMAP,
- 0,
- uintptr(st.Size),
- syscall.PROT_READ|syscall.PROT_WRITE,
- syscall.MAP_SHARED,
- uintptr(bridge.displayFd),
- 0)
- if errno != 0 {
- log.Exitf("mmap display: %s", os.Errno(errno))
- }
-
- bridge.share = (*videoShare)(unsafe.Pointer(addr))
-
- // Overestimate frame buffer size
- // (must use a compile-time constant)
- // and then reslice. 256 megapixels (1 GB) should be enough.
- fb := (*[256 * 1024 * 1024]Color)(unsafe.Pointer(addr + videoShareSize))
- bridge.pixel = fb[0 : (st.Size-videoShareSize)/4]
-
- // Configure RPC connection back to client.
- var err os.Error
- bridge.client, err = srpc.NewClient(bridge.rpcFd)
- if err != nil {
- log.Exitf("NewClient: %s", err)
- }
- bridge.flushRPC = bridge.client.NewRPC(nil)
-
- // Notify waiters that the bridge is ready.
- println("bridged", bridge.share.revision)
- bridge.c <- true
-
- return srpc.OK
-}
-
-func init() {
- bridge.c = make(chan bool, 1)
- if srpcEnabled {
- srpc.Add("nacl_multimedia_bridge", "hh:", multimediaBridge{})
- }
-}
diff --git a/src/pkg/exp/nacl/av/event.go b/src/pkg/exp/nacl/av/event.go
deleted file mode 100644
index 11405c980..000000000
--- a/src/pkg/exp/nacl/av/event.go
+++ /dev/null
@@ -1,472 +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.
-
-// NaCl GUI events.
-// Clients do not have raw access to the event stream
-// (only filtered through the lens of package draw)
-// but perhaps they will.
-
-package av
-
-import (
- "encoding/binary"
- "exp/draw"
- "log"
- "os"
- "time"
-)
-
-// An eventType identifies the type of a Native Client Event.
-type eventType uint8
-
-const (
- eventActive = 1 + iota
- eventExpose
- eventKeyDown
- eventKeyUp
- eventMouseMotion
- eventMouseButtonDown
- eventMouseButtonUp
- eventQuit
- eventUnsupported
-)
-
-// A key represents a key on a keyboard.
-type key uint16
-
-const (
- keyUnknown = 0
- keyFirst = 0
- keyBackspace = 8
- keyTab = 9
- keyClear = 12
- keyReturn = 13
- keyPause = 19
- keyEscape = 27
- keySpace = 32
- keyExclaim = 33
- keyQuotedbl = 34
- keyHash = 35
- keyDollar = 36
- keyAmpersand = 38
- keyQuote = 39
- keyLeftparen = 40
- keyRightparen = 41
- keyAsterisk = 42
- keyPlus = 43
- keyComma = 44
- keyMinus = 45
- keyPeriod = 46
- keySlash = 47
- key0 = 48
- key1 = 49
- key2 = 50
- key3 = 51
- key4 = 52
- key5 = 53
- key6 = 54
- key7 = 55
- key8 = 56
- key9 = 57
- keyColon = 58
- keySemicolon = 59
- keyLess = 60
- keyEquals = 61
- keyGreater = 62
- keyQuestion = 63
- keyAt = 64
- keyLeftbracket = 91
- keyBackslash = 92
- keyRightbracket = 93
- keyCaret = 94
- keyUnderscore = 95
- keyBackquote = 96
- keyA = 97
- keyB = 98
- keyC = 99
- keyD = 100
- keyE = 101
- keyF = 102
- keyG = 103
- keyH = 104
- keyI = 105
- keyJ = 106
- keyK = 107
- keyL = 108
- keyM = 109
- keyN = 110
- keyO = 111
- keyP = 112
- keyQ = 113
- keyR = 114
- keyS = 115
- keyT = 116
- keyU = 117
- keyV = 118
- keyW = 119
- keyX = 120
- keyY = 121
- keyZ = 122
- keyDelete = 127
- keyWorld0 = 160
- keyWorld1 = 161
- keyWorld2 = 162
- keyWorld3 = 163
- keyWorld4 = 164
- keyWorld5 = 165
- keyWorld6 = 166
- keyWorld7 = 167
- keyWorld8 = 168
- keyWorld9 = 169
- keyWorld10 = 170
- keyWorld11 = 171
- keyWorld12 = 172
- keyWorld13 = 173
- keyWorld14 = 174
- keyWorld15 = 175
- keyWorld16 = 176
- keyWorld17 = 177
- keyWorld18 = 178
- keyWorld19 = 179
- keyWorld20 = 180
- keyWorld21 = 181
- keyWorld22 = 182
- keyWorld23 = 183
- keyWorld24 = 184
- keyWorld25 = 185
- keyWorld26 = 186
- keyWorld27 = 187
- keyWorld28 = 188
- keyWorld29 = 189
- keyWorld30 = 190
- keyWorld31 = 191
- keyWorld32 = 192
- keyWorld33 = 193
- keyWorld34 = 194
- keyWorld35 = 195
- keyWorld36 = 196
- keyWorld37 = 197
- keyWorld38 = 198
- keyWorld39 = 199
- keyWorld40 = 200
- keyWorld41 = 201
- keyWorld42 = 202
- keyWorld43 = 203
- keyWorld44 = 204
- keyWorld45 = 205
- keyWorld46 = 206
- keyWorld47 = 207
- keyWorld48 = 208
- keyWorld49 = 209
- keyWorld50 = 210
- keyWorld51 = 211
- keyWorld52 = 212
- keyWorld53 = 213
- keyWorld54 = 214
- keyWorld55 = 215
- keyWorld56 = 216
- keyWorld57 = 217
- keyWorld58 = 218
- keyWorld59 = 219
- keyWorld60 = 220
- keyWorld61 = 221
- keyWorld62 = 222
- keyWorld63 = 223
- keyWorld64 = 224
- keyWorld65 = 225
- keyWorld66 = 226
- keyWorld67 = 227
- keyWorld68 = 228
- keyWorld69 = 229
- keyWorld70 = 230
- keyWorld71 = 231
- keyWorld72 = 232
- keyWorld73 = 233
- keyWorld74 = 234
- keyWorld75 = 235
- keyWorld76 = 236
- keyWorld77 = 237
- keyWorld78 = 238
- keyWorld79 = 239
- keyWorld80 = 240
- keyWorld81 = 241
- keyWorld82 = 242
- keyWorld83 = 243
- keyWorld84 = 244
- keyWorld85 = 245
- keyWorld86 = 246
- keyWorld87 = 247
- keyWorld88 = 248
- keyWorld89 = 249
- keyWorld90 = 250
- keyWorld91 = 251
- keyWorld92 = 252
- keyWorld93 = 253
- keyWorld94 = 254
- keyWorld95 = 255
-
- // Numeric keypad
- keyKp0 = 256
- keyKp1 = 257
- keyKp2 = 258
- keyKp3 = 259
- keyKp4 = 260
- keyKp5 = 261
- keyKp6 = 262
- keyKp7 = 263
- keyKp8 = 264
- keyKp9 = 265
- keyKpPeriod = 266
- keyKpDivide = 267
- keyKpMultiply = 268
- keyKpMinus = 269
- keyKpPlus = 270
- keyKpEnter = 271
- keyKpEquals = 272
-
- // Arrow & insert/delete pad
- keyUp = 273
- keyDown = 274
- keyRight = 275
- keyLeft = 276
- keyInsert = 277
- keyHome = 278
- keyEnd = 279
- keyPageup = 280
- keyPagedown = 281
-
- // Function keys
- keyF1 = 282
- keyF2 = 283
- keyF3 = 284
- keyF4 = 285
- keyF5 = 286
- keyF6 = 287
- keyF7 = 288
- keyF8 = 289
- keyF9 = 290
- keyF10 = 291
- keyF11 = 292
- keyF12 = 293
- keyF13 = 294
- keyF14 = 295
- keyF15 = 296
-
- // Modifier keys
- keyNumlock = 300
- keyCapslock = 301
- keyScrollock = 302
- keyRshift = 303
- keyLshift = 304
- keyRctrl = 305
- keyLctrl = 306
- keyRalt = 307
- keyLalt = 308
- keyRmeta = 309
- keyLmeta = 310
- keyLsuper = 311
- keyRsuper = 312
- keyMode = 313
- keyCompose = 314
-
- // Misc keys
- keyHelp = 315
- keyPrint = 316
- keySysreq = 317
- keyBreak = 318
- keyMenu = 319
- keyPower = 320
- keyEuro = 321
- keyUndo = 322
-
- // Add any other keys here
- keyLast
-)
-
-// A keymod is a set of bit flags
-type keymod uint16
-
-const (
- keymodNone = 0x0000
- keymodLshift = 0x0001
- keymodRshift = 0x0002
- keymodLctrl = 0x0040
- keymodRctrl = 0x0080
- keymodLalt = 0x0100
- keymodRalt = 0x0200
- keymodLmeta = 0x0400
- keymodRmeta = 0x0800
- keymodNum = 0x1000
- keymodCaps = 0x2000
- keymodMode = 0x4000
- keymodReserved = 0x8000
-)
-
-const (
- mouseButtonLeft = 1
- mouseButtonMiddle = 2
- mouseButtonRight = 3
- mouseScrollUp = 4
- mouseScrollDown = 5
-)
-
-const (
- mouseStateLeftButtonPressed = 1
- mouseStateMiddleButtonPressed = 2
- mouseStateRightButtonPressed = 4
-)
-
-const (
- activeMouse = 1 // mouse leaving/entering
- activeInputFocus = 2 // input focus lost/restored
- activeApplication = 4 // application minimized/restored
-)
-
-const maxEventBytes = 64
-
-type activeEvent struct {
- EventType eventType
- Gain uint8
- State uint8
-}
-
-type exposeEvent struct {
- EventType eventType
-}
-
-type keyboardEvent struct {
- EventType eventType
- Device uint8
- State uint8
- Pad uint8
- ScanCode uint8
- Pad1 uint8
- Key key
- Mod keymod
- Unicode uint16
-}
-
-type mouseMotionEvent struct {
- EventType eventType
- Device uint8
- Buttons uint8
- Pad uint8
- X uint16
- Y uint16
- Xrel int16
- Yrel int16
-}
-
-type mouseButtonEvent struct {
- EventType eventType
- Device uint8
- Button uint8
- State uint8
- X uint16
- Y uint16
-}
-
-type quitEvent struct {
- EventType eventType
-}
-
-type syncEvent struct{}
-
-type event interface{}
-
-type reader []byte
-
-func (r *reader) Read(p []byte) (n int, err os.Error) {
- b := *r
- if len(b) == 0 && len(p) > 0 {
- return 0, os.EOF
- }
- n = copy(p, b)
- *r = b[n:]
- return
-}
-
-func (w *Window) readEvents() {
- buf := make([]byte, maxEventBytes)
- clean := false
- var (
- ea *activeEvent
- ee *exposeEvent
- ke *keyboardEvent
- mme *mouseMotionEvent
- mbe *mouseButtonEvent
- qe *quitEvent
- )
- var m draw.Mouse
- for {
- if err := videoPollEvent(buf); err != nil {
- if !clean {
- clean = w.resizec <- false
- }
- time.Sleep(10e6) // 10ms
- continue
- }
- clean = false
- var e event
- switch buf[0] {
- default:
- log.Stdout("unsupported event type", buf[0])
- continue
- case eventActive:
- ea = new(activeEvent)
- e = ea
- case eventExpose:
- ee = new(exposeEvent)
- e = ee
- case eventKeyDown, eventKeyUp:
- ke = new(keyboardEvent)
- e = ke
- case eventMouseMotion:
- mme = new(mouseMotionEvent)
- e = mme
- case eventMouseButtonDown, eventMouseButtonUp:
- mbe = new(mouseButtonEvent)
- e = mbe
- case eventQuit:
- qe = new(quitEvent)
- e = qe
- }
- r := reader(buf)
- if err := binary.Read(&r, binary.LittleEndian, e); err != nil {
- log.Stdout("unpacking %T event: %s", e, err)
- continue
- }
- // log.Stdoutf("%#v\n", e);
- switch buf[0] {
- case eventExpose:
- w.resizec <- true
- case eventKeyDown:
- w.kbdc <- int(ke.Key)
- case eventKeyUp:
- w.kbdc <- -int(ke.Key)
- case eventMouseMotion:
- m.X = int(mme.X)
- m.Y = int(mme.Y)
- m.Buttons = int(mme.Buttons)
- m.Nsec = time.Nanoseconds()
- _ = w.mousec <- m
- case eventMouseButtonDown:
- m.X = int(mbe.X)
- m.Y = int(mbe.Y)
- // TODO(rsc): Remove uint cast once 8g bug is fixed.
- m.Buttons |= 1 << uint(mbe.Button-1)
- m.Nsec = time.Nanoseconds()
- _ = w.mousec <- m
- case eventMouseButtonUp:
- m.X = int(mbe.X)
- m.Y = int(mbe.Y)
- // TODO(rsc): Remove uint cast once 8g bug is fixed.
- m.Buttons &^= 1 << uint(mbe.Button-1)
- m.Nsec = time.Nanoseconds()
- _ = w.mousec <- m
- case eventQuit:
- w.quitc <- true
- }
- }
-}
diff --git a/src/pkg/exp/nacl/av/image.go b/src/pkg/exp/nacl/av/image.go
deleted file mode 100644
index 8de531136..000000000
--- a/src/pkg/exp/nacl/av/image.go
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package av
-
-import (
- "image"
-)
-
-// Native Client image format:
-// a single linear array of 32-bit ARGB as packed uint32s.
-
-// An Image represents a Native Client frame buffer.
-// The pixels in the image can be accessed as a single
-// linear slice or as a two-dimensional slice of slices.
-// Image implements image.Image.
-type Image struct {
- Linear []Color
- Pixel [][]Color
-}
-
-var _ image.Image = (*Image)(nil)
-
-func (m *Image) ColorModel() image.ColorModel { return ColorModel }
-
-func (m *Image) Width() int {
- if len(m.Pixel) == 0 {
- return 0
- }
- return len(m.Pixel[0])
-}
-
-func (m *Image) Height() int { return len(m.Pixel) }
-
-func (m *Image) At(x, y int) image.Color { return m.Pixel[y][x] }
-
-func (m *Image) Set(x, y int, color image.Color) {
- if c, ok := color.(Color); ok {
- m.Pixel[y][x] = c
- }
- m.Pixel[y][x] = makeColor(color.RGBA())
-}
-
-func newImage(dx, dy int, linear []Color) *Image {
- if linear == nil {
- linear = make([]Color, dx*dy)
- }
- pix := make([][]Color, dy)
- for i := range pix {
- pix[i] = linear[dx*i : dx*(i+1)]
- }
- return &Image{linear, pix}
-}
-
-// A Color represents a Native Client color value,
-// a 32-bit R, G, B, A value packed as 0xAARRGGBB.
-type Color uint32
-
-func (p Color) RGBA() (r, g, b, a uint32) {
- x := uint32(p)
- a = x >> 24
- a |= a << 8
- r = (x >> 16) & 0xFF
- r |= r << 8
- g = (x >> 8) & 0xFF
- g |= g << 8
- b = x & 0xFF
- b |= b << 8
- return
-}
-
-func makeColor(r, g, b, a uint32) Color {
- return Color(a>>24<<24 | r>>24<<16 | g>>24<<8 | b>>24)
-}
-
-func toColor(color image.Color) image.Color {
- if c, ok := color.(Color); ok {
- return c
- }
- return makeColor(color.RGBA())
-}
-
-// ColorModel is the color model corresponding to the Native Client Color.
-var ColorModel = image.ColorModelFunc(toColor)
diff --git a/src/pkg/exp/nacl/srpc/client.go b/src/pkg/exp/nacl/srpc/client.go
deleted file mode 100644
index f45730ffa..000000000
--- a/src/pkg/exp/nacl/srpc/client.go
+++ /dev/null
@@ -1,210 +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 package implements Native Client's simple RPC (SRPC).
-package srpc
-
-import (
- "bytes"
- "log"
- "os"
- "sync"
-)
-
-// A Client represents the client side of an SRPC connection.
-type Client struct {
- fd int // fd to server
- r msgReceiver
- s msgSender
- service map[string]srv // services by name
- out chan *msg // send to out to write to connection
-
- mu sync.Mutex // protects pending, idGen
- pending map[uint64]*RPC
- idGen uint64 // generator for request IDs
-}
-
-// A srv is a single method that the server offers.
-type srv struct {
- num uint32 // method number
- fmt string // argument format
-}
-
-// An RPC represents a single RPC issued by a client.
-type RPC struct {
- Ret []interface{} // Return values
- Done chan *RPC // Channel where notification of done arrives
- Errno Errno // Status code
- c *Client
- id uint64 // request id
-}
-
-// NewClient allocates a new client using the file descriptor fd.
-func NewClient(fd int) (c *Client, err os.Error) {
- c = new(Client)
- c.fd = fd
- c.r.fd = fd
- c.s.fd = fd
- c.service = make(map[string]srv)
- c.pending = make(map[uint64]*RPC)
-
- // service discovery request
- m := &msg{
- protocol: protocol,
- isReq: true,
- Ret: []interface{}{[]byte(nil)},
- Size: []int{4000},
- }
- m.packRequest()
- c.s.send(m)
- m, err = c.r.recv()
- if err != nil {
- return nil, err
- }
- m.unpackResponse()
- if m.status != OK {
- log.Stderrf("NewClient service_discovery: %s", m.status)
- return nil, m.status
- }
- for n, line := range bytes.Split(m.Ret[0].([]byte), []byte{'\n'}, -1) {
- i := bytes.Index(line, []byte{':'})
- if i < 0 {
- continue
- }
- c.service[string(line[0:i])] = srv{uint32(n), string(line[i+1:])}
- }
-
- c.out = make(chan *msg)
- go c.input()
- go c.output()
- return c, nil
-}
-
-func (c *Client) input() {
- for {
- m, err := c.r.recv()
- if err != nil {
- log.Exitf("client recv: %s", err)
- }
- if m.unpackResponse(); m.status != OK {
- log.Stderrf("invalid message: %s", m.status)
- continue
- }
- c.mu.Lock()
- rpc, ok := c.pending[m.requestId]
- if ok {
- c.pending[m.requestId] = nil, false
- }
- c.mu.Unlock()
- if !ok {
- log.Stderrf("unexpected response")
- continue
- }
- rpc.Ret = m.Ret
- rpc.Done <- rpc
- }
-}
-
-func (c *Client) output() {
- for m := range c.out {
- c.s.send(m)
- }
-}
-
-// NewRPC creates a new RPC on the client connection.
-func (c *Client) NewRPC(done chan *RPC) *RPC {
- if done == nil {
- done = make(chan *RPC)
- }
- c.mu.Lock()
- id := c.idGen
- c.idGen++
- c.mu.Unlock()
- return &RPC{nil, done, OK, c, id}
-}
-
-// Start issues an RPC request for method name with the given arguments.
-// The RPC r must not be in use for another pending request.
-// To wait for the RPC to finish, receive from r.Done and then
-// inspect r.Ret and r.Errno.
-func (r *RPC) Start(name string, arg []interface{}) {
- var m msg
-
- r.Errno = OK
- r.c.mu.Lock()
- srv, ok := r.c.service[name]
- if !ok {
- r.c.mu.Unlock()
- r.Errno = ErrBadRPCNumber
- r.Done <- r
- return
- }
- r.c.pending[r.id] = r
- r.c.mu.Unlock()
-
- m.protocol = protocol
- m.requestId = r.id
- m.isReq = true
- m.rpcNumber = srv.num
- m.Arg = arg
-
- // Fill in the return values and sizes to generate
- // the right type chars. We'll take most any size.
-
- // Skip over input arguments.
- // We could check them against arg, but the server
- // will do that anyway.
- i := 0
- for srv.fmt[i] != ':' {
- i++
- }
- fmt := srv.fmt[i+1:]
-
- // Now the return prototypes.
- m.Ret = make([]interface{}, len(fmt)-i)
- m.Size = make([]int, len(fmt)-i)
- for i := 0; i < len(fmt); i++ {
- switch fmt[i] {
- default:
- log.Exitf("unexpected service type %c", fmt[i])
- case 'b':
- m.Ret[i] = false
- case 'C':
- m.Ret[i] = []byte(nil)
- m.Size[i] = 1 << 30
- case 'd':
- m.Ret[i] = float64(0)
- case 'D':
- m.Ret[i] = []float64(nil)
- m.Size[i] = 1 << 30
- case 'h':
- m.Ret[i] = int(-1)
- case 'i':
- m.Ret[i] = int32(0)
- case 'I':
- m.Ret[i] = []int32(nil)
- m.Size[i] = 1 << 30
- case 's':
- m.Ret[i] = ""
- m.Size[i] = 1 << 30
- }
- }
-
- m.packRequest()
- r.c.out <- &m
-}
-
-// Call is a convenient wrapper that starts the RPC request,
-// waits for it to finish, and then returns the results.
-// Its implementation is:
-//
-// r.Start(name, arg)
-// <-r.Done
-// return r.Ret, r.Errno
-//
-func (r *RPC) Call(name string, arg []interface{}) (ret []interface{}, err Errno) {
- r.Start(name, arg)
- <-r.Done
- return r.Ret, r.Errno
-}
diff --git a/src/pkg/exp/nacl/srpc/msg.go b/src/pkg/exp/nacl/srpc/msg.go
deleted file mode 100644
index fe36dbdeb..000000000
--- a/src/pkg/exp/nacl/srpc/msg.go
+++ /dev/null
@@ -1,526 +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.
-
-// SRPC constants, data structures, and parsing.
-
-package srpc
-
-import (
- "math"
- "os"
- "strconv"
- "syscall"
- "unsafe"
-)
-
-// An Errno is an SRPC status code.
-type Errno uint32
-
-const (
- OK Errno = 256 + iota
- ErrBreak
- ErrMessageTruncated
- ErrNoMemory
- ErrProtocolMismatch
- ErrBadRPCNumber
- ErrBadArgType
- ErrTooFewArgs
- ErrTooManyArgs
- ErrInArgTypeMismatch
- ErrOutArgTypeMismatch
- ErrInternalError
- ErrAppError
-)
-
-var errstr = [...]string{
- OK - OK: "ok",
- ErrBreak - OK: "break",
- ErrMessageTruncated - OK: "message truncated",
- ErrNoMemory - OK: "out of memory",
- ErrProtocolMismatch - OK: "protocol mismatch",
- ErrBadRPCNumber - OK: "invalid RPC method number",
- ErrBadArgType - OK: "unexpected argument type",
- ErrTooFewArgs - OK: "too few arguments",
- ErrTooManyArgs - OK: "too many arguments",
- ErrInArgTypeMismatch - OK: "input argument type mismatch",
- ErrOutArgTypeMismatch - OK: "output argument type mismatch",
- ErrInternalError - OK: "internal error",
- ErrAppError - OK: "application error",
-}
-
-func (e Errno) String() string {
- if e < OK || int(e-OK) >= len(errstr) {
- return "Errno(" + strconv.Itoa64(int64(e)) + ")"
- }
- return errstr[e-OK]
-}
-
-// A *msgHdr is the data argument to the imc_recvmsg
-// and imc_sendmsg system calls. Because it contains unchecked
-// counts trusted by the system calls, the data structure is unsafe
-// to expose to package clients.
-type msgHdr struct {
- iov *iov
- niov int32
- desc *int32
- ndesc int32
- flags uint32
-}
-
-// A single region for I/O. Just as unsafe as msgHdr.
-type iov struct {
- base *byte
- len int32
-}
-
-// A msg is the Go representation of a message.
-type msg struct {
- rdata []byte // data being consumed during message parsing
- rdesc []int32 // file descriptors being consumed during message parsing
- wdata []byte // data being generated when replying
-
- // parsed version of message
- protocol uint32
- requestId uint64
- isReq bool
- rpcNumber uint32
- gotHeader bool
- status Errno // error code sent in response
- Arg []interface{} // method arguments
- Ret []interface{} // method results
- Size []int // max sizes for arrays in method results
- fmt string // accumulated format string of arg+":"+ret
-}
-
-// A msgReceiver receives messages from a file descriptor.
-type msgReceiver struct {
- fd int
- data [128 * 1024]byte
- desc [8]int32
- hdr msgHdr
- iov iov
-}
-
-func (r *msgReceiver) recv() (*msg, os.Error) {
- // Init pointers to buffers where syscall recvmsg can write.
- r.iov.base = &r.data[0]
- r.iov.len = int32(len(r.data))
- r.hdr.iov = &r.iov
- r.hdr.niov = 1
- r.hdr.desc = &r.desc[0]
- r.hdr.ndesc = int32(len(r.desc))
- n, _, e := syscall.Syscall(syscall.SYS_IMC_RECVMSG, uintptr(r.fd), uintptr(unsafe.Pointer(&r.hdr)), 0)
- if e != 0 {
- return nil, os.NewSyscallError("imc_recvmsg", int(e))
- }
-
- // Make a copy of the data so that the next recvmsg doesn't
- // smash it. The system call did not update r.iov.len. Instead it
- // returned the total byte count as n.
- m := new(msg)
- m.rdata = make([]byte, n)
- copy(m.rdata, r.data[0:])
-
- // Make a copy of the desc too.
- // The system call *did* update r.hdr.ndesc.
- if r.hdr.ndesc > 0 {
- m.rdesc = make([]int32, r.hdr.ndesc)
- for i := range m.rdesc {
- m.rdesc[i] = r.desc[i]
- }
- }
-
- return m, nil
-}
-
-// A msgSender sends messages on a file descriptor.
-type msgSender struct {
- fd int
- hdr msgHdr
- iov iov
-}
-
-func (s *msgSender) send(m *msg) os.Error {
- if len(m.wdata) > 0 {
- s.iov.base = &m.wdata[0]
- }
- s.iov.len = int32(len(m.wdata))
- s.hdr.iov = &s.iov
- s.hdr.niov = 1
- s.hdr.desc = nil
- s.hdr.ndesc = 0
- _, _, e := syscall.Syscall(syscall.SYS_IMC_SENDMSG, uintptr(s.fd), uintptr(unsafe.Pointer(&s.hdr)), 0)
- if e != 0 {
- return os.NewSyscallError("imc_sendmsg", int(e))
- }
- return nil
-}
-
-// Reading from msg.rdata.
-func (m *msg) uint8() uint8 {
- if m.status != OK {
- return 0
- }
- if len(m.rdata) < 1 {
- m.status = ErrMessageTruncated
- return 0
- }
- x := m.rdata[0]
- m.rdata = m.rdata[1:]
- return x
-}
-
-func (m *msg) uint32() uint32 {
- if m.status != OK {
- return 0
- }
- if len(m.rdata) < 4 {
- m.status = ErrMessageTruncated
- return 0
- }
- b := m.rdata[0:4]
- x := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
- m.rdata = m.rdata[4:]
- return x
-}
-
-func (m *msg) uint64() uint64 {
- if m.status != OK {
- return 0
- }
- if len(m.rdata) < 8 {
- m.status = ErrMessageTruncated
- return 0
- }
- b := m.rdata[0:8]
- x := uint64(uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24)
- x |= uint64(uint32(b[4])|uint32(b[5])<<8|uint32(b[6])<<16|uint32(b[7])<<24) << 32
- m.rdata = m.rdata[8:]
- return x
-}
-
-func (m *msg) bytes(n int) []byte {
- if m.status != OK {
- return nil
- }
- if len(m.rdata) < n {
- m.status = ErrMessageTruncated
- return nil
- }
- x := m.rdata[0:n]
- m.rdata = m.rdata[n:]
- return x
-}
-
-// Writing to msg.wdata.
-func (m *msg) grow(n int) []byte {
- i := len(m.wdata)
- if i+n > cap(m.wdata) {
- a := make([]byte, i, (i+n)*2)
- copy(a, m.wdata)
- m.wdata = a
- }
- m.wdata = m.wdata[0 : i+n]
- return m.wdata[i : i+n]
-}
-
-func (m *msg) wuint8(x uint8) { m.grow(1)[0] = x }
-
-func (m *msg) wuint32(x uint32) {
- b := m.grow(4)
- b[0] = byte(x)
- b[1] = byte(x >> 8)
- b[2] = byte(x >> 16)
- b[3] = byte(x >> 24)
-}
-
-func (m *msg) wuint64(x uint64) {
- b := m.grow(8)
- lo := uint32(x)
- b[0] = byte(lo)
- b[1] = byte(lo >> 8)
- b[2] = byte(lo >> 16)
- b[3] = byte(lo >> 24)
- hi := uint32(x >> 32)
- b[4] = byte(hi)
- b[5] = byte(hi >> 8)
- b[6] = byte(hi >> 16)
- b[7] = byte(hi >> 24)
-}
-
-func (m *msg) wbytes(p []byte) { copy(m.grow(len(p)), p) }
-
-func (m *msg) wstring(s string) {
- b := m.grow(len(s))
- for i := range b {
- b[i] = s[i]
- }
-}
-
-// Parsing of RPC header and arguments.
-//
-// The header format is:
-// protocol uint32;
-// requestId uint64;
-// isReq bool;
-// rpcNumber uint32;
-// status uint32; // only for response
-//
-// Then a sequence of values follow, preceded by the length:
-// nvalue uint32;
-//
-// Each value begins with a one-byte type followed by
-// type-specific data.
-//
-// type uint8;
-// 'b': x bool;
-// 'C': len uint32; x [len]byte;
-// 'd': x float64;
-// 'D': len uint32; x [len]float64;
-// 'h': x int; // handle aka file descriptor
-// 'i': x int32;
-// 'I': len uint32; x [len]int32;
-// 's': len uint32; x [len]byte;
-//
-// If this is a request, a sequence of pseudo-values follows,
-// preceded by its length (nvalue uint32).
-//
-// Each pseudo-value is a one-byte type as above,
-// followed by a maximum length (len uint32)
-// for the 'C', 'D', 'I', and 's' types.
-//
-// In the Go msg, we represent each argument by
-// an empty interface containing the type of x in the
-// corresponding case.
-
-// The current protocol number.
-const protocol = 0xc0da0002
-
-func (m *msg) unpackHeader() {
- m.protocol = m.uint32()
- m.requestId = m.uint64()
- m.isReq = m.uint8() != 0
- m.rpcNumber = m.uint32()
- m.gotHeader = m.status == OK // signal that header parsed successfully
- if m.gotHeader && !m.isReq {
- status := Errno(m.uint32())
- m.gotHeader = m.status == OK // still ok?
- if m.gotHeader {
- m.status = status
- }
- }
-}
-
-func (m *msg) packHeader() {
- m.wuint32(m.protocol)
- m.wuint64(m.requestId)
- if m.isReq {
- m.wuint8(1)
- } else {
- m.wuint8(0)
- }
- m.wuint32(m.rpcNumber)
- if !m.isReq {
- m.wuint32(uint32(m.status))
- }
-}
-
-func (m *msg) unpackValues(v []interface{}) {
- for i := range v {
- t := m.uint8()
- m.fmt += string(t)
- switch t {
- default:
- if m.status == OK {
- m.status = ErrBadArgType
- }
- return
- case 'b': // bool[1]
- v[i] = m.uint8() > 0
- case 'C': // char array
- v[i] = m.bytes(int(m.uint32()))
- case 'd': // double
- v[i] = math.Float64frombits(m.uint64())
- case 'D': // double array
- a := make([]float64, int(m.uint32()))
- for j := range a {
- a[j] = math.Float64frombits(m.uint64())
- }
- v[i] = a
- case 'h': // file descriptor (handle)
- if len(m.rdesc) == 0 {
- if m.status == OK {
- m.status = ErrBadArgType
- }
- return
- }
- v[i] = int(m.rdesc[0])
- m.rdesc = m.rdesc[1:]
- case 'i': // int
- v[i] = int32(m.uint32())
- case 'I': // int array
- a := make([]int32, int(m.uint32()))
- for j := range a {
- a[j] = int32(m.uint32())
- }
- v[i] = a
- case 's': // string
- v[i] = string(m.bytes(int(m.uint32())))
- }
- }
-}
-
-func (m *msg) packValues(v []interface{}) {
- for i := range v {
- switch x := v[i].(type) {
- default:
- if m.status == OK {
- m.status = ErrInternalError
- }
- return
- case bool:
- m.wuint8('b')
- if x {
- m.wuint8(1)
- } else {
- m.wuint8(0)
- }
- case []byte:
- m.wuint8('C')
- m.wuint32(uint32(len(x)))
- m.wbytes(x)
- case float64:
- m.wuint8('d')
- m.wuint64(math.Float64bits(x))
- case []float64:
- m.wuint8('D')
- m.wuint32(uint32(len(x)))
- for _, f := range x {
- m.wuint64(math.Float64bits(f))
- }
- case int32:
- m.wuint8('i')
- m.wuint32(uint32(x))
- case []int32:
- m.wuint8('I')
- m.wuint32(uint32(len(x)))
- for _, i := range x {
- m.wuint32(uint32(i))
- }
- case string:
- m.wuint8('s')
- m.wuint32(uint32(len(x)))
- m.wstring(x)
- }
- }
-}
-
-func (m *msg) unpackRequest() {
- m.status = OK
- if m.unpackHeader(); m.status != OK {
- return
- }
- if m.protocol != protocol || !m.isReq {
- m.status = ErrProtocolMismatch
- return
- }
-
- // type-tagged argument values
- m.Arg = make([]interface{}, m.uint32())
- m.unpackValues(m.Arg)
- if m.status != OK {
- return
- }
-
- // type-tagged expected return sizes.
- // fill in zero values for each return value
- // and save sizes.
- m.fmt += ":"
- m.Ret = make([]interface{}, m.uint32())
- m.Size = make([]int, len(m.Ret))
- for i := range m.Ret {
- t := m.uint8()
- m.fmt += string(t)
- switch t {
- default:
- if m.status == OK {
- m.status = ErrBadArgType
- }
- return
- case 'b': // bool[1]
- m.Ret[i] = false
- case 'C': // char array
- m.Size[i] = int(m.uint32())
- m.Ret[i] = []byte(nil)
- case 'd': // double
- m.Ret[i] = float64(0)
- case 'D': // double array
- m.Size[i] = int(m.uint32())
- m.Ret[i] = []float64(nil)
- case 'h': // file descriptor (handle)
- m.Ret[i] = int(-1)
- case 'i': // int
- m.Ret[i] = int32(0)
- case 'I': // int array
- m.Size[i] = int(m.uint32())
- m.Ret[i] = []int32(nil)
- case 's': // string
- m.Size[i] = int(m.uint32())
- m.Ret[i] = ""
- }
- }
-}
-
-func (m *msg) packRequest() {
- m.packHeader()
- m.wuint32(uint32(len(m.Arg)))
- m.packValues(m.Arg)
- m.wuint32(uint32(len(m.Ret)))
- for i, v := range m.Ret {
- switch x := v.(type) {
- case bool:
- m.wuint8('b')
- case []byte:
- m.wuint8('C')
- m.wuint32(uint32(m.Size[i]))
- case float64:
- m.wuint8('d')
- case []float64:
- m.wuint8('D')
- m.wuint32(uint32(m.Size[i]))
- case int:
- m.wuint8('h')
- case int32:
- m.wuint8('i')
- case []int32:
- m.wuint8('I')
- m.wuint32(uint32(m.Size[i]))
- case string:
- m.wuint8('s')
- m.wuint32(uint32(m.Size[i]))
- }
- }
-}
-
-func (m *msg) unpackResponse() {
- m.status = OK
- if m.unpackHeader(); m.status != OK {
- return
- }
- if m.protocol != protocol || m.isReq {
- m.status = ErrProtocolMismatch
- return
- }
-
- // type-tagged return values
- m.fmt = ""
- m.Ret = make([]interface{}, m.uint32())
- m.unpackValues(m.Ret)
-}
-
-func (m *msg) packResponse() {
- m.packHeader()
- m.wuint32(uint32(len(m.Ret)))
- m.packValues(m.Ret)
-}
diff --git a/src/pkg/exp/nacl/srpc/server.go b/src/pkg/exp/nacl/srpc/server.go
deleted file mode 100644
index af2b855f5..000000000
--- a/src/pkg/exp/nacl/srpc/server.go
+++ /dev/null
@@ -1,201 +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.
-
-// SRPC server
-
-package srpc
-
-import (
- "bytes"
- "log"
- "os"
- "syscall"
-)
-
-// TODO(rsc): I'd prefer to make this
-// type Handler func(m *msg) Errno
-// but NaCl can't use closures.
-// The explicit interface is a way to attach state.
-
-// A Handler is a handler for an SRPC method.
-// It reads arguments from arg, checks size for array limits,
-// writes return values to ret, and returns an Errno status code.
-type Handler interface {
- Run(arg, ret []interface{}, size []int) Errno
-}
-
-type method struct {
- name string
- fmt string
- handler Handler
-}
-
-var rpcMethod []method
-
-// BUG(rsc): Add's format string should be replaced by analyzing the
-// type of an arbitrary func passed in an interface{} using reflection.
-
-// Add registers a handler for the named method.
-// Fmt is a Native Client format string, a sequence of
-// alphabetic characters representing the types of the parameter values,
-// a colon, and then a sequence of alphabetic characters
-// representing the types of the returned values.
-// The format characters and corresponding dynamic types are:
-//
-// b bool
-// C []byte
-// d float64
-// D []float64
-// h int // a file descriptor (aka handle)
-// i int32
-// I []int32
-// s string
-//
-func Add(name, fmt string, handler Handler) {
- n := len(rpcMethod)
- if n >= cap(rpcMethod) {
- a := make([]method, n, (n+4)*2)
- for i := range a {
- a[i] = rpcMethod[i]
- }
- rpcMethod = a
- }
- rpcMethod = rpcMethod[0 : n+1]
- rpcMethod[n] = method{name, fmt, handler}
-}
-
-// Serve accepts new SRPC connections from the file descriptor fd
-// and answers RPCs issued on those connections.
-// It closes fd and returns an error if the imc_accept system call fails.
-func Serve(fd int) os.Error {
- defer syscall.Close(fd)
-
- for {
- cfd, _, e := syscall.Syscall(syscall.SYS_IMC_ACCEPT, uintptr(fd), 0, 0)
- if e != 0 {
- return os.NewSyscallError("imc_accept", int(e))
- }
- go serveLoop(int(cfd))
- }
- panic("unreachable")
-}
-
-func serveLoop(fd int) {
- c := make(chan *msg)
- go sendLoop(fd, c)
-
- var r msgReceiver
- r.fd = fd
- for {
- m, err := r.recv()
- if err != nil {
- break
- }
- m.unpackRequest()
- if !m.gotHeader {
- log.Stderrf("cannot unpack header: %s", m.status)
- continue
- }
- // log.Stdoutf("<- %#v", m);
- m.isReq = false // set up for response
- go serveMsg(m, c)
- }
- close(c)
-}
-
-func sendLoop(fd int, c <-chan *msg) {
- var s msgSender
- s.fd = fd
- for m := range c {
- // log.Stdoutf("-> %#v", m);
- m.packResponse()
- s.send(m)
- }
- syscall.Close(fd)
-}
-
-func serveMsg(m *msg, c chan<- *msg) {
- if m.status != OK {
- c <- m
- return
- }
- if m.rpcNumber >= uint32(len(rpcMethod)) {
- m.status = ErrBadRPCNumber
- c <- m
- return
- }
-
- meth := &rpcMethod[m.rpcNumber]
- if meth.fmt != m.fmt {
- switch {
- case len(m.fmt) < len(meth.fmt):
- m.status = ErrTooFewArgs
- case len(m.fmt) > len(meth.fmt):
- m.status = ErrTooManyArgs
- default:
- // There's a type mismatch.
- // It's an in-arg mismatch if the mismatch happens
- // before the colon; otherwise it's an out-arg mismatch.
- m.status = ErrInArgTypeMismatch
- for i := 0; i < len(m.fmt) && m.fmt[i] == meth.fmt[i]; i++ {
- if m.fmt[i] == ':' {
- m.status = ErrOutArgTypeMismatch
- break
- }
- }
- }
- c <- m
- return
- }
-
- m.status = meth.handler.Run(m.Arg, m.Ret, m.Size)
- c <- m
-}
-
-// ServeRuntime serves RPCs issued by the Native Client embedded runtime.
-// This should be called by main once all methods have been registered using Add.
-func ServeRuntime() os.Error {
- // Call getFd to check that we are running embedded.
- if _, err := getFd(); err != nil {
- return err
- }
-
- // We are running embedded.
- // The fd returned by getFd is a red herring.
- // Accept connections on magic fd 3.
- return Serve(3)
-}
-
-// getFd runs the srpc_get_fd system call.
-func getFd() (fd int, err os.Error) {
- r1, _, e := syscall.Syscall(syscall.SYS_SRPC_GET_FD, 0, 0, 0)
- return int(r1), os.NewSyscallError("srpc_get_fd", int(e))
-}
-
-// Enabled returns true if SRPC is enabled in the Native Client runtime.
-func Enabled() bool {
- _, err := getFd()
- return err == nil
-}
-
-// Service #0, service_discovery, returns a list of the other services
-// and their argument formats.
-type serviceDiscovery struct{}
-
-func (serviceDiscovery) Run(arg, ret []interface{}, size []int) Errno {
- var b bytes.Buffer
- for _, m := range rpcMethod {
- b.WriteString(m.name)
- b.WriteByte(':')
- b.WriteString(m.fmt)
- b.WriteByte('\n')
- }
- if b.Len() > size[0] {
- return ErrNoMemory
- }
- ret[0] = b.Bytes()
- return OK
-}
-
-func init() { Add("service_discovery", ":C", serviceDiscovery{}) }
diff --git a/src/pkg/exp/ogle/Makefile b/src/pkg/exp/ogle/Makefile
index b701afd9e..ef65d36c8 100644
--- a/src/pkg/exp/ogle/Makefile
+++ b/src/pkg/exp/ogle/Makefile
@@ -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 ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=exp/ogle
GOFILES=\
@@ -23,7 +23,7 @@ CLEANFILES+=ogle
include ../../../Make.pkg
main.$O: main.go package
- $(QUOTED_GOBIN)/$(GC) -I_obj $<
+ $(GC) -I_obj $<
ogle: main.$O
- $(QUOTED_GOBIN)/$(LD) -L_obj -o $@ $<
+ $(LD) -L_obj -o $@ $<
diff --git a/src/pkg/exp/ogle/cmd.go b/src/pkg/exp/ogle/cmd.go
index 2f087b777..ff137b0f8 100644
--- a/src/pkg/exp/ogle/cmd.go
+++ b/src/pkg/exp/ogle/cmd.go
@@ -18,6 +18,7 @@ import (
"strings"
)
+var fset = token.NewFileSet()
var world *eval.World
var curProc *Process
@@ -43,7 +44,7 @@ func Main() {
}
// Try line as code
- code, err := world.Compile(string(line))
+ code, err := world.Compile(fset, string(line))
if err != nil {
scanner.PrintError(os.Stderr, err)
continue
@@ -63,8 +64,7 @@ func Main() {
func newScanner(input []byte) (*scanner.Scanner, *scanner.ErrorVector) {
sc := new(scanner.Scanner)
ev := new(scanner.ErrorVector)
- sc.Init("input", input, ev, 0)
-
+ sc.Init(fset, "input", input, ev, 0)
return sc, ev
}
@@ -84,8 +84,8 @@ type cmd struct {
}
var cmds = []cmd{
- cmd{"load", cmdLoad},
- cmd{"bt", cmdBt},
+ {"load", cmdLoad},
+ {"bt", cmdBt},
}
// getCmd attempts to parse an input line as a registered command. If
@@ -101,7 +101,7 @@ func getCmd(line []byte) (*cmd, []byte) {
slit := string(lit)
for i := range cmds {
if cmds[i].cmd == slit {
- return &cmds[i], line[pos.Offset+len(lit):]
+ return &cmds[i], line[fset.Position(pos).Offset+len(lit):]
}
}
return nil, nil
diff --git a/src/pkg/exp/ogle/process.go b/src/pkg/exp/ogle/process.go
index 970a7497a..58e830aa6 100644
--- a/src/pkg/exp/ogle/process.go
+++ b/src/pkg/exp/ogle/process.go
@@ -390,17 +390,7 @@ func (p *Process) causesToEvents() ([]Event, os.Error) {
// postEvent appends an event to the posted queue. These events will
// be processed before any currently pending events.
func (p *Process) postEvent(ev Event) {
- n := len(p.posted)
- m := n * 2
- if m == 0 {
- m = 4
- }
- posted := make([]Event, n+1, m)
- for i, p := range p.posted {
- posted[i] = p
- }
- posted[n] = ev
- p.posted = posted
+ p.posted = append(p.posted, ev)
}
// processEvents processes events in the event queue until no events
@@ -452,7 +442,7 @@ func (p *Process) processEvent(ev Event) (EventAction, os.Error) {
action, err = p.goroutineExitHook.handle(ev)
default:
- log.Crashf("Unknown event type %T in queue", p.event)
+ log.Panicf("Unknown event type %T in queue", p.event)
}
if err != nil {
diff --git a/src/pkg/exp/ogle/rtype.go b/src/pkg/exp/ogle/rtype.go
index ce4fdb663..fd77f1bc2 100644
--- a/src/pkg/exp/ogle/rtype.go
+++ b/src/pkg/exp/ogle/rtype.go
@@ -103,7 +103,7 @@ func newManualType(t eval.Type, arch Arch) *remoteType {
rt = &remoteType{t, offset, fieldAlign, mk}
default:
- log.Crashf("cannot manually construct type %T", t)
+ log.Panicf("cannot manually construct type %T", t)
}
typeMap[t] = rt
@@ -142,7 +142,7 @@ func parseRemoteType(a aborter, rs remoteStruct) *remoteType {
if sym != nil {
name = sym.Name
}
- log.Stderrf("%sParsing type at %#x (%s)", prtIndent, addr, name)
+ log.Printf("%sParsing type at %#x (%s)", prtIndent, addr, name)
prtIndent += " "
defer func() { prtIndent = prtIndent[0 : len(prtIndent)-1] }()
}
diff --git a/src/pkg/exp/ogle/vars.go b/src/pkg/exp/ogle/vars.go
index eed60acec..8a3a14791 100644
--- a/src/pkg/exp/ogle/vars.go
+++ b/src/pkg/exp/ogle/vars.go
@@ -140,7 +140,7 @@ func (p *Process) populateWorld(w *eval.World) os.Error {
// Symbol name
name := s.BaseName()
if _, ok := pkg[name]; ok {
- log.Stderrf("Multiple definitions of symbol %s", s.Name)
+ log.Printf("Multiple definitions of symbol %s", s.Name)
continue
}
@@ -191,7 +191,7 @@ func (p *Process) populateWorld(w *eval.World) os.Error {
err := w.DefineConst(pkgName, pkgType, pkgVal)
if err != nil {
- log.Stderrf("while defining package %s: %v", pkgName, err)
+ log.Printf("while defining package %s: %v", pkgName, err)
}
}
diff --git a/src/pkg/exp/spacewar/Makefile b/src/pkg/exp/spacewar/Makefile
deleted file mode 100644
index a27e1f969..000000000
--- a/src/pkg/exp/spacewar/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.
-
-all: 8.out
-
-pdp1.8: pdp1.go
- 8g pdp1.go
-
-spacewar.8: spacewar.go code.go pdp1.8
- 8g spacewar.go code.go
-
-8.out: spacewar.8
- 8l spacewar.8
-
-clean:
- rm -f *.8 8.out
-
diff --git a/src/pkg/exp/spacewar/code.go b/src/pkg/exp/spacewar/code.go
deleted file mode 100644
index 6391b500a..000000000
--- a/src/pkg/exp/spacewar/code.go
+++ /dev/null
@@ -1,7556 +0,0 @@
-// This file contains the assembly language and machine code for
-// Spacewar!, the original PDP-1 video game. It is downloaded from
-// http://spacewar.oversigma.com/sources/sources.zip which has
-// the following notice at http://spacewar.oversigma.com/:
-//
-// Spacewar! was conceived in 1961 by Martin Graetz, Stephen Russell,
-// and Wayne Wiitanen. It was first realized on the PDP-1 in 1962 by
-// Stephen Russell, Peter Samson, Dan Edwards, and Martin Graetz,
-// together with Alan Kotok, Steve Piner, and Robert A Saunders.
-// Spacewar! is in the public domain, but this credit paragraph must
-// accompany all distributed versions of the program.
-//
-// This is the original version! Martin Graetz provided us with a
-// printed version of the source. We typed in in again - it was about
-// 40 pages long - and re-assembled it with a PDP-1 assembler written
-// in PERL. The resulting binary runs on a PDP-1 emulator written as
-// a Java applet. The code is extremely faithful to the original. There
-// are only two changes. 1)The spaceships have been made bigger and
-// 2) The overall timing has been special cased to deal with varying
-// machine speeds.
-//
-// The "a", "s", "d", "f" keys control one of the spaceships. The "k",
-// "l", ";", "'" keys control the other. The controls are spin one
-// way, spin the other, thrust, and fire.
-//
-// Barry Silverman
-// Brian Silverman
-// Vadim Gerasimov
-//
-
-package main
-
-const spacewarCode = `
--/macro fio-dec system, june 1963
- 007652 640500 szm=sza sma-szf
- 007652 650500 spq=szm i
- 007652 761200 clc=cma+cla-opr
-- define senseswitch A
-- repeat 3, A=A+A
-- szs A
-- term
-- define init A,B
-- law B
-- dap A
-- term
-- define index A,B,C
-- idx A
-- sas B
-- jmp C
-- term
-- define listen
-- cla+cli+clf 1-opr-opr
-- szf i 1
-- jmp .-1
-- tyi
-- term
-- define swap
-- rcl 9s
-- rcl 9s
-- term
-- define load A,B
-- lio (B
-- dio A
-- term
-- define setup A,B
-- law i B
-- dac A
-- term
-- define count A,B
-- isp A
-- jmp B
-- term
-- define move A,B
-- lio A
-- dio B
-- term
-- define clear A,B
-- init .+2, A
-- dzm
-- index .-1, (dzm B+1, .-1
-- term
--/spacewar 3.1 24 sep 62 p1. 1
- 000003 3/
- 000003 600061 jmp sbf / ignore seq. break
- 000004 601561 jmp a40
- 000005 601556 jmp a1 / use test word for control, note iot 11 00
--/ interesting and often changed constants
--/symb loc usual value (all instructions are executed,
--/ and may be replaced by jda or jsp)
- 000006 tno,
- 000006 6,
- 000006 710041 law i 41 / number of torps + 1
- 000007 tvl,
- 000007 7,
- 000007 675017 sar 4s / torpedo velocity
- 000010 rlt,
- 000010 10,
- 000010 710020 law i 20 / torpedo reload time
- 000011 tlf,
- 000011 11,
- 000011 710140 law i 140 / torpedo life
- 000012 foo,
- 000012 12,
- 000012 757777 -20000 / fuel supply
- 000013 maa,
- 000013 13,
- 000013 000010 10 / spaceship angular acceleration
- 000014 sac,
- 000014 14,
- 000014 675017 sar 4s / spaceship acceleration
- 000015 str,
- 000015 15,
- 000015 000001 1 / star capture radius
- 000016 me1,
- 000016 16,
- 000016 006000 6000 / collision "radius"
- 000017 me2,
- 000017 17,
- 000017 003000 3000 / above/2
- 000020 ddd,
- 000020 20,
- 000020 777777 777777 / 0 to save space for ddt
- 000021 the,
- 000021 21,
- 000021 675777 sar 9s / amount of torpedo space warpage
- 000022 mhs,
- 000022 22,
- 000022 710010 law i 10 / number of hyperspace shots
- 000023 hd1,
- 000023 23,
- 000023 710040 law i 40 / time in hyperspace before breakout
- 000024 hd2,
- 000024 24,
- 000024 710100 law i 100 / time in hyperspace breakout
- 000025 hd3,
- 000025 25,
- 000025 710200 law i 200 / time to recharge hyperfield generator
- 000026 hr1,
- 000026 26,
- 000026 667777 scl 9s / scale on hyperspatial displacement
- 000027 hr2,
- 000027 27,
- 000027 667017 scl 4s / scale on hyperspatially induced velocity
- 000030 hur,
- 000030 30,
- 000030 040000 40000 / hyperspatial uncertancy
- 000031 ran,
- 000031 31,
- 000031 000000 0 / random number
--/ place to build a private control word routine.
--/ it should leave the control word in the io as follows.
--/ high order 4 bits, rotate ccw, rotate cw, (both mean hyperspace)
--/ fire rocket, and fire torpedo. low order 4 bits, same for
--/ other ship. routine is entered by jsp cwg.
- 000040 40/
- 000040 cwr,
- 000040 601672 jmp mg1 / normally iot 11 control
- 000061 . 20/ / space
--////
--/ routine to flush sequence breaks, if they occur.
- 000061 sbf,
- 000061 720004 tyi
- 000062 220002 lio 2
- 000063 200000 lac 0
- 000064 720054 lsm
- 000065 610001 jmp i 1
-- define xincr X,Y,INS
-- lac Y
-- INS ~ssn
-- dac Y
-- lac X
-- INS ~scn
-- dac X
-- term
-- define yincr X,Y,INS
-- lac Y
-- INS ~scn
-- dac Y
-- lac X
-- -INS+add+sub ~ssn
-- dac X
-- term
--////
-- define dispatch
-- add (a+r
-- dap . 1
-- jmp .
--a,
-- term
-- define dispt A,Y,B
-- repeat 6, B=B+B
-- lio Y
-- dpy-A+B
-- term
-- define scale A,B,C
-- lac A
-- sar B
-- dac C
-- term
-- define diff V,S,QF
-- add i V
-- dac i V
-- xct QF
-- add i S
-- dac i S
-- term
-- define random
-- lac ran
-- rar 1s
-- xor (355760
-- add (355670
-- dac ran
-- term
-- define ranct S,X,C
-- random
-- S
-- X
-- sma
-- cma
-- dac C
-- term
--////
--/sine-cosine subroutine. adams associates
--/calling sequence= number in ac, jda jda sin or jdacos.
--/argument is between q+2 pi, with binary point to right of bit 3.
--/anser has binary point to right of bit 0. time = 2.35 ms.
-- define mult Z
-- jda mpy
-- lac Z
-- term
- 000066 cos,
- 000066 000000 0
- 000067 260142 dap csx
- 000070 202760 lac (62210
- 000071 400066 add cos
- 000072 240074 dac sin
- 000073 600077 jmp .+4
- 000074 sin,
- 000074 000000 0
- 000075 260142 dap csx
- 000076 200074 lac sin
- 000077 640200 spa
- 000100 si1,
- 000100 402761 add (311040
- 000101 422760 sub (62210
- 000102 640400 sma
- 000103 600143 jmp si2
- 000104 402760 add (62210
- 000105 si3,
- 000105 661003 ral 2s
-- mult (242763
-+000106 170171 jda mpy
-+000107 202762 lac ZZ11
- 000110 240074 dac sin
-- mult sin
-+000111 170171 jda mpy
-+000112 200074 lac ZZ12
- 000113 240066 dac cos
-- mult (756103
-+000114 170171 jda mpy
-+000115 202763 lac ZZ13
- 000116 402764 add (121312
-- mult cos
-+000117 170171 jda mpy
-+000120 200066 lac ZZ14
- 000121 402765 add (532511
-- mult cos
-+000122 170171 jda mpy
-+000123 200066 lac ZZ15
- 000124 402766 add (144417
-- mult sin
-+000125 170171 jda mpy
-+000126 200074 lac ZZ16
- 000127 667007 scl 3s
- 000130 240066 dac cos
- 000131 060074 xor sin
- 000132 640400 sma
- 000133 600141 jmp csx-1
- 000134 202767 lac (377777
- 000135 220074 lio sin
- 000136 642000 spi
- 000137 761000 cma
- 000140 600142 jmp csx
- 000141 200066 lac cos
- 000142 csx,
- 000142 600142 jmp .
- 000143 si2,
- 000143 761000 cma
- 000144 402760 add (62210
- 000145 640400 sma
- 000146 600105 jmp si3
- 000147 402760 add (62210
- 000150 640200 spa
- 000151 600154 jmp .+3
- 000152 422760 sub (62210
- 000153 600105 jmp si3
- 000154 422760 sub (62210
- 000155 600100 jmp si1
--////
--/bbn multiply subroutine
--/call.. lac one factor, jdy mpy or imp, lac other factor.
- 000156 imp,
- 000156 000000 0 /returns low 17 bits and sign in ac
- 000157 260160 dap im1
- 000160 im1,
- 000160 100000 xct
- 000161 170171 jda mpy
- 000162 200156 lac imp
- 000163 440160 idx im1
- 000164 672001 rir 1s
- 000165 673777 rcr 9s
- 000166 673777 rcr 9s
- 000167 610160 jmp i im1
- 000170 mp2,
- 000170 000000 0
- 000171 mpy,
- 000171 000000 0 /return 34 bits and 2 signs
- 000172 260200 dap mp1
- 000173 200171 lac mpy
- 000174 640200 spa
- 000175 761000 cma
- 000176 673777 rcr 9s
- 000177 673777 rcr 9s
- 000200 mp1,
- 000200 100000 xct
- 000201 640200 spa
- 000202 761000 cma
- 000203 240170 dac mp2
- 000204 760200 cla
- 000205 540170 mus mp2
-+000206 540170 mus mp2
-+000207 540170 mus mp2
-+000210 540170 mus mp2
-+000211 540170 mus mp2
-+000212 540170 mus mp2
-+000213 540170 mus mp2
-+000214 540170 mus mp2
-+000215 540170 mus mp2
-+000216 540170 mus mp2
-+000217 540170 mus mp2
-+000220 540170 mus mp2
-+000221 540170 mus mp2
-+000222 540170 mus mp2
-+000223 540170 mus mp2
-+000224 540170 mus mp2
-+000225 540170 mus mp2
- 000226 240170 dac mp2
- 000227 100200 xct mp1
- 000230 060171 xor mpy
- 000231 640400 sma
- 000232 600243 jmp mp3
- 000233 200170 lac mp2
- 000234 761000 cma
- 000235 673777 rcr 9s
- 000236 673777 rcr 9s
- 000237 761000 cma
- 000240 673777 rcr 9s
- 000241 673777 rcr 9s
- 000242 240170 dac mp2
- 000243 mp3,
- 000243 440200 idx mp1
- 000244 200170 lac mp2
- 000245 610200 jmp i mp1
--////
--/integer square root
--/input in ac, binary point to right of bit 17, jda sqt
--/answer in ac with binary point between 8 and 9
--/largest input number = 177777
- 000246 sqt,
- 000246 000000 0
- 000247 260260 dap sqx
- 000250 710023 law i 23
- 000251 240304 dac sq1
- 000252 340305 dzm sq2
- 000253 220246 lio sqt
- 000254 340246 dzm sqt
- 000255 sq3,
- 000255 460304 isp sq1
- 000256 600261 jmp .+3
- 000257 200305 lac sq2
- 000260 sqx,
- 000260 600260 jmp .
- 000261 200305 lac sq2
- 000262 665001 sal 1s
- 000263 240305 dac sq2
- 000264 200246 lac sqt
- 000265 663003 rcl 2s
- 000266 650100 sza i
- 000267 600255 jmp sq3
- 000270 240246 dac sqt
- 000271 200305 lac sq2
- 000272 665001 sal 1s
- 000273 402770 add (1
- 000274 420246 sub sqt
- 000275 640500 sma+sza-skip
- 000276 600255 jmp sq3
- 000277 640200 spa
- 000300 761000 cma
- 000301 240246 dac sqt
- 000302 440305 idx sq2
- 000303 600255 jmp sq3
- 000304 sq1,
- 000304 000000 0
- 000305 sq2,
- 000305 000000 0
--////
--/bbn divide subroutine
--/calling sequence.. lac hi-dividend, lio lo-dividend, jda dvd, lac divisor.
--/returns quot in ac, rem in io.
- 000306 idv,
- 000306 000000 0 /integer divide, dividend in ac.
- 000307 260317 dap dv1
- 000310 200306 lac idv
- 000311 677777 scr 9s
- 000312 677377 scr 8s
- 000313 240315 dac dvd
- 000314 600317 jmp dv1
- 000315 dvd,
- 000315 000000 0
- 000316 260317 dap dv1
- 000317 dv1,
- 000317 100000 xct
- 000320 640200 spa
- 000321 761000 cma
- 000322 240306 dac idv
- 000323 200315 lac dvd
- 000324 640400 sma
- 000325 600334 jmp dv2
- 000326 761000 cma
- 000327 673777 rcr 9s
- 000330 673777 rcr 9s
- 000331 761000 cma
- 000332 673777 rcr 9s
- 000333 673777 rcr 9s
- 000334 dv2,
- 000334 420306 sub idv
- 000335 640400 sma
- 000336 600376 jmp dve
- 000337 560306 dis idv
-+000340 560306 dis idv
-+000341 560306 dis idv
-+000342 560306 dis idv
-+000343 560306 dis idv
-+000344 560306 dis idv
-+000345 560306 dis idv
-+000346 560306 dis idv
-+000347 560306 dis idv
-+000350 560306 dis idv
-+000351 560306 dis idv
-+000352 560306 dis idv
-+000353 560306 dis idv
-+000354 560306 dis idv
-+000355 560306 dis idv
-+000356 560306 dis idv
-+000357 560306 dis idv
-+000360 560306 dis idv
- 000361 400306 add idv
- 000362 320306 dio idv
- 000363 764000 cli
- 000364 673001 rcr 1s
- 000365 220315 lio dvd
- 000366 642000 spi
- 000367 761000 cma
- 000370 240315 dac dvd
- 000371 100317 xct dv1
- 000372 060315 xor dvd
- 000373 673777 rcr 9s
- 000374 673777 rcr 9s
- 000375 440317 idx dv1
- 000376 dve,
- 000376 440317 idx dv1
- 000377 200306 lac idv
- 000400 642000 spi
- 000401 761000 cma
- 000402 220315 lio dvd
- 000403 610317 jmp i dv1
--////
--/outline compiler
--/ac=where to compile to, call oc
--/ot=address of outline table
-- define plinst A
-- lac A
-- dac i oc
-- idx oc
-- terminate
-- define comtab A, B
-- plinst A
-- jsp ocs
-- lac B
-- jmp oce
-- terminate
- 000404 ocs,
- 000404 260411 dap ocz /puts in swap
- 000405 330412 dio i oc
- 000406 440412 idx oc
- 000407 330412 dio i oc
- 000410 440412 idx oc
- 000411 ocz,
- 000411 600411 jmp .
- 000412 oc,
- 000412 000000 0
- 000413 260554 dap ocx
- 000414 210554 lac i ocx
- 000415 260434 dap ocg
-- plinst (stf 5
-+000416 202771 lac ZZ17
-+000417 250412 dac i oc
-+000420 440412 idx oc
- 000421 260555 dap ocm
- 000422 440554 idx ocx
- 000423 ock,
-- plinst (lac ~sx1
-+000423 202772 lac ZZ18
-+000424 250412 dac i oc
-+000425 440412 idx oc
-- plinst (lio ~sy1
-+000426 202773 lac ZZ19
-+000427 250412 dac i oc
-+000430 440412 idx oc
- 000431 760006 clf 6
- 000432 ocj,
-- setup ~occ,6
-+000432 710006 law i ZZ210
-+000433 243112 dac ZZ110
- 000434 ocg,
- 000434 220434 lio .
- 000435 och,
- 000435 760200 cla
- 000436 663007 rcl 3s
- 000437 323113 dio ~oci
- 000440 222774 lio (rcl 9s
-- dispatch
-+000441 402775 add (a11
-+000442 260443 dap . 1
-+000443 600443 jmp .
-+000444 a11,
- 000444 760000 opr
- 000445 600557 jmp oc1
- 000446 oco,
- 000446 600602 jmp oc2
- 000447 ocq,
- 000447 600610 jmp oc3
- 000450 ocp,
- 000450 600616 jmp oc4
- 000451 ocr,
- 000451 600624 jmp oc5
- 000452 600632 jmp oc6
--////
-- plinst (szf 5 //code
-+000453 202776 lac ZZ112
-+000454 250412 dac i oc
-+000455 440412 idx oc
- 000456 402777 add (4
- 000457 260556 dap ocn
-- plinst ocn
-+000460 200556 lac ZZ113
-+000461 250412 dac i oc
-+000462 440412 idx oc
-- plinst (dac ~sx1
-+000463 203000 lac ZZ114
-+000464 250412 dac i oc
-+000465 440412 idx oc
-- plinst (dio ~sy1
-+000466 203001 lac ZZ115
-+000467 250412 dac i oc
-+000470 440412 idx oc
-- plinst (jmp sq6
-+000471 203002 lac ZZ116
-+000472 250412 dac i oc
-+000473 440412 idx oc
-- plinst (clf 5
-+000474 203003 lac ZZ117
-+000475 250412 dac i oc
-+000476 440412 idx oc
-- plinst (lac ~scm
-+000477 203004 lac ZZ118
-+000500 250412 dac i oc
-+000501 440412 idx oc
-- plinst (cma
-+000502 203005 lac ZZ119
-+000503 250412 dac i oc
-+000504 440412 idx oc
-- plinst (dac ~scm
-+000505 203006 lac ZZ120
-+000506 250412 dac i oc
-+000507 440412 idx oc
-- plinst (lac ~ssm
-+000510 203007 lac ZZ121
-+000511 250412 dac i oc
-+000512 440412 idx oc
-- plinst (cma
-+000513 203005 lac ZZ122
-+000514 250412 dac i oc
-+000515 440412 idx oc
-- plinst (dac ~ssm
-+000516 203010 lac ZZ123
-+000517 250412 dac i oc
-+000520 440412 idx oc
-- plinst (lac ~csm
-+000521 203011 lac ZZ124
-+000522 250412 dac i oc
-+000523 440412 idx oc
-- plinst (lio ~ssd
-+000524 203012 lac ZZ125
-+000525 250412 dac i oc
-+000526 440412 idx oc
-- plinst (dac ~ssd
-+000527 203013 lac ZZ126
-+000530 250412 dac i oc
-+000531 440412 idx oc
-- plinst (dio ~csm
-+000532 203014 lac ZZ127
-+000533 250412 dac i oc
-+000534 440412 idx oc
-- plinst (lac ~ssc
-+000535 203015 lac ZZ128
-+000536 250412 dac i oc
-+000537 440412 idx oc
-- plinst (lio ~csn
-+000540 203016 lac ZZ129
-+000541 250412 dac i oc
-+000542 440412 idx oc
-- plinst (dac ~csn
-+000543 203017 lac ZZ130
-+000544 250412 dac i oc
-+000545 440412 idx oc
-- plinst (dio ~ssc
-+000546 203020 lac ZZ131
-+000547 250412 dac i oc
-+000550 440412 idx oc
-- plinst ocm
-+000551 200555 lac ZZ132
-+000552 250412 dac i oc
-+000553 440412 idx oc
- 000554 ocx,
- 000554 600554 jmp .
- 000555 ocm,
- 000555 600555 jmp .
- 000556 ocn,
- 000556 600556 jmp .
- 000557 oc1,
-- plinst (add ~ssn
-+000557 203021 lac ZZ133
-+000560 250412 dac i oc
-+000561 440412 idx oc
- 000562 620404 jsp ocs
- 000563 203022 lac (sub ~scn
- 000564 oce,
- 000564 250412 dac i oc
- 000565 440412 idx oc
- 000566 620404 jsp ocs
-- plinst (ioh
-+000567 203023 lac ZZ134
-+000570 250412 dac i oc
-+000571 440412 idx oc
- 000572 203024 lac (dpy-4000
- 000573 ocd,
- 000573 250412 dac i oc
- 000574 440412 idx oc
- 000575 223113 lio ~oci
-- count ~occ, och
-+000576 463112 isp ZZ135
-+000577 600435 jmp ZZ235
- 000600 440434 idx ocg
- 000601 600432 jmp ocj
- 000602 oc2,
-- comtab (add ~scm, (add ~ssm
-- plinst ZZ136
-+000602 203025 lac ZZ137
-+000603 250412 dac i oc
-+000604 440412 idx oc
-+000605 620404 jsp ocs
-+000606 203026 lac ZZ236
-+000607 600564 jmp oce
- 000610 oc3,
-- comtab (add ~ssc, (sub ~csm
-- plinst ZZ138
-+000610 203027 lac ZZ139
-+000611 250412 dac i oc
-+000612 440412 idx oc
-+000613 620404 jsp ocs
-+000614 203030 lac ZZ238
-+000615 600564 jmp oce
- 000616 oc4,
-- comtab (sub ~scm, (sub ~ssm
-- plinst ZZ140
-+000616 203031 lac ZZ141
-+000617 250412 dac i oc
-+000620 440412 idx oc
-+000621 620404 jsp ocs
-+000622 203032 lac ZZ240
-+000623 600564 jmp oce
- 000624 oc5,
-- comtab (add ~csn, (sub ~ssd
-- plinst ZZ142
-+000624 203033 lac ZZ143
-+000625 250412 dac i oc
-+000626 440412 idx oc
-+000627 620404 jsp ocs
-+000630 203034 lac ZZ242
-+000631 600564 jmp oce
- 000632 oc6,
- 000632 640006 szf 6
- 000633 600642 jmp oc9
- 000634 760016 stf 6
-- plinst (dac ~ssa
-+000635 203035 lac ZZ144
-+000636 250412 dac i oc
-+000637 440412 idx oc
- 000640 203036 lac (dio ~ssi
- 000641 600573 jmp ocd
- 000642 oc9,
- 000642 760006 clf 6
-- plinst (lac ~ssa
-+000643 203037 lac ZZ145
-+000644 250412 dac i oc
-+000645 440412 idx oc
- 000646 203040 lac (lio ~ssi
- 000647 600573 jmp ocd
--////
--/ display a star
-- define starp
-- add ~bx
-- swap
-- add ~by
-- swap
-- ioh
-- dpy-4000
-- terminate
-- /star
- 000650 blp,
- 000650 260675 dap blx
- 000651 640060 szs 60
- 000652 600675 jmp blx
-- random
-+000653 200031 lac ran
-+000654 671001 rar 1s
-+000655 063041 xor (355760
-+000656 403042 add (355670
-+000657 240031 dac ran
- 000660 671777 rar 9s
- 000661 023043 and (add 340
- 000662 640200 spa
- 000663 062767 xor (377777
- 000664 243116 dac ~bx
- 000665 200031 lac ran
- 000666 661017 ral 4s
- 000667 023043 and (add 340
- 000670 640200 spa
- 000671 062767 xor (377777
- 000672 243117 dac ~by
- 000673 620676 jsp bpt
- 000674 730000 ioh
- 000675 blx,
- 000675 600675 jmp .
- 000676 bpt,
- 000676 261117 dap bpx
-- random
-+000677 200031 lac ran
-+000700 671001 rar 1s
-+000701 063041 xor (355760
-+000702 403042 add (355670
-+000703 240031 dac ran
- 000704 675777 sar 9s
- 000705 675037 sar 5s
- 000706 640200 spa
- 000707 761000 cma
- 000710 665007 sal 3s
- 000711 403044 add (bds
- 000712 260715 dap bjm
- 000713 764206 cla cli clf 6-opr-opr
- 000714 724007 dpy-4000
- 000715 bjm,
- 000715 600715 jmp .
- 000716 bds,
-- starp
-+000716 403116 add ~bx
-- swap
-+000717 663777 rcl 9s
-+000720 663777 rcl 9s
-+000721 403117 add ~by
-- swap
-+000722 663777 rcl 9s
-+000723 663777 rcl 9s
-+000724 730000 ioh
-+000725 724007 dpy-4000
-- starp
-+000726 403116 add ~bx
-- swap
-+000727 663777 rcl 9s
-+000730 663777 rcl 9s
-+000731 403117 add ~by
-- swap
-+000732 663777 rcl 9s
-+000733 663777 rcl 9s
-+000734 730000 ioh
-+000735 724007 dpy-4000
-- starp
-+000736 403116 add ~bx
-- swap
-+000737 663777 rcl 9s
-+000740 663777 rcl 9s
-+000741 403117 add ~by
-- swap
-+000742 663777 rcl 9s
-+000743 663777 rcl 9s
-+000744 730000 ioh
-+000745 724007 dpy-4000
-- starp
-+000746 403116 add ~bx
-- swap
-+000747 663777 rcl 9s
-+000750 663777 rcl 9s
-+000751 403117 add ~by
-- swap
-+000752 663777 rcl 9s
-+000753 663777 rcl 9s
-+000754 730000 ioh
-+000755 724007 dpy-4000
-- starp
-+000756 403116 add ~bx
-- swap
-+000757 663777 rcl 9s
-+000760 663777 rcl 9s
-+000761 403117 add ~by
-- swap
-+000762 663777 rcl 9s
-+000763 663777 rcl 9s
-+000764 730000 ioh
-+000765 724007 dpy-4000
-- starp
-+000766 403116 add ~bx
-- swap
-+000767 663777 rcl 9s
-+000770 663777 rcl 9s
-+000771 403117 add ~by
-- swap
-+000772 663777 rcl 9s
-+000773 663777 rcl 9s
-+000774 730000 ioh
-+000775 724007 dpy-4000
-- starp
-+000776 403116 add ~bx
-- swap
-+000777 663777 rcl 9s
-+001000 663777 rcl 9s
-+001001 403117 add ~by
-- swap
-+001002 663777 rcl 9s
-+001003 663777 rcl 9s
-+001004 730000 ioh
-+001005 724007 dpy-4000
-- starp
-+001006 403116 add ~bx
-- swap
-+001007 663777 rcl 9s
-+001010 663777 rcl 9s
-+001011 403117 add ~by
-- swap
-+001012 663777 rcl 9s
-+001013 663777 rcl 9s
-+001014 730000 ioh
-+001015 724007 dpy-4000
-- starp
-+001016 403116 add ~bx
-- swap
-+001017 663777 rcl 9s
-+001020 663777 rcl 9s
-+001021 403117 add ~by
-- swap
-+001022 663777 rcl 9s
-+001023 663777 rcl 9s
-+001024 730000 ioh
-+001025 724007 dpy-4000
-- starp
-+001026 403116 add ~bx
-- swap
-+001027 663777 rcl 9s
-+001030 663777 rcl 9s
-+001031 403117 add ~by
-- swap
-+001032 663777 rcl 9s
-+001033 663777 rcl 9s
-+001034 730000 ioh
-+001035 724007 dpy-4000
-- starp
-+001036 403116 add ~bx
-- swap
-+001037 663777 rcl 9s
-+001040 663777 rcl 9s
-+001041 403117 add ~by
-- swap
-+001042 663777 rcl 9s
-+001043 663777 rcl 9s
-+001044 730000 ioh
-+001045 724007 dpy-4000
-- starp
-+001046 403116 add ~bx
-- swap
-+001047 663777 rcl 9s
-+001050 663777 rcl 9s
-+001051 403117 add ~by
-- swap
-+001052 663777 rcl 9s
-+001053 663777 rcl 9s
-+001054 730000 ioh
-+001055 724007 dpy-4000
-- starp
-+001056 403116 add ~bx
-- swap
-+001057 663777 rcl 9s
-+001060 663777 rcl 9s
-+001061 403117 add ~by
-- swap
-+001062 663777 rcl 9s
-+001063 663777 rcl 9s
-+001064 730000 ioh
-+001065 724007 dpy-4000
-- starp
-+001066 403116 add ~bx
-- swap
-+001067 663777 rcl 9s
-+001070 663777 rcl 9s
-+001071 403117 add ~by
-- swap
-+001072 663777 rcl 9s
-+001073 663777 rcl 9s
-+001074 730000 ioh
-+001075 724007 dpy-4000
-- starp
-+001076 403116 add ~bx
-- swap
-+001077 663777 rcl 9s
-+001100 663777 rcl 9s
-+001101 403117 add ~by
-- swap
-+001102 663777 rcl 9s
-+001103 663777 rcl 9s
-+001104 730000 ioh
-+001105 724007 dpy-4000
-- starp
-+001106 403116 add ~bx
-- swap
-+001107 663777 rcl 9s
-+001110 663777 rcl 9s
-+001111 403117 add ~by
-- swap
-+001112 663777 rcl 9s
-+001113 663777 rcl 9s
-+001114 730000 ioh
-+001115 724007 dpy-4000
- 001116 640006 szf 6
- 001117 bpx,
- 001117 601117 jmp .
- 001120 760016 stf 6
- 001121 761000 cma
-- swap
-+001122 663777 rcl 9s
-+001123 663777 rcl 9s
- 001124 761000 cma
-- swap
-+001125 663777 rcl 9s
-+001126 663777 rcl 9s
- 001127 600715 jmp bjm
--////
--/background display . 3/13/62, prs.
-- define dislis J, Q, B
-- repeat 6, B=B+B
-- clf 5
-- lac flo+r
-- dap fpo+r
--fs,
-- dap fin+r
-- dap fyn+r
-- idx fyn+r
--fin,
-- lac /lac x
-- sub fpr /right margin
-- sma
-- jmp fgr+r
-- add (2000
--frr,
-- spq
--fou,
-- jmp fuu+r
--fie,
-- sub (1000
-- sal 8s
--fyn,
-- lio /lio y
-- dpy-i+B
-- stf 5
--fid,
-- idx fyn+r
-- sad (lio Q+2
-- jmp flp+r
-- sad fpo+r
-- jmp fx+r
-- dap fin+r
-- idx fyn+r
-- jmp fin+r
--fgr,
-- add (2000 -20000
-- jmp frr+r
--fuu,
-- szf 5
--fx,
-- jmp flo+r+1 /return
-- idx flo+r
-- idx flo+r
-- sas (Q+2
-- jmp fid+r
-- law J
-- dac flo+r
-- jmp fid+r
--flp,
-- lac (lio J
-- sad fpo+r
-- jmp fx+r
-- dap fin+r
-- law J+1
-- dap fyn+r
-- jmp fin+r
--fpo,
-- lio
--flo,
-- J
-- terminate
--////
-- define background
-- jsp bck
-- termin
- 001130 bck,
- 001130 261134 dap bcx
- 001131 640040 szs 40
- 001132 601134 jmp bcx
- 001133 461441 isp bcc
- 001134 bcx,
- 001134 601134 jmp .
- 001135 710002 law i 2
- 001136 241441 dac bcc
-- dislis 1j,1q,3
-+001137 000006 ZZ398=ZZ398+ZZ398
-+001137 000014 ZZ398=ZZ398+ZZ398
-+001137 000030 ZZ398=ZZ398+ZZ398
-+001137 000060 ZZ398=ZZ398+ZZ398
-+001137 000140 ZZ398=ZZ398+ZZ398
-+001137 000300 ZZ398=ZZ398+ZZ398
-+001137 760005 clf 5
-+001140 201214 lac flo98
-+001141 261213 dap fpo98
-+001142 fs98,
-+001142 261145 dap fin98
-+001143 261156 dap fyn98
-+001144 441156 idx fyn98
-+001145 fin98,
-+001145 200000 lac
-+001146 421443 sub fpr
-+001147 640400 sma
-+001150 601171 jmp fgr98
-+001151 403045 add (2000
-+001152 frr98,
-+001152 650500 spq
-+001153 fou98,
-+001153 601173 jmp fuu98
-+001154 fie98,
-+001154 423046 sub (1000
-+001155 665377 sal 8s
-+001156 fyn98,
-+001156 220000 lio
-+001157 720307 dpy-i+ZZ398
-+001160 760015 stf 5
-+001161 fid98,
-+001161 441156 idx fyn98
-+001162 503047 sad (lio ZZ298+2
-+001163 601204 jmp flp98
-+001164 501213 sad fpo98
-+001165 601174 jmp fx98
-+001166 261145 dap fin98
-+001167 441156 idx fyn98
-+001170 601145 jmp fin98
-+001171 fgr98,
-+001171 403050 add (2000 -20000
-+001172 601152 jmp frr98
-+001173 fuu98,
-+001173 640005 szf 5
-+001174 fx98,
-+001174 601215 jmp flo98+1
-+001175 441214 idx flo98
-+001176 441214 idx flo98
-+001177 523051 sas (ZZ298+2
-+001200 601161 jmp fid98
-+001201 706000 law ZZ198
-+001202 241214 dac flo98
-+001203 601161 jmp fid98
-+001204 flp98,
-+001204 203052 lac (lio ZZ198
-+001205 501213 sad fpo98
-+001206 601174 jmp fx98
-+001207 261145 dap fin98
-+001210 706001 law ZZ198+1
-+001211 261156 dap fyn98
-+001212 601145 jmp fin98
-+001213 fpo98,
-+001213 220000 lio
-+001214 flo98,
-+001214 006000 ZZ198
-- dislis 2j,2q,2
-+001215 000004 ZZ399=ZZ399+ZZ399
-+001215 000010 ZZ399=ZZ399+ZZ399
-+001215 000020 ZZ399=ZZ399+ZZ399
-+001215 000040 ZZ399=ZZ399+ZZ399
-+001215 000100 ZZ399=ZZ399+ZZ399
-+001215 000200 ZZ399=ZZ399+ZZ399
-+001215 760005 clf 5
-+001216 201272 lac flo99
-+001217 261271 dap fpo99
-+001220 fs99,
-+001220 261223 dap fin99
-+001221 261234 dap fyn99
-+001222 441234 idx fyn99
-+001223 fin99,
-+001223 200000 lac
-+001224 421443 sub fpr
-+001225 640400 sma
-+001226 601247 jmp fgr99
-+001227 403045 add (2000
-+001230 frr99,
-+001230 650500 spq
-+001231 fou99,
-+001231 601251 jmp fuu99
-+001232 fie99,
-+001232 423046 sub (1000
-+001233 665377 sal 8s
-+001234 fyn99,
-+001234 220000 lio
-+001235 720207 dpy-i+ZZ399
-+001236 760015 stf 5
-+001237 fid99,
-+001237 441234 idx fyn99
-+001240 503053 sad (lio ZZ299+2
-+001241 601262 jmp flp99
-+001242 501271 sad fpo99
-+001243 601252 jmp fx99
-+001244 261223 dap fin99
-+001245 441234 idx fyn99
-+001246 601223 jmp fin99
-+001247 fgr99,
-+001247 403050 add (2000 -20000
-+001250 601230 jmp frr99
-+001251 fuu99,
-+001251 640005 szf 5
-+001252 fx99,
-+001252 601273 jmp flo99+1
-+001253 441272 idx flo99
-+001254 441272 idx flo99
-+001255 523054 sas (ZZ299+2
-+001256 601237 jmp fid99
-+001257 706022 law ZZ199
-+001260 241272 dac flo99
-+001261 601237 jmp fid99
-+001262 flp99,
-+001262 203055 lac (lio ZZ199
-+001263 501271 sad fpo99
-+001264 601252 jmp fx99
-+001265 261223 dap fin99
-+001266 706023 law ZZ199+1
-+001267 261234 dap fyn99
-+001270 601223 jmp fin99
-+001271 fpo99,
-+001271 220000 lio
-+001272 flo99,
-+001272 006022 ZZ199
-- dislis 3j,3q,1
-+001273 000002 ZZ3100=ZZ3100+ZZ3100
-+001273 000004 ZZ3100=ZZ3100+ZZ3100
-+001273 000010 ZZ3100=ZZ3100+ZZ3100
-+001273 000020 ZZ3100=ZZ3100+ZZ3100
-+001273 000040 ZZ3100=ZZ3100+ZZ3100
-+001273 000100 ZZ3100=ZZ3100+ZZ3100
-+001273 760005 clf 5
-+001274 201350 lac flo100
-+001275 261347 dap fpo100
-+001276 fs100,
-+001276 261301 dap fin100
-+001277 261312 dap fyn100
-+001300 441312 idx fyn100
-+001301 fin100,
-+001301 200000 lac
-+001302 421443 sub fpr
-+001303 640400 sma
-+001304 601325 jmp fgr100
-+001305 403045 add (2000
-+001306 frr100,
-+001306 650500 spq
-+001307 fou100,
-+001307 601327 jmp fuu100
-+001310 fie100,
-+001310 423046 sub (1000
-+001311 665377 sal 8s
-+001312 fyn100,
-+001312 220000 lio
-+001313 720107 dpy-i+ZZ3100
-+001314 760015 stf 5
-+001315 fid100,
-+001315 441312 idx fyn100
-+001316 503056 sad (lio ZZ2100+2
-+001317 601340 jmp flp100
-+001320 501347 sad fpo100
-+001321 601330 jmp fx100
-+001322 261301 dap fin100
-+001323 441312 idx fyn100
-+001324 601301 jmp fin100
-+001325 fgr100,
-+001325 403050 add (2000 -20000
-+001326 601306 jmp frr100
-+001327 fuu100,
-+001327 640005 szf 5
-+001330 fx100,
-+001330 601351 jmp flo100+1
-+001331 441350 idx flo100
-+001332 441350 idx flo100
-+001333 523057 sas (ZZ2100+2
-+001334 601315 jmp fid100
-+001335 706044 law ZZ1100
-+001336 241350 dac flo100
-+001337 601315 jmp fid100
-+001340 flp100,
-+001340 203060 lac (lio ZZ1100
-+001341 501347 sad fpo100
-+001342 601330 jmp fx100
-+001343 261301 dap fin100
-+001344 706045 law ZZ1100+1
-+001345 261312 dap fyn100
-+001346 601301 jmp fin100
-+001347 fpo100,
-+001347 220000 lio
-+001350 flo100,
-+001350 006044 ZZ1100
-- dislis 4j,4q,0
-+001351 000000 ZZ3101=ZZ3101+ZZ3101
-+001351 000000 ZZ3101=ZZ3101+ZZ3101
-+001351 000000 ZZ3101=ZZ3101+ZZ3101
-+001351 000000 ZZ3101=ZZ3101+ZZ3101
-+001351 000000 ZZ3101=ZZ3101+ZZ3101
-+001351 000000 ZZ3101=ZZ3101+ZZ3101
-+001351 760005 clf 5
-+001352 201426 lac flo101
-+001353 261425 dap fpo101
-+001354 fs101,
-+001354 261357 dap fin101
-+001355 261370 dap fyn101
-+001356 441370 idx fyn101
-+001357 fin101,
-+001357 200000 lac
-+001360 421443 sub fpr
-+001361 640400 sma
-+001362 601403 jmp fgr101
-+001363 403045 add (2000
-+001364 frr101,
-+001364 650500 spq
-+001365 fou101,
-+001365 601405 jmp fuu101
-+001366 fie101,
-+001366 423046 sub (1000
-+001367 665377 sal 8s
-+001370 fyn101,
-+001370 220000 lio
-+001371 720007 dpy-i+ZZ3101
-+001372 760015 stf 5
-+001373 fid101,
-+001373 441370 idx fyn101
-+001374 503061 sad (lio ZZ2101+2
-+001375 601416 jmp flp101
-+001376 501425 sad fpo101
-+001377 601406 jmp fx101
-+001400 261357 dap fin101
-+001401 441370 idx fyn101
-+001402 601357 jmp fin101
-+001403 fgr101,
-+001403 403050 add (2000 -20000
-+001404 601364 jmp frr101
-+001405 fuu101,
-+001405 640005 szf 5
-+001406 fx101,
-+001406 601427 jmp flo101+1
-+001407 441426 idx flo101
-+001410 441426 idx flo101
-+001411 523062 sas (ZZ2101+2
-+001412 601373 jmp fid101
-+001413 706306 law ZZ1101
-+001414 241426 dac flo101
-+001415 601373 jmp fid101
-+001416 flp101,
-+001416 203063 lac (lio ZZ1101
-+001417 501425 sad fpo101
-+001420 601406 jmp fx101
-+001421 261357 dap fin101
-+001422 706307 law ZZ1101+1
-+001423 261370 dap fyn101
-+001424 601357 jmp fin101
-+001425 fpo101,
-+001425 220000 lio
-+001426 flo101,
-+001426 006306 ZZ1101
- 001427 461442 isp bkc
- 001430 601134 jmp bcx
- 001431 710020 law i 20
- 001432 241442 dac bkc
- 001433 710001 law i 1
- 001434 401443 add fpr
- 001435 640200 spa
- 001436 403064 add (20000
- 001437 241443 dac fpr
- 001440 601134 jmp bcx
- 001441 bcc,
- 001441 000000 0
- 001442 bkc,
- 001442 000000 0
- 001443 fpr,
- 001443 010000 10000
--////
--/spacewar 3.1 24 sep 62 pt. 2
--/main control for spaceships
- 001444 000030 nob=30 /total number of colliding objects
- 001444 ml0,
-- load ~mtc, -4000 /delay for loop
-+001444 223065 lio (ZZ2102
-+001445 323120 dio ZZ1102
-- init ml1, mtb /loc of calc routines
-+001446 703365 law ZZ2103
-+001447 261703 dap ZZ1103
- 001450 403066 add (nob
- 001451 261737 dap mx1 /x
- 001452 003415 nx1=mtb nob
- 001452 403066 add (nob
- 001453 261747 dap my1 /y
- 001454 003445 ny1=nx1 nob
- 001454 403066 add (nob
- 001455 261772 dap ma1 / count for length of explosion or torp
- 001456 003475 na1=ny1 nob
- 001456 403066 add (nob
- 001457 262006 dap mb1 / count of instructions taken by calc routine
- 001460 003525 nb1=na1 nob
- 001460 403066 add (nob
- 001461 243121 dac ~mdx / dx
- 001462 003555 ndx=nb1 nob
- 001462 403066 add (nob
- 001463 243122 dac ~mdy / dy
- 001464 003605 ndy=ndx nob
- 001464 403066 add (nob
- 001465 262327 dap mom /angular velocity
- 001466 003635 nom=ndy nob
- 001466 403067 add (2
- 001467 262343 dap mth / angle
- 001470 003637 nth=nom 2
- 001470 403067 add (2
- 001471 243123 dac ~mfu /fuel
- 001472 003641 nfu=nth 2
- 001472 403067 add (2
- 001473 243124 dac ~mtr / no torps remaining
- 001474 003643 ntr=nfu 2
- 001474 403067 add (2
- 001475 261732 dap mot / outline of spaceship
- 001476 003645 not=ntr 2
- 001476 403067 add (2
- 001477 262577 dap mco / old control word
- 001500 003647 nco=not 2
- 001500 403067 add (2
- 001501 243125 dac ~mh1
- 001502 003651 nh1=nco 2
- 001502 403067 add (2
- 001503 243126 dac ~mh2
- 001504 003653 nh2=nh1 2
- 001504 403067 add (2
- 001505 243127 dac ~mh3
- 001506 003655 nh3=nh2 2
- 001506 403067 add (2
- 001507 243130 dac ~mh4
- 001510 003657 nh4=nh3 2
- 001510 003661 nnn=nh4 2
--////
- 001510 702310 law ss1
- 001511 063365 xor mtb
- 001512 640100 sza
- 001513 601534 jmp mdn
- 001514 702314 law ss2
- 001515 063366 xor mtb 1
- 001516 640100 sza
- 001517 601534 jmp mdn
- 001520 700001 law 1 / test if both ships out of torps
- 001521 403643 add ntr
- 001522 640200 spa
- 001523 601530 jmp md1
- 001524 700001 law 1
- 001525 403644 add ntr 1
- 001526 650200 spa i
- 001527 601534 jmp mdn
- 001530 md1,
- 001530 100011 xct tlf / restart delay is 2x torpedo life
- 001531 665001 sal 1s
- 001532 243131 dac ~ntd
- 001533 601703 jmp ml1
- 001534 mdn,
-- count ~ntd,ml1
-+001534 463131 isp ZZ1104
-+001535 601703 jmp ZZ2104
- 001536 760011 stf 1
- 001537 760012 stf 2
- 001540 702310 law ss1
- 001541 063365 xor mtb
- 001542 640100 sza
- 001543 760001 clf 1
- 001544 650100 sza i
- 001545 443132 idx ~1sc
- 001546 702314 law ss2
- 001547 063366 xor mtb 1
- 001550 640100 sza
- 001551 760002 clf 2
- 001552 650100 sza i
- 001553 443133 idx ~2sc
- 001554 760002 clf 2
- 001555 601564 jmp a
--////
- 001556 a1,
- 001556 701676 law mg2 / test word control
- 001557 243134 dac ~cwg
- 001560 601564 jmp a
- 001561 a40,
- 001561 700040 law cwr / here from start at 4
- 001562 243134 dac ~cwg
- 001563 601613 jmp a6
- 001564 a,
- 001564 203135 lac ~gct
- 001565 640400 sma
- 001566 601576 jmp a5
-- count ~gct, a5
-+001567 463135 isp ZZ1105
-+001570 601576 jmp ZZ2105
- 001571 203132 lac ~1sc
- 001572 523133 sas ~2sc
- 001573 601602 jmp a4
- 001574 710001 law i 1
- 001575 243135 dac ~gct
- 001576 a5,
- 001576 762200 lat
- 001577 023070 and (40
- 001600 650100 sza i
- 001601 601621 jmp a2
- 001602 a4,
- 001602 203132 lac ~1sc
- 001603 223133 lio ~2sc
- 001604 760400 hlt
- 001605 762200 lat
- 001606 023070 and (40
- 001607 640100 sza
- 001610 601621 jmp a2
- 001611 343132 dzm ~1sc
- 001612 343133 dzm ~2sc
- 001613 a6,
- 001613 762200 lat
- 001614 671077 rar 6s
- 001615 023071 and (37
- 001616 640100 sza
- 001617 761000 cma
- 001620 243135 dac ~gct
- 001621 a2,
-- clear mtb, nnn-1 / clear out all tables
-- init .+2, ZZ1106
-+001621 703365 law ZZ2107
-+001622 261623 dap ZZ1107
-+001623 340000 dzm
-- index .-1, (dzm ZZ2106+1, .-1
-+001624 441623 idx ZZ1108
-+001625 523072 sas ZZ2108
-+001626 601623 jmp ZZ3108
- 001627 702310 law ss1
- 001630 243365 dac mtb
- 001631 702314 law ss2
- 001632 243366 dac mtb 1
- 001633 203073 lac (200000
- 001634 243415 dac nx1
- 001635 243445 dac ny1
- 001636 761000 cma
- 001637 243416 dac nx1 1
- 001640 243446 dac ny1 1
- 001641 203074 lac (144420
- 001642 243637 dac nth
--////
- 001643 703661 law nnn / start of outline problem
- 001644 243645 dac not
- 001645 220020 lio ddd
- 001646 652000 spi i
- 001647 601652 jmp a3
- 001650 170412 jda oc
- 001651 002735 ot1
- 001652 a3,
- 001652 243646 dac not 1
- 001653 170412 jda oc
- 001654 002746 ot2
- 001655 100006 xct tno
- 001656 243643 dac ntr
- 001657 243644 dac ntr 1
- 001660 200012 lac foo
- 001661 243641 dac nfu
- 001662 243642 dac nfu 1
- 001663 702000 law 2000
- 001664 243525 dac nb1
- 001665 243526 dac nb1 1
- 001666 100022 xct mhs
- 001667 243653 dac nh2
- 001670 243654 dac nh2 1
- 001671 601444 jmp ml0
--/ control word get routines
- 001672 mg1,
- 001672 261675 dap mg3
- 001673 764000 cli
- 001674 720011 iot 11
- 001675 mg3,
- 001675 601675 jmp .
- 001676 mg2,
- 001676 261702 dap mg4
- 001677 762200 lat
-- swap
-+001700 663777 rcl 9s
-+001701 663777 rcl 9s
- 001702 mg4,
- 001702 601702 jmp .
--////
- 001703 ml1,
- 001703 201703 lac . / 1st control word
- 001704 650100 sza i / zero if not active
- 001705 602011 jmp mq1 / not active
-- swap
-+001706 663777 rcl 9s
-+001707 663777 rcl 9s
- 001710 443136 idx ~moc
- 001711 642000 spi
- 001712 602003 jmp mq4
- 001713 700001 law 1
- 001714 401703 add ml1
- 001715 261734 dap ml2
- 001716 700001 law 1
- 001717 401737 add mx1
- 001720 261740 dap mx2
- 001721 700001 law 1
- 001722 401747 add my1
- 001723 261750 dap my2
- 001724 700001 law 1
- 001725 401772 add ma1
- 001726 261773 dap ma2
- 001727 700001 law 1
- 001730 402006 add mb1
- 001731 261766 dap mb2
- 001732 mot,
- 001732 201732 lac .
- 001733 262530 dap sp5
- 001734 ml2,
- 001734 201734 lac . / 2nd control word
- 001735 650500 spq / can it collide?
- 001736 601774 jmp mq2 / no
- 001737 mx1,
- 001737 201737 lac . / calc if collision
- 001740 mx2,
- 001740 421740 sub . / delta x
- 001741 640200 spa / take abs value
- 001742 761000 cma
- 001743 243137 dac ~mt1
- 001744 420016 sub me1 / < epsilon ?
- 001745 640400 sma
- 001746 601774 jmp mq2 / no
- 001747 my1,
- 001747 201747 lac .
- 001750 my2,
- 001750 421750 sub .
- 001751 640200 spa
- 001752 761000 cma
- 001753 420016 sub me1 / < epsilon ?
- 001754 640400 sma
- 001755 601774 jmp mq2 / no
- 001756 403137 add ~mt1
- 001757 420017 sub me2
- 001760 640400 sma
- 001761 601774 jmp mq2
- 001762 203103 lac (mex 400000 / yes, explode
- 001763 251703 dac i ml1 / replace calc routine with explosion
- 001764 251734 dac i ml2
- 001765 212006 lac i mb1 / duration of explosion
- 001766 mb2,
- 001766 401766 add .
- 001767 761000 cma
- 001770 675377 sar 8s
- 001771 402770 add (1
- 001772 ma1,
- 001772 241772 dac .
- 001773 ma2,
- 001773 241773 dac .
- 001774 mq2,
- 001774 441740 idx mx2 / end of comparion loop
- 001775 441750 idx my2
- 001776 441773 idx ma2
- 001777 441766 idx mb2
-- index ml2, (lac mtb nob, ml2
-+002000 441734 idx ZZ1111
-+002001 523075 sas ZZ2111
-+002002 601734 jmp ZZ3111
--////
- 002003 mq4,
- 002003 211703 lac i ml1 / routine for calculating spaceship
- 002004 262005 dap . 1 / or other object and displaying it
- 002005 622005 jsp .
- 002006 mb1,
- 002006 202006 lac . / alter count of number of instructions
- 002007 403120 add ~mtc
- 002010 243120 dac ~mtc
- 002011 mq1,
- 002011 441737 idx mx1 / end of comparison and display loop
- 002012 441747 idx my1
- 002013 441772 idx ma1
- 002014 442006 idx mb1
- 002015 443121 idx ~mdx
- 002016 443122 idx ~mdy
- 002017 442327 idx mom
- 002020 442343 idx mth
- 002021 443140 idx ~mas
- 002022 443123 idx ~mfu
- 002023 443124 idx ~mtr
- 002024 441732 idx mot
- 002025 442577 idx mco
- 002026 443125 idx ~mh1
- 002027 443126 idx ~mh2
- 002030 443127 idx ~mh3
- 002031 443130 idx ~mh4
-- index ml1, (lac mtb nob-1, ml1
-+002032 441703 idx ZZ1112
-+002033 523076 sas ZZ2112
-+002034 601703 jmp ZZ3112
- 002035 211703 lac i ml1 / display and compute last point
- 002036 650100 sza i / if active
- 002037 602045 jmp mq3
- 002040 262041 dap . 1
- 002041 622041 jsp .
- 002042 212006 lac i mb1
- 002043 403120 add ~mtc
- 002044 243120 dac ~mtc
- 002045 mq3,
-- background / display stars of the heavens
-+002045 621130 jsp bck
- 002046 620650 jsp blp / display massive star
-- count ~mtc, . / use the rest of time of main loop
-+002047 463120 isp ZZ1114
-+002050 602047 jmp ZZ2114
- 002051 601444 jmp ml0 / repeat whole works
--////
--/ misc calculation routines
-- / explosion
- 002052 mex,
- 002052 262133 dap mxr
- 002053 760200 cla
-- diff ~mdx, mx1, (sar 3s
-+002054 413121 add i ZZ1115
-+002055 253121 dac i ZZ1115
-+002056 103077 xct ZZ3115
-+002057 411737 add i ZZ2115
-+002060 251737 dac i ZZ2115
- 002061 760200 cla
-- diff ~mdy, my1, (sar 3s
-+002062 413122 add i ZZ1116
-+002063 253122 dac i ZZ1116
-+002064 103077 xct ZZ3116
-+002065 411747 add i ZZ2116
-+002066 251747 dac i ZZ2116
- 002067 702134 law ms2
- 002070 262117 dap msh
- 002071 212006 lac i mb1 / time involved
- 002072 765000 cma cli-opr
- 002073 675007 sar 3s
- 002074 243141 dac ~mxc
- 002075 ms1,
- 002075 423100 sub (140
- 002076 640400 sma
- 002077 442117 idx msh
- 002100 mz1,
-- random
-+002100 200031 lac ran
-+002101 671001 rar 1s
-+002102 063041 xor (355760
-+002103 403042 add (355670
-+002104 240031 dac ran
- 002105 023101 and (777
- 002106 043102 ior (scl
- 002107 242120 dac mi1
-- random
-+002110 200031 lac ran
-+002111 671001 rar 1s
-+002112 063041 xor (355760
-+002113 403042 add (355670
-+002114 240031 dac ran
- 002115 677777 scr 9s
- 002116 676777 sir 9s
- 002117 msh,
- 002117 102117 xct .
- 002120 mi1,
- 002120 760400 hlt
- 002121 411747 add i my1
-- swap
-+002122 663777 rcl 9s
-+002123 663777 rcl 9s
- 002124 411737 add i mx1
- 002125 720307 dpy-i 300
-- count ~mxc, mz1
-+002126 463141 isp ZZ1120
-+002127 602100 jmp ZZ2120
-- count i ma1, mxr
-+002130 471772 isp ZZ1121
-+002131 602133 jmp ZZ2121
- 002132 351703 dzm i ml1
- 002133 mxr,
- 002133 602133 jmp .
- 002134 ms2,
- 002134 677001 scr 1s
- 002135 677007 scr 3s
--/ torpedo calc routine
- 002136 tcr,
- 002136 262167 dap trc
-- count i ma1, tc1
-+002137 471772 isp ZZ1122
-+002140 602146 jmp ZZ2122
- 002141 203103 lac (mex 400000
- 002142 251703 dac i ml1
- 002143 710002 law i 2
- 002144 251772 dac i ma1
- 002145 602167 jmp trc
- 002146 tc1,
- 002146 211737 lac i mx1
- 002147 675777 sar 9s
- 002150 100021 xct the
-- diff ~mdy, my1, (sar 3s
-+002151 413122 add i ZZ1123
-+002152 253122 dac i ZZ1123
-+002153 103077 xct ZZ3123
-+002154 411747 add i ZZ2123
-+002155 251747 dac i ZZ2123
- 002156 675777 sar 9s
- 002157 100021 xct the
-- diff ~mdx, mx1, (sar 3s
-+002160 413121 add i ZZ1124
-+002161 253121 dac i ZZ1124
-+002162 103077 xct ZZ3124
-+002163 411737 add i ZZ2124
-+002164 251737 dac i ZZ2124
-- dispt i, i my1, 1
-+002165 000002 ZZ3125=ZZ3125+ZZ3125
-+002165 000004 ZZ3125=ZZ3125+ZZ3125
-+002165 000010 ZZ3125=ZZ3125+ZZ3125
-+002165 000020 ZZ3125=ZZ3125+ZZ3125
-+002165 000040 ZZ3125=ZZ3125+ZZ3125
-+002165 000100 ZZ3125=ZZ3125+ZZ3125
-+002165 231747 lio ZZ2125
-+002166 720107 dpy-ZZ1125+ZZ3125
- 002167 trc,
- 002167 602167 jmp .
--////
--/ hyperspace routines
--/ this routine handles a non-colliding ship invisibly
--/ in hyperspace
- 002170 hp1,
- 002170 262245 dap hp2
-- count i ma1, hp2
-+002171 471772 isp ZZ1126
-+002172 602245 jmp ZZ2126
- 002173 702246 law hp3 / next step
- 002174 251703 dac i ml1
- 002175 700007 law 7
- 002176 252006 dac i mb1
-- random
-+002177 200031 lac ran
-+002200 671001 rar 1s
-+002201 063041 xor (355760
-+002202 403042 add (355670
-+002203 240031 dac ran
- 002204 677777 scr 9s
- 002205 676777 sir 9s
- 002206 100026 xct hr1
- 002207 411737 add i mx1
- 002210 251737 dac i mx1
-- swap
-+002211 663777 rcl 9s
-+002212 663777 rcl 9s
- 002213 411747 add i my1
- 002214 251747 dac i my1
-- random
-+002215 200031 lac ran
-+002216 671001 rar 1s
-+002217 063041 xor (355760
-+002220 403042 add (355670
-+002221 240031 dac ran
- 002222 677777 scr 9s
- 002223 676777 sir 9s
- 002224 100027 xct hr2
- 002225 253122 dac i ~mdy
- 002226 333121 dio i ~mdx
-- setup ~hpt,3
-+002227 710003 law i ZZ2130
-+002230 243142 dac ZZ1130
- 002231 200031 lac ran
- 002232 252343 dac i mth
- 002233 hp4,
- 002233 212343 lac i mth
- 002234 640400 sma
- 002235 422761 sub (311040
- 002236 640200 spa
- 002237 402761 add (311040
- 002240 252343 dac i mth
-- count ~hpt,hp4
-+002241 463142 isp ZZ1131
-+002242 602233 jmp ZZ2131
- 002243 100024 xct hd2
- 002244 251772 dac i ma1
- 002245 hp2,
- 002245 602245 jmp .
--/ this routine handles a ship breaking out of
--/ hyperspace
- 002246 hp3,
- 002246 262307 dap hp5
-- count i ma1,hp6
-+002247 471772 isp ZZ1132
-+002250 602304 jmp ZZ2132
- 002251 213125 lac i ~mh1
- 002252 251703 dac i ml1
- 002253 702000 law 2000
- 002254 252006 dac i mb1
-- count i ~mh2,hp7
-+002255 473126 isp ZZ1133
-+002256 602260 jmp ZZ2133
- 002257 353126 dzm i ~mh2
--////
- 002260 hp7,
- 002260 100025 xct hd3
- 002261 253127 dac i ~mh3
- 002262 213130 lac i ~mh4
- 002263 400030 add hur
- 002264 253130 dac i ~mh4
-- random
-+002265 200031 lac ran
-+002266 671001 rar 1s
-+002267 063041 xor (355760
-+002270 403042 add (355670
-+002271 240031 dac ran
- 002272 043104 ior (400000
- 002273 413130 add i ~mh4
- 002274 640200 spa
- 002275 602307 jmp hp5
- 002276 203103 lac (mex 400000
- 002277 251703 dac i ml1
- 002300 710010 law i 10
- 002301 251772 dac i ma1
- 002302 702000 law 2000
- 002303 252006 dac i mb1
- 002304 hp6,
- 002304 211737 lac i mx1
-- dispt i, i my1, 2
-+002305 000004 ZZ3135=ZZ3135+ZZ3135
-+002305 000010 ZZ3135=ZZ3135+ZZ3135
-+002305 000020 ZZ3135=ZZ3135+ZZ3135
-+002305 000040 ZZ3135=ZZ3135+ZZ3135
-+002305 000100 ZZ3135=ZZ3135+ZZ3135
-+002305 000200 ZZ3135=ZZ3135+ZZ3135
-+002305 231747 lio ZZ2135
-+002306 720207 dpy-ZZ1135+ZZ3135
- 002307 hp5,
- 002307 602307 jmp .
--////
--/ spaceship calc
- 002310 ss1,
- 002310 262713 dap srt / first spaceship
- 002311 633134 jsp i ~cwg
- 002312 323143 dio ~scw
- 002313 602320 jmp sr0
- 002314 ss2,
- 002314 262713 dap srt
- 002315 633134 jsp i ~cwg
- 002316 672017 rir 4s
- 002317 323143 dio ~scw
- 002320 sr0,
- 002320 sc1,
- 002320 223143 lio ~scw /control word
- 002321 760206 clf 6 cla-opr /update angle
- 002322 642000 spi
- 002323 400013 add maa
- 002324 662001 ril 1s
- 002325 642000 spi
- 002326 420013 sub maa
- 002327 mom,
- 002327 402327 add .
- 002330 252327 dac i mom
- 002331 640010 szs 10
- 002332 602335 jmp sr8
- 002333 352327 dzm i mom
- 002334 661177 ral 7s
- 002335 sr8,
- 002335 662001 ril 1s
- 002336 642000 spi
- 002337 760016 stf 6
- 002340 233123 lio i ~mfu
- 002341 652000 spi i
- 002342 760006 clf 6
- 002343 mth,
- 002343 402343 add .
- 002344 640400 sma
- 002345 422761 sub (311040
- 002346 640200 spa
- 002347 402761 add (311040
- 002350 252343 dac i mth
- 002351 170074 jda sin
- 002352 243144 dac ~sn
- 002353 343116 dzm ~bx
- 002354 343117 dzm ~by
- 002355 640060 szs 60
- 002356 602430 jmp bsg
- 002357 211737 lac i mx1
- 002360 675777 sar 9s
- 002361 675003 sar 2s
- 002362 243145 dac ~t1
- 002363 170156 jda imp
- 002364 203145 lac ~t1
- 002365 243146 dac ~t2
- 002366 211747 lac i my1
--////
- 002367 675777 sar 9s
- 002370 675003 sar 2s
- 002371 243145 dac ~t1
- 002372 170156 jda imp
- 002373 203145 lac ~t1
- 002374 403146 add ~t2
- 002375 420015 sub str
- 002376 650500 sma i sza-skp
- 002377 602714 jmp poh
- 002400 400015 add str
- 002401 243145 dac ~t1
- 002402 170246 jda sqt
- 002403 675777 sar 9s
- 002404 170171 jda mpy
- 002405 203145 lac ~t1
- 002406 677003 scr 2s
- 002407 650020 szs i 20 / switch 2 for light star
- 002410 677003 scr 2s
- 002411 640100 sza
- 002412 602430 jmp bsg
- 002413 323145 dio ~t1
- 002414 211737 lac i mx1
- 002415 761000 cma
- 002416 170306 jda idv
- 002417 203145 lac ~t1
- 002420 760000 opr
- 002421 243116 dac ~bx
- 002422 211747 lac i my1
- 002423 761000 cma
- 002424 170306 jda idv
- 002425 203145 lac ~t1
- 002426 760000 opr
- 002427 243117 dac ~by
- 002430 bsg,
- 002430 760200 cla
- 002431 513123 sad i ~mfu
- 002432 760006 clf 6
- 002433 212343 lac i mth
- 002434 170066 jda cos
- 002435 243147 dac ~cs
- 002436 675777 sar 9s
- 002437 100014 xct sac
- 002440 650006 szf i 6
- 002441 760200 cla
- 002442 403117 add ~by
-- diff ~mdy, my1, (sar 3s
-+002443 413122 add i ZZ1136
-+002444 253122 dac i ZZ1136
-+002445 103077 xct ZZ3136
-+002446 411747 add i ZZ2136
-+002447 251747 dac i ZZ2136
- 002450 203144 lac ~sn
- 002451 675777 sar 9s
- 002452 100014 xct sac
- 002453 761000 cma
- 002454 650006 szf i 6
- 002455 760200 cla
- 002456 403116 add ~bx
-- diff ~mdx, mx1, (sar 3s
-+002457 413121 add i ZZ1137
-+002460 253121 dac i ZZ1137
-+002461 103077 xct ZZ3137
-+002462 411737 add i ZZ2137
-+002463 251737 dac i ZZ2137
- 002464 sp1,
-- scale ~sn, 5s, ~ssn
-+002464 203144 lac ZZ1138
-+002465 675037 sar ZZ2138
-+002466 243150 dac ZZ3138
- 002467 sp2,
-- scale ~cs, 5s, ~scn
-+002467 203147 lac ZZ1139
-+002470 675037 sar ZZ2139
-+002471 243114 dac ZZ3139
- 002472 211737 lac i mx1
--////
- 002473 423150 sub ~ssn
- 002474 243151 dac ~sx1
- 002475 423150 sub ~ssn
- 002476 243152 dac ~stx
- 002477 211747 lac i my1
- 002500 403114 add ~scn
- 002501 243153 dac ~sy1
- 002502 403114 add ~scn
- 002503 243154 dac ~sty
--/ Modified for Smaller Laptop screens - BDS
--// scale ~sn, 9s, ~ssn
--// scale ~cs, 9s, ~scn
-- scale ~sn, 8s, ~ssn
-+002504 203144 lac ZZ1140
-+002505 675377 sar ZZ2140
-+002506 243150 dac ZZ3140
-- scale ~cs, 8s, ~scn
-+002507 203147 lac ZZ1141
-+002510 675377 sar ZZ2141
-+002511 243114 dac ZZ3141
- 002512 203150 lac ~ssn
- 002513 243155 dac ~ssm
- 002514 403114 add ~scn
- 002515 243156 dac ~ssc
- 002516 243157 dac ~ssd
- 002517 203150 lac ~ssn
- 002520 423114 sub ~scn
- 002521 243160 dac ~csn
- 002522 761000 cma
- 002523 243161 dac ~csm
- 002524 203114 lac ~scn
- 002525 243162 dac ~scm
- 002526 764200 cla cli-opr
- 002527 724007 dpy-4000
- 002530 sp5,
- 002530 602530 jmp .
- 002531 sq6,
- 002531 730000 ioh
-- ranct sar 9s, sar 4s, ~src
-- random
-+002532 200031 lac ran
-+002533 671001 rar 1s
-+002534 063041 xor (355760
-+002535 403042 add (355670
-+002536 240031 dac ran
-+002537 675777 ZZ1142
-+002540 675017 ZZ2142
-+002541 640400 sma
-+002542 761000 cma
-+002543 243163 dac ZZ3142
- 002544 223143 lio ~scw
- 002545 662003 ril 2s
- 002546 652000 spi i / not blasting
- 002547 602574 jmp sq9 / no tail
- 002550 sq7,
-- scale ~sn, 8s, ~ssn
-+002550 203144 lac ZZ1144
-+002551 675377 sar ZZ2144
-+002552 243150 dac ZZ3144
-- scale ~cs, 8s, ~scn
-+002553 203147 lac ZZ1145
-+002554 675377 sar ZZ2145
-+002555 243114 dac ZZ3145
-- count i ~mfu, st2
-+002556 473123 isp ZZ1146
-+002557 602562 jmp ZZ2146
- 002560 353123 dzm i ~mfu
- 002561 602574 jmp sq9
- 002562 st2,
-- yincr ~sx1, ~sy1, sub
-+002562 203153 lac ZZ2147
-+002563 423114 ZZ3147 ~scn
-+002564 243153 dac ZZ2147
-+002565 203151 lac ZZ1147
-+002566 403150 -ZZ3147+add+sub ~ssn
-+002567 243151 dac ZZ1147
-- dispt i, ~sy1
-+002570 000000 ZZ3148=ZZ3148+ZZ3148
-+002570 000000 ZZ3148=ZZ3148+ZZ3148
-+002570 000000 ZZ3148=ZZ3148+ZZ3148
-+002570 000000 ZZ3148=ZZ3148+ZZ3148
-+002570 000000 ZZ3148=ZZ3148+ZZ3148
-+002570 000000 ZZ3148=ZZ3148+ZZ3148
-+002570 223153 lio ZZ2148
-+002571 720007 dpy-ZZ1148+ZZ3148
-- count ~src,sq7
-+002572 463163 isp ZZ1149
-+002573 602550 jmp ZZ2149
- 002574 sq9,
-- count i ma1, sr5 / check if torp tube reloaded
-+002574 471772 isp ZZ1150
-+002575 602667 jmp ZZ2150
- 002576 351772 dzm i ma1 / prevent count around
- 002577 mco,
- 002577 202577 lac . / previous control word
- 002600 761000 cma
- 002601 650030 szs i 30
- 002602 761200 clc
- 002603 023143 and ~scw / present control word
- 002604 661007 ral 3s / torpedo bit to bit 0
- 002605 640400 sma
- 002606 602667 jmp sr5 / no launch
-- count i ~mtr, st1 / check if torpedos exhausted
-+002607 473124 isp ZZ1151
-+002610 602613 jmp ZZ2151
- 002611 353124 dzm i ~mtr / prevent count around
- 002612 602667 jmp sr5
- 002613 st1,
-- init sr1, mtb / search for unused object
-+002613 703365 law ZZ2152
-+002614 262615 dap ZZ1152
- 002615 sr1,
- 002615 202615 lac .
- 002616 650100 sza i / 0 if unused
- 002617 602625 jmp sr2
-- index sr1, (lac mtb+nob, sr1
-+002620 442615 idx ZZ1153
-+002621 523105 sas ZZ2153
-+002622 602615 jmp ZZ3153
- 002623 760400 hlt / no space for new objects
- 002624 602623 jmp .-1
--////
- 002625 sr2,
- 002625 203106 lac (tcr
- 002626 252615 dac i sr1
- 002627 700030 law nob
- 002630 402615 add sr1
- 002631 262633 dap ss3
- 002632 223152 lio ~stx
- 002633 ss3,
- 002633 322633 dio .
- 002634 403066 add (nob
- 002635 262637 dap ss4
- 002636 223154 lio ~sty
- 002637 ss4,
- 002637 322637 dio .
- 002640 403066 add (nob
- 002641 262664 dap sr6
- 002642 403066 add (nob
- 002643 262666 dap sr7
- 002644 403066 add (nob
- 002645 262654 dap sr3
- 002646 403066 add (nob
- 002647 262660 dap sr4
- 002650 203144 lac ~sn
- 002651 100007 xct tvl
- 002652 761000 cma
- 002653 413121 add i ~mdx
- 002654 sr3,
- 002654 242654 dac .
- 002655 203147 lac ~cs
- 002656 100007 xct tvl
- 002657 413122 add i ~mdy
- 002660 sr4,
- 002660 242660 dac .
- 002661 100010 xct rlt
- 002662 251772 dac i ma1 / permit torp tubes to cool
- 002663 trp,
- 002663 100011 xct tlf / life of torpedo
- 002664 sr6,
- 002664 242664 dac .
- 002665 700020 law 20
- 002666 sr7,
- 002666 262666 dap . / length of torp calc
- 002667 sr5,
-- count i ~mh3, st3 / hyperbutton active?
-+002667 473127 isp ZZ1154
-+002670 602713 jmp ZZ2154
- 002671 353127 dzm i ~mh3
- 002672 213126 lac i ~mh2
- 002673 650100 sza i
- 002674 602713 jmp st3
- 002675 203143 lac ~scw
- 002676 761000 cma
- 002677 052577 ior i mco
- 002700 023107 and (600000
- 002701 640100 sza
- 002702 602713 jmp st3
- 002703 211703 lac i ml1
- 002704 253125 dac i ~mh1
- 002705 203110 lac (hp1 400000
- 002706 251703 dac i ml1
- 002707 100023 xct hd1
- 002710 251772 dac i ma1
- 002711 700003 law 3
- 002712 252006 dac i mb1
- 002713 st3,
- 002713 srt,
- 002713 602713 jmp .
--////
--/ here to handle spaceships into star
--/ spaceship in star
- 002714 poh,
- 002714 353121 dzm i ~mdx
- 002715 353122 dzm i ~mdy
- 002716 640050 szs 50
- 002717 602730 jmp po1
- 002720 202767 lac (377777
- 002721 251737 dac i mx1
- 002722 251747 dac i my1
- 002723 212006 lac i mb1
- 002724 243150 dac ~ssn
-- count ~ssn, .
-+002725 463150 isp ZZ1155
-+002726 602725 jmp ZZ2155
- 002727 602713 jmp srt
- 002730 po1,
- 002730 203103 lac (mex 400000 / now go bang
- 002731 251703 dac i ml1
- 002732 710010 law i 10
- 002733 251772 dac i ma1
- 002734 602713 jmp srt
--////
--/ outlines of spaceships
- 002735 ot1,
- 002735 111131 111131
- 002736 111111 111111
- 002737 111111 111111
- 002740 111163 111163
- 002741 311111 311111
- 002742 146111 146111
- 002743 111114 111114
- 002744 700000 700000
- 002745 000005 . 5/
- 002746 ot2,
- 002746 013113 013113
- 002747 113111 113111
- 002750 116313 116313
- 002751 131111 131111
- 002752 161151 161151
- 002753 111633 111633
- 002754 365114 365114
- 002755 700000 700000
- 002756 000005 . 5/
- 002757 203164 lac ~ssa / To fix assembler bug - ~ssa only referenced in lit
- 002760 constants
-+002760 062210 62210
-+002761 311040 311040
-+002762 242763 242763
-+002763 756103 756103
-+002764 121312 121312
-+002765 532511 532511
-+002766 144417 144417
-+002767 377777 377777
-+002770 000001 1
-+002771 760015 stf 5
-+002772 203151 lac ~sx1
-+002773 223153 lio ~sy1
-+002774 663777 rcl 9s
-+002775 000444 a11
-+002776 640005 szf 5
-+002777 000004 4
-+003000 243151 dac ~sx1
-+003001 323153 dio ~sy1
-+003002 602531 jmp sq6
-+003003 760005 clf 5
-+003004 203162 lac ~scm
-+003005 761000 cma
-+003006 243162 dac ~scm
-+003007 203155 lac ~ssm
-+003010 243155 dac ~ssm
-+003011 203161 lac ~csm
-+003012 223157 lio ~ssd
-+003013 243157 dac ~ssd
-+003014 323161 dio ~csm
-+003015 203156 lac ~ssc
-+003016 223160 lio ~csn
-+003017 243160 dac ~csn
-+003020 323156 dio ~ssc
-+003021 403150 add ~ssn
-+003022 423114 sub ~scn
-+003023 730000 ioh
-+003024 724007 dpy-4000
-+003025 403162 add ~scm
-+003026 403155 add ~ssm
-+003027 403156 add ~ssc
-+003030 423161 sub ~csm
-+003031 423162 sub ~scm
-+003032 423155 sub ~ssm
-+003033 403160 add ~csn
-+003034 423157 sub ~ssd
-+003035 243164 dac ~ssa
-+003036 323115 dio ~ssi
-+003037 203164 lac ~ssa
-+003040 223115 lio ~ssi
-+003041 355760 355760
-+003042 355670 355670
-+003043 400340 add 340
-+003044 000716 bds
-+003045 002000 2000
-+003046 001000 1000
-+003047 226022 lio ZZ298+2
-+003050 761777 2000 -20000
-+003051 006022 ZZ298+2
-+003052 226000 lio ZZ198
-+003053 226044 lio ZZ299+2
-+003054 006044 ZZ299+2
-+003055 226022 lio ZZ199
-+003056 226306 lio ZZ2100+2
-+003057 006306 ZZ2100+2
-+003060 226044 lio ZZ1100
-+003061 227652 lio ZZ2101+2
-+003062 007652 ZZ2101+2
-+003063 226306 lio ZZ1101
-+003064 020000 20000
-+003065 773777 ZZ2102
-+003066 000030 nob
-+003067 000002 2
-+003070 000040 40
-+003071 000037 37
-+003072 343661 dzm ZZ2106+1
-+003073 200000 200000
-+003074 144420 144420
-+003075 203415 lac mtb nob
-+003076 203414 lac mtb nob-1
-+003077 675007 sar 3s
-+003100 000140 140
-+003101 000777 777
-+003102 667000 scl
-+003103 402052 mex 400000
-+003104 400000 400000
-+003105 203415 lac mtb+nob
-+003106 002136 tcr
-+003107 600000 600000
-+003110 402170 hp1 400000
- 003111 000000 0
- 003112 variables
-+003112 000000 occ
-+003113 000000 oci
-+003114 000000 scn
-+003115 000000 ssi
-+003116 000000 bx
-+003117 000000 by
-+003120 000000 mtc
-+003121 000000 mdx
-+003122 000000 mdy
-+003123 000000 mfu
-+003124 000000 mtr
-+003125 000000 mh1
-+003126 000000 mh2
-+003127 000000 mh3
-+003130 000000 mh4
-+003131 000000 ntd
-+003132 000000 1sc
-+003133 000000 2sc
-+003134 000000 cwg
-+003135 000000 gct
-+003136 000000 moc
-+003137 000000 mt1
-+003140 000000 mas
-+003141 000000 mxc
-+003142 000000 hpt
-+003143 000000 scw
-+003144 000000 sn
-+003145 000000 t1
-+003146 000000 t2
-+003147 000000 cs
-+003150 000000 ssn
-+003151 000000 sx1
-+003152 000000 stx
-+003153 000000 sy1
-+003154 000000 sty
-+003155 000000 ssm
-+003156 000000 ssc
-+003157 000000 ssd
-+003160 000000 csn
-+003161 000000 csm
-+003162 000000 scm
-+003163 000000 src
-+003164 000000 ssa
- 003165 p,
- 003365 . 200/ / space for patches
- 003365 mtb,
-- / table of objects and their properties
- 006000 6000/
--/stars 1 3/13/62 prs.
- 006000 decimal
-- define mark X, Y
-- repeat 10, Y=Y+Y
-- 0 8192 -X
-- 0 Y
-- terminate
- 006000 1j,
-- mark 1537, 371 /87 taur, aldebaran
-+006000 001346 ZZ2156=ZZ2156+ZZ2156
-+006000 002714 ZZ2156=ZZ2156+ZZ2156
-+006000 005630 ZZ2156=ZZ2156+ZZ2156
-+006000 013460 ZZ2156=ZZ2156+ZZ2156
-+006000 027140 ZZ2156=ZZ2156+ZZ2156
-+006000 056300 ZZ2156=ZZ2156+ZZ2156
-+006000 134600 ZZ2156=ZZ2156+ZZ2156
-+006000 271400 ZZ2156=ZZ2156+ZZ2156
-+006000 014777 0 8192 -ZZ1156
-+006001 271400 0 ZZ2156
-- mark 1762, -189 /19 orio, rigel
-+006002 777204 ZZ2157=ZZ2157+ZZ2157
-+006002 776410 ZZ2157=ZZ2157+ZZ2157
-+006002 775020 ZZ2157=ZZ2157+ZZ2157
-+006002 772040 ZZ2157=ZZ2157+ZZ2157
-+006002 764100 ZZ2157=ZZ2157+ZZ2157
-+006002 750200 ZZ2157=ZZ2157+ZZ2157
-+006002 720400 ZZ2157=ZZ2157+ZZ2157
-+006002 641000 ZZ2157=ZZ2157+ZZ2157
-+006002 014436 0 8192 -ZZ1157
-+006003 641000 0 ZZ2157
-- mark 1990, 168 /58 orio, betelgeuze
-+006004 000520 ZZ2158=ZZ2158+ZZ2158
-+006004 001240 ZZ2158=ZZ2158+ZZ2158
-+006004 002500 ZZ2158=ZZ2158+ZZ2158
-+006004 005200 ZZ2158=ZZ2158+ZZ2158
-+006004 012400 ZZ2158=ZZ2158+ZZ2158
-+006004 025000 ZZ2158=ZZ2158+ZZ2158
-+006004 052000 ZZ2158=ZZ2158+ZZ2158
-+006004 124000 ZZ2158=ZZ2158+ZZ2158
-+006004 014072 0 8192 -ZZ1158
-+006005 124000 0 ZZ2158
-- mark 2280, -377 /9 cmaj, sirius
-+006006 776414 ZZ2159=ZZ2159+ZZ2159
-+006006 775030 ZZ2159=ZZ2159+ZZ2159
-+006006 772060 ZZ2159=ZZ2159+ZZ2159
-+006006 764140 ZZ2159=ZZ2159+ZZ2159
-+006006 750300 ZZ2159=ZZ2159+ZZ2159
-+006006 720600 ZZ2159=ZZ2159+ZZ2159
-+006006 641400 ZZ2159=ZZ2159+ZZ2159
-+006006 503000 ZZ2159=ZZ2159+ZZ2159
-+006006 013430 0 8192 -ZZ1159
-+006007 503000 0 ZZ2159
-- mark 2583, 125 /25 cmin, procyon
-+006010 000372 ZZ2160=ZZ2160+ZZ2160
-+006010 000764 ZZ2160=ZZ2160+ZZ2160
-+006010 001750 ZZ2160=ZZ2160+ZZ2160
-+006010 003720 ZZ2160=ZZ2160+ZZ2160
-+006010 007640 ZZ2160=ZZ2160+ZZ2160
-+006010 017500 ZZ2160=ZZ2160+ZZ2160
-+006010 037200 ZZ2160=ZZ2160+ZZ2160
-+006010 076400 ZZ2160=ZZ2160+ZZ2160
-+006010 012751 0 8192 -ZZ1160
-+006011 076400 0 ZZ2160
-- mark 3431, 283 /32 leon, regulus
-+006012 001066 ZZ2161=ZZ2161+ZZ2161
-+006012 002154 ZZ2161=ZZ2161+ZZ2161
-+006012 004330 ZZ2161=ZZ2161+ZZ2161
-+006012 010660 ZZ2161=ZZ2161+ZZ2161
-+006012 021540 ZZ2161=ZZ2161+ZZ2161
-+006012 043300 ZZ2161=ZZ2161+ZZ2161
-+006012 106600 ZZ2161=ZZ2161+ZZ2161
-+006012 215400 ZZ2161=ZZ2161+ZZ2161
-+006012 011231 0 8192 -ZZ1161
-+006013 215400 0 ZZ2161
-- mark 4551, -242 /67 virg, spica
-+006014 777032 ZZ2162=ZZ2162+ZZ2162
-+006014 776064 ZZ2162=ZZ2162+ZZ2162
-+006014 774150 ZZ2162=ZZ2162+ZZ2162
-+006014 770320 ZZ2162=ZZ2162+ZZ2162
-+006014 760640 ZZ2162=ZZ2162+ZZ2162
-+006014 741500 ZZ2162=ZZ2162+ZZ2162
-+006014 703200 ZZ2162=ZZ2162+ZZ2162
-+006014 606400 ZZ2162=ZZ2162+ZZ2162
-+006014 007071 0 8192 -ZZ1162
-+006015 606400 0 ZZ2162
-- mark 4842, 448 /16 boot, arcturus
-+006016 001600 ZZ2163=ZZ2163+ZZ2163
-+006016 003400 ZZ2163=ZZ2163+ZZ2163
-+006016 007000 ZZ2163=ZZ2163+ZZ2163
-+006016 016000 ZZ2163=ZZ2163+ZZ2163
-+006016 034000 ZZ2163=ZZ2163+ZZ2163
-+006016 070000 ZZ2163=ZZ2163+ZZ2163
-+006016 160000 ZZ2163=ZZ2163+ZZ2163
-+006016 340000 ZZ2163=ZZ2163+ZZ2163
-+006016 006426 0 8192 -ZZ1163
-+006017 340000 0 ZZ2163
- 006020 1q,
-- mark 6747, 196 /53 aqil, altair
-+006020 000610 ZZ2164=ZZ2164+ZZ2164
-+006020 001420 ZZ2164=ZZ2164+ZZ2164
-+006020 003040 ZZ2164=ZZ2164+ZZ2164
-+006020 006100 ZZ2164=ZZ2164+ZZ2164
-+006020 014200 ZZ2164=ZZ2164+ZZ2164
-+006020 030400 ZZ2164=ZZ2164+ZZ2164
-+006020 061000 ZZ2164=ZZ2164+ZZ2164
-+006020 142000 ZZ2164=ZZ2164+ZZ2164
-+006020 002645 0 8192 -ZZ1164
-+006021 142000 0 ZZ2164
- 006022 2j,
-- mark 1819, 143 /24 orio, bellatrix
-+006022 000436 ZZ2165=ZZ2165+ZZ2165
-+006022 001074 ZZ2165=ZZ2165+ZZ2165
-+006022 002170 ZZ2165=ZZ2165+ZZ2165
-+006022 004360 ZZ2165=ZZ2165+ZZ2165
-+006022 010740 ZZ2165=ZZ2165+ZZ2165
-+006022 021700 ZZ2165=ZZ2165+ZZ2165
-+006022 043600 ZZ2165=ZZ2165+ZZ2165
-+006022 107400 ZZ2165=ZZ2165+ZZ2165
-+006022 014345 0 8192 -ZZ1165
-+006023 107400 0 ZZ2165
-- mark 1884, -29 /46 orio
-+006024 777704 ZZ2166=ZZ2166+ZZ2166
-+006024 777610 ZZ2166=ZZ2166+ZZ2166
-+006024 777420 ZZ2166=ZZ2166+ZZ2166
-+006024 777040 ZZ2166=ZZ2166+ZZ2166
-+006024 776100 ZZ2166=ZZ2166+ZZ2166
-+006024 774200 ZZ2166=ZZ2166+ZZ2166
-+006024 770400 ZZ2166=ZZ2166+ZZ2166
-+006024 761000 ZZ2166=ZZ2166+ZZ2166
-+006024 014244 0 8192 -ZZ1166
-+006025 761000 0 ZZ2166
-- mark 1910, -46 /50 orio
-+006026 777642 ZZ2167=ZZ2167+ZZ2167
-+006026 777504 ZZ2167=ZZ2167+ZZ2167
-+006026 777210 ZZ2167=ZZ2167+ZZ2167
-+006026 776420 ZZ2167=ZZ2167+ZZ2167
-+006026 775040 ZZ2167=ZZ2167+ZZ2167
-+006026 772100 ZZ2167=ZZ2167+ZZ2167
-+006026 764200 ZZ2167=ZZ2167+ZZ2167
-+006026 750400 ZZ2167=ZZ2167+ZZ2167
-+006026 014212 0 8192 -ZZ1167
-+006027 750400 0 ZZ2167
-- mark 1951, -221 /53 orio
-+006030 777104 ZZ2168=ZZ2168+ZZ2168
-+006030 776210 ZZ2168=ZZ2168+ZZ2168
-+006030 774420 ZZ2168=ZZ2168+ZZ2168
-+006030 771040 ZZ2168=ZZ2168+ZZ2168
-+006030 762100 ZZ2168=ZZ2168+ZZ2168
-+006030 744200 ZZ2168=ZZ2168+ZZ2168
-+006030 710400 ZZ2168=ZZ2168+ZZ2168
-+006030 621000 ZZ2168=ZZ2168+ZZ2168
-+006030 014141 0 8192 -ZZ1168
-+006031 621000 0 ZZ2168
-- mark 2152, -407 / 2 cmaj
-+006032 776320 ZZ2169=ZZ2169+ZZ2169
-+006032 774640 ZZ2169=ZZ2169+ZZ2169
-+006032 771500 ZZ2169=ZZ2169+ZZ2169
-+006032 763200 ZZ2169=ZZ2169+ZZ2169
-+006032 746400 ZZ2169=ZZ2169+ZZ2169
-+006032 715000 ZZ2169=ZZ2169+ZZ2169
-+006032 632000 ZZ2169=ZZ2169+ZZ2169
-+006032 464000 ZZ2169=ZZ2169+ZZ2169
-+006032 013630 0 8192 -ZZ1169
-+006033 464000 0 ZZ2169
-- mark 2230, 375 /24 gemi
-+006034 001356 ZZ2170=ZZ2170+ZZ2170
-+006034 002734 ZZ2170=ZZ2170+ZZ2170
-+006034 005670 ZZ2170=ZZ2170+ZZ2170
-+006034 013560 ZZ2170=ZZ2170+ZZ2170
-+006034 027340 ZZ2170=ZZ2170+ZZ2170
-+006034 056700 ZZ2170=ZZ2170+ZZ2170
-+006034 135600 ZZ2170=ZZ2170+ZZ2170
-+006034 273400 ZZ2170=ZZ2170+ZZ2170
-+006034 013512 0 8192 -ZZ1170
-+006035 273400 0 ZZ2170
-- mark 3201, -187 /30 hyda, alphard
-+006036 777210 ZZ2171=ZZ2171+ZZ2171
-+006036 776420 ZZ2171=ZZ2171+ZZ2171
-+006036 775040 ZZ2171=ZZ2171+ZZ2171
-+006036 772100 ZZ2171=ZZ2171+ZZ2171
-+006036 764200 ZZ2171=ZZ2171+ZZ2171
-+006036 750400 ZZ2171=ZZ2171+ZZ2171
-+006036 721000 ZZ2171=ZZ2171+ZZ2171
-+006036 642000 ZZ2171=ZZ2171+ZZ2171
-+006036 011577 0 8192 -ZZ1171
-+006037 642000 0 ZZ2171
-- mark 4005, 344 /94 leon, denebola
-+006040 001260 ZZ2172=ZZ2172+ZZ2172
-+006040 002540 ZZ2172=ZZ2172+ZZ2172
-+006040 005300 ZZ2172=ZZ2172+ZZ2172
-+006040 012600 ZZ2172=ZZ2172+ZZ2172
-+006040 025400 ZZ2172=ZZ2172+ZZ2172
-+006040 053000 ZZ2172=ZZ2172+ZZ2172
-+006040 126000 ZZ2172=ZZ2172+ZZ2172
-+006040 254000 ZZ2172=ZZ2172+ZZ2172
-+006040 010133 0 8192 -ZZ1172
-+006041 254000 0 ZZ2172
- 006042 2q,
-- mark 5975, 288 /55 ophi
-+006042 001100 ZZ2173=ZZ2173+ZZ2173
-+006042 002200 ZZ2173=ZZ2173+ZZ2173
-+006042 004400 ZZ2173=ZZ2173+ZZ2173
-+006042 011000 ZZ2173=ZZ2173+ZZ2173
-+006042 022000 ZZ2173=ZZ2173+ZZ2173
-+006042 044000 ZZ2173=ZZ2173+ZZ2173
-+006042 110000 ZZ2173=ZZ2173+ZZ2173
-+006042 220000 ZZ2173=ZZ2173+ZZ2173
-+006042 004251 0 8192 -ZZ1173
-+006043 220000 0 ZZ2173
- 006044 3j,
-- mark 46, 333 /88 pegs, algenib
-+006044 001232 ZZ2174=ZZ2174+ZZ2174
-+006044 002464 ZZ2174=ZZ2174+ZZ2174
-+006044 005150 ZZ2174=ZZ2174+ZZ2174
-+006044 012320 ZZ2174=ZZ2174+ZZ2174
-+006044 024640 ZZ2174=ZZ2174+ZZ2174
-+006044 051500 ZZ2174=ZZ2174+ZZ2174
-+006044 123200 ZZ2174=ZZ2174+ZZ2174
-+006044 246400 ZZ2174=ZZ2174+ZZ2174
-+006044 017722 0 8192 -ZZ1174
-+006045 246400 0 ZZ2174
-- mark 362, -244 /31 ceti
-+006046 777026 ZZ2175=ZZ2175+ZZ2175
-+006046 776054 ZZ2175=ZZ2175+ZZ2175
-+006046 774130 ZZ2175=ZZ2175+ZZ2175
-+006046 770260 ZZ2175=ZZ2175+ZZ2175
-+006046 760540 ZZ2175=ZZ2175+ZZ2175
-+006046 741300 ZZ2175=ZZ2175+ZZ2175
-+006046 702600 ZZ2175=ZZ2175+ZZ2175
-+006046 605400 ZZ2175=ZZ2175+ZZ2175
-+006046 017226 0 8192 -ZZ1175
-+006047 605400 0 ZZ2175
-- mark 490, 338 /99 pisc
-+006050 001244 ZZ2176=ZZ2176+ZZ2176
-+006050 002510 ZZ2176=ZZ2176+ZZ2176
-+006050 005220 ZZ2176=ZZ2176+ZZ2176
-+006050 012440 ZZ2176=ZZ2176+ZZ2176
-+006050 025100 ZZ2176=ZZ2176+ZZ2176
-+006050 052200 ZZ2176=ZZ2176+ZZ2176
-+006050 124400 ZZ2176=ZZ2176+ZZ2176
-+006050 251000 ZZ2176=ZZ2176+ZZ2176
-+006050 017026 0 8192 -ZZ1176
-+006051 251000 0 ZZ2176
-- mark 566, -375 /52 ceti
-+006052 776420 ZZ2177=ZZ2177+ZZ2177
-+006052 775040 ZZ2177=ZZ2177+ZZ2177
-+006052 772100 ZZ2177=ZZ2177+ZZ2177
-+006052 764200 ZZ2177=ZZ2177+ZZ2177
-+006052 750400 ZZ2177=ZZ2177+ZZ2177
-+006052 721000 ZZ2177=ZZ2177+ZZ2177
-+006052 642000 ZZ2177=ZZ2177+ZZ2177
-+006052 504000 ZZ2177=ZZ2177+ZZ2177
-+006052 016712 0 8192 -ZZ1177
-+006053 504000 0 ZZ2177
-- mark 621, 462 / 6 arie
-+006054 001634 ZZ2178=ZZ2178+ZZ2178
-+006054 003470 ZZ2178=ZZ2178+ZZ2178
-+006054 007160 ZZ2178=ZZ2178+ZZ2178
-+006054 016340 ZZ2178=ZZ2178+ZZ2178
-+006054 034700 ZZ2178=ZZ2178+ZZ2178
-+006054 071600 ZZ2178=ZZ2178+ZZ2178
-+006054 163400 ZZ2178=ZZ2178+ZZ2178
-+006054 347000 ZZ2178=ZZ2178+ZZ2178
-+006054 016623 0 8192 -ZZ1178
-+006055 347000 0 ZZ2178
-- mark 764, -78 /68 ceti, mira
-+006056 777542 ZZ2179=ZZ2179+ZZ2179
-+006056 777304 ZZ2179=ZZ2179+ZZ2179
-+006056 776610 ZZ2179=ZZ2179+ZZ2179
-+006056 775420 ZZ2179=ZZ2179+ZZ2179
-+006056 773040 ZZ2179=ZZ2179+ZZ2179
-+006056 766100 ZZ2179=ZZ2179+ZZ2179
-+006056 754200 ZZ2179=ZZ2179+ZZ2179
-+006056 730400 ZZ2179=ZZ2179+ZZ2179
-+006056 016404 0 8192 -ZZ1179
-+006057 730400 0 ZZ2179
-- mark 900, 64 /86 ceti
-+006060 000200 ZZ2180=ZZ2180+ZZ2180
-+006060 000400 ZZ2180=ZZ2180+ZZ2180
-+006060 001000 ZZ2180=ZZ2180+ZZ2180
-+006060 002000 ZZ2180=ZZ2180+ZZ2180
-+006060 004000 ZZ2180=ZZ2180+ZZ2180
-+006060 010000 ZZ2180=ZZ2180+ZZ2180
-+006060 020000 ZZ2180=ZZ2180+ZZ2180
-+006060 040000 ZZ2180=ZZ2180+ZZ2180
-+006060 016174 0 8192 -ZZ1180
-+006061 040000 0 ZZ2180
-- mark 1007, 84 /92 ceti
-+006062 000250 ZZ2181=ZZ2181+ZZ2181
-+006062 000520 ZZ2181=ZZ2181+ZZ2181
-+006062 001240 ZZ2181=ZZ2181+ZZ2181
-+006062 002500 ZZ2181=ZZ2181+ZZ2181
-+006062 005200 ZZ2181=ZZ2181+ZZ2181
-+006062 012400 ZZ2181=ZZ2181+ZZ2181
-+006062 025000 ZZ2181=ZZ2181+ZZ2181
-+006062 052000 ZZ2181=ZZ2181+ZZ2181
-+006062 016021 0 8192 -ZZ1181
-+006063 052000 0 ZZ2181
-- mark 1243, -230 /23 erid
-+006064 777062 ZZ2182=ZZ2182+ZZ2182
-+006064 776144 ZZ2182=ZZ2182+ZZ2182
-+006064 774310 ZZ2182=ZZ2182+ZZ2182
-+006064 770620 ZZ2182=ZZ2182+ZZ2182
-+006064 761440 ZZ2182=ZZ2182+ZZ2182
-+006064 743100 ZZ2182=ZZ2182+ZZ2182
-+006064 706200 ZZ2182=ZZ2182+ZZ2182
-+006064 614400 ZZ2182=ZZ2182+ZZ2182
-+006064 015445 0 8192 -ZZ1182
-+006065 614400 0 ZZ2182
-- mark 1328, -314 /34 erid
-+006066 776612 ZZ2183=ZZ2183+ZZ2183
-+006066 775424 ZZ2183=ZZ2183+ZZ2183
-+006066 773050 ZZ2183=ZZ2183+ZZ2183
-+006066 766120 ZZ2183=ZZ2183+ZZ2183
-+006066 754240 ZZ2183=ZZ2183+ZZ2183
-+006066 730500 ZZ2183=ZZ2183+ZZ2183
-+006066 661200 ZZ2183=ZZ2183+ZZ2183
-+006066 542400 ZZ2183=ZZ2183+ZZ2183
-+006066 015320 0 8192 -ZZ1183
-+006067 542400 0 ZZ2183
-- mark 1495, 432 /74 taur
-+006070 001540 ZZ2184=ZZ2184+ZZ2184
-+006070 003300 ZZ2184=ZZ2184+ZZ2184
-+006070 006600 ZZ2184=ZZ2184+ZZ2184
-+006070 015400 ZZ2184=ZZ2184+ZZ2184
-+006070 033000 ZZ2184=ZZ2184+ZZ2184
-+006070 066000 ZZ2184=ZZ2184+ZZ2184
-+006070 154000 ZZ2184=ZZ2184+ZZ2184
-+006070 330000 ZZ2184=ZZ2184+ZZ2184
-+006070 015051 0 8192 -ZZ1184
-+006071 330000 0 ZZ2184
-- mark 1496, 356 /78 taur
-+006072 001310 ZZ2185=ZZ2185+ZZ2185
-+006072 002620 ZZ2185=ZZ2185+ZZ2185
-+006072 005440 ZZ2185=ZZ2185+ZZ2185
-+006072 013100 ZZ2185=ZZ2185+ZZ2185
-+006072 026200 ZZ2185=ZZ2185+ZZ2185
-+006072 054400 ZZ2185=ZZ2185+ZZ2185
-+006072 131000 ZZ2185=ZZ2185+ZZ2185
-+006072 262000 ZZ2185=ZZ2185+ZZ2185
-+006072 015050 0 8192 -ZZ1185
-+006073 262000 0 ZZ2185
-- mark 1618, 154 / 1 orio
-+006074 000464 ZZ2186=ZZ2186+ZZ2186
-+006074 001150 ZZ2186=ZZ2186+ZZ2186
-+006074 002320 ZZ2186=ZZ2186+ZZ2186
-+006074 004640 ZZ2186=ZZ2186+ZZ2186
-+006074 011500 ZZ2186=ZZ2186+ZZ2186
-+006074 023200 ZZ2186=ZZ2186+ZZ2186
-+006074 046400 ZZ2186=ZZ2186+ZZ2186
-+006074 115000 ZZ2186=ZZ2186+ZZ2186
-+006074 014656 0 8192 -ZZ1186
-+006075 115000 0 ZZ2186
-- mark 1644, 52 / 8 orio
-+006076 000150 ZZ2187=ZZ2187+ZZ2187
-+006076 000320 ZZ2187=ZZ2187+ZZ2187
-+006076 000640 ZZ2187=ZZ2187+ZZ2187
-+006076 001500 ZZ2187=ZZ2187+ZZ2187
-+006076 003200 ZZ2187=ZZ2187+ZZ2187
-+006076 006400 ZZ2187=ZZ2187+ZZ2187
-+006076 015000 ZZ2187=ZZ2187+ZZ2187
-+006076 032000 ZZ2187=ZZ2187+ZZ2187
-+006076 014624 0 8192 -ZZ1187
-+006077 032000 0 ZZ2187
-- mark 1723, -119 /67 erid
-+006100 777420 ZZ2188=ZZ2188+ZZ2188
-+006100 777040 ZZ2188=ZZ2188+ZZ2188
-+006100 776100 ZZ2188=ZZ2188+ZZ2188
-+006100 774200 ZZ2188=ZZ2188+ZZ2188
-+006100 770400 ZZ2188=ZZ2188+ZZ2188
-+006100 761000 ZZ2188=ZZ2188+ZZ2188
-+006100 742000 ZZ2188=ZZ2188+ZZ2188
-+006100 704000 ZZ2188=ZZ2188+ZZ2188
-+006100 014505 0 8192 -ZZ1188
-+006101 704000 0 ZZ2188
-- mark 1755, -371 / 5 leps
-+006102 776430 ZZ2189=ZZ2189+ZZ2189
-+006102 775060 ZZ2189=ZZ2189+ZZ2189
-+006102 772140 ZZ2189=ZZ2189+ZZ2189
-+006102 764300 ZZ2189=ZZ2189+ZZ2189
-+006102 750600 ZZ2189=ZZ2189+ZZ2189
-+006102 721400 ZZ2189=ZZ2189+ZZ2189
-+006102 643000 ZZ2189=ZZ2189+ZZ2189
-+006102 506000 ZZ2189=ZZ2189+ZZ2189
-+006102 014445 0 8192 -ZZ1189
-+006103 506000 0 ZZ2189
-- mark 1779, -158 /20 orio
-+006104 777302 ZZ2190=ZZ2190+ZZ2190
-+006104 776604 ZZ2190=ZZ2190+ZZ2190
-+006104 775410 ZZ2190=ZZ2190+ZZ2190
-+006104 773020 ZZ2190=ZZ2190+ZZ2190
-+006104 766040 ZZ2190=ZZ2190+ZZ2190
-+006104 754100 ZZ2190=ZZ2190+ZZ2190
-+006104 730200 ZZ2190=ZZ2190+ZZ2190
-+006104 660400 ZZ2190=ZZ2190+ZZ2190
-+006104 014415 0 8192 -ZZ1190
-+006105 660400 0 ZZ2190
-- mark 1817, -57 /28 orio
-+006106 777614 ZZ2191=ZZ2191+ZZ2191
-+006106 777430 ZZ2191=ZZ2191+ZZ2191
-+006106 777060 ZZ2191=ZZ2191+ZZ2191
-+006106 776140 ZZ2191=ZZ2191+ZZ2191
-+006106 774300 ZZ2191=ZZ2191+ZZ2191
-+006106 770600 ZZ2191=ZZ2191+ZZ2191
-+006106 761400 ZZ2191=ZZ2191+ZZ2191
-+006106 743000 ZZ2191=ZZ2191+ZZ2191
-+006106 014347 0 8192 -ZZ1191
-+006107 743000 0 ZZ2191
-- mark 1843, -474 / 9 leps
-+006110 776112 ZZ2192=ZZ2192+ZZ2192
-+006110 774224 ZZ2192=ZZ2192+ZZ2192
-+006110 770450 ZZ2192=ZZ2192+ZZ2192
-+006110 761120 ZZ2192=ZZ2192+ZZ2192
-+006110 742240 ZZ2192=ZZ2192+ZZ2192
-+006110 704500 ZZ2192=ZZ2192+ZZ2192
-+006110 611200 ZZ2192=ZZ2192+ZZ2192
-+006110 422400 ZZ2192=ZZ2192+ZZ2192
-+006110 014315 0 8192 -ZZ1192
-+006111 422400 0 ZZ2192
-- mark 1860, -8 /34 orio
-+006112 777756 ZZ2193=ZZ2193+ZZ2193
-+006112 777734 ZZ2193=ZZ2193+ZZ2193
-+006112 777670 ZZ2193=ZZ2193+ZZ2193
-+006112 777560 ZZ2193=ZZ2193+ZZ2193
-+006112 777340 ZZ2193=ZZ2193+ZZ2193
-+006112 776700 ZZ2193=ZZ2193+ZZ2193
-+006112 775600 ZZ2193=ZZ2193+ZZ2193
-+006112 773400 ZZ2193=ZZ2193+ZZ2193
-+006112 014274 0 8192 -ZZ1193
-+006113 773400 0 ZZ2193
-- mark 1868, -407 /11 leps
-+006114 776320 ZZ2194=ZZ2194+ZZ2194
-+006114 774640 ZZ2194=ZZ2194+ZZ2194
-+006114 771500 ZZ2194=ZZ2194+ZZ2194
-+006114 763200 ZZ2194=ZZ2194+ZZ2194
-+006114 746400 ZZ2194=ZZ2194+ZZ2194
-+006114 715000 ZZ2194=ZZ2194+ZZ2194
-+006114 632000 ZZ2194=ZZ2194+ZZ2194
-+006114 464000 ZZ2194=ZZ2194+ZZ2194
-+006114 014264 0 8192 -ZZ1194
-+006115 464000 0 ZZ2194
-- mark 1875, 225 /39 orio
-+006116 000702 ZZ2195=ZZ2195+ZZ2195
-+006116 001604 ZZ2195=ZZ2195+ZZ2195
-+006116 003410 ZZ2195=ZZ2195+ZZ2195
-+006116 007020 ZZ2195=ZZ2195+ZZ2195
-+006116 016040 ZZ2195=ZZ2195+ZZ2195
-+006116 034100 ZZ2195=ZZ2195+ZZ2195
-+006116 070200 ZZ2195=ZZ2195+ZZ2195
-+006116 160400 ZZ2195=ZZ2195+ZZ2195
-+006116 014255 0 8192 -ZZ1195
-+006117 160400 0 ZZ2195
-- mark 1880, -136 /44 orio
-+006120 777356 ZZ2196=ZZ2196+ZZ2196
-+006120 776734 ZZ2196=ZZ2196+ZZ2196
-+006120 775670 ZZ2196=ZZ2196+ZZ2196
-+006120 773560 ZZ2196=ZZ2196+ZZ2196
-+006120 767340 ZZ2196=ZZ2196+ZZ2196
-+006120 756700 ZZ2196=ZZ2196+ZZ2196
-+006120 735600 ZZ2196=ZZ2196+ZZ2196
-+006120 673400 ZZ2196=ZZ2196+ZZ2196
-+006120 014250 0 8192 -ZZ1196
-+006121 673400 0 ZZ2196
-- mark 1887, 480 /123 taur
-+006122 001700 ZZ2197=ZZ2197+ZZ2197
-+006122 003600 ZZ2197=ZZ2197+ZZ2197
-+006122 007400 ZZ2197=ZZ2197+ZZ2197
-+006122 017000 ZZ2197=ZZ2197+ZZ2197
-+006122 036000 ZZ2197=ZZ2197+ZZ2197
-+006122 074000 ZZ2197=ZZ2197+ZZ2197
-+006122 170000 ZZ2197=ZZ2197+ZZ2197
-+006122 360000 ZZ2197=ZZ2197+ZZ2197
-+006122 014241 0 8192 -ZZ1197
-+006123 360000 0 ZZ2197
-- mark 1948, -338 /14 leps
-+006124 776532 ZZ2198=ZZ2198+ZZ2198
-+006124 775264 ZZ2198=ZZ2198+ZZ2198
-+006124 772550 ZZ2198=ZZ2198+ZZ2198
-+006124 765320 ZZ2198=ZZ2198+ZZ2198
-+006124 752640 ZZ2198=ZZ2198+ZZ2198
-+006124 725500 ZZ2198=ZZ2198+ZZ2198
-+006124 653200 ZZ2198=ZZ2198+ZZ2198
-+006124 526400 ZZ2198=ZZ2198+ZZ2198
-+006124 014144 0 8192 -ZZ1198
-+006125 526400 0 ZZ2198
-- mark 2274, 296 /31 gemi
-+006126 001120 ZZ2199=ZZ2199+ZZ2199
-+006126 002240 ZZ2199=ZZ2199+ZZ2199
-+006126 004500 ZZ2199=ZZ2199+ZZ2199
-+006126 011200 ZZ2199=ZZ2199+ZZ2199
-+006126 022400 ZZ2199=ZZ2199+ZZ2199
-+006126 045000 ZZ2199=ZZ2199+ZZ2199
-+006126 112000 ZZ2199=ZZ2199+ZZ2199
-+006126 224000 ZZ2199=ZZ2199+ZZ2199
-+006126 013436 0 8192 -ZZ1199
-+006127 224000 0 ZZ2199
-- mark 2460, 380 /54 gemi
-+006130 001370 ZZ2200=ZZ2200+ZZ2200
-+006130 002760 ZZ2200=ZZ2200+ZZ2200
-+006130 005740 ZZ2200=ZZ2200+ZZ2200
-+006130 013700 ZZ2200=ZZ2200+ZZ2200
-+006130 027600 ZZ2200=ZZ2200+ZZ2200
-+006130 057400 ZZ2200=ZZ2200+ZZ2200
-+006130 137000 ZZ2200=ZZ2200+ZZ2200
-+006130 276000 ZZ2200=ZZ2200+ZZ2200
-+006130 013144 0 8192 -ZZ1200
-+006131 276000 0 ZZ2200
-- mark 2470, 504 /55 gemi
-+006132 001760 ZZ2201=ZZ2201+ZZ2201
-+006132 003740 ZZ2201=ZZ2201+ZZ2201
-+006132 007700 ZZ2201=ZZ2201+ZZ2201
-+006132 017600 ZZ2201=ZZ2201+ZZ2201
-+006132 037400 ZZ2201=ZZ2201+ZZ2201
-+006132 077000 ZZ2201=ZZ2201+ZZ2201
-+006132 176000 ZZ2201=ZZ2201+ZZ2201
-+006132 374000 ZZ2201=ZZ2201+ZZ2201
-+006132 013132 0 8192 -ZZ1201
-+006133 374000 0 ZZ2201
-- mark 2513, 193 / 3 cmin
-+006134 000602 ZZ2202=ZZ2202+ZZ2202
-+006134 001404 ZZ2202=ZZ2202+ZZ2202
-+006134 003010 ZZ2202=ZZ2202+ZZ2202
-+006134 006020 ZZ2202=ZZ2202+ZZ2202
-+006134 014040 ZZ2202=ZZ2202+ZZ2202
-+006134 030100 ZZ2202=ZZ2202+ZZ2202
-+006134 060200 ZZ2202=ZZ2202+ZZ2202
-+006134 140400 ZZ2202=ZZ2202+ZZ2202
-+006134 013057 0 8192 -ZZ1202
-+006135 140400 0 ZZ2202
-- mark 2967, 154 /11 hyda
-+006136 000464 ZZ2203=ZZ2203+ZZ2203
-+006136 001150 ZZ2203=ZZ2203+ZZ2203
-+006136 002320 ZZ2203=ZZ2203+ZZ2203
-+006136 004640 ZZ2203=ZZ2203+ZZ2203
-+006136 011500 ZZ2203=ZZ2203+ZZ2203
-+006136 023200 ZZ2203=ZZ2203+ZZ2203
-+006136 046400 ZZ2203=ZZ2203+ZZ2203
-+006136 115000 ZZ2203=ZZ2203+ZZ2203
-+006136 012151 0 8192 -ZZ1203
-+006137 115000 0 ZZ2203
-- mark 3016, 144 /16 hyda
-+006140 000440 ZZ2204=ZZ2204+ZZ2204
-+006140 001100 ZZ2204=ZZ2204+ZZ2204
-+006140 002200 ZZ2204=ZZ2204+ZZ2204
-+006140 004400 ZZ2204=ZZ2204+ZZ2204
-+006140 011000 ZZ2204=ZZ2204+ZZ2204
-+006140 022000 ZZ2204=ZZ2204+ZZ2204
-+006140 044000 ZZ2204=ZZ2204+ZZ2204
-+006140 110000 ZZ2204=ZZ2204+ZZ2204
-+006140 012070 0 8192 -ZZ1204
-+006141 110000 0 ZZ2204
-- mark 3424, 393 /30 leon
-+006142 001422 ZZ2205=ZZ2205+ZZ2205
-+006142 003044 ZZ2205=ZZ2205+ZZ2205
-+006142 006110 ZZ2205=ZZ2205+ZZ2205
-+006142 014220 ZZ2205=ZZ2205+ZZ2205
-+006142 030440 ZZ2205=ZZ2205+ZZ2205
-+006142 061100 ZZ2205=ZZ2205+ZZ2205
-+006142 142200 ZZ2205=ZZ2205+ZZ2205
-+006142 304400 ZZ2205=ZZ2205+ZZ2205
-+006142 011240 0 8192 -ZZ1205
-+006143 304400 0 ZZ2205
-- mark 3496, 463 /41 leon, algieba
-+006144 001636 ZZ2206=ZZ2206+ZZ2206
-+006144 003474 ZZ2206=ZZ2206+ZZ2206
-+006144 007170 ZZ2206=ZZ2206+ZZ2206
-+006144 016360 ZZ2206=ZZ2206+ZZ2206
-+006144 034740 ZZ2206=ZZ2206+ZZ2206
-+006144 071700 ZZ2206=ZZ2206+ZZ2206
-+006144 163600 ZZ2206=ZZ2206+ZZ2206
-+006144 347400 ZZ2206=ZZ2206+ZZ2206
-+006144 011130 0 8192 -ZZ1206
-+006145 347400 0 ZZ2206
-- mark 3668, -357 /nu hyda
-+006146 776464 ZZ2207=ZZ2207+ZZ2207
-+006146 775150 ZZ2207=ZZ2207+ZZ2207
-+006146 772320 ZZ2207=ZZ2207+ZZ2207
-+006146 764640 ZZ2207=ZZ2207+ZZ2207
-+006146 751500 ZZ2207=ZZ2207+ZZ2207
-+006146 723200 ZZ2207=ZZ2207+ZZ2207
-+006146 646400 ZZ2207=ZZ2207+ZZ2207
-+006146 515000 ZZ2207=ZZ2207+ZZ2207
-+006146 010654 0 8192 -ZZ1207
-+006147 515000 0 ZZ2207
-- mark 3805, 479 /68 leon
-+006150 001676 ZZ2208=ZZ2208+ZZ2208
-+006150 003574 ZZ2208=ZZ2208+ZZ2208
-+006150 007370 ZZ2208=ZZ2208+ZZ2208
-+006150 016760 ZZ2208=ZZ2208+ZZ2208
-+006150 035740 ZZ2208=ZZ2208+ZZ2208
-+006150 073700 ZZ2208=ZZ2208+ZZ2208
-+006150 167600 ZZ2208=ZZ2208+ZZ2208
-+006150 357400 ZZ2208=ZZ2208+ZZ2208
-+006150 010443 0 8192 -ZZ1208
-+006151 357400 0 ZZ2208
-- mark 3806, 364 /10 leon
-+006152 001330 ZZ2209=ZZ2209+ZZ2209
-+006152 002660 ZZ2209=ZZ2209+ZZ2209
-+006152 005540 ZZ2209=ZZ2209+ZZ2209
-+006152 013300 ZZ2209=ZZ2209+ZZ2209
-+006152 026600 ZZ2209=ZZ2209+ZZ2209
-+006152 055400 ZZ2209=ZZ2209+ZZ2209
-+006152 133000 ZZ2209=ZZ2209+ZZ2209
-+006152 266000 ZZ2209=ZZ2209+ZZ2209
-+006152 010442 0 8192 -ZZ1209
-+006153 266000 0 ZZ2209
-- mark 4124, -502 / 2 corv
-+006154 776022 ZZ2210=ZZ2210+ZZ2210
-+006154 774044 ZZ2210=ZZ2210+ZZ2210
-+006154 770110 ZZ2210=ZZ2210+ZZ2210
-+006154 760220 ZZ2210=ZZ2210+ZZ2210
-+006154 740440 ZZ2210=ZZ2210+ZZ2210
-+006154 701100 ZZ2210=ZZ2210+ZZ2210
-+006154 602200 ZZ2210=ZZ2210+ZZ2210
-+006154 404400 ZZ2210=ZZ2210+ZZ2210
-+006154 007744 0 8192 -ZZ1210
-+006155 404400 0 ZZ2210
-- mark 4157, -387 / 4 corv
-+006156 776370 ZZ2211=ZZ2211+ZZ2211
-+006156 774760 ZZ2211=ZZ2211+ZZ2211
-+006156 771740 ZZ2211=ZZ2211+ZZ2211
-+006156 763700 ZZ2211=ZZ2211+ZZ2211
-+006156 747600 ZZ2211=ZZ2211+ZZ2211
-+006156 717400 ZZ2211=ZZ2211+ZZ2211
-+006156 637000 ZZ2211=ZZ2211+ZZ2211
-+006156 476000 ZZ2211=ZZ2211+ZZ2211
-+006156 007703 0 8192 -ZZ1211
-+006157 476000 0 ZZ2211
-- mark 4236, -363 / 7 corv
-+006160 776450 ZZ2212=ZZ2212+ZZ2212
-+006160 775120 ZZ2212=ZZ2212+ZZ2212
-+006160 772240 ZZ2212=ZZ2212+ZZ2212
-+006160 764500 ZZ2212=ZZ2212+ZZ2212
-+006160 751200 ZZ2212=ZZ2212+ZZ2212
-+006160 722400 ZZ2212=ZZ2212+ZZ2212
-+006160 645000 ZZ2212=ZZ2212+ZZ2212
-+006160 512000 ZZ2212=ZZ2212+ZZ2212
-+006160 007564 0 8192 -ZZ1212
-+006161 512000 0 ZZ2212
-- mark 4304, -21 /29 virg
-+006162 777724 ZZ2213=ZZ2213+ZZ2213
-+006162 777650 ZZ2213=ZZ2213+ZZ2213
-+006162 777520 ZZ2213=ZZ2213+ZZ2213
-+006162 777240 ZZ2213=ZZ2213+ZZ2213
-+006162 776500 ZZ2213=ZZ2213+ZZ2213
-+006162 775200 ZZ2213=ZZ2213+ZZ2213
-+006162 772400 ZZ2213=ZZ2213+ZZ2213
-+006162 765000 ZZ2213=ZZ2213+ZZ2213
-+006162 007460 0 8192 -ZZ1213
-+006163 765000 0 ZZ2213
-- mark 4384, 90 /43 virg
-+006164 000264 ZZ2214=ZZ2214+ZZ2214
-+006164 000550 ZZ2214=ZZ2214+ZZ2214
-+006164 001320 ZZ2214=ZZ2214+ZZ2214
-+006164 002640 ZZ2214=ZZ2214+ZZ2214
-+006164 005500 ZZ2214=ZZ2214+ZZ2214
-+006164 013200 ZZ2214=ZZ2214+ZZ2214
-+006164 026400 ZZ2214=ZZ2214+ZZ2214
-+006164 055000 ZZ2214=ZZ2214+ZZ2214
-+006164 007340 0 8192 -ZZ1214
-+006165 055000 0 ZZ2214
-- mark 4421, 262 /47 virg
-+006166 001014 ZZ2215=ZZ2215+ZZ2215
-+006166 002030 ZZ2215=ZZ2215+ZZ2215
-+006166 004060 ZZ2215=ZZ2215+ZZ2215
-+006166 010140 ZZ2215=ZZ2215+ZZ2215
-+006166 020300 ZZ2215=ZZ2215+ZZ2215
-+006166 040600 ZZ2215=ZZ2215+ZZ2215
-+006166 101400 ZZ2215=ZZ2215+ZZ2215
-+006166 203000 ZZ2215=ZZ2215+ZZ2215
-+006166 007273 0 8192 -ZZ1215
-+006167 203000 0 ZZ2215
-- mark 4606, -2 /79 virg
-+006170 777772 ZZ2216=ZZ2216+ZZ2216
-+006170 777764 ZZ2216=ZZ2216+ZZ2216
-+006170 777750 ZZ2216=ZZ2216+ZZ2216
-+006170 777720 ZZ2216=ZZ2216+ZZ2216
-+006170 777640 ZZ2216=ZZ2216+ZZ2216
-+006170 777500 ZZ2216=ZZ2216+ZZ2216
-+006170 777200 ZZ2216=ZZ2216+ZZ2216
-+006170 776400 ZZ2216=ZZ2216+ZZ2216
-+006170 007002 0 8192 -ZZ1216
-+006171 776400 0 ZZ2216
-- mark 4721, 430 / 8 boot
-+006172 001534 ZZ2217=ZZ2217+ZZ2217
-+006172 003270 ZZ2217=ZZ2217+ZZ2217
-+006172 006560 ZZ2217=ZZ2217+ZZ2217
-+006172 015340 ZZ2217=ZZ2217+ZZ2217
-+006172 032700 ZZ2217=ZZ2217+ZZ2217
-+006172 065600 ZZ2217=ZZ2217+ZZ2217
-+006172 153400 ZZ2217=ZZ2217+ZZ2217
-+006172 327000 ZZ2217=ZZ2217+ZZ2217
-+006172 006617 0 8192 -ZZ1217
-+006173 327000 0 ZZ2217
-- mark 5037, -356 / 9 libr
-+006174 776466 ZZ2218=ZZ2218+ZZ2218
-+006174 775154 ZZ2218=ZZ2218+ZZ2218
-+006174 772330 ZZ2218=ZZ2218+ZZ2218
-+006174 764660 ZZ2218=ZZ2218+ZZ2218
-+006174 751540 ZZ2218=ZZ2218+ZZ2218
-+006174 723300 ZZ2218=ZZ2218+ZZ2218
-+006174 646600 ZZ2218=ZZ2218+ZZ2218
-+006174 515400 ZZ2218=ZZ2218+ZZ2218
-+006174 006123 0 8192 -ZZ1218
-+006175 515400 0 ZZ2218
-- mark 5186, -205 /27 libr
-+006176 777144 ZZ2219=ZZ2219+ZZ2219
-+006176 776310 ZZ2219=ZZ2219+ZZ2219
-+006176 774620 ZZ2219=ZZ2219+ZZ2219
-+006176 771440 ZZ2219=ZZ2219+ZZ2219
-+006176 763100 ZZ2219=ZZ2219+ZZ2219
-+006176 746200 ZZ2219=ZZ2219+ZZ2219
-+006176 714400 ZZ2219=ZZ2219+ZZ2219
-+006176 631000 ZZ2219=ZZ2219+ZZ2219
-+006176 005676 0 8192 -ZZ1219
-+006177 631000 0 ZZ2219
-- mark 5344, 153 /24 serp
-+006200 000462 ZZ2220=ZZ2220+ZZ2220
-+006200 001144 ZZ2220=ZZ2220+ZZ2220
-+006200 002310 ZZ2220=ZZ2220+ZZ2220
-+006200 004620 ZZ2220=ZZ2220+ZZ2220
-+006200 011440 ZZ2220=ZZ2220+ZZ2220
-+006200 023100 ZZ2220=ZZ2220+ZZ2220
-+006200 046200 ZZ2220=ZZ2220+ZZ2220
-+006200 114400 ZZ2220=ZZ2220+ZZ2220
-+006200 005440 0 8192 -ZZ1220
-+006201 114400 0 ZZ2220
-- mark 5357, 358 /28 serp
-+006202 001314 ZZ2221=ZZ2221+ZZ2221
-+006202 002630 ZZ2221=ZZ2221+ZZ2221
-+006202 005460 ZZ2221=ZZ2221+ZZ2221
-+006202 013140 ZZ2221=ZZ2221+ZZ2221
-+006202 026300 ZZ2221=ZZ2221+ZZ2221
-+006202 054600 ZZ2221=ZZ2221+ZZ2221
-+006202 131400 ZZ2221=ZZ2221+ZZ2221
-+006202 263000 ZZ2221=ZZ2221+ZZ2221
-+006202 005423 0 8192 -ZZ1221
-+006203 263000 0 ZZ2221
-- mark 5373, -71 /32 serp
-+006204 777560 ZZ2222=ZZ2222+ZZ2222
-+006204 777340 ZZ2222=ZZ2222+ZZ2222
-+006204 776700 ZZ2222=ZZ2222+ZZ2222
-+006204 775600 ZZ2222=ZZ2222+ZZ2222
-+006204 773400 ZZ2222=ZZ2222+ZZ2222
-+006204 767000 ZZ2222=ZZ2222+ZZ2222
-+006204 756000 ZZ2222=ZZ2222+ZZ2222
-+006204 734000 ZZ2222=ZZ2222+ZZ2222
-+006204 005403 0 8192 -ZZ1222
-+006205 734000 0 ZZ2222
-- mark 5430, -508 / 7 scor
-+006206 776006 ZZ2223=ZZ2223+ZZ2223
-+006206 774014 ZZ2223=ZZ2223+ZZ2223
-+006206 770030 ZZ2223=ZZ2223+ZZ2223
-+006206 760060 ZZ2223=ZZ2223+ZZ2223
-+006206 740140 ZZ2223=ZZ2223+ZZ2223
-+006206 700300 ZZ2223=ZZ2223+ZZ2223
-+006206 600600 ZZ2223=ZZ2223+ZZ2223
-+006206 401400 ZZ2223=ZZ2223+ZZ2223
-+006206 005312 0 8192 -ZZ1223
-+006207 401400 0 ZZ2223
-- mark 5459, -445 / 8 scor
-+006210 776204 ZZ2224=ZZ2224+ZZ2224
-+006210 774410 ZZ2224=ZZ2224+ZZ2224
-+006210 771020 ZZ2224=ZZ2224+ZZ2224
-+006210 762040 ZZ2224=ZZ2224+ZZ2224
-+006210 744100 ZZ2224=ZZ2224+ZZ2224
-+006210 710200 ZZ2224=ZZ2224+ZZ2224
-+006210 620400 ZZ2224=ZZ2224+ZZ2224
-+006210 441000 ZZ2224=ZZ2224+ZZ2224
-+006210 005255 0 8192 -ZZ1224
-+006211 441000 0 ZZ2224
-- mark 5513, -78 / 1 ophi
-+006212 777542 ZZ2225=ZZ2225+ZZ2225
-+006212 777304 ZZ2225=ZZ2225+ZZ2225
-+006212 776610 ZZ2225=ZZ2225+ZZ2225
-+006212 775420 ZZ2225=ZZ2225+ZZ2225
-+006212 773040 ZZ2225=ZZ2225+ZZ2225
-+006212 766100 ZZ2225=ZZ2225+ZZ2225
-+006212 754200 ZZ2225=ZZ2225+ZZ2225
-+006212 730400 ZZ2225=ZZ2225+ZZ2225
-+006212 005167 0 8192 -ZZ1225
-+006213 730400 0 ZZ2225
-- mark 5536, -101 / 2 ophi
-+006214 777464 ZZ2226=ZZ2226+ZZ2226
-+006214 777150 ZZ2226=ZZ2226+ZZ2226
-+006214 776320 ZZ2226=ZZ2226+ZZ2226
-+006214 774640 ZZ2226=ZZ2226+ZZ2226
-+006214 771500 ZZ2226=ZZ2226+ZZ2226
-+006214 763200 ZZ2226=ZZ2226+ZZ2226
-+006214 746400 ZZ2226=ZZ2226+ZZ2226
-+006214 715000 ZZ2226=ZZ2226+ZZ2226
-+006214 005140 0 8192 -ZZ1226
-+006215 715000 0 ZZ2226
-- mark 5609, 494 /27 herc
-+006216 001734 ZZ2227=ZZ2227+ZZ2227
-+006216 003670 ZZ2227=ZZ2227+ZZ2227
-+006216 007560 ZZ2227=ZZ2227+ZZ2227
-+006216 017340 ZZ2227=ZZ2227+ZZ2227
-+006216 036700 ZZ2227=ZZ2227+ZZ2227
-+006216 075600 ZZ2227=ZZ2227+ZZ2227
-+006216 173400 ZZ2227=ZZ2227+ZZ2227
-+006216 367000 ZZ2227=ZZ2227+ZZ2227
-+006216 005027 0 8192 -ZZ1227
-+006217 367000 0 ZZ2227
-- mark 5641, -236 /13 ophi
-+006220 777046 ZZ2228=ZZ2228+ZZ2228
-+006220 776114 ZZ2228=ZZ2228+ZZ2228
-+006220 774230 ZZ2228=ZZ2228+ZZ2228
-+006220 770460 ZZ2228=ZZ2228+ZZ2228
-+006220 761140 ZZ2228=ZZ2228+ZZ2228
-+006220 742300 ZZ2228=ZZ2228+ZZ2228
-+006220 704600 ZZ2228=ZZ2228+ZZ2228
-+006220 611400 ZZ2228=ZZ2228+ZZ2228
-+006220 004767 0 8192 -ZZ1228
-+006221 611400 0 ZZ2228
-- mark 5828, -355 /35 ophi
-+006222 776470 ZZ2229=ZZ2229+ZZ2229
-+006222 775160 ZZ2229=ZZ2229+ZZ2229
-+006222 772340 ZZ2229=ZZ2229+ZZ2229
-+006222 764700 ZZ2229=ZZ2229+ZZ2229
-+006222 751600 ZZ2229=ZZ2229+ZZ2229
-+006222 723400 ZZ2229=ZZ2229+ZZ2229
-+006222 647000 ZZ2229=ZZ2229+ZZ2229
-+006222 516000 ZZ2229=ZZ2229+ZZ2229
-+006222 004474 0 8192 -ZZ1229
-+006223 516000 0 ZZ2229
-- mark 5860, 330 /64 herc
-+006224 001224 ZZ2230=ZZ2230+ZZ2230
-+006224 002450 ZZ2230=ZZ2230+ZZ2230
-+006224 005120 ZZ2230=ZZ2230+ZZ2230
-+006224 012240 ZZ2230=ZZ2230+ZZ2230
-+006224 024500 ZZ2230=ZZ2230+ZZ2230
-+006224 051200 ZZ2230=ZZ2230+ZZ2230
-+006224 122400 ZZ2230=ZZ2230+ZZ2230
-+006224 245000 ZZ2230=ZZ2230+ZZ2230
-+006224 004434 0 8192 -ZZ1230
-+006225 245000 0 ZZ2230
-- mark 5984, -349 /55 serp
-+006226 776504 ZZ2231=ZZ2231+ZZ2231
-+006226 775210 ZZ2231=ZZ2231+ZZ2231
-+006226 772420 ZZ2231=ZZ2231+ZZ2231
-+006226 765040 ZZ2231=ZZ2231+ZZ2231
-+006226 752100 ZZ2231=ZZ2231+ZZ2231
-+006226 724200 ZZ2231=ZZ2231+ZZ2231
-+006226 650400 ZZ2231=ZZ2231+ZZ2231
-+006226 521000 ZZ2231=ZZ2231+ZZ2231
-+006226 004240 0 8192 -ZZ1231
-+006227 521000 0 ZZ2231
-- mark 6047, 63 /62 ophi
-+006230 000176 ZZ2232=ZZ2232+ZZ2232
-+006230 000374 ZZ2232=ZZ2232+ZZ2232
-+006230 000770 ZZ2232=ZZ2232+ZZ2232
-+006230 001760 ZZ2232=ZZ2232+ZZ2232
-+006230 003740 ZZ2232=ZZ2232+ZZ2232
-+006230 007700 ZZ2232=ZZ2232+ZZ2232
-+006230 017600 ZZ2232=ZZ2232+ZZ2232
-+006230 037400 ZZ2232=ZZ2232+ZZ2232
-+006230 004141 0 8192 -ZZ1232
-+006231 037400 0 ZZ2232
-- mark 6107, -222 /64 ophi
-+006232 777102 ZZ2233=ZZ2233+ZZ2233
-+006232 776204 ZZ2233=ZZ2233+ZZ2233
-+006232 774410 ZZ2233=ZZ2233+ZZ2233
-+006232 771020 ZZ2233=ZZ2233+ZZ2233
-+006232 762040 ZZ2233=ZZ2233+ZZ2233
-+006232 744100 ZZ2233=ZZ2233+ZZ2233
-+006232 710200 ZZ2233=ZZ2233+ZZ2233
-+006232 620400 ZZ2233=ZZ2233+ZZ2233
-+006232 004045 0 8192 -ZZ1233
-+006233 620400 0 ZZ2233
-- mark 6159, 217 /72 ophi
-+006234 000662 ZZ2234=ZZ2234+ZZ2234
-+006234 001544 ZZ2234=ZZ2234+ZZ2234
-+006234 003310 ZZ2234=ZZ2234+ZZ2234
-+006234 006620 ZZ2234=ZZ2234+ZZ2234
-+006234 015440 ZZ2234=ZZ2234+ZZ2234
-+006234 033100 ZZ2234=ZZ2234+ZZ2234
-+006234 066200 ZZ2234=ZZ2234+ZZ2234
-+006234 154400 ZZ2234=ZZ2234+ZZ2234
-+006234 003761 0 8192 -ZZ1234
-+006235 154400 0 ZZ2234
-- mark 6236, -66 /58 serp
-+006236 777572 ZZ2235=ZZ2235+ZZ2235
-+006236 777364 ZZ2235=ZZ2235+ZZ2235
-+006236 776750 ZZ2235=ZZ2235+ZZ2235
-+006236 775720 ZZ2235=ZZ2235+ZZ2235
-+006236 773640 ZZ2235=ZZ2235+ZZ2235
-+006236 767500 ZZ2235=ZZ2235+ZZ2235
-+006236 757200 ZZ2235=ZZ2235+ZZ2235
-+006236 736400 ZZ2235=ZZ2235+ZZ2235
-+006236 003644 0 8192 -ZZ1235
-+006237 736400 0 ZZ2235
-- mark 6439, -483 /37 sgtr
-+006240 776070 ZZ2236=ZZ2236+ZZ2236
-+006240 774160 ZZ2236=ZZ2236+ZZ2236
-+006240 770340 ZZ2236=ZZ2236+ZZ2236
-+006240 760700 ZZ2236=ZZ2236+ZZ2236
-+006240 741600 ZZ2236=ZZ2236+ZZ2236
-+006240 703400 ZZ2236=ZZ2236+ZZ2236
-+006240 607000 ZZ2236=ZZ2236+ZZ2236
-+006240 416000 ZZ2236=ZZ2236+ZZ2236
-+006240 003331 0 8192 -ZZ1236
-+006241 416000 0 ZZ2236
-- mark 6490, 312 /17 aqil
-+006242 001160 ZZ2237=ZZ2237+ZZ2237
-+006242 002340 ZZ2237=ZZ2237+ZZ2237
-+006242 004700 ZZ2237=ZZ2237+ZZ2237
-+006242 011600 ZZ2237=ZZ2237+ZZ2237
-+006242 023400 ZZ2237=ZZ2237+ZZ2237
-+006242 047000 ZZ2237=ZZ2237+ZZ2237
-+006242 116000 ZZ2237=ZZ2237+ZZ2237
-+006242 234000 ZZ2237=ZZ2237+ZZ2237
-+006242 003246 0 8192 -ZZ1237
-+006243 234000 0 ZZ2237
-- mark 6491, -115 /16 aqil
-+006244 777430 ZZ2238=ZZ2238+ZZ2238
-+006244 777060 ZZ2238=ZZ2238+ZZ2238
-+006244 776140 ZZ2238=ZZ2238+ZZ2238
-+006244 774300 ZZ2238=ZZ2238+ZZ2238
-+006244 770600 ZZ2238=ZZ2238+ZZ2238
-+006244 761400 ZZ2238=ZZ2238+ZZ2238
-+006244 743000 ZZ2238=ZZ2238+ZZ2238
-+006244 706000 ZZ2238=ZZ2238+ZZ2238
-+006244 003245 0 8192 -ZZ1238
-+006245 706000 0 ZZ2238
-- mark 6507, -482 /41 sgtr
-+006246 776072 ZZ2239=ZZ2239+ZZ2239
-+006246 774164 ZZ2239=ZZ2239+ZZ2239
-+006246 770350 ZZ2239=ZZ2239+ZZ2239
-+006246 760720 ZZ2239=ZZ2239+ZZ2239
-+006246 741640 ZZ2239=ZZ2239+ZZ2239
-+006246 703500 ZZ2239=ZZ2239+ZZ2239
-+006246 607200 ZZ2239=ZZ2239+ZZ2239
-+006246 416400 ZZ2239=ZZ2239+ZZ2239
-+006246 003225 0 8192 -ZZ1239
-+006247 416400 0 ZZ2239
-- mark 6602, 66 /30 aqil
-+006250 000204 ZZ2240=ZZ2240+ZZ2240
-+006250 000410 ZZ2240=ZZ2240+ZZ2240
-+006250 001020 ZZ2240=ZZ2240+ZZ2240
-+006250 002040 ZZ2240=ZZ2240+ZZ2240
-+006250 004100 ZZ2240=ZZ2240+ZZ2240
-+006250 010200 ZZ2240=ZZ2240+ZZ2240
-+006250 020400 ZZ2240=ZZ2240+ZZ2240
-+006250 041000 ZZ2240=ZZ2240+ZZ2240
-+006250 003066 0 8192 -ZZ1240
-+006251 041000 0 ZZ2240
-- mark 6721, 236 /50 aqil
-+006252 000730 ZZ2241=ZZ2241+ZZ2241
-+006252 001660 ZZ2241=ZZ2241+ZZ2241
-+006252 003540 ZZ2241=ZZ2241+ZZ2241
-+006252 007300 ZZ2241=ZZ2241+ZZ2241
-+006252 016600 ZZ2241=ZZ2241+ZZ2241
-+006252 035400 ZZ2241=ZZ2241+ZZ2241
-+006252 073000 ZZ2241=ZZ2241+ZZ2241
-+006252 166000 ZZ2241=ZZ2241+ZZ2241
-+006252 002677 0 8192 -ZZ1241
-+006253 166000 0 ZZ2241
-- mark 6794, 437 /12 sgte
-+006254 001552 ZZ2242=ZZ2242+ZZ2242
-+006254 003324 ZZ2242=ZZ2242+ZZ2242
-+006254 006650 ZZ2242=ZZ2242+ZZ2242
-+006254 015520 ZZ2242=ZZ2242+ZZ2242
-+006254 033240 ZZ2242=ZZ2242+ZZ2242
-+006254 066500 ZZ2242=ZZ2242+ZZ2242
-+006254 155200 ZZ2242=ZZ2242+ZZ2242
-+006254 332400 ZZ2242=ZZ2242+ZZ2242
-+006254 002566 0 8192 -ZZ1242
-+006255 332400 0 ZZ2242
-- mark 6862, -25 /65 aqil
-+006256 777714 ZZ2243=ZZ2243+ZZ2243
-+006256 777630 ZZ2243=ZZ2243+ZZ2243
-+006256 777460 ZZ2243=ZZ2243+ZZ2243
-+006256 777140 ZZ2243=ZZ2243+ZZ2243
-+006256 776300 ZZ2243=ZZ2243+ZZ2243
-+006256 774600 ZZ2243=ZZ2243+ZZ2243
-+006256 771400 ZZ2243=ZZ2243+ZZ2243
-+006256 763000 ZZ2243=ZZ2243+ZZ2243
-+006256 002462 0 8192 -ZZ1243
-+006257 763000 0 ZZ2243
-- mark 6914, -344 / 9 capr
-+006260 776516 ZZ2244=ZZ2244+ZZ2244
-+006260 775234 ZZ2244=ZZ2244+ZZ2244
-+006260 772470 ZZ2244=ZZ2244+ZZ2244
-+006260 765160 ZZ2244=ZZ2244+ZZ2244
-+006260 752340 ZZ2244=ZZ2244+ZZ2244
-+006260 724700 ZZ2244=ZZ2244+ZZ2244
-+006260 651600 ZZ2244=ZZ2244+ZZ2244
-+006260 523400 ZZ2244=ZZ2244+ZZ2244
-+006260 002376 0 8192 -ZZ1244
-+006261 523400 0 ZZ2244
-- mark 7014, 324 / 6 dlph
-+006262 001210 ZZ2245=ZZ2245+ZZ2245
-+006262 002420 ZZ2245=ZZ2245+ZZ2245
-+006262 005040 ZZ2245=ZZ2245+ZZ2245
-+006262 012100 ZZ2245=ZZ2245+ZZ2245
-+006262 024200 ZZ2245=ZZ2245+ZZ2245
-+006262 050400 ZZ2245=ZZ2245+ZZ2245
-+006262 121000 ZZ2245=ZZ2245+ZZ2245
-+006262 242000 ZZ2245=ZZ2245+ZZ2245
-+006262 002232 0 8192 -ZZ1245
-+006263 242000 0 ZZ2245
-- mark 7318, -137 /22 aqar
-+006264 777354 ZZ2246=ZZ2246+ZZ2246
-+006264 776730 ZZ2246=ZZ2246+ZZ2246
-+006264 775660 ZZ2246=ZZ2246+ZZ2246
-+006264 773540 ZZ2246=ZZ2246+ZZ2246
-+006264 767300 ZZ2246=ZZ2246+ZZ2246
-+006264 756600 ZZ2246=ZZ2246+ZZ2246
-+006264 735400 ZZ2246=ZZ2246+ZZ2246
-+006264 673000 ZZ2246=ZZ2246+ZZ2246
-+006264 001552 0 8192 -ZZ1246
-+006265 673000 0 ZZ2246
-- mark 7391, 214 / 8 pegs
-+006266 000654 ZZ2247=ZZ2247+ZZ2247
-+006266 001530 ZZ2247=ZZ2247+ZZ2247
-+006266 003260 ZZ2247=ZZ2247+ZZ2247
-+006266 006540 ZZ2247=ZZ2247+ZZ2247
-+006266 015300 ZZ2247=ZZ2247+ZZ2247
-+006266 032600 ZZ2247=ZZ2247+ZZ2247
-+006266 065400 ZZ2247=ZZ2247+ZZ2247
-+006266 153000 ZZ2247=ZZ2247+ZZ2247
-+006266 001441 0 8192 -ZZ1247
-+006267 153000 0 ZZ2247
-- mark 7404, -377 /49 capr
-+006270 776414 ZZ2248=ZZ2248+ZZ2248
-+006270 775030 ZZ2248=ZZ2248+ZZ2248
-+006270 772060 ZZ2248=ZZ2248+ZZ2248
-+006270 764140 ZZ2248=ZZ2248+ZZ2248
-+006270 750300 ZZ2248=ZZ2248+ZZ2248
-+006270 720600 ZZ2248=ZZ2248+ZZ2248
-+006270 641400 ZZ2248=ZZ2248+ZZ2248
-+006270 503000 ZZ2248=ZZ2248+ZZ2248
-+006270 001424 0 8192 -ZZ1248
-+006271 503000 0 ZZ2248
-- mark 7513, -18 /34 aqar
-+006272 777732 ZZ2249=ZZ2249+ZZ2249
-+006272 777664 ZZ2249=ZZ2249+ZZ2249
-+006272 777550 ZZ2249=ZZ2249+ZZ2249
-+006272 777320 ZZ2249=ZZ2249+ZZ2249
-+006272 776640 ZZ2249=ZZ2249+ZZ2249
-+006272 775500 ZZ2249=ZZ2249+ZZ2249
-+006272 773200 ZZ2249=ZZ2249+ZZ2249
-+006272 766400 ZZ2249=ZZ2249+ZZ2249
-+006272 001247 0 8192 -ZZ1249
-+006273 766400 0 ZZ2249
-- mark 7539, 130 /26 pegs
-+006274 000404 ZZ2250=ZZ2250+ZZ2250
-+006274 001010 ZZ2250=ZZ2250+ZZ2250
-+006274 002020 ZZ2250=ZZ2250+ZZ2250
-+006274 004040 ZZ2250=ZZ2250+ZZ2250
-+006274 010100 ZZ2250=ZZ2250+ZZ2250
-+006274 020200 ZZ2250=ZZ2250+ZZ2250
-+006274 040400 ZZ2250=ZZ2250+ZZ2250
-+006274 101000 ZZ2250=ZZ2250+ZZ2250
-+006274 001215 0 8192 -ZZ1250
-+006275 101000 0 ZZ2250
-- mark 7644, -12 /55 aqar
-+006276 777746 ZZ2251=ZZ2251+ZZ2251
-+006276 777714 ZZ2251=ZZ2251+ZZ2251
-+006276 777630 ZZ2251=ZZ2251+ZZ2251
-+006276 777460 ZZ2251=ZZ2251+ZZ2251
-+006276 777140 ZZ2251=ZZ2251+ZZ2251
-+006276 776300 ZZ2251=ZZ2251+ZZ2251
-+006276 774600 ZZ2251=ZZ2251+ZZ2251
-+006276 771400 ZZ2251=ZZ2251+ZZ2251
-+006276 001044 0 8192 -ZZ1251
-+006277 771400 0 ZZ2251
-- mark 7717, 235 /42 pegs
-+006300 000726 ZZ2252=ZZ2252+ZZ2252
-+006300 001654 ZZ2252=ZZ2252+ZZ2252
-+006300 003530 ZZ2252=ZZ2252+ZZ2252
-+006300 007260 ZZ2252=ZZ2252+ZZ2252
-+006300 016540 ZZ2252=ZZ2252+ZZ2252
-+006300 035300 ZZ2252=ZZ2252+ZZ2252
-+006300 072600 ZZ2252=ZZ2252+ZZ2252
-+006300 165400 ZZ2252=ZZ2252+ZZ2252
-+006300 000733 0 8192 -ZZ1252
-+006301 165400 0 ZZ2252
-- mark 7790, -372 /76 aqar
-+006302 776426 ZZ2253=ZZ2253+ZZ2253
-+006302 775054 ZZ2253=ZZ2253+ZZ2253
-+006302 772130 ZZ2253=ZZ2253+ZZ2253
-+006302 764260 ZZ2253=ZZ2253+ZZ2253
-+006302 750540 ZZ2253=ZZ2253+ZZ2253
-+006302 721300 ZZ2253=ZZ2253+ZZ2253
-+006302 642600 ZZ2253=ZZ2253+ZZ2253
-+006302 505400 ZZ2253=ZZ2253+ZZ2253
-+006302 000622 0 8192 -ZZ1253
-+006303 505400 0 ZZ2253
- 006304 3q,
-- mark 7849, 334 /54 pegs, markab
-+006304 001234 ZZ2254=ZZ2254+ZZ2254
-+006304 002470 ZZ2254=ZZ2254+ZZ2254
-+006304 005160 ZZ2254=ZZ2254+ZZ2254
-+006304 012340 ZZ2254=ZZ2254+ZZ2254
-+006304 024700 ZZ2254=ZZ2254+ZZ2254
-+006304 051600 ZZ2254=ZZ2254+ZZ2254
-+006304 123400 ZZ2254=ZZ2254+ZZ2254
-+006304 247000 ZZ2254=ZZ2254+ZZ2254
-+006304 000527 0 8192 -ZZ1254
-+006305 247000 0 ZZ2254
- 006306 4j,
-- mark 1, -143 /33 pisc
-+006306 777340 ZZ2255=ZZ2255+ZZ2255
-+006306 776700 ZZ2255=ZZ2255+ZZ2255
-+006306 775600 ZZ2255=ZZ2255+ZZ2255
-+006306 773400 ZZ2255=ZZ2255+ZZ2255
-+006306 767000 ZZ2255=ZZ2255+ZZ2255
-+006306 756000 ZZ2255=ZZ2255+ZZ2255
-+006306 734000 ZZ2255=ZZ2255+ZZ2255
-+006306 670000 ZZ2255=ZZ2255+ZZ2255
-+006306 017777 0 8192 -ZZ1255
-+006307 670000 0 ZZ2255
-- mark 54, 447 /89 pegs
-+006310 001576 ZZ2256=ZZ2256+ZZ2256
-+006310 003374 ZZ2256=ZZ2256+ZZ2256
-+006310 006770 ZZ2256=ZZ2256+ZZ2256
-+006310 015760 ZZ2256=ZZ2256+ZZ2256
-+006310 033740 ZZ2256=ZZ2256+ZZ2256
-+006310 067700 ZZ2256=ZZ2256+ZZ2256
-+006310 157600 ZZ2256=ZZ2256+ZZ2256
-+006310 337400 ZZ2256=ZZ2256+ZZ2256
-+006310 017712 0 8192 -ZZ1256
-+006311 337400 0 ZZ2256
-- mark 54, -443 /7 ceti
-+006312 776210 ZZ2257=ZZ2257+ZZ2257
-+006312 774420 ZZ2257=ZZ2257+ZZ2257
-+006312 771040 ZZ2257=ZZ2257+ZZ2257
-+006312 762100 ZZ2257=ZZ2257+ZZ2257
-+006312 744200 ZZ2257=ZZ2257+ZZ2257
-+006312 710400 ZZ2257=ZZ2257+ZZ2257
-+006312 621000 ZZ2257=ZZ2257+ZZ2257
-+006312 442000 ZZ2257=ZZ2257+ZZ2257
-+006312 017712 0 8192 -ZZ1257
-+006313 442000 0 ZZ2257
-- mark 82, -214 /8 ceti
-+006314 777122 ZZ2258=ZZ2258+ZZ2258
-+006314 776244 ZZ2258=ZZ2258+ZZ2258
-+006314 774510 ZZ2258=ZZ2258+ZZ2258
-+006314 771220 ZZ2258=ZZ2258+ZZ2258
-+006314 762440 ZZ2258=ZZ2258+ZZ2258
-+006314 745100 ZZ2258=ZZ2258+ZZ2258
-+006314 712200 ZZ2258=ZZ2258+ZZ2258
-+006314 624400 ZZ2258=ZZ2258+ZZ2258
-+006314 017656 0 8192 -ZZ1258
-+006315 624400 0 ZZ2258
-- mark 223, -254 /17 ceti
-+006316 777002 ZZ2259=ZZ2259+ZZ2259
-+006316 776004 ZZ2259=ZZ2259+ZZ2259
-+006316 774010 ZZ2259=ZZ2259+ZZ2259
-+006316 770020 ZZ2259=ZZ2259+ZZ2259
-+006316 760040 ZZ2259=ZZ2259+ZZ2259
-+006316 740100 ZZ2259=ZZ2259+ZZ2259
-+006316 700200 ZZ2259=ZZ2259+ZZ2259
-+006316 600400 ZZ2259=ZZ2259+ZZ2259
-+006316 017441 0 8192 -ZZ1259
-+006317 600400 0 ZZ2259
-- mark 248, 160 /63 pisc
-+006320 000500 ZZ2260=ZZ2260+ZZ2260
-+006320 001200 ZZ2260=ZZ2260+ZZ2260
-+006320 002400 ZZ2260=ZZ2260+ZZ2260
-+006320 005000 ZZ2260=ZZ2260+ZZ2260
-+006320 012000 ZZ2260=ZZ2260+ZZ2260
-+006320 024000 ZZ2260=ZZ2260+ZZ2260
-+006320 050000 ZZ2260=ZZ2260+ZZ2260
-+006320 120000 ZZ2260=ZZ2260+ZZ2260
-+006320 017410 0 8192 -ZZ1260
-+006321 120000 0 ZZ2260
-- mark 273, -38 /20 ceti
-+006322 777662 ZZ2261=ZZ2261+ZZ2261
-+006322 777544 ZZ2261=ZZ2261+ZZ2261
-+006322 777310 ZZ2261=ZZ2261+ZZ2261
-+006322 776620 ZZ2261=ZZ2261+ZZ2261
-+006322 775440 ZZ2261=ZZ2261+ZZ2261
-+006322 773100 ZZ2261=ZZ2261+ZZ2261
-+006322 766200 ZZ2261=ZZ2261+ZZ2261
-+006322 754400 ZZ2261=ZZ2261+ZZ2261
-+006322 017357 0 8192 -ZZ1261
-+006323 754400 0 ZZ2261
-- mark 329, 167 /71 pisc
-+006324 000516 ZZ2262=ZZ2262+ZZ2262
-+006324 001234 ZZ2262=ZZ2262+ZZ2262
-+006324 002470 ZZ2262=ZZ2262+ZZ2262
-+006324 005160 ZZ2262=ZZ2262+ZZ2262
-+006324 012340 ZZ2262=ZZ2262+ZZ2262
-+006324 024700 ZZ2262=ZZ2262+ZZ2262
-+006324 051600 ZZ2262=ZZ2262+ZZ2262
-+006324 123400 ZZ2262=ZZ2262+ZZ2262
-+006324 017267 0 8192 -ZZ1262
-+006325 123400 0 ZZ2262
-- mark 376, 467 /84 pisc
-+006326 001646 ZZ2263=ZZ2263+ZZ2263
-+006326 003514 ZZ2263=ZZ2263+ZZ2263
-+006326 007230 ZZ2263=ZZ2263+ZZ2263
-+006326 016460 ZZ2263=ZZ2263+ZZ2263
-+006326 035140 ZZ2263=ZZ2263+ZZ2263
-+006326 072300 ZZ2263=ZZ2263+ZZ2263
-+006326 164600 ZZ2263=ZZ2263+ZZ2263
-+006326 351400 ZZ2263=ZZ2263+ZZ2263
-+006326 017210 0 8192 -ZZ1263
-+006327 351400 0 ZZ2263
-- mark 450, -198 /45 ceti
-+006330 777162 ZZ2264=ZZ2264+ZZ2264
-+006330 776344 ZZ2264=ZZ2264+ZZ2264
-+006330 774710 ZZ2264=ZZ2264+ZZ2264
-+006330 771620 ZZ2264=ZZ2264+ZZ2264
-+006330 763440 ZZ2264=ZZ2264+ZZ2264
-+006330 747100 ZZ2264=ZZ2264+ZZ2264
-+006330 716200 ZZ2264=ZZ2264+ZZ2264
-+006330 634400 ZZ2264=ZZ2264+ZZ2264
-+006330 017076 0 8192 -ZZ1264
-+006331 634400 0 ZZ2264
-- mark 548, 113 /106 pisc
-+006332 000342 ZZ2265=ZZ2265+ZZ2265
-+006332 000704 ZZ2265=ZZ2265+ZZ2265
-+006332 001610 ZZ2265=ZZ2265+ZZ2265
-+006332 003420 ZZ2265=ZZ2265+ZZ2265
-+006332 007040 ZZ2265=ZZ2265+ZZ2265
-+006332 016100 ZZ2265=ZZ2265+ZZ2265
-+006332 034200 ZZ2265=ZZ2265+ZZ2265
-+006332 070400 ZZ2265=ZZ2265+ZZ2265
-+006332 016734 0 8192 -ZZ1265
-+006333 070400 0 ZZ2265
-- mark 570, 197 /110 pisc
-+006334 000612 ZZ2266=ZZ2266+ZZ2266
-+006334 001424 ZZ2266=ZZ2266+ZZ2266
-+006334 003050 ZZ2266=ZZ2266+ZZ2266
-+006334 006120 ZZ2266=ZZ2266+ZZ2266
-+006334 014240 ZZ2266=ZZ2266+ZZ2266
-+006334 030500 ZZ2266=ZZ2266+ZZ2266
-+006334 061200 ZZ2266=ZZ2266+ZZ2266
-+006334 142400 ZZ2266=ZZ2266+ZZ2266
-+006334 016706 0 8192 -ZZ1266
-+006335 142400 0 ZZ2266
-- mark 595, -255 /53 ceti
-+006336 777000 ZZ2267=ZZ2267+ZZ2267
-+006336 776000 ZZ2267=ZZ2267+ZZ2267
-+006336 774000 ZZ2267=ZZ2267+ZZ2267
-+006336 770000 ZZ2267=ZZ2267+ZZ2267
-+006336 760000 ZZ2267=ZZ2267+ZZ2267
-+006336 740000 ZZ2267=ZZ2267+ZZ2267
-+006336 700000 ZZ2267=ZZ2267+ZZ2267
-+006336 600000 ZZ2267=ZZ2267+ZZ2267
-+006336 016655 0 8192 -ZZ1267
-+006337 600000 0 ZZ2267
-- mark 606, -247 /55 ceti
-+006340 777020 ZZ2268=ZZ2268+ZZ2268
-+006340 776040 ZZ2268=ZZ2268+ZZ2268
-+006340 774100 ZZ2268=ZZ2268+ZZ2268
-+006340 770200 ZZ2268=ZZ2268+ZZ2268
-+006340 760400 ZZ2268=ZZ2268+ZZ2268
-+006340 741000 ZZ2268=ZZ2268+ZZ2268
-+006340 702000 ZZ2268=ZZ2268+ZZ2268
-+006340 604000 ZZ2268=ZZ2268+ZZ2268
-+006340 016642 0 8192 -ZZ1268
-+006341 604000 0 ZZ2268
-- mark 615, 428 / 5 arie
-+006342 001530 ZZ2269=ZZ2269+ZZ2269
-+006342 003260 ZZ2269=ZZ2269+ZZ2269
-+006342 006540 ZZ2269=ZZ2269+ZZ2269
-+006342 015300 ZZ2269=ZZ2269+ZZ2269
-+006342 032600 ZZ2269=ZZ2269+ZZ2269
-+006342 065400 ZZ2269=ZZ2269+ZZ2269
-+006342 153000 ZZ2269=ZZ2269+ZZ2269
-+006342 326000 ZZ2269=ZZ2269+ZZ2269
-+006342 016631 0 8192 -ZZ1269
-+006343 326000 0 ZZ2269
-- mark 617, 61 /14 pisc
-+006344 000172 ZZ2270=ZZ2270+ZZ2270
-+006344 000364 ZZ2270=ZZ2270+ZZ2270
-+006344 000750 ZZ2270=ZZ2270+ZZ2270
-+006344 001720 ZZ2270=ZZ2270+ZZ2270
-+006344 003640 ZZ2270=ZZ2270+ZZ2270
-+006344 007500 ZZ2270=ZZ2270+ZZ2270
-+006344 017200 ZZ2270=ZZ2270+ZZ2270
-+006344 036400 ZZ2270=ZZ2270+ZZ2270
-+006344 016627 0 8192 -ZZ1270
-+006345 036400 0 ZZ2270
-- mark 656, -491 /59 ceti
-+006346 776050 ZZ2271=ZZ2271+ZZ2271
-+006346 774120 ZZ2271=ZZ2271+ZZ2271
-+006346 770240 ZZ2271=ZZ2271+ZZ2271
-+006346 760500 ZZ2271=ZZ2271+ZZ2271
-+006346 741200 ZZ2271=ZZ2271+ZZ2271
-+006346 702400 ZZ2271=ZZ2271+ZZ2271
-+006346 605000 ZZ2271=ZZ2271+ZZ2271
-+006346 412000 ZZ2271=ZZ2271+ZZ2271
-+006346 016560 0 8192 -ZZ1271
-+006347 412000 0 ZZ2271
-- mark 665, 52 /113 pisc
-+006350 000150 ZZ2272=ZZ2272+ZZ2272
-+006350 000320 ZZ2272=ZZ2272+ZZ2272
-+006350 000640 ZZ2272=ZZ2272+ZZ2272
-+006350 001500 ZZ2272=ZZ2272+ZZ2272
-+006350 003200 ZZ2272=ZZ2272+ZZ2272
-+006350 006400 ZZ2272=ZZ2272+ZZ2272
-+006350 015000 ZZ2272=ZZ2272+ZZ2272
-+006350 032000 ZZ2272=ZZ2272+ZZ2272
-+006350 016547 0 8192 -ZZ1272
-+006351 032000 0 ZZ2272
-- mark 727, 191 /65 ceti
-+006352 000576 ZZ2273=ZZ2273+ZZ2273
-+006352 001374 ZZ2273=ZZ2273+ZZ2273
-+006352 002770 ZZ2273=ZZ2273+ZZ2273
-+006352 005760 ZZ2273=ZZ2273+ZZ2273
-+006352 013740 ZZ2273=ZZ2273+ZZ2273
-+006352 027700 ZZ2273=ZZ2273+ZZ2273
-+006352 057600 ZZ2273=ZZ2273+ZZ2273
-+006352 137400 ZZ2273=ZZ2273+ZZ2273
-+006352 016451 0 8192 -ZZ1273
-+006353 137400 0 ZZ2273
-- mark 803, -290 /72 ceti
-+006354 776672 ZZ2274=ZZ2274+ZZ2274
-+006354 775564 ZZ2274=ZZ2274+ZZ2274
-+006354 773350 ZZ2274=ZZ2274+ZZ2274
-+006354 766720 ZZ2274=ZZ2274+ZZ2274
-+006354 755640 ZZ2274=ZZ2274+ZZ2274
-+006354 733500 ZZ2274=ZZ2274+ZZ2274
-+006354 667200 ZZ2274=ZZ2274+ZZ2274
-+006354 556400 ZZ2274=ZZ2274+ZZ2274
-+006354 016335 0 8192 -ZZ1274
-+006355 556400 0 ZZ2274
-- mark 813, 182 /73 ceti
-+006356 000554 ZZ2275=ZZ2275+ZZ2275
-+006356 001330 ZZ2275=ZZ2275+ZZ2275
-+006356 002660 ZZ2275=ZZ2275+ZZ2275
-+006356 005540 ZZ2275=ZZ2275+ZZ2275
-+006356 013300 ZZ2275=ZZ2275+ZZ2275
-+006356 026600 ZZ2275=ZZ2275+ZZ2275
-+006356 055400 ZZ2275=ZZ2275+ZZ2275
-+006356 133000 ZZ2275=ZZ2275+ZZ2275
-+006356 016323 0 8192 -ZZ1275
-+006357 133000 0 ZZ2275
-- mark 838, -357 /76 ceti
-+006360 776464 ZZ2276=ZZ2276+ZZ2276
-+006360 775150 ZZ2276=ZZ2276+ZZ2276
-+006360 772320 ZZ2276=ZZ2276+ZZ2276
-+006360 764640 ZZ2276=ZZ2276+ZZ2276
-+006360 751500 ZZ2276=ZZ2276+ZZ2276
-+006360 723200 ZZ2276=ZZ2276+ZZ2276
-+006360 646400 ZZ2276=ZZ2276+ZZ2276
-+006360 515000 ZZ2276=ZZ2276+ZZ2276
-+006360 016272 0 8192 -ZZ1276
-+006361 515000 0 ZZ2276
-- mark 878, -2 /82 ceti
-+006362 777772 ZZ2277=ZZ2277+ZZ2277
-+006362 777764 ZZ2277=ZZ2277+ZZ2277
-+006362 777750 ZZ2277=ZZ2277+ZZ2277
-+006362 777720 ZZ2277=ZZ2277+ZZ2277
-+006362 777640 ZZ2277=ZZ2277+ZZ2277
-+006362 777500 ZZ2277=ZZ2277+ZZ2277
-+006362 777200 ZZ2277=ZZ2277+ZZ2277
-+006362 776400 ZZ2277=ZZ2277+ZZ2277
-+006362 016222 0 8192 -ZZ1277
-+006363 776400 0 ZZ2277
-- mark 907, -340 /89 ceti
-+006364 776526 ZZ2278=ZZ2278+ZZ2278
-+006364 775254 ZZ2278=ZZ2278+ZZ2278
-+006364 772530 ZZ2278=ZZ2278+ZZ2278
-+006364 765260 ZZ2278=ZZ2278+ZZ2278
-+006364 752540 ZZ2278=ZZ2278+ZZ2278
-+006364 725300 ZZ2278=ZZ2278+ZZ2278
-+006364 652600 ZZ2278=ZZ2278+ZZ2278
-+006364 525400 ZZ2278=ZZ2278+ZZ2278
-+006364 016165 0 8192 -ZZ1278
-+006365 525400 0 ZZ2278
-- mark 908, 221 /87 ceti
-+006366 000672 ZZ2279=ZZ2279+ZZ2279
-+006366 001564 ZZ2279=ZZ2279+ZZ2279
-+006366 003350 ZZ2279=ZZ2279+ZZ2279
-+006366 006720 ZZ2279=ZZ2279+ZZ2279
-+006366 015640 ZZ2279=ZZ2279+ZZ2279
-+006366 033500 ZZ2279=ZZ2279+ZZ2279
-+006366 067200 ZZ2279=ZZ2279+ZZ2279
-+006366 156400 ZZ2279=ZZ2279+ZZ2279
-+006366 016164 0 8192 -ZZ1279
-+006367 156400 0 ZZ2279
-- mark 913, -432 / 1 erid
-+006370 776236 ZZ2280=ZZ2280+ZZ2280
-+006370 774474 ZZ2280=ZZ2280+ZZ2280
-+006370 771170 ZZ2280=ZZ2280+ZZ2280
-+006370 762360 ZZ2280=ZZ2280+ZZ2280
-+006370 744740 ZZ2280=ZZ2280+ZZ2280
-+006370 711700 ZZ2280=ZZ2280+ZZ2280
-+006370 623600 ZZ2280=ZZ2280+ZZ2280
-+006370 447400 ZZ2280=ZZ2280+ZZ2280
-+006370 016157 0 8192 -ZZ1280
-+006371 447400 0 ZZ2280
-- mark 947, -487 / 2 erid
-+006372 776060 ZZ2281=ZZ2281+ZZ2281
-+006372 774140 ZZ2281=ZZ2281+ZZ2281
-+006372 770300 ZZ2281=ZZ2281+ZZ2281
-+006372 760600 ZZ2281=ZZ2281+ZZ2281
-+006372 741400 ZZ2281=ZZ2281+ZZ2281
-+006372 703000 ZZ2281=ZZ2281+ZZ2281
-+006372 606000 ZZ2281=ZZ2281+ZZ2281
-+006372 414000 ZZ2281=ZZ2281+ZZ2281
-+006372 016115 0 8192 -ZZ1281
-+006373 414000 0 ZZ2281
-- mark 976, -212 / 3 erid
-+006374 777126 ZZ2282=ZZ2282+ZZ2282
-+006374 776254 ZZ2282=ZZ2282+ZZ2282
-+006374 774530 ZZ2282=ZZ2282+ZZ2282
-+006374 771260 ZZ2282=ZZ2282+ZZ2282
-+006374 762540 ZZ2282=ZZ2282+ZZ2282
-+006374 745300 ZZ2282=ZZ2282+ZZ2282
-+006374 712600 ZZ2282=ZZ2282+ZZ2282
-+006374 625400 ZZ2282=ZZ2282+ZZ2282
-+006374 016060 0 8192 -ZZ1282
-+006375 625400 0 ZZ2282
-- mark 992, 194 /91 ceti
-+006376 000604 ZZ2283=ZZ2283+ZZ2283
-+006376 001410 ZZ2283=ZZ2283+ZZ2283
-+006376 003020 ZZ2283=ZZ2283+ZZ2283
-+006376 006040 ZZ2283=ZZ2283+ZZ2283
-+006376 014100 ZZ2283=ZZ2283+ZZ2283
-+006376 030200 ZZ2283=ZZ2283+ZZ2283
-+006376 060400 ZZ2283=ZZ2283+ZZ2283
-+006376 141000 ZZ2283=ZZ2283+ZZ2283
-+006376 016040 0 8192 -ZZ1283
-+006377 141000 0 ZZ2283
-- mark 1058, 440 /57 arie
-+006400 001560 ZZ2284=ZZ2284+ZZ2284
-+006400 003340 ZZ2284=ZZ2284+ZZ2284
-+006400 006700 ZZ2284=ZZ2284+ZZ2284
-+006400 015600 ZZ2284=ZZ2284+ZZ2284
-+006400 033400 ZZ2284=ZZ2284+ZZ2284
-+006400 067000 ZZ2284=ZZ2284+ZZ2284
-+006400 156000 ZZ2284=ZZ2284+ZZ2284
-+006400 334000 ZZ2284=ZZ2284+ZZ2284
-+006400 015736 0 8192 -ZZ1284
-+006401 334000 0 ZZ2284
-- mark 1076, 470 /58 arie
-+006402 001654 ZZ2285=ZZ2285+ZZ2285
-+006402 003530 ZZ2285=ZZ2285+ZZ2285
-+006402 007260 ZZ2285=ZZ2285+ZZ2285
-+006402 016540 ZZ2285=ZZ2285+ZZ2285
-+006402 035300 ZZ2285=ZZ2285+ZZ2285
-+006402 072600 ZZ2285=ZZ2285+ZZ2285
-+006402 165400 ZZ2285=ZZ2285+ZZ2285
-+006402 353000 ZZ2285=ZZ2285+ZZ2285
-+006402 015714 0 8192 -ZZ1285
-+006403 353000 0 ZZ2285
-- mark 1087, -209 /13 erid
-+006404 777134 ZZ2286=ZZ2286+ZZ2286
-+006404 776270 ZZ2286=ZZ2286+ZZ2286
-+006404 774560 ZZ2286=ZZ2286+ZZ2286
-+006404 771340 ZZ2286=ZZ2286+ZZ2286
-+006404 762700 ZZ2286=ZZ2286+ZZ2286
-+006404 745600 ZZ2286=ZZ2286+ZZ2286
-+006404 713400 ZZ2286=ZZ2286+ZZ2286
-+006404 627000 ZZ2286=ZZ2286+ZZ2286
-+006404 015701 0 8192 -ZZ1286
-+006405 627000 0 ZZ2286
-- mark 1104, 68 /96 ceti
-+006406 000210 ZZ2287=ZZ2287+ZZ2287
-+006406 000420 ZZ2287=ZZ2287+ZZ2287
-+006406 001040 ZZ2287=ZZ2287+ZZ2287
-+006406 002100 ZZ2287=ZZ2287+ZZ2287
-+006406 004200 ZZ2287=ZZ2287+ZZ2287
-+006406 010400 ZZ2287=ZZ2287+ZZ2287
-+006406 021000 ZZ2287=ZZ2287+ZZ2287
-+006406 042000 ZZ2287=ZZ2287+ZZ2287
-+006406 015660 0 8192 -ZZ1287
-+006407 042000 0 ZZ2287
-- mark 1110, -503 /16 erid
-+006410 776020 ZZ2288=ZZ2288+ZZ2288
-+006410 774040 ZZ2288=ZZ2288+ZZ2288
-+006410 770100 ZZ2288=ZZ2288+ZZ2288
-+006410 760200 ZZ2288=ZZ2288+ZZ2288
-+006410 740400 ZZ2288=ZZ2288+ZZ2288
-+006410 701000 ZZ2288=ZZ2288+ZZ2288
-+006410 602000 ZZ2288=ZZ2288+ZZ2288
-+006410 404000 ZZ2288=ZZ2288+ZZ2288
-+006410 015652 0 8192 -ZZ1288
-+006411 404000 0 ZZ2288
-- mark 1135, 198 / 1 taur
-+006412 000614 ZZ2289=ZZ2289+ZZ2289
-+006412 001430 ZZ2289=ZZ2289+ZZ2289
-+006412 003060 ZZ2289=ZZ2289+ZZ2289
-+006412 006140 ZZ2289=ZZ2289+ZZ2289
-+006412 014300 ZZ2289=ZZ2289+ZZ2289
-+006412 030600 ZZ2289=ZZ2289+ZZ2289
-+006412 061400 ZZ2289=ZZ2289+ZZ2289
-+006412 143000 ZZ2289=ZZ2289+ZZ2289
-+006412 015621 0 8192 -ZZ1289
-+006413 143000 0 ZZ2289
-- mark 1148, 214 / 2 taur
-+006414 000654 ZZ2290=ZZ2290+ZZ2290
-+006414 001530 ZZ2290=ZZ2290+ZZ2290
-+006414 003260 ZZ2290=ZZ2290+ZZ2290
-+006414 006540 ZZ2290=ZZ2290+ZZ2290
-+006414 015300 ZZ2290=ZZ2290+ZZ2290
-+006414 032600 ZZ2290=ZZ2290+ZZ2290
-+006414 065400 ZZ2290=ZZ2290+ZZ2290
-+006414 153000 ZZ2290=ZZ2290+ZZ2290
-+006414 015604 0 8192 -ZZ1290
-+006415 153000 0 ZZ2290
-- mark 1168, 287 / 5 taur
-+006416 001076 ZZ2291=ZZ2291+ZZ2291
-+006416 002174 ZZ2291=ZZ2291+ZZ2291
-+006416 004370 ZZ2291=ZZ2291+ZZ2291
-+006416 010760 ZZ2291=ZZ2291+ZZ2291
-+006416 021740 ZZ2291=ZZ2291+ZZ2291
-+006416 043700 ZZ2291=ZZ2291+ZZ2291
-+006416 107600 ZZ2291=ZZ2291+ZZ2291
-+006416 217400 ZZ2291=ZZ2291+ZZ2291
-+006416 015560 0 8192 -ZZ1291
-+006417 217400 0 ZZ2291
-- mark 1170, -123 /17 erid
-+006420 777410 ZZ2292=ZZ2292+ZZ2292
-+006420 777020 ZZ2292=ZZ2292+ZZ2292
-+006420 776040 ZZ2292=ZZ2292+ZZ2292
-+006420 774100 ZZ2292=ZZ2292+ZZ2292
-+006420 770200 ZZ2292=ZZ2292+ZZ2292
-+006420 760400 ZZ2292=ZZ2292+ZZ2292
-+006420 741000 ZZ2292=ZZ2292+ZZ2292
-+006420 702000 ZZ2292=ZZ2292+ZZ2292
-+006420 015556 0 8192 -ZZ1292
-+006421 702000 0 ZZ2292
-- mark 1185, -223 /18 erid
-+006422 777100 ZZ2293=ZZ2293+ZZ2293
-+006422 776200 ZZ2293=ZZ2293+ZZ2293
-+006422 774400 ZZ2293=ZZ2293+ZZ2293
-+006422 771000 ZZ2293=ZZ2293+ZZ2293
-+006422 762000 ZZ2293=ZZ2293+ZZ2293
-+006422 744000 ZZ2293=ZZ2293+ZZ2293
-+006422 710000 ZZ2293=ZZ2293+ZZ2293
-+006422 620000 ZZ2293=ZZ2293+ZZ2293
-+006422 015537 0 8192 -ZZ1293
-+006423 620000 0 ZZ2293
-- mark 1191, -500 /19 erid
-+006424 776026 ZZ2294=ZZ2294+ZZ2294
-+006424 774054 ZZ2294=ZZ2294+ZZ2294
-+006424 770130 ZZ2294=ZZ2294+ZZ2294
-+006424 760260 ZZ2294=ZZ2294+ZZ2294
-+006424 740540 ZZ2294=ZZ2294+ZZ2294
-+006424 701300 ZZ2294=ZZ2294+ZZ2294
-+006424 602600 ZZ2294=ZZ2294+ZZ2294
-+006424 405400 ZZ2294=ZZ2294+ZZ2294
-+006424 015531 0 8192 -ZZ1294
-+006425 405400 0 ZZ2294
-- mark 1205, 2 /10 taur
-+006426 000004 ZZ2295=ZZ2295+ZZ2295
-+006426 000010 ZZ2295=ZZ2295+ZZ2295
-+006426 000020 ZZ2295=ZZ2295+ZZ2295
-+006426 000040 ZZ2295=ZZ2295+ZZ2295
-+006426 000100 ZZ2295=ZZ2295+ZZ2295
-+006426 000200 ZZ2295=ZZ2295+ZZ2295
-+006426 000400 ZZ2295=ZZ2295+ZZ2295
-+006426 001000 ZZ2295=ZZ2295+ZZ2295
-+006426 015513 0 8192 -ZZ1295
-+006427 001000 0 ZZ2295
-- mark 1260, -283 /26 erid
-+006430 776710 ZZ2296=ZZ2296+ZZ2296
-+006430 775620 ZZ2296=ZZ2296+ZZ2296
-+006430 773440 ZZ2296=ZZ2296+ZZ2296
-+006430 767100 ZZ2296=ZZ2296+ZZ2296
-+006430 756200 ZZ2296=ZZ2296+ZZ2296
-+006430 734400 ZZ2296=ZZ2296+ZZ2296
-+006430 671000 ZZ2296=ZZ2296+ZZ2296
-+006430 562000 ZZ2296=ZZ2296+ZZ2296
-+006430 015424 0 8192 -ZZ1296
-+006431 562000 0 ZZ2296
-- mark 1304, -74 /32 erid
-+006432 777552 ZZ2297=ZZ2297+ZZ2297
-+006432 777324 ZZ2297=ZZ2297+ZZ2297
-+006432 776650 ZZ2297=ZZ2297+ZZ2297
-+006432 775520 ZZ2297=ZZ2297+ZZ2297
-+006432 773240 ZZ2297=ZZ2297+ZZ2297
-+006432 766500 ZZ2297=ZZ2297+ZZ2297
-+006432 755200 ZZ2297=ZZ2297+ZZ2297
-+006432 732400 ZZ2297=ZZ2297+ZZ2297
-+006432 015350 0 8192 -ZZ1297
-+006433 732400 0 ZZ2297
-- mark 1338, 278 /35 taur
-+006434 001054 ZZ2298=ZZ2298+ZZ2298
-+006434 002130 ZZ2298=ZZ2298+ZZ2298
-+006434 004260 ZZ2298=ZZ2298+ZZ2298
-+006434 010540 ZZ2298=ZZ2298+ZZ2298
-+006434 021300 ZZ2298=ZZ2298+ZZ2298
-+006434 042600 ZZ2298=ZZ2298+ZZ2298
-+006434 105400 ZZ2298=ZZ2298+ZZ2298
-+006434 213000 ZZ2298=ZZ2298+ZZ2298
-+006434 015306 0 8192 -ZZ1298
-+006435 213000 0 ZZ2298
-- mark 1353, 130 /38 taur
-+006436 000404 ZZ2299=ZZ2299+ZZ2299
-+006436 001010 ZZ2299=ZZ2299+ZZ2299
-+006436 002020 ZZ2299=ZZ2299+ZZ2299
-+006436 004040 ZZ2299=ZZ2299+ZZ2299
-+006436 010100 ZZ2299=ZZ2299+ZZ2299
-+006436 020200 ZZ2299=ZZ2299+ZZ2299
-+006436 040400 ZZ2299=ZZ2299+ZZ2299
-+006436 101000 ZZ2299=ZZ2299+ZZ2299
-+006436 015267 0 8192 -ZZ1299
-+006437 101000 0 ZZ2299
-- mark 1358, 497 /37 taur
-+006440 001742 ZZ2300=ZZ2300+ZZ2300
-+006440 003704 ZZ2300=ZZ2300+ZZ2300
-+006440 007610 ZZ2300=ZZ2300+ZZ2300
-+006440 017420 ZZ2300=ZZ2300+ZZ2300
-+006440 037040 ZZ2300=ZZ2300+ZZ2300
-+006440 076100 ZZ2300=ZZ2300+ZZ2300
-+006440 174200 ZZ2300=ZZ2300+ZZ2300
-+006440 370400 ZZ2300=ZZ2300+ZZ2300
-+006440 015262 0 8192 -ZZ1300
-+006441 370400 0 ZZ2300
-- mark 1405, -162 /38 erid
-+006442 777272 ZZ2301=ZZ2301+ZZ2301
-+006442 776564 ZZ2301=ZZ2301+ZZ2301
-+006442 775350 ZZ2301=ZZ2301+ZZ2301
-+006442 772720 ZZ2301=ZZ2301+ZZ2301
-+006442 765640 ZZ2301=ZZ2301+ZZ2301
-+006442 753500 ZZ2301=ZZ2301+ZZ2301
-+006442 727200 ZZ2301=ZZ2301+ZZ2301
-+006442 656400 ZZ2301=ZZ2301+ZZ2301
-+006442 015203 0 8192 -ZZ1301
-+006443 656400 0 ZZ2301
-- mark 1414, 205 /47 taur
-+006444 000632 ZZ2302=ZZ2302+ZZ2302
-+006444 001464 ZZ2302=ZZ2302+ZZ2302
-+006444 003150 ZZ2302=ZZ2302+ZZ2302
-+006444 006320 ZZ2302=ZZ2302+ZZ2302
-+006444 014640 ZZ2302=ZZ2302+ZZ2302
-+006444 031500 ZZ2302=ZZ2302+ZZ2302
-+006444 063200 ZZ2302=ZZ2302+ZZ2302
-+006444 146400 ZZ2302=ZZ2302+ZZ2302
-+006444 015172 0 8192 -ZZ1302
-+006445 146400 0 ZZ2302
-- mark 1423, 197 /49 taur
-+006446 000612 ZZ2303=ZZ2303+ZZ2303
-+006446 001424 ZZ2303=ZZ2303+ZZ2303
-+006446 003050 ZZ2303=ZZ2303+ZZ2303
-+006446 006120 ZZ2303=ZZ2303+ZZ2303
-+006446 014240 ZZ2303=ZZ2303+ZZ2303
-+006446 030500 ZZ2303=ZZ2303+ZZ2303
-+006446 061200 ZZ2303=ZZ2303+ZZ2303
-+006446 142400 ZZ2303=ZZ2303+ZZ2303
-+006446 015161 0 8192 -ZZ1303
-+006447 142400 0 ZZ2303
-- mark 1426, -178 /40 erid
-+006450 777232 ZZ2304=ZZ2304+ZZ2304
-+006450 776464 ZZ2304=ZZ2304+ZZ2304
-+006450 775150 ZZ2304=ZZ2304+ZZ2304
-+006450 772320 ZZ2304=ZZ2304+ZZ2304
-+006450 764640 ZZ2304=ZZ2304+ZZ2304
-+006450 751500 ZZ2304=ZZ2304+ZZ2304
-+006450 723200 ZZ2304=ZZ2304+ZZ2304
-+006450 646400 ZZ2304=ZZ2304+ZZ2304
-+006450 015156 0 8192 -ZZ1304
-+006451 646400 0 ZZ2304
-- mark 1430, 463 /50 taur
-+006452 001636 ZZ2305=ZZ2305+ZZ2305
-+006452 003474 ZZ2305=ZZ2305+ZZ2305
-+006452 007170 ZZ2305=ZZ2305+ZZ2305
-+006452 016360 ZZ2305=ZZ2305+ZZ2305
-+006452 034740 ZZ2305=ZZ2305+ZZ2305
-+006452 071700 ZZ2305=ZZ2305+ZZ2305
-+006452 163600 ZZ2305=ZZ2305+ZZ2305
-+006452 347400 ZZ2305=ZZ2305+ZZ2305
-+006452 015152 0 8192 -ZZ1305
-+006453 347400 0 ZZ2305
-- mark 1446, 350 /54 taur
-+006454 001274 ZZ2306=ZZ2306+ZZ2306
-+006454 002570 ZZ2306=ZZ2306+ZZ2306
-+006454 005360 ZZ2306=ZZ2306+ZZ2306
-+006454 012740 ZZ2306=ZZ2306+ZZ2306
-+006454 025700 ZZ2306=ZZ2306+ZZ2306
-+006454 053600 ZZ2306=ZZ2306+ZZ2306
-+006454 127400 ZZ2306=ZZ2306+ZZ2306
-+006454 257000 ZZ2306=ZZ2306+ZZ2306
-+006454 015132 0 8192 -ZZ1306
-+006455 257000 0 ZZ2306
-- mark 1463, 394 /61 taur
-+006456 001424 ZZ2307=ZZ2307+ZZ2307
-+006456 003050 ZZ2307=ZZ2307+ZZ2307
-+006456 006120 ZZ2307=ZZ2307+ZZ2307
-+006456 014240 ZZ2307=ZZ2307+ZZ2307
-+006456 030500 ZZ2307=ZZ2307+ZZ2307
-+006456 061200 ZZ2307=ZZ2307+ZZ2307
-+006456 142400 ZZ2307=ZZ2307+ZZ2307
-+006456 305000 ZZ2307=ZZ2307+ZZ2307
-+006456 015111 0 8192 -ZZ1307
-+006457 305000 0 ZZ2307
-- mark 1470, 392 /64 taur
-+006460 001420 ZZ2308=ZZ2308+ZZ2308
-+006460 003040 ZZ2308=ZZ2308+ZZ2308
-+006460 006100 ZZ2308=ZZ2308+ZZ2308
-+006460 014200 ZZ2308=ZZ2308+ZZ2308
-+006460 030400 ZZ2308=ZZ2308+ZZ2308
-+006460 061000 ZZ2308=ZZ2308+ZZ2308
-+006460 142000 ZZ2308=ZZ2308+ZZ2308
-+006460 304000 ZZ2308=ZZ2308+ZZ2308
-+006460 015102 0 8192 -ZZ1308
-+006461 304000 0 ZZ2308
-- mark 1476, 502 /65 taur
-+006462 001754 ZZ2309=ZZ2309+ZZ2309
-+006462 003730 ZZ2309=ZZ2309+ZZ2309
-+006462 007660 ZZ2309=ZZ2309+ZZ2309
-+006462 017540 ZZ2309=ZZ2309+ZZ2309
-+006462 037300 ZZ2309=ZZ2309+ZZ2309
-+006462 076600 ZZ2309=ZZ2309+ZZ2309
-+006462 175400 ZZ2309=ZZ2309+ZZ2309
-+006462 373000 ZZ2309=ZZ2309+ZZ2309
-+006462 015074 0 8192 -ZZ1309
-+006463 373000 0 ZZ2309
-- mark 1477, 403 /68 taur
-+006464 001446 ZZ2310=ZZ2310+ZZ2310
-+006464 003114 ZZ2310=ZZ2310+ZZ2310
-+006464 006230 ZZ2310=ZZ2310+ZZ2310
-+006464 014460 ZZ2310=ZZ2310+ZZ2310
-+006464 031140 ZZ2310=ZZ2310+ZZ2310
-+006464 062300 ZZ2310=ZZ2310+ZZ2310
-+006464 144600 ZZ2310=ZZ2310+ZZ2310
-+006464 311400 ZZ2310=ZZ2310+ZZ2310
-+006464 015073 0 8192 -ZZ1310
-+006465 311400 0 ZZ2310
-- mark 1483, 350 /71 taur
-+006466 001274 ZZ2311=ZZ2311+ZZ2311
-+006466 002570 ZZ2311=ZZ2311+ZZ2311
-+006466 005360 ZZ2311=ZZ2311+ZZ2311
-+006466 012740 ZZ2311=ZZ2311+ZZ2311
-+006466 025700 ZZ2311=ZZ2311+ZZ2311
-+006466 053600 ZZ2311=ZZ2311+ZZ2311
-+006466 127400 ZZ2311=ZZ2311+ZZ2311
-+006466 257000 ZZ2311=ZZ2311+ZZ2311
-+006466 015065 0 8192 -ZZ1311
-+006467 257000 0 ZZ2311
-- mark 1485, 330 /73 taur
-+006470 001224 ZZ2312=ZZ2312+ZZ2312
-+006470 002450 ZZ2312=ZZ2312+ZZ2312
-+006470 005120 ZZ2312=ZZ2312+ZZ2312
-+006470 012240 ZZ2312=ZZ2312+ZZ2312
-+006470 024500 ZZ2312=ZZ2312+ZZ2312
-+006470 051200 ZZ2312=ZZ2312+ZZ2312
-+006470 122400 ZZ2312=ZZ2312+ZZ2312
-+006470 245000 ZZ2312=ZZ2312+ZZ2312
-+006470 015063 0 8192 -ZZ1312
-+006471 245000 0 ZZ2312
-- mark 1495, 358 /77 taur
-+006472 001314 ZZ2313=ZZ2313+ZZ2313
-+006472 002630 ZZ2313=ZZ2313+ZZ2313
-+006472 005460 ZZ2313=ZZ2313+ZZ2313
-+006472 013140 ZZ2313=ZZ2313+ZZ2313
-+006472 026300 ZZ2313=ZZ2313+ZZ2313
-+006472 054600 ZZ2313=ZZ2313+ZZ2313
-+006472 131400 ZZ2313=ZZ2313+ZZ2313
-+006472 263000 ZZ2313=ZZ2313+ZZ2313
-+006472 015051 0 8192 -ZZ1313
-+006473 263000 0 ZZ2313
-- mark 1507, 364 /
-+006474 001330 ZZ2314=ZZ2314+ZZ2314
-+006474 002660 ZZ2314=ZZ2314+ZZ2314
-+006474 005540 ZZ2314=ZZ2314+ZZ2314
-+006474 013300 ZZ2314=ZZ2314+ZZ2314
-+006474 026600 ZZ2314=ZZ2314+ZZ2314
-+006474 055400 ZZ2314=ZZ2314+ZZ2314
-+006474 133000 ZZ2314=ZZ2314+ZZ2314
-+006474 266000 ZZ2314=ZZ2314+ZZ2314
-+006474 015035 0 8192 -ZZ1314
-+006475 266000 0 ZZ2314
-- mark 1518, -6 /45 erid
-+006476 777762 ZZ2315=ZZ2315+ZZ2315
-+006476 777744 ZZ2315=ZZ2315+ZZ2315
-+006476 777710 ZZ2315=ZZ2315+ZZ2315
-+006476 777620 ZZ2315=ZZ2315+ZZ2315
-+006476 777440 ZZ2315=ZZ2315+ZZ2315
-+006476 777100 ZZ2315=ZZ2315+ZZ2315
-+006476 776200 ZZ2315=ZZ2315+ZZ2315
-+006476 774400 ZZ2315=ZZ2315+ZZ2315
-+006476 015022 0 8192 -ZZ1315
-+006477 774400 0 ZZ2315
-- mark 1526, 333 /86 taur
-+006500 001232 ZZ2316=ZZ2316+ZZ2316
-+006500 002464 ZZ2316=ZZ2316+ZZ2316
-+006500 005150 ZZ2316=ZZ2316+ZZ2316
-+006500 012320 ZZ2316=ZZ2316+ZZ2316
-+006500 024640 ZZ2316=ZZ2316+ZZ2316
-+006500 051500 ZZ2316=ZZ2316+ZZ2316
-+006500 123200 ZZ2316=ZZ2316+ZZ2316
-+006500 246400 ZZ2316=ZZ2316+ZZ2316
-+006500 015012 0 8192 -ZZ1316
-+006501 246400 0 ZZ2316
-- mark 1537, 226 /88 taur
-+006502 000704 ZZ2317=ZZ2317+ZZ2317
-+006502 001610 ZZ2317=ZZ2317+ZZ2317
-+006502 003420 ZZ2317=ZZ2317+ZZ2317
-+006502 007040 ZZ2317=ZZ2317+ZZ2317
-+006502 016100 ZZ2317=ZZ2317+ZZ2317
-+006502 034200 ZZ2317=ZZ2317+ZZ2317
-+006502 070400 ZZ2317=ZZ2317+ZZ2317
-+006502 161000 ZZ2317=ZZ2317+ZZ2317
-+006502 014777 0 8192 -ZZ1317
-+006503 161000 0 ZZ2317
-- mark 1544, -81 /48 erid
-+006504 777534 ZZ2318=ZZ2318+ZZ2318
-+006504 777270 ZZ2318=ZZ2318+ZZ2318
-+006504 776560 ZZ2318=ZZ2318+ZZ2318
-+006504 775340 ZZ2318=ZZ2318+ZZ2318
-+006504 772700 ZZ2318=ZZ2318+ZZ2318
-+006504 765600 ZZ2318=ZZ2318+ZZ2318
-+006504 753400 ZZ2318=ZZ2318+ZZ2318
-+006504 727000 ZZ2318=ZZ2318+ZZ2318
-+006504 014770 0 8192 -ZZ1318
-+006505 727000 0 ZZ2318
-- mark 1551, 280 /90 taur
-+006506 001060 ZZ2319=ZZ2319+ZZ2319
-+006506 002140 ZZ2319=ZZ2319+ZZ2319
-+006506 004300 ZZ2319=ZZ2319+ZZ2319
-+006506 010600 ZZ2319=ZZ2319+ZZ2319
-+006506 021400 ZZ2319=ZZ2319+ZZ2319
-+006506 043000 ZZ2319=ZZ2319+ZZ2319
-+006506 106000 ZZ2319=ZZ2319+ZZ2319
-+006506 214000 ZZ2319=ZZ2319+ZZ2319
-+006506 014761 0 8192 -ZZ1319
-+006507 214000 0 ZZ2319
-- mark 1556, 358 /92 taur
-+006510 001314 ZZ2320=ZZ2320+ZZ2320
-+006510 002630 ZZ2320=ZZ2320+ZZ2320
-+006510 005460 ZZ2320=ZZ2320+ZZ2320
-+006510 013140 ZZ2320=ZZ2320+ZZ2320
-+006510 026300 ZZ2320=ZZ2320+ZZ2320
-+006510 054600 ZZ2320=ZZ2320+ZZ2320
-+006510 131400 ZZ2320=ZZ2320+ZZ2320
-+006510 263000 ZZ2320=ZZ2320+ZZ2320
-+006510 014754 0 8192 -ZZ1320
-+006511 263000 0 ZZ2320
-- mark 1557, -330 /53 erid
-+006512 776552 ZZ2321=ZZ2321+ZZ2321
-+006512 775324 ZZ2321=ZZ2321+ZZ2321
-+006512 772650 ZZ2321=ZZ2321+ZZ2321
-+006512 765520 ZZ2321=ZZ2321+ZZ2321
-+006512 753240 ZZ2321=ZZ2321+ZZ2321
-+006512 726500 ZZ2321=ZZ2321+ZZ2321
-+006512 655200 ZZ2321=ZZ2321+ZZ2321
-+006512 532400 ZZ2321=ZZ2321+ZZ2321
-+006512 014753 0 8192 -ZZ1321
-+006513 532400 0 ZZ2321
-- mark 1571, -452 /54 erid
-+006514 776166 ZZ2322=ZZ2322+ZZ2322
-+006514 774354 ZZ2322=ZZ2322+ZZ2322
-+006514 770730 ZZ2322=ZZ2322+ZZ2322
-+006514 761660 ZZ2322=ZZ2322+ZZ2322
-+006514 743540 ZZ2322=ZZ2322+ZZ2322
-+006514 707300 ZZ2322=ZZ2322+ZZ2322
-+006514 616600 ZZ2322=ZZ2322+ZZ2322
-+006514 435400 ZZ2322=ZZ2322+ZZ2322
-+006514 014735 0 8192 -ZZ1322
-+006515 435400 0 ZZ2322
-- mark 1596, -78 /57 erid
-+006516 777542 ZZ2323=ZZ2323+ZZ2323
-+006516 777304 ZZ2323=ZZ2323+ZZ2323
-+006516 776610 ZZ2323=ZZ2323+ZZ2323
-+006516 775420 ZZ2323=ZZ2323+ZZ2323
-+006516 773040 ZZ2323=ZZ2323+ZZ2323
-+006516 766100 ZZ2323=ZZ2323+ZZ2323
-+006516 754200 ZZ2323=ZZ2323+ZZ2323
-+006516 730400 ZZ2323=ZZ2323+ZZ2323
-+006516 014704 0 8192 -ZZ1323
-+006517 730400 0 ZZ2323
-- mark 1622, 199 / 2 orio
-+006520 000616 ZZ2324=ZZ2324+ZZ2324
-+006520 001434 ZZ2324=ZZ2324+ZZ2324
-+006520 003070 ZZ2324=ZZ2324+ZZ2324
-+006520 006160 ZZ2324=ZZ2324+ZZ2324
-+006520 014340 ZZ2324=ZZ2324+ZZ2324
-+006520 030700 ZZ2324=ZZ2324+ZZ2324
-+006520 061600 ZZ2324=ZZ2324+ZZ2324
-+006520 143400 ZZ2324=ZZ2324+ZZ2324
-+006520 014652 0 8192 -ZZ1324
-+006521 143400 0 ZZ2324
-- mark 1626, 124 / 3 orio
-+006522 000370 ZZ2325=ZZ2325+ZZ2325
-+006522 000760 ZZ2325=ZZ2325+ZZ2325
-+006522 001740 ZZ2325=ZZ2325+ZZ2325
-+006522 003700 ZZ2325=ZZ2325+ZZ2325
-+006522 007600 ZZ2325=ZZ2325+ZZ2325
-+006522 017400 ZZ2325=ZZ2325+ZZ2325
-+006522 037000 ZZ2325=ZZ2325+ZZ2325
-+006522 076000 ZZ2325=ZZ2325+ZZ2325
-+006522 014646 0 8192 -ZZ1325
-+006523 076000 0 ZZ2325
-- mark 1638, -128 /61 erid
-+006524 777376 ZZ2326=ZZ2326+ZZ2326
-+006524 776774 ZZ2326=ZZ2326+ZZ2326
-+006524 775770 ZZ2326=ZZ2326+ZZ2326
-+006524 773760 ZZ2326=ZZ2326+ZZ2326
-+006524 767740 ZZ2326=ZZ2326+ZZ2326
-+006524 757700 ZZ2326=ZZ2326+ZZ2326
-+006524 737600 ZZ2326=ZZ2326+ZZ2326
-+006524 677400 ZZ2326=ZZ2326+ZZ2326
-+006524 014632 0 8192 -ZZ1326
-+006525 677400 0 ZZ2326
-- mark 1646, 228 / 7 orio
-+006526 000710 ZZ2327=ZZ2327+ZZ2327
-+006526 001620 ZZ2327=ZZ2327+ZZ2327
-+006526 003440 ZZ2327=ZZ2327+ZZ2327
-+006526 007100 ZZ2327=ZZ2327+ZZ2327
-+006526 016200 ZZ2327=ZZ2327+ZZ2327
-+006526 034400 ZZ2327=ZZ2327+ZZ2327
-+006526 071000 ZZ2327=ZZ2327+ZZ2327
-+006526 162000 ZZ2327=ZZ2327+ZZ2327
-+006526 014622 0 8192 -ZZ1327
-+006527 162000 0 ZZ2327
-- mark 1654, 304 / 9 orio
-+006530 001140 ZZ2328=ZZ2328+ZZ2328
-+006530 002300 ZZ2328=ZZ2328+ZZ2328
-+006530 004600 ZZ2328=ZZ2328+ZZ2328
-+006530 011400 ZZ2328=ZZ2328+ZZ2328
-+006530 023000 ZZ2328=ZZ2328+ZZ2328
-+006530 046000 ZZ2328=ZZ2328+ZZ2328
-+006530 114000 ZZ2328=ZZ2328+ZZ2328
-+006530 230000 ZZ2328=ZZ2328+ZZ2328
-+006530 014612 0 8192 -ZZ1328
-+006531 230000 0 ZZ2328
-- mark 1669, 36 /10 orio
-+006532 000110 ZZ2329=ZZ2329+ZZ2329
-+006532 000220 ZZ2329=ZZ2329+ZZ2329
-+006532 000440 ZZ2329=ZZ2329+ZZ2329
-+006532 001100 ZZ2329=ZZ2329+ZZ2329
-+006532 002200 ZZ2329=ZZ2329+ZZ2329
-+006532 004400 ZZ2329=ZZ2329+ZZ2329
-+006532 011000 ZZ2329=ZZ2329+ZZ2329
-+006532 022000 ZZ2329=ZZ2329+ZZ2329
-+006532 014573 0 8192 -ZZ1329
-+006533 022000 0 ZZ2329
-- mark 1680, -289 /64 erid
-+006534 776674 ZZ2330=ZZ2330+ZZ2330
-+006534 775570 ZZ2330=ZZ2330+ZZ2330
-+006534 773360 ZZ2330=ZZ2330+ZZ2330
-+006534 766740 ZZ2330=ZZ2330+ZZ2330
-+006534 755700 ZZ2330=ZZ2330+ZZ2330
-+006534 733600 ZZ2330=ZZ2330+ZZ2330
-+006534 667400 ZZ2330=ZZ2330+ZZ2330
-+006534 557000 ZZ2330=ZZ2330+ZZ2330
-+006534 014560 0 8192 -ZZ1330
-+006535 557000 0 ZZ2330
-- mark 1687, -167 /65 erid
-+006536 777260 ZZ2331=ZZ2331+ZZ2331
-+006536 776540 ZZ2331=ZZ2331+ZZ2331
-+006536 775300 ZZ2331=ZZ2331+ZZ2331
-+006536 772600 ZZ2331=ZZ2331+ZZ2331
-+006536 765400 ZZ2331=ZZ2331+ZZ2331
-+006536 753000 ZZ2331=ZZ2331+ZZ2331
-+006536 726000 ZZ2331=ZZ2331+ZZ2331
-+006536 654000 ZZ2331=ZZ2331+ZZ2331
-+006536 014551 0 8192 -ZZ1331
-+006537 654000 0 ZZ2331
-- mark 1690, -460 /
-+006540 776146 ZZ2332=ZZ2332+ZZ2332
-+006540 774314 ZZ2332=ZZ2332+ZZ2332
-+006540 770630 ZZ2332=ZZ2332+ZZ2332
-+006540 761460 ZZ2332=ZZ2332+ZZ2332
-+006540 743140 ZZ2332=ZZ2332+ZZ2332
-+006540 706300 ZZ2332=ZZ2332+ZZ2332
-+006540 614600 ZZ2332=ZZ2332+ZZ2332
-+006540 431400 ZZ2332=ZZ2332+ZZ2332
-+006540 014546 0 8192 -ZZ1332
-+006541 431400 0 ZZ2332
-- mark 1690, 488 /102 taur
-+006542 001720 ZZ2333=ZZ2333+ZZ2333
-+006542 003640 ZZ2333=ZZ2333+ZZ2333
-+006542 007500 ZZ2333=ZZ2333+ZZ2333
-+006542 017200 ZZ2333=ZZ2333+ZZ2333
-+006542 036400 ZZ2333=ZZ2333+ZZ2333
-+006542 075000 ZZ2333=ZZ2333+ZZ2333
-+006542 172000 ZZ2333=ZZ2333+ZZ2333
-+006542 364000 ZZ2333=ZZ2333+ZZ2333
-+006542 014546 0 8192 -ZZ1333
-+006543 364000 0 ZZ2333
-- mark 1700, 347 /11 orio
-+006544 001266 ZZ2334=ZZ2334+ZZ2334
-+006544 002554 ZZ2334=ZZ2334+ZZ2334
-+006544 005330 ZZ2334=ZZ2334+ZZ2334
-+006544 012660 ZZ2334=ZZ2334+ZZ2334
-+006544 025540 ZZ2334=ZZ2334+ZZ2334
-+006544 053300 ZZ2334=ZZ2334+ZZ2334
-+006544 126600 ZZ2334=ZZ2334+ZZ2334
-+006544 255400 ZZ2334=ZZ2334+ZZ2334
-+006544 014534 0 8192 -ZZ1334
-+006545 255400 0 ZZ2334
-- mark 1729, 352 /15 orio
-+006546 001300 ZZ2335=ZZ2335+ZZ2335
-+006546 002600 ZZ2335=ZZ2335+ZZ2335
-+006546 005400 ZZ2335=ZZ2335+ZZ2335
-+006546 013000 ZZ2335=ZZ2335+ZZ2335
-+006546 026000 ZZ2335=ZZ2335+ZZ2335
-+006546 054000 ZZ2335=ZZ2335+ZZ2335
-+006546 130000 ZZ2335=ZZ2335+ZZ2335
-+006546 260000 ZZ2335=ZZ2335+ZZ2335
-+006546 014477 0 8192 -ZZ1335
-+006547 260000 0 ZZ2335
-- mark 1732, -202 /69 erid
-+006550 777152 ZZ2336=ZZ2336+ZZ2336
-+006550 776324 ZZ2336=ZZ2336+ZZ2336
-+006550 774650 ZZ2336=ZZ2336+ZZ2336
-+006550 771520 ZZ2336=ZZ2336+ZZ2336
-+006550 763240 ZZ2336=ZZ2336+ZZ2336
-+006550 746500 ZZ2336=ZZ2336+ZZ2336
-+006550 715200 ZZ2336=ZZ2336+ZZ2336
-+006550 632400 ZZ2336=ZZ2336+ZZ2336
-+006550 014474 0 8192 -ZZ1336
-+006551 632400 0 ZZ2336
-- mark 1750, -273 / 3 leps
-+006552 776734 ZZ2337=ZZ2337+ZZ2337
-+006552 775670 ZZ2337=ZZ2337+ZZ2337
-+006552 773560 ZZ2337=ZZ2337+ZZ2337
-+006552 767340 ZZ2337=ZZ2337+ZZ2337
-+006552 756700 ZZ2337=ZZ2337+ZZ2337
-+006552 735600 ZZ2337=ZZ2337+ZZ2337
-+006552 673400 ZZ2337=ZZ2337+ZZ2337
-+006552 567000 ZZ2337=ZZ2337+ZZ2337
-+006552 014452 0 8192 -ZZ1337
-+006553 567000 0 ZZ2337
-- mark 1753, 63 /17 orio
-+006554 000176 ZZ2338=ZZ2338+ZZ2338
-+006554 000374 ZZ2338=ZZ2338+ZZ2338
-+006554 000770 ZZ2338=ZZ2338+ZZ2338
-+006554 001760 ZZ2338=ZZ2338+ZZ2338
-+006554 003740 ZZ2338=ZZ2338+ZZ2338
-+006554 007700 ZZ2338=ZZ2338+ZZ2338
-+006554 017600 ZZ2338=ZZ2338+ZZ2338
-+006554 037400 ZZ2338=ZZ2338+ZZ2338
-+006554 014447 0 8192 -ZZ1338
-+006555 037400 0 ZZ2338
-- mark 1756, -297 / 4 leps
-+006556 776654 ZZ2339=ZZ2339+ZZ2339
-+006556 775530 ZZ2339=ZZ2339+ZZ2339
-+006556 773260 ZZ2339=ZZ2339+ZZ2339
-+006556 766540 ZZ2339=ZZ2339+ZZ2339
-+006556 755300 ZZ2339=ZZ2339+ZZ2339
-+006556 732600 ZZ2339=ZZ2339+ZZ2339
-+006556 665400 ZZ2339=ZZ2339+ZZ2339
-+006556 553000 ZZ2339=ZZ2339+ZZ2339
-+006556 014444 0 8192 -ZZ1339
-+006557 553000 0 ZZ2339
-- mark 1792, -302 / 6 leps
-+006560 776642 ZZ2340=ZZ2340+ZZ2340
-+006560 775504 ZZ2340=ZZ2340+ZZ2340
-+006560 773210 ZZ2340=ZZ2340+ZZ2340
-+006560 766420 ZZ2340=ZZ2340+ZZ2340
-+006560 755040 ZZ2340=ZZ2340+ZZ2340
-+006560 732100 ZZ2340=ZZ2340+ZZ2340
-+006560 664200 ZZ2340=ZZ2340+ZZ2340
-+006560 550400 ZZ2340=ZZ2340+ZZ2340
-+006560 014400 0 8192 -ZZ1340
-+006561 550400 0 ZZ2340
-- mark 1799, -486 /
-+006562 776062 ZZ2341=ZZ2341+ZZ2341
-+006562 774144 ZZ2341=ZZ2341+ZZ2341
-+006562 770310 ZZ2341=ZZ2341+ZZ2341
-+006562 760620 ZZ2341=ZZ2341+ZZ2341
-+006562 741440 ZZ2341=ZZ2341+ZZ2341
-+006562 703100 ZZ2341=ZZ2341+ZZ2341
-+006562 606200 ZZ2341=ZZ2341+ZZ2341
-+006562 414400 ZZ2341=ZZ2341+ZZ2341
-+006562 014371 0 8192 -ZZ1341
-+006563 414400 0 ZZ2341
-- mark 1801, -11 /22 orio
-+006564 777750 ZZ2342=ZZ2342+ZZ2342
-+006564 777720 ZZ2342=ZZ2342+ZZ2342
-+006564 777640 ZZ2342=ZZ2342+ZZ2342
-+006564 777500 ZZ2342=ZZ2342+ZZ2342
-+006564 777200 ZZ2342=ZZ2342+ZZ2342
-+006564 776400 ZZ2342=ZZ2342+ZZ2342
-+006564 775000 ZZ2342=ZZ2342+ZZ2342
-+006564 772000 ZZ2342=ZZ2342+ZZ2342
-+006564 014367 0 8192 -ZZ1342
-+006565 772000 0 ZZ2342
-- mark 1807, 79 /23 orio
-+006566 000236 ZZ2343=ZZ2343+ZZ2343
-+006566 000474 ZZ2343=ZZ2343+ZZ2343
-+006566 001170 ZZ2343=ZZ2343+ZZ2343
-+006566 002360 ZZ2343=ZZ2343+ZZ2343
-+006566 004740 ZZ2343=ZZ2343+ZZ2343
-+006566 011700 ZZ2343=ZZ2343+ZZ2343
-+006566 023600 ZZ2343=ZZ2343+ZZ2343
-+006566 047400 ZZ2343=ZZ2343+ZZ2343
-+006566 014361 0 8192 -ZZ1343
-+006567 047400 0 ZZ2343
-- mark 1816, -180 /29 orio
-+006570 777226 ZZ2344=ZZ2344+ZZ2344
-+006570 776454 ZZ2344=ZZ2344+ZZ2344
-+006570 775130 ZZ2344=ZZ2344+ZZ2344
-+006570 772260 ZZ2344=ZZ2344+ZZ2344
-+006570 764540 ZZ2344=ZZ2344+ZZ2344
-+006570 751300 ZZ2344=ZZ2344+ZZ2344
-+006570 722600 ZZ2344=ZZ2344+ZZ2344
-+006570 645400 ZZ2344=ZZ2344+ZZ2344
-+006570 014350 0 8192 -ZZ1344
-+006571 645400 0 ZZ2344
-- mark 1818, 40 /25 orio
-+006572 000120 ZZ2345=ZZ2345+ZZ2345
-+006572 000240 ZZ2345=ZZ2345+ZZ2345
-+006572 000500 ZZ2345=ZZ2345+ZZ2345
-+006572 001200 ZZ2345=ZZ2345+ZZ2345
-+006572 002400 ZZ2345=ZZ2345+ZZ2345
-+006572 005000 ZZ2345=ZZ2345+ZZ2345
-+006572 012000 ZZ2345=ZZ2345+ZZ2345
-+006572 024000 ZZ2345=ZZ2345+ZZ2345
-+006572 014346 0 8192 -ZZ1345
-+006573 024000 0 ZZ2345
-- mark 1830, 497 /114 taur
-+006574 001742 ZZ2346=ZZ2346+ZZ2346
-+006574 003704 ZZ2346=ZZ2346+ZZ2346
-+006574 007610 ZZ2346=ZZ2346+ZZ2346
-+006574 017420 ZZ2346=ZZ2346+ZZ2346
-+006574 037040 ZZ2346=ZZ2346+ZZ2346
-+006574 076100 ZZ2346=ZZ2346+ZZ2346
-+006574 174200 ZZ2346=ZZ2346+ZZ2346
-+006574 370400 ZZ2346=ZZ2346+ZZ2346
-+006574 014332 0 8192 -ZZ1346
-+006575 370400 0 ZZ2346
-- mark 1830, 69 /30 orio
-+006576 000212 ZZ2347=ZZ2347+ZZ2347
-+006576 000424 ZZ2347=ZZ2347+ZZ2347
-+006576 001050 ZZ2347=ZZ2347+ZZ2347
-+006576 002120 ZZ2347=ZZ2347+ZZ2347
-+006576 004240 ZZ2347=ZZ2347+ZZ2347
-+006576 010500 ZZ2347=ZZ2347+ZZ2347
-+006576 021200 ZZ2347=ZZ2347+ZZ2347
-+006576 042400 ZZ2347=ZZ2347+ZZ2347
-+006576 014332 0 8192 -ZZ1347
-+006577 042400 0 ZZ2347
-- mark 1851, 134 /32 orio
-+006600 000414 ZZ2348=ZZ2348+ZZ2348
-+006600 001030 ZZ2348=ZZ2348+ZZ2348
-+006600 002060 ZZ2348=ZZ2348+ZZ2348
-+006600 004140 ZZ2348=ZZ2348+ZZ2348
-+006600 010300 ZZ2348=ZZ2348+ZZ2348
-+006600 020600 ZZ2348=ZZ2348+ZZ2348
-+006600 041400 ZZ2348=ZZ2348+ZZ2348
-+006600 103000 ZZ2348=ZZ2348+ZZ2348
-+006600 014305 0 8192 -ZZ1348
-+006601 103000 0 ZZ2348
-- mark 1857, 421 /119 taur
-+006602 001512 ZZ2349=ZZ2349+ZZ2349
-+006602 003224 ZZ2349=ZZ2349+ZZ2349
-+006602 006450 ZZ2349=ZZ2349+ZZ2349
-+006602 015120 ZZ2349=ZZ2349+ZZ2349
-+006602 032240 ZZ2349=ZZ2349+ZZ2349
-+006602 064500 ZZ2349=ZZ2349+ZZ2349
-+006602 151200 ZZ2349=ZZ2349+ZZ2349
-+006602 322400 ZZ2349=ZZ2349+ZZ2349
-+006602 014277 0 8192 -ZZ1349
-+006603 322400 0 ZZ2349
-- mark 1861, -168 /36 orio
-+006604 777256 ZZ2350=ZZ2350+ZZ2350
-+006604 776534 ZZ2350=ZZ2350+ZZ2350
-+006604 775270 ZZ2350=ZZ2350+ZZ2350
-+006604 772560 ZZ2350=ZZ2350+ZZ2350
-+006604 765340 ZZ2350=ZZ2350+ZZ2350
-+006604 752700 ZZ2350=ZZ2350+ZZ2350
-+006604 725600 ZZ2350=ZZ2350+ZZ2350
-+006604 653400 ZZ2350=ZZ2350+ZZ2350
-+006604 014273 0 8192 -ZZ1350
-+006605 653400 0 ZZ2350
-- mark 1874, 214 /37 orio
-+006606 000654 ZZ2351=ZZ2351+ZZ2351
-+006606 001530 ZZ2351=ZZ2351+ZZ2351
-+006606 003260 ZZ2351=ZZ2351+ZZ2351
-+006606 006540 ZZ2351=ZZ2351+ZZ2351
-+006606 015300 ZZ2351=ZZ2351+ZZ2351
-+006606 032600 ZZ2351=ZZ2351+ZZ2351
-+006606 065400 ZZ2351=ZZ2351+ZZ2351
-+006606 153000 ZZ2351=ZZ2351+ZZ2351
-+006606 014256 0 8192 -ZZ1351
-+006607 153000 0 ZZ2351
-- mark 1878, -132 /
-+006610 777366 ZZ2352=ZZ2352+ZZ2352
-+006610 776754 ZZ2352=ZZ2352+ZZ2352
-+006610 775730 ZZ2352=ZZ2352+ZZ2352
-+006610 773660 ZZ2352=ZZ2352+ZZ2352
-+006610 767540 ZZ2352=ZZ2352+ZZ2352
-+006610 757300 ZZ2352=ZZ2352+ZZ2352
-+006610 736600 ZZ2352=ZZ2352+ZZ2352
-+006610 675400 ZZ2352=ZZ2352+ZZ2352
-+006610 014252 0 8192 -ZZ1352
-+006611 675400 0 ZZ2352
-- mark 1880, -112 /42 orio
-+006612 777436 ZZ2353=ZZ2353+ZZ2353
-+006612 777074 ZZ2353=ZZ2353+ZZ2353
-+006612 776170 ZZ2353=ZZ2353+ZZ2353
-+006612 774360 ZZ2353=ZZ2353+ZZ2353
-+006612 770740 ZZ2353=ZZ2353+ZZ2353
-+006612 761700 ZZ2353=ZZ2353+ZZ2353
-+006612 743600 ZZ2353=ZZ2353+ZZ2353
-+006612 707400 ZZ2353=ZZ2353+ZZ2353
-+006612 014250 0 8192 -ZZ1353
-+006613 707400 0 ZZ2353
-- mark 1885, 210 /40 orio
-+006614 000644 ZZ2354=ZZ2354+ZZ2354
-+006614 001510 ZZ2354=ZZ2354+ZZ2354
-+006614 003220 ZZ2354=ZZ2354+ZZ2354
-+006614 006440 ZZ2354=ZZ2354+ZZ2354
-+006614 015100 ZZ2354=ZZ2354+ZZ2354
-+006614 032200 ZZ2354=ZZ2354+ZZ2354
-+006614 064400 ZZ2354=ZZ2354+ZZ2354
-+006614 151000 ZZ2354=ZZ2354+ZZ2354
-+006614 014243 0 8192 -ZZ1354
-+006615 151000 0 ZZ2354
-- mark 1899,-60 /48 orio
-+006616 777606 ZZ2355=ZZ2355+ZZ2355
-+006616 777414 ZZ2355=ZZ2355+ZZ2355
-+006616 777030 ZZ2355=ZZ2355+ZZ2355
-+006616 776060 ZZ2355=ZZ2355+ZZ2355
-+006616 774140 ZZ2355=ZZ2355+ZZ2355
-+006616 770300 ZZ2355=ZZ2355+ZZ2355
-+006616 760600 ZZ2355=ZZ2355+ZZ2355
-+006616 741400 ZZ2355=ZZ2355+ZZ2355
-+006616 014225 0 8192 -ZZ1355
-+006617 741400 0 ZZ2355
-- mark 1900, 93 /47 orio
-+006620 000272 ZZ2356=ZZ2356+ZZ2356
-+006620 000564 ZZ2356=ZZ2356+ZZ2356
-+006620 001350 ZZ2356=ZZ2356+ZZ2356
-+006620 002720 ZZ2356=ZZ2356+ZZ2356
-+006620 005640 ZZ2356=ZZ2356+ZZ2356
-+006620 013500 ZZ2356=ZZ2356+ZZ2356
-+006620 027200 ZZ2356=ZZ2356+ZZ2356
-+006620 056400 ZZ2356=ZZ2356+ZZ2356
-+006620 014224 0 8192 -ZZ1356
-+006621 056400 0 ZZ2356
-- mark 1900, -165 /49 orio
-+006622 777264 ZZ2357=ZZ2357+ZZ2357
-+006622 776550 ZZ2357=ZZ2357+ZZ2357
-+006622 775320 ZZ2357=ZZ2357+ZZ2357
-+006622 772640 ZZ2357=ZZ2357+ZZ2357
-+006622 765500 ZZ2357=ZZ2357+ZZ2357
-+006622 753200 ZZ2357=ZZ2357+ZZ2357
-+006622 726400 ZZ2357=ZZ2357+ZZ2357
-+006622 655000 ZZ2357=ZZ2357+ZZ2357
-+006622 014224 0 8192 -ZZ1357
-+006623 655000 0 ZZ2357
-- mark 1909, 375 /126 taur
-+006624 001356 ZZ2358=ZZ2358+ZZ2358
-+006624 002734 ZZ2358=ZZ2358+ZZ2358
-+006624 005670 ZZ2358=ZZ2358+ZZ2358
-+006624 013560 ZZ2358=ZZ2358+ZZ2358
-+006624 027340 ZZ2358=ZZ2358+ZZ2358
-+006624 056700 ZZ2358=ZZ2358+ZZ2358
-+006624 135600 ZZ2358=ZZ2358+ZZ2358
-+006624 273400 ZZ2358=ZZ2358+ZZ2358
-+006624 014213 0 8192 -ZZ1358
-+006625 273400 0 ZZ2358
-- mark 1936, -511 /13 leps
-+006626 776000 ZZ2359=ZZ2359+ZZ2359
-+006626 774000 ZZ2359=ZZ2359+ZZ2359
-+006626 770000 ZZ2359=ZZ2359+ZZ2359
-+006626 760000 ZZ2359=ZZ2359+ZZ2359
-+006626 740000 ZZ2359=ZZ2359+ZZ2359
-+006626 700000 ZZ2359=ZZ2359+ZZ2359
-+006626 600000 ZZ2359=ZZ2359+ZZ2359
-+006626 400000 ZZ2359=ZZ2359+ZZ2359
-+006626 014160 0 8192 -ZZ1359
-+006627 400000 0 ZZ2359
-- mark 1957, 287 /134 taur
-+006630 001076 ZZ2360=ZZ2360+ZZ2360
-+006630 002174 ZZ2360=ZZ2360+ZZ2360
-+006630 004370 ZZ2360=ZZ2360+ZZ2360
-+006630 010760 ZZ2360=ZZ2360+ZZ2360
-+006630 021740 ZZ2360=ZZ2360+ZZ2360
-+006630 043700 ZZ2360=ZZ2360+ZZ2360
-+006630 107600 ZZ2360=ZZ2360+ZZ2360
-+006630 217400 ZZ2360=ZZ2360+ZZ2360
-+006630 014133 0 8192 -ZZ1360
-+006631 217400 0 ZZ2360
-- mark 1974, -475 /15 leps
-+006632 776110 ZZ2361=ZZ2361+ZZ2361
-+006632 774220 ZZ2361=ZZ2361+ZZ2361
-+006632 770440 ZZ2361=ZZ2361+ZZ2361
-+006632 761100 ZZ2361=ZZ2361+ZZ2361
-+006632 742200 ZZ2361=ZZ2361+ZZ2361
-+006632 704400 ZZ2361=ZZ2361+ZZ2361
-+006632 611000 ZZ2361=ZZ2361+ZZ2361
-+006632 422000 ZZ2361=ZZ2361+ZZ2361
-+006632 014112 0 8192 -ZZ1361
-+006633 422000 0 ZZ2361
-- mark 1982, 461 /54 orio
-+006634 001632 ZZ2362=ZZ2362+ZZ2362
-+006634 003464 ZZ2362=ZZ2362+ZZ2362
-+006634 007150 ZZ2362=ZZ2362+ZZ2362
-+006634 016320 ZZ2362=ZZ2362+ZZ2362
-+006634 034640 ZZ2362=ZZ2362+ZZ2362
-+006634 071500 ZZ2362=ZZ2362+ZZ2362
-+006634 163200 ZZ2362=ZZ2362+ZZ2362
-+006634 346400 ZZ2362=ZZ2362+ZZ2362
-+006634 014102 0 8192 -ZZ1362
-+006635 346400 0 ZZ2362
-- mark 2002, -323 /16 leps
-+006636 776570 ZZ2363=ZZ2363+ZZ2363
-+006636 775360 ZZ2363=ZZ2363+ZZ2363
-+006636 772740 ZZ2363=ZZ2363+ZZ2363
-+006636 765700 ZZ2363=ZZ2363+ZZ2363
-+006636 753600 ZZ2363=ZZ2363+ZZ2363
-+006636 727400 ZZ2363=ZZ2363+ZZ2363
-+006636 657000 ZZ2363=ZZ2363+ZZ2363
-+006636 536000 ZZ2363=ZZ2363+ZZ2363
-+006636 014056 0 8192 -ZZ1363
-+006637 536000 0 ZZ2363
-- mark 2020, -70 /
-+006640 777562 ZZ2364=ZZ2364+ZZ2364
-+006640 777344 ZZ2364=ZZ2364+ZZ2364
-+006640 776710 ZZ2364=ZZ2364+ZZ2364
-+006640 775620 ZZ2364=ZZ2364+ZZ2364
-+006640 773440 ZZ2364=ZZ2364+ZZ2364
-+006640 767100 ZZ2364=ZZ2364+ZZ2364
-+006640 756200 ZZ2364=ZZ2364+ZZ2364
-+006640 734400 ZZ2364=ZZ2364+ZZ2364
-+006640 014034 0 8192 -ZZ1364
-+006641 734400 0 ZZ2364
-- mark 2030, 220 /61 orio
-+006642 000670 ZZ2365=ZZ2365+ZZ2365
-+006642 001560 ZZ2365=ZZ2365+ZZ2365
-+006642 003340 ZZ2365=ZZ2365+ZZ2365
-+006642 006700 ZZ2365=ZZ2365+ZZ2365
-+006642 015600 ZZ2365=ZZ2365+ZZ2365
-+006642 033400 ZZ2365=ZZ2365+ZZ2365
-+006642 067000 ZZ2365=ZZ2365+ZZ2365
-+006642 156000 ZZ2365=ZZ2365+ZZ2365
-+006642 014022 0 8192 -ZZ1365
-+006643 156000 0 ZZ2365
-- mark 2032, -241 / 3 mono
-+006644 777034 ZZ2366=ZZ2366+ZZ2366
-+006644 776070 ZZ2366=ZZ2366+ZZ2366
-+006644 774160 ZZ2366=ZZ2366+ZZ2366
-+006644 770340 ZZ2366=ZZ2366+ZZ2366
-+006644 760700 ZZ2366=ZZ2366+ZZ2366
-+006644 741600 ZZ2366=ZZ2366+ZZ2366
-+006644 703400 ZZ2366=ZZ2366+ZZ2366
-+006644 607000 ZZ2366=ZZ2366+ZZ2366
-+006644 014020 0 8192 -ZZ1366
-+006645 607000 0 ZZ2366
-- mark 2037, 458 /62 orio
-+006646 001624 ZZ2367=ZZ2367+ZZ2367
-+006646 003450 ZZ2367=ZZ2367+ZZ2367
-+006646 007120 ZZ2367=ZZ2367+ZZ2367
-+006646 016240 ZZ2367=ZZ2367+ZZ2367
-+006646 034500 ZZ2367=ZZ2367+ZZ2367
-+006646 071200 ZZ2367=ZZ2367+ZZ2367
-+006646 162400 ZZ2367=ZZ2367+ZZ2367
-+006646 345000 ZZ2367=ZZ2367+ZZ2367
-+006646 014013 0 8192 -ZZ1367
-+006647 345000 0 ZZ2367
-- mark 2057, -340 /18 leps
-+006650 776526 ZZ2368=ZZ2368+ZZ2368
-+006650 775254 ZZ2368=ZZ2368+ZZ2368
-+006650 772530 ZZ2368=ZZ2368+ZZ2368
-+006650 765260 ZZ2368=ZZ2368+ZZ2368
-+006650 752540 ZZ2368=ZZ2368+ZZ2368
-+006650 725300 ZZ2368=ZZ2368+ZZ2368
-+006650 652600 ZZ2368=ZZ2368+ZZ2368
-+006650 525400 ZZ2368=ZZ2368+ZZ2368
-+006650 013767 0 8192 -ZZ1368
-+006651 525400 0 ZZ2368
-- mark 2059, 336 /67 orio
-+006652 001240 ZZ2369=ZZ2369+ZZ2369
-+006652 002500 ZZ2369=ZZ2369+ZZ2369
-+006652 005200 ZZ2369=ZZ2369+ZZ2369
-+006652 012400 ZZ2369=ZZ2369+ZZ2369
-+006652 025000 ZZ2369=ZZ2369+ZZ2369
-+006652 052000 ZZ2369=ZZ2369+ZZ2369
-+006652 124000 ZZ2369=ZZ2369+ZZ2369
-+006652 250000 ZZ2369=ZZ2369+ZZ2369
-+006652 013765 0 8192 -ZZ1369
-+006653 250000 0 ZZ2369
-- mark 2084, 368 /69 orio
-+006654 001340 ZZ2370=ZZ2370+ZZ2370
-+006654 002700 ZZ2370=ZZ2370+ZZ2370
-+006654 005600 ZZ2370=ZZ2370+ZZ2370
-+006654 013400 ZZ2370=ZZ2370+ZZ2370
-+006654 027000 ZZ2370=ZZ2370+ZZ2370
-+006654 056000 ZZ2370=ZZ2370+ZZ2370
-+006654 134000 ZZ2370=ZZ2370+ZZ2370
-+006654 270000 ZZ2370=ZZ2370+ZZ2370
-+006654 013734 0 8192 -ZZ1370
-+006655 270000 0 ZZ2370
-- mark 2084, 324 /70 orio
-+006656 001210 ZZ2371=ZZ2371+ZZ2371
-+006656 002420 ZZ2371=ZZ2371+ZZ2371
-+006656 005040 ZZ2371=ZZ2371+ZZ2371
-+006656 012100 ZZ2371=ZZ2371+ZZ2371
-+006656 024200 ZZ2371=ZZ2371+ZZ2371
-+006656 050400 ZZ2371=ZZ2371+ZZ2371
-+006656 121000 ZZ2371=ZZ2371+ZZ2371
-+006656 242000 ZZ2371=ZZ2371+ZZ2371
-+006656 013734 0 8192 -ZZ1371
-+006657 242000 0 ZZ2371
-- mark 2105, -142 / 5 mono
-+006660 777342 ZZ2372=ZZ2372+ZZ2372
-+006660 776704 ZZ2372=ZZ2372+ZZ2372
-+006660 775610 ZZ2372=ZZ2372+ZZ2372
-+006660 773420 ZZ2372=ZZ2372+ZZ2372
-+006660 767040 ZZ2372=ZZ2372+ZZ2372
-+006660 756100 ZZ2372=ZZ2372+ZZ2372
-+006660 734200 ZZ2372=ZZ2372+ZZ2372
-+006660 670400 ZZ2372=ZZ2372+ZZ2372
-+006660 013707 0 8192 -ZZ1372
-+006661 670400 0 ZZ2372
-- mark 2112, -311 /
-+006662 776620 ZZ2373=ZZ2373+ZZ2373
-+006662 775440 ZZ2373=ZZ2373+ZZ2373
-+006662 773100 ZZ2373=ZZ2373+ZZ2373
-+006662 766200 ZZ2373=ZZ2373+ZZ2373
-+006662 754400 ZZ2373=ZZ2373+ZZ2373
-+006662 731000 ZZ2373=ZZ2373+ZZ2373
-+006662 662000 ZZ2373=ZZ2373+ZZ2373
-+006662 544000 ZZ2373=ZZ2373+ZZ2373
-+006662 013700 0 8192 -ZZ1373
-+006663 544000 0 ZZ2373
-- mark 2153, 106 / 8 mono
-+006664 000324 ZZ2374=ZZ2374+ZZ2374
-+006664 000650 ZZ2374=ZZ2374+ZZ2374
-+006664 001520 ZZ2374=ZZ2374+ZZ2374
-+006664 003240 ZZ2374=ZZ2374+ZZ2374
-+006664 006500 ZZ2374=ZZ2374+ZZ2374
-+006664 015200 ZZ2374=ZZ2374+ZZ2374
-+006664 032400 ZZ2374=ZZ2374+ZZ2374
-+006664 065000 ZZ2374=ZZ2374+ZZ2374
-+006664 013627 0 8192 -ZZ1374
-+006665 065000 0 ZZ2374
-- mark 2179, 462 /18 gemi
-+006666 001634 ZZ2375=ZZ2375+ZZ2375
-+006666 003470 ZZ2375=ZZ2375+ZZ2375
-+006666 007160 ZZ2375=ZZ2375+ZZ2375
-+006666 016340 ZZ2375=ZZ2375+ZZ2375
-+006666 034700 ZZ2375=ZZ2375+ZZ2375
-+006666 071600 ZZ2375=ZZ2375+ZZ2375
-+006666 163400 ZZ2375=ZZ2375+ZZ2375
-+006666 347000 ZZ2375=ZZ2375+ZZ2375
-+006666 013575 0 8192 -ZZ1375
-+006667 347000 0 ZZ2375
-- mark 2179, -107 /10 mono
-+006670 777450 ZZ2376=ZZ2376+ZZ2376
-+006670 777120 ZZ2376=ZZ2376+ZZ2376
-+006670 776240 ZZ2376=ZZ2376+ZZ2376
-+006670 774500 ZZ2376=ZZ2376+ZZ2376
-+006670 771200 ZZ2376=ZZ2376+ZZ2376
-+006670 762400 ZZ2376=ZZ2376+ZZ2376
-+006670 745000 ZZ2376=ZZ2376+ZZ2376
-+006670 712000 ZZ2376=ZZ2376+ZZ2376
-+006670 013575 0 8192 -ZZ1376
-+006671 712000 0 ZZ2376
-- mark 2184, -159 /11 mono
-+006672 777300 ZZ2377=ZZ2377+ZZ2377
-+006672 776600 ZZ2377=ZZ2377+ZZ2377
-+006672 775400 ZZ2377=ZZ2377+ZZ2377
-+006672 773000 ZZ2377=ZZ2377+ZZ2377
-+006672 766000 ZZ2377=ZZ2377+ZZ2377
-+006672 754000 ZZ2377=ZZ2377+ZZ2377
-+006672 730000 ZZ2377=ZZ2377+ZZ2377
-+006672 660000 ZZ2377=ZZ2377+ZZ2377
-+006672 013570 0 8192 -ZZ1377
-+006673 660000 0 ZZ2377
-- mark 2204, 168 /13 mono
-+006674 000520 ZZ2378=ZZ2378+ZZ2378
-+006674 001240 ZZ2378=ZZ2378+ZZ2378
-+006674 002500 ZZ2378=ZZ2378+ZZ2378
-+006674 005200 ZZ2378=ZZ2378+ZZ2378
-+006674 012400 ZZ2378=ZZ2378+ZZ2378
-+006674 025000 ZZ2378=ZZ2378+ZZ2378
-+006674 052000 ZZ2378=ZZ2378+ZZ2378
-+006674 124000 ZZ2378=ZZ2378+ZZ2378
-+006674 013544 0 8192 -ZZ1378
-+006675 124000 0 ZZ2378
-- mark 2232, -436 / 7 cmaj
-+006676 776226 ZZ2379=ZZ2379+ZZ2379
-+006676 774454 ZZ2379=ZZ2379+ZZ2379
-+006676 771130 ZZ2379=ZZ2379+ZZ2379
-+006676 762260 ZZ2379=ZZ2379+ZZ2379
-+006676 744540 ZZ2379=ZZ2379+ZZ2379
-+006676 711300 ZZ2379=ZZ2379+ZZ2379
-+006676 622600 ZZ2379=ZZ2379+ZZ2379
-+006676 445400 ZZ2379=ZZ2379+ZZ2379
-+006676 013510 0 8192 -ZZ1379
-+006677 445400 0 ZZ2379
-- mark 2239, -413 / 8 cmaj
-+006700 776304 ZZ2380=ZZ2380+ZZ2380
-+006700 774610 ZZ2380=ZZ2380+ZZ2380
-+006700 771420 ZZ2380=ZZ2380+ZZ2380
-+006700 763040 ZZ2380=ZZ2380+ZZ2380
-+006700 746100 ZZ2380=ZZ2380+ZZ2380
-+006700 714200 ZZ2380=ZZ2380+ZZ2380
-+006700 630400 ZZ2380=ZZ2380+ZZ2380
-+006700 461000 ZZ2380=ZZ2380+ZZ2380
-+006700 013501 0 8192 -ZZ1380
-+006701 461000 0 ZZ2380
-- mark 2245, -320 /
-+006702 776576 ZZ2381=ZZ2381+ZZ2381
-+006702 775374 ZZ2381=ZZ2381+ZZ2381
-+006702 772770 ZZ2381=ZZ2381+ZZ2381
-+006702 765760 ZZ2381=ZZ2381+ZZ2381
-+006702 753740 ZZ2381=ZZ2381+ZZ2381
-+006702 727700 ZZ2381=ZZ2381+ZZ2381
-+006702 657600 ZZ2381=ZZ2381+ZZ2381
-+006702 537400 ZZ2381=ZZ2381+ZZ2381
-+006702 013473 0 8192 -ZZ1381
-+006703 537400 0 ZZ2381
-- mark 2250, 227 /15 mono
-+006704 000706 ZZ2382=ZZ2382+ZZ2382
-+006704 001614 ZZ2382=ZZ2382+ZZ2382
-+006704 003430 ZZ2382=ZZ2382+ZZ2382
-+006704 007060 ZZ2382=ZZ2382+ZZ2382
-+006704 016140 ZZ2382=ZZ2382+ZZ2382
-+006704 034300 ZZ2382=ZZ2382+ZZ2382
-+006704 070600 ZZ2382=ZZ2382+ZZ2382
-+006704 161400 ZZ2382=ZZ2382+ZZ2382
-+006704 013466 0 8192 -ZZ1382
-+006705 161400 0 ZZ2382
-- mark 2266, 303 /30 gemi
-+006706 001136 ZZ2383=ZZ2383+ZZ2383
-+006706 002274 ZZ2383=ZZ2383+ZZ2383
-+006706 004570 ZZ2383=ZZ2383+ZZ2383
-+006706 011360 ZZ2383=ZZ2383+ZZ2383
-+006706 022740 ZZ2383=ZZ2383+ZZ2383
-+006706 045700 ZZ2383=ZZ2383+ZZ2383
-+006706 113600 ZZ2383=ZZ2383+ZZ2383
-+006706 227400 ZZ2383=ZZ2383+ZZ2383
-+006706 013446 0 8192 -ZZ1383
-+006707 227400 0 ZZ2383
-- mark 2291, 57 /18 mono
-+006710 000162 ZZ2384=ZZ2384+ZZ2384
-+006710 000344 ZZ2384=ZZ2384+ZZ2384
-+006710 000710 ZZ2384=ZZ2384+ZZ2384
-+006710 001620 ZZ2384=ZZ2384+ZZ2384
-+006710 003440 ZZ2384=ZZ2384+ZZ2384
-+006710 007100 ZZ2384=ZZ2384+ZZ2384
-+006710 016200 ZZ2384=ZZ2384+ZZ2384
-+006710 034400 ZZ2384=ZZ2384+ZZ2384
-+006710 013415 0 8192 -ZZ1384
-+006711 034400 0 ZZ2384
-- mark 2327, 303 /38 gemi
-+006712 001136 ZZ2385=ZZ2385+ZZ2385
-+006712 002274 ZZ2385=ZZ2385+ZZ2385
-+006712 004570 ZZ2385=ZZ2385+ZZ2385
-+006712 011360 ZZ2385=ZZ2385+ZZ2385
-+006712 022740 ZZ2385=ZZ2385+ZZ2385
-+006712 045700 ZZ2385=ZZ2385+ZZ2385
-+006712 113600 ZZ2385=ZZ2385+ZZ2385
-+006712 227400 ZZ2385=ZZ2385+ZZ2385
-+006712 013351 0 8192 -ZZ1385
-+006713 227400 0 ZZ2385
-- mark 2328, -457 /15 cmaj
-+006714 776154 ZZ2386=ZZ2386+ZZ2386
-+006714 774330 ZZ2386=ZZ2386+ZZ2386
-+006714 770660 ZZ2386=ZZ2386+ZZ2386
-+006714 761540 ZZ2386=ZZ2386+ZZ2386
-+006714 743300 ZZ2386=ZZ2386+ZZ2386
-+006714 706600 ZZ2386=ZZ2386+ZZ2386
-+006714 615400 ZZ2386=ZZ2386+ZZ2386
-+006714 433000 ZZ2386=ZZ2386+ZZ2386
-+006714 013350 0 8192 -ZZ1386
-+006715 433000 0 ZZ2386
-- mark 2330, -271 /14 cmaj
-+006716 776740 ZZ2387=ZZ2387+ZZ2387
-+006716 775700 ZZ2387=ZZ2387+ZZ2387
-+006716 773600 ZZ2387=ZZ2387+ZZ2387
-+006716 767400 ZZ2387=ZZ2387+ZZ2387
-+006716 757000 ZZ2387=ZZ2387+ZZ2387
-+006716 736000 ZZ2387=ZZ2387+ZZ2387
-+006716 674000 ZZ2387=ZZ2387+ZZ2387
-+006716 570000 ZZ2387=ZZ2387+ZZ2387
-+006716 013346 0 8192 -ZZ1387
-+006717 570000 0 ZZ2387
-- mark 2340, -456 /19 cmaj
-+006720 776156 ZZ2388=ZZ2388+ZZ2388
-+006720 774334 ZZ2388=ZZ2388+ZZ2388
-+006720 770670 ZZ2388=ZZ2388+ZZ2388
-+006720 761560 ZZ2388=ZZ2388+ZZ2388
-+006720 743340 ZZ2388=ZZ2388+ZZ2388
-+006720 706700 ZZ2388=ZZ2388+ZZ2388
-+006720 615600 ZZ2388=ZZ2388+ZZ2388
-+006720 433400 ZZ2388=ZZ2388+ZZ2388
-+006720 013334 0 8192 -ZZ1388
-+006721 433400 0 ZZ2388
-- mark 2342, -385 /20 cmaj
-+006722 776374 ZZ2389=ZZ2389+ZZ2389
-+006722 774770 ZZ2389=ZZ2389+ZZ2389
-+006722 771760 ZZ2389=ZZ2389+ZZ2389
-+006722 763740 ZZ2389=ZZ2389+ZZ2389
-+006722 747700 ZZ2389=ZZ2389+ZZ2389
-+006722 717600 ZZ2389=ZZ2389+ZZ2389
-+006722 637400 ZZ2389=ZZ2389+ZZ2389
-+006722 477000 ZZ2389=ZZ2389+ZZ2389
-+006722 013332 0 8192 -ZZ1389
-+006723 477000 0 ZZ2389
-- mark 2378, -93 /19 mono
-+006724 777504 ZZ2390=ZZ2390+ZZ2390
-+006724 777210 ZZ2390=ZZ2390+ZZ2390
-+006724 776420 ZZ2390=ZZ2390+ZZ2390
-+006724 775040 ZZ2390=ZZ2390+ZZ2390
-+006724 772100 ZZ2390=ZZ2390+ZZ2390
-+006724 764200 ZZ2390=ZZ2390+ZZ2390
-+006724 750400 ZZ2390=ZZ2390+ZZ2390
-+006724 721000 ZZ2390=ZZ2390+ZZ2390
-+006724 013266 0 8192 -ZZ1390
-+006725 721000 0 ZZ2390
-- mark 2379, 471 /43 gemi
-+006726 001656 ZZ2391=ZZ2391+ZZ2391
-+006726 003534 ZZ2391=ZZ2391+ZZ2391
-+006726 007270 ZZ2391=ZZ2391+ZZ2391
-+006726 016560 ZZ2391=ZZ2391+ZZ2391
-+006726 035340 ZZ2391=ZZ2391+ZZ2391
-+006726 072700 ZZ2391=ZZ2391+ZZ2391
-+006726 165600 ZZ2391=ZZ2391+ZZ2391
-+006726 353400 ZZ2391=ZZ2391+ZZ2391
-+006726 013265 0 8192 -ZZ1391
-+006727 353400 0 ZZ2391
-- mark 2385, -352 /23 cmaj
-+006730 776476 ZZ2392=ZZ2392+ZZ2392
-+006730 775174 ZZ2392=ZZ2392+ZZ2392
-+006730 772370 ZZ2392=ZZ2392+ZZ2392
-+006730 764760 ZZ2392=ZZ2392+ZZ2392
-+006730 751740 ZZ2392=ZZ2392+ZZ2392
-+006730 723700 ZZ2392=ZZ2392+ZZ2392
-+006730 647600 ZZ2392=ZZ2392+ZZ2392
-+006730 517400 ZZ2392=ZZ2392+ZZ2392
-+006730 013257 0 8192 -ZZ1392
-+006731 517400 0 ZZ2392
-- mark 2428, -8 /22 mono
-+006732 777756 ZZ2393=ZZ2393+ZZ2393
-+006732 777734 ZZ2393=ZZ2393+ZZ2393
-+006732 777670 ZZ2393=ZZ2393+ZZ2393
-+006732 777560 ZZ2393=ZZ2393+ZZ2393
-+006732 777340 ZZ2393=ZZ2393+ZZ2393
-+006732 776700 ZZ2393=ZZ2393+ZZ2393
-+006732 775600 ZZ2393=ZZ2393+ZZ2393
-+006732 773400 ZZ2393=ZZ2393+ZZ2393
-+006732 013204 0 8192 -ZZ1393
-+006733 773400 0 ZZ2393
-- mark 2491, -429 /
-+006734 776244 ZZ2394=ZZ2394+ZZ2394
-+006734 774510 ZZ2394=ZZ2394+ZZ2394
-+006734 771220 ZZ2394=ZZ2394+ZZ2394
-+006734 762440 ZZ2394=ZZ2394+ZZ2394
-+006734 745100 ZZ2394=ZZ2394+ZZ2394
-+006734 712200 ZZ2394=ZZ2394+ZZ2394
-+006734 624400 ZZ2394=ZZ2394+ZZ2394
-+006734 451000 ZZ2394=ZZ2394+ZZ2394
-+006734 013105 0 8192 -ZZ1394
-+006735 451000 0 ZZ2394
-- mark 2519, 208 / 4 cmin
-+006736 000640 ZZ2395=ZZ2395+ZZ2395
-+006736 001500 ZZ2395=ZZ2395+ZZ2395
-+006736 003200 ZZ2395=ZZ2395+ZZ2395
-+006736 006400 ZZ2395=ZZ2395+ZZ2395
-+006736 015000 ZZ2395=ZZ2395+ZZ2395
-+006736 032000 ZZ2395=ZZ2395+ZZ2395
-+006736 064000 ZZ2395=ZZ2395+ZZ2395
-+006736 150000 ZZ2395=ZZ2395+ZZ2395
-+006736 013051 0 8192 -ZZ1395
-+006737 150000 0 ZZ2395
-- mark 2527, 278 / 6 cmin
-+006740 001054 ZZ2396=ZZ2396+ZZ2396
-+006740 002130 ZZ2396=ZZ2396+ZZ2396
-+006740 004260 ZZ2396=ZZ2396+ZZ2396
-+006740 010540 ZZ2396=ZZ2396+ZZ2396
-+006740 021300 ZZ2396=ZZ2396+ZZ2396
-+006740 042600 ZZ2396=ZZ2396+ZZ2396
-+006740 105400 ZZ2396=ZZ2396+ZZ2396
-+006740 213000 ZZ2396=ZZ2396+ZZ2396
-+006740 013041 0 8192 -ZZ1396
-+006741 213000 0 ZZ2396
-- mark 2559, -503 /
-+006742 776020 ZZ2397=ZZ2397+ZZ2397
-+006742 774040 ZZ2397=ZZ2397+ZZ2397
-+006742 770100 ZZ2397=ZZ2397+ZZ2397
-+006742 760200 ZZ2397=ZZ2397+ZZ2397
-+006742 740400 ZZ2397=ZZ2397+ZZ2397
-+006742 701000 ZZ2397=ZZ2397+ZZ2397
-+006742 602000 ZZ2397=ZZ2397+ZZ2397
-+006742 404000 ZZ2397=ZZ2397+ZZ2397
-+006742 013001 0 8192 -ZZ1397
-+006743 404000 0 ZZ2397
-- mark 2597, -212 /26 mono
-+006744 777126 ZZ2398=ZZ2398+ZZ2398
-+006744 776254 ZZ2398=ZZ2398+ZZ2398
-+006744 774530 ZZ2398=ZZ2398+ZZ2398
-+006744 771260 ZZ2398=ZZ2398+ZZ2398
-+006744 762540 ZZ2398=ZZ2398+ZZ2398
-+006744 745300 ZZ2398=ZZ2398+ZZ2398
-+006744 712600 ZZ2398=ZZ2398+ZZ2398
-+006744 625400 ZZ2398=ZZ2398+ZZ2398
-+006744 012733 0 8192 -ZZ1398
-+006745 625400 0 ZZ2398
-- mark 2704, -412 /
-+006746 776306 ZZ2399=ZZ2399+ZZ2399
-+006746 774614 ZZ2399=ZZ2399+ZZ2399
-+006746 771430 ZZ2399=ZZ2399+ZZ2399
-+006746 763060 ZZ2399=ZZ2399+ZZ2399
-+006746 746140 ZZ2399=ZZ2399+ZZ2399
-+006746 714300 ZZ2399=ZZ2399+ZZ2399
-+006746 630600 ZZ2399=ZZ2399+ZZ2399
-+006746 461400 ZZ2399=ZZ2399+ZZ2399
-+006746 012560 0 8192 -ZZ1399
-+006747 461400 0 ZZ2399
-- mark 2709, -25 /28 mono
-+006750 777714 ZZ2400=ZZ2400+ZZ2400
-+006750 777630 ZZ2400=ZZ2400+ZZ2400
-+006750 777460 ZZ2400=ZZ2400+ZZ2400
-+006750 777140 ZZ2400=ZZ2400+ZZ2400
-+006750 776300 ZZ2400=ZZ2400+ZZ2400
-+006750 774600 ZZ2400=ZZ2400+ZZ2400
-+006750 771400 ZZ2400=ZZ2400+ZZ2400
-+006750 763000 ZZ2400=ZZ2400+ZZ2400
-+006750 012553 0 8192 -ZZ1400
-+006751 763000 0 ZZ2400
-- mark 2714, 60 /
-+006752 000170 ZZ2401=ZZ2401+ZZ2401
-+006752 000360 ZZ2401=ZZ2401+ZZ2401
-+006752 000740 ZZ2401=ZZ2401+ZZ2401
-+006752 001700 ZZ2401=ZZ2401+ZZ2401
-+006752 003600 ZZ2401=ZZ2401+ZZ2401
-+006752 007400 ZZ2401=ZZ2401+ZZ2401
-+006752 017000 ZZ2401=ZZ2401+ZZ2401
-+006752 036000 ZZ2401=ZZ2401+ZZ2401
-+006752 012546 0 8192 -ZZ1401
-+006753 036000 0 ZZ2401
-- mark 2751, -61 /29 mono
-+006754 777604 ZZ2402=ZZ2402+ZZ2402
-+006754 777410 ZZ2402=ZZ2402+ZZ2402
-+006754 777020 ZZ2402=ZZ2402+ZZ2402
-+006754 776040 ZZ2402=ZZ2402+ZZ2402
-+006754 774100 ZZ2402=ZZ2402+ZZ2402
-+006754 770200 ZZ2402=ZZ2402+ZZ2402
-+006754 760400 ZZ2402=ZZ2402+ZZ2402
-+006754 741000 ZZ2402=ZZ2402+ZZ2402
-+006754 012501 0 8192 -ZZ1402
-+006755 741000 0 ZZ2402
-- mark 2757, -431 /16 pupp
-+006756 776240 ZZ2403=ZZ2403+ZZ2403
-+006756 774500 ZZ2403=ZZ2403+ZZ2403
-+006756 771200 ZZ2403=ZZ2403+ZZ2403
-+006756 762400 ZZ2403=ZZ2403+ZZ2403
-+006756 745000 ZZ2403=ZZ2403+ZZ2403
-+006756 712000 ZZ2403=ZZ2403+ZZ2403
-+006756 624000 ZZ2403=ZZ2403+ZZ2403
-+006756 450000 ZZ2403=ZZ2403+ZZ2403
-+006756 012473 0 8192 -ZZ1403
-+006757 450000 0 ZZ2403
-- mark 2768, -288 /19 pupp
-+006760 776676 ZZ2404=ZZ2404+ZZ2404
-+006760 775574 ZZ2404=ZZ2404+ZZ2404
-+006760 773370 ZZ2404=ZZ2404+ZZ2404
-+006760 766760 ZZ2404=ZZ2404+ZZ2404
-+006760 755740 ZZ2404=ZZ2404+ZZ2404
-+006760 733700 ZZ2404=ZZ2404+ZZ2404
-+006760 667600 ZZ2404=ZZ2404+ZZ2404
-+006760 557400 ZZ2404=ZZ2404+ZZ2404
-+006760 012460 0 8192 -ZZ1404
-+006761 557400 0 ZZ2404
-- mark 2794, 216 /17 canc
-+006762 000660 ZZ2405=ZZ2405+ZZ2405
-+006762 001540 ZZ2405=ZZ2405+ZZ2405
-+006762 003300 ZZ2405=ZZ2405+ZZ2405
-+006762 006600 ZZ2405=ZZ2405+ZZ2405
-+006762 015400 ZZ2405=ZZ2405+ZZ2405
-+006762 033000 ZZ2405=ZZ2405+ZZ2405
-+006762 066000 ZZ2405=ZZ2405+ZZ2405
-+006762 154000 ZZ2405=ZZ2405+ZZ2405
-+006762 012426 0 8192 -ZZ1405
-+006763 154000 0 ZZ2405
-- mark 2848, -82 /
-+006764 777532 ZZ2406=ZZ2406+ZZ2406
-+006764 777264 ZZ2406=ZZ2406+ZZ2406
-+006764 776550 ZZ2406=ZZ2406+ZZ2406
-+006764 775320 ZZ2406=ZZ2406+ZZ2406
-+006764 772640 ZZ2406=ZZ2406+ZZ2406
-+006764 765500 ZZ2406=ZZ2406+ZZ2406
-+006764 753200 ZZ2406=ZZ2406+ZZ2406
-+006764 726400 ZZ2406=ZZ2406+ZZ2406
-+006764 012340 0 8192 -ZZ1406
-+006765 726400 0 ZZ2406
-- mark 2915, 138 / 4 hyda
-+006766 000424 ZZ2407=ZZ2407+ZZ2407
-+006766 001050 ZZ2407=ZZ2407+ZZ2407
-+006766 002120 ZZ2407=ZZ2407+ZZ2407
-+006766 004240 ZZ2407=ZZ2407+ZZ2407
-+006766 010500 ZZ2407=ZZ2407+ZZ2407
-+006766 021200 ZZ2407=ZZ2407+ZZ2407
-+006766 042400 ZZ2407=ZZ2407+ZZ2407
-+006766 105000 ZZ2407=ZZ2407+ZZ2407
-+006766 012235 0 8192 -ZZ1407
-+006767 105000 0 ZZ2407
-- mark 2921, 84 / 5 hyda
-+006770 000250 ZZ2408=ZZ2408+ZZ2408
-+006770 000520 ZZ2408=ZZ2408+ZZ2408
-+006770 001240 ZZ2408=ZZ2408+ZZ2408
-+006770 002500 ZZ2408=ZZ2408+ZZ2408
-+006770 005200 ZZ2408=ZZ2408+ZZ2408
-+006770 012400 ZZ2408=ZZ2408+ZZ2408
-+006770 025000 ZZ2408=ZZ2408+ZZ2408
-+006770 052000 ZZ2408=ZZ2408+ZZ2408
-+006770 012227 0 8192 -ZZ1408
-+006771 052000 0 ZZ2408
-- mark 2942, -355 / 9 hyda
-+006772 776470 ZZ2409=ZZ2409+ZZ2409
-+006772 775160 ZZ2409=ZZ2409+ZZ2409
-+006772 772340 ZZ2409=ZZ2409+ZZ2409
-+006772 764700 ZZ2409=ZZ2409+ZZ2409
-+006772 751600 ZZ2409=ZZ2409+ZZ2409
-+006772 723400 ZZ2409=ZZ2409+ZZ2409
-+006772 647000 ZZ2409=ZZ2409+ZZ2409
-+006772 516000 ZZ2409=ZZ2409+ZZ2409
-+006772 012202 0 8192 -ZZ1409
-+006773 516000 0 ZZ2409
-- mark 2944, 497 /43 canc
-+006774 001742 ZZ2410=ZZ2410+ZZ2410
-+006774 003704 ZZ2410=ZZ2410+ZZ2410
-+006774 007610 ZZ2410=ZZ2410+ZZ2410
-+006774 017420 ZZ2410=ZZ2410+ZZ2410
-+006774 037040 ZZ2410=ZZ2410+ZZ2410
-+006774 076100 ZZ2410=ZZ2410+ZZ2410
-+006774 174200 ZZ2410=ZZ2410+ZZ2410
-+006774 370400 ZZ2410=ZZ2410+ZZ2410
-+006774 012200 0 8192 -ZZ1410
-+006775 370400 0 ZZ2410
-- mark 2947, 85 / 7 hyda
-+006776 000252 ZZ2411=ZZ2411+ZZ2411
-+006776 000524 ZZ2411=ZZ2411+ZZ2411
-+006776 001250 ZZ2411=ZZ2411+ZZ2411
-+006776 002520 ZZ2411=ZZ2411+ZZ2411
-+006776 005240 ZZ2411=ZZ2411+ZZ2411
-+006776 012500 ZZ2411=ZZ2411+ZZ2411
-+006776 025200 ZZ2411=ZZ2411+ZZ2411
-+006776 052400 ZZ2411=ZZ2411+ZZ2411
-+006776 012175 0 8192 -ZZ1411
-+006777 052400 0 ZZ2411
-- mark 2951, -156 /
-+007000 777306 ZZ2412=ZZ2412+ZZ2412
-+007000 776614 ZZ2412=ZZ2412+ZZ2412
-+007000 775430 ZZ2412=ZZ2412+ZZ2412
-+007000 773060 ZZ2412=ZZ2412+ZZ2412
-+007000 766140 ZZ2412=ZZ2412+ZZ2412
-+007000 754300 ZZ2412=ZZ2412+ZZ2412
-+007000 730600 ZZ2412=ZZ2412+ZZ2412
-+007000 661400 ZZ2412=ZZ2412+ZZ2412
-+007000 012171 0 8192 -ZZ1412
-+007001 661400 0 ZZ2412
-- mark 2953, 421 /47 canc
-+007002 001512 ZZ2413=ZZ2413+ZZ2413
-+007002 003224 ZZ2413=ZZ2413+ZZ2413
-+007002 006450 ZZ2413=ZZ2413+ZZ2413
-+007002 015120 ZZ2413=ZZ2413+ZZ2413
-+007002 032240 ZZ2413=ZZ2413+ZZ2413
-+007002 064500 ZZ2413=ZZ2413+ZZ2413
-+007002 151200 ZZ2413=ZZ2413+ZZ2413
-+007002 322400 ZZ2413=ZZ2413+ZZ2413
-+007002 012167 0 8192 -ZZ1413
-+007003 322400 0 ZZ2413
-- mark 2968, -300 /12 hyda
-+007004 776646 ZZ2414=ZZ2414+ZZ2414
-+007004 775514 ZZ2414=ZZ2414+ZZ2414
-+007004 773230 ZZ2414=ZZ2414+ZZ2414
-+007004 766460 ZZ2414=ZZ2414+ZZ2414
-+007004 755140 ZZ2414=ZZ2414+ZZ2414
-+007004 732300 ZZ2414=ZZ2414+ZZ2414
-+007004 664600 ZZ2414=ZZ2414+ZZ2414
-+007004 551400 ZZ2414=ZZ2414+ZZ2414
-+007004 012150 0 8192 -ZZ1414
-+007005 551400 0 ZZ2414
-- mark 2976, 141 /13 hyda
-+007006 000432 ZZ2415=ZZ2415+ZZ2415
-+007006 001064 ZZ2415=ZZ2415+ZZ2415
-+007006 002150 ZZ2415=ZZ2415+ZZ2415
-+007006 004320 ZZ2415=ZZ2415+ZZ2415
-+007006 010640 ZZ2415=ZZ2415+ZZ2415
-+007006 021500 ZZ2415=ZZ2415+ZZ2415
-+007006 043200 ZZ2415=ZZ2415+ZZ2415
-+007006 106400 ZZ2415=ZZ2415+ZZ2415
-+007006 012140 0 8192 -ZZ1415
-+007007 106400 0 ZZ2415
-- mark 3032, 279 /65 canc
-+007010 001056 ZZ2416=ZZ2416+ZZ2416
-+007010 002134 ZZ2416=ZZ2416+ZZ2416
-+007010 004270 ZZ2416=ZZ2416+ZZ2416
-+007010 010560 ZZ2416=ZZ2416+ZZ2416
-+007010 021340 ZZ2416=ZZ2416+ZZ2416
-+007010 042700 ZZ2416=ZZ2416+ZZ2416
-+007010 105600 ZZ2416=ZZ2416+ZZ2416
-+007010 213400 ZZ2416=ZZ2416+ZZ2416
-+007010 012050 0 8192 -ZZ1416
-+007011 213400 0 ZZ2416
-- mark 3124, 62 /22 hyda
-+007012 000174 ZZ2417=ZZ2417+ZZ2417
-+007012 000370 ZZ2417=ZZ2417+ZZ2417
-+007012 000760 ZZ2417=ZZ2417+ZZ2417
-+007012 001740 ZZ2417=ZZ2417+ZZ2417
-+007012 003700 ZZ2417=ZZ2417+ZZ2417
-+007012 007600 ZZ2417=ZZ2417+ZZ2417
-+007012 017400 ZZ2417=ZZ2417+ZZ2417
-+007012 037000 ZZ2417=ZZ2417+ZZ2417
-+007012 011714 0 8192 -ZZ1417
-+007013 037000 0 ZZ2417
-- mark 3157, -263 /26 hyda
-+007014 776760 ZZ2418=ZZ2418+ZZ2418
-+007014 775740 ZZ2418=ZZ2418+ZZ2418
-+007014 773700 ZZ2418=ZZ2418+ZZ2418
-+007014 767600 ZZ2418=ZZ2418+ZZ2418
-+007014 757400 ZZ2418=ZZ2418+ZZ2418
-+007014 737000 ZZ2418=ZZ2418+ZZ2418
-+007014 676000 ZZ2418=ZZ2418+ZZ2418
-+007014 574000 ZZ2418=ZZ2418+ZZ2418
-+007014 011653 0 8192 -ZZ1418
-+007015 574000 0 ZZ2418
-- mark 3161, -208 /27 hyda
-+007016 777136 ZZ2419=ZZ2419+ZZ2419
-+007016 776274 ZZ2419=ZZ2419+ZZ2419
-+007016 774570 ZZ2419=ZZ2419+ZZ2419
-+007016 771360 ZZ2419=ZZ2419+ZZ2419
-+007016 762740 ZZ2419=ZZ2419+ZZ2419
-+007016 745700 ZZ2419=ZZ2419+ZZ2419
-+007016 713600 ZZ2419=ZZ2419+ZZ2419
-+007016 627400 ZZ2419=ZZ2419+ZZ2419
-+007016 011647 0 8192 -ZZ1419
-+007017 627400 0 ZZ2419
-- mark 3209, -53 /31 hyda
-+007020 777624 ZZ2420=ZZ2420+ZZ2420
-+007020 777450 ZZ2420=ZZ2420+ZZ2420
-+007020 777120 ZZ2420=ZZ2420+ZZ2420
-+007020 776240 ZZ2420=ZZ2420+ZZ2420
-+007020 774500 ZZ2420=ZZ2420+ZZ2420
-+007020 771200 ZZ2420=ZZ2420+ZZ2420
-+007020 762400 ZZ2420=ZZ2420+ZZ2420
-+007020 745000 ZZ2420=ZZ2420+ZZ2420
-+007020 011567 0 8192 -ZZ1420
-+007021 745000 0 ZZ2420
-- mark 3225, -17 /32 hyda
-+007022 777734 ZZ2421=ZZ2421+ZZ2421
-+007022 777670 ZZ2421=ZZ2421+ZZ2421
-+007022 777560 ZZ2421=ZZ2421+ZZ2421
-+007022 777340 ZZ2421=ZZ2421+ZZ2421
-+007022 776700 ZZ2421=ZZ2421+ZZ2421
-+007022 775600 ZZ2421=ZZ2421+ZZ2421
-+007022 773400 ZZ2421=ZZ2421+ZZ2421
-+007022 767000 ZZ2421=ZZ2421+ZZ2421
-+007022 011547 0 8192 -ZZ1421
-+007023 767000 0 ZZ2421
-- mark 3261, 116 /
-+007024 000350 ZZ2422=ZZ2422+ZZ2422
-+007024 000720 ZZ2422=ZZ2422+ZZ2422
-+007024 001640 ZZ2422=ZZ2422+ZZ2422
-+007024 003500 ZZ2422=ZZ2422+ZZ2422
-+007024 007200 ZZ2422=ZZ2422+ZZ2422
-+007024 016400 ZZ2422=ZZ2422+ZZ2422
-+007024 035000 ZZ2422=ZZ2422+ZZ2422
-+007024 072000 ZZ2422=ZZ2422+ZZ2422
-+007024 011503 0 8192 -ZZ1422
-+007025 072000 0 ZZ2422
-- mark 3270, -16 /35 hyda
-+007026 777736 ZZ2423=ZZ2423+ZZ2423
-+007026 777674 ZZ2423=ZZ2423+ZZ2423
-+007026 777570 ZZ2423=ZZ2423+ZZ2423
-+007026 777360 ZZ2423=ZZ2423+ZZ2423
-+007026 776740 ZZ2423=ZZ2423+ZZ2423
-+007026 775700 ZZ2423=ZZ2423+ZZ2423
-+007026 773600 ZZ2423=ZZ2423+ZZ2423
-+007026 767400 ZZ2423=ZZ2423+ZZ2423
-+007026 011472 0 8192 -ZZ1423
-+007027 767400 0 ZZ2423
-- mark 3274, -316 /38 hyda
-+007030 776606 ZZ2424=ZZ2424+ZZ2424
-+007030 775414 ZZ2424=ZZ2424+ZZ2424
-+007030 773030 ZZ2424=ZZ2424+ZZ2424
-+007030 766060 ZZ2424=ZZ2424+ZZ2424
-+007030 754140 ZZ2424=ZZ2424+ZZ2424
-+007030 730300 ZZ2424=ZZ2424+ZZ2424
-+007030 660600 ZZ2424=ZZ2424+ZZ2424
-+007030 541400 ZZ2424=ZZ2424+ZZ2424
-+007030 011466 0 8192 -ZZ1424
-+007031 541400 0 ZZ2424
-- mark 3276, 236 /14 leon
-+007032 000730 ZZ2425=ZZ2425+ZZ2425
-+007032 001660 ZZ2425=ZZ2425+ZZ2425
-+007032 003540 ZZ2425=ZZ2425+ZZ2425
-+007032 007300 ZZ2425=ZZ2425+ZZ2425
-+007032 016600 ZZ2425=ZZ2425+ZZ2425
-+007032 035400 ZZ2425=ZZ2425+ZZ2425
-+007032 073000 ZZ2425=ZZ2425+ZZ2425
-+007032 166000 ZZ2425=ZZ2425+ZZ2425
-+007032 011464 0 8192 -ZZ1425
-+007033 166000 0 ZZ2425
-- mark 3338, -327 /39 hyda
-+007034 776560 ZZ2426=ZZ2426+ZZ2426
-+007034 775340 ZZ2426=ZZ2426+ZZ2426
-+007034 772700 ZZ2426=ZZ2426+ZZ2426
-+007034 765600 ZZ2426=ZZ2426+ZZ2426
-+007034 753400 ZZ2426=ZZ2426+ZZ2426
-+007034 727000 ZZ2426=ZZ2426+ZZ2426
-+007034 656000 ZZ2426=ZZ2426+ZZ2426
-+007034 534000 ZZ2426=ZZ2426+ZZ2426
-+007034 011366 0 8192 -ZZ1426
-+007035 534000 0 ZZ2426
-- mark 3385, 194 /29 leon
-+007036 000604 ZZ2427=ZZ2427+ZZ2427
-+007036 001410 ZZ2427=ZZ2427+ZZ2427
-+007036 003020 ZZ2427=ZZ2427+ZZ2427
-+007036 006040 ZZ2427=ZZ2427+ZZ2427
-+007036 014100 ZZ2427=ZZ2427+ZZ2427
-+007036 030200 ZZ2427=ZZ2427+ZZ2427
-+007036 060400 ZZ2427=ZZ2427+ZZ2427
-+007036 141000 ZZ2427=ZZ2427+ZZ2427
-+007036 011307 0 8192 -ZZ1427
-+007037 141000 0 ZZ2427
-- mark 3415, -286 /40 hyda
-+007040 776702 ZZ2428=ZZ2428+ZZ2428
-+007040 775604 ZZ2428=ZZ2428+ZZ2428
-+007040 773410 ZZ2428=ZZ2428+ZZ2428
-+007040 767020 ZZ2428=ZZ2428+ZZ2428
-+007040 756040 ZZ2428=ZZ2428+ZZ2428
-+007040 734100 ZZ2428=ZZ2428+ZZ2428
-+007040 670200 ZZ2428=ZZ2428+ZZ2428
-+007040 560400 ZZ2428=ZZ2428+ZZ2428
-+007040 011251 0 8192 -ZZ1428
-+007041 560400 0 ZZ2428
-- mark 3428, 239 /31 leon
-+007042 000736 ZZ2429=ZZ2429+ZZ2429
-+007042 001674 ZZ2429=ZZ2429+ZZ2429
-+007042 003570 ZZ2429=ZZ2429+ZZ2429
-+007042 007360 ZZ2429=ZZ2429+ZZ2429
-+007042 016740 ZZ2429=ZZ2429+ZZ2429
-+007042 035700 ZZ2429=ZZ2429+ZZ2429
-+007042 073600 ZZ2429=ZZ2429+ZZ2429
-+007042 167400 ZZ2429=ZZ2429+ZZ2429
-+007042 011234 0 8192 -ZZ1429
-+007043 167400 0 ZZ2429
-- mark 3429, 3 /15 sext
-+007044 000006 ZZ2430=ZZ2430+ZZ2430
-+007044 000014 ZZ2430=ZZ2430+ZZ2430
-+007044 000030 ZZ2430=ZZ2430+ZZ2430
-+007044 000060 ZZ2430=ZZ2430+ZZ2430
-+007044 000140 ZZ2430=ZZ2430+ZZ2430
-+007044 000300 ZZ2430=ZZ2430+ZZ2430
-+007044 000600 ZZ2430=ZZ2430+ZZ2430
-+007044 001400 ZZ2430=ZZ2430+ZZ2430
-+007044 011233 0 8192 -ZZ1430
-+007045 001400 0 ZZ2430
-- mark 3446, -270 /41 hyda
-+007046 776742 ZZ2431=ZZ2431+ZZ2431
-+007046 775704 ZZ2431=ZZ2431+ZZ2431
-+007046 773610 ZZ2431=ZZ2431+ZZ2431
-+007046 767420 ZZ2431=ZZ2431+ZZ2431
-+007046 757040 ZZ2431=ZZ2431+ZZ2431
-+007046 736100 ZZ2431=ZZ2431+ZZ2431
-+007046 674200 ZZ2431=ZZ2431+ZZ2431
-+007046 570400 ZZ2431=ZZ2431+ZZ2431
-+007046 011212 0 8192 -ZZ1431
-+007047 570400 0 ZZ2431
-- mark 3495, 455 /40 leon
-+007050 001616 ZZ2432=ZZ2432+ZZ2432
-+007050 003434 ZZ2432=ZZ2432+ZZ2432
-+007050 007070 ZZ2432=ZZ2432+ZZ2432
-+007050 016160 ZZ2432=ZZ2432+ZZ2432
-+007050 034340 ZZ2432=ZZ2432+ZZ2432
-+007050 070700 ZZ2432=ZZ2432+ZZ2432
-+007050 161600 ZZ2432=ZZ2432+ZZ2432
-+007050 343400 ZZ2432=ZZ2432+ZZ2432
-+007050 011131 0 8192 -ZZ1432
-+007051 343400 0 ZZ2432
-- mark 3534, -372 /42 hyda
-+007052 776426 ZZ2433=ZZ2433+ZZ2433
-+007052 775054 ZZ2433=ZZ2433+ZZ2433
-+007052 772130 ZZ2433=ZZ2433+ZZ2433
-+007052 764260 ZZ2433=ZZ2433+ZZ2433
-+007052 750540 ZZ2433=ZZ2433+ZZ2433
-+007052 721300 ZZ2433=ZZ2433+ZZ2433
-+007052 642600 ZZ2433=ZZ2433+ZZ2433
-+007052 505400 ZZ2433=ZZ2433+ZZ2433
-+007052 011062 0 8192 -ZZ1433
-+007053 505400 0 ZZ2433
-- mark 3557, -3 /30 sext
-+007054 777770 ZZ2434=ZZ2434+ZZ2434
-+007054 777760 ZZ2434=ZZ2434+ZZ2434
-+007054 777740 ZZ2434=ZZ2434+ZZ2434
-+007054 777700 ZZ2434=ZZ2434+ZZ2434
-+007054 777600 ZZ2434=ZZ2434+ZZ2434
-+007054 777400 ZZ2434=ZZ2434+ZZ2434
-+007054 777000 ZZ2434=ZZ2434+ZZ2434
-+007054 776000 ZZ2434=ZZ2434+ZZ2434
-+007054 011033 0 8192 -ZZ1434
-+007055 776000 0 ZZ2434
-- mark 3570, 223 /47 leon
-+007056 000676 ZZ2435=ZZ2435+ZZ2435
-+007056 001574 ZZ2435=ZZ2435+ZZ2435
-+007056 003370 ZZ2435=ZZ2435+ZZ2435
-+007056 006760 ZZ2435=ZZ2435+ZZ2435
-+007056 015740 ZZ2435=ZZ2435+ZZ2435
-+007056 033700 ZZ2435=ZZ2435+ZZ2435
-+007056 067600 ZZ2435=ZZ2435+ZZ2435
-+007056 157400 ZZ2435=ZZ2435+ZZ2435
-+007056 011016 0 8192 -ZZ1435
-+007057 157400 0 ZZ2435
-- mark 3726, -404 /al crat
-+007060 776326 ZZ2436=ZZ2436+ZZ2436
-+007060 774654 ZZ2436=ZZ2436+ZZ2436
-+007060 771530 ZZ2436=ZZ2436+ZZ2436
-+007060 763260 ZZ2436=ZZ2436+ZZ2436
-+007060 746540 ZZ2436=ZZ2436+ZZ2436
-+007060 715300 ZZ2436=ZZ2436+ZZ2436
-+007060 632600 ZZ2436=ZZ2436+ZZ2436
-+007060 465400 ZZ2436=ZZ2436+ZZ2436
-+007060 010562 0 8192 -ZZ1436
-+007061 465400 0 ZZ2436
-- mark 3736, -44 /61 leon
-+007062 777646 ZZ2437=ZZ2437+ZZ2437
-+007062 777514 ZZ2437=ZZ2437+ZZ2437
-+007062 777230 ZZ2437=ZZ2437+ZZ2437
-+007062 776460 ZZ2437=ZZ2437+ZZ2437
-+007062 775140 ZZ2437=ZZ2437+ZZ2437
-+007062 772300 ZZ2437=ZZ2437+ZZ2437
-+007062 764600 ZZ2437=ZZ2437+ZZ2437
-+007062 751400 ZZ2437=ZZ2437+ZZ2437
-+007062 010550 0 8192 -ZZ1437
-+007063 751400 0 ZZ2437
-- mark 3738, 471 /60 leon
-+007064 001656 ZZ2438=ZZ2438+ZZ2438
-+007064 003534 ZZ2438=ZZ2438+ZZ2438
-+007064 007270 ZZ2438=ZZ2438+ZZ2438
-+007064 016560 ZZ2438=ZZ2438+ZZ2438
-+007064 035340 ZZ2438=ZZ2438+ZZ2438
-+007064 072700 ZZ2438=ZZ2438+ZZ2438
-+007064 165600 ZZ2438=ZZ2438+ZZ2438
-+007064 353400 ZZ2438=ZZ2438+ZZ2438
-+007064 010546 0 8192 -ZZ1438
-+007065 353400 0 ZZ2438
-- mark 3754, 179 /63 leon
-+007066 000546 ZZ2439=ZZ2439+ZZ2439
-+007066 001314 ZZ2439=ZZ2439+ZZ2439
-+007066 002630 ZZ2439=ZZ2439+ZZ2439
-+007066 005460 ZZ2439=ZZ2439+ZZ2439
-+007066 013140 ZZ2439=ZZ2439+ZZ2439
-+007066 026300 ZZ2439=ZZ2439+ZZ2439
-+007066 054600 ZZ2439=ZZ2439+ZZ2439
-+007066 131400 ZZ2439=ZZ2439+ZZ2439
-+007066 010526 0 8192 -ZZ1439
-+007067 131400 0 ZZ2439
-- mark 3793, -507 /11 crat
-+007070 776010 ZZ2440=ZZ2440+ZZ2440
-+007070 774020 ZZ2440=ZZ2440+ZZ2440
-+007070 770040 ZZ2440=ZZ2440+ZZ2440
-+007070 760100 ZZ2440=ZZ2440+ZZ2440
-+007070 740200 ZZ2440=ZZ2440+ZZ2440
-+007070 700400 ZZ2440=ZZ2440+ZZ2440
-+007070 601000 ZZ2440=ZZ2440+ZZ2440
-+007070 402000 ZZ2440=ZZ2440+ZZ2440
-+007070 010457 0 8192 -ZZ1440
-+007071 402000 0 ZZ2440
-- mark 3821, -71 /74 leon
-+007072 777560 ZZ2441=ZZ2441+ZZ2441
-+007072 777340 ZZ2441=ZZ2441+ZZ2441
-+007072 776700 ZZ2441=ZZ2441+ZZ2441
-+007072 775600 ZZ2441=ZZ2441+ZZ2441
-+007072 773400 ZZ2441=ZZ2441+ZZ2441
-+007072 767000 ZZ2441=ZZ2441+ZZ2441
-+007072 756000 ZZ2441=ZZ2441+ZZ2441
-+007072 734000 ZZ2441=ZZ2441+ZZ2441
-+007072 010423 0 8192 -ZZ1441
-+007073 734000 0 ZZ2441
-- mark 3836, -324 /12 crat
-+007074 776566 ZZ2442=ZZ2442+ZZ2442
-+007074 775354 ZZ2442=ZZ2442+ZZ2442
-+007074 772730 ZZ2442=ZZ2442+ZZ2442
-+007074 765660 ZZ2442=ZZ2442+ZZ2442
-+007074 753540 ZZ2442=ZZ2442+ZZ2442
-+007074 727300 ZZ2442=ZZ2442+ZZ2442
-+007074 656600 ZZ2442=ZZ2442+ZZ2442
-+007074 535400 ZZ2442=ZZ2442+ZZ2442
-+007074 010404 0 8192 -ZZ1442
-+007075 535400 0 ZZ2442
-- mark 3846, 150 /77 leon
-+007076 000454 ZZ2443=ZZ2443+ZZ2443
-+007076 001130 ZZ2443=ZZ2443+ZZ2443
-+007076 002260 ZZ2443=ZZ2443+ZZ2443
-+007076 004540 ZZ2443=ZZ2443+ZZ2443
-+007076 011300 ZZ2443=ZZ2443+ZZ2443
-+007076 022600 ZZ2443=ZZ2443+ZZ2443
-+007076 045400 ZZ2443=ZZ2443+ZZ2443
-+007076 113000 ZZ2443=ZZ2443+ZZ2443
-+007076 010372 0 8192 -ZZ1443
-+007077 113000 0 ZZ2443
-- mark 3861, 252 /78 leon
-+007100 000770 ZZ2444=ZZ2444+ZZ2444
-+007100 001760 ZZ2444=ZZ2444+ZZ2444
-+007100 003740 ZZ2444=ZZ2444+ZZ2444
-+007100 007700 ZZ2444=ZZ2444+ZZ2444
-+007100 017600 ZZ2444=ZZ2444+ZZ2444
-+007100 037400 ZZ2444=ZZ2444+ZZ2444
-+007100 077000 ZZ2444=ZZ2444+ZZ2444
-+007100 176000 ZZ2444=ZZ2444+ZZ2444
-+007100 010353 0 8192 -ZZ1444
-+007101 176000 0 ZZ2444
-- mark 3868, -390 /15 crat
-+007102 776362 ZZ2445=ZZ2445+ZZ2445
-+007102 774744 ZZ2445=ZZ2445+ZZ2445
-+007102 771710 ZZ2445=ZZ2445+ZZ2445
-+007102 763620 ZZ2445=ZZ2445+ZZ2445
-+007102 747440 ZZ2445=ZZ2445+ZZ2445
-+007102 717100 ZZ2445=ZZ2445+ZZ2445
-+007102 636200 ZZ2445=ZZ2445+ZZ2445
-+007102 474400 ZZ2445=ZZ2445+ZZ2445
-+007102 010344 0 8192 -ZZ1445
-+007103 474400 0 ZZ2445
-- mark 3935, -211 /21 crat
-+007104 777130 ZZ2446=ZZ2446+ZZ2446
-+007104 776260 ZZ2446=ZZ2446+ZZ2446
-+007104 774540 ZZ2446=ZZ2446+ZZ2446
-+007104 771300 ZZ2446=ZZ2446+ZZ2446
-+007104 762600 ZZ2446=ZZ2446+ZZ2446
-+007104 745400 ZZ2446=ZZ2446+ZZ2446
-+007104 713000 ZZ2446=ZZ2446+ZZ2446
-+007104 626000 ZZ2446=ZZ2446+ZZ2446
-+007104 010241 0 8192 -ZZ1446
-+007105 626000 0 ZZ2446
-- mark 3936, -6 /91 leon
-+007106 777762 ZZ2447=ZZ2447+ZZ2447
-+007106 777744 ZZ2447=ZZ2447+ZZ2447
-+007106 777710 ZZ2447=ZZ2447+ZZ2447
-+007106 777620 ZZ2447=ZZ2447+ZZ2447
-+007106 777440 ZZ2447=ZZ2447+ZZ2447
-+007106 777100 ZZ2447=ZZ2447+ZZ2447
-+007106 776200 ZZ2447=ZZ2447+ZZ2447
-+007106 774400 ZZ2447=ZZ2447+ZZ2447
-+007106 010240 0 8192 -ZZ1447
-+007107 774400 0 ZZ2447
-- mark 3981, -405 /27 crat
-+007110 776324 ZZ2448=ZZ2448+ZZ2448
-+007110 774650 ZZ2448=ZZ2448+ZZ2448
-+007110 771520 ZZ2448=ZZ2448+ZZ2448
-+007110 763240 ZZ2448=ZZ2448+ZZ2448
-+007110 746500 ZZ2448=ZZ2448+ZZ2448
-+007110 715200 ZZ2448=ZZ2448+ZZ2448
-+007110 632400 ZZ2448=ZZ2448+ZZ2448
-+007110 465000 ZZ2448=ZZ2448+ZZ2448
-+007110 010163 0 8192 -ZZ1448
-+007111 465000 0 ZZ2448
-- mark 3986, 161 / 3 virg
-+007112 000502 ZZ2449=ZZ2449+ZZ2449
-+007112 001204 ZZ2449=ZZ2449+ZZ2449
-+007112 002410 ZZ2449=ZZ2449+ZZ2449
-+007112 005020 ZZ2449=ZZ2449+ZZ2449
-+007112 012040 ZZ2449=ZZ2449+ZZ2449
-+007112 024100 ZZ2449=ZZ2449+ZZ2449
-+007112 050200 ZZ2449=ZZ2449+ZZ2449
-+007112 120400 ZZ2449=ZZ2449+ZZ2449
-+007112 010156 0 8192 -ZZ1449
-+007113 120400 0 ZZ2449
-- mark 3998, 473 /93 leon
-+007114 001662 ZZ2450=ZZ2450+ZZ2450
-+007114 003544 ZZ2450=ZZ2450+ZZ2450
-+007114 007310 ZZ2450=ZZ2450+ZZ2450
-+007114 016620 ZZ2450=ZZ2450+ZZ2450
-+007114 035440 ZZ2450=ZZ2450+ZZ2450
-+007114 073100 ZZ2450=ZZ2450+ZZ2450
-+007114 166200 ZZ2450=ZZ2450+ZZ2450
-+007114 354400 ZZ2450=ZZ2450+ZZ2450
-+007114 010142 0 8192 -ZZ1450
-+007115 354400 0 ZZ2450
-- mark 4013, 53 / 5 virg
-+007116 000152 ZZ2451=ZZ2451+ZZ2451
-+007116 000324 ZZ2451=ZZ2451+ZZ2451
-+007116 000650 ZZ2451=ZZ2451+ZZ2451
-+007116 001520 ZZ2451=ZZ2451+ZZ2451
-+007116 003240 ZZ2451=ZZ2451+ZZ2451
-+007116 006500 ZZ2451=ZZ2451+ZZ2451
-+007116 015200 ZZ2451=ZZ2451+ZZ2451
-+007116 032400 ZZ2451=ZZ2451+ZZ2451
-+007116 010123 0 8192 -ZZ1451
-+007117 032400 0 ZZ2451
-- mark 4072, 163 / 8 virg
-+007120 000506 ZZ2452=ZZ2452+ZZ2452
-+007120 001214 ZZ2452=ZZ2452+ZZ2452
-+007120 002430 ZZ2452=ZZ2452+ZZ2452
-+007120 005060 ZZ2452=ZZ2452+ZZ2452
-+007120 012140 ZZ2452=ZZ2452+ZZ2452
-+007120 024300 ZZ2452=ZZ2452+ZZ2452
-+007120 050600 ZZ2452=ZZ2452+ZZ2452
-+007120 121400 ZZ2452=ZZ2452+ZZ2452
-+007120 010030 0 8192 -ZZ1452
-+007121 121400 0 ZZ2452
-- mark 4097, 211 / 9 virg
-+007122 000646 ZZ2453=ZZ2453+ZZ2453
-+007122 001514 ZZ2453=ZZ2453+ZZ2453
-+007122 003230 ZZ2453=ZZ2453+ZZ2453
-+007122 006460 ZZ2453=ZZ2453+ZZ2453
-+007122 015140 ZZ2453=ZZ2453+ZZ2453
-+007122 032300 ZZ2453=ZZ2453+ZZ2453
-+007122 064600 ZZ2453=ZZ2453+ZZ2453
-+007122 151400 ZZ2453=ZZ2453+ZZ2453
-+007122 007777 0 8192 -ZZ1453
-+007123 151400 0 ZZ2453
-- mark 4180, -3 /15 virg
-+007124 777770 ZZ2454=ZZ2454+ZZ2454
-+007124 777760 ZZ2454=ZZ2454+ZZ2454
-+007124 777740 ZZ2454=ZZ2454+ZZ2454
-+007124 777700 ZZ2454=ZZ2454+ZZ2454
-+007124 777600 ZZ2454=ZZ2454+ZZ2454
-+007124 777400 ZZ2454=ZZ2454+ZZ2454
-+007124 777000 ZZ2454=ZZ2454+ZZ2454
-+007124 776000 ZZ2454=ZZ2454+ZZ2454
-+007124 007654 0 8192 -ZZ1454
-+007125 776000 0 ZZ2454
-- mark 4185, 418 /11 coma
-+007126 001504 ZZ2455=ZZ2455+ZZ2455
-+007126 003210 ZZ2455=ZZ2455+ZZ2455
-+007126 006420 ZZ2455=ZZ2455+ZZ2455
-+007126 015040 ZZ2455=ZZ2455+ZZ2455
-+007126 032100 ZZ2455=ZZ2455+ZZ2455
-+007126 064200 ZZ2455=ZZ2455+ZZ2455
-+007126 150400 ZZ2455=ZZ2455+ZZ2455
-+007126 321000 ZZ2455=ZZ2455+ZZ2455
-+007126 007647 0 8192 -ZZ1455
-+007127 321000 0 ZZ2455
-- mark 4249, -356 / 8 corv
-+007130 776466 ZZ2456=ZZ2456+ZZ2456
-+007130 775154 ZZ2456=ZZ2456+ZZ2456
-+007130 772330 ZZ2456=ZZ2456+ZZ2456
-+007130 764660 ZZ2456=ZZ2456+ZZ2456
-+007130 751540 ZZ2456=ZZ2456+ZZ2456
-+007130 723300 ZZ2456=ZZ2456+ZZ2456
-+007130 646600 ZZ2456=ZZ2456+ZZ2456
-+007130 515400 ZZ2456=ZZ2456+ZZ2456
-+007130 007547 0 8192 -ZZ1456
-+007131 515400 0 ZZ2456
-- mark 4290, -170 /26 virg
-+007132 777252 ZZ2457=ZZ2457+ZZ2457
-+007132 776524 ZZ2457=ZZ2457+ZZ2457
-+007132 775250 ZZ2457=ZZ2457+ZZ2457
-+007132 772520 ZZ2457=ZZ2457+ZZ2457
-+007132 765240 ZZ2457=ZZ2457+ZZ2457
-+007132 752500 ZZ2457=ZZ2457+ZZ2457
-+007132 725200 ZZ2457=ZZ2457+ZZ2457
-+007132 652400 ZZ2457=ZZ2457+ZZ2457
-+007132 007476 0 8192 -ZZ1457
-+007133 652400 0 ZZ2457
-- mark 4305, 245 /30 virg
-+007134 000752 ZZ2458=ZZ2458+ZZ2458
-+007134 001724 ZZ2458=ZZ2458+ZZ2458
-+007134 003650 ZZ2458=ZZ2458+ZZ2458
-+007134 007520 ZZ2458=ZZ2458+ZZ2458
-+007134 017240 ZZ2458=ZZ2458+ZZ2458
-+007134 036500 ZZ2458=ZZ2458+ZZ2458
-+007134 075200 ZZ2458=ZZ2458+ZZ2458
-+007134 172400 ZZ2458=ZZ2458+ZZ2458
-+007134 007457 0 8192 -ZZ1458
-+007135 172400 0 ZZ2458
-- mark 4376, -205 /40 virg
-+007136 777144 ZZ2459=ZZ2459+ZZ2459
-+007136 776310 ZZ2459=ZZ2459+ZZ2459
-+007136 774620 ZZ2459=ZZ2459+ZZ2459
-+007136 771440 ZZ2459=ZZ2459+ZZ2459
-+007136 763100 ZZ2459=ZZ2459+ZZ2459
-+007136 746200 ZZ2459=ZZ2459+ZZ2459
-+007136 714400 ZZ2459=ZZ2459+ZZ2459
-+007136 631000 ZZ2459=ZZ2459+ZZ2459
-+007136 007350 0 8192 -ZZ1459
-+007137 631000 0 ZZ2459
-- mark 4403, 409 /36 coma
-+007140 001462 ZZ2460=ZZ2460+ZZ2460
-+007140 003144 ZZ2460=ZZ2460+ZZ2460
-+007140 006310 ZZ2460=ZZ2460+ZZ2460
-+007140 014620 ZZ2460=ZZ2460+ZZ2460
-+007140 031440 ZZ2460=ZZ2460+ZZ2460
-+007140 063100 ZZ2460=ZZ2460+ZZ2460
-+007140 146200 ZZ2460=ZZ2460+ZZ2460
-+007140 314400 ZZ2460=ZZ2460+ZZ2460
-+007140 007315 0 8192 -ZZ1460
-+007141 314400 0 ZZ2460
-- mark 4465, -114 /51 virg
-+007142 777432 ZZ2461=ZZ2461+ZZ2461
-+007142 777064 ZZ2461=ZZ2461+ZZ2461
-+007142 776150 ZZ2461=ZZ2461+ZZ2461
-+007142 774320 ZZ2461=ZZ2461+ZZ2461
-+007142 770640 ZZ2461=ZZ2461+ZZ2461
-+007142 761500 ZZ2461=ZZ2461+ZZ2461
-+007142 743200 ZZ2461=ZZ2461+ZZ2461
-+007142 706400 ZZ2461=ZZ2461+ZZ2461
-+007142 007217 0 8192 -ZZ1461
-+007143 706400 0 ZZ2461
-- mark 4466, 411 /42 coma
-+007144 001466 ZZ2462=ZZ2462+ZZ2462
-+007144 003154 ZZ2462=ZZ2462+ZZ2462
-+007144 006330 ZZ2462=ZZ2462+ZZ2462
-+007144 014660 ZZ2462=ZZ2462+ZZ2462
-+007144 031540 ZZ2462=ZZ2462+ZZ2462
-+007144 063300 ZZ2462=ZZ2462+ZZ2462
-+007144 146600 ZZ2462=ZZ2462+ZZ2462
-+007144 315400 ZZ2462=ZZ2462+ZZ2462
-+007144 007216 0 8192 -ZZ1462
-+007145 315400 0 ZZ2462
-- mark 4512, -404 /61 virg
-+007146 776326 ZZ2463=ZZ2463+ZZ2463
-+007146 774654 ZZ2463=ZZ2463+ZZ2463
-+007146 771530 ZZ2463=ZZ2463+ZZ2463
-+007146 763260 ZZ2463=ZZ2463+ZZ2463
-+007146 746540 ZZ2463=ZZ2463+ZZ2463
-+007146 715300 ZZ2463=ZZ2463+ZZ2463
-+007146 632600 ZZ2463=ZZ2463+ZZ2463
-+007146 465400 ZZ2463=ZZ2463+ZZ2463
-+007146 007140 0 8192 -ZZ1463
-+007147 465400 0 ZZ2463
-- mark 4563, -352 /69 virg
-+007150 776476 ZZ2464=ZZ2464+ZZ2464
-+007150 775174 ZZ2464=ZZ2464+ZZ2464
-+007150 772370 ZZ2464=ZZ2464+ZZ2464
-+007150 764760 ZZ2464=ZZ2464+ZZ2464
-+007150 751740 ZZ2464=ZZ2464+ZZ2464
-+007150 723700 ZZ2464=ZZ2464+ZZ2464
-+007150 647600 ZZ2464=ZZ2464+ZZ2464
-+007150 517400 ZZ2464=ZZ2464+ZZ2464
-+007150 007055 0 8192 -ZZ1464
-+007151 517400 0 ZZ2464
-- mark 4590, -131 /74 virg
-+007152 777370 ZZ2465=ZZ2465+ZZ2465
-+007152 776760 ZZ2465=ZZ2465+ZZ2465
-+007152 775740 ZZ2465=ZZ2465+ZZ2465
-+007152 773700 ZZ2465=ZZ2465+ZZ2465
-+007152 767600 ZZ2465=ZZ2465+ZZ2465
-+007152 757400 ZZ2465=ZZ2465+ZZ2465
-+007152 737000 ZZ2465=ZZ2465+ZZ2465
-+007152 676000 ZZ2465=ZZ2465+ZZ2465
-+007152 007022 0 8192 -ZZ1465
-+007153 676000 0 ZZ2465
-- mark 4603, 95 /78 virg
-+007154 000276 ZZ2466=ZZ2466+ZZ2466
-+007154 000574 ZZ2466=ZZ2466+ZZ2466
-+007154 001370 ZZ2466=ZZ2466+ZZ2466
-+007154 002760 ZZ2466=ZZ2466+ZZ2466
-+007154 005740 ZZ2466=ZZ2466+ZZ2466
-+007154 013700 ZZ2466=ZZ2466+ZZ2466
-+007154 027600 ZZ2466=ZZ2466+ZZ2466
-+007154 057400 ZZ2466=ZZ2466+ZZ2466
-+007154 007005 0 8192 -ZZ1466
-+007155 057400 0 ZZ2466
-- mark 4679, 409 / 4 boot
-+007156 001462 ZZ2467=ZZ2467+ZZ2467
-+007156 003144 ZZ2467=ZZ2467+ZZ2467
-+007156 006310 ZZ2467=ZZ2467+ZZ2467
-+007156 014620 ZZ2467=ZZ2467+ZZ2467
-+007156 031440 ZZ2467=ZZ2467+ZZ2467
-+007156 063100 ZZ2467=ZZ2467+ZZ2467
-+007156 146200 ZZ2467=ZZ2467+ZZ2467
-+007156 314400 ZZ2467=ZZ2467+ZZ2467
-+007156 006671 0 8192 -ZZ1467
-+007157 314400 0 ZZ2467
-- mark 4691, 371 / 5 boot
-+007160 001346 ZZ2468=ZZ2468+ZZ2468
-+007160 002714 ZZ2468=ZZ2468+ZZ2468
-+007160 005630 ZZ2468=ZZ2468+ZZ2468
-+007160 013460 ZZ2468=ZZ2468+ZZ2468
-+007160 027140 ZZ2468=ZZ2468+ZZ2468
-+007160 056300 ZZ2468=ZZ2468+ZZ2468
-+007160 134600 ZZ2468=ZZ2468+ZZ2468
-+007160 271400 ZZ2468=ZZ2468+ZZ2468
-+007160 006655 0 8192 -ZZ1468
-+007161 271400 0 ZZ2468
-- mark 4759, 46 /93 virg
-+007162 000134 ZZ2469=ZZ2469+ZZ2469
-+007162 000270 ZZ2469=ZZ2469+ZZ2469
-+007162 000560 ZZ2469=ZZ2469+ZZ2469
-+007162 001340 ZZ2469=ZZ2469+ZZ2469
-+007162 002700 ZZ2469=ZZ2469+ZZ2469
-+007162 005600 ZZ2469=ZZ2469+ZZ2469
-+007162 013400 ZZ2469=ZZ2469+ZZ2469
-+007162 027000 ZZ2469=ZZ2469+ZZ2469
-+007162 006551 0 8192 -ZZ1469
-+007163 027000 0 ZZ2469
-- mark 4820, 66 /
-+007164 000204 ZZ2470=ZZ2470+ZZ2470
-+007164 000410 ZZ2470=ZZ2470+ZZ2470
-+007164 001020 ZZ2470=ZZ2470+ZZ2470
-+007164 002040 ZZ2470=ZZ2470+ZZ2470
-+007164 004100 ZZ2470=ZZ2470+ZZ2470
-+007164 010200 ZZ2470=ZZ2470+ZZ2470
-+007164 020400 ZZ2470=ZZ2470+ZZ2470
-+007164 041000 ZZ2470=ZZ2470+ZZ2470
-+007164 006454 0 8192 -ZZ1470
-+007165 041000 0 ZZ2470
-- mark 4822, -223 /98 virg
-+007166 777100 ZZ2471=ZZ2471+ZZ2471
-+007166 776200 ZZ2471=ZZ2471+ZZ2471
-+007166 774400 ZZ2471=ZZ2471+ZZ2471
-+007166 771000 ZZ2471=ZZ2471+ZZ2471
-+007166 762000 ZZ2471=ZZ2471+ZZ2471
-+007166 744000 ZZ2471=ZZ2471+ZZ2471
-+007166 710000 ZZ2471=ZZ2471+ZZ2471
-+007166 620000 ZZ2471=ZZ2471+ZZ2471
-+007166 006452 0 8192 -ZZ1471
-+007167 620000 0 ZZ2471
-- mark 4840, -126 /99 virg
-+007170 777402 ZZ2472=ZZ2472+ZZ2472
-+007170 777004 ZZ2472=ZZ2472+ZZ2472
-+007170 776010 ZZ2472=ZZ2472+ZZ2472
-+007170 774020 ZZ2472=ZZ2472+ZZ2472
-+007170 770040 ZZ2472=ZZ2472+ZZ2472
-+007170 760100 ZZ2472=ZZ2472+ZZ2472
-+007170 740200 ZZ2472=ZZ2472+ZZ2472
-+007170 700400 ZZ2472=ZZ2472+ZZ2472
-+007170 006430 0 8192 -ZZ1472
-+007171 700400 0 ZZ2472
-- mark 4857, -294 /100 virg
-+007172 776662 ZZ2473=ZZ2473+ZZ2473
-+007172 775544 ZZ2473=ZZ2473+ZZ2473
-+007172 773310 ZZ2473=ZZ2473+ZZ2473
-+007172 766620 ZZ2473=ZZ2473+ZZ2473
-+007172 755440 ZZ2473=ZZ2473+ZZ2473
-+007172 733100 ZZ2473=ZZ2473+ZZ2473
-+007172 666200 ZZ2473=ZZ2473+ZZ2473
-+007172 554400 ZZ2473=ZZ2473+ZZ2473
-+007172 006407 0 8192 -ZZ1473
-+007173 554400 0 ZZ2473
-- mark 4864, 382 /20 boot
-+007174 001374 ZZ2474=ZZ2474+ZZ2474
-+007174 002770 ZZ2474=ZZ2474+ZZ2474
-+007174 005760 ZZ2474=ZZ2474+ZZ2474
-+007174 013740 ZZ2474=ZZ2474+ZZ2474
-+007174 027700 ZZ2474=ZZ2474+ZZ2474
-+007174 057600 ZZ2474=ZZ2474+ZZ2474
-+007174 137400 ZZ2474=ZZ2474+ZZ2474
-+007174 277000 ZZ2474=ZZ2474+ZZ2474
-+007174 006400 0 8192 -ZZ1474
-+007175 277000 0 ZZ2474
-- mark 4910, -41 /105 virg
-+007176 777654 ZZ2475=ZZ2475+ZZ2475
-+007176 777530 ZZ2475=ZZ2475+ZZ2475
-+007176 777260 ZZ2475=ZZ2475+ZZ2475
-+007176 776540 ZZ2475=ZZ2475+ZZ2475
-+007176 775300 ZZ2475=ZZ2475+ZZ2475
-+007176 772600 ZZ2475=ZZ2475+ZZ2475
-+007176 765400 ZZ2475=ZZ2475+ZZ2475
-+007176 753000 ZZ2475=ZZ2475+ZZ2475
-+007176 006322 0 8192 -ZZ1475
-+007177 753000 0 ZZ2475
-- mark 4984, 383 /29 boot
-+007200 001376 ZZ2476=ZZ2476+ZZ2476
-+007200 002774 ZZ2476=ZZ2476+ZZ2476
-+007200 005770 ZZ2476=ZZ2476+ZZ2476
-+007200 013760 ZZ2476=ZZ2476+ZZ2476
-+007200 027740 ZZ2476=ZZ2476+ZZ2476
-+007200 057700 ZZ2476=ZZ2476+ZZ2476
-+007200 137600 ZZ2476=ZZ2476+ZZ2476
-+007200 277400 ZZ2476=ZZ2476+ZZ2476
-+007200 006210 0 8192 -ZZ1476
-+007201 277400 0 ZZ2476
-- mark 4986, 322 /30 boot
-+007202 001204 ZZ2477=ZZ2477+ZZ2477
-+007202 002410 ZZ2477=ZZ2477+ZZ2477
-+007202 005020 ZZ2477=ZZ2477+ZZ2477
-+007202 012040 ZZ2477=ZZ2477+ZZ2477
-+007202 024100 ZZ2477=ZZ2477+ZZ2477
-+007202 050200 ZZ2477=ZZ2477+ZZ2477
-+007202 120400 ZZ2477=ZZ2477+ZZ2477
-+007202 241000 ZZ2477=ZZ2477+ZZ2477
-+007202 006206 0 8192 -ZZ1477
-+007203 241000 0 ZZ2477
-- mark 4994, -119 /107 virg
-+007204 777420 ZZ2478=ZZ2478+ZZ2478
-+007204 777040 ZZ2478=ZZ2478+ZZ2478
-+007204 776100 ZZ2478=ZZ2478+ZZ2478
-+007204 774200 ZZ2478=ZZ2478+ZZ2478
-+007204 770400 ZZ2478=ZZ2478+ZZ2478
-+007204 761000 ZZ2478=ZZ2478+ZZ2478
-+007204 742000 ZZ2478=ZZ2478+ZZ2478
-+007204 704000 ZZ2478=ZZ2478+ZZ2478
-+007204 006176 0 8192 -ZZ1478
-+007205 704000 0 ZZ2478
-- mark 5009, 396 /35 boot
-+007206 001430 ZZ2479=ZZ2479+ZZ2479
-+007206 003060 ZZ2479=ZZ2479+ZZ2479
-+007206 006140 ZZ2479=ZZ2479+ZZ2479
-+007206 014300 ZZ2479=ZZ2479+ZZ2479
-+007206 030600 ZZ2479=ZZ2479+ZZ2479
-+007206 061400 ZZ2479=ZZ2479+ZZ2479
-+007206 143000 ZZ2479=ZZ2479+ZZ2479
-+007206 306000 ZZ2479=ZZ2479+ZZ2479
-+007206 006157 0 8192 -ZZ1479
-+007207 306000 0 ZZ2479
-- mark 5013, 53 /109 virg
-+007210 000152 ZZ2480=ZZ2480+ZZ2480
-+007210 000324 ZZ2480=ZZ2480+ZZ2480
-+007210 000650 ZZ2480=ZZ2480+ZZ2480
-+007210 001520 ZZ2480=ZZ2480+ZZ2480
-+007210 003240 ZZ2480=ZZ2480+ZZ2480
-+007210 006500 ZZ2480=ZZ2480+ZZ2480
-+007210 015200 ZZ2480=ZZ2480+ZZ2480
-+007210 032400 ZZ2480=ZZ2480+ZZ2480
-+007210 006153 0 8192 -ZZ1480
-+007211 032400 0 ZZ2480
-- mark 5045, 444 /37 boot
-+007212 001570 ZZ2481=ZZ2481+ZZ2481
-+007212 003360 ZZ2481=ZZ2481+ZZ2481
-+007212 006740 ZZ2481=ZZ2481+ZZ2481
-+007212 015700 ZZ2481=ZZ2481+ZZ2481
-+007212 033600 ZZ2481=ZZ2481+ZZ2481
-+007212 067400 ZZ2481=ZZ2481+ZZ2481
-+007212 157000 ZZ2481=ZZ2481+ZZ2481
-+007212 336000 ZZ2481=ZZ2481+ZZ2481
-+007212 006113 0 8192 -ZZ1481
-+007213 336000 0 ZZ2481
-- mark 5074, -90 /16 libr
-+007214 777512 ZZ2482=ZZ2482+ZZ2482
-+007214 777224 ZZ2482=ZZ2482+ZZ2482
-+007214 776450 ZZ2482=ZZ2482+ZZ2482
-+007214 775120 ZZ2482=ZZ2482+ZZ2482
-+007214 772240 ZZ2482=ZZ2482+ZZ2482
-+007214 764500 ZZ2482=ZZ2482+ZZ2482
-+007214 751200 ZZ2482=ZZ2482+ZZ2482
-+007214 722400 ZZ2482=ZZ2482+ZZ2482
-+007214 006056 0 8192 -ZZ1482
-+007215 722400 0 ZZ2482
-- mark 5108, 57 /110 virg
-+007216 000162 ZZ2483=ZZ2483+ZZ2483
-+007216 000344 ZZ2483=ZZ2483+ZZ2483
-+007216 000710 ZZ2483=ZZ2483+ZZ2483
-+007216 001620 ZZ2483=ZZ2483+ZZ2483
-+007216 003440 ZZ2483=ZZ2483+ZZ2483
-+007216 007100 ZZ2483=ZZ2483+ZZ2483
-+007216 016200 ZZ2483=ZZ2483+ZZ2483
-+007216 034400 ZZ2483=ZZ2483+ZZ2483
-+007216 006014 0 8192 -ZZ1483
-+007217 034400 0 ZZ2483
-- mark 5157, -442 /24 libr
-+007220 776212 ZZ2484=ZZ2484+ZZ2484
-+007220 774424 ZZ2484=ZZ2484+ZZ2484
-+007220 771050 ZZ2484=ZZ2484+ZZ2484
-+007220 762120 ZZ2484=ZZ2484+ZZ2484
-+007220 744240 ZZ2484=ZZ2484+ZZ2484
-+007220 710500 ZZ2484=ZZ2484+ZZ2484
-+007220 621200 ZZ2484=ZZ2484+ZZ2484
-+007220 442400 ZZ2484=ZZ2484+ZZ2484
-+007220 005733 0 8192 -ZZ1484
-+007221 442400 0 ZZ2484
-- mark 5283, -221 /37 libr
-+007222 777104 ZZ2485=ZZ2485+ZZ2485
-+007222 776210 ZZ2485=ZZ2485+ZZ2485
-+007222 774420 ZZ2485=ZZ2485+ZZ2485
-+007222 771040 ZZ2485=ZZ2485+ZZ2485
-+007222 762100 ZZ2485=ZZ2485+ZZ2485
-+007222 744200 ZZ2485=ZZ2485+ZZ2485
-+007222 710400 ZZ2485=ZZ2485+ZZ2485
-+007222 621000 ZZ2485=ZZ2485+ZZ2485
-+007222 005535 0 8192 -ZZ1485
-+007223 621000 0 ZZ2485
-- mark 5290, -329 /38 libr
-+007224 776554 ZZ2486=ZZ2486+ZZ2486
-+007224 775330 ZZ2486=ZZ2486+ZZ2486
-+007224 772660 ZZ2486=ZZ2486+ZZ2486
-+007224 765540 ZZ2486=ZZ2486+ZZ2486
-+007224 753300 ZZ2486=ZZ2486+ZZ2486
-+007224 726600 ZZ2486=ZZ2486+ZZ2486
-+007224 655400 ZZ2486=ZZ2486+ZZ2486
-+007224 533000 ZZ2486=ZZ2486+ZZ2486
-+007224 005526 0 8192 -ZZ1486
-+007225 533000 0 ZZ2486
-- mark 5291, 247 /13 serp
-+007226 000756 ZZ2487=ZZ2487+ZZ2487
-+007226 001734 ZZ2487=ZZ2487+ZZ2487
-+007226 003670 ZZ2487=ZZ2487+ZZ2487
-+007226 007560 ZZ2487=ZZ2487+ZZ2487
-+007226 017340 ZZ2487=ZZ2487+ZZ2487
-+007226 036700 ZZ2487=ZZ2487+ZZ2487
-+007226 075600 ZZ2487=ZZ2487+ZZ2487
-+007226 173400 ZZ2487=ZZ2487+ZZ2487
-+007226 005525 0 8192 -ZZ1487
-+007227 173400 0 ZZ2487
-- mark 5326, -440 /43 libr
-+007230 776216 ZZ2488=ZZ2488+ZZ2488
-+007230 774434 ZZ2488=ZZ2488+ZZ2488
-+007230 771070 ZZ2488=ZZ2488+ZZ2488
-+007230 762160 ZZ2488=ZZ2488+ZZ2488
-+007230 744340 ZZ2488=ZZ2488+ZZ2488
-+007230 710700 ZZ2488=ZZ2488+ZZ2488
-+007230 621600 ZZ2488=ZZ2488+ZZ2488
-+007230 443400 ZZ2488=ZZ2488+ZZ2488
-+007230 005462 0 8192 -ZZ1488
-+007231 443400 0 ZZ2488
-- mark 5331, 455 /21 serp
-+007232 001616 ZZ2489=ZZ2489+ZZ2489
-+007232 003434 ZZ2489=ZZ2489+ZZ2489
-+007232 007070 ZZ2489=ZZ2489+ZZ2489
-+007232 016160 ZZ2489=ZZ2489+ZZ2489
-+007232 034340 ZZ2489=ZZ2489+ZZ2489
-+007232 070700 ZZ2489=ZZ2489+ZZ2489
-+007232 161600 ZZ2489=ZZ2489+ZZ2489
-+007232 343400 ZZ2489=ZZ2489+ZZ2489
-+007232 005455 0 8192 -ZZ1489
-+007233 343400 0 ZZ2489
-- mark 5357, 175 /27 serp
-+007234 000536 ZZ2490=ZZ2490+ZZ2490
-+007234 001274 ZZ2490=ZZ2490+ZZ2490
-+007234 002570 ZZ2490=ZZ2490+ZZ2490
-+007234 005360 ZZ2490=ZZ2490+ZZ2490
-+007234 012740 ZZ2490=ZZ2490+ZZ2490
-+007234 025700 ZZ2490=ZZ2490+ZZ2490
-+007234 053600 ZZ2490=ZZ2490+ZZ2490
-+007234 127400 ZZ2490=ZZ2490+ZZ2490
-+007234 005423 0 8192 -ZZ1490
-+007235 127400 0 ZZ2490
-- mark 5372, 420 /35 serp
-+007236 001510 ZZ2491=ZZ2491+ZZ2491
-+007236 003220 ZZ2491=ZZ2491+ZZ2491
-+007236 006440 ZZ2491=ZZ2491+ZZ2491
-+007236 015100 ZZ2491=ZZ2491+ZZ2491
-+007236 032200 ZZ2491=ZZ2491+ZZ2491
-+007236 064400 ZZ2491=ZZ2491+ZZ2491
-+007236 151000 ZZ2491=ZZ2491+ZZ2491
-+007236 322000 ZZ2491=ZZ2491+ZZ2491
-+007236 005404 0 8192 -ZZ1491
-+007237 322000 0 ZZ2491
-- mark 5381, 109 /37 serp
-+007240 000332 ZZ2492=ZZ2492+ZZ2492
-+007240 000664 ZZ2492=ZZ2492+ZZ2492
-+007240 001550 ZZ2492=ZZ2492+ZZ2492
-+007240 003320 ZZ2492=ZZ2492+ZZ2492
-+007240 006640 ZZ2492=ZZ2492+ZZ2492
-+007240 015500 ZZ2492=ZZ2492+ZZ2492
-+007240 033200 ZZ2492=ZZ2492+ZZ2492
-+007240 066400 ZZ2492=ZZ2492+ZZ2492
-+007240 005373 0 8192 -ZZ1492
-+007241 066400 0 ZZ2492
-- mark 5387, 484 /38 serp
-+007242 001710 ZZ2493=ZZ2493+ZZ2493
-+007242 003620 ZZ2493=ZZ2493+ZZ2493
-+007242 007440 ZZ2493=ZZ2493+ZZ2493
-+007242 017100 ZZ2493=ZZ2493+ZZ2493
-+007242 036200 ZZ2493=ZZ2493+ZZ2493
-+007242 074400 ZZ2493=ZZ2493+ZZ2493
-+007242 171000 ZZ2493=ZZ2493+ZZ2493
-+007242 362000 ZZ2493=ZZ2493+ZZ2493
-+007242 005365 0 8192 -ZZ1493
-+007243 362000 0 ZZ2493
-- mark 5394, -374 /46 libr
-+007244 776422 ZZ2494=ZZ2494+ZZ2494
-+007244 775044 ZZ2494=ZZ2494+ZZ2494
-+007244 772110 ZZ2494=ZZ2494+ZZ2494
-+007244 764220 ZZ2494=ZZ2494+ZZ2494
-+007244 750440 ZZ2494=ZZ2494+ZZ2494
-+007244 721100 ZZ2494=ZZ2494+ZZ2494
-+007244 642200 ZZ2494=ZZ2494+ZZ2494
-+007244 504400 ZZ2494=ZZ2494+ZZ2494
-+007244 005356 0 8192 -ZZ1494
-+007245 504400 0 ZZ2494
-- mark 5415, 364 /41 serp
-+007246 001330 ZZ2495=ZZ2495+ZZ2495
-+007246 002660 ZZ2495=ZZ2495+ZZ2495
-+007246 005540 ZZ2495=ZZ2495+ZZ2495
-+007246 013300 ZZ2495=ZZ2495+ZZ2495
-+007246 026600 ZZ2495=ZZ2495+ZZ2495
-+007246 055400 ZZ2495=ZZ2495+ZZ2495
-+007246 133000 ZZ2495=ZZ2495+ZZ2495
-+007246 266000 ZZ2495=ZZ2495+ZZ2495
-+007246 005331 0 8192 -ZZ1495
-+007247 266000 0 ZZ2495
-- mark 5419, -318 /48 libr
-+007250 776602 ZZ2496=ZZ2496+ZZ2496
-+007250 775404 ZZ2496=ZZ2496+ZZ2496
-+007250 773010 ZZ2496=ZZ2496+ZZ2496
-+007250 766020 ZZ2496=ZZ2496+ZZ2496
-+007250 754040 ZZ2496=ZZ2496+ZZ2496
-+007250 730100 ZZ2496=ZZ2496+ZZ2496
-+007250 660200 ZZ2496=ZZ2496+ZZ2496
-+007250 540400 ZZ2496=ZZ2496+ZZ2496
-+007250 005325 0 8192 -ZZ1496
-+007251 540400 0 ZZ2496
-- mark 5455, -253 /xi scor
-+007252 777004 ZZ2497=ZZ2497+ZZ2497
-+007252 776010 ZZ2497=ZZ2497+ZZ2497
-+007252 774020 ZZ2497=ZZ2497+ZZ2497
-+007252 770040 ZZ2497=ZZ2497+ZZ2497
-+007252 760100 ZZ2497=ZZ2497+ZZ2497
-+007252 740200 ZZ2497=ZZ2497+ZZ2497
-+007252 700400 ZZ2497=ZZ2497+ZZ2497
-+007252 601000 ZZ2497=ZZ2497+ZZ2497
-+007252 005261 0 8192 -ZZ1497
-+007253 601000 0 ZZ2497
-- mark 5467, -464 / 9 scor
-+007254 776136 ZZ2498=ZZ2498+ZZ2498
-+007254 774274 ZZ2498=ZZ2498+ZZ2498
-+007254 770570 ZZ2498=ZZ2498+ZZ2498
-+007254 761360 ZZ2498=ZZ2498+ZZ2498
-+007254 742740 ZZ2498=ZZ2498+ZZ2498
-+007254 705700 ZZ2498=ZZ2498+ZZ2498
-+007254 613600 ZZ2498=ZZ2498+ZZ2498
-+007254 427400 ZZ2498=ZZ2498+ZZ2498
-+007254 005245 0 8192 -ZZ1498
-+007255 427400 0 ZZ2498
-- mark 5470, -469 /10 scor
-+007256 776124 ZZ2499=ZZ2499+ZZ2499
-+007256 774250 ZZ2499=ZZ2499+ZZ2499
-+007256 770520 ZZ2499=ZZ2499+ZZ2499
-+007256 761240 ZZ2499=ZZ2499+ZZ2499
-+007256 742500 ZZ2499=ZZ2499+ZZ2499
-+007256 705200 ZZ2499=ZZ2499+ZZ2499
-+007256 612400 ZZ2499=ZZ2499+ZZ2499
-+007256 425000 ZZ2499=ZZ2499+ZZ2499
-+007256 005242 0 8192 -ZZ1499
-+007257 425000 0 ZZ2499
-- mark 5497, -437 /14 scor
-+007260 776224 ZZ2500=ZZ2500+ZZ2500
-+007260 774450 ZZ2500=ZZ2500+ZZ2500
-+007260 771120 ZZ2500=ZZ2500+ZZ2500
-+007260 762240 ZZ2500=ZZ2500+ZZ2500
-+007260 744500 ZZ2500=ZZ2500+ZZ2500
-+007260 711200 ZZ2500=ZZ2500+ZZ2500
-+007260 622400 ZZ2500=ZZ2500+ZZ2500
-+007260 445000 ZZ2500=ZZ2500+ZZ2500
-+007260 005207 0 8192 -ZZ1500
-+007261 445000 0 ZZ2500
-- mark 5499, -223 /15 scor
-+007262 777100 ZZ2501=ZZ2501+ZZ2501
-+007262 776200 ZZ2501=ZZ2501+ZZ2501
-+007262 774400 ZZ2501=ZZ2501+ZZ2501
-+007262 771000 ZZ2501=ZZ2501+ZZ2501
-+007262 762000 ZZ2501=ZZ2501+ZZ2501
-+007262 744000 ZZ2501=ZZ2501+ZZ2501
-+007262 710000 ZZ2501=ZZ2501+ZZ2501
-+007262 620000 ZZ2501=ZZ2501+ZZ2501
-+007262 005205 0 8192 -ZZ1501
-+007263 620000 0 ZZ2501
-- mark 5558, 29 /50 serp
-+007264 000072 ZZ2502=ZZ2502+ZZ2502
-+007264 000164 ZZ2502=ZZ2502+ZZ2502
-+007264 000350 ZZ2502=ZZ2502+ZZ2502
-+007264 000720 ZZ2502=ZZ2502+ZZ2502
-+007264 001640 ZZ2502=ZZ2502+ZZ2502
-+007264 003500 ZZ2502=ZZ2502+ZZ2502
-+007264 007200 ZZ2502=ZZ2502+ZZ2502
-+007264 016400 ZZ2502=ZZ2502+ZZ2502
-+007264 005112 0 8192 -ZZ1502
-+007265 016400 0 ZZ2502
-- mark 5561, 441 /20 herc
-+007266 001562 ZZ2503=ZZ2503+ZZ2503
-+007266 003344 ZZ2503=ZZ2503+ZZ2503
-+007266 006710 ZZ2503=ZZ2503+ZZ2503
-+007266 015620 ZZ2503=ZZ2503+ZZ2503
-+007266 033440 ZZ2503=ZZ2503+ZZ2503
-+007266 067100 ZZ2503=ZZ2503+ZZ2503
-+007266 156200 ZZ2503=ZZ2503+ZZ2503
-+007266 334400 ZZ2503=ZZ2503+ZZ2503
-+007266 005107 0 8192 -ZZ1503
-+007267 334400 0 ZZ2503
-- mark 5565, -451 / 4 ophi
-+007270 776170 ZZ2504=ZZ2504+ZZ2504
-+007270 774360 ZZ2504=ZZ2504+ZZ2504
-+007270 770740 ZZ2504=ZZ2504+ZZ2504
-+007270 761700 ZZ2504=ZZ2504+ZZ2504
-+007270 743600 ZZ2504=ZZ2504+ZZ2504
-+007270 707400 ZZ2504=ZZ2504+ZZ2504
-+007270 617000 ZZ2504=ZZ2504+ZZ2504
-+007270 436000 ZZ2504=ZZ2504+ZZ2504
-+007270 005103 0 8192 -ZZ1504
-+007271 436000 0 ZZ2504
-- mark 5580, 325 /24 herc
-+007272 001212 ZZ2505=ZZ2505+ZZ2505
-+007272 002424 ZZ2505=ZZ2505+ZZ2505
-+007272 005050 ZZ2505=ZZ2505+ZZ2505
-+007272 012120 ZZ2505=ZZ2505+ZZ2505
-+007272 024240 ZZ2505=ZZ2505+ZZ2505
-+007272 050500 ZZ2505=ZZ2505+ZZ2505
-+007272 121200 ZZ2505=ZZ2505+ZZ2505
-+007272 242400 ZZ2505=ZZ2505+ZZ2505
-+007272 005064 0 8192 -ZZ1505
-+007273 242400 0 ZZ2505
-- mark 5582, -415 / 7 ophi
-+007274 776300 ZZ2506=ZZ2506+ZZ2506
-+007274 774600 ZZ2506=ZZ2506+ZZ2506
-+007274 771400 ZZ2506=ZZ2506+ZZ2506
-+007274 763000 ZZ2506=ZZ2506+ZZ2506
-+007274 746000 ZZ2506=ZZ2506+ZZ2506
-+007274 714000 ZZ2506=ZZ2506+ZZ2506
-+007274 630000 ZZ2506=ZZ2506+ZZ2506
-+007274 460000 ZZ2506=ZZ2506+ZZ2506
-+007274 005062 0 8192 -ZZ1506
-+007275 460000 0 ZZ2506
-- mark 5589, -186 / 3 ophi
-+007276 777212 ZZ2507=ZZ2507+ZZ2507
-+007276 776424 ZZ2507=ZZ2507+ZZ2507
-+007276 775050 ZZ2507=ZZ2507+ZZ2507
-+007276 772120 ZZ2507=ZZ2507+ZZ2507
-+007276 764240 ZZ2507=ZZ2507+ZZ2507
-+007276 750500 ZZ2507=ZZ2507+ZZ2507
-+007276 721200 ZZ2507=ZZ2507+ZZ2507
-+007276 642400 ZZ2507=ZZ2507+ZZ2507
-+007276 005053 0 8192 -ZZ1507
-+007277 642400 0 ZZ2507
-- mark 5606, -373 / 8 ophi
-+007300 776424 ZZ2508=ZZ2508+ZZ2508
-+007300 775050 ZZ2508=ZZ2508+ZZ2508
-+007300 772120 ZZ2508=ZZ2508+ZZ2508
-+007300 764240 ZZ2508=ZZ2508+ZZ2508
-+007300 750500 ZZ2508=ZZ2508+ZZ2508
-+007300 721200 ZZ2508=ZZ2508+ZZ2508
-+007300 642400 ZZ2508=ZZ2508+ZZ2508
-+007300 505000 ZZ2508=ZZ2508+ZZ2508
-+007300 005032 0 8192 -ZZ1508
-+007301 505000 0 ZZ2508
-- mark 5609, 50 /10 ophi
-+007302 000144 ZZ2509=ZZ2509+ZZ2509
-+007302 000310 ZZ2509=ZZ2509+ZZ2509
-+007302 000620 ZZ2509=ZZ2509+ZZ2509
-+007302 001440 ZZ2509=ZZ2509+ZZ2509
-+007302 003100 ZZ2509=ZZ2509+ZZ2509
-+007302 006200 ZZ2509=ZZ2509+ZZ2509
-+007302 014400 ZZ2509=ZZ2509+ZZ2509
-+007302 031000 ZZ2509=ZZ2509+ZZ2509
-+007302 005027 0 8192 -ZZ1509
-+007303 031000 0 ZZ2509
-- mark 5610, -484 / 9 ophi
-+007304 776066 ZZ2510=ZZ2510+ZZ2510
-+007304 774154 ZZ2510=ZZ2510+ZZ2510
-+007304 770330 ZZ2510=ZZ2510+ZZ2510
-+007304 760660 ZZ2510=ZZ2510+ZZ2510
-+007304 741540 ZZ2510=ZZ2510+ZZ2510
-+007304 703300 ZZ2510=ZZ2510+ZZ2510
-+007304 606600 ZZ2510=ZZ2510+ZZ2510
-+007304 415400 ZZ2510=ZZ2510+ZZ2510
-+007304 005026 0 8192 -ZZ1510
-+007305 415400 0 ZZ2510
-- mark 5620, 266 /29 herc
-+007306 001024 ZZ2511=ZZ2511+ZZ2511
-+007306 002050 ZZ2511=ZZ2511+ZZ2511
-+007306 004120 ZZ2511=ZZ2511+ZZ2511
-+007306 010240 ZZ2511=ZZ2511+ZZ2511
-+007306 020500 ZZ2511=ZZ2511+ZZ2511
-+007306 041200 ZZ2511=ZZ2511+ZZ2511
-+007306 102400 ZZ2511=ZZ2511+ZZ2511
-+007306 205000 ZZ2511=ZZ2511+ZZ2511
-+007306 005014 0 8192 -ZZ1511
-+007307 205000 0 ZZ2511
-- mark 5713, -241 /20 ophi
-+007310 777034 ZZ2512=ZZ2512+ZZ2512
-+007310 776070 ZZ2512=ZZ2512+ZZ2512
-+007310 774160 ZZ2512=ZZ2512+ZZ2512
-+007310 770340 ZZ2512=ZZ2512+ZZ2512
-+007310 760700 ZZ2512=ZZ2512+ZZ2512
-+007310 741600 ZZ2512=ZZ2512+ZZ2512
-+007310 703400 ZZ2512=ZZ2512+ZZ2512
-+007310 607000 ZZ2512=ZZ2512+ZZ2512
-+007310 004657 0 8192 -ZZ1512
-+007311 607000 0 ZZ2512
-- mark 5742, 235 /25 ophi
-+007312 000726 ZZ2513=ZZ2513+ZZ2513
-+007312 001654 ZZ2513=ZZ2513+ZZ2513
-+007312 003530 ZZ2513=ZZ2513+ZZ2513
-+007312 007260 ZZ2513=ZZ2513+ZZ2513
-+007312 016540 ZZ2513=ZZ2513+ZZ2513
-+007312 035300 ZZ2513=ZZ2513+ZZ2513
-+007312 072600 ZZ2513=ZZ2513+ZZ2513
-+007312 165400 ZZ2513=ZZ2513+ZZ2513
-+007312 004622 0 8192 -ZZ1513
-+007313 165400 0 ZZ2513
-- mark 5763, 217 /27 ophi
-+007314 000662 ZZ2514=ZZ2514+ZZ2514
-+007314 001544 ZZ2514=ZZ2514+ZZ2514
-+007314 003310 ZZ2514=ZZ2514+ZZ2514
-+007314 006620 ZZ2514=ZZ2514+ZZ2514
-+007314 015440 ZZ2514=ZZ2514+ZZ2514
-+007314 033100 ZZ2514=ZZ2514+ZZ2514
-+007314 066200 ZZ2514=ZZ2514+ZZ2514
-+007314 154400 ZZ2514=ZZ2514+ZZ2514
-+007314 004575 0 8192 -ZZ1514
-+007315 154400 0 ZZ2514
-- mark 5807, 293 /60 herc
-+007316 001112 ZZ2515=ZZ2515+ZZ2515
-+007316 002224 ZZ2515=ZZ2515+ZZ2515
-+007316 004450 ZZ2515=ZZ2515+ZZ2515
-+007316 011120 ZZ2515=ZZ2515+ZZ2515
-+007316 022240 ZZ2515=ZZ2515+ZZ2515
-+007316 044500 ZZ2515=ZZ2515+ZZ2515
-+007316 111200 ZZ2515=ZZ2515+ZZ2515
-+007316 222400 ZZ2515=ZZ2515+ZZ2515
-+007316 004521 0 8192 -ZZ1515
-+007317 222400 0 ZZ2515
-- mark 5868, -8 /41 ophi
-+007320 777756 ZZ2516=ZZ2516+ZZ2516
-+007320 777734 ZZ2516=ZZ2516+ZZ2516
-+007320 777670 ZZ2516=ZZ2516+ZZ2516
-+007320 777560 ZZ2516=ZZ2516+ZZ2516
-+007320 777340 ZZ2516=ZZ2516+ZZ2516
-+007320 776700 ZZ2516=ZZ2516+ZZ2516
-+007320 775600 ZZ2516=ZZ2516+ZZ2516
-+007320 773400 ZZ2516=ZZ2516+ZZ2516
-+007320 004424 0 8192 -ZZ1516
-+007321 773400 0 ZZ2516
-- mark 5888, -478 /40 ophi
-+007322 776102 ZZ2517=ZZ2517+ZZ2517
-+007322 774204 ZZ2517=ZZ2517+ZZ2517
-+007322 770410 ZZ2517=ZZ2517+ZZ2517
-+007322 761020 ZZ2517=ZZ2517+ZZ2517
-+007322 742040 ZZ2517=ZZ2517+ZZ2517
-+007322 704100 ZZ2517=ZZ2517+ZZ2517
-+007322 610200 ZZ2517=ZZ2517+ZZ2517
-+007322 420400 ZZ2517=ZZ2517+ZZ2517
-+007322 004400 0 8192 -ZZ1517
-+007323 420400 0 ZZ2517
-- mark 5889, -290 /53 serp
-+007324 776672 ZZ2518=ZZ2518+ZZ2518
-+007324 775564 ZZ2518=ZZ2518+ZZ2518
-+007324 773350 ZZ2518=ZZ2518+ZZ2518
-+007324 766720 ZZ2518=ZZ2518+ZZ2518
-+007324 755640 ZZ2518=ZZ2518+ZZ2518
-+007324 733500 ZZ2518=ZZ2518+ZZ2518
-+007324 667200 ZZ2518=ZZ2518+ZZ2518
-+007324 556400 ZZ2518=ZZ2518+ZZ2518
-+007324 004377 0 8192 -ZZ1518
-+007325 556400 0 ZZ2518
-- mark 5924, -114 /
-+007326 777432 ZZ2519=ZZ2519+ZZ2519
-+007326 777064 ZZ2519=ZZ2519+ZZ2519
-+007326 776150 ZZ2519=ZZ2519+ZZ2519
-+007326 774320 ZZ2519=ZZ2519+ZZ2519
-+007326 770640 ZZ2519=ZZ2519+ZZ2519
-+007326 761500 ZZ2519=ZZ2519+ZZ2519
-+007326 743200 ZZ2519=ZZ2519+ZZ2519
-+007326 706400 ZZ2519=ZZ2519+ZZ2519
-+007326 004334 0 8192 -ZZ1519
-+007327 706400 0 ZZ2519
-- mark 5925, 96 /49 ophi
-+007330 000300 ZZ2520=ZZ2520+ZZ2520
-+007330 000600 ZZ2520=ZZ2520+ZZ2520
-+007330 001400 ZZ2520=ZZ2520+ZZ2520
-+007330 003000 ZZ2520=ZZ2520+ZZ2520
-+007330 006000 ZZ2520=ZZ2520+ZZ2520
-+007330 014000 ZZ2520=ZZ2520+ZZ2520
-+007330 030000 ZZ2520=ZZ2520+ZZ2520
-+007330 060000 ZZ2520=ZZ2520+ZZ2520
-+007330 004333 0 8192 -ZZ1520
-+007331 060000 0 ZZ2520
-- mark 5987, -183 /57 ophi
-+007332 777220 ZZ2521=ZZ2521+ZZ2521
-+007332 776440 ZZ2521=ZZ2521+ZZ2521
-+007332 775100 ZZ2521=ZZ2521+ZZ2521
-+007332 772200 ZZ2521=ZZ2521+ZZ2521
-+007332 764400 ZZ2521=ZZ2521+ZZ2521
-+007332 751000 ZZ2521=ZZ2521+ZZ2521
-+007332 722000 ZZ2521=ZZ2521+ZZ2521
-+007332 644000 ZZ2521=ZZ2521+ZZ2521
-+007332 004235 0 8192 -ZZ1521
-+007333 644000 0 ZZ2521
-- mark 6006, -292 /56 serp
-+007334 776666 ZZ2522=ZZ2522+ZZ2522
-+007334 775554 ZZ2522=ZZ2522+ZZ2522
-+007334 773330 ZZ2522=ZZ2522+ZZ2522
-+007334 766660 ZZ2522=ZZ2522+ZZ2522
-+007334 755540 ZZ2522=ZZ2522+ZZ2522
-+007334 733300 ZZ2522=ZZ2522+ZZ2522
-+007334 666600 ZZ2522=ZZ2522+ZZ2522
-+007334 555400 ZZ2522=ZZ2522+ZZ2522
-+007334 004212 0 8192 -ZZ1522
-+007335 555400 0 ZZ2522
-- mark 6016, -492 /58 ophi
-+007336 776046 ZZ2523=ZZ2523+ZZ2523
-+007336 774114 ZZ2523=ZZ2523+ZZ2523
-+007336 770230 ZZ2523=ZZ2523+ZZ2523
-+007336 760460 ZZ2523=ZZ2523+ZZ2523
-+007336 741140 ZZ2523=ZZ2523+ZZ2523
-+007336 702300 ZZ2523=ZZ2523+ZZ2523
-+007336 604600 ZZ2523=ZZ2523+ZZ2523
-+007336 411400 ZZ2523=ZZ2523+ZZ2523
-+007336 004200 0 8192 -ZZ1523
-+007337 411400 0 ZZ2523
-- mark 6117, -84 /57 serp
-+007340 777526 ZZ2524=ZZ2524+ZZ2524
-+007340 777254 ZZ2524=ZZ2524+ZZ2524
-+007340 776530 ZZ2524=ZZ2524+ZZ2524
-+007340 775260 ZZ2524=ZZ2524+ZZ2524
-+007340 772540 ZZ2524=ZZ2524+ZZ2524
-+007340 765300 ZZ2524=ZZ2524+ZZ2524
-+007340 752600 ZZ2524=ZZ2524+ZZ2524
-+007340 725400 ZZ2524=ZZ2524+ZZ2524
-+007340 004033 0 8192 -ZZ1524
-+007341 725400 0 ZZ2524
-- mark 6117, 99 /66 ophi
-+007342 000306 ZZ2525=ZZ2525+ZZ2525
-+007342 000614 ZZ2525=ZZ2525+ZZ2525
-+007342 001430 ZZ2525=ZZ2525+ZZ2525
-+007342 003060 ZZ2525=ZZ2525+ZZ2525
-+007342 006140 ZZ2525=ZZ2525+ZZ2525
-+007342 014300 ZZ2525=ZZ2525+ZZ2525
-+007342 030600 ZZ2525=ZZ2525+ZZ2525
-+007342 061400 ZZ2525=ZZ2525+ZZ2525
-+007342 004033 0 8192 -ZZ1525
-+007343 061400 0 ZZ2525
-- mark 6119, 381 /93 herc
-+007344 001372 ZZ2526=ZZ2526+ZZ2526
-+007344 002764 ZZ2526=ZZ2526+ZZ2526
-+007344 005750 ZZ2526=ZZ2526+ZZ2526
-+007344 013720 ZZ2526=ZZ2526+ZZ2526
-+007344 027640 ZZ2526=ZZ2526+ZZ2526
-+007344 057500 ZZ2526=ZZ2526+ZZ2526
-+007344 137200 ZZ2526=ZZ2526+ZZ2526
-+007344 276400 ZZ2526=ZZ2526+ZZ2526
-+007344 004031 0 8192 -ZZ1526
-+007345 276400 0 ZZ2526
-- mark 6119, 67 /67 ophi
-+007346 000206 ZZ2527=ZZ2527+ZZ2527
-+007346 000414 ZZ2527=ZZ2527+ZZ2527
-+007346 001030 ZZ2527=ZZ2527+ZZ2527
-+007346 002060 ZZ2527=ZZ2527+ZZ2527
-+007346 004140 ZZ2527=ZZ2527+ZZ2527
-+007346 010300 ZZ2527=ZZ2527+ZZ2527
-+007346 020600 ZZ2527=ZZ2527+ZZ2527
-+007346 041400 ZZ2527=ZZ2527+ZZ2527
-+007346 004031 0 8192 -ZZ1527
-+007347 041400 0 ZZ2527
-- mark 6125, 30 /68 ophi
-+007350 000074 ZZ2528=ZZ2528+ZZ2528
-+007350 000170 ZZ2528=ZZ2528+ZZ2528
-+007350 000360 ZZ2528=ZZ2528+ZZ2528
-+007350 000740 ZZ2528=ZZ2528+ZZ2528
-+007350 001700 ZZ2528=ZZ2528+ZZ2528
-+007350 003600 ZZ2528=ZZ2528+ZZ2528
-+007350 007400 ZZ2528=ZZ2528+ZZ2528
-+007350 017000 ZZ2528=ZZ2528+ZZ2528
-+007350 004023 0 8192 -ZZ1528
-+007351 017000 0 ZZ2528
-- mark 6146, 57 /70 ophi
-+007352 000162 ZZ2529=ZZ2529+ZZ2529
-+007352 000344 ZZ2529=ZZ2529+ZZ2529
-+007352 000710 ZZ2529=ZZ2529+ZZ2529
-+007352 001620 ZZ2529=ZZ2529+ZZ2529
-+007352 003440 ZZ2529=ZZ2529+ZZ2529
-+007352 007100 ZZ2529=ZZ2529+ZZ2529
-+007352 016200 ZZ2529=ZZ2529+ZZ2529
-+007352 034400 ZZ2529=ZZ2529+ZZ2529
-+007352 003776 0 8192 -ZZ1529
-+007353 034400 0 ZZ2529
-- mark 6158, 198 /71 ophi
-+007354 000614 ZZ2530=ZZ2530+ZZ2530
-+007354 001430 ZZ2530=ZZ2530+ZZ2530
-+007354 003060 ZZ2530=ZZ2530+ZZ2530
-+007354 006140 ZZ2530=ZZ2530+ZZ2530
-+007354 014300 ZZ2530=ZZ2530+ZZ2530
-+007354 030600 ZZ2530=ZZ2530+ZZ2530
-+007354 061400 ZZ2530=ZZ2530+ZZ2530
-+007354 143000 ZZ2530=ZZ2530+ZZ2530
-+007354 003762 0 8192 -ZZ1530
-+007355 143000 0 ZZ2530
-- mark 6170, 473 /102 herc
-+007356 001662 ZZ2531=ZZ2531+ZZ2531
-+007356 003544 ZZ2531=ZZ2531+ZZ2531
-+007356 007310 ZZ2531=ZZ2531+ZZ2531
-+007356 016620 ZZ2531=ZZ2531+ZZ2531
-+007356 035440 ZZ2531=ZZ2531+ZZ2531
-+007356 073100 ZZ2531=ZZ2531+ZZ2531
-+007356 166200 ZZ2531=ZZ2531+ZZ2531
-+007356 354400 ZZ2531=ZZ2531+ZZ2531
-+007356 003746 0 8192 -ZZ1531
-+007357 354400 0 ZZ2531
-- mark 6188, -480 /13 sgtr
-+007360 776076 ZZ2532=ZZ2532+ZZ2532
-+007360 774174 ZZ2532=ZZ2532+ZZ2532
-+007360 770370 ZZ2532=ZZ2532+ZZ2532
-+007360 760760 ZZ2532=ZZ2532+ZZ2532
-+007360 741740 ZZ2532=ZZ2532+ZZ2532
-+007360 703700 ZZ2532=ZZ2532+ZZ2532
-+007360 607600 ZZ2532=ZZ2532+ZZ2532
-+007360 417400 ZZ2532=ZZ2532+ZZ2532
-+007360 003724 0 8192 -ZZ1532
-+007361 417400 0 ZZ2532
-- mark 6234, 76 /74 ophi
-+007362 000230 ZZ2533=ZZ2533+ZZ2533
-+007362 000460 ZZ2533=ZZ2533+ZZ2533
-+007362 001140 ZZ2533=ZZ2533+ZZ2533
-+007362 002300 ZZ2533=ZZ2533+ZZ2533
-+007362 004600 ZZ2533=ZZ2533+ZZ2533
-+007362 011400 ZZ2533=ZZ2533+ZZ2533
-+007362 023000 ZZ2533=ZZ2533+ZZ2533
-+007362 046000 ZZ2533=ZZ2533+ZZ2533
-+007362 003646 0 8192 -ZZ1533
-+007363 046000 0 ZZ2533
-- mark 6235, 499 /106 herc
-+007364 001746 ZZ2534=ZZ2534+ZZ2534
-+007364 003714 ZZ2534=ZZ2534+ZZ2534
-+007364 007630 ZZ2534=ZZ2534+ZZ2534
-+007364 017460 ZZ2534=ZZ2534+ZZ2534
-+007364 037140 ZZ2534=ZZ2534+ZZ2534
-+007364 076300 ZZ2534=ZZ2534+ZZ2534
-+007364 174600 ZZ2534=ZZ2534+ZZ2534
-+007364 371400 ZZ2534=ZZ2534+ZZ2534
-+007364 003645 0 8192 -ZZ1534
-+007365 371400 0 ZZ2534
-- mark 6247, -204 /xi scut
-+007366 777146 ZZ2535=ZZ2535+ZZ2535
-+007366 776314 ZZ2535=ZZ2535+ZZ2535
-+007366 774630 ZZ2535=ZZ2535+ZZ2535
-+007366 771460 ZZ2535=ZZ2535+ZZ2535
-+007366 763140 ZZ2535=ZZ2535+ZZ2535
-+007366 746300 ZZ2535=ZZ2535+ZZ2535
-+007366 714600 ZZ2535=ZZ2535+ZZ2535
-+007366 631400 ZZ2535=ZZ2535+ZZ2535
-+007366 003631 0 8192 -ZZ1535
-+007367 631400 0 ZZ2535
-- mark 6254, -469 /21 sgtr
-+007370 776124 ZZ2536=ZZ2536+ZZ2536
-+007370 774250 ZZ2536=ZZ2536+ZZ2536
-+007370 770520 ZZ2536=ZZ2536+ZZ2536
-+007370 761240 ZZ2536=ZZ2536+ZZ2536
-+007370 742500 ZZ2536=ZZ2536+ZZ2536
-+007370 705200 ZZ2536=ZZ2536+ZZ2536
-+007370 612400 ZZ2536=ZZ2536+ZZ2536
-+007370 425000 ZZ2536=ZZ2536+ZZ2536
-+007370 003622 0 8192 -ZZ1536
-+007371 425000 0 ZZ2536
-- mark 6255, 494 /109 herc
-+007372 001734 ZZ2537=ZZ2537+ZZ2537
-+007372 003670 ZZ2537=ZZ2537+ZZ2537
-+007372 007560 ZZ2537=ZZ2537+ZZ2537
-+007372 017340 ZZ2537=ZZ2537+ZZ2537
-+007372 036700 ZZ2537=ZZ2537+ZZ2537
-+007372 075600 ZZ2537=ZZ2537+ZZ2537
-+007372 173400 ZZ2537=ZZ2537+ZZ2537
-+007372 367000 ZZ2537=ZZ2537+ZZ2537
-+007372 003621 0 8192 -ZZ1537
-+007373 367000 0 ZZ2537
-- mark 6278, -333 /ga scut
-+007374 776544 ZZ2538=ZZ2538+ZZ2538
-+007374 775310 ZZ2538=ZZ2538+ZZ2538
-+007374 772620 ZZ2538=ZZ2538+ZZ2538
-+007374 765440 ZZ2538=ZZ2538+ZZ2538
-+007374 753100 ZZ2538=ZZ2538+ZZ2538
-+007374 726200 ZZ2538=ZZ2538+ZZ2538
-+007374 654400 ZZ2538=ZZ2538+ZZ2538
-+007374 531000 ZZ2538=ZZ2538+ZZ2538
-+007374 003572 0 8192 -ZZ1538
-+007375 531000 0 ZZ2538
-- mark 6313, -189 /al scut
-+007376 777204 ZZ2539=ZZ2539+ZZ2539
-+007376 776410 ZZ2539=ZZ2539+ZZ2539
-+007376 775020 ZZ2539=ZZ2539+ZZ2539
-+007376 772040 ZZ2539=ZZ2539+ZZ2539
-+007376 764100 ZZ2539=ZZ2539+ZZ2539
-+007376 750200 ZZ2539=ZZ2539+ZZ2539
-+007376 720400 ZZ2539=ZZ2539+ZZ2539
-+007376 641000 ZZ2539=ZZ2539+ZZ2539
-+007376 003527 0 8192 -ZZ1539
-+007377 641000 0 ZZ2539
-- mark 6379, 465 /110 herc
-+007400 001642 ZZ2540=ZZ2540+ZZ2540
-+007400 003504 ZZ2540=ZZ2540+ZZ2540
-+007400 007210 ZZ2540=ZZ2540+ZZ2540
-+007400 016420 ZZ2540=ZZ2540+ZZ2540
-+007400 035040 ZZ2540=ZZ2540+ZZ2540
-+007400 072100 ZZ2540=ZZ2540+ZZ2540
-+007400 164200 ZZ2540=ZZ2540+ZZ2540
-+007400 350400 ZZ2540=ZZ2540+ZZ2540
-+007400 003425 0 8192 -ZZ1540
-+007401 350400 0 ZZ2540
-- mark 6382, -110 /be scut
-+007402 777442 ZZ2541=ZZ2541+ZZ2541
-+007402 777104 ZZ2541=ZZ2541+ZZ2541
-+007402 776210 ZZ2541=ZZ2541+ZZ2541
-+007402 774420 ZZ2541=ZZ2541+ZZ2541
-+007402 771040 ZZ2541=ZZ2541+ZZ2541
-+007402 762100 ZZ2541=ZZ2541+ZZ2541
-+007402 744200 ZZ2541=ZZ2541+ZZ2541
-+007402 710400 ZZ2541=ZZ2541+ZZ2541
-+007402 003422 0 8192 -ZZ1541
-+007403 710400 0 ZZ2541
-- mark 6386, 411 /111 herc
-+007404 001466 ZZ2542=ZZ2542+ZZ2542
-+007404 003154 ZZ2542=ZZ2542+ZZ2542
-+007404 006330 ZZ2542=ZZ2542+ZZ2542
-+007404 014660 ZZ2542=ZZ2542+ZZ2542
-+007404 031540 ZZ2542=ZZ2542+ZZ2542
-+007404 063300 ZZ2542=ZZ2542+ZZ2542
-+007404 146600 ZZ2542=ZZ2542+ZZ2542
-+007404 315400 ZZ2542=ZZ2542+ZZ2542
-+007404 003416 0 8192 -ZZ1542
-+007405 315400 0 ZZ2542
-- mark 6436, 93 /63 serp
-+007406 000272 ZZ2543=ZZ2543+ZZ2543
-+007406 000564 ZZ2543=ZZ2543+ZZ2543
-+007406 001350 ZZ2543=ZZ2543+ZZ2543
-+007406 002720 ZZ2543=ZZ2543+ZZ2543
-+007406 005640 ZZ2543=ZZ2543+ZZ2543
-+007406 013500 ZZ2543=ZZ2543+ZZ2543
-+007406 027200 ZZ2543=ZZ2543+ZZ2543
-+007406 056400 ZZ2543=ZZ2543+ZZ2543
-+007406 003334 0 8192 -ZZ1543
-+007407 056400 0 ZZ2543
-- mark 6457, 340 /13 aqil
-+007410 001250 ZZ2544=ZZ2544+ZZ2544
-+007410 002520 ZZ2544=ZZ2544+ZZ2544
-+007410 005240 ZZ2544=ZZ2544+ZZ2544
-+007410 012500 ZZ2544=ZZ2544+ZZ2544
-+007410 025200 ZZ2544=ZZ2544+ZZ2544
-+007410 052400 ZZ2544=ZZ2544+ZZ2544
-+007410 125000 ZZ2544=ZZ2544+ZZ2544
-+007410 252000 ZZ2544=ZZ2544+ZZ2544
-+007410 003307 0 8192 -ZZ1544
-+007411 252000 0 ZZ2544
-- mark 6465, -134 /12 aqil
-+007412 777362 ZZ2545=ZZ2545+ZZ2545
-+007412 776744 ZZ2545=ZZ2545+ZZ2545
-+007412 775710 ZZ2545=ZZ2545+ZZ2545
-+007412 773620 ZZ2545=ZZ2545+ZZ2545
-+007412 767440 ZZ2545=ZZ2545+ZZ2545
-+007412 757100 ZZ2545=ZZ2545+ZZ2545
-+007412 736200 ZZ2545=ZZ2545+ZZ2545
-+007412 674400 ZZ2545=ZZ2545+ZZ2545
-+007412 003277 0 8192 -ZZ1545
-+007413 674400 0 ZZ2545
-- mark 6478, -498 /39 sgtr
-+007414 776032 ZZ2546=ZZ2546+ZZ2546
-+007414 774064 ZZ2546=ZZ2546+ZZ2546
-+007414 770150 ZZ2546=ZZ2546+ZZ2546
-+007414 760320 ZZ2546=ZZ2546+ZZ2546
-+007414 740640 ZZ2546=ZZ2546+ZZ2546
-+007414 701500 ZZ2546=ZZ2546+ZZ2546
-+007414 603200 ZZ2546=ZZ2546+ZZ2546
-+007414 406400 ZZ2546=ZZ2546+ZZ2546
-+007414 003262 0 8192 -ZZ1546
-+007415 406400 0 ZZ2546
-- mark 6553, 483 / 1 vulp
-+007416 001706 ZZ2547=ZZ2547+ZZ2547
-+007416 003614 ZZ2547=ZZ2547+ZZ2547
-+007416 007430 ZZ2547=ZZ2547+ZZ2547
-+007416 017060 ZZ2547=ZZ2547+ZZ2547
-+007416 036140 ZZ2547=ZZ2547+ZZ2547
-+007416 074300 ZZ2547=ZZ2547+ZZ2547
-+007416 170600 ZZ2547=ZZ2547+ZZ2547
-+007416 361400 ZZ2547=ZZ2547+ZZ2547
-+007416 003147 0 8192 -ZZ1547
-+007417 361400 0 ZZ2547
-- mark 6576, -410 /44 sgtr
-+007420 776312 ZZ2548=ZZ2548+ZZ2548
-+007420 774624 ZZ2548=ZZ2548+ZZ2548
-+007420 771450 ZZ2548=ZZ2548+ZZ2548
-+007420 763120 ZZ2548=ZZ2548+ZZ2548
-+007420 746240 ZZ2548=ZZ2548+ZZ2548
-+007420 714500 ZZ2548=ZZ2548+ZZ2548
-+007420 631200 ZZ2548=ZZ2548+ZZ2548
-+007420 462400 ZZ2548=ZZ2548+ZZ2548
-+007420 003120 0 8192 -ZZ1548
-+007421 462400 0 ZZ2548
-- mark 6576, -368 /46 sgtr
-+007422 776436 ZZ2549=ZZ2549+ZZ2549
-+007422 775074 ZZ2549=ZZ2549+ZZ2549
-+007422 772170 ZZ2549=ZZ2549+ZZ2549
-+007422 764360 ZZ2549=ZZ2549+ZZ2549
-+007422 750740 ZZ2549=ZZ2549+ZZ2549
-+007422 721700 ZZ2549=ZZ2549+ZZ2549
-+007422 643600 ZZ2549=ZZ2549+ZZ2549
-+007422 507400 ZZ2549=ZZ2549+ZZ2549
-+007422 003120 0 8192 -ZZ1549
-+007423 507400 0 ZZ2549
-- mark 6607, 3 /32 aqil
-+007424 000006 ZZ2550=ZZ2550+ZZ2550
-+007424 000014 ZZ2550=ZZ2550+ZZ2550
-+007424 000030 ZZ2550=ZZ2550+ZZ2550
-+007424 000060 ZZ2550=ZZ2550+ZZ2550
-+007424 000140 ZZ2550=ZZ2550+ZZ2550
-+007424 000300 ZZ2550=ZZ2550+ZZ2550
-+007424 000600 ZZ2550=ZZ2550+ZZ2550
-+007424 001400 ZZ2550=ZZ2550+ZZ2550
-+007424 003061 0 8192 -ZZ1550
-+007425 001400 0 ZZ2550
-- mark 6651, 163 /38 aqil
-+007426 000506 ZZ2551=ZZ2551+ZZ2551
-+007426 001214 ZZ2551=ZZ2551+ZZ2551
-+007426 002430 ZZ2551=ZZ2551+ZZ2551
-+007426 005060 ZZ2551=ZZ2551+ZZ2551
-+007426 012140 ZZ2551=ZZ2551+ZZ2551
-+007426 024300 ZZ2551=ZZ2551+ZZ2551
-+007426 050600 ZZ2551=ZZ2551+ZZ2551
-+007426 121400 ZZ2551=ZZ2551+ZZ2551
-+007426 003005 0 8192 -ZZ1551
-+007427 121400 0 ZZ2551
-- mark 6657, 445 / 9 vulp
-+007430 001572 ZZ2552=ZZ2552+ZZ2552
-+007430 003364 ZZ2552=ZZ2552+ZZ2552
-+007430 006750 ZZ2552=ZZ2552+ZZ2552
-+007430 015720 ZZ2552=ZZ2552+ZZ2552
-+007430 033640 ZZ2552=ZZ2552+ZZ2552
-+007430 067500 ZZ2552=ZZ2552+ZZ2552
-+007430 157200 ZZ2552=ZZ2552+ZZ2552
-+007430 336400 ZZ2552=ZZ2552+ZZ2552
-+007430 002777 0 8192 -ZZ1552
-+007431 336400 0 ZZ2552
-- mark 6665, -35 /41 aqil
-+007432 777670 ZZ2553=ZZ2553+ZZ2553
-+007432 777560 ZZ2553=ZZ2553+ZZ2553
-+007432 777340 ZZ2553=ZZ2553+ZZ2553
-+007432 776700 ZZ2553=ZZ2553+ZZ2553
-+007432 775600 ZZ2553=ZZ2553+ZZ2553
-+007432 773400 ZZ2553=ZZ2553+ZZ2553
-+007432 767000 ZZ2553=ZZ2553+ZZ2553
-+007432 756000 ZZ2553=ZZ2553+ZZ2553
-+007432 002767 0 8192 -ZZ1553
-+007433 756000 0 ZZ2553
-- mark 6688, 405 / 5 sgte
-+007434 001452 ZZ2554=ZZ2554+ZZ2554
-+007434 003124 ZZ2554=ZZ2554+ZZ2554
-+007434 006250 ZZ2554=ZZ2554+ZZ2554
-+007434 014520 ZZ2554=ZZ2554+ZZ2554
-+007434 031240 ZZ2554=ZZ2554+ZZ2554
-+007434 062500 ZZ2554=ZZ2554+ZZ2554
-+007434 145200 ZZ2554=ZZ2554+ZZ2554
-+007434 312400 ZZ2554=ZZ2554+ZZ2554
-+007434 002740 0 8192 -ZZ1554
-+007435 312400 0 ZZ2554
-- mark 6693, 393 / 6 sgte
-+007436 001422 ZZ2555=ZZ2555+ZZ2555
-+007436 003044 ZZ2555=ZZ2555+ZZ2555
-+007436 006110 ZZ2555=ZZ2555+ZZ2555
-+007436 014220 ZZ2555=ZZ2555+ZZ2555
-+007436 030440 ZZ2555=ZZ2555+ZZ2555
-+007436 061100 ZZ2555=ZZ2555+ZZ2555
-+007436 142200 ZZ2555=ZZ2555+ZZ2555
-+007436 304400 ZZ2555=ZZ2555+ZZ2555
-+007436 002733 0 8192 -ZZ1555
-+007437 304400 0 ZZ2555
-- mark 6730, 416 / 7 sgte
-+007440 001500 ZZ2556=ZZ2556+ZZ2556
-+007440 003200 ZZ2556=ZZ2556+ZZ2556
-+007440 006400 ZZ2556=ZZ2556+ZZ2556
-+007440 015000 ZZ2556=ZZ2556+ZZ2556
-+007440 032000 ZZ2556=ZZ2556+ZZ2556
-+007440 064000 ZZ2556=ZZ2556+ZZ2556
-+007440 150000 ZZ2556=ZZ2556+ZZ2556
-+007440 320000 ZZ2556=ZZ2556+ZZ2556
-+007440 002666 0 8192 -ZZ1556
-+007441 320000 0 ZZ2556
-- mark 6739, 430 / 8 sgte
-+007442 001534 ZZ2557=ZZ2557+ZZ2557
-+007442 003270 ZZ2557=ZZ2557+ZZ2557
-+007442 006560 ZZ2557=ZZ2557+ZZ2557
-+007442 015340 ZZ2557=ZZ2557+ZZ2557
-+007442 032700 ZZ2557=ZZ2557+ZZ2557
-+007442 065600 ZZ2557=ZZ2557+ZZ2557
-+007442 153400 ZZ2557=ZZ2557+ZZ2557
-+007442 327000 ZZ2557=ZZ2557+ZZ2557
-+007442 002655 0 8192 -ZZ1557
-+007443 327000 0 ZZ2557
-- mark 6755, 17 /55 aqil
-+007444 000042 ZZ2558=ZZ2558+ZZ2558
-+007444 000104 ZZ2558=ZZ2558+ZZ2558
-+007444 000210 ZZ2558=ZZ2558+ZZ2558
-+007444 000420 ZZ2558=ZZ2558+ZZ2558
-+007444 001040 ZZ2558=ZZ2558+ZZ2558
-+007444 002100 ZZ2558=ZZ2558+ZZ2558
-+007444 004200 ZZ2558=ZZ2558+ZZ2558
-+007444 010400 ZZ2558=ZZ2558+ZZ2558
-+007444 002635 0 8192 -ZZ1558
-+007445 010400 0 ZZ2558
-- mark 6766, 187 /59 aqil
-+007446 000566 ZZ2559=ZZ2559+ZZ2559
-+007446 001354 ZZ2559=ZZ2559+ZZ2559
-+007446 002730 ZZ2559=ZZ2559+ZZ2559
-+007446 005660 ZZ2559=ZZ2559+ZZ2559
-+007446 013540 ZZ2559=ZZ2559+ZZ2559
-+007446 027300 ZZ2559=ZZ2559+ZZ2559
-+007446 056600 ZZ2559=ZZ2559+ZZ2559
-+007446 135400 ZZ2559=ZZ2559+ZZ2559
-+007446 002622 0 8192 -ZZ1559
-+007447 135400 0 ZZ2559
-- mark 6772, 140 /60 aqil
-+007450 000430 ZZ2560=ZZ2560+ZZ2560
-+007450 001060 ZZ2560=ZZ2560+ZZ2560
-+007450 002140 ZZ2560=ZZ2560+ZZ2560
-+007450 004300 ZZ2560=ZZ2560+ZZ2560
-+007450 010600 ZZ2560=ZZ2560+ZZ2560
-+007450 021400 ZZ2560=ZZ2560+ZZ2560
-+007450 043000 ZZ2560=ZZ2560+ZZ2560
-+007450 106000 ZZ2560=ZZ2560+ZZ2560
-+007450 002614 0 8192 -ZZ1560
-+007451 106000 0 ZZ2560
-- mark 6882, 339 /67 aqil
-+007452 001246 ZZ2561=ZZ2561+ZZ2561
-+007452 002514 ZZ2561=ZZ2561+ZZ2561
-+007452 005230 ZZ2561=ZZ2561+ZZ2561
-+007452 012460 ZZ2561=ZZ2561+ZZ2561
-+007452 025140 ZZ2561=ZZ2561+ZZ2561
-+007452 052300 ZZ2561=ZZ2561+ZZ2561
-+007452 124600 ZZ2561=ZZ2561+ZZ2561
-+007452 251400 ZZ2561=ZZ2561+ZZ2561
-+007452 002436 0 8192 -ZZ1561
-+007453 251400 0 ZZ2561
-- mark 6896, -292 / 5 capr
-+007454 776666 ZZ2562=ZZ2562+ZZ2562
-+007454 775554 ZZ2562=ZZ2562+ZZ2562
-+007454 773330 ZZ2562=ZZ2562+ZZ2562
-+007454 766660 ZZ2562=ZZ2562+ZZ2562
-+007454 755540 ZZ2562=ZZ2562+ZZ2562
-+007454 733300 ZZ2562=ZZ2562+ZZ2562
-+007454 666600 ZZ2562=ZZ2562+ZZ2562
-+007454 555400 ZZ2562=ZZ2562+ZZ2562
-+007454 002420 0 8192 -ZZ1562
-+007455 555400 0 ZZ2562
-- mark 6898, -292 / 6 capr
-+007456 776666 ZZ2563=ZZ2563+ZZ2563
-+007456 775554 ZZ2563=ZZ2563+ZZ2563
-+007456 773330 ZZ2563=ZZ2563+ZZ2563
-+007456 766660 ZZ2563=ZZ2563+ZZ2563
-+007456 755540 ZZ2563=ZZ2563+ZZ2563
-+007456 733300 ZZ2563=ZZ2563+ZZ2563
-+007456 666600 ZZ2563=ZZ2563+ZZ2563
-+007456 555400 ZZ2563=ZZ2563+ZZ2563
-+007456 002416 0 8192 -ZZ1563
-+007457 555400 0 ZZ2563
-- mark 6913, -297 / 8 capr
-+007460 776654 ZZ2564=ZZ2564+ZZ2564
-+007460 775530 ZZ2564=ZZ2564+ZZ2564
-+007460 773260 ZZ2564=ZZ2564+ZZ2564
-+007460 766540 ZZ2564=ZZ2564+ZZ2564
-+007460 755300 ZZ2564=ZZ2564+ZZ2564
-+007460 732600 ZZ2564=ZZ2564+ZZ2564
-+007460 665400 ZZ2564=ZZ2564+ZZ2564
-+007460 553000 ZZ2564=ZZ2564+ZZ2564
-+007460 002377 0 8192 -ZZ1564
-+007461 553000 0 ZZ2564
-- mark 6958, -413 /11 capr
-+007462 776304 ZZ2565=ZZ2565+ZZ2565
-+007462 774610 ZZ2565=ZZ2565+ZZ2565
-+007462 771420 ZZ2565=ZZ2565+ZZ2565
-+007462 763040 ZZ2565=ZZ2565+ZZ2565
-+007462 746100 ZZ2565=ZZ2565+ZZ2565
-+007462 714200 ZZ2565=ZZ2565+ZZ2565
-+007462 630400 ZZ2565=ZZ2565+ZZ2565
-+007462 461000 ZZ2565=ZZ2565+ZZ2565
-+007462 002322 0 8192 -ZZ1565
-+007463 461000 0 ZZ2565
-- mark 6988, 250 / 2 dlph
-+007464 000764 ZZ2566=ZZ2566+ZZ2566
-+007464 001750 ZZ2566=ZZ2566+ZZ2566
-+007464 003720 ZZ2566=ZZ2566+ZZ2566
-+007464 007640 ZZ2566=ZZ2566+ZZ2566
-+007464 017500 ZZ2566=ZZ2566+ZZ2566
-+007464 037200 ZZ2566=ZZ2566+ZZ2566
-+007464 076400 ZZ2566=ZZ2566+ZZ2566
-+007464 175000 ZZ2566=ZZ2566+ZZ2566
-+007464 002264 0 8192 -ZZ1566
-+007465 175000 0 ZZ2566
-- mark 7001, 326 / 4 dlph
-+007466 001214 ZZ2567=ZZ2567+ZZ2567
-+007466 002430 ZZ2567=ZZ2567+ZZ2567
-+007466 005060 ZZ2567=ZZ2567+ZZ2567
-+007466 012140 ZZ2567=ZZ2567+ZZ2567
-+007466 024300 ZZ2567=ZZ2567+ZZ2567
-+007466 050600 ZZ2567=ZZ2567+ZZ2567
-+007466 121400 ZZ2567=ZZ2567+ZZ2567
-+007466 243000 ZZ2567=ZZ2567+ZZ2567
-+007466 002247 0 8192 -ZZ1567
-+007467 243000 0 ZZ2567
-- mark 7015, -33 /71 aqil
-+007470 777674 ZZ2568=ZZ2568+ZZ2568
-+007470 777570 ZZ2568=ZZ2568+ZZ2568
-+007470 777360 ZZ2568=ZZ2568+ZZ2568
-+007470 776740 ZZ2568=ZZ2568+ZZ2568
-+007470 775700 ZZ2568=ZZ2568+ZZ2568
-+007470 773600 ZZ2568=ZZ2568+ZZ2568
-+007470 767400 ZZ2568=ZZ2568+ZZ2568
-+007470 757000 ZZ2568=ZZ2568+ZZ2568
-+007470 002231 0 8192 -ZZ1568
-+007471 757000 0 ZZ2568
-- mark 7020, 475 /29 vulp
-+007472 001666 ZZ2569=ZZ2569+ZZ2569
-+007472 003554 ZZ2569=ZZ2569+ZZ2569
-+007472 007330 ZZ2569=ZZ2569+ZZ2569
-+007472 016660 ZZ2569=ZZ2569+ZZ2569
-+007472 035540 ZZ2569=ZZ2569+ZZ2569
-+007472 073300 ZZ2569=ZZ2569+ZZ2569
-+007472 166600 ZZ2569=ZZ2569+ZZ2569
-+007472 355400 ZZ2569=ZZ2569+ZZ2569
-+007472 002224 0 8192 -ZZ1569
-+007473 355400 0 ZZ2569
-- mark 7026, 354 / 9 dlph
-+007474 001304 ZZ2570=ZZ2570+ZZ2570
-+007474 002610 ZZ2570=ZZ2570+ZZ2570
-+007474 005420 ZZ2570=ZZ2570+ZZ2570
-+007474 013040 ZZ2570=ZZ2570+ZZ2570
-+007474 026100 ZZ2570=ZZ2570+ZZ2570
-+007474 054200 ZZ2570=ZZ2570+ZZ2570
-+007474 130400 ZZ2570=ZZ2570+ZZ2570
-+007474 261000 ZZ2570=ZZ2570+ZZ2570
-+007474 002216 0 8192 -ZZ1570
-+007475 261000 0 ZZ2570
-- mark 7047, 335 /11 dlph
-+007476 001236 ZZ2571=ZZ2571+ZZ2571
-+007476 002474 ZZ2571=ZZ2571+ZZ2571
-+007476 005170 ZZ2571=ZZ2571+ZZ2571
-+007476 012360 ZZ2571=ZZ2571+ZZ2571
-+007476 024740 ZZ2571=ZZ2571+ZZ2571
-+007476 051700 ZZ2571=ZZ2571+ZZ2571
-+007476 123600 ZZ2571=ZZ2571+ZZ2571
-+007476 247400 ZZ2571=ZZ2571+ZZ2571
-+007476 002171 0 8192 -ZZ1571
-+007477 247400 0 ZZ2571
-- mark 7066, 359 /12 dlph
-+007500 001316 ZZ2572=ZZ2572+ZZ2572
-+007500 002634 ZZ2572=ZZ2572+ZZ2572
-+007500 005470 ZZ2572=ZZ2572+ZZ2572
-+007500 013160 ZZ2572=ZZ2572+ZZ2572
-+007500 026340 ZZ2572=ZZ2572+ZZ2572
-+007500 054700 ZZ2572=ZZ2572+ZZ2572
-+007500 131600 ZZ2572=ZZ2572+ZZ2572
-+007500 263400 ZZ2572=ZZ2572+ZZ2572
-+007500 002146 0 8192 -ZZ1572
-+007501 263400 0 ZZ2572
-- mark 7067, -225 / 2 aqar
-+007502 777074 ZZ2573=ZZ2573+ZZ2573
-+007502 776170 ZZ2573=ZZ2573+ZZ2573
-+007502 774360 ZZ2573=ZZ2573+ZZ2573
-+007502 770740 ZZ2573=ZZ2573+ZZ2573
-+007502 761700 ZZ2573=ZZ2573+ZZ2573
-+007502 743600 ZZ2573=ZZ2573+ZZ2573
-+007502 707400 ZZ2573=ZZ2573+ZZ2573
-+007502 617000 ZZ2573=ZZ2573+ZZ2573
-+007502 002145 0 8192 -ZZ1573
-+007503 617000 0 ZZ2573
-- mark 7068, -123 / 3 aqar
-+007504 777410 ZZ2574=ZZ2574+ZZ2574
-+007504 777020 ZZ2574=ZZ2574+ZZ2574
-+007504 776040 ZZ2574=ZZ2574+ZZ2574
-+007504 774100 ZZ2574=ZZ2574+ZZ2574
-+007504 770200 ZZ2574=ZZ2574+ZZ2574
-+007504 760400 ZZ2574=ZZ2574+ZZ2574
-+007504 741000 ZZ2574=ZZ2574+ZZ2574
-+007504 702000 ZZ2574=ZZ2574+ZZ2574
-+007504 002144 0 8192 -ZZ1574
-+007505 702000 0 ZZ2574
-- mark 7096, -213 / 6 aqar
-+007506 777124 ZZ2575=ZZ2575+ZZ2575
-+007506 776250 ZZ2575=ZZ2575+ZZ2575
-+007506 774520 ZZ2575=ZZ2575+ZZ2575
-+007506 771240 ZZ2575=ZZ2575+ZZ2575
-+007506 762500 ZZ2575=ZZ2575+ZZ2575
-+007506 745200 ZZ2575=ZZ2575+ZZ2575
-+007506 712400 ZZ2575=ZZ2575+ZZ2575
-+007506 625000 ZZ2575=ZZ2575+ZZ2575
-+007506 002110 0 8192 -ZZ1575
-+007507 625000 0 ZZ2575
-- mark 7161, -461 /22 capr
-+007510 776144 ZZ2576=ZZ2576+ZZ2576
-+007510 774310 ZZ2576=ZZ2576+ZZ2576
-+007510 770620 ZZ2576=ZZ2576+ZZ2576
-+007510 761440 ZZ2576=ZZ2576+ZZ2576
-+007510 743100 ZZ2576=ZZ2576+ZZ2576
-+007510 706200 ZZ2576=ZZ2576+ZZ2576
-+007510 614400 ZZ2576=ZZ2576+ZZ2576
-+007510 431000 ZZ2576=ZZ2576+ZZ2576
-+007510 002007 0 8192 -ZZ1576
-+007511 431000 0 ZZ2576
-- mark 7170, -401 /23 capr
-+007512 776334 ZZ2577=ZZ2577+ZZ2577
-+007512 774670 ZZ2577=ZZ2577+ZZ2577
-+007512 771560 ZZ2577=ZZ2577+ZZ2577
-+007512 763340 ZZ2577=ZZ2577+ZZ2577
-+007512 746700 ZZ2577=ZZ2577+ZZ2577
-+007512 715600 ZZ2577=ZZ2577+ZZ2577
-+007512 633400 ZZ2577=ZZ2577+ZZ2577
-+007512 467000 ZZ2577=ZZ2577+ZZ2577
-+007512 001776 0 8192 -ZZ1577
-+007513 467000 0 ZZ2577
-- mark 7192, -268 /13 capr
-+007514 776746 ZZ2578=ZZ2578+ZZ2578
-+007514 775714 ZZ2578=ZZ2578+ZZ2578
-+007514 773630 ZZ2578=ZZ2578+ZZ2578
-+007514 767460 ZZ2578=ZZ2578+ZZ2578
-+007514 757140 ZZ2578=ZZ2578+ZZ2578
-+007514 736300 ZZ2578=ZZ2578+ZZ2578
-+007514 674600 ZZ2578=ZZ2578+ZZ2578
-+007514 571400 ZZ2578=ZZ2578+ZZ2578
-+007514 001750 0 8192 -ZZ1578
-+007515 571400 0 ZZ2578
-- mark 7199, 222 / 5 equl
-+007516 000674 ZZ2579=ZZ2579+ZZ2579
-+007516 001570 ZZ2579=ZZ2579+ZZ2579
-+007516 003360 ZZ2579=ZZ2579+ZZ2579
-+007516 006740 ZZ2579=ZZ2579+ZZ2579
-+007516 015700 ZZ2579=ZZ2579+ZZ2579
-+007516 033600 ZZ2579=ZZ2579+ZZ2579
-+007516 067400 ZZ2579=ZZ2579+ZZ2579
-+007516 157000 ZZ2579=ZZ2579+ZZ2579
-+007516 001741 0 8192 -ZZ1579
-+007517 157000 0 ZZ2579
-- mark 7223, 219 / 7 equl
-+007520 000666 ZZ2580=ZZ2580+ZZ2580
-+007520 001554 ZZ2580=ZZ2580+ZZ2580
-+007520 003330 ZZ2580=ZZ2580+ZZ2580
-+007520 006660 ZZ2580=ZZ2580+ZZ2580
-+007520 015540 ZZ2580=ZZ2580+ZZ2580
-+007520 033300 ZZ2580=ZZ2580+ZZ2580
-+007520 066600 ZZ2580=ZZ2580+ZZ2580
-+007520 155400 ZZ2580=ZZ2580+ZZ2580
-+007520 001711 0 8192 -ZZ1580
-+007521 155400 0 ZZ2580
-- mark 7230, 110 / 8 equl
-+007522 000334 ZZ2581=ZZ2581+ZZ2581
-+007522 000670 ZZ2581=ZZ2581+ZZ2581
-+007522 001560 ZZ2581=ZZ2581+ZZ2581
-+007522 003340 ZZ2581=ZZ2581+ZZ2581
-+007522 006700 ZZ2581=ZZ2581+ZZ2581
-+007522 015600 ZZ2581=ZZ2581+ZZ2581
-+007522 033400 ZZ2581=ZZ2581+ZZ2581
-+007522 067000 ZZ2581=ZZ2581+ZZ2581
-+007522 001702 0 8192 -ZZ1581
-+007523 067000 0 ZZ2581
-- mark 7263, -393 /32 capr
-+007524 776354 ZZ2582=ZZ2582+ZZ2582
-+007524 774730 ZZ2582=ZZ2582+ZZ2582
-+007524 771660 ZZ2582=ZZ2582+ZZ2582
-+007524 763540 ZZ2582=ZZ2582+ZZ2582
-+007524 747300 ZZ2582=ZZ2582+ZZ2582
-+007524 716600 ZZ2582=ZZ2582+ZZ2582
-+007524 635400 ZZ2582=ZZ2582+ZZ2582
-+007524 473000 ZZ2582=ZZ2582+ZZ2582
-+007524 001641 0 8192 -ZZ1582
-+007525 473000 0 ZZ2582
-- mark 7267, 441 / 1 pegs
-+007526 001562 ZZ2583=ZZ2583+ZZ2583
-+007526 003344 ZZ2583=ZZ2583+ZZ2583
-+007526 006710 ZZ2583=ZZ2583+ZZ2583
-+007526 015620 ZZ2583=ZZ2583+ZZ2583
-+007526 033440 ZZ2583=ZZ2583+ZZ2583
-+007526 067100 ZZ2583=ZZ2583+ZZ2583
-+007526 156200 ZZ2583=ZZ2583+ZZ2583
-+007526 334400 ZZ2583=ZZ2583+ZZ2583
-+007526 001635 0 8192 -ZZ1583
-+007527 334400 0 ZZ2583
-- mark 7299, -506 /36 capr
-+007530 776012 ZZ2584=ZZ2584+ZZ2584
-+007530 774024 ZZ2584=ZZ2584+ZZ2584
-+007530 770050 ZZ2584=ZZ2584+ZZ2584
-+007530 760120 ZZ2584=ZZ2584+ZZ2584
-+007530 740240 ZZ2584=ZZ2584+ZZ2584
-+007530 700500 ZZ2584=ZZ2584+ZZ2584
-+007530 601200 ZZ2584=ZZ2584+ZZ2584
-+007530 402400 ZZ2584=ZZ2584+ZZ2584
-+007530 001575 0 8192 -ZZ1584
-+007531 402400 0 ZZ2584
-- mark 7347, -453 /39 capr
-+007532 776164 ZZ2585=ZZ2585+ZZ2585
-+007532 774350 ZZ2585=ZZ2585+ZZ2585
-+007532 770720 ZZ2585=ZZ2585+ZZ2585
-+007532 761640 ZZ2585=ZZ2585+ZZ2585
-+007532 743500 ZZ2585=ZZ2585+ZZ2585
-+007532 707200 ZZ2585=ZZ2585+ZZ2585
-+007532 616400 ZZ2585=ZZ2585+ZZ2585
-+007532 435000 ZZ2585=ZZ2585+ZZ2585
-+007532 001515 0 8192 -ZZ1585
-+007533 435000 0 ZZ2585
-- mark 7353, -189 /23 aqar
-+007534 777204 ZZ2586=ZZ2586+ZZ2586
-+007534 776410 ZZ2586=ZZ2586+ZZ2586
-+007534 775020 ZZ2586=ZZ2586+ZZ2586
-+007534 772040 ZZ2586=ZZ2586+ZZ2586
-+007534 764100 ZZ2586=ZZ2586+ZZ2586
-+007534 750200 ZZ2586=ZZ2586+ZZ2586
-+007534 720400 ZZ2586=ZZ2586+ZZ2586
-+007534 641000 ZZ2586=ZZ2586+ZZ2586
-+007534 001507 0 8192 -ZZ1586
-+007535 641000 0 ZZ2586
-- mark 7365, -390 /40 capr
-+007536 776362 ZZ2587=ZZ2587+ZZ2587
-+007536 774744 ZZ2587=ZZ2587+ZZ2587
-+007536 771710 ZZ2587=ZZ2587+ZZ2587
-+007536 763620 ZZ2587=ZZ2587+ZZ2587
-+007536 747440 ZZ2587=ZZ2587+ZZ2587
-+007536 717100 ZZ2587=ZZ2587+ZZ2587
-+007536 636200 ZZ2587=ZZ2587+ZZ2587
-+007536 474400 ZZ2587=ZZ2587+ZZ2587
-+007536 001473 0 8192 -ZZ1587
-+007537 474400 0 ZZ2587
-- mark 7379, -440 /43 capr
-+007540 776216 ZZ2588=ZZ2588+ZZ2588
-+007540 774434 ZZ2588=ZZ2588+ZZ2588
-+007540 771070 ZZ2588=ZZ2588+ZZ2588
-+007540 762160 ZZ2588=ZZ2588+ZZ2588
-+007540 744340 ZZ2588=ZZ2588+ZZ2588
-+007540 710700 ZZ2588=ZZ2588+ZZ2588
-+007540 621600 ZZ2588=ZZ2588+ZZ2588
-+007540 443400 ZZ2588=ZZ2588+ZZ2588
-+007540 001455 0 8192 -ZZ1588
-+007541 443400 0 ZZ2588
-- mark 7394, 384 / 9 pegs
-+007542 001400 ZZ2589=ZZ2589+ZZ2589
-+007542 003000 ZZ2589=ZZ2589+ZZ2589
-+007542 006000 ZZ2589=ZZ2589+ZZ2589
-+007542 014000 ZZ2589=ZZ2589+ZZ2589
-+007542 030000 ZZ2589=ZZ2589+ZZ2589
-+007542 060000 ZZ2589=ZZ2589+ZZ2589
-+007542 140000 ZZ2589=ZZ2589+ZZ2589
-+007542 300000 ZZ2589=ZZ2589+ZZ2589
-+007542 001436 0 8192 -ZZ1589
-+007543 300000 0 ZZ2589
-- mark 7499, -60 /31 aquar
-+007544 777606 ZZ2590=ZZ2590+ZZ2590
-+007544 777414 ZZ2590=ZZ2590+ZZ2590
-+007544 777030 ZZ2590=ZZ2590+ZZ2590
-+007544 776060 ZZ2590=ZZ2590+ZZ2590
-+007544 774140 ZZ2590=ZZ2590+ZZ2590
-+007544 770300 ZZ2590=ZZ2590+ZZ2590
-+007544 760600 ZZ2590=ZZ2590+ZZ2590
-+007544 741400 ZZ2590=ZZ2590+ZZ2590
-+007544 001265 0 8192 -ZZ1590
-+007545 741400 0 ZZ2590
-- mark 7513, 104 /22 pegs
-+007546 000320 ZZ2591=ZZ2591+ZZ2591
-+007546 000640 ZZ2591=ZZ2591+ZZ2591
-+007546 001500 ZZ2591=ZZ2591+ZZ2591
-+007546 003200 ZZ2591=ZZ2591+ZZ2591
-+007546 006400 ZZ2591=ZZ2591+ZZ2591
-+007546 015000 ZZ2591=ZZ2591+ZZ2591
-+007546 032000 ZZ2591=ZZ2591+ZZ2591
-+007546 064000 ZZ2591=ZZ2591+ZZ2591
-+007546 001247 0 8192 -ZZ1591
-+007547 064000 0 ZZ2591
-- mark 7515, -327 /33 aqar
-+007550 776560 ZZ2592=ZZ2592+ZZ2592
-+007550 775340 ZZ2592=ZZ2592+ZZ2592
-+007550 772700 ZZ2592=ZZ2592+ZZ2592
-+007550 765600 ZZ2592=ZZ2592+ZZ2592
-+007550 753400 ZZ2592=ZZ2592+ZZ2592
-+007550 727000 ZZ2592=ZZ2592+ZZ2592
-+007550 656000 ZZ2592=ZZ2592+ZZ2592
-+007550 534000 ZZ2592=ZZ2592+ZZ2592
-+007550 001245 0 8192 -ZZ1592
-+007551 534000 0 ZZ2592
-- mark 7575, -189 /43 aqar
-+007552 777204 ZZ2593=ZZ2593+ZZ2593
-+007552 776410 ZZ2593=ZZ2593+ZZ2593
-+007552 775020 ZZ2593=ZZ2593+ZZ2593
-+007552 772040 ZZ2593=ZZ2593+ZZ2593
-+007552 764100 ZZ2593=ZZ2593+ZZ2593
-+007552 750200 ZZ2593=ZZ2593+ZZ2593
-+007552 720400 ZZ2593=ZZ2593+ZZ2593
-+007552 641000 ZZ2593=ZZ2593+ZZ2593
-+007552 001151 0 8192 -ZZ1593
-+007553 641000 0 ZZ2593
-- mark 7603, -43 /48 aqar
-+007554 777650 ZZ2594=ZZ2594+ZZ2594
-+007554 777520 ZZ2594=ZZ2594+ZZ2594
-+007554 777240 ZZ2594=ZZ2594+ZZ2594
-+007554 776500 ZZ2594=ZZ2594+ZZ2594
-+007554 775200 ZZ2594=ZZ2594+ZZ2594
-+007554 772400 ZZ2594=ZZ2594+ZZ2594
-+007554 765000 ZZ2594=ZZ2594+ZZ2594
-+007554 752000 ZZ2594=ZZ2594+ZZ2594
-+007554 001115 0 8192 -ZZ1594
-+007555 752000 0 ZZ2594
-- mark 7604, 266 /31 pegs
-+007556 001024 ZZ2595=ZZ2595+ZZ2595
-+007556 002050 ZZ2595=ZZ2595+ZZ2595
-+007556 004120 ZZ2595=ZZ2595+ZZ2595
-+007556 010240 ZZ2595=ZZ2595+ZZ2595
-+007556 020500 ZZ2595=ZZ2595+ZZ2595
-+007556 041200 ZZ2595=ZZ2595+ZZ2595
-+007556 102400 ZZ2595=ZZ2595+ZZ2595
-+007556 205000 ZZ2595=ZZ2595+ZZ2595
-+007556 001114 0 8192 -ZZ1595
-+007557 205000 0 ZZ2595
-- mark 7624, 20 /52 aquar
-+007560 000050 ZZ2596=ZZ2596+ZZ2596
-+007560 000120 ZZ2596=ZZ2596+ZZ2596
-+007560 000240 ZZ2596=ZZ2596+ZZ2596
-+007560 000500 ZZ2596=ZZ2596+ZZ2596
-+007560 001200 ZZ2596=ZZ2596+ZZ2596
-+007560 002400 ZZ2596=ZZ2596+ZZ2596
-+007560 005000 ZZ2596=ZZ2596+ZZ2596
-+007560 012000 ZZ2596=ZZ2596+ZZ2596
-+007560 001070 0 8192 -ZZ1596
-+007561 012000 0 ZZ2596
-- mark 7639, 96 /35 pegs
-+007562 000300 ZZ2597=ZZ2597+ZZ2597
-+007562 000600 ZZ2597=ZZ2597+ZZ2597
-+007562 001400 ZZ2597=ZZ2597+ZZ2597
-+007562 003000 ZZ2597=ZZ2597+ZZ2597
-+007562 006000 ZZ2597=ZZ2597+ZZ2597
-+007562 014000 ZZ2597=ZZ2597+ZZ2597
-+007562 030000 ZZ2597=ZZ2597+ZZ2597
-+007562 060000 ZZ2597=ZZ2597+ZZ2597
-+007562 001051 0 8192 -ZZ1597
-+007563 060000 0 ZZ2597
-- mark 7654, -255 /57 aqar
-+007564 777000 ZZ2598=ZZ2598+ZZ2598
-+007564 776000 ZZ2598=ZZ2598+ZZ2598
-+007564 774000 ZZ2598=ZZ2598+ZZ2598
-+007564 770000 ZZ2598=ZZ2598+ZZ2598
-+007564 760000 ZZ2598=ZZ2598+ZZ2598
-+007564 740000 ZZ2598=ZZ2598+ZZ2598
-+007564 700000 ZZ2598=ZZ2598+ZZ2598
-+007564 600000 ZZ2598=ZZ2598+ZZ2598
-+007564 001032 0 8192 -ZZ1598
-+007565 600000 0 ZZ2598
-- mark 7681, -14 /62 aqar
-+007566 777742 ZZ2599=ZZ2599+ZZ2599
-+007566 777704 ZZ2599=ZZ2599+ZZ2599
-+007566 777610 ZZ2599=ZZ2599+ZZ2599
-+007566 777420 ZZ2599=ZZ2599+ZZ2599
-+007566 777040 ZZ2599=ZZ2599+ZZ2599
-+007566 776100 ZZ2599=ZZ2599+ZZ2599
-+007566 774200 ZZ2599=ZZ2599+ZZ2599
-+007566 770400 ZZ2599=ZZ2599+ZZ2599
-+007566 000777 0 8192 -ZZ1599
-+007567 770400 0 ZZ2599
-- mark 7727, -440 /66 aqar
-+007570 776216 ZZ2600=ZZ2600+ZZ2600
-+007570 774434 ZZ2600=ZZ2600+ZZ2600
-+007570 771070 ZZ2600=ZZ2600+ZZ2600
-+007570 762160 ZZ2600=ZZ2600+ZZ2600
-+007570 744340 ZZ2600=ZZ2600+ZZ2600
-+007570 710700 ZZ2600=ZZ2600+ZZ2600
-+007570 621600 ZZ2600=ZZ2600+ZZ2600
-+007570 443400 ZZ2600=ZZ2600+ZZ2600
-+007570 000721 0 8192 -ZZ1600
-+007571 443400 0 ZZ2600
-- mark 7747, 266 /46 pegs
-+007572 001024 ZZ2601=ZZ2601+ZZ2601
-+007572 002050 ZZ2601=ZZ2601+ZZ2601
-+007572 004120 ZZ2601=ZZ2601+ZZ2601
-+007572 010240 ZZ2601=ZZ2601+ZZ2601
-+007572 020500 ZZ2601=ZZ2601+ZZ2601
-+007572 041200 ZZ2601=ZZ2601+ZZ2601
-+007572 102400 ZZ2601=ZZ2601+ZZ2601
-+007572 205000 ZZ2601=ZZ2601+ZZ2601
-+007572 000675 0 8192 -ZZ1601
-+007573 205000 0 ZZ2601
-- mark 7761, -321 /71 aqar
-+007574 776574 ZZ2602=ZZ2602+ZZ2602
-+007574 775370 ZZ2602=ZZ2602+ZZ2602
-+007574 772760 ZZ2602=ZZ2602+ZZ2602
-+007574 765740 ZZ2602=ZZ2602+ZZ2602
-+007574 753700 ZZ2602=ZZ2602+ZZ2602
-+007574 727600 ZZ2602=ZZ2602+ZZ2602
-+007574 657400 ZZ2602=ZZ2602+ZZ2602
-+007574 537000 ZZ2602=ZZ2602+ZZ2602
-+007574 000657 0 8192 -ZZ1602
-+007575 537000 0 ZZ2602
-- mark 7779, -185 /73 aqar
-+007576 777214 ZZ2603=ZZ2603+ZZ2603
-+007576 776430 ZZ2603=ZZ2603+ZZ2603
-+007576 775060 ZZ2603=ZZ2603+ZZ2603
-+007576 772140 ZZ2603=ZZ2603+ZZ2603
-+007576 764300 ZZ2603=ZZ2603+ZZ2603
-+007576 750600 ZZ2603=ZZ2603+ZZ2603
-+007576 721400 ZZ2603=ZZ2603+ZZ2603
-+007576 643000 ZZ2603=ZZ2603+ZZ2603
-+007576 000635 0 8192 -ZZ1603
-+007577 643000 0 ZZ2603
-- mark 7795, 189 /50 pegs
-+007600 000572 ZZ2604=ZZ2604+ZZ2604
-+007600 001364 ZZ2604=ZZ2604+ZZ2604
-+007600 002750 ZZ2604=ZZ2604+ZZ2604
-+007600 005720 ZZ2604=ZZ2604+ZZ2604
-+007600 013640 ZZ2604=ZZ2604+ZZ2604
-+007600 027500 ZZ2604=ZZ2604+ZZ2604
-+007600 057200 ZZ2604=ZZ2604+ZZ2604
-+007600 136400 ZZ2604=ZZ2604+ZZ2604
-+007600 000615 0 8192 -ZZ1604
-+007601 136400 0 ZZ2604
-- mark 7844, 75 / 4 pisc
-+007602 000226 ZZ2605=ZZ2605+ZZ2605
-+007602 000454 ZZ2605=ZZ2605+ZZ2605
-+007602 001130 ZZ2605=ZZ2605+ZZ2605
-+007602 002260 ZZ2605=ZZ2605+ZZ2605
-+007602 004540 ZZ2605=ZZ2605+ZZ2605
-+007602 011300 ZZ2605=ZZ2605+ZZ2605
-+007602 022600 ZZ2605=ZZ2605+ZZ2605
-+007602 045400 ZZ2605=ZZ2605+ZZ2605
-+007602 000534 0 8192 -ZZ1605
-+007603 045400 0 ZZ2605
-- mark 7862, 202 /55 pegs
-+007604 000624 ZZ2606=ZZ2606+ZZ2606
-+007604 001450 ZZ2606=ZZ2606+ZZ2606
-+007604 003120 ZZ2606=ZZ2606+ZZ2606
-+007604 006240 ZZ2606=ZZ2606+ZZ2606
-+007604 014500 ZZ2606=ZZ2606+ZZ2606
-+007604 031200 ZZ2606=ZZ2606+ZZ2606
-+007604 062400 ZZ2606=ZZ2606+ZZ2606
-+007604 145000 ZZ2606=ZZ2606+ZZ2606
-+007604 000512 0 8192 -ZZ1606
-+007605 145000 0 ZZ2606
-- mark 7874, -494 /88 aqar
-+007606 776042 ZZ2607=ZZ2607+ZZ2607
-+007606 774104 ZZ2607=ZZ2607+ZZ2607
-+007606 770210 ZZ2607=ZZ2607+ZZ2607
-+007606 760420 ZZ2607=ZZ2607+ZZ2607
-+007606 741040 ZZ2607=ZZ2607+ZZ2607
-+007606 702100 ZZ2607=ZZ2607+ZZ2607
-+007606 604200 ZZ2607=ZZ2607+ZZ2607
-+007606 410400 ZZ2607=ZZ2607+ZZ2607
-+007606 000476 0 8192 -ZZ1607
-+007607 410400 0 ZZ2607
-- mark 7903, -150 /90 aqar
-+007610 777322 ZZ2608=ZZ2608+ZZ2608
-+007610 776644 ZZ2608=ZZ2608+ZZ2608
-+007610 775510 ZZ2608=ZZ2608+ZZ2608
-+007610 773220 ZZ2608=ZZ2608+ZZ2608
-+007610 766440 ZZ2608=ZZ2608+ZZ2608
-+007610 755100 ZZ2608=ZZ2608+ZZ2608
-+007610 732200 ZZ2608=ZZ2608+ZZ2608
-+007610 664400 ZZ2608=ZZ2608+ZZ2608
-+007610 000441 0 8192 -ZZ1608
-+007611 664400 0 ZZ2608
-- mark 7911, -219 /91 aqar
-+007612 777110 ZZ2609=ZZ2609+ZZ2609
-+007612 776220 ZZ2609=ZZ2609+ZZ2609
-+007612 774440 ZZ2609=ZZ2609+ZZ2609
-+007612 771100 ZZ2609=ZZ2609+ZZ2609
-+007612 762200 ZZ2609=ZZ2609+ZZ2609
-+007612 744400 ZZ2609=ZZ2609+ZZ2609
-+007612 711000 ZZ2609=ZZ2609+ZZ2609
-+007612 622000 ZZ2609=ZZ2609+ZZ2609
-+007612 000431 0 8192 -ZZ1609
-+007613 622000 0 ZZ2609
-- mark 7919, 62 / 6 pisc
-+007614 000174 ZZ2610=ZZ2610+ZZ2610
-+007614 000370 ZZ2610=ZZ2610+ZZ2610
-+007614 000760 ZZ2610=ZZ2610+ZZ2610
-+007614 001740 ZZ2610=ZZ2610+ZZ2610
-+007614 003700 ZZ2610=ZZ2610+ZZ2610
-+007614 007600 ZZ2610=ZZ2610+ZZ2610
-+007614 017400 ZZ2610=ZZ2610+ZZ2610
-+007614 037000 ZZ2610=ZZ2610+ZZ2610
-+007614 000421 0 8192 -ZZ1610
-+007615 037000 0 ZZ2610
-- mark 7923, -222 /93 aqar
-+007616 777102 ZZ2611=ZZ2611+ZZ2611
-+007616 776204 ZZ2611=ZZ2611+ZZ2611
-+007616 774410 ZZ2611=ZZ2611+ZZ2611
-+007616 771020 ZZ2611=ZZ2611+ZZ2611
-+007616 762040 ZZ2611=ZZ2611+ZZ2611
-+007616 744100 ZZ2611=ZZ2611+ZZ2611
-+007616 710200 ZZ2611=ZZ2611+ZZ2611
-+007616 620400 ZZ2611=ZZ2611+ZZ2611
-+007616 000415 0 8192 -ZZ1611
-+007617 620400 0 ZZ2611
-- mark 7952, -470 /98 aqar
-+007620 776122 ZZ2612=ZZ2612+ZZ2612
-+007620 774244 ZZ2612=ZZ2612+ZZ2612
-+007620 770510 ZZ2612=ZZ2612+ZZ2612
-+007620 761220 ZZ2612=ZZ2612+ZZ2612
-+007620 742440 ZZ2612=ZZ2612+ZZ2612
-+007620 705100 ZZ2612=ZZ2612+ZZ2612
-+007620 612200 ZZ2612=ZZ2612+ZZ2612
-+007620 424400 ZZ2612=ZZ2612+ZZ2612
-+007620 000360 0 8192 -ZZ1612
-+007621 424400 0 ZZ2612
-- mark 7969, -482 /99 aqar
-+007622 776072 ZZ2613=ZZ2613+ZZ2613
-+007622 774164 ZZ2613=ZZ2613+ZZ2613
-+007622 770350 ZZ2613=ZZ2613+ZZ2613
-+007622 760720 ZZ2613=ZZ2613+ZZ2613
-+007622 741640 ZZ2613=ZZ2613+ZZ2613
-+007622 703500 ZZ2613=ZZ2613+ZZ2613
-+007622 607200 ZZ2613=ZZ2613+ZZ2613
-+007622 416400 ZZ2613=ZZ2613+ZZ2613
-+007622 000337 0 8192 -ZZ1613
-+007623 416400 0 ZZ2613
-- mark 7975, 16 / 8 pisc
-+007624 000040 ZZ2614=ZZ2614+ZZ2614
-+007624 000100 ZZ2614=ZZ2614+ZZ2614
-+007624 000200 ZZ2614=ZZ2614+ZZ2614
-+007624 000400 ZZ2614=ZZ2614+ZZ2614
-+007624 001000 ZZ2614=ZZ2614+ZZ2614
-+007624 002000 ZZ2614=ZZ2614+ZZ2614
-+007624 004000 ZZ2614=ZZ2614+ZZ2614
-+007624 010000 ZZ2614=ZZ2614+ZZ2614
-+007624 000331 0 8192 -ZZ1614
-+007625 010000 0 ZZ2614
-- mark 7981, 133 /10 pisc
-+007626 000412 ZZ2615=ZZ2615+ZZ2615
-+007626 001024 ZZ2615=ZZ2615+ZZ2615
-+007626 002050 ZZ2615=ZZ2615+ZZ2615
-+007626 004120 ZZ2615=ZZ2615+ZZ2615
-+007626 010240 ZZ2615=ZZ2615+ZZ2615
-+007626 020500 ZZ2615=ZZ2615+ZZ2615
-+007626 041200 ZZ2615=ZZ2615+ZZ2615
-+007626 102400 ZZ2615=ZZ2615+ZZ2615
-+007626 000323 0 8192 -ZZ1615
-+007627 102400 0 ZZ2615
-- mark 7988, 278 /70 pegs
-+007630 001054 ZZ2616=ZZ2616+ZZ2616
-+007630 002130 ZZ2616=ZZ2616+ZZ2616
-+007630 004260 ZZ2616=ZZ2616+ZZ2616
-+007630 010540 ZZ2616=ZZ2616+ZZ2616
-+007630 021300 ZZ2616=ZZ2616+ZZ2616
-+007630 042600 ZZ2616=ZZ2616+ZZ2616
-+007630 105400 ZZ2616=ZZ2616+ZZ2616
-+007630 213000 ZZ2616=ZZ2616+ZZ2616
-+007630 000314 0 8192 -ZZ1616
-+007631 213000 0 ZZ2616
-- mark 8010, -489 /101 aqar
-+007632 776054 ZZ2617=ZZ2617+ZZ2617
-+007632 774130 ZZ2617=ZZ2617+ZZ2617
-+007632 770260 ZZ2617=ZZ2617+ZZ2617
-+007632 760540 ZZ2617=ZZ2617+ZZ2617
-+007632 741300 ZZ2617=ZZ2617+ZZ2617
-+007632 702600 ZZ2617=ZZ2617+ZZ2617
-+007632 605400 ZZ2617=ZZ2617+ZZ2617
-+007632 413000 ZZ2617=ZZ2617+ZZ2617
-+007632 000266 0 8192 -ZZ1617
-+007633 413000 0 ZZ2617
-- mark 8049, 116 /17 pisc
-+007634 000350 ZZ2618=ZZ2618+ZZ2618
-+007634 000720 ZZ2618=ZZ2618+ZZ2618
-+007634 001640 ZZ2618=ZZ2618+ZZ2618
-+007634 003500 ZZ2618=ZZ2618+ZZ2618
-+007634 007200 ZZ2618=ZZ2618+ZZ2618
-+007634 016400 ZZ2618=ZZ2618+ZZ2618
-+007634 035000 ZZ2618=ZZ2618+ZZ2618
-+007634 072000 ZZ2618=ZZ2618+ZZ2618
-+007634 000217 0 8192 -ZZ1618
-+007635 072000 0 ZZ2618
-- mark 8059, -418 /104 aqar
-+007636 776272 ZZ2619=ZZ2619+ZZ2619
-+007636 774564 ZZ2619=ZZ2619+ZZ2619
-+007636 771350 ZZ2619=ZZ2619+ZZ2619
-+007636 762720 ZZ2619=ZZ2619+ZZ2619
-+007636 745640 ZZ2619=ZZ2619+ZZ2619
-+007636 713500 ZZ2619=ZZ2619+ZZ2619
-+007636 627200 ZZ2619=ZZ2619+ZZ2619
-+007636 456400 ZZ2619=ZZ2619+ZZ2619
-+007636 000205 0 8192 -ZZ1619
-+007637 456400 0 ZZ2619
-- mark 8061, 28 /18 pisc
-+007640 000070 ZZ2620=ZZ2620+ZZ2620
-+007640 000160 ZZ2620=ZZ2620+ZZ2620
-+007640 000340 ZZ2620=ZZ2620+ZZ2620
-+007640 000700 ZZ2620=ZZ2620+ZZ2620
-+007640 001600 ZZ2620=ZZ2620+ZZ2620
-+007640 003400 ZZ2620=ZZ2620+ZZ2620
-+007640 007000 ZZ2620=ZZ2620+ZZ2620
-+007640 016000 ZZ2620=ZZ2620+ZZ2620
-+007640 000203 0 8192 -ZZ1620
-+007641 016000 0 ZZ2620
-- mark 8064, -344 /105 aqar
-+007642 776516 ZZ2621=ZZ2621+ZZ2621
-+007642 775234 ZZ2621=ZZ2621+ZZ2621
-+007642 772470 ZZ2621=ZZ2621+ZZ2621
-+007642 765160 ZZ2621=ZZ2621+ZZ2621
-+007642 752340 ZZ2621=ZZ2621+ZZ2621
-+007642 724700 ZZ2621=ZZ2621+ZZ2621
-+007642 651600 ZZ2621=ZZ2621+ZZ2621
-+007642 523400 ZZ2621=ZZ2621+ZZ2621
-+007642 000200 0 8192 -ZZ1621
-+007643 523400 0 ZZ2621
-- mark 8159, 144 /28 pisc
-+007644 000440 ZZ2622=ZZ2622+ZZ2622
-+007644 001100 ZZ2622=ZZ2622+ZZ2622
-+007644 002200 ZZ2622=ZZ2622+ZZ2622
-+007644 004400 ZZ2622=ZZ2622+ZZ2622
-+007644 011000 ZZ2622=ZZ2622+ZZ2622
-+007644 022000 ZZ2622=ZZ2622+ZZ2622
-+007644 044000 ZZ2622=ZZ2622+ZZ2622
-+007644 110000 ZZ2622=ZZ2622+ZZ2622
-+007644 000041 0 8192 -ZZ1622
-+007645 110000 0 ZZ2622
-- mark 8174, -149 /30 pisc
-+007646 777324 ZZ2623=ZZ2623+ZZ2623
-+007646 776650 ZZ2623=ZZ2623+ZZ2623
-+007646 775520 ZZ2623=ZZ2623+ZZ2623
-+007646 773240 ZZ2623=ZZ2623+ZZ2623
-+007646 766500 ZZ2623=ZZ2623+ZZ2623
-+007646 755200 ZZ2623=ZZ2623+ZZ2623
-+007646 732400 ZZ2623=ZZ2623+ZZ2623
-+007646 665000 ZZ2623=ZZ2623+ZZ2623
-+007646 000022 0 8192 -ZZ1623
-+007647 665000 0 ZZ2623
- 007650 4q,
-- mark 8188, -407 / 2 ceti
-+007650 776320 ZZ2624=ZZ2624+ZZ2624
-+007650 774640 ZZ2624=ZZ2624+ZZ2624
-+007650 771500 ZZ2624=ZZ2624+ZZ2624
-+007650 763200 ZZ2624=ZZ2624+ZZ2624
-+007650 746400 ZZ2624=ZZ2624+ZZ2624
-+007650 715000 ZZ2624=ZZ2624+ZZ2624
-+007650 632000 ZZ2624=ZZ2624+ZZ2624
-+007650 464000 ZZ2624=ZZ2624+ZZ2624
-+007650 000004 0 8192 -ZZ1624
-+007651 464000 0 ZZ2624
- 007652 start 4
-`
diff --git a/src/pkg/exp/spacewar/pdp1.go b/src/pkg/exp/spacewar/pdp1.go
deleted file mode 100644
index e3abd6807..000000000
--- a/src/pkg/exp/spacewar/pdp1.go
+++ /dev/null
@@ -1,389 +0,0 @@
-// Copyright (c) 1996 Barry Silverman, Brian Silverman, Vadim Gerasimov.
-// Portions Copyright (c) 2009 The Go Authors.
-//
-// 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.
-
-// This package and spacewar.go implement a simple PDP-1 emulator
-// complete enough to run the original PDP-1 video game Spacewar!
-// See ../../nacl/README for details on running them.
-//
-// They are a translation of the Java emulator pdp1.java in
-// http://spacewar.oversigma.com/sources/sources.zip.
-//
-// See also the PDP-1 handbook at http://www.dbit.com/~greeng3/pdp1/pdp1.html
-//
-// http://spacewar.oversigma.com/readme.html reads:
-//
-// Spacewar! was conceived in 1961 by Martin Graetz, Stephen Russell,
-// and Wayne Wiitanen. It was first realized on the PDP-1 in 1962 by
-// Stephen Russell, Peter Samson, Dan Edwards, and Martin Graetz,
-// together with Alan Kotok, Steve Piner, and Robert A Saunders.
-// Spacewar! is in the public domain, but this credit paragraph must
-// accompany all distributed versions of the program.
-//
-// This is the original version! Martin Graetz provided us with a
-// printed version of the source. We typed in in again - it was about
-// 40 pages long - and re-assembled it with a PDP-1 assembler written
-// in PERL. The resulting binary runs on a PDP-1 emulator written as
-// a Java applet. The code is extremely faithful to the original. There
-// are only two changes. 1)The spaceships have been made bigger and
-// 2) The overall timing has been special cased to deal with varying
-// machine speeds.
-//
-// The "a", "s", "d", "f" keys control one of the spaceships. The "k",
-// "l", ";", "'" keys control the other. The controls are spin one
-// way, spin the other, thrust, and fire.
-//
-// Barry Silverman
-// Brian Silverman
-// Vadim Gerasimov
-//
-package pdp1
-
-import (
- "bufio"
- "fmt"
- "os"
- "io"
-)
-
-type Word uint32
-
-const mask = 0777777
-const sign = 0400000
-
-const (
- _ = iota // 00
- opAND
- opIOR
- opXOR
- opXCT
- _
- _
- opCALJDA
-
- opLAC // 10
- opLIO
- opDAC
- opDAP
- _
- opDIO
- opDZM
- _
-
- opADD // 20
- opSUB
- opIDX
- opISP
- opSAD
- opSAS
- opMUS
- opDIS
-
- opJMP // 30
- opJSP
- opSKP
- opSFT
- opLAW
- opIOT
- _
- opOPR
-)
-
-// A Trapper represents an object with a Trap method.
-// The machine calls the Trap method to implement the
-// PDP-1 IOT instruction.
-type Trapper interface {
- Trap(y Word)
-}
-
-// An M represents the machine state of a PDP-1.
-// Clients can set Display to install an output device.
-type M struct {
- AC, IO, PC, OV Word
- Mem [010000]Word
- Flag [7]bool
- Sense [7]bool
- Halt bool
-}
-
-
-// Step runs a single machine instruction.
-func (m *M) Step(t Trapper) os.Error {
- inst := m.Mem[m.PC]
- m.PC++
- return m.run(inst, t)
-}
-
-// Normalize actual 32-bit integer i to 18-bit ones-complement integer.
-// Interpret mod 0777777, because 0777777 == -0 == +0 == 0000000.
-func norm(i Word) Word {
- i += i >> 18
- i &= mask
- if i == mask {
- i = 0
- }
- return i
-}
-
-type UnknownInstrError struct {
- Inst Word
- PC Word
-}
-
-func (e UnknownInstrError) String() string {
- return fmt.Sprintf("unknown instruction %06o at %06o", e.Inst, e.PC)
-}
-
-type HaltError Word
-
-func (e HaltError) String() string {
- return fmt.Sprintf("executed HLT instruction at %06o", e)
-}
-
-type LoopError Word
-
-func (e LoopError) String() string { return fmt.Sprintf("indirect load looping at %06o", e) }
-
-func (m *M) run(inst Word, t Trapper) os.Error {
- ib, y := (inst>>12)&1, inst&07777
- op := inst >> 13
- if op < opSKP && op != opCALJDA {
- for n := 0; ib != 0; n++ {
- if n > 07777 {
- return LoopError(m.PC - 1)
- }
- ib = (m.Mem[y] >> 12) & 1
- y = m.Mem[y] & 07777
- }
- }
-
- switch op {
- case opAND:
- m.AC &= m.Mem[y]
- case opIOR:
- m.AC |= m.Mem[y]
- case opXOR:
- m.AC ^= m.Mem[y]
- case opXCT:
- m.run(m.Mem[y], t)
- case opCALJDA:
- a := y
- if ib == 0 {
- a = 64
- }
- m.Mem[a] = m.AC
- m.AC = (m.OV << 17) + m.PC
- m.PC = a + 1
- case opLAC:
- m.AC = m.Mem[y]
- case opLIO:
- m.IO = m.Mem[y]
- case opDAC:
- m.Mem[y] = m.AC
- case opDAP:
- m.Mem[y] = m.Mem[y]&0770000 | m.AC&07777
- case opDIO:
- m.Mem[y] = m.IO
- case opDZM:
- m.Mem[y] = 0
- case opADD:
- m.AC += m.Mem[y]
- m.OV = m.AC >> 18
- m.AC = norm(m.AC)
- case opSUB:
- diffSigns := (m.AC^m.Mem[y])>>17 == 1
- m.AC += m.Mem[y] ^ mask
- m.AC = norm(m.AC)
- if diffSigns && m.Mem[y]>>17 == m.AC>>17 {
- m.OV = 1
- }
- case opIDX:
- m.AC = norm(m.Mem[y] + 1)
- m.Mem[y] = m.AC
- case opISP:
- m.AC = norm(m.Mem[y] + 1)
- m.Mem[y] = m.AC
- if m.AC&sign == 0 {
- m.PC++
- }
- case opSAD:
- if m.AC != m.Mem[y] {
- m.PC++
- }
- case opSAS:
- if m.AC == m.Mem[y] {
- m.PC++
- }
- case opMUS:
- if m.IO&1 == 1 {
- m.AC += m.Mem[y]
- m.AC = norm(m.AC)
- }
- m.IO = (m.IO>>1 | m.AC<<17) & mask
- m.AC >>= 1
- case opDIS:
- m.AC, m.IO = (m.AC<<1|m.IO>>17)&mask,
- ((m.IO<<1|m.AC>>17)&mask)^1
- if m.IO&1 == 1 {
- m.AC = m.AC + (m.Mem[y] ^ mask)
- } else {
- m.AC = m.AC + 1 + m.Mem[y]
- }
- m.AC = norm(m.AC)
- case opJMP:
- m.PC = y
- case opJSP:
- m.AC = (m.OV << 17) + m.PC
- m.PC = y
- case opSKP:
- cond := y&0100 == 0100 && m.AC == 0 ||
- y&0200 == 0200 && m.AC>>17 == 0 ||
- y&0400 == 0400 && m.AC>>17 == 1 ||
- y&01000 == 01000 && m.OV == 0 ||
- y&02000 == 02000 && m.IO>>17 == 0 ||
- y&7 != 0 && !m.Flag[y&7] ||
- y&070 != 0 && !m.Sense[(y&070)>>3] ||
- y&070 == 010
- if (ib == 0) == cond {
- m.PC++
- }
- if y&01000 == 01000 {
- m.OV = 0
- }
- case opSFT:
- for count := inst & 0777; count != 0; count >>= 1 {
- if count&1 == 0 {
- continue
- }
- switch (inst >> 9) & 017 {
- case 001: // rotate AC left
- m.AC = (m.AC<<1 | m.AC>>17) & mask
- case 002: // rotate IO left
- m.IO = (m.IO<<1 | m.IO>>17) & mask
- case 003: // rotate AC and IO left.
- w := uint64(m.AC)<<18 | uint64(m.IO)
- w = w<<1 | w>>35
- m.AC = Word(w>>18) & mask
- m.IO = Word(w) & mask
- case 005: // shift AC left (excluding sign bit)
- m.AC = (m.AC<<1|m.AC>>17)&mask&^sign | m.AC&sign
- case 006: // shift IO left (excluding sign bit)
- m.IO = (m.IO<<1|m.IO>>17)&mask&^sign | m.IO&sign
- case 007: // shift AC and IO left (excluding AC's sign bit)
- w := uint64(m.AC)<<18 | uint64(m.IO)
- w = w<<1 | w>>35
- m.AC = Word(w>>18)&mask&^sign | m.AC&sign
- m.IO = Word(w)&mask&^sign | m.AC&sign
- case 011: // rotate AC right
- m.AC = (m.AC>>1 | m.AC<<17) & mask
- case 012: // rotate IO right
- m.IO = (m.IO>>1 | m.IO<<17) & mask
- case 013: // rotate AC and IO right
- w := uint64(m.AC)<<18 | uint64(m.IO)
- w = w>>1 | w<<35
- m.AC = Word(w>>18) & mask
- m.IO = Word(w) & mask
- case 015: // shift AC right (excluding sign bit)
- m.AC = m.AC>>1 | m.AC&sign
- case 016: // shift IO right (excluding sign bit)
- m.IO = m.IO>>1 | m.IO&sign
- case 017: // shift AC and IO right (excluding AC's sign bit)
- w := uint64(m.AC)<<18 | uint64(m.IO)
- w = w >> 1
- m.AC = Word(w>>18) | m.AC&sign
- m.IO = Word(w) & mask
- default:
- goto Unknown
- }
- }
- case opLAW:
- if ib == 0 {
- m.AC = y
- } else {
- m.AC = y ^ mask
- }
- case opIOT:
- t.Trap(y)
- case opOPR:
- if y&0200 == 0200 {
- m.AC = 0
- }
- if y&04000 == 04000 {
- m.IO = 0
- }
- if y&01000 == 01000 {
- m.AC ^= mask
- }
- if y&0400 == 0400 {
- m.PC--
- return HaltError(m.PC)
- }
- switch i, f := y&7, y&010 == 010; {
- case i == 7:
- for i := 2; i < 7; i++ {
- m.Flag[i] = f
- }
- case i >= 2:
- m.Flag[i] = f
- }
- default:
- Unknown:
- return UnknownInstrError{inst, m.PC - 1}
- }
- return nil
-}
-
-// Load loads the machine's memory from a text input file
-// listing octal address-value pairs, one per line, matching the
-// regular expression ^[ +]([0-7]+)\t([0-7]+).
-func (m *M) Load(r io.Reader) os.Error {
- b := bufio.NewReader(r)
- for {
- line, err := b.ReadString('\n')
- if err != nil {
- if err != os.EOF {
- return err
- }
- break
- }
- // look for ^[ +]([0-9]+)\t([0-9]+)
- if line[0] != ' ' && line[0] != '+' {
- continue
- }
- i := 1
- a := Word(0)
- for ; i < len(line) && '0' <= line[i] && line[i] <= '7'; i++ {
- a = a*8 + Word(line[i]-'0')
- }
- if i >= len(line) || line[i] != '\t' || i == 1 {
- continue
- }
- v := Word(0)
- j := i
- for i++; i < len(line) && '0' <= line[i] && line[i] <= '7'; i++ {
- v = v*8 + Word(line[i]-'0')
- }
- if i == j {
- continue
- }
- m.Mem[a] = v
- }
- return nil
-}
diff --git a/src/pkg/exp/spacewar/spacewar.go b/src/pkg/exp/spacewar/spacewar.go
deleted file mode 100644
index 7333220ef..000000000
--- a/src/pkg/exp/spacewar/spacewar.go
+++ /dev/null
@@ -1,196 +0,0 @@
-// Copyright (c) 1996 Barry Silverman, Brian Silverman, Vadim Gerasimov.
-// Portions Copyright (c) 2009 The Go Authors.
-//
-// 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.
-
-// See ../../nacl/README.
-
-package main
-
-import (
- "bytes"
- "exp/draw"
- "exp/nacl/av"
- "exp/nacl/srpc"
- "image"
- "log"
- "os"
- "runtime"
- "time"
- "./pdp1"
-)
-
-func main() {
- runtime.LockOSThread()
- if srpc.Enabled() {
- go srpc.ServeRuntime()
- }
-
- w, err := av.Init(av.SubsystemVideo, 512, 512)
- if err != nil {
- log.Exitf("av.Init: %s", err)
- }
-
- go quitter(w.QuitChan())
-
- var m SpacewarPDP1
- m.Init(w)
- m.PC = 4
- f := bytes.NewBuffer([]byte(spacewarCode))
- if err = m.Load(f); err != nil {
- log.Exitf("loading %s: %s", "spacewar.lst", err)
- }
- for err == nil {
- //fmt.Printf("step PC=%06o ", m.PC);
- //fmt.Printf("inst=%06o AC=%06o IO=%06o OV=%o\n",
- // m.Mem[m.PC], m.AC, m.IO, m.OV);
- err = m.Step()
- }
- log.Exitf("step: %s", err)
-}
-
-func quitter(c <-chan bool) {
- <-c
- os.Exit(0)
-}
-
-// A SpacewarPDP1 is a PDP-1 machine configured to run Spacewar!
-// It responds to traps by drawing on the display, and it flushes the
-// display and pauses every second time the program counter reaches
-// instruction 02051.
-type SpacewarPDP1 struct {
- pdp1.M
- nframe int
- frameTime int64
- ctxt draw.Context
- dx, dy int
- screen draw.Image
- ctl pdp1.Word
- kc <-chan int
- colorModel image.ColorModel
- cmap []image.Color
- pix [][]uint8
-}
-
-func min(a, b int) int {
- if a < b {
- return a
- }
- return b
-}
-
-func (m *SpacewarPDP1) Init(ctxt draw.Context) {
- m.ctxt = ctxt
- m.kc = ctxt.KeyboardChan()
- m.screen = ctxt.Screen()
- m.dx = m.screen.Width()
- m.dy = m.screen.Height()
- m.colorModel = m.screen.ColorModel()
- m.pix = make([][]uint8, m.dy)
- for i := range m.pix {
- m.pix[i] = make([]uint8, m.dx)
- }
- m.cmap = make([]image.Color, 256)
- for i := range m.cmap {
- var r, g, b uint8
- r = uint8(min(0, 255))
- g = uint8(min(i*2, 255))
- b = uint8(min(0, 255))
- m.cmap[i] = m.colorModel.Convert(image.RGBAColor{r, g, b, 0xff})
- }
-}
-
-const (
- frameDelay = 56 * 1e6 // 56 ms
-)
-
-var ctlBits = [...]pdp1.Word{
- 'f': 0000001,
- 'd': 0000002,
- 'a': 0000004,
- 's': 0000010,
- '\'': 0040000,
- ';': 0100000,
- 'k': 0200000,
- 'l': 0400000,
-}
-
-func (m *SpacewarPDP1) Step() os.Error {
- if m.PC == 02051 {
- m.pollInput()
- m.nframe++
- if m.nframe&1 == 0 {
- m.flush()
- t := time.Nanoseconds()
- if t >= m.frameTime+3*frameDelay {
- m.frameTime = t
- } else {
- m.frameTime += frameDelay
- for t < m.frameTime {
- time.Sleep(m.frameTime - t)
- t = time.Nanoseconds()
- }
- }
- }
- }
- return m.M.Step(m)
-}
-
-func (m *SpacewarPDP1) Trap(y pdp1.Word) {
- switch y & 077 {
- case 7:
- x := int(m.AC+0400000) & 0777777
- y := int(m.IO+0400000) & 0777777
- x = x * m.dx / 0777777
- y = y * m.dy / 0777777
- if 0 <= x && x < m.dx && 0 <= y && y < m.dy {
- n := uint8(min(int(m.pix[y][x])+128, 255))
- m.pix[y][x] = n
- }
- case 011:
- m.IO = m.ctl
- }
-}
-
-func (m *SpacewarPDP1) flush() {
- // Update screen image; simulate phosphor decay.
- for y := 0; y < m.dy; y++ {
- for x := 0; x < m.dx; x++ {
- m.screen.Set(x, y, m.cmap[m.pix[y][x]])
- m.pix[y][x] >>= 1
- }
- }
- m.ctxt.FlushImage()
-}
-
-func (m *SpacewarPDP1) pollInput() {
- for {
- select {
- case ch := <-m.kc:
- if 0 <= ch && ch < len(ctlBits) {
- m.ctl |= ctlBits[ch]
- }
- if 0 <= -ch && -ch < len(ctlBits) {
- m.ctl &^= ctlBits[-ch]
- }
- default:
- return
- }
- }
-}
diff --git a/src/pkg/exp/spacewar/spacewar.html b/src/pkg/exp/spacewar/spacewar.html
deleted file mode 100644
index 8f49b1c34..000000000
--- a/src/pkg/exp/spacewar/spacewar.html
+++ /dev/null
@@ -1,21 +0,0 @@
-
-<h1>Spacewar</h1>
-<table>
-<tr><td valign=top>
-<embed name="nacl_module" id="pluginobj" src="8.out" type="application/x-nacl-srpc" width=512 height=512>
-<td valign=top>
-This is a Go translation of the Java emulator pdp1.java in
-<a href="http://spacewar.oversigma.com/sources/sources.zip">http://spacewar.oversigma.com/sources/sources.zip</a>.
-See <a href="pdp1.go">pdp1.go</a>, <a href="spacewar.go">spacewar.go</a>,
-and
-<a href="http://spacewar.oversigma.com/readme.html">http://spacewar.oversigma.com/readme.html</a>.
-<br><br>
-The <i>a</i>, <i>s</i>, <i>d</i>, <i>f</i> keys control one of the spaceships. The <i>k</i>,
-<i>l</i>, <i>;</i>, <i>'</i> keys control the other. The controls are spin one
-way, spin the other, thrust, and fire.
-<br>
-<br>
-<b>You may need to click on the game window to
-focus the keyboard on it.</b>
-
-</table>
diff --git a/src/pkg/expvar/Makefile b/src/pkg/expvar/Makefile
index 544891739..5619630d1 100644
--- a/src/pkg/expvar/Makefile
+++ b/src/pkg/expvar/Makefile
@@ -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 ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=expvar
GOFILES=\
diff --git a/src/pkg/expvar/expvar.go b/src/pkg/expvar/expvar.go
index 4017027b7..fb20b25b2 100644
--- a/src/pkg/expvar/expvar.go
+++ b/src/pkg/expvar/expvar.go
@@ -6,6 +6,8 @@
// such as operation counters in servers. It exposes these variables via
// HTTP at /debug/vars in JSON format.
//
+// Operations to set or modify these public variables are atomic.
+//
// In addition to adding the HTTP handler, this package registers the
// following variables:
//
@@ -50,6 +52,12 @@ func (v *Int) Add(delta int64) {
v.i += delta
}
+func (v *Int) Set(value int64) {
+ v.mu.Lock()
+ defer v.mu.Unlock()
+ v.i = value
+}
+
// Map is a string-to-Var map variable, and satisfies the Var interface.
type Map struct {
m map[string]Var
@@ -144,7 +152,7 @@ func (v IntFunc) String() string { return strconv.Itoa64(v()) }
// The function will be called each time the Var is evaluated.
type StringFunc func() string
-func (f StringFunc) String() string { return f() }
+func (f StringFunc) String() string { return strconv.Quote(f()) }
// All published variables.
@@ -153,12 +161,12 @@ var mutex sync.Mutex
// Publish declares an named exported variable. This should be called from a
// package's init function when it creates its Vars. If the name is already
-// registered then this will log.Crash.
+// registered then this will log.Panic.
func Publish(name string, v Var) {
mutex.Lock()
defer mutex.Unlock()
if _, existing := vars[name]; existing {
- log.Crash("Reuse of exported var name:", name)
+ log.Panicln("Reuse of exported var name:", name)
}
vars[name] = v
}
@@ -210,18 +218,18 @@ func Iter() <-chan KeyValue {
return c
}
-func expvarHandler(c *http.Conn, req *http.Request) {
- c.SetHeader("content-type", "application/json; charset=utf-8")
- fmt.Fprintf(c, "{\n")
+func expvarHandler(w http.ResponseWriter, r *http.Request) {
+ w.SetHeader("content-type", "application/json; charset=utf-8")
+ fmt.Fprintf(w, "{\n")
first := true
for name, value := range vars {
if !first {
- fmt.Fprintf(c, ",\n")
+ fmt.Fprintf(w, ",\n")
}
first = false
- fmt.Fprintf(c, "%q: %s", name, value)
+ fmt.Fprintf(w, "%q: %s", name, value)
}
- fmt.Fprintf(c, "\n}\n")
+ fmt.Fprintf(w, "\n}\n")
}
func memstats() string {
diff --git a/src/pkg/expvar/expvar_test.go b/src/pkg/expvar/expvar_test.go
index 98cd9c2ea..009f24d1a 100644
--- a/src/pkg/expvar/expvar_test.go
+++ b/src/pkg/expvar/expvar_test.go
@@ -27,6 +27,11 @@ func TestInt(t *testing.T) {
if s := reqs.String(); s != "4" {
t.Errorf("reqs.String() = %q, want \"4\"", s)
}
+
+ reqs.Set(-2)
+ if reqs.i != -2 {
+ t.Errorf("reqs.i = %v, want -2", reqs.i)
+ }
}
func TestString(t *testing.T) {
@@ -76,13 +81,13 @@ func TestMapCounter(t *testing.T) {
t.Error("red.Kind() is not a number.")
}
if x != 3 {
- t.Error("red = %v, want 3", x)
+ t.Errorf("red = %v, want 3", x)
}
}
func TestIntFunc(t *testing.T) {
- x := int(4)
- ix := IntFunc(func() int64 { return int64(x) })
+ x := int64(4)
+ ix := IntFunc(func() int64 { return x })
if s := ix.String(); s != "4" {
t.Errorf("ix.String() = %v, want 4", s)
}
@@ -92,3 +97,16 @@ func TestIntFunc(t *testing.T) {
t.Errorf("ix.String() = %v, want 5", s)
}
}
+
+func TestStringFunc(t *testing.T) {
+ x := "hello"
+ sx := StringFunc(func() string { return x })
+ if s, exp := sx.String(), `"hello"`; s != exp {
+ t.Errorf(`sx.String() = %q, want %q`, s, exp)
+ }
+
+ x = "goodbye"
+ if s, exp := sx.String(), `"goodbye"`; s != exp {
+ t.Errorf(`sx.String() = %q, want %q`, s, exp)
+ }
+}
diff --git a/src/pkg/flag/Makefile b/src/pkg/flag/Makefile
index 3ffbea83c..3408ca474 100644
--- a/src/pkg/flag/Makefile
+++ b/src/pkg/flag/Makefile
@@ -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 ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=flag
GOFILES=\
diff --git a/src/pkg/flag/export_test.go b/src/pkg/flag/export_test.go
new file mode 100644
index 000000000..b5e3243b3
--- /dev/null
+++ b/src/pkg/flag/export_test.go
@@ -0,0 +1,32 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package flag
+
+import "os"
+
+// Additional routines compiled into the package only during testing.
+
+// ResetForTesting clears all flag state and sets the usage function as directed.
+// After calling ResetForTesting, parse errors in flag handling will panic rather
+// than exit the program.
+func ResetForTesting(usage func()) {
+ flags = &allFlags{make(map[string]*Flag), make(map[string]*Flag), os.Args[1:]}
+ Usage = usage
+ panicOnError = true
+}
+
+// ParseForTesting parses the flag state using the provided arguments. It
+// should be called after 1) ResetForTesting and 2) setting up the new flags.
+// The return value reports whether the parse was error-free.
+func ParseForTesting(args []string) (result bool) {
+ defer func() {
+ if recover() != nil {
+ result = false
+ }
+ }()
+ os.Args = args
+ Parse()
+ return true
+}
diff --git a/src/pkg/flag/flag.go b/src/pkg/flag/flag.go
index 59c33403d..04fe2fa05 100644
--- a/src/pkg/flag/flag.go
+++ b/src/pkg/flag/flag.go
@@ -7,7 +7,7 @@
Usage:
- 1) Define flags using flag.String(), Bool(), Int(), etc. Example:
+ Define flags using flag.String(), Bool(), Int(), etc. Example:
import "flag"
var ip *int = flag.Int("flagname", 1234, "help message for flagname")
If you like, you can bind the flag to a variable using the Var() functions.
@@ -20,17 +20,18 @@
flag.Var(&flagVal, "name", "help message for flagname")
For such flags, the default value is just the initial value of the variable.
- 2) After all flags are defined, call
+ After all flags are defined, call
flag.Parse()
to parse the command line into the defined flags.
- 3) Flags may then be used directly. If you're using the flags themselves,
+ Flags may then be used directly. If you're using the flags themselves,
they are all pointers; if you bind to variables, they're values.
fmt.Println("ip has value ", *ip);
fmt.Println("flagvar has value ", flagvar);
- 4) After parsing, flag.Arg(i) is the i'th argument after the flags.
- Args are indexed from 0 up to flag.NArg().
+ After parsing, the arguments after the flag are available as the
+ slice flag.Args() or individually as flag.Arg(i).
+ The arguments are indexed from 0 up to flag.NArg().
Command line flag syntax:
-flag
@@ -48,6 +49,19 @@
Integer flags accept 1234, 0664, 0x1234 and may be negative.
Boolean flags may be 1, 0, t, f, true, false, TRUE, FALSE, True, False.
+
+ It is safe to call flag.Parse multiple times, possibly after changing
+ os.Args. This makes it possible to implement command lines with
+ subcommands that enable additional flags, as in:
+
+ flag.Bool(...) // global options
+ flag.Parse() // parse leading command
+ subcmd := flag.Args(0)
+ switch subcmd {
+ // add per-subcommand options
+ }
+ os.Args = flag.Args()
+ flag.Parse()
*/
package flag
@@ -200,9 +214,9 @@ type Flag struct {
}
type allFlags struct {
- actual map[string]*Flag
- formal map[string]*Flag
- first_arg int // 0 is the program name, 1 is first arg
+ actual map[string]*Flag
+ formal map[string]*Flag
+ args []string // arguments after flags
}
var flags *allFlags
@@ -275,18 +289,17 @@ func NFlag() int { return len(flags.actual) }
// Arg returns the i'th command-line argument. Arg(0) is the first remaining argument
// after flags have been processed.
func Arg(i int) string {
- i += flags.first_arg
- if i < 0 || i >= len(os.Args) {
+ if i < 0 || i >= len(flags.args) {
return ""
}
- return os.Args[i]
+ return flags.args[i]
}
// NArg is the number of arguments remaining after flags have been processed.
-func NArg() int { return len(os.Args) - flags.first_arg }
+func NArg() int { return len(flags.args) }
// Args returns the non-flag command-line arguments.
-func Args() []string { return os.Args[flags.first_arg:] }
+func Args() []string { return flags.args }
// BoolVar defines a bool flag with specified name, default value, and usage string.
// The argument p points to a bool variable in which to store the value of the flag.
@@ -414,23 +427,20 @@ func Var(value Value, name string, usage string) {
}
-func (f *allFlags) parseOne(index int) (ok bool, next int) {
- s := os.Args[index]
- f.first_arg = index // until proven otherwise
- if len(s) == 0 {
- return false, -1
+func (f *allFlags) parseOne() (ok bool) {
+ if len(f.args) == 0 {
+ return false
}
- if s[0] != '-' {
- return false, -1
+ s := f.args[0]
+ if len(s) == 0 || s[0] != '-' || len(s) == 1 {
+ return false
}
num_minuses := 1
- if len(s) == 1 {
- return false, index
- }
if s[1] == '-' {
num_minuses++
if len(s) == 2 { // "--" terminates the flags
- return false, index + 1
+ f.args = f.args[1:]
+ return false
}
}
name := s[num_minuses:]
@@ -440,6 +450,7 @@ func (f *allFlags) parseOne(index int) (ok bool, next int) {
}
// it's a flag. does it have an argument?
+ f.args = f.args[1:]
has_value := false
value := ""
for i := 1; i < len(name); i++ { // equals cannot be first
@@ -456,22 +467,21 @@ func (f *allFlags) parseOne(index int) (ok bool, next int) {
fmt.Fprintf(os.Stderr, "flag provided but not defined: -%s\n", name)
fail()
}
- if f, ok := flag.Value.(*boolValue); ok { // special case: doesn't need an arg
+ if fv, ok := flag.Value.(*boolValue); ok { // special case: doesn't need an arg
if has_value {
- if !f.Set(value) {
- fmt.Fprintf(os.Stderr, "invalid boolean value %t for flag: -%s\n", value, name)
+ if !fv.Set(value) {
+ fmt.Fprintf(os.Stderr, "invalid boolean value %q for flag: -%s\n", value, name)
fail()
}
} else {
- f.Set("true")
+ fv.Set("true")
}
} else {
// It must have a value, which might be the next argument.
- if !has_value && index < len(os.Args)-1 {
+ if !has_value && len(f.args) > 0 {
// value is the next arg
has_value = true
- index++
- value = os.Args[index]
+ value, f.args = f.args[0], f.args[1:]
}
if !has_value {
fmt.Fprintf(os.Stderr, "flag needs an argument: -%s\n", name)
@@ -479,54 +489,22 @@ func (f *allFlags) parseOne(index int) (ok bool, next int) {
}
ok = flag.Value.Set(value)
if !ok {
- fmt.Fprintf(os.Stderr, "invalid value %s for flag: -%s\n", value, name)
+ fmt.Fprintf(os.Stderr, "invalid value %q for flag: -%s\n", value, name)
fail()
}
}
flags.actual[name] = flag
- return true, index + 1
+ return true
}
// Parse parses the command-line flags. Must be called after all flags are defined
// and before any are accessed by the program.
func Parse() {
- for i := 1; i < len(os.Args); {
- ok, next := flags.parseOne(i)
- if next > 0 {
- flags.first_arg = next
- i = next
- }
- if !ok {
- break
- }
+ flags.args = os.Args[1:]
+ for flags.parseOne() {
}
}
-// ResetForTesting clears all flag state and sets the usage function as directed.
-// After calling ResetForTesting, parse errors in flag handling will panic rather
-// than exit the program.
-// For testing only!
-func ResetForTesting(usage func()) {
- flags = &allFlags{make(map[string]*Flag), make(map[string]*Flag), 1}
- Usage = usage
- panicOnError = true
-}
-
-// ParseForTesting parses the flag state using the provided arguments. It
-// should be called after 1) ResetForTesting and 2) setting up the new flags.
-// The return value reports whether the parse was error-free.
-// For testing only!
-func ParseForTesting(args []string) (result bool) {
- defer func() {
- if recover() != nil {
- result = false
- }
- }()
- os.Args = args
- Parse()
- return true
-}
-
func init() {
- flags = &allFlags{make(map[string]*Flag), make(map[string]*Flag), 1}
+ flags = &allFlags{make(map[string]*Flag), make(map[string]*Flag), os.Args[1:]}
}
diff --git a/src/pkg/flag/flag_test.go b/src/pkg/flag/flag_test.go
index 83bf7eebf..4ebb73805 100644
--- a/src/pkg/flag/flag_test.go
+++ b/src/pkg/flag/flag_test.go
@@ -7,6 +7,7 @@ package flag_test
import (
. "flag"
"fmt"
+ "os"
"testing"
)
@@ -161,10 +162,7 @@ func (f *flagVar) String() string {
}
func (f *flagVar) Set(value string) bool {
- n := make(flagVar, len(*f)+1)
- copy(n, *f)
- *f = n
- (*f)[len(*f)-1] = value
+ *f = append(*f, value)
return true
}
@@ -183,3 +181,21 @@ func TestUserDefined(t *testing.T) {
t.Errorf("expected value %q got %q", expect, v.String())
}
}
+
+func TestChangingArgs(t *testing.T) {
+ ResetForTesting(func() { t.Fatal("bad parse") })
+ oldArgs := os.Args
+ defer func() { os.Args = oldArgs }()
+ os.Args = []string{"cmd", "-before", "subcmd", "-after", "args"}
+ before := Bool("before", false, "")
+ Parse()
+ cmd := Arg(0)
+ os.Args = Args()
+ after := Bool("after", false, "")
+ Parse()
+ args := Args()
+
+ if !*before || cmd != "subcmd" || !*after || len(args) != 1 || args[0] != "args" {
+ t.Fatalf("expected true subcmd true [args] got %v %v %v %v", *before, cmd, *after, args)
+ }
+}
diff --git a/src/pkg/fmt/Makefile b/src/pkg/fmt/Makefile
index 28ea396c7..44b48bc67 100644
--- a/src/pkg/fmt/Makefile
+++ b/src/pkg/fmt/Makefile
@@ -2,10 +2,11 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=fmt
GOFILES=\
+ doc.go\
format.go\
print.go\
scan.go\
diff --git a/src/pkg/fmt/doc.go b/src/pkg/fmt/doc.go
new file mode 100644
index 000000000..f3067eac9
--- /dev/null
+++ b/src/pkg/fmt/doc.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.
+
+/*
+ Package fmt implements formatted I/O with functions analogous
+ to C's printf and scanf. The format 'verbs' are derived from C's but
+ are simpler.
+
+ Printing:
+
+ The verbs:
+
+ General:
+ %v the value in a default format.
+ when printing structs, the plus flag (%+v) adds field names
+ %#v a Go-syntax representation of the value
+ %T a Go-syntax representation of the type of the value
+
+ Boolean:
+ %t the word true or false
+ Integer:
+ %b base 2
+ %c the character represented by the corresponding Unicode code point
+ %d base 10
+ %o base 8
+ %x base 16, with lower-case letters for a-f
+ %X base 16, with upper-case letters for A-F
+ %U unicode format: U+1234; same as "U+%x" with 4 digits default
+ Floating-point and complex constituents:
+ %e scientific notation, e.g. -1234.456e+78
+ %E scientific notation, e.g. -1234.456E+78
+ %f decimal point but no exponent, e.g. 123.456
+ %g whichever of %e or %f produces more compact output
+ %G whichever of %E or %f produces more compact output
+ String and slice of bytes:
+ %s the uninterpreted bytes of the string or slice
+ %q a double-quoted string safely escaped with Go syntax
+ %x base 16 notation with two characters per byte
+ Pointer:
+ %p base 16 notation, with leading 0x
+
+ There is no 'u' flag. Integers are printed unsigned if they have unsigned type.
+ Similarly, there is no need to specify the size of the operand (int8, int64).
+
+ For numeric values, the width and precision flags control
+ formatting; width sets the width of the field, precision the
+ number of places after the decimal, if appropriate. The
+ format %6.2f prints 123.45. The width of a field is the number
+ of Unicode code points in the string. This differs from C's printf where
+ the field width is the number of bytes. Either or both of the
+ flags may be replaced with the character '*', causing their values
+ to be obtained from the next operand, which must be of type int.
+
+ Other flags:
+ + always print a sign for numeric values
+ - pad with spaces on the right rather than the left (left-justify the field)
+ # alternate format: add leading 0 for octal (%#o), 0x for hex (%#x);
+ 0X for hex (%#X); suppress 0x for %p (%#p);
+ print a raw (backquoted) string if possible for %q (%#q)
+ ' ' (space) leave a space for elided sign in numbers (% d);
+ put spaces between bytes printing strings or slices in hex (% x, % X)
+ 0 pad with leading zeros rather than spaces
+
+ For each Printf-like function, there is also a Print function
+ that takes no format and is equivalent to saying %v for every
+ operand. Another variant Println inserts blanks between
+ operands and appends a newline.
+
+ Regardless of the verb, if an operand is an interface value,
+ the internal concrete value is used, not the interface itself.
+ Thus:
+ var i interface{} = 23
+ fmt.Printf("%v\n", i)
+ will print 23.
+
+ If an operand implements interface Formatter, that interface
+ can be used for fine control of formatting.
+
+ If an operand implements method String() string that method
+ will be used to convert the object to a string, which will then
+ be formatted as required by the verb (if any). To avoid
+ recursion in cases such as
+ type X int
+ func (x X) String() string { return Sprintf("%d", x) }
+ cast the value before recurring:
+ func (x X) String() string { return Sprintf("%d", int(x)) }
+
+ Format errors:
+
+ If an invalid argument is given for a verb, such as providing
+ a string to %d, the generated string will contain a
+ description of the problem, as in these examples:
+
+ Wrong type or unknown verb: %!verb(type=value)
+ Printf("%d", hi): %!d(string=hi)
+ Too many arguments: %!(EXTRA type=value)
+ Printf("hi", "guys"): hi%!(EXTRA string=guys)
+ Too few arguments: %!verb(MISSING)
+ Printf("hi%d"): hi %!d(MISSING)
+ Non-int for width or precision: %!(BADWIDTH) or %!(BADPREC)
+ Printf("%*s", 4.5, "hi"): %!(BADWIDTH)hi
+ Printf("%.*s", 4.5, "hi"): %!(BADPREC)hi
+
+ All errors begin with the string "%!" followed sometimes
+ by a single character (the verb) and end with a parenthesized
+ description.
+
+ Scanning:
+
+ An analogous set of functions scans formatted text to yield
+ values. Scan, Scanf and Scanln read from os.Stdin; Fscan,
+ Fscanf and Fscanln read from a specified os.Reader; Sscan,
+ Sscanf and Sscanln read from an argument string. Sscanln,
+ Fscanln and Sscanln stop scanning at a newline and require that
+ the items be followed by one; Sscanf, Fscanf and Sscanf require
+ newlines in the input to match newlines in the format; the other
+ routines treat newlines as spaces.
+
+ Scanf, Fscanf, and Sscanf parse the arguments according to a
+ format string, analogous to that of Printf. For example, %x
+ will scan an integer as a hexadecimal number, and %v will scan
+ the default representation format for the value.
+
+ The formats behave analogously to those of Printf with the
+ following exceptions:
+
+ %p is not implemented
+ %T is not implemented
+ %e %E %f %F %g %g are all equivalent and scan any floating point or complex value
+ %s and %v on strings scan a space-delimited token
+
+ Width is interpreted in the input text (%5s means at most
+ five runes of input will be read to scan a string) but there
+ is no syntax for scanning with a precision (no %5.2f, just
+ %5f).
+
+ When scanning with a format, all non-empty runs of space
+ characters (except newline) are equivalent to a single
+ space in both the format and the input. With that proviso,
+ text in the format string must match the input text; scanning
+ stops if it does not, with the return value of the function
+ indicating the number of arguments scanned.
+
+ In all the scanning functions, if an operand implements method
+ Scan (that is, it implements the Scanner interface) that
+ method will be used to scan the text for that operand. Also,
+ if the number of arguments scanned is less than the number of
+ arguments provided, an error is returned.
+
+ All arguments to be scanned must be either pointers to basic
+ types or implementations of the Scanner interface.
+
+ Note: Fscan etc. can read one character (rune) past the
+ input they return, which means that a loop calling a scan
+ routine may skip some of the input. This is usually a
+ problem only when there is no space between input values.
+ However, if the reader provided to Fscan implements UnreadRune,
+ that method will be used to save the character and successive
+ calls will not lose data. To attach an UnreadRune method
+ to a reader without that capability, use bufio.NewReader.
+*/
+package fmt
diff --git a/src/pkg/fmt/fmt_test.go b/src/pkg/fmt/fmt_test.go
index 7e59d4073..0aafe6d99 100644
--- a/src/pkg/fmt/fmt_test.go
+++ b/src/pkg/fmt/fmt_test.go
@@ -45,11 +45,6 @@ func TestFmtInterface(t *testing.T) {
}
}
-type fmtTest struct {
- fmt string
- val interface{}
- out string
-}
const b32 uint32 = 1<<32 - 1
const b64 uint64 = 1<<64 - 1
@@ -78,268 +73,326 @@ type C struct {
B
}
+type F int
+
+func (f F) Format(s State, c int) {
+ Fprintf(s, "<%c=F(%d)>", c, int(f))
+}
+
+type G int
+
+func (g G) GoString() string {
+ return Sprintf("GoString(%d)", int(g))
+}
+
+type S struct {
+ f F // a struct field that Formats
+ g G // a struct field that GoStrings
+}
+
+// A type with a String method with pointer receiver for testing %p
+type P int
+
+var pValue P
+
+func (p *P) String() string {
+ return "String(p)"
+}
+
var b byte
-var fmttests = []fmtTest{
- fmtTest{"%d", 12345, "12345"},
- fmtTest{"%v", 12345, "12345"},
- fmtTest{"%t", true, "true"},
+var fmttests = []struct {
+ fmt string
+ val interface{}
+ out string
+}{
+ {"%d", 12345, "12345"},
+ {"%v", 12345, "12345"},
+ {"%t", true, "true"},
// basic string
- fmtTest{"%s", "abc", "abc"},
- fmtTest{"%x", "abc", "616263"},
- fmtTest{"%x", "xyz", "78797a"},
- fmtTest{"%X", "xyz", "78797A"},
- fmtTest{"%q", "abc", `"abc"`},
+ {"%s", "abc", "abc"},
+ {"%x", "abc", "616263"},
+ {"%x", "xyz", "78797a"},
+ {"%X", "xyz", "78797A"},
+ {"%q", "abc", `"abc"`},
// basic bytes
- fmtTest{"%s", []byte("abc"), "abc"},
- fmtTest{"%x", []byte("abc"), "616263"},
- fmtTest{"% x", []byte("abc"), "61 62 63"},
- fmtTest{"%x", []byte("xyz"), "78797a"},
- fmtTest{"%X", []byte("xyz"), "78797A"},
- fmtTest{"%q", []byte("abc"), `"abc"`},
+ {"%s", []byte("abc"), "abc"},
+ {"%x", []byte("abc"), "616263"},
+ {"% x", []byte("abc\xff"), "61 62 63 ff"},
+ {"% X", []byte("abc\xff"), "61 62 63 FF"},
+ {"%x", []byte("xyz"), "78797a"},
+ {"%X", []byte("xyz"), "78797A"},
+ {"%q", []byte("abc"), `"abc"`},
// escaped strings
- fmtTest{"%#q", `abc`, "`abc`"},
- fmtTest{"%#q", `"`, "`\"`"},
- fmtTest{"1 %#q", `\n`, "1 `\\n`"},
- fmtTest{"2 %#q", "\n", `2 "\n"`},
- fmtTest{"%q", `"`, `"\""`},
- fmtTest{"%q", "\a\b\f\r\n\t\v", `"\a\b\f\r\n\t\v"`},
- fmtTest{"%q", "abc\xffdef", `"abc\xffdef"`},
- fmtTest{"%q", "\u263a", `"\u263a"`},
- fmtTest{"%q", "\U0010ffff", `"\U0010ffff"`},
+ {"%#q", `abc`, "`abc`"},
+ {"%#q", `"`, "`\"`"},
+ {"1 %#q", `\n`, "1 `\\n`"},
+ {"2 %#q", "\n", `2 "\n"`},
+ {"%q", `"`, `"\""`},
+ {"%q", "\a\b\f\r\n\t\v", `"\a\b\f\r\n\t\v"`},
+ {"%q", "abc\xffdef", `"abc\xffdef"`},
+ {"%q", "\u263a", `"\u263a"`},
+ {"%q", "\U0010ffff", `"\U0010ffff"`},
// width
- fmtTest{"%5s", "abc", " abc"},
- fmtTest{"%2s", "\u263a", " \u263a"},
- fmtTest{"%-5s", "abc", "abc "},
- fmtTest{"%05s", "abc", "00abc"},
+ {"%5s", "abc", " abc"},
+ {"%2s", "\u263a", " \u263a"},
+ {"%-5s", "abc", "abc "},
+ {"%05s", "abc", "00abc"},
// integers
- fmtTest{"%d", 12345, "12345"},
- fmtTest{"%d", -12345, "-12345"},
- fmtTest{"%10d", 12345, " 12345"},
- fmtTest{"%10d", -12345, " -12345"},
- fmtTest{"%+10d", 12345, " +12345"},
- fmtTest{"%010d", 12345, "0000012345"},
- fmtTest{"%010d", -12345, "-000012345"},
- fmtTest{"%-10d", 12345, "12345 "},
- fmtTest{"%010.3d", 1, " 001"},
- fmtTest{"%010.3d", -1, " -001"},
- fmtTest{"%+d", 12345, "+12345"},
- fmtTest{"%+d", -12345, "-12345"},
- fmtTest{"%+d", 0, "+0"},
- fmtTest{"% d", 0, " 0"},
- fmtTest{"% d", 12345, " 12345"},
+ {"%d", 12345, "12345"},
+ {"%d", -12345, "-12345"},
+ {"%10d", 12345, " 12345"},
+ {"%10d", -12345, " -12345"},
+ {"%+10d", 12345, " +12345"},
+ {"%010d", 12345, "0000012345"},
+ {"%010d", -12345, "-000012345"},
+ {"%-10d", 12345, "12345 "},
+ {"%010.3d", 1, " 001"},
+ {"%010.3d", -1, " -001"},
+ {"%+d", 12345, "+12345"},
+ {"%+d", -12345, "-12345"},
+ {"%+d", 0, "+0"},
+ {"% d", 0, " 0"},
+ {"% d", 12345, " 12345"},
+
+ // unicode format
+ {"%U", 0x1, "U+0001"},
+ {"%.8U", 0x2, "U+00000002"},
+ {"%U", 0x1234, "U+1234"},
+ {"%U", 0x12345, "U+12345"},
+ {"%10.6U", 0xABC, " U+000ABC"},
+ {"%-10.6U", 0xABC, "U+000ABC "},
// floats
- fmtTest{"%+.3e", 0.0, "+0.000e+00"},
- fmtTest{"%+.3e", 1.0, "+1.000e+00"},
- fmtTest{"%+.3f", -1.0, "-1.000"},
- fmtTest{"% .3E", -1.0, "-1.000E+00"},
- fmtTest{"% .3e", 1.0, " 1.000e+00"},
- fmtTest{"%+.3g", 0.0, "+0"},
- fmtTest{"%+.3g", 1.0, "+1"},
- fmtTest{"%+.3g", -1.0, "-1"},
- fmtTest{"% .3g", -1.0, "-1"},
- fmtTest{"% .3g", 1.0, " 1"},
+ {"%+.3e", 0.0, "+0.000e+00"},
+ {"%+.3e", 1.0, "+1.000e+00"},
+ {"%+.3f", -1.0, "-1.000"},
+ {"% .3E", -1.0, "-1.000E+00"},
+ {"% .3e", 1.0, " 1.000e+00"},
+ {"%+.3g", 0.0, "+0"},
+ {"%+.3g", 1.0, "+1"},
+ {"%+.3g", -1.0, "-1"},
+ {"% .3g", -1.0, "-1"},
+ {"% .3g", 1.0, " 1"},
// complex values
- fmtTest{"%+.3e", 0i, "(+0.000e+00+0.000e+00i)"},
- fmtTest{"%+.3f", 0i, "(+0.000+0.000i)"},
- fmtTest{"%+.3g", 0i, "(+0+0i)"},
- fmtTest{"%+.3e", 1 + 2i, "(+1.000e+00+2.000e+00i)"},
- fmtTest{"%+.3f", 1 + 2i, "(+1.000+2.000i)"},
- fmtTest{"%+.3g", 1 + 2i, "(+1+2i)"},
- fmtTest{"%.3e", 0i, "(0.000e+00+0.000e+00i)"},
- fmtTest{"%.3f", 0i, "(0.000+0.000i)"},
- fmtTest{"%.3g", 0i, "(0+0i)"},
- fmtTest{"%.3e", 1 + 2i, "(1.000e+00+2.000e+00i)"},
- fmtTest{"%.3f", 1 + 2i, "(1.000+2.000i)"},
- fmtTest{"%.3g", 1 + 2i, "(1+2i)"},
- fmtTest{"%.3e", -1 - 2i, "(-1.000e+00-2.000e+00i)"},
- fmtTest{"%.3f", -1 - 2i, "(-1.000-2.000i)"},
- fmtTest{"%.3g", -1 - 2i, "(-1-2i)"},
- fmtTest{"% .3E", -1 - 2i, "(-1.000E+00-2.000E+00i)"},
- fmtTest{"%+.3g", complex64(1 + 2i), "(+1+2i)"},
- fmtTest{"%+.3g", complex128(1 + 2i), "(+1+2i)"},
+ {"%+.3e", 0i, "(+0.000e+00+0.000e+00i)"},
+ {"%+.3f", 0i, "(+0.000+0.000i)"},
+ {"%+.3g", 0i, "(+0+0i)"},
+ {"%+.3e", 1 + 2i, "(+1.000e+00+2.000e+00i)"},
+ {"%+.3f", 1 + 2i, "(+1.000+2.000i)"},
+ {"%+.3g", 1 + 2i, "(+1+2i)"},
+ {"%.3e", 0i, "(0.000e+00+0.000e+00i)"},
+ {"%.3f", 0i, "(0.000+0.000i)"},
+ {"%.3g", 0i, "(0+0i)"},
+ {"%.3e", 1 + 2i, "(1.000e+00+2.000e+00i)"},
+ {"%.3f", 1 + 2i, "(1.000+2.000i)"},
+ {"%.3g", 1 + 2i, "(1+2i)"},
+ {"%.3e", -1 - 2i, "(-1.000e+00-2.000e+00i)"},
+ {"%.3f", -1 - 2i, "(-1.000-2.000i)"},
+ {"%.3g", -1 - 2i, "(-1-2i)"},
+ {"% .3E", -1 - 2i, "(-1.000E+00-2.000E+00i)"},
+ {"%+.3g", complex64(1 + 2i), "(+1+2i)"},
+ {"%+.3g", complex128(1 + 2i), "(+1+2i)"},
// erroneous formats
- fmtTest{"", 2, "?(extra int=2)"},
- fmtTest{"%d", "hello", "%d(string=hello)"},
+ {"", 2, "%!(EXTRA int=2)"},
+ {"%d", "hello", "%!d(string=hello)"},
// old test/fmt_test.go
- fmtTest{"%d", 1234, "1234"},
- fmtTest{"%d", -1234, "-1234"},
- fmtTest{"%d", uint(1234), "1234"},
- fmtTest{"%d", uint32(b32), "4294967295"},
- fmtTest{"%d", uint64(b64), "18446744073709551615"},
- fmtTest{"%o", 01234, "1234"},
- fmtTest{"%#o", 01234, "01234"},
- fmtTest{"%o", uint32(b32), "37777777777"},
- fmtTest{"%o", uint64(b64), "1777777777777777777777"},
- fmtTest{"%x", 0x1234abcd, "1234abcd"},
- fmtTest{"%#x", 0x1234abcd, "0x1234abcd"},
- fmtTest{"%x", b32 - 0x1234567, "fedcba98"},
- fmtTest{"%X", 0x1234abcd, "1234ABCD"},
- fmtTest{"%X", b32 - 0x1234567, "FEDCBA98"},
- fmtTest{"%#X", 0, "0X0"},
- fmtTest{"%x", b64, "ffffffffffffffff"},
- fmtTest{"%b", 7, "111"},
- fmtTest{"%b", b64, "1111111111111111111111111111111111111111111111111111111111111111"},
- fmtTest{"%b", -6, "-110"},
- fmtTest{"%e", float64(1), "1.000000e+00"},
- fmtTest{"%e", float64(1234.5678e3), "1.234568e+06"},
- fmtTest{"%e", float64(1234.5678e-8), "1.234568e-05"},
- fmtTest{"%e", float64(-7), "-7.000000e+00"},
- fmtTest{"%e", float64(-1e-9), "-1.000000e-09"},
- fmtTest{"%f", float64(1234.5678e3), "1234567.800000"},
- fmtTest{"%f", float64(1234.5678e-8), "0.000012"},
- fmtTest{"%f", float64(-7), "-7.000000"},
- fmtTest{"%f", float64(-1e-9), "-0.000000"},
- fmtTest{"%g", float64(1234.5678e3), "1.2345678e+06"},
- fmtTest{"%g", float32(1234.5678e3), "1.2345678e+06"},
- fmtTest{"%g", float64(1234.5678e-8), "1.2345678e-05"},
- fmtTest{"%g", float64(-7), "-7"},
- fmtTest{"%g", float64(-1e-9), "-1e-09"},
- fmtTest{"%g", float32(-1e-9), "-1e-09"},
- fmtTest{"%E", float64(1), "1.000000E+00"},
- fmtTest{"%E", float64(1234.5678e3), "1.234568E+06"},
- fmtTest{"%E", float64(1234.5678e-8), "1.234568E-05"},
- fmtTest{"%E", float64(-7), "-7.000000E+00"},
- fmtTest{"%E", float64(-1e-9), "-1.000000E-09"},
- fmtTest{"%G", float64(1234.5678e3), "1.2345678E+06"},
- fmtTest{"%G", float32(1234.5678e3), "1.2345678E+06"},
- fmtTest{"%G", float64(1234.5678e-8), "1.2345678E-05"},
- fmtTest{"%G", float64(-7), "-7"},
- fmtTest{"%G", float64(-1e-9), "-1E-09"},
- fmtTest{"%G", float32(-1e-9), "-1E-09"},
- fmtTest{"%c", 'x', "x"},
- fmtTest{"%c", 0xe4, "ä"},
- fmtTest{"%c", 0x672c, "本"},
- fmtTest{"%c", '日', "日"},
- fmtTest{"%20.8d", 1234, " 00001234"},
- fmtTest{"%20.8d", -1234, " -00001234"},
- fmtTest{"%20d", 1234, " 1234"},
- fmtTest{"%-20.8d", 1234, "00001234 "},
- fmtTest{"%-20.8d", -1234, "-00001234 "},
- fmtTest{"%-#20.8x", 0x1234abc, "0x01234abc "},
- fmtTest{"%-#20.8X", 0x1234abc, "0X01234ABC "},
- fmtTest{"%-#20.8o", 01234, "00001234 "},
- fmtTest{"%.20b", 7, "00000000000000000111"},
- fmtTest{"%20.5s", "qwertyuiop", " qwert"},
- fmtTest{"%.5s", "qwertyuiop", "qwert"},
- fmtTest{"%-20.5s", "qwertyuiop", "qwert "},
- fmtTest{"%20c", 'x', " x"},
- fmtTest{"%-20c", 'x', "x "},
- fmtTest{"%20.6e", 1.2345e3, " 1.234500e+03"},
- fmtTest{"%20.6e", 1.2345e-3, " 1.234500e-03"},
- fmtTest{"%20e", 1.2345e3, " 1.234500e+03"},
- fmtTest{"%20e", 1.2345e-3, " 1.234500e-03"},
- fmtTest{"%20.8e", 1.2345e3, " 1.23450000e+03"},
- fmtTest{"%20f", float64(1.23456789e3), " 1234.567890"},
- fmtTest{"%20f", float64(1.23456789e-3), " 0.001235"},
- fmtTest{"%20f", float64(12345678901.23456789), " 12345678901.234568"},
- fmtTest{"%-20f", float64(1.23456789e3), "1234.567890 "},
- fmtTest{"%20.8f", float64(1.23456789e3), " 1234.56789000"},
- fmtTest{"%20.8f", float64(1.23456789e-3), " 0.00123457"},
- fmtTest{"%g", float64(1.23456789e3), "1234.56789"},
- fmtTest{"%g", float64(1.23456789e-3), "0.00123456789"},
- fmtTest{"%g", float64(1.23456789e20), "1.23456789e+20"},
- fmtTest{"%20e", math.Inf(1), " +Inf"},
- fmtTest{"%-20f", math.Inf(-1), "-Inf "},
- fmtTest{"%20g", math.NaN(), " NaN"},
+ {"%d", 1234, "1234"},
+ {"%d", -1234, "-1234"},
+ {"%d", uint(1234), "1234"},
+ {"%d", uint32(b32), "4294967295"},
+ {"%d", uint64(b64), "18446744073709551615"},
+ {"%o", 01234, "1234"},
+ {"%#o", 01234, "01234"},
+ {"%o", uint32(b32), "37777777777"},
+ {"%o", uint64(b64), "1777777777777777777777"},
+ {"%x", 0x1234abcd, "1234abcd"},
+ {"%#x", 0x1234abcd, "0x1234abcd"},
+ {"%x", b32 - 0x1234567, "fedcba98"},
+ {"%X", 0x1234abcd, "1234ABCD"},
+ {"%X", b32 - 0x1234567, "FEDCBA98"},
+ {"%#X", 0, "0X0"},
+ {"%x", b64, "ffffffffffffffff"},
+ {"%b", 7, "111"},
+ {"%b", b64, "1111111111111111111111111111111111111111111111111111111111111111"},
+ {"%b", -6, "-110"},
+ {"%e", float64(1), "1.000000e+00"},
+ {"%e", float64(1234.5678e3), "1.234568e+06"},
+ {"%e", float64(1234.5678e-8), "1.234568e-05"},
+ {"%e", float64(-7), "-7.000000e+00"},
+ {"%e", float64(-1e-9), "-1.000000e-09"},
+ {"%f", float64(1234.5678e3), "1234567.800000"},
+ {"%f", float64(1234.5678e-8), "0.000012"},
+ {"%f", float64(-7), "-7.000000"},
+ {"%f", float64(-1e-9), "-0.000000"},
+ {"%g", float64(1234.5678e3), "1.2345678e+06"},
+ {"%g", float32(1234.5678e3), "1.2345678e+06"},
+ {"%g", float64(1234.5678e-8), "1.2345678e-05"},
+ {"%g", float64(-7), "-7"},
+ {"%g", float64(-1e-9), "-1e-09"},
+ {"%g", float32(-1e-9), "-1e-09"},
+ {"%E", float64(1), "1.000000E+00"},
+ {"%E", float64(1234.5678e3), "1.234568E+06"},
+ {"%E", float64(1234.5678e-8), "1.234568E-05"},
+ {"%E", float64(-7), "-7.000000E+00"},
+ {"%E", float64(-1e-9), "-1.000000E-09"},
+ {"%G", float64(1234.5678e3), "1.2345678E+06"},
+ {"%G", float32(1234.5678e3), "1.2345678E+06"},
+ {"%G", float64(1234.5678e-8), "1.2345678E-05"},
+ {"%G", float64(-7), "-7"},
+ {"%G", float64(-1e-9), "-1E-09"},
+ {"%G", float32(-1e-9), "-1E-09"},
+ {"%c", 'x', "x"},
+ {"%c", 0xe4, "ä"},
+ {"%c", 0x672c, "本"},
+ {"%c", '日', "日"},
+ {"%20.8d", 1234, " 00001234"},
+ {"%20.8d", -1234, " -00001234"},
+ {"%20d", 1234, " 1234"},
+ {"%-20.8d", 1234, "00001234 "},
+ {"%-20.8d", -1234, "-00001234 "},
+ {"%-#20.8x", 0x1234abc, "0x01234abc "},
+ {"%-#20.8X", 0x1234abc, "0X01234ABC "},
+ {"%-#20.8o", 01234, "00001234 "},
+ {"%.20b", 7, "00000000000000000111"},
+ {"%20.5s", "qwertyuiop", " qwert"},
+ {"%.5s", "qwertyuiop", "qwert"},
+ {"%-20.5s", "qwertyuiop", "qwert "},
+ {"%20c", 'x', " x"},
+ {"%-20c", 'x', "x "},
+ {"%20.6e", 1.2345e3, " 1.234500e+03"},
+ {"%20.6e", 1.2345e-3, " 1.234500e-03"},
+ {"%20e", 1.2345e3, " 1.234500e+03"},
+ {"%20e", 1.2345e-3, " 1.234500e-03"},
+ {"%20.8e", 1.2345e3, " 1.23450000e+03"},
+ {"%20f", float64(1.23456789e3), " 1234.567890"},
+ {"%20f", float64(1.23456789e-3), " 0.001235"},
+ {"%20f", float64(12345678901.23456789), " 12345678901.234568"},
+ {"%-20f", float64(1.23456789e3), "1234.567890 "},
+ {"%20.8f", float64(1.23456789e3), " 1234.56789000"},
+ {"%20.8f", float64(1.23456789e-3), " 0.00123457"},
+ {"%g", float64(1.23456789e3), "1234.56789"},
+ {"%g", float64(1.23456789e-3), "0.00123456789"},
+ {"%g", float64(1.23456789e20), "1.23456789e+20"},
+ {"%20e", math.Inf(1), " +Inf"},
+ {"%-20f", math.Inf(-1), "-Inf "},
+ {"%20g", math.NaN(), " NaN"},
// arrays
- fmtTest{"%v", array, "[1 2 3 4 5]"},
- fmtTest{"%v", iarray, "[1 hello 2.5 <nil>]"},
- fmtTest{"%v", &array, "&[1 2 3 4 5]"},
- fmtTest{"%v", &iarray, "&[1 hello 2.5 <nil>]"},
+ {"%v", array, "[1 2 3 4 5]"},
+ {"%v", iarray, "[1 hello 2.5 <nil>]"},
+ {"%v", &array, "&[1 2 3 4 5]"},
+ {"%v", &iarray, "&[1 hello 2.5 <nil>]"},
// complexes with %v
- fmtTest{"%v", 1 + 2i, "(1+2i)"},
- fmtTest{"%v", complex64(1 + 2i), "(1+2i)"},
- fmtTest{"%v", complex128(1 + 2i), "(1+2i)"},
+ {"%v", 1 + 2i, "(1+2i)"},
+ {"%v", complex64(1 + 2i), "(1+2i)"},
+ {"%v", complex128(1 + 2i), "(1+2i)"},
// structs
- fmtTest{"%v", A{1, 2, "a", []int{1, 2}}, `{1 2 a [1 2]}`},
- fmtTest{"%+v", A{1, 2, "a", []int{1, 2}}, `{i:1 j:2 s:a x:[1 2]}`},
+ {"%v", A{1, 2, "a", []int{1, 2}}, `{1 2 a [1 2]}`},
+ {"%+v", A{1, 2, "a", []int{1, 2}}, `{i:1 j:2 s:a x:[1 2]}`},
// +v on structs with Stringable items
- fmtTest{"%+v", B{1, 2}, `{i:<1> j:2}`},
- fmtTest{"%+v", C{1, B{2, 3}}, `{i:1 B:{i:<2> j:3}}`},
+ {"%+v", B{1, 2}, `{i:<1> j:2}`},
+ {"%+v", C{1, B{2, 3}}, `{i:1 B:{i:<2> j:3}}`},
// q on Stringable items
- fmtTest{"%s", I(23), `<23>`},
- fmtTest{"%q", I(23), `"<23>"`},
- fmtTest{"%x", I(23), `3c32333e`},
- fmtTest{"%d", I(23), `%d(string=<23>)`},
-
- // %p on non-pointers
- fmtTest{"%p", make(chan int), "PTR"},
- fmtTest{"%p", make(map[int]int), "PTR"},
- fmtTest{"%p", make([]int, 1), "PTR"},
+ {"%s", I(23), `<23>`},
+ {"%q", I(23), `"<23>"`},
+ {"%x", I(23), `3c32333e`},
+ {"%d", I(23), `%!d(string=<23>)`},
// go syntax
- fmtTest{"%#v", A{1, 2, "a", []int{1, 2}}, `fmt_test.A{i:1, j:0x2, s:"a", x:[]int{1, 2}}`},
- fmtTest{"%#v", &b, "(*uint8)(PTR)"},
- fmtTest{"%#v", TestFmtInterface, "(func(*testing.T))(PTR)"},
- fmtTest{"%#v", make(chan int), "(chan int)(PTR)"},
- fmtTest{"%#v", uint64(1<<64 - 1), "0xffffffffffffffff"},
- fmtTest{"%#v", 1000000000, "1000000000"},
- fmtTest{"%#v", map[string]int{"a": 1, "b": 2}, `map[string] int{"a":1, "b":2}`},
- fmtTest{"%#v", map[string]B{"a": B{1, 2}, "b": B{3, 4}}, `map[string] fmt_test.B{"a":fmt_test.B{i:1, j:2}, "b":fmt_test.B{i:3, j:4}}`},
- fmtTest{"%#v", []string{"a", "b"}, `[]string{"a", "b"}`},
+ {"%#v", A{1, 2, "a", []int{1, 2}}, `fmt_test.A{i:1, j:0x2, s:"a", x:[]int{1, 2}}`},
+ {"%#v", &b, "(*uint8)(PTR)"},
+ {"%#v", TestFmtInterface, "(func(*testing.T))(PTR)"},
+ {"%#v", make(chan int), "(chan int)(PTR)"},
+ {"%#v", uint64(1<<64 - 1), "0xffffffffffffffff"},
+ {"%#v", 1000000000, "1000000000"},
+ {"%#v", map[string]int{"a": 1, "b": 2}, `map[string] int{"a":1, "b":2}`},
+ {"%#v", map[string]B{"a": {1, 2}, "b": {3, 4}}, `map[string] fmt_test.B{"a":fmt_test.B{i:1, j:2}, "b":fmt_test.B{i:3, j:4}}`},
+ {"%#v", []string{"a", "b"}, `[]string{"a", "b"}`},
// slices with other formats
- fmtTest{"%#x", []int{1, 2, 15}, `[0x1 0x2 0xf]`},
- fmtTest{"%x", []int{1, 2, 15}, `[1 2 f]`},
- fmtTest{"%q", []string{"a", "b"}, `["a" "b"]`},
+ {"%#x", []int{1, 2, 15}, `[0x1 0x2 0xf]`},
+ {"%x", []int{1, 2, 15}, `[1 2 f]`},
+ {"%d", []int{1, 2, 15}, `[1 2 15]`},
+ {"%d", []byte{1, 2, 15}, `[1 2 15]`},
+ {"%q", []string{"a", "b"}, `["a" "b"]`},
// renamings
- fmtTest{"%v", renamedBool(true), "true"},
- fmtTest{"%d", renamedBool(true), "%d(fmt_test.renamedBool=true)"},
- fmtTest{"%o", renamedInt(8), "10"},
- fmtTest{"%d", renamedInt8(-9), "-9"},
- fmtTest{"%v", renamedInt16(10), "10"},
- fmtTest{"%v", renamedInt32(-11), "-11"},
- fmtTest{"%X", renamedInt64(255), "FF"},
- fmtTest{"%v", renamedUint(13), "13"},
- fmtTest{"%o", renamedUint8(14), "16"},
- fmtTest{"%X", renamedUint16(15), "F"},
- fmtTest{"%d", renamedUint32(16), "16"},
- fmtTest{"%X", renamedUint64(17), "11"},
- fmtTest{"%o", renamedUintptr(18), "22"},
- fmtTest{"%x", renamedString("thing"), "7468696e67"},
- // TODO: It would be nice if this one worked, but it's hard.
- // fmtTest{"%q", renamedBytes([]byte("hello")), `"hello"`},
- fmtTest{"%v", renamedFloat(11), "11"},
- fmtTest{"%v", renamedFloat32(22), "22"},
- fmtTest{"%v", renamedFloat64(33), "33"},
- fmtTest{"%v", renamedComplex(7 + .2i), "(7+0.2i)"},
- fmtTest{"%v", renamedComplex64(3 + 4i), "(3+4i)"},
- fmtTest{"%v", renamedComplex128(4 - 3i), "(4-3i)"},
+ {"%v", renamedBool(true), "true"},
+ {"%d", renamedBool(true), "%!d(fmt_test.renamedBool=true)"},
+ {"%o", renamedInt(8), "10"},
+ {"%d", renamedInt8(-9), "-9"},
+ {"%v", renamedInt16(10), "10"},
+ {"%v", renamedInt32(-11), "-11"},
+ {"%X", renamedInt64(255), "FF"},
+ {"%v", renamedUint(13), "13"},
+ {"%o", renamedUint8(14), "16"},
+ {"%X", renamedUint16(15), "F"},
+ {"%d", renamedUint32(16), "16"},
+ {"%X", renamedUint64(17), "11"},
+ {"%o", renamedUintptr(18), "22"},
+ {"%x", renamedString("thing"), "7468696e67"},
+ {"%d", renamedBytes([]byte{1, 2, 15}), `[1 2 15]`},
+ {"%q", renamedBytes([]byte("hello")), `"hello"`},
+ {"%v", renamedFloat(11), "11"},
+ {"%v", renamedFloat32(22), "22"},
+ {"%v", renamedFloat64(33), "33"},
+ {"%v", renamedComplex(7 + .2i), "(7+0.2i)"},
+ {"%v", renamedComplex64(3 + 4i), "(3+4i)"},
+ {"%v", renamedComplex128(4 - 3i), "(4-3i)"},
+
+ // Formatter
+ {"%x", F(1), "<x=F(1)>"},
+ {"%x", G(2), "2"},
+ {"%+v", S{F(4), G(5)}, "{f:<v=F(4)> g:5}"},
+
+ // GoStringer
+ {"%#v", G(6), "GoString(6)"},
+ {"%#v", S{F(7), G(8)}, "fmt_test.S{f:<v=F(7)>, g:GoString(8)}"},
// %T
- fmtTest{"%T", (4 - 3i), "complex"},
- fmtTest{"%T", renamedComplex128(4 - 3i), "fmt_test.renamedComplex128"},
- fmtTest{"%T", intVal, "int"},
- fmtTest{"%6T", &intVal, " *int"},
+ {"%T", (4 - 3i), "complex"},
+ {"%T", renamedComplex128(4 - 3i), "fmt_test.renamedComplex128"},
+ {"%T", intVal, "int"},
+ {"%6T", &intVal, " *int"},
+
+ // %p
+ {"p0=%p", new(int), "p0=PTR"},
+ {"p1=%s", &pValue, "p1=String(p)"}, // String method...
+ {"p2=%p", &pValue, "p2=PTR"}, // ... not called with %p
+
+ // %p on non-pointers
+ {"%p", make(chan int), "PTR"},
+ {"%p", make(map[int]int), "PTR"},
+ {"%p", make([]int, 1), "PTR"},
+ {"%p", 27, "%!p(int=27)"}, // not a pointer at all
// erroneous things
- fmtTest{"%d", "hello", "%d(string=hello)"},
- fmtTest{"no args", "hello", "no args?(extra string=hello)"},
- fmtTest{"%s", nil, "%s(<nil>)"},
- fmtTest{"%T", nil, "<nil>"},
- fmtTest{"%-1", 100, "%1(int=100)"},
+ {"%s %", "hello", "hello %!(NOVERB)"},
+ {"%s %.2", "hello", "hello %!(NOVERB)"},
+ {"%d", "hello", "%!d(string=hello)"},
+ {"no args", "hello", "no args%!(EXTRA string=hello)"},
+ {"%s", nil, "%!s(<nil>)"},
+ {"%T", nil, "<nil>"},
+ {"%-1", 100, "%!(NOVERB)%!(EXTRA int=100)"},
}
func TestSprintf(t *testing.T) {
for _, tt := range fmttests {
s := Sprintf(tt.fmt, tt.val)
- if i := strings.Index(s, "0x"); i >= 0 && strings.Index(tt.out, "PTR") >= 0 {
+ if i := strings.Index(s, "0x"); i >= 0 && strings.Contains(tt.out, "PTR") {
j := i + 2
for ; j < len(s); j++ {
c := s[j]
@@ -385,6 +438,12 @@ func BenchmarkSprintfIntInt(b *testing.B) {
}
}
+func BenchmarkSprintfPrefixedInt(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Sprintf("This is some meaningless prefix text that needs to be scanned %d", 6)
+ }
+}
+
func TestCountMallocs(t *testing.T) {
mallocs := 0 - runtime.MemStats.Mallocs
for i := 0; i < 100; i++ {
@@ -431,24 +490,22 @@ func (*flagPrinter) Format(f State, c int) {
io.WriteString(f, "["+s+"]")
}
-type flagTest struct {
+var flagtests = []struct {
in string
out string
-}
-
-var flagtests = []flagTest{
- flagTest{"%a", "[%a]"},
- flagTest{"%-a", "[%-a]"},
- flagTest{"%+a", "[%+a]"},
- flagTest{"%#a", "[%#a]"},
- flagTest{"% a", "[% a]"},
- flagTest{"%0a", "[%0a]"},
- flagTest{"%1.2a", "[%1.2a]"},
- flagTest{"%-1.2a", "[%-1.2a]"},
- flagTest{"%+1.2a", "[%+1.2a]"},
- flagTest{"%-+1.2a", "[%+-1.2a]"},
- flagTest{"%-+1.2abc", "[%+-1.2a]bc"},
- flagTest{"%-1.2abc", "[%-1.2a]bc"},
+}{
+ {"%a", "[%a]"},
+ {"%-a", "[%-a]"},
+ {"%+a", "[%+a]"},
+ {"%#a", "[%#a]"},
+ {"% a", "[% a]"},
+ {"%0a", "[%0a]"},
+ {"%1.2a", "[%1.2a]"},
+ {"%-1.2a", "[%-1.2a]"},
+ {"%+1.2a", "[%+1.2a]"},
+ {"%-+1.2a", "[%+-1.2a]"},
+ {"%-+1.2abc", "[%+-1.2a]bc"},
+ {"%-1.2abc", "[%-1.2a]bc"},
}
func TestFlagParser(t *testing.T) {
@@ -470,13 +527,12 @@ func TestStructPrinter(t *testing.T) {
s.a = "abc"
s.b = "def"
s.c = 123
- type Test struct {
+ var tests = []struct {
fmt string
out string
- }
- var tests = []Test{
- Test{"%v", "{abc def 123}"},
- Test{"%+v", "{a:abc b:def c:123}"},
+ }{
+ {"%v", "{abc def 123}"},
+ {"%+v", "{a:abc b:def c:123}"},
}
for _, tt := range tests {
out := Sprintf(tt.fmt, s)
@@ -526,3 +582,73 @@ func TestEmptyMap(t *testing.T) {
t.Errorf("empty map printed as %q not %q", s, emptyMapStr)
}
}
+
+// Check that Sprint (and hence Print, Fprint) puts spaces in the right places,
+// that is, between arg pairs in which neither is a string.
+func TestBlank(t *testing.T) {
+ got := Sprint("<", 1, ">:", 1, 2, 3, "!")
+ expect := "<1>:1 2 3!"
+ if got != expect {
+ t.Errorf("got %q expected %q", got, expect)
+ }
+}
+
+// Check that Sprintln (and hence Println, Fprintln) puts spaces in the right places,
+// that is, between all arg pairs.
+func TestBlankln(t *testing.T) {
+ got := Sprintln("<", 1, ">:", 1, 2, 3, "!")
+ expect := "< 1 >: 1 2 3 !\n"
+ if got != expect {
+ t.Errorf("got %q expected %q", got, expect)
+ }
+}
+
+
+// Check Formatter with Sprint, Sprintln, Sprintf
+func TestFormatterPrintln(t *testing.T) {
+ f := F(1)
+ expect := "<v=F(1)>\n"
+ s := Sprint(f, "\n")
+ if s != expect {
+ t.Errorf("Sprint wrong with Formatter: expected %q got %q", expect, s)
+ }
+ s = Sprintln(f)
+ if s != expect {
+ t.Errorf("Sprintln wrong with Formatter: expected %q got %q", expect, s)
+ }
+ s = Sprintf("%v\n", f)
+ if s != expect {
+ t.Errorf("Sprintf wrong with Formatter: expected %q got %q", expect, s)
+ }
+}
+
+func args(a ...interface{}) []interface{} { return a }
+
+var startests = []struct {
+ fmt string
+ in []interface{}
+ out string
+}{
+ {"%*d", args(4, 42), " 42"},
+ {"%.*d", args(4, 42), "0042"},
+ {"%*.*d", args(8, 4, 42), " 0042"},
+ {"%0*d", args(4, 42), "0042"},
+ {"%-*d", args(4, 42), "42 "},
+
+ // erroneous
+ {"%*d", args(nil, 42), "%!(BADWIDTH)42"},
+ {"%.*d", args(nil, 42), "%!(BADPREC)42"},
+ {"%*d", args(5, "foo"), "%!d(string= foo)"},
+ {"%*% %d", args(20, 5), "% 5"},
+ {"%*", args(4), "%!(NOVERB)"},
+ {"%*d", args(int32(4), 42), "%!(BADWIDTH)42"},
+}
+
+func TestWidthAndPrecision(t *testing.T) {
+ for _, tt := range startests {
+ s := Sprintf(tt.fmt, tt.in...)
+ if s != tt.out {
+ t.Errorf("%q: got %q expected %q", tt.fmt, s, tt.out)
+ }
+ }
+}
diff --git a/src/pkg/fmt/format.go b/src/pkg/fmt/format.go
index 3ec1cf139..0121dda31 100644
--- a/src/pkg/fmt/format.go
+++ b/src/pkg/fmt/format.go
@@ -49,6 +49,7 @@ type fmt struct {
plus bool
sharp bool
space bool
+ unicode bool
zero bool
}
@@ -61,6 +62,7 @@ func (f *fmt) clearflags() {
f.plus = false
f.sharp = false
f.space = false
+ f.unicode = false
f.zero = false
}
@@ -213,6 +215,12 @@ func (f *fmt) integer(a int64, base uint64, signedness bool, digits string) {
buf[i] = '0'
}
}
+ if f.unicode {
+ i--
+ buf[i] = '+'
+ i--
+ buf[i] = 'U'
+ }
if negative {
i--
@@ -255,6 +263,9 @@ func (f *fmt) fmt_sx(s string) {
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])
diff --git a/src/pkg/fmt/print.go b/src/pkg/fmt/print.go
index 20bfa9107..412260441 100644
--- a/src/pkg/fmt/print.go
+++ b/src/pkg/fmt/print.go
@@ -2,132 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-/*
- Package fmt implements formatted I/O with functions analogous
- to C's printf and scanf. The format 'verbs' are derived from C's but
- are simpler.
-
- Printing:
-
- The verbs:
-
- General:
- %v the value in a default format.
- when printing structs, the plus flag (%+v) adds field names
- %#v a Go-syntax representation of the value
- %T a Go-syntax representation of the type of the value
-
- Boolean:
- %t the word true or false
- Integer:
- %b base 2
- %c the character represented by the corresponding Unicode code point
- %d base 10
- %o base 8
- %x base 16, with lower-case letters for a-f
- %X base 16, with upper-case letters for A-F
- Floating-point and complex constituents:
- %e scientific notation, e.g. -1234.456e+78
- %E scientific notation, e.g. -1234.456E+78
- %f decimal point but no exponent, e.g. 123.456
- %g whichever of %e or %f produces more compact output
- %G whichever of %E or %f produces more compact output
- String and slice of bytes:
- %s the uninterpreted bytes of the string or slice
- %q a double-quoted string safely escaped with Go syntax
- %x base 16 notation with two characters per byte
- Pointer:
- %p base 16 notation, with leading 0x
-
- There is no 'u' flag. Integers are printed unsigned if they have unsigned type.
- Similarly, there is no need to specify the size of the operand (int8, int64).
-
- For numeric values, the width and precision flags control
- formatting; width sets the width of the field, precision the
- number of places after the decimal, if appropriate. The
- format %6.2f prints 123.45. The width of a field is the number
- of Unicode code points in the string. This differs from C's printf where
- the field width is the number of bytes.
-
- Other flags:
- + always print a sign for numeric values
- - pad with spaces on the right rather than the left (left-justify the field)
- # alternate format: add leading 0 for octal (%#o), 0x for hex (%#x);
- suppress 0x for %p (%#p);
- print a raw (backquoted) string if possible for %q (%#q)
- ' ' (space) leave a space for elided sign in numbers (% d);
- put spaces between bytes printing strings or slices in hex (% x)
- 0 pad with leading zeros rather than spaces
-
- For each Printf-like function, there is also a Print function
- that takes no format and is equivalent to saying %v for every
- operand. Another variant Println inserts blanks between
- operands and appends a newline.
-
- Regardless of the verb, if an operand is an interface value,
- the internal concrete value is used, not the interface itself.
- Thus:
- var i interface{} = 23;
- fmt.Printf("%v\n", i);
- will print 23.
-
- If an operand implements interface Formatter, that interface
- can be used for fine control of formatting.
-
- If an operand implements method String() string that method
- will be used to conver 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)) }
-
- Scanning:
-
- An analogous set of functions scans formatted text to yield
- values. Scan, Scanf and Scanln read from os.Stdin; Fscan,
- Fscanf and Fscanln read from a specified os.Reader; Sscan,
- Sscanf and Sscanln read from an argument string. Sscanln,
- Fscanln and Sscanln stop scanning at a newline and require that
- the items be followed by one; the other routines treat newlines
- as spaces.
-
- Scanf, Fscanf, and Sscanf parse the arguments according to a
- format string, analogous to that of Printf. For example, "%x"
- will scan an integer as a hexadecimal number, and %v will scan
- the default representation format for the value.
-
- The formats behave analogously to those of Printf with the
- following exceptions:
-
- %p is not implemented
- %T is not implemented
- %e %E %f %F %g %g are all equivalent and scan any floating
- point or complex value
- %s and %v on strings scan a space-delimited token
-
- Width is interpreted in the input text (%5s means at most
- five runes of input will be read to scan a string) but there
- is no syntax for scanning with a precision (no %5.2f, just
- %5f).
-
- When scanning with a format, all non-empty runs of space
- characters (including newline) are equivalent to a single
- space in both the format and the input. With that proviso,
- text in the format string must match the input text; scanning
- stops if it does not, with the return value of the function
- indicating the number of arguments scanned.
-
- In all the scanning functions, if an operand implements method
- Scan (that is, it implements the Scanner interface) that
- method will be used to scan the text for that operand. Also,
- if the number of arguments scanned is less than the number of
- arguments provided, an error is returned.
-
- All arguments to be scanned must be either pointers to basic
- types or implementations of the Scanner interface.
-*/
package fmt
import (
@@ -146,10 +20,13 @@ var (
nilParenBytes = []byte("(nil)")
nilBytes = []byte("nil")
mapBytes = []byte("map[")
- missingBytes = []byte("missing")
- extraBytes = []byte("?(extra ")
+ missingBytes = []byte("(MISSING)")
+ extraBytes = []byte("%!(EXTRA ")
irparenBytes = []byte("i)")
bytesBytes = []byte("[]byte{")
+ widthBytes = []byte("%!(BADWIDTH)")
+ precBytes = []byte("%!(BADPREC)")
+ noVerbBytes = []byte("%!(NOVERB)")
)
// State represents the printer state passed to custom formatters.
@@ -241,12 +118,7 @@ func (p *pp) Flag(b int) bool {
}
func (p *pp) add(c int) {
- if c < utf8.RuneSelf {
- p.buf.WriteByte(byte(c))
- } else {
- w := utf8.EncodeRune(c, p.runeBuf[0:])
- p.buf.Write(p.runeBuf[0:w])
- }
+ p.buf.WriteRune(c)
}
// Implement Write so we can call Fprintf on a pp (through State), for
@@ -258,6 +130,7 @@ func (p *pp) Write(b []byte) (ret int, err os.Error) {
// These routines end in 'f' and take a format string.
// Fprintf formats according to a format specifier and writes to w.
+// It returns the number of bytes written and any write error encountered.
func Fprintf(w io.Writer, format string, a ...interface{}) (n int, error os.Error) {
p := newPrinter()
p.doPrintf(format, a)
@@ -267,8 +140,9 @@ func Fprintf(w io.Writer, format string, a ...interface{}) (n int, error os.Erro
}
// Printf formats according to a format specifier and writes to standard output.
+// It returns the number of bytes written and any write error encountered.
func Printf(format string, a ...interface{}) (n int, errno os.Error) {
- n, errno = Fprintf(os.Stdout, format, a)
+ n, errno = Fprintf(os.Stdout, format, a...)
return n, errno
}
@@ -281,10 +155,17 @@ func Sprintf(format string, a ...interface{}) string {
return s
}
+// Errorf formats according to a format specifier and returns the string
+// converted to an os.ErrorString, which satisfies the os.Error interface.
+func Errorf(format string, a ...interface{}) os.Error {
+ return os.ErrorString(Sprintf(format, a...))
+}
+
// These routines do not take a format string
// Fprint formats using the default formats for its operands and writes to w.
// Spaces are added between operands when neither is a string.
+// It returns the number of bytes written and any write error encountered.
func Fprint(w io.Writer, a ...interface{}) (n int, error os.Error) {
p := newPrinter()
p.doPrint(a, false, false)
@@ -295,8 +176,9 @@ func Fprint(w io.Writer, a ...interface{}) (n int, error 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, errno os.Error) {
- n, errno = Fprint(os.Stdout, a)
+ n, errno = Fprint(os.Stdout, a...)
return n, errno
}
@@ -316,6 +198,7 @@ func Sprint(a ...interface{}) string {
// Fprintln formats using the default formats for its operands and writes to w.
// Spaces are always added between operands and a newline is appended.
+// It returns the number of bytes written and any write error encountered.
func Fprintln(w io.Writer, a ...interface{}) (n int, error os.Error) {
p := newPrinter()
p.doPrint(a, true, true)
@@ -326,8 +209,9 @@ func Fprintln(w io.Writer, a ...interface{}) (n int, error 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, errno os.Error) {
- n, errno = Fprintln(os.Stdout, a)
+ n, errno = Fprintln(os.Stdout, a...)
return n, errno
}
@@ -384,6 +268,7 @@ func (p *pp) unknownType(v interface{}) {
func (p *pp) badVerb(verb int, val interface{}) {
p.add('%')
+ p.add('!')
p.add(verb)
p.add('(')
if val == nil {
@@ -411,7 +296,7 @@ func (p *pp) fmtC(c int64) {
if int64(rune) != c {
rune = utf8.RuneError
}
- w := utf8.EncodeRune(rune, p.runeBuf[0:utf8.UTFMax])
+ w := utf8.EncodeRune(p.runeBuf[0:utf8.UTFMax], rune)
p.fmt.pad(p.runeBuf[0:w])
}
@@ -427,6 +312,8 @@ func (p *pp) fmtInt64(v int64, verb int, value interface{}) {
p.fmt.integer(v, 8, signed, ldigits)
case 'x':
p.fmt.integer(v, 16, signed, ldigits)
+ case 'U':
+ p.fmtUnicode(v)
case 'X':
p.fmt.integer(v, 16, signed, udigits)
default:
@@ -434,7 +321,7 @@ func (p *pp) fmtInt64(v int64, verb int, value interface{}) {
}
}
-// fmt_sharpHex64 formats a uint64 in hexadecimal and prefixes it with 0x by
+// fmt0x64 formats a uint64 in hexadecimal and prefixes it with 0x by
// temporarily turning on the sharp flag.
func (p *pp) fmt0x64(v uint64) {
sharp := p.fmt.sharp
@@ -443,6 +330,23 @@ func (p *pp) fmt0x64(v uint64) {
p.fmt.sharp = sharp
}
+// fmtUnicode formats a uint64 in U+1234 form by
+// temporarily turning on the unicode flag and tweaking the precision.
+func (p *pp) fmtUnicode(v int64) {
+ precPresent := p.fmt.precPresent
+ prec := p.fmt.prec
+ if !precPresent {
+ // If prec is already set, leave it alone; otherwise 4 is minimum.
+ p.fmt.prec = 4
+ p.fmt.precPresent = true
+ }
+ p.fmt.unicode = true // turn on U+
+ p.fmt.integer(int64(v), 16, unsigned, udigits)
+ p.fmt.unicode = false
+ p.fmt.prec = prec
+ p.fmt.precPresent = precPresent
+}
+
func (p *pp) fmtUint64(v uint64, verb int, goSyntax bool, value interface{}) {
switch verb {
case 'b':
@@ -550,7 +454,7 @@ func (p *pp) fmtString(v string, verb int, goSyntax bool, value interface{}) {
}
func (p *pp) fmtBytes(v []byte, verb int, goSyntax bool, depth int, value interface{}) {
- if verb == 'v' {
+ if verb == 'v' || verb == 'd' {
if goSyntax {
p.buf.Write(bytesBytes)
} else {
@@ -588,13 +492,14 @@ func (p *pp) fmtBytes(v []byte, verb int, goSyntax bool, depth int, value interf
}
}
-func (p *pp) fmtUintptrGetter(field interface{}, value reflect.Value, verb int, sharp bool) bool {
+func (p *pp) fmtPointer(field interface{}, value reflect.Value, verb int, goSyntax bool) {
v, ok := value.(uintptrGetter)
- if !ok {
- return false
+ if !ok { // reflect.PtrValue is a uintptrGetter, so failure means it's not a pointer at all.
+ p.badVerb(verb, field)
+ return
}
u := v.Get()
- if sharp {
+ if goSyntax {
p.add('(')
p.buf.WriteString(reflect.Typeof(field).String())
p.add(')')
@@ -608,7 +513,6 @@ func (p *pp) fmtUintptrGetter(field interface{}, value reflect.Value, verb int,
} else {
p.fmt0x64(uint64(u))
}
- return true
}
var (
@@ -618,19 +522,49 @@ var (
uintptrBits = reflect.Typeof(uintptr(0)).Bits()
)
-func (p *pp) printField(field interface{}, verb int, plus, goSyntax bool, depth int) (was_string bool) {
- if field != nil {
- switch {
- default:
- if stringer, ok := field.(Stringer); ok {
- p.printField(stringer.String(), verb, plus, goSyntax, depth)
- return false // this value is not a string
- }
- case goSyntax:
- if stringer, ok := field.(GoStringer); ok {
- p.printField(stringer.GoString(), verb, plus, goSyntax, depth)
- return false // this value is not a string
- }
+func (p *pp) printField(field interface{}, verb int, plus, goSyntax bool, depth int) (wasString bool) {
+ if field == nil {
+ if verb == 'T' || verb == 'v' {
+ p.buf.Write(nilAngleBytes)
+ } else {
+ p.badVerb(verb, field)
+ }
+ return false
+ }
+
+ // Special processing considerations.
+ // %T (the value's type) and %p (its address) are special; we always do them first.
+ switch verb {
+ case 'T':
+ p.printField(reflect.Typeof(field).String(), 's', false, false, 0)
+ return false
+ case 'p':
+ p.fmtPointer(field, reflect.NewValue(field), verb, goSyntax)
+ return false
+ }
+ // Is it a Formatter?
+ if formatter, ok := field.(Formatter); ok {
+ formatter.Format(p, verb)
+ return false // this value is not a string
+
+ }
+ // Must not touch flags before Formatter looks at them.
+ if plus {
+ p.fmt.plus = false
+ }
+ // If we're doing Go syntax and the field knows how to supply it, take care of it now.
+ if goSyntax {
+ p.fmt.sharp = false
+ if stringer, ok := field.(GoStringer); ok {
+ // Print the result of GoString unadorned.
+ p.fmtString(stringer.GoString(), 's', false, field)
+ return false // this value is not a string
+ }
+ } else {
+ // Is it a Stringer?
+ if stringer, ok := field.(Stringer); ok {
+ p.printField(stringer.String(), verb, plus, false, depth)
+ return false // this value is not a string
}
}
@@ -706,21 +640,8 @@ func (p *pp) printField(field interface{}, verb int, plus, goSyntax bool, depth
return verb == 's'
}
- if field == nil {
- if verb == 'v' {
- p.buf.Write(nilAngleBytes)
- } else {
- p.badVerb(verb, field)
- }
- return false
- }
-
- value := reflect.NewValue(field)
// Need to use reflection
- // Special case for reflection values that know how to print with %p.
- if verb == 'p' && p.fmtUintptrGetter(field, value, verb, goSyntax) { // TODO: is this goSyntax right?
- return false
- }
+ value := reflect.NewValue(field)
BigSwitch:
switch f := value.(type) {
@@ -806,6 +727,22 @@ BigSwitch:
return p.printField(value.Interface(), verb, plus, goSyntax, depth+1)
}
case reflect.ArrayOrSliceValue:
+ // Byte slices are special.
+ if f.Type().(reflect.ArrayOrSliceType).Elem().Kind() == reflect.Uint8 {
+ // We know it's a slice of bytes, but we also know it does not have static type
+ // []byte, or it would have been caught above. Therefore we cannot convert
+ // it directly in the (slightly) obvious way: f.Interface().([]byte); it doesn't have
+ // that type, and we can't write an expression of the right type and do a
+ // conversion because we don't have a static way to write the right type.
+ // So we build a slice by hand. This is a rare case but it would be nice
+ // if reflection could help a little more.
+ bytes := make([]byte, f.Len())
+ for i := range bytes {
+ bytes[i] = byte(f.Elem(i).(*reflect.UintValue).Get())
+ }
+ p.fmtBytes(bytes, verb, goSyntax, depth, field)
+ return verb == 's'
+ }
if goSyntax {
p.buf.WriteString(reflect.Typeof(field).String())
p.buf.WriteByte('{')
@@ -862,30 +799,40 @@ BigSwitch:
}
p.fmt0x64(uint64(v))
case uintptrGetter:
- if p.fmtUintptrGetter(field, value, verb, goSyntax) {
- break
- }
- p.unknownType(f)
+ p.fmtPointer(field, value, verb, goSyntax)
default:
p.unknownType(f)
}
return false
}
+// intFromArg gets the fieldnumth element of a. On return, isInt reports whether the argument has type int.
+func intFromArg(a []interface{}, end, i, fieldnum int) (num int, isInt bool, newi, newfieldnum int) {
+ newi, newfieldnum = end, fieldnum
+ if i < end && fieldnum < len(a) {
+ num, isInt = a[fieldnum].(int)
+ newi, newfieldnum = i+1, fieldnum+1
+ }
+ return
+}
+
func (p *pp) doPrintf(format string, a []interface{}) {
- end := len(format) - 1
+ end := len(format)
fieldnum := 0 // we process one field per non-trivial format
- for i := 0; i <= end; {
- c, w := utf8.DecodeRuneInString(format[i:])
- if c != '%' || i == end {
- if w == 1 {
- p.buf.WriteByte(byte(c))
- } else {
- p.buf.WriteString(format[i : i+w])
- }
- i += w
- continue
+ for i := 0; i < end; {
+ lasti := i
+ for i < end && format[i] != '%' {
+ i++
}
+ if i > lasti {
+ p.buf.WriteString(format[lasti:i])
+ }
+ if i >= end {
+ // done processing format string
+ break
+ }
+
+ // Process one verb
i++
// flags and widths
p.fmt.clearflags()
@@ -906,17 +853,35 @@ func (p *pp) doPrintf(format string, a []interface{}) {
break F
}
}
- // do we have 20 (width)?
- p.fmt.wid, p.fmt.widPresent, i = parsenum(format, i, end)
- // do we have .20 (precision)?
+ // do we have width?
+ if i < end && format[i] == '*' {
+ p.fmt.wid, p.fmt.widPresent, i, fieldnum = intFromArg(a, end, i, fieldnum)
+ if !p.fmt.widPresent {
+ p.buf.Write(widthBytes)
+ }
+ } else {
+ p.fmt.wid, p.fmt.widPresent, i = parsenum(format, i, end)
+ }
+ // do we have precision?
if i < end && format[i] == '.' {
- p.fmt.prec, p.fmt.precPresent, i = parsenum(format, i+1, end)
+ if format[i+1] == '*' {
+ p.fmt.prec, p.fmt.precPresent, i, fieldnum = intFromArg(a, end, i+1, fieldnum)
+ if !p.fmt.precPresent {
+ p.buf.Write(precBytes)
+ }
+ } else {
+ p.fmt.prec, p.fmt.precPresent, i = parsenum(format, i+1, end)
+ }
}
- c, w = utf8.DecodeRuneInString(format[i:])
+ if i >= end {
+ p.buf.Write(noVerbBytes)
+ continue
+ }
+ c, w := utf8.DecodeRuneInString(format[i:])
i += w
// percent is special - absorbs no operand
if c == '%' {
- p.buf.WriteByte('%') // TODO: should we bother with width & prec?
+ p.buf.WriteByte('%') // We ignore width and prec.
continue
}
if fieldnum >= len(a) { // out of operands
@@ -928,33 +893,8 @@ func (p *pp) doPrintf(format string, a []interface{}) {
field := a[fieldnum]
fieldnum++
- // %T is special; we always do it here.
- if c == 'T' {
- // the value's type
- if field == nil {
- p.buf.Write(nilAngleBytes)
- break
- }
- p.printField(reflect.Typeof(field).String(), 's', false, false, 0)
- continue
- }
-
- // Try Formatter (except for %T).
- if field != nil {
- if formatter, ok := field.(Formatter); ok {
- formatter.Format(p, c)
- continue
- }
- }
-
goSyntax := c == 'v' && p.fmt.sharp
- if goSyntax {
- p.fmt.sharp = false
- }
plus := c == 'v' && p.fmt.plus
- if plus {
- p.fmt.plus = false
- }
p.printField(field, c, plus, goSyntax, 0)
}
@@ -976,18 +916,18 @@ func (p *pp) doPrintf(format string, a []interface{}) {
}
func (p *pp) doPrint(a []interface{}, addspace, addnewline bool) {
- prev_string := false
+ prevString := false
for fieldnum := 0; fieldnum < len(a); fieldnum++ {
p.fmt.clearflags()
// always add spaces if we're doing println
field := a[fieldnum]
if fieldnum > 0 {
- _, is_string := field.(*reflect.StringValue)
- if addspace || !is_string && !prev_string {
+ isString := field != nil && reflect.Typeof(field).Kind() == reflect.String
+ if addspace || !isString && !prevString {
p.buf.WriteByte(' ')
}
}
- prev_string = p.printField(field, 'v', false, false, 0)
+ prevString = p.printField(field, 'v', false, false, 0)
}
if addnewline {
p.buf.WriteByte('\n')
diff --git a/src/pkg/fmt/scan.go b/src/pkg/fmt/scan.go
index ded1f7719..dcc42bc92 100644
--- a/src/pkg/fmt/scan.go
+++ b/src/pkg/fmt/scan.go
@@ -22,6 +22,14 @@ type readRuner interface {
ReadRune() (rune int, size int, err os.Error)
}
+// unreadRuner is the interface to something that can unread runes.
+// If the object provided to Scan does not satisfy this interface,
+// a local buffer will be used to back up the input, but its contents
+// will be lost when Scan returns.
+type unreadRuner interface {
+ UnreadRune() os.Error
+}
+
// ScanState represents the scanner state passed to custom scanners.
// Scanners may do rune-at-a-time scanning or ask the ScanState
// to discover the next space-delimited token.
@@ -29,7 +37,7 @@ type ScanState interface {
// GetRune reads the next rune (Unicode code point) from the input.
GetRune() (rune int, err os.Error)
// UngetRune causes the next call to GetRune to return the rune.
- UngetRune(rune int)
+ UngetRune()
// Width returns the value of the width option and whether it has been set.
// The unit is Unicode code points.
Width() (wid int, ok bool)
@@ -52,20 +60,20 @@ type Scanner interface {
// as space. It returns the number of items successfully scanned.
// If that is less than the number of arguments, err will report why.
func Scan(a ...interface{}) (n int, err os.Error) {
- return Fscan(os.Stdin, a)
+ return Fscan(os.Stdin, a...)
}
// Scanln is similar to Scan, but stops scanning at a newline and
// after the final item there must be a newline or EOF.
func Scanln(a ...interface{}) (n int, err os.Error) {
- return Fscanln(os.Stdin, a)
+ return Fscanln(os.Stdin, a...)
}
// Scanf scans text read from standard input, storing successive
// space-separated values into successive arguments as determined by
// the format. It returns the number of items successfully scanned.
func Scanf(format string, a ...interface{}) (n int, err os.Error) {
- return Fscanf(os.Stdin, format, a)
+ return Fscanf(os.Stdin, format, a...)
}
// Sscan scans the argument string, storing successive space-separated
@@ -73,20 +81,20 @@ func Scanf(format string, a ...interface{}) (n int, err os.Error) {
// 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)
+ return Fscan(strings.NewReader(str), a...)
}
// Sscanln is similar to Sscan, but stops scanning at a newline and
// after the final item there must be a newline or EOF.
func Sscanln(str string, a ...interface{}) (n int, err os.Error) {
- return Fscanln(strings.NewReader(str), a)
+ return Fscanln(strings.NewReader(str), a...)
}
// Sscanf scans the argument string, storing successive space-separated
// values into successive arguments as determined by the format. It
// returns the number of items successfully parsed.
func Sscanf(str string, format string, a ...interface{}) (n int, err os.Error) {
- return Fscanf(strings.NewReader(str), format, a)
+ return Fscanf(strings.NewReader(str), format, a...)
}
// Fscan scans text read from r, storing successive space-separated
@@ -133,6 +141,7 @@ type ss struct {
buf bytes.Buffer // token accumulator
nlIsSpace bool // whether newline counts as white space
peekRune int // one-rune lookahead
+ prevRune int // last rune returned by GetRune
atEOF bool // already read EOF
maxWid int // max width of field, in runes
widPresent bool // width was specified
@@ -142,10 +151,14 @@ type ss struct {
func (s *ss) GetRune() (rune int, err os.Error) {
if s.peekRune >= 0 {
rune = s.peekRune
+ s.prevRune = rune
s.peekRune = -1
return
}
rune, _, err = s.rr.ReadRune()
+ if err == nil {
+ s.prevRune = rune
+ }
return
}
@@ -161,11 +174,14 @@ func (s *ss) getRune() (rune int) {
}
if s.peekRune >= 0 {
rune = s.peekRune
+ s.prevRune = rune
s.peekRune = -1
return
}
rune, _, err := s.rr.ReadRune()
- if err != nil {
+ if err == nil {
+ s.prevRune = rune
+ } else if err != nil {
if err == os.EOF {
s.atEOF = true
return EOF
@@ -198,8 +214,12 @@ func (s *ss) mustGetRune() (rune int) {
}
-func (s *ss) UngetRune(rune int) {
- s.peekRune = rune
+func (s *ss) UngetRune() {
+ if u, ok := s.rr.(unreadRuner); ok {
+ u.UnreadRune()
+ } else {
+ s.peekRune = s.prevRune
+ }
}
func (s *ss) error(err os.Error) {
@@ -316,14 +336,17 @@ func (s *ss) free() {
_ = ssFree <- s
}
-// skipSpace skips spaces and maybe newlines
-func (s *ss) skipSpace() {
+// skipSpace skips spaces and maybe newlines.
+func (s *ss) skipSpace(stopAtNewline bool) {
for {
rune := s.getRune()
if rune == EOF {
return
}
if rune == '\n' {
+ if stopAtNewline {
+ break
+ }
if s.nlIsSpace {
continue
}
@@ -331,7 +354,7 @@ func (s *ss) skipSpace() {
return
}
if !unicode.IsSpace(rune) {
- s.UngetRune(rune)
+ s.UngetRune()
break
}
}
@@ -341,7 +364,7 @@ func (s *ss) skipSpace() {
// skips white space. For Scanln, it stops at newlines. For Scan,
// newlines are treated as spaces.
func (s *ss) token() string {
- s.skipSpace()
+ s.skipSpace(false)
// read until white space or newline
for nrunes := 0; !s.widPresent || nrunes < s.maxWid; nrunes++ {
rune := s.getRune()
@@ -349,7 +372,7 @@ func (s *ss) token() string {
break
}
if unicode.IsSpace(rune) {
- s.UngetRune(rune)
+ s.UngetRune()
break
}
s.buf.WriteRune(rune)
@@ -365,9 +388,9 @@ func (s *ss) typeError(field interface{}, expected string) {
var complexError = os.ErrorString("syntax error scanning complex number")
var boolError = os.ErrorString("syntax error scanning boolean")
-// accepts checks the next rune in the input. If it's a byte (sic) in the string, it puts it in the
-// buffer and returns true. Otherwise it return false.
-func (s *ss) accept(ok string) bool {
+// consume reads the next rune in the input and reports whether it is in the ok string.
+// If accept is true, it puts the character into the input token.
+func (s *ss) consume(ok string, accept bool) bool {
if s.wid >= s.maxWid {
return false
}
@@ -377,17 +400,25 @@ func (s *ss) accept(ok string) bool {
}
for i := 0; i < len(ok); i++ {
if int(ok[i]) == rune {
- s.buf.WriteRune(rune)
- s.wid++
+ if accept {
+ s.buf.WriteRune(rune)
+ s.wid++
+ }
return true
}
}
- if rune != EOF {
- s.UngetRune(rune)
+ if rune != EOF && accept {
+ s.UngetRune()
}
return false
}
+// accept checks the next rune in the input. If it's a byte (sic) in the string, it puts it in the
+// buffer and returns true. Otherwise it return false.
+func (s *ss) accept(ok string) bool {
+ return s.consume(ok, true)
+}
+
// okVerb verifies that the verb is present in the list, setting s.err appropriately if not.
func (s *ss) okVerb(verb int, okVerbs, typ string) bool {
for _, v := range okVerbs {
@@ -437,7 +468,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) {
- s.okVerb(verb, "bdoxXv", "integer") // sets s.err
+ s.okVerb(verb, "bdoUxXv", "integer") // sets s.err
base = 10
digits = decimalDigits
switch verb {
@@ -447,7 +478,7 @@ func (s *ss) getBase(verb int) (base int, digits string) {
case 'o':
base = 8
digits = octalDigits
- case 'x', 'X':
+ case 'x', 'X', 'U':
base = 16
digits = hexadecimalDigits
}
@@ -482,8 +513,14 @@ func (s *ss) scanInt(verb int, bitSize int) int64 {
return s.scanRune(bitSize)
}
base, digits := s.getBase(verb)
- s.skipSpace()
- s.accept(sign) // If there's a sign, it will be left in the token buffer.
+ s.skipSpace(false)
+ if verb == 'U' {
+ if !s.consume("U", false) || !s.consume("+", false) {
+ s.errorString("bad unicode format ")
+ }
+ } else {
+ s.accept(sign) // If there's a sign, it will be left in the token buffer.
+ }
tok := s.scanNumber(digits)
i, err := strconv.Btoi64(tok, base)
if err != nil {
@@ -504,7 +541,12 @@ func (s *ss) scanUint(verb int, bitSize int) uint64 {
return uint64(s.scanRune(bitSize))
}
base, digits := s.getBase(verb)
- s.skipSpace()
+ s.skipSpace(false)
+ if verb == 'U' {
+ if !s.consume("U", false) || !s.consume("+", false) {
+ s.errorString("bad unicode format ")
+ }
+ }
tok := s.scanNumber(digits)
i, err := strconv.Btoui64(tok, base)
if err != nil {
@@ -523,8 +565,16 @@ func (s *ss) scanUint(verb int, bitSize int) uint64 {
// we have at least some digits, but Atof will do that.
func (s *ss) floatToken() string {
s.buf.Reset()
+ // NaN?
+ if s.accept("nN") && s.accept("aA") && s.accept("nN") {
+ return s.buf.String()
+ }
// leading sign?
s.accept(sign)
+ // Inf?
+ if s.accept("iI") && s.accept("nN") && s.accept("fF") {
+ return s.buf.String()
+ }
// digits?
for s.accept(decimalDigits) {
}
@@ -586,7 +636,7 @@ func (s *ss) scanComplex(verb int, n int) complex128 {
if !s.okVerb(verb, floatVerbs, "complex") {
return 0
}
- s.skipSpace()
+ s.skipSpace(false)
sreal, simag := s.complexTokens()
real := s.convertFloat(sreal, n/2)
imag := s.convertFloat(simag, n/2)
@@ -595,18 +645,24 @@ 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) string {
+func (s *ss) convertString(verb int) (str string) {
if !s.okVerb(verb, "svqx", "string") {
return ""
}
- s.skipSpace()
+ s.skipSpace(false)
switch verb {
case 'q':
- return s.quotedString()
+ str = s.quotedString()
case 'x':
- return s.hexString()
+ str = s.hexString()
+ default:
+ str = s.token() // %s and %v just return the next word
+ }
+ // Empty strings other than with %q are not OK.
+ if len(str) == 0 && verb != 'q' && s.maxWid > 0 {
+ s.errorString("Scan: no data for string")
}
- return s.token() // %s and %v just return the next word
+ return
}
// quotedString returns the double- or back-quoted string represented by the next input characters.
@@ -672,7 +728,7 @@ func (s *ss) hexByte() (b byte, ok bool) {
return
}
if unicode.IsSpace(rune1) {
- s.UngetRune(rune1)
+ s.UngetRune()
return
}
rune2 := s.mustGetRune()
@@ -731,7 +787,7 @@ func (s *ss) scanOne(verb int, field interface{}) {
case *int32:
*v = int32(s.scanInt(verb, 32))
case *int64:
- *v = s.scanInt(verb, intBits)
+ *v = s.scanInt(verb, 64)
case *uint:
*v = uint(s.scanUint(verb, intBits))
case *uint8:
@@ -748,17 +804,17 @@ func (s *ss) scanOne(verb int, field interface{}) {
// scan in high precision and convert, in order to preserve the correct error condition.
case *float:
if s.okVerb(verb, floatVerbs, "float") {
- s.skipSpace()
+ s.skipSpace(false)
*v = float(s.convertFloat(s.floatToken(), int(floatBits)))
}
case *float32:
if s.okVerb(verb, floatVerbs, "float32") {
- s.skipSpace()
+ s.skipSpace(false)
*v = float32(s.convertFloat(s.floatToken(), 32))
}
case *float64:
if s.okVerb(verb, floatVerbs, "float64") {
- s.skipSpace()
+ s.skipSpace(false)
*v = s.convertFloat(s.floatToken(), 64)
}
case *string:
@@ -795,7 +851,7 @@ func (s *ss) scanOne(verb int, field interface{}) {
v.Elem(i).(*reflect.UintValue).Set(uint64(str[i]))
}
case *reflect.FloatValue:
- s.skipSpace()
+ s.skipSpace(false)
v.Set(s.convertFloat(s.floatToken(), v.Type().Bits()))
case *reflect.ComplexValue:
v.Set(s.scanComplex(verb, v.Type().Bits()))
@@ -878,12 +934,12 @@ func (s *ss) advance(format string) (i int) {
// Space in format but not in input: error
s.errorString("expected space in input to match format")
}
- s.skipSpace()
+ s.skipSpace(true)
continue
}
inputc := s.mustGetRune()
if fmtc != inputc {
- s.UngetRune(inputc)
+ s.UngetRune()
return -1
}
i += w
diff --git a/src/pkg/fmt/scan_test.go b/src/pkg/fmt/scan_test.go
index 1e0319836..fe5ee1d61 100644
--- a/src/pkg/fmt/scan_test.go
+++ b/src/pkg/fmt/scan_test.go
@@ -5,10 +5,13 @@
package fmt_test
import (
+ "bufio"
. "fmt"
"io"
+ "math"
"os"
"reflect"
+ "regexp"
"strings"
"testing"
"utf8"
@@ -78,6 +81,12 @@ var (
renamedComplex128Val renamedComplex128
)
+type FloatTest struct {
+ text string
+ in float64
+ out float64
+}
+
// Xs accepts any non-empty run of the verb character
type Xs string
@@ -100,7 +109,7 @@ func (x *Xs) Scan(state ScanState, verb int) os.Error {
if err != nil {
return err
}
- if !testing.MustCompile("^" + string(verb) + "+$").MatchString(tok) {
+ if !regexp.MustCompile("^" + string(verb) + "+$").MatchString(tok) {
return os.ErrorString("syntax error for xs")
}
*x = Xs(tok)
@@ -125,154 +134,163 @@ func newReader(s string) *myStringReader {
var scanTests = []ScanTest{
// Numbers
- ScanTest{"T\n", &boolVal, true}, // boolean test vals toggle to be sure they are written
- ScanTest{"F\n", &boolVal, false}, // restored to zero value
- ScanTest{"21\n", &intVal, 21},
- ScanTest{"22\n", &int8Val, int8(22)},
- ScanTest{"23\n", &int16Val, int16(23)},
- ScanTest{"24\n", &int32Val, int32(24)},
- ScanTest{"25\n", &int64Val, int64(25)},
- ScanTest{"127\n", &int8Val, int8(127)},
- ScanTest{"-21\n", &intVal, -21},
- ScanTest{"-22\n", &int8Val, int8(-22)},
- ScanTest{"-23\n", &int16Val, int16(-23)},
- ScanTest{"-24\n", &int32Val, int32(-24)},
- ScanTest{"-25\n", &int64Val, int64(-25)},
- ScanTest{"-128\n", &int8Val, int8(-128)},
- ScanTest{"+21\n", &intVal, +21},
- ScanTest{"+22\n", &int8Val, int8(+22)},
- ScanTest{"+23\n", &int16Val, int16(+23)},
- ScanTest{"+24\n", &int32Val, int32(+24)},
- ScanTest{"+25\n", &int64Val, int64(+25)},
- ScanTest{"+127\n", &int8Val, int8(+127)},
- ScanTest{"26\n", &uintVal, uint(26)},
- ScanTest{"27\n", &uint8Val, uint8(27)},
- ScanTest{"28\n", &uint16Val, uint16(28)},
- ScanTest{"29\n", &uint32Val, uint32(29)},
- ScanTest{"30\n", &uint64Val, uint64(30)},
- ScanTest{"255\n", &uint8Val, uint8(255)},
- ScanTest{"32767\n", &int16Val, int16(32767)},
- ScanTest{"2.3\n", &floatVal, 2.3},
- ScanTest{"2.3e1\n", &float32Val, float32(2.3e1)},
- ScanTest{"2.3e2\n", &float64Val, float64(2.3e2)},
- ScanTest{"2.35\n", &stringVal, "2.35"},
- ScanTest{"2345678\n", &bytesVal, []byte("2345678")},
- ScanTest{"(3.4e1-2i)\n", &complexVal, 3.4e1 - 2i},
- ScanTest{"-3.45e1-3i\n", &complex64Val, complex64(-3.45e1 - 3i)},
- ScanTest{"-.45e1-1e2i\n", &complex128Val, complex128(-.45e1 - 100i)},
- ScanTest{"hello\n", &stringVal, "hello"},
+ {"T\n", &boolVal, true}, // boolean test vals toggle to be sure they are written
+ {"F\n", &boolVal, false}, // restored to zero value
+ {"21\n", &intVal, 21},
+ {"22\n", &int8Val, int8(22)},
+ {"23\n", &int16Val, int16(23)},
+ {"24\n", &int32Val, int32(24)},
+ {"25\n", &int64Val, int64(25)},
+ {"127\n", &int8Val, int8(127)},
+ {"-21\n", &intVal, -21},
+ {"-22\n", &int8Val, int8(-22)},
+ {"-23\n", &int16Val, int16(-23)},
+ {"-24\n", &int32Val, int32(-24)},
+ {"-25\n", &int64Val, int64(-25)},
+ {"-128\n", &int8Val, int8(-128)},
+ {"+21\n", &intVal, +21},
+ {"+22\n", &int8Val, int8(+22)},
+ {"+23\n", &int16Val, int16(+23)},
+ {"+24\n", &int32Val, int32(+24)},
+ {"+25\n", &int64Val, int64(+25)},
+ {"+127\n", &int8Val, int8(+127)},
+ {"26\n", &uintVal, uint(26)},
+ {"27\n", &uint8Val, uint8(27)},
+ {"28\n", &uint16Val, uint16(28)},
+ {"29\n", &uint32Val, uint32(29)},
+ {"30\n", &uint64Val, uint64(30)},
+ {"255\n", &uint8Val, uint8(255)},
+ {"32767\n", &int16Val, int16(32767)},
+ {"2.3\n", &floatVal, 2.3},
+ {"2.3e1\n", &float32Val, float32(2.3e1)},
+ {"2.3e2\n", &float64Val, float64(2.3e2)},
+ {"2.35\n", &stringVal, "2.35"},
+ {"2345678\n", &bytesVal, []byte("2345678")},
+ {"(3.4e1-2i)\n", &complexVal, 3.4e1 - 2i},
+ {"-3.45e1-3i\n", &complex64Val, complex64(-3.45e1 - 3i)},
+ {"-.45e1-1e2i\n", &complex128Val, complex128(-.45e1 - 100i)},
+ {"hello\n", &stringVal, "hello"},
// Renamed types
- ScanTest{"true\n", &renamedBoolVal, renamedBool(true)},
- ScanTest{"F\n", &renamedBoolVal, renamedBool(false)},
- ScanTest{"101\n", &renamedIntVal, renamedInt(101)},
- ScanTest{"102\n", &renamedIntVal, renamedInt(102)},
- ScanTest{"103\n", &renamedUintVal, renamedUint(103)},
- ScanTest{"104\n", &renamedUintVal, renamedUint(104)},
- ScanTest{"105\n", &renamedInt8Val, renamedInt8(105)},
- ScanTest{"106\n", &renamedInt16Val, renamedInt16(106)},
- ScanTest{"107\n", &renamedInt32Val, renamedInt32(107)},
- ScanTest{"108\n", &renamedInt64Val, renamedInt64(108)},
- ScanTest{"109\n", &renamedUint8Val, renamedUint8(109)},
- ScanTest{"110\n", &renamedUint16Val, renamedUint16(110)},
- ScanTest{"111\n", &renamedUint32Val, renamedUint32(111)},
- ScanTest{"112\n", &renamedUint64Val, renamedUint64(112)},
- ScanTest{"113\n", &renamedUintptrVal, renamedUintptr(113)},
- ScanTest{"114\n", &renamedStringVal, renamedString("114")},
- ScanTest{"115\n", &renamedBytesVal, renamedBytes([]byte("115"))},
+ {"true\n", &renamedBoolVal, renamedBool(true)},
+ {"F\n", &renamedBoolVal, renamedBool(false)},
+ {"101\n", &renamedIntVal, renamedInt(101)},
+ {"102\n", &renamedIntVal, renamedInt(102)},
+ {"103\n", &renamedUintVal, renamedUint(103)},
+ {"104\n", &renamedUintVal, renamedUint(104)},
+ {"105\n", &renamedInt8Val, renamedInt8(105)},
+ {"106\n", &renamedInt16Val, renamedInt16(106)},
+ {"107\n", &renamedInt32Val, renamedInt32(107)},
+ {"108\n", &renamedInt64Val, renamedInt64(108)},
+ {"109\n", &renamedUint8Val, renamedUint8(109)},
+ {"110\n", &renamedUint16Val, renamedUint16(110)},
+ {"111\n", &renamedUint32Val, renamedUint32(111)},
+ {"112\n", &renamedUint64Val, renamedUint64(112)},
+ {"113\n", &renamedUintptrVal, renamedUintptr(113)},
+ {"114\n", &renamedStringVal, renamedString("114")},
+ {"115\n", &renamedBytesVal, renamedBytes([]byte("115"))},
// Custom scanner.
- ScanTest{" vvv ", &xVal, Xs("vvv")},
+ {" vvv ", &xVal, Xs("vvv")},
+
+ // Fixed bugs
+ {"2147483648\n", &int64Val, int64(2147483648)}, // was: integer overflow
}
var scanfTests = []ScanfTest{
- ScanfTest{"%v", "TRUE\n", &boolVal, true},
- ScanfTest{"%t", "false\n", &boolVal, false},
- ScanfTest{"%v", "-71\n", &intVal, -71},
- ScanfTest{"%d", "72\n", &intVal, 72},
- ScanfTest{"%c", "a\n", &intVal, 'a'},
- ScanfTest{"%c", "\u5072\n", &intVal, 0x5072},
- ScanfTest{"%c", "\u1234\n", &intVal, '\u1234'},
- ScanfTest{"%d", "73\n", &int8Val, int8(73)},
- ScanfTest{"%d", "+74\n", &int16Val, int16(74)},
- ScanfTest{"%d", "75\n", &int32Val, int32(75)},
- ScanfTest{"%d", "76\n", &int64Val, int64(76)},
- ScanfTest{"%b", "1001001\n", &intVal, 73},
- ScanfTest{"%o", "075\n", &intVal, 075},
- ScanfTest{"%x", "a75\n", &intVal, 0xa75},
- ScanfTest{"%v", "71\n", &uintVal, uint(71)},
- ScanfTest{"%d", "72\n", &uintVal, uint(72)},
- ScanfTest{"%d", "73\n", &uint8Val, uint8(73)},
- ScanfTest{"%d", "74\n", &uint16Val, uint16(74)},
- ScanfTest{"%d", "75\n", &uint32Val, uint32(75)},
- ScanfTest{"%d", "76\n", &uint64Val, uint64(76)},
- ScanfTest{"%b", "1001001\n", &uintVal, uint(73)},
- ScanfTest{"%o", "075\n", &uintVal, uint(075)},
- ScanfTest{"%x", "a75\n", &uintVal, uint(0xa75)},
- ScanfTest{"%x", "A75\n", &uintVal, uint(0xa75)},
+ {"%v", "TRUE\n", &boolVal, true},
+ {"%t", "false\n", &boolVal, false},
+ {"%v", "-71\n", &intVal, -71},
+ {"%d", "72\n", &intVal, 72},
+ {"%c", "a\n", &intVal, 'a'},
+ {"%c", "\u5072\n", &intVal, 0x5072},
+ {"%c", "\u1234\n", &intVal, '\u1234'},
+ {"%d", "73\n", &int8Val, int8(73)},
+ {"%d", "+74\n", &int16Val, int16(74)},
+ {"%d", "75\n", &int32Val, int32(75)},
+ {"%d", "76\n", &int64Val, int64(76)},
+ {"%b", "1001001\n", &intVal, 73},
+ {"%o", "075\n", &intVal, 075},
+ {"%x", "a75\n", &intVal, 0xa75},
+ {"%v", "71\n", &uintVal, uint(71)},
+ {"%d", "72\n", &uintVal, uint(72)},
+ {"%d", "73\n", &uint8Val, uint8(73)},
+ {"%d", "74\n", &uint16Val, uint16(74)},
+ {"%d", "75\n", &uint32Val, uint32(75)},
+ {"%d", "76\n", &uint64Val, uint64(76)},
+ {"%b", "1001001\n", &uintVal, uint(73)},
+ {"%o", "075\n", &uintVal, uint(075)},
+ {"%x", "a75\n", &uintVal, uint(0xa75)},
+ {"%x", "A75\n", &uintVal, uint(0xa75)},
+ {"%U", "U+1234\n", &intVal, int(0x1234)},
+ {"%U", "U+4567\n", &uintVal, uint(0x4567)},
// Strings
- ScanfTest{"%s", "using-%s\n", &stringVal, "using-%s"},
- ScanfTest{"%x", "7573696e672d2578\n", &stringVal, "using-%x"},
- ScanfTest{"%q", `"quoted\twith\\do\u0075bl\x65s"` + "\n", &stringVal, "quoted\twith\\doubles"},
- ScanfTest{"%q", "`quoted with backs`\n", &stringVal, "quoted with backs"},
+ {"%s", "using-%s\n", &stringVal, "using-%s"},
+ {"%x", "7573696e672d2578\n", &stringVal, "using-%x"},
+ {"%q", `"quoted\twith\\do\u0075bl\x65s"` + "\n", &stringVal, "quoted\twith\\doubles"},
+ {"%q", "`quoted with backs`\n", &stringVal, "quoted with backs"},
// Byte slices
- ScanfTest{"%s", "bytes-%s\n", &bytesVal, []byte("bytes-%s")},
- ScanfTest{"%x", "62797465732d2578\n", &bytesVal, []byte("bytes-%x")},
- ScanfTest{"%q", `"bytes\rwith\vdo\u0075bl\x65s"` + "\n", &bytesVal, []byte("bytes\rwith\vdoubles")},
- ScanfTest{"%q", "`bytes with backs`\n", &bytesVal, []byte("bytes with backs")},
+ {"%s", "bytes-%s\n", &bytesVal, []byte("bytes-%s")},
+ {"%x", "62797465732d2578\n", &bytesVal, []byte("bytes-%x")},
+ {"%q", `"bytes\rwith\vdo\u0075bl\x65s"` + "\n", &bytesVal, []byte("bytes\rwith\vdoubles")},
+ {"%q", "`bytes with backs`\n", &bytesVal, []byte("bytes with backs")},
// Renamed types
- ScanfTest{"%v\n", "true\n", &renamedBoolVal, renamedBool(true)},
- ScanfTest{"%t\n", "F\n", &renamedBoolVal, renamedBool(false)},
- ScanfTest{"%v", "101\n", &renamedIntVal, renamedInt(101)},
- ScanfTest{"%c", "\u0101\n", &renamedIntVal, renamedInt('\u0101')},
- ScanfTest{"%o", "0146\n", &renamedIntVal, renamedInt(102)},
- ScanfTest{"%v", "103\n", &renamedUintVal, renamedUint(103)},
- ScanfTest{"%d", "104\n", &renamedUintVal, renamedUint(104)},
- ScanfTest{"%d", "105\n", &renamedInt8Val, renamedInt8(105)},
- ScanfTest{"%d", "106\n", &renamedInt16Val, renamedInt16(106)},
- ScanfTest{"%d", "107\n", &renamedInt32Val, renamedInt32(107)},
- ScanfTest{"%d", "108\n", &renamedInt64Val, renamedInt64(108)},
- ScanfTest{"%x", "6D\n", &renamedUint8Val, renamedUint8(109)},
- ScanfTest{"%o", "0156\n", &renamedUint16Val, renamedUint16(110)},
- ScanfTest{"%d", "111\n", &renamedUint32Val, renamedUint32(111)},
- ScanfTest{"%d", "112\n", &renamedUint64Val, renamedUint64(112)},
- ScanfTest{"%d", "113\n", &renamedUintptrVal, renamedUintptr(113)},
- ScanfTest{"%s", "114\n", &renamedStringVal, renamedString("114")},
- ScanfTest{"%q", "\"1155\"\n", &renamedBytesVal, renamedBytes([]byte("1155"))},
- ScanfTest{"%g", "115.1\n", &renamedFloatVal, renamedFloat(115.1)},
- ScanfTest{"%g", "116e1\n", &renamedFloat32Val, renamedFloat32(116e1)},
- ScanfTest{"%g", "-11.7e+1", &renamedFloat64Val, renamedFloat64(-11.7e+1)},
- ScanfTest{"%g", "11+5.1i\n", &renamedComplexVal, renamedComplex(11 + 5.1i)},
- ScanfTest{"%g", "11+6e1i\n", &renamedComplex64Val, renamedComplex64(11 + 6e1i)},
- ScanfTest{"%g", "-11.+7e+1i", &renamedComplex128Val, renamedComplex128(-11. + 7e+1i)},
+ {"%v\n", "true\n", &renamedBoolVal, renamedBool(true)},
+ {"%t\n", "F\n", &renamedBoolVal, renamedBool(false)},
+ {"%v", "101\n", &renamedIntVal, renamedInt(101)},
+ {"%c", "\u0101\n", &renamedIntVal, renamedInt('\u0101')},
+ {"%o", "0146\n", &renamedIntVal, renamedInt(102)},
+ {"%v", "103\n", &renamedUintVal, renamedUint(103)},
+ {"%d", "104\n", &renamedUintVal, renamedUint(104)},
+ {"%d", "105\n", &renamedInt8Val, renamedInt8(105)},
+ {"%d", "106\n", &renamedInt16Val, renamedInt16(106)},
+ {"%d", "107\n", &renamedInt32Val, renamedInt32(107)},
+ {"%d", "108\n", &renamedInt64Val, renamedInt64(108)},
+ {"%x", "6D\n", &renamedUint8Val, renamedUint8(109)},
+ {"%o", "0156\n", &renamedUint16Val, renamedUint16(110)},
+ {"%d", "111\n", &renamedUint32Val, renamedUint32(111)},
+ {"%d", "112\n", &renamedUint64Val, renamedUint64(112)},
+ {"%d", "113\n", &renamedUintptrVal, renamedUintptr(113)},
+ {"%s", "114\n", &renamedStringVal, renamedString("114")},
+ {"%q", "\"1155\"\n", &renamedBytesVal, renamedBytes([]byte("1155"))},
+ {"%g", "115.1\n", &renamedFloatVal, renamedFloat(115.1)},
+ {"%g", "116e1\n", &renamedFloat32Val, renamedFloat32(116e1)},
+ {"%g", "-11.7e+1", &renamedFloat64Val, renamedFloat64(-11.7e+1)},
+ {"%g", "11+5.1i\n", &renamedComplexVal, renamedComplex(11 + 5.1i)},
+ {"%g", "11+6e1i\n", &renamedComplex64Val, renamedComplex64(11 + 6e1i)},
+ {"%g", "-11.+7e+1i", &renamedComplex128Val, renamedComplex128(-11. + 7e+1i)},
// Interesting formats
- ScanfTest{"here is\tthe value:%d", "here is the\tvalue:118\n", &intVal, 118},
- ScanfTest{"%% %%:%d", "% %:119\n", &intVal, 119},
+ {"here is\tthe value:%d", "here is the\tvalue:118\n", &intVal, 118},
+ {"%% %%:%d", "% %:119\n", &intVal, 119},
// Corner cases
- ScanfTest{"%x", "FFFFFFFF\n", &uint32Val, uint32(0xFFFFFFFF)},
+ {"%x", "FFFFFFFF\n", &uint32Val, uint32(0xFFFFFFFF)},
// Custom scanner.
- ScanfTest{"%s", " sss ", &xVal, Xs("sss")},
- ScanfTest{"%2s", "sssss", &xVal, Xs("ss")},
+ {"%s", " sss ", &xVal, Xs("sss")},
+ {"%2s", "sssss", &xVal, Xs("ss")},
+
+ // Fixed bugs
+ {"%d\n", "27\n", &intVal, 27}, // ok
+ {"%d\n", "28 \n", &intVal, 28}, // was: "unexpected newline"
}
var overflowTests = []ScanTest{
- ScanTest{"128", &int8Val, 0},
- ScanTest{"32768", &int16Val, 0},
- ScanTest{"-129", &int8Val, 0},
- ScanTest{"-32769", &int16Val, 0},
- ScanTest{"256", &uint8Val, 0},
- ScanTest{"65536", &uint16Val, 0},
- ScanTest{"1e100", &float32Val, 0},
- ScanTest{"1e500", &float64Val, 0},
- ScanTest{"(1e100+0i)", &complexVal, 0},
- ScanTest{"(1+1e100i)", &complex64Val, 0},
- ScanTest{"(1-1e500i)", &complex128Val, 0},
+ {"128", &int8Val, 0},
+ {"32768", &int16Val, 0},
+ {"-129", &int8Val, 0},
+ {"-32769", &int16Val, 0},
+ {"256", &uint8Val, 0},
+ {"65536", &uint16Val, 0},
+ {"1e100", &float32Val, 0},
+ {"1e500", &float64Val, 0},
+ {"(1e100+0i)", &complexVal, 0},
+ {"(1+1e100i)", &complex64Val, 0},
+ {"(1-1e500i)", &complex128Val, 0},
}
var i, j, k int
@@ -281,32 +299,30 @@ var s, t string
var c complex
var x, y Xs
-func args(a ...interface{}) []interface{} { return a }
-
var multiTests = []ScanfMultiTest{
- ScanfMultiTest{"", "", nil, nil, ""},
- ScanfMultiTest{"%d", "23", args(&i), args(23), ""},
- ScanfMultiTest{"%2s%3s", "22333", args(&s, &t), args("22", "333"), ""},
- ScanfMultiTest{"%2d%3d", "44555", args(&i, &j), args(44, 555), ""},
- ScanfMultiTest{"%2d.%3d", "66.777", args(&i, &j), args(66, 777), ""},
- ScanfMultiTest{"%d, %d", "23, 18", args(&i, &j), args(23, 18), ""},
- ScanfMultiTest{"%3d22%3d", "33322333", args(&i, &j), args(333, 333), ""},
- ScanfMultiTest{"%6vX=%3fY", "3+2iX=2.5Y", args(&c, &f), args((3 + 2i), float(2.5)), ""},
- ScanfMultiTest{"%d%s", "123abc", args(&i, &s), args(123, "abc"), ""},
- ScanfMultiTest{"%c%c%c", "2\u50c2X", args(&i, &j, &k), args('2', '\u50c2', 'X'), ""},
+ {"", "", nil, nil, ""},
+ {"%d", "23", args(&i), args(23), ""},
+ {"%2s%3s", "22333", args(&s, &t), args("22", "333"), ""},
+ {"%2d%3d", "44555", args(&i, &j), args(44, 555), ""},
+ {"%2d.%3d", "66.777", args(&i, &j), args(66, 777), ""},
+ {"%d, %d", "23, 18", args(&i, &j), args(23, 18), ""},
+ {"%3d22%3d", "33322333", args(&i, &j), args(333, 333), ""},
+ {"%6vX=%3fY", "3+2iX=2.5Y", args(&c, &f), args((3 + 2i), float(2.5)), ""},
+ {"%d%s", "123abc", args(&i, &s), args(123, "abc"), ""},
+ {"%c%c%c", "2\u50c2X", args(&i, &j, &k), args('2', '\u50c2', 'X'), ""},
// Custom scanner.
- ScanfMultiTest{"%2e%f", "eefffff", args(&x, &y), args(Xs("ee"), Xs("fffff")), ""},
+ {"%2e%f", "eefffff", args(&x, &y), args(Xs("ee"), Xs("fffff")), ""},
// Errors
- ScanfMultiTest{"%t", "23 18", args(&i), nil, "bad verb"},
- ScanfMultiTest{"%d %d %d", "23 18", args(&i, &j), args(23, 18), "too few operands"},
- ScanfMultiTest{"%d %d", "23 18 27", args(&i, &j, &k), args(23, 18), "too many operands"},
- ScanfMultiTest{"%c", "\u0100", args(&int8Val), nil, "overflow"},
- ScanfMultiTest{"X%d", "10X", args(&intVal), nil, "input does not match format"},
+ {"%t", "23 18", args(&i), nil, "bad verb"},
+ {"%d %d %d", "23 18", args(&i, &j), args(23, 18), "too few operands"},
+ {"%d %d", "23 18 27", args(&i, &j, &k), args(23, 18), "too many operands"},
+ {"%c", "\u0100", args(&int8Val), nil, "overflow"},
+ {"X%d", "10X", args(&intVal), nil, "input does not match format"},
// Bad UTF-8: should see every byte.
- ScanfMultiTest{"%c%c%c", "\xc2X\xc2", args(&i, &j, &k), args(utf8.RuneError, 'X', utf8.RuneError), ""},
+ {"%c%c%c", "\xc2X\xc2", args(&i, &j, &k), args(utf8.RuneError, 'X', utf8.RuneError), ""},
}
func testScan(name string, t *testing.T, scan func(r io.Reader, a ...interface{}) (int, os.Error)) {
@@ -379,7 +395,7 @@ func TestScanf(t *testing.T) {
func TestScanOverflow(t *testing.T) {
// different machines and different types report errors with different strings.
- re := testing.MustCompile("overflow|too large|out of range|not representable")
+ re := regexp.MustCompile("overflow|too large|out of range|not representable")
for _, test := range overflowTests {
_, err := Sscan(test.text, test.in)
if err == nil {
@@ -392,6 +408,57 @@ func TestScanOverflow(t *testing.T) {
}
}
+func verifyNaN(str string, t *testing.T) {
+ var f float
+ var f32 float32
+ var f64 float64
+ text := str + " " + str + " " + str
+ n, err := Fscan(strings.NewReader(text), &f, &f32, &f64)
+ if err != nil {
+ t.Errorf("got error scanning %q: %s", text, err)
+ }
+ if n != 3 {
+ t.Errorf("count error scanning %q: got %d", text, n)
+ }
+ if !math.IsNaN(float64(f)) || !math.IsNaN(float64(f32)) || !math.IsNaN(f64) {
+ t.Errorf("didn't get NaNs scanning %q: got %g %g %g", text, f, f32, f64)
+ }
+}
+
+func TestNaN(t *testing.T) {
+ for _, s := range []string{"nan", "NAN", "NaN"} {
+ verifyNaN(s, t)
+ }
+}
+
+func verifyInf(str string, t *testing.T) {
+ var f float
+ var f32 float32
+ var f64 float64
+ text := str + " " + str + " " + str
+ n, err := Fscan(strings.NewReader(text), &f, &f32, &f64)
+ if err != nil {
+ t.Errorf("got error scanning %q: %s", text, err)
+ }
+ if n != 3 {
+ t.Errorf("count error scanning %q: got %d", text, n)
+ }
+ sign := 1
+ if str[0] == '-' {
+ sign = -1
+ }
+ if !math.IsInf(float64(f), sign) || !math.IsInf(float64(f32), sign) || !math.IsInf(f64, sign) {
+ t.Errorf("didn't get right Infs scanning %q: got %g %g %g", text, f, f32, f64)
+ }
+}
+
+
+func TestInf(t *testing.T) {
+ for _, s := range []string{"inf", "+inf", "-inf", "INF", "-INF", "+INF", "Inf", "-Inf", "+Inf"} {
+ verifyInf(s, t)
+ }
+}
+
// TODO: there's no conversion from []T to ...T, but we can fake it. These
// functions do the faking. We index the table by the length of the param list.
var fscanf = []func(io.Reader, string, []interface{}) (int, os.Error){
@@ -460,6 +527,46 @@ func TestScanMultiple(t *testing.T) {
if a != 123 || s != "abc" {
t.Errorf("Sscan wrong values: got (%d %q) expected (123 \"abc\")", a, s)
}
+ n, err = Sscan("asdf", &s, &a)
+ if n != 1 {
+ t.Errorf("Sscan count error: expected 1: got %d", n)
+ }
+ if err == nil {
+ t.Errorf("Sscan expected error; got none: %s", err)
+ }
+ if s != "asdf" {
+ t.Errorf("Sscan wrong values: got %q expected \"asdf\"", s)
+ }
+}
+
+// Empty strings are not valid input when scanning a string.
+func TestScanEmpty(t *testing.T) {
+ var s1, s2 string
+ n, err := Sscan("abc", &s1, &s2)
+ if n != 1 {
+ t.Errorf("Sscan count error: expected 1: got %d", n)
+ }
+ if err == nil {
+ t.Error("Sscan <one item> expected error; got none")
+ }
+ if s1 != "abc" {
+ t.Errorf("Sscan wrong values: got %q expected \"abc\"", s1)
+ }
+ n, err = Sscan("", &s1, &s2)
+ if n != 0 {
+ t.Errorf("Sscan count error: expected 0: got %d", n)
+ }
+ if err == nil {
+ t.Error("Sscan <empty> expected error; got none")
+ }
+ // Quoted empty string is OK.
+ n, err = Sscanf(`""`, "%q", &s1)
+ if n != 1 {
+ t.Errorf("Sscanf count error: expected 1: got %d", n)
+ }
+ if err != nil {
+ t.Errorf("Sscanf <empty> expected no error with quoted string; got %s", err)
+ }
}
func TestScanNotPointer(t *testing.T) {
@@ -535,3 +642,24 @@ func TestEOF(t *testing.T) {
t.Error("expected one EOF, got", ec.eofCount)
}
}
+
+// Verify that, at least when using bufio, successive calls to Fscan do not lose runes.
+func TestUnreadRuneWithBufio(t *testing.T) {
+ r := bufio.NewReader(strings.NewReader("123αb"))
+ var i int
+ var a string
+ n, err := Fscanf(r, "%d", &i)
+ if n != 1 || err != nil {
+ t.Errorf("reading int expected one item, no errors; got %d %q", n, err)
+ }
+ if i != 123 {
+ t.Errorf("expected 123; got %d", i)
+ }
+ n, err = Fscanf(r, "%s", &a)
+ if n != 1 || err != nil {
+ t.Errorf("reading string expected one item, no errors; got %d %q", n, err)
+ }
+ if a != "αb" {
+ t.Errorf("expected αb; got %q", a)
+ }
+}
diff --git a/src/pkg/go/ast/Makefile b/src/pkg/go/ast/Makefile
index 9b5c904c1..e9b885c70 100644
--- a/src/pkg/go/ast/Makefile
+++ b/src/pkg/go/ast/Makefile
@@ -2,12 +2,13 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=go/ast
GOFILES=\
ast.go\
filter.go\
+ print.go\
scope.go\
walk.go\
diff --git a/src/pkg/go/ast/ast.go b/src/pkg/go/ast/ast.go
index 2fc8b215f..cf2ce36df 100644
--- a/src/pkg/go/ast/ast.go
+++ b/src/pkg/go/ast/ast.go
@@ -34,8 +34,8 @@ import (
// All node types implement the Node interface.
type Node interface {
- // Pos returns the (beginning) position of the node.
- Pos() token.Position
+ Pos() token.Pos // position of first character belonging to the node
+ End() token.Pos // position of first character immediately after the node
}
@@ -65,19 +65,27 @@ type Decl interface {
// A Comment node represents a single //-style or /*-style comment.
type Comment struct {
- token.Position // beginning position of the comment
- Text []byte // comment text (excluding '\n' for //-style comments)
+ Slash token.Pos // position of "/" starting the comment
+ Text []byte // comment text (excluding '\n' for //-style comments)
}
+func (c *Comment) Pos() token.Pos { return c.Slash }
+func (c *Comment) End() token.Pos { return token.Pos(int(c.Slash) + len(c.Text)) }
+
+
// A CommentGroup represents a sequence of comments
// with no other tokens and no empty lines between.
//
type CommentGroup struct {
- List []*Comment
+ List []*Comment // len(List) > 0
}
+func (g *CommentGroup) Pos() token.Pos { return g.List[0].Pos() }
+func (g *CommentGroup) End() token.Pos { return g.List[len(g.List)-1].End() }
+
+
// ----------------------------------------------------------------------------
// Expressions and types
@@ -94,7 +102,7 @@ type Field struct {
}
-func (f *Field) Pos() token.Position {
+func (f *Field) Pos() token.Pos {
if len(f.Names) > 0 {
return f.Names[0].Pos()
}
@@ -102,11 +110,45 @@ func (f *Field) Pos() token.Position {
}
+func (f *Field) End() token.Pos {
+ if f.Tag != nil {
+ return f.Tag.End()
+ }
+ return f.Type.End()
+}
+
+
// A FieldList represents a list of Fields, enclosed by parentheses or braces.
type FieldList struct {
- Opening token.Position // position of opening parenthesis/brace
- List []*Field // field list
- Closing token.Position // position of closing parenthesis/brace
+ Opening token.Pos // position of opening parenthesis/brace, if any
+ List []*Field // field list
+ Closing token.Pos // position of closing parenthesis/brace, if any
+}
+
+
+func (f *FieldList) Pos() token.Pos {
+ if f.Opening.IsValid() {
+ return f.Opening
+ }
+ // the list should not be empty in this case;
+ // be conservative and guard against bad ASTs
+ if len(f.List) > 0 {
+ return f.List[0].Pos()
+ }
+ return token.NoPos
+}
+
+
+func (f *FieldList) End() token.Pos {
+ if f.Closing.IsValid() {
+ return f.Closing + 1
+ }
+ // the list should not be empty in this case;
+ // be conservative and guard against bad ASTs
+ if n := len(f.List); n > 0 {
+ return f.List[n-1].End()
+ }
+ return token.NoPos
}
@@ -135,28 +177,29 @@ type (
// created.
//
BadExpr struct {
- token.Position // beginning position of bad expression
+ From, To token.Pos // position range of bad expression
}
// An Ident node represents an identifier.
Ident struct {
- token.Position // identifier position
- Obj *Object // denoted object
+ NamePos token.Pos // identifier position
+ Name string // identifier name
+ Obj *Object // denoted object; or nil
}
// An Ellipsis node stands for the "..." type in a
// parameter list or the "..." length in an array type.
//
Ellipsis struct {
- token.Position // position of "..."
- Elt Expr // ellipsis element type (parameter lists only)
+ Ellipsis token.Pos // position of "..."
+ Elt Expr // ellipsis element type (parameter lists only); or nil
}
// A BasicLit node represents a literal of basic type.
BasicLit struct {
- token.Position // literal position
- Kind token.Token // token.INT, token.FLOAT, token.IMAG, token.CHAR, or token.STRING
- Value []byte // literal string; e.g. 42, 0x7f, 3.14, 1e-9, 'a', '\x7f', "foo" or `\m\n\o`
+ ValuePos token.Pos // literal position
+ Kind token.Token // token.INT, token.FLOAT, token.IMAG, token.CHAR, or token.STRING
+ Value []byte // literal string; e.g. 42, 0x7f, 3.14, 1e-9, 2.4i, 'a', '\x7f', "foo" or `\m\n\o`
}
// A FuncLit node represents a function literal.
@@ -166,19 +209,18 @@ type (
}
// A CompositeLit node represents a composite literal.
- //
CompositeLit struct {
- Type Expr // literal type
- Lbrace token.Position // position of "{"
- Elts []Expr // list of composite elements
- Rbrace token.Position // position of "}"
+ Type Expr // literal type; or nil
+ Lbrace token.Pos // position of "{"
+ Elts []Expr // list of composite elements; or nil
+ Rbrace token.Pos // position of "}"
}
// A ParenExpr node represents a parenthesized expression.
ParenExpr struct {
- token.Position // position of "("
- X Expr // parenthesized expression
- Rparen token.Position // position of ")"
+ Lparen token.Pos // position of "("
+ X Expr // parenthesized expression
+ Rparen token.Pos // position of ")"
}
// A SelectorExpr node represents an expression followed by a selector.
@@ -189,15 +231,19 @@ type (
// An IndexExpr node represents an expression followed by an index.
IndexExpr struct {
- X Expr // expression
- Index Expr // index expression
+ X Expr // expression
+ Lbrack token.Pos // position of "["
+ Index Expr // index expression
+ Rbrack token.Pos // position of "]"
}
// An SliceExpr node represents an expression followed by slice indices.
SliceExpr struct {
- X Expr // expression
- Index Expr // beginning of slice range
- End Expr // end of slice range; or nil
+ X Expr // expression
+ Lbrack token.Pos // position of "["
+ Low Expr // begin of slice range; or nil
+ High Expr // end of slice range; or nil
+ Rbrack token.Pos // position of "]"
}
// A TypeAssertExpr node represents an expression followed by a
@@ -210,35 +256,36 @@ type (
// A CallExpr node represents an expression followed by an argument list.
CallExpr struct {
- Fun Expr // function expression
- Lparen token.Position // position of "("
- Args []Expr // function arguments
- Rparen token.Position // positions of ")"
+ Fun Expr // function expression
+ Lparen token.Pos // position of "("
+ Args []Expr // function arguments; or nil
+ Ellipsis token.Pos // position of "...", if any
+ Rparen token.Pos // position of ")"
}
// A StarExpr node represents an expression of the form "*" Expression.
// Semantically it could be a unary "*" expression, or a pointer type.
+ //
StarExpr struct {
- token.Position // position of "*"
- X Expr // operand
+ Star token.Pos // position of "*"
+ X Expr // operand
}
// A UnaryExpr node represents a unary expression.
// Unary "*" expressions are represented via StarExpr nodes.
//
UnaryExpr struct {
- token.Position // position of Op
- Op token.Token // operator
- X Expr // operand
+ OpPos token.Pos // position of Op
+ Op token.Token // operator
+ X Expr // operand
}
// A BinaryExpr node represents a binary expression.
- //
BinaryExpr struct {
- X Expr // left operand
- OpPos token.Position // position of Op
- Op token.Token // operator
- Y Expr // right operand
+ X Expr // left operand
+ OpPos token.Pos // position of Op
+ Op token.Token // operator
+ Y Expr // right operand
}
// A KeyValueExpr node represents (key : value) pairs
@@ -246,7 +293,7 @@ type (
//
KeyValueExpr struct {
Key Expr
- Colon token.Position // position of ":"
+ Colon token.Pos // position of ":"
Value Expr
}
)
@@ -270,66 +317,123 @@ const (
type (
// An ArrayType node represents an array or slice type.
ArrayType struct {
- token.Position // position of "["
- Len Expr // Ellipsis node for [...]T array types, nil for slice types
- Elt Expr // element type
+ Lbrack token.Pos // position of "["
+ Len Expr // Ellipsis node for [...]T array types, nil for slice types
+ Elt Expr // element type
}
// A StructType node represents a struct type.
StructType struct {
- token.Position // position of "struct" keyword
- Fields *FieldList // list of field declarations
- Incomplete bool // true if (source) fields are missing in the Fields list
+ Struct token.Pos // position of "struct" keyword
+ Fields *FieldList // list of field declarations
+ Incomplete bool // true if (source) fields are missing in the Fields list
}
// Pointer types are represented via StarExpr nodes.
// A FuncType node represents a function type.
FuncType struct {
- token.Position // position of "func" keyword
- Params *FieldList // (incoming) parameters
- Results *FieldList // (outgoing) results
+ Func token.Pos // position of "func" keyword
+ Params *FieldList // (incoming) parameters
+ Results *FieldList // (outgoing) results; or nil
}
// An InterfaceType node represents an interface type.
InterfaceType struct {
- token.Position // position of "interface" keyword
- Methods *FieldList // list of methods
- Incomplete bool // true if (source) methods are missing in the Methods list
+ Interface token.Pos // position of "interface" keyword
+ Methods *FieldList // list of methods
+ Incomplete bool // true if (source) methods are missing in the Methods list
}
// A MapType node represents a map type.
MapType struct {
- token.Position // position of "map" keyword
- Key Expr
- Value Expr
+ Map token.Pos // position of "map" keyword
+ Key Expr
+ Value Expr
}
// A ChanType node represents a channel type.
ChanType struct {
- token.Position // position of "chan" keyword or "<-" (whichever comes first)
- Dir ChanDir // channel direction
- Value Expr // value type
+ Begin token.Pos // position of "chan" keyword or "<-" (whichever comes first)
+ Dir ChanDir // channel direction
+ Value Expr // value type
}
)
-// Pos() implementations for expression/type where the position
-// corresponds to the position of a sub-node.
+// Pos and End implementations for expression/type nodes.
//
-func (x *FuncLit) Pos() token.Position { return x.Type.Pos() }
-func (x *CompositeLit) Pos() token.Position { return x.Type.Pos() }
-func (x *SelectorExpr) Pos() token.Position { return x.X.Pos() }
-func (x *IndexExpr) Pos() token.Position { return x.X.Pos() }
-func (x *SliceExpr) Pos() token.Position { return x.X.Pos() }
-func (x *TypeAssertExpr) Pos() token.Position { return x.X.Pos() }
-func (x *CallExpr) Pos() token.Position { return x.Fun.Pos() }
-func (x *BinaryExpr) Pos() token.Position { return x.X.Pos() }
-func (x *KeyValueExpr) Pos() token.Position { return x.Key.Pos() }
+func (x *BadExpr) Pos() token.Pos { return x.From }
+func (x *Ident) Pos() token.Pos { return x.NamePos }
+func (x *Ellipsis) Pos() token.Pos { return x.Ellipsis }
+func (x *BasicLit) Pos() token.Pos { return x.ValuePos }
+func (x *FuncLit) Pos() token.Pos { return x.Type.Pos() }
+func (x *CompositeLit) Pos() token.Pos {
+ if x.Type != nil {
+ return x.Type.Pos()
+ }
+ return x.Lbrace
+}
+func (x *ParenExpr) Pos() token.Pos { return x.Lparen }
+func (x *SelectorExpr) Pos() token.Pos { return x.X.Pos() }
+func (x *IndexExpr) Pos() token.Pos { return x.X.Pos() }
+func (x *SliceExpr) Pos() token.Pos { return x.X.Pos() }
+func (x *TypeAssertExpr) Pos() token.Pos { return x.X.Pos() }
+func (x *CallExpr) Pos() token.Pos { return x.Fun.Pos() }
+func (x *StarExpr) Pos() token.Pos { return x.Star }
+func (x *UnaryExpr) Pos() token.Pos { return x.OpPos }
+func (x *BinaryExpr) Pos() token.Pos { return x.X.Pos() }
+func (x *KeyValueExpr) Pos() token.Pos { return x.Key.Pos() }
+func (x *ArrayType) Pos() token.Pos { return x.Lbrack }
+func (x *StructType) Pos() token.Pos { return x.Struct }
+func (x *FuncType) Pos() token.Pos { return x.Func }
+func (x *InterfaceType) Pos() token.Pos { return x.Interface }
+func (x *MapType) Pos() token.Pos { return x.Map }
+func (x *ChanType) Pos() token.Pos { return x.Begin }
+
+
+func (x *BadExpr) End() token.Pos { return x.To }
+func (x *Ident) End() token.Pos { return token.Pos(int(x.NamePos) + len(x.Name)) }
+func (x *Ellipsis) End() token.Pos {
+ if x.Elt != nil {
+ return x.Elt.End()
+ }
+ return x.Ellipsis + 3 // len("...")
+}
+func (x *BasicLit) End() token.Pos { return token.Pos(int(x.ValuePos) + len(x.Value)) }
+func (x *FuncLit) End() token.Pos { return x.Body.End() }
+func (x *CompositeLit) End() token.Pos { return x.Rbrace + 1 }
+func (x *ParenExpr) End() token.Pos { return x.Rparen + 1 }
+func (x *SelectorExpr) End() token.Pos { return x.Sel.End() }
+func (x *IndexExpr) End() token.Pos { return x.Rbrack + 1 }
+func (x *SliceExpr) End() token.Pos { return x.Rbrack + 1 }
+func (x *TypeAssertExpr) End() token.Pos {
+ if x.Type != nil {
+ return x.Type.End()
+ }
+ return x.X.End()
+}
+func (x *CallExpr) End() token.Pos { return x.Rparen + 1 }
+func (x *StarExpr) End() token.Pos { return x.X.End() }
+func (x *UnaryExpr) End() token.Pos { return x.X.End() }
+func (x *BinaryExpr) End() token.Pos { return x.Y.End() }
+func (x *KeyValueExpr) End() token.Pos { return x.Value.End() }
+func (x *ArrayType) End() token.Pos { return x.Elt.End() }
+func (x *StructType) End() token.Pos { return x.Fields.End() }
+func (x *FuncType) End() token.Pos {
+ if x.Results != nil {
+ return x.Results.End()
+ }
+ return x.Params.End()
+}
+func (x *InterfaceType) End() token.Pos { return x.Methods.End() }
+func (x *MapType) End() token.Pos { return x.Value.End() }
+func (x *ChanType) End() token.Pos { return x.Value.End() }
// exprNode() ensures that only expression/type nodes can be
// assigned to an ExprNode.
+//
func (x *BadExpr) exprNode() {}
func (x *Ident) exprNode() {}
func (x *Ellipsis) exprNode() {}
@@ -358,17 +462,17 @@ func (x *ChanType) exprNode() {}
// ----------------------------------------------------------------------------
// Convenience functions for Idents
-var noPos token.Position
+var noPos token.Pos
-// NewIdent creates a new Ident without position and minimal object
-// information. Useful for ASTs generated by code other than the Go
-// parser.
+// NewIdent creates a new Ident without position.
+// Useful for ASTs generated by code other than the Go parser.
//
-func NewIdent(name string) *Ident { return &Ident{noPos, NewObj(Err, noPos, name)} }
+func NewIdent(name string) *Ident { return &Ident{noPos, name, nil} }
// IsExported returns whether name is an exported Go symbol
// (i.e., whether it begins with an uppercase letter).
+//
func IsExported(name string) bool {
ch, _ := utf8.DecodeRuneInString(name)
return unicode.IsUpper(ch)
@@ -377,16 +481,13 @@ func IsExported(name string) bool {
// IsExported returns whether id is an exported Go symbol
// (i.e., whether it begins with an uppercase letter).
-func (id *Ident) IsExported() bool { return id.Obj.IsExported() }
-
-
-// Name returns an identifier's name.
-func (id *Ident) Name() string { return id.Obj.Name }
+//
+func (id *Ident) IsExported() bool { return IsExported(id.Name) }
func (id *Ident) String() string {
- if id != nil && id.Obj != nil {
- return id.Obj.Name
+ if id != nil {
+ return id.Name
}
return "<nil>"
}
@@ -404,7 +505,7 @@ type (
// created.
//
BadStmt struct {
- token.Position // beginning position of bad statement
+ From, To token.Pos // position range of bad statement
}
// A DeclStmt node represents a declaration in a statement list.
@@ -417,12 +518,13 @@ type (
// of the immediately preceeding semicolon.
//
EmptyStmt struct {
- token.Position // position of preceeding ";"
+ Semicolon token.Pos // position of preceeding ";"
}
// A LabeledStmt node represents a labeled statement.
LabeledStmt struct {
Label *Ident
+ Colon token.Pos // position of ":"
Stmt Stmt
}
@@ -435,138 +537,212 @@ type (
// An IncDecStmt node represents an increment or decrement statement.
IncDecStmt struct {
- X Expr
- Tok token.Token // INC or DEC
+ X Expr
+ TokPos token.Pos // position of Tok
+ Tok token.Token // INC or DEC
}
// An AssignStmt node represents an assignment or
// a short variable declaration.
+ //
AssignStmt struct {
Lhs []Expr
- TokPos token.Position // position of Tok
- Tok token.Token // assignment token, DEFINE
+ TokPos token.Pos // position of Tok
+ Tok token.Token // assignment token, DEFINE
Rhs []Expr
}
// A GoStmt node represents a go statement.
GoStmt struct {
- token.Position // position of "go" keyword
- Call *CallExpr
+ Go token.Pos // position of "go" keyword
+ Call *CallExpr
}
// A DeferStmt node represents a defer statement.
DeferStmt struct {
- token.Position // position of "defer" keyword
- Call *CallExpr
+ Defer token.Pos // position of "defer" keyword
+ Call *CallExpr
}
// A ReturnStmt node represents a return statement.
ReturnStmt struct {
- token.Position // position of "return" keyword
- Results []Expr
+ Return token.Pos // position of "return" keyword
+ Results []Expr // result expressions; or nil
}
// A BranchStmt node represents a break, continue, goto,
// or fallthrough statement.
//
BranchStmt struct {
- token.Position // position of Tok
- Tok token.Token // keyword token (BREAK, CONTINUE, GOTO, FALLTHROUGH)
- Label *Ident
+ TokPos token.Pos // position of Tok
+ Tok token.Token // keyword token (BREAK, CONTINUE, GOTO, FALLTHROUGH)
+ Label *Ident // label name; or nil
}
// A BlockStmt node represents a braced statement list.
BlockStmt struct {
- token.Position // position of "{"
- List []Stmt
- Rbrace token.Position // position of "}"
+ Lbrace token.Pos // position of "{"
+ List []Stmt
+ Rbrace token.Pos // position of "}"
}
// An IfStmt node represents an if statement.
IfStmt struct {
- token.Position // position of "if" keyword
- Init Stmt
- Cond Expr
- Body *BlockStmt
- Else Stmt
+ If token.Pos // position of "if" keyword
+ Init Stmt // initalization statement; or nil
+ Cond Expr // condition; or nil
+ Body *BlockStmt
+ Else Stmt // else branch; or nil
}
// A CaseClause represents a case of an expression switch statement.
CaseClause struct {
- token.Position // position of "case" or "default" keyword
- Values []Expr // nil means default case
- Colon token.Position // position of ":"
- Body []Stmt // statement list; or nil
+ Case token.Pos // position of "case" or "default" keyword
+ Values []Expr // nil means default case
+ Colon token.Pos // position of ":"
+ Body []Stmt // statement list; or nil
}
// A SwitchStmt node represents an expression switch statement.
SwitchStmt struct {
- token.Position // position of "switch" keyword
- Init Stmt
- Tag Expr
- Body *BlockStmt // CaseClauses only
+ Switch token.Pos // position of "switch" keyword
+ Init Stmt // initalization statement; or nil
+ Tag Expr // tag expression; or nil
+ Body *BlockStmt // CaseClauses only
}
// A TypeCaseClause represents a case of a type switch statement.
TypeCaseClause struct {
- token.Position // position of "case" or "default" keyword
- Types []Expr // nil means default case
- Colon token.Position // position of ":"
- Body []Stmt // statement list; or nil
+ Case token.Pos // position of "case" or "default" keyword
+ Types []Expr // nil means default case
+ Colon token.Pos // position of ":"
+ Body []Stmt // statement list; or nil
}
// An TypeSwitchStmt node represents a type switch statement.
TypeSwitchStmt struct {
- token.Position // position of "switch" keyword
- Init Stmt
- Assign Stmt // x := y.(type)
- Body *BlockStmt // TypeCaseClauses only
+ Switch token.Pos // position of "switch" keyword
+ Init Stmt // initalization statement; or nil
+ Assign Stmt // x := y.(type)
+ Body *BlockStmt // TypeCaseClauses only
}
// A CommClause node represents a case of a select statement.
CommClause struct {
- token.Position // position of "case" or "default" keyword
- Tok token.Token // ASSIGN or DEFINE (valid only if Lhs != nil)
- Lhs, Rhs Expr // Rhs == nil means default case
- Colon token.Position // position of ":"
- Body []Stmt // statement list; or nil
+ Case token.Pos // position of "case" or "default" keyword
+ Tok token.Token // ASSIGN or DEFINE (valid only if Lhs != nil)
+ Lhs, Rhs Expr // Rhs == nil means default case
+ Colon token.Pos // position of ":"
+ Body []Stmt // statement list; or nil
}
// An SelectStmt node represents a select statement.
SelectStmt struct {
- token.Position // position of "select" keyword
- Body *BlockStmt // CommClauses only
+ Select token.Pos // position of "select" keyword
+ Body *BlockStmt // CommClauses only
}
// A ForStmt represents a for statement.
ForStmt struct {
- token.Position // position of "for" keyword
- Init Stmt
- Cond Expr
- Post Stmt
- Body *BlockStmt
+ For token.Pos // position of "for" keyword
+ Init Stmt // initalization statement; or nil
+ Cond Expr // condition; or nil
+ Post Stmt // post iteration statement; or nil
+ Body *BlockStmt
}
// A RangeStmt represents a for statement with a range clause.
RangeStmt struct {
- token.Position // position of "for" keyword
- Key, Value Expr // Value may be nil
- TokPos token.Position // position of Tok
- Tok token.Token // ASSIGN, DEFINE
- X Expr // value to range over
- Body *BlockStmt
+ For token.Pos // position of "for" keyword
+ Key, Value Expr // Value may be nil
+ TokPos token.Pos // position of Tok
+ Tok token.Token // ASSIGN, DEFINE
+ X Expr // value to range over
+ Body *BlockStmt
}
)
-// Pos() implementations for statement nodes where the position
-// corresponds to the position of a sub-node.
+// Pos and End implementations for statement nodes.
//
-func (s *DeclStmt) Pos() token.Position { return s.Decl.Pos() }
-func (s *LabeledStmt) Pos() token.Position { return s.Label.Pos() }
-func (s *ExprStmt) Pos() token.Position { return s.X.Pos() }
-func (s *IncDecStmt) Pos() token.Position { return s.X.Pos() }
-func (s *AssignStmt) Pos() token.Position { return s.Lhs[0].Pos() }
+func (s *BadStmt) Pos() token.Pos { return s.From }
+func (s *DeclStmt) Pos() token.Pos { return s.Decl.Pos() }
+func (s *EmptyStmt) Pos() token.Pos { return s.Semicolon }
+func (s *LabeledStmt) Pos() token.Pos { return s.Label.Pos() }
+func (s *ExprStmt) Pos() token.Pos { return s.X.Pos() }
+func (s *IncDecStmt) Pos() token.Pos { return s.X.Pos() }
+func (s *AssignStmt) Pos() token.Pos { return s.Lhs[0].Pos() }
+func (s *GoStmt) Pos() token.Pos { return s.Go }
+func (s *DeferStmt) Pos() token.Pos { return s.Defer }
+func (s *ReturnStmt) Pos() token.Pos { return s.Return }
+func (s *BranchStmt) Pos() token.Pos { return s.TokPos }
+func (s *BlockStmt) Pos() token.Pos { return s.Lbrace }
+func (s *IfStmt) Pos() token.Pos { return s.If }
+func (s *CaseClause) Pos() token.Pos { return s.Case }
+func (s *SwitchStmt) Pos() token.Pos { return s.Switch }
+func (s *TypeCaseClause) Pos() token.Pos { return s.Case }
+func (s *TypeSwitchStmt) Pos() token.Pos { return s.Switch }
+func (s *CommClause) Pos() token.Pos { return s.Case }
+func (s *SelectStmt) Pos() token.Pos { return s.Select }
+func (s *ForStmt) Pos() token.Pos { return s.For }
+func (s *RangeStmt) Pos() token.Pos { return s.For }
+
+
+func (s *BadStmt) End() token.Pos { return s.To }
+func (s *DeclStmt) End() token.Pos { return s.Decl.End() }
+func (s *EmptyStmt) End() token.Pos {
+ return s.Semicolon + 1 /* len(";") */
+}
+func (s *LabeledStmt) End() token.Pos { return s.Stmt.End() }
+func (s *ExprStmt) End() token.Pos { return s.X.End() }
+func (s *IncDecStmt) End() token.Pos {
+ return s.TokPos + 2 /* len("++") */
+}
+func (s *AssignStmt) End() token.Pos { return s.Rhs[len(s.Rhs)-1].End() }
+func (s *GoStmt) End() token.Pos { return s.Call.End() }
+func (s *DeferStmt) End() token.Pos { return s.Call.End() }
+func (s *ReturnStmt) End() token.Pos {
+ if n := len(s.Results); n > 0 {
+ return s.Results[n-1].End()
+ }
+ return s.Return + 6 // len("return")
+}
+func (s *BranchStmt) End() token.Pos {
+ if s.Label != nil {
+ return s.Label.End()
+ }
+ return token.Pos(int(s.TokPos) + len(s.Tok.String()))
+}
+func (s *BlockStmt) End() token.Pos { return s.Rbrace + 1 }
+func (s *IfStmt) End() token.Pos {
+ if s.Else != nil {
+ return s.Else.End()
+ }
+ return s.Body.End()
+}
+func (s *CaseClause) End() token.Pos {
+ if n := len(s.Body); n > 0 {
+ return s.Body[n-1].End()
+ }
+ return s.Colon + 1
+}
+func (s *SwitchStmt) End() token.Pos { return s.Body.End() }
+func (s *TypeCaseClause) End() token.Pos {
+ if n := len(s.Body); n > 0 {
+ return s.Body[n-1].End()
+ }
+ return s.Colon + 1
+}
+func (s *TypeSwitchStmt) End() token.Pos { return s.Body.End() }
+func (s *CommClause) End() token.Pos {
+ if n := len(s.Body); n > 0 {
+ return s.Body[n-1].End()
+ }
+ return s.Colon + 1
+}
+func (s *SelectStmt) End() token.Pos { return s.Body.End() }
+func (s *ForStmt) End() token.Pos { return s.Body.End() }
+func (s *RangeStmt) End() token.Pos { return s.Body.End() }
// stmtNode() ensures that only statement nodes can be
@@ -618,9 +794,10 @@ type (
// A ValueSpec node represents a constant or variable declaration
// (ConstSpec or VarSpec production).
+ //
ValueSpec struct {
Doc *CommentGroup // associated documentation; or nil
- Names []*Ident // value names
+ Names []*Ident // value names (len(Names) > 0)
Type Expr // value type; or nil
Values []Expr // initial values; or nil
Comment *CommentGroup // line comments; or nil
@@ -630,23 +807,35 @@ type (
TypeSpec struct {
Doc *CommentGroup // associated documentation; or nil
Name *Ident // type name
- Type Expr // *ArrayType, *StructType, *FuncType, *InterfaceType, *MapType, *ChanType or *Ident
+ Type Expr // *Ident, *ParenExpr, *SelectorExpr, *StarExpr, or any of the *XxxTypes
Comment *CommentGroup // line comments; or nil
}
)
-// Pos() implementations for spec nodes.
+// Pos and End implementations for spec nodes.
//
-func (s *ImportSpec) Pos() token.Position {
+func (s *ImportSpec) Pos() token.Pos {
if s.Name != nil {
return s.Name.Pos()
}
return s.Path.Pos()
}
+func (s *ValueSpec) Pos() token.Pos { return s.Names[0].Pos() }
+func (s *TypeSpec) Pos() token.Pos { return s.Name.Pos() }
+
-func (s *ValueSpec) Pos() token.Position { return s.Names[0].Pos() }
-func (s *TypeSpec) Pos() token.Position { return s.Name.Pos() }
+func (s *ImportSpec) End() token.Pos { return s.Path.End() }
+func (s *ValueSpec) End() token.Pos {
+ if n := len(s.Values); n > 0 {
+ return s.Values[n-1].End()
+ }
+ if s.Type != nil {
+ return s.Type.End()
+ }
+ return s.Names[len(s.Names)-1].End()
+}
+func (s *TypeSpec) End() token.Pos { return s.Type.End() }
// specNode() ensures that only spec nodes can be
@@ -665,7 +854,7 @@ type (
// created.
//
BadDecl struct {
- token.Position // beginning position of bad declaration
+ From, To token.Pos // position range of bad declaration
}
// A GenDecl node (generic declaration node) represents an import,
@@ -680,12 +869,12 @@ type (
// token.VAR *ValueSpec
//
GenDecl struct {
- Doc *CommentGroup // associated documentation; or nil
- token.Position // position of Tok
- Tok token.Token // IMPORT, CONST, TYPE, VAR
- Lparen token.Position // position of '(', if any
- Specs []Spec
- Rparen token.Position // position of ')', if any
+ Doc *CommentGroup // associated documentation; or nil
+ TokPos token.Pos // position of Tok
+ Tok token.Token // IMPORT, CONST, TYPE, VAR
+ Lparen token.Pos // position of '(', if any
+ Specs []Spec
+ Rparen token.Pos // position of ')', if any
}
// A FuncDecl node represents a function declaration.
@@ -699,8 +888,26 @@ type (
)
-// The position of a FuncDecl node is the position of its function type.
-func (d *FuncDecl) Pos() token.Position { return d.Type.Pos() }
+// Pos and End implementations for declaration nodes.
+//
+func (d *BadDecl) Pos() token.Pos { return d.From }
+func (d *GenDecl) Pos() token.Pos { return d.TokPos }
+func (d *FuncDecl) Pos() token.Pos { return d.Type.Pos() }
+
+
+func (d *BadDecl) End() token.Pos { return d.To }
+func (d *GenDecl) End() token.Pos {
+ if d.Rparen.IsValid() {
+ return d.Rparen + 1
+ }
+ return d.Specs[0].End()
+}
+func (d *FuncDecl) End() token.Pos {
+ if d.Body != nil {
+ return d.Body.End()
+ }
+ return d.Type.End()
+}
// declNode() ensures that only declaration nodes can be
@@ -721,11 +928,20 @@ func (d *FuncDecl) declNode() {}
// via Doc and Comment fields.
//
type File struct {
- Doc *CommentGroup // associated documentation; or nil
- token.Position // position of "package" keyword
- Name *Ident // package name
- Decls []Decl // top-level declarations
- Comments []*CommentGroup // list of all comments in the source file
+ Doc *CommentGroup // associated documentation; or nil
+ Package token.Pos // position of "package" keyword
+ Name *Ident // package name
+ Decls []Decl // top-level declarations; or nil
+ Comments []*CommentGroup // list of all comments in the source file
+}
+
+
+func (f *File) Pos() token.Pos { return f.Package }
+func (f *File) End() token.Pos {
+ if n := len(f.Decls); n > 0 {
+ return f.Decls[n-1].End()
+ }
+ return f.Name.End()
}
@@ -734,6 +950,10 @@ type File struct {
//
type Package struct {
Name string // package name
- Scope *Scope // package scope
+ Scope *Scope // package scope; or nil
Files map[string]*File // Go source files by filename
}
+
+
+func (p *Package) Pos() token.Pos { return token.NoPos }
+func (p *Package) End() token.Pos { return token.NoPos }
diff --git a/src/pkg/go/ast/filter.go b/src/pkg/go/ast/filter.go
index 009ffc21d..0c3cef4b2 100644
--- a/src/pkg/go/ast/filter.go
+++ b/src/pkg/go/ast/filter.go
@@ -197,7 +197,7 @@ type Filter func(string) bool
func filterIdentList(list []*Ident, f Filter) []*Ident {
j := 0
for _, x := range list {
- if f(x.Name()) {
+ if f(x.Name) {
list[j] = x
j++
}
@@ -212,7 +212,7 @@ func filterSpec(spec Spec, f Filter) bool {
s.Names = filterIdentList(s.Names, f)
return len(s.Names) > 0
case *TypeSpec:
- return f(s.Name.Name())
+ return f(s.Name.Name)
}
return false
}
@@ -236,7 +236,7 @@ func filterDecl(decl Decl, f Filter) bool {
d.Specs = filterSpecList(d.Specs, f)
return len(d.Specs) > 0
case *FuncDecl:
- return f(d.Name.Name())
+ return f(d.Name.Name)
}
return false
}
@@ -307,27 +307,6 @@ const (
var separator = &Comment{noPos, []byte("//")}
-// lineAfterComment computes the position of the beginning
-// of the line immediately following a comment.
-func lineAfterComment(c *Comment) token.Position {
- pos := c.Pos()
- line := pos.Line
- text := c.Text
- if text[1] == '*' {
- /*-style comment - determine endline */
- for _, ch := range text {
- if ch == '\n' {
- line++
- }
- }
- }
- pos.Offset += len(text) + 1 // +1 for newline
- pos.Line = line + 1 // line after comment
- pos.Column = 1 // beginning of line
- return pos
-}
-
-
// MergePackageFiles creates a file AST by merging the ASTs of the
// files belonging to a package. The mode flags control merging behavior.
//
@@ -351,7 +330,7 @@ func MergePackageFiles(pkg *Package, mode MergeMode) *File {
// a package comment; but it's better to collect extra comments
// than drop them on the floor.
var doc *CommentGroup
- var pos token.Position
+ var pos token.Pos
if ndocs > 0 {
list := make([]*Comment, ndocs-1) // -1: no separator before first group
i := 0
@@ -366,11 +345,11 @@ func MergePackageFiles(pkg *Package, mode MergeMode) *File {
list[i] = c
i++
}
- end := lineAfterComment(f.Doc.List[len(f.Doc.List)-1])
- if end.Offset > pos.Offset {
- // Keep the maximum end position as
- // position for the package clause.
- pos = end
+ if f.Package > pos {
+ // Keep the maximum package clause position as
+ // position for the package clause of the merged
+ // files.
+ pos = f.Package
}
}
}
@@ -397,7 +376,7 @@ func MergePackageFiles(pkg *Package, mode MergeMode) *File {
// entities (const, type, vars) if
// multiple declarations are common.
if f, isFun := d.(*FuncDecl); isFun {
- name := f.Name.Name()
+ name := f.Name.Name
if j, exists := funcs[name]; exists {
// function declared already
if decls[j] != nil && decls[j].(*FuncDecl).Doc == nil {
diff --git a/src/pkg/go/ast/print.go b/src/pkg/go/ast/print.go
new file mode 100644
index 000000000..d71490d4a
--- /dev/null
+++ b/src/pkg/go/ast/print.go
@@ -0,0 +1,217 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file contains printing suppport for ASTs.
+
+package ast
+
+import (
+ "fmt"
+ "go/token"
+ "io"
+ "os"
+ "reflect"
+)
+
+
+// A FieldFilter may be provided to Fprint to control the output.
+type FieldFilter func(name string, value reflect.Value) bool
+
+
+// NotNilFilter returns true for field values that are not nil;
+// it returns false otherwise.
+func NotNilFilter(_ string, value reflect.Value) bool {
+ v, ok := value.(interface {
+ IsNil() bool
+ })
+ return !ok || !v.IsNil()
+}
+
+
+// Fprint prints the (sub-)tree starting at AST node x to w.
+//
+// A non-nil FieldFilter f may be provided to control the output:
+// struct fields for which f(fieldname, fieldvalue) is true are
+// are printed; all others are filtered from the output.
+//
+func Fprint(w io.Writer, x interface{}, f FieldFilter) (n int, err os.Error) {
+ // setup printer
+ p := printer{
+ output: w,
+ filter: f,
+ ptrmap: make(map[interface{}]int),
+ last: '\n', // force printing of line number on first line
+ }
+
+ // install error handler
+ defer func() {
+ n = p.written
+ if e := recover(); e != nil {
+ err = e.(localError).err // re-panics if it's not a localError
+ }
+ }()
+
+ // print x
+ if x == nil {
+ p.printf("nil\n")
+ return
+ }
+ p.print(reflect.NewValue(x))
+ p.printf("\n")
+
+ return
+}
+
+
+// Print prints x to standard output, skipping nil fields.
+// Print(x) is the same as Fprint(os.Stdout, x, NotNilFilter).
+func Print(x interface{}) (int, os.Error) {
+ return Fprint(os.Stdout, x, NotNilFilter)
+}
+
+
+type printer struct {
+ output io.Writer
+ filter FieldFilter
+ ptrmap map[interface{}]int // *reflect.PtrValue -> line number
+ written int // number of bytes written to output
+ indent int // current indentation level
+ last byte // the last byte processed by Write
+ line int // current line number
+}
+
+
+var indent = []byte(". ")
+
+func (p *printer) Write(data []byte) (n int, err os.Error) {
+ var m int
+ for i, b := range data {
+ // invariant: data[0:n] has been written
+ if b == '\n' {
+ m, err = p.output.Write(data[n : i+1])
+ n += m
+ if err != nil {
+ return
+ }
+ p.line++
+ } else if p.last == '\n' {
+ _, err = fmt.Fprintf(p.output, "%6d ", p.line)
+ if err != nil {
+ return
+ }
+ for j := p.indent; j > 0; j-- {
+ _, err = p.output.Write(indent)
+ if err != nil {
+ return
+ }
+ }
+ }
+ p.last = b
+ }
+ m, err = p.output.Write(data[n:])
+ n += m
+ return
+}
+
+
+// localError wraps locally caught os.Errors so we can distinguish
+// them from genuine panics which we don't want to return as errors.
+type localError struct {
+ err os.Error
+}
+
+
+// printf is a convenience wrapper that takes care of print errors.
+func (p *printer) printf(format string, args ...interface{}) {
+ n, err := fmt.Fprintf(p, format, args...)
+ p.written += n
+ if err != nil {
+ panic(localError{err})
+ }
+}
+
+
+// Implementation note: Print is written for AST nodes but could be
+// used to print arbitrary data structures; such a version should
+// probably be in a different package.
+
+func (p *printer) print(x reflect.Value) {
+ // Note: This test is only needed because AST nodes
+ // embed a token.Position, and thus all of them
+ // understand the String() method (but it only
+ // applies to the Position field).
+ // TODO: Should reconsider this AST design decision.
+ if pos, ok := x.Interface().(token.Position); ok {
+ p.printf("%s", pos)
+ return
+ }
+
+ if !NotNilFilter("", x) {
+ p.printf("nil")
+ return
+ }
+
+ switch v := x.(type) {
+ case *reflect.InterfaceValue:
+ p.print(v.Elem())
+
+ case *reflect.MapValue:
+ p.printf("%s (len = %d) {\n", x.Type().String(), v.Len())
+ p.indent++
+ for _, key := range v.Keys() {
+ p.print(key)
+ p.printf(": ")
+ p.print(v.Elem(key))
+ }
+ p.indent--
+ p.printf("}")
+
+ case *reflect.PtrValue:
+ p.printf("*")
+ // type-checked ASTs may contain cycles - use ptrmap
+ // to keep track of objects that have been printed
+ // already and print the respective line number instead
+ ptr := v.Interface()
+ if line, exists := p.ptrmap[ptr]; exists {
+ p.printf("(obj @ %d)", line)
+ } else {
+ p.ptrmap[ptr] = p.line
+ p.print(v.Elem())
+ }
+
+ case *reflect.SliceValue:
+ if s, ok := v.Interface().([]byte); ok {
+ p.printf("%#q", s)
+ return
+ }
+ p.printf("%s (len = %d) {\n", x.Type().String(), v.Len())
+ p.indent++
+ for i, n := 0, v.Len(); i < n; i++ {
+ p.printf("%d: ", i)
+ p.print(v.Elem(i))
+ p.printf("\n")
+ }
+ p.indent--
+ p.printf("}")
+
+ case *reflect.StructValue:
+ p.printf("%s {\n", x.Type().String())
+ p.indent++
+ t := v.Type().(*reflect.StructType)
+ for i, n := 0, t.NumField(); i < n; i++ {
+ name := t.Field(i).Name
+ value := v.Field(i)
+ if p.filter == nil || p.filter(name, value) {
+ p.printf("%s: ", name)
+ p.print(value)
+ p.printf("\n")
+ }
+ }
+ p.indent--
+ p.printf("}")
+
+ default:
+ p.printf("%v", x.Interface())
+ }
+}
diff --git a/src/pkg/go/ast/scope.go b/src/pkg/go/ast/scope.go
index b5a38484e..956a208ae 100644
--- a/src/pkg/go/ast/scope.go
+++ b/src/pkg/go/ast/scope.go
@@ -2,25 +2,110 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// This file implements scopes, the objects they contain,
+// and object types.
+
package ast
-import "go/token"
+// A Scope maintains the set of named language entities declared
+// in the scope and a link to the immediately surrounding (outer)
+// scope.
+//
+type Scope struct {
+ Outer *Scope
+ Objects []*Object // in declaration order
+ // Implementation note: In some cases (struct fields,
+ // function parameters) we need the source order of
+ // variables. Thus for now, we store scope entries
+ // in a linear list. If scopes become very large
+ // (say, for packages), we may need to change this
+ // to avoid slow lookups.
+}
+
+
+// NewScope creates a new scope nested in the outer scope.
+func NewScope(outer *Scope) *Scope {
+ const n = 4 // initial scope capacity, must be > 0
+ return &Scope{outer, make([]*Object, 0, n)}
+}
+
+
+// Lookup returns the object with the given name if it is
+// found in scope s, otherwise it returns nil. Outer scopes
+// are ignored.
+//
+// Lookup always returns nil if name is "_", even if the scope
+// contains objects with that name.
+//
+func (s *Scope) Lookup(name string) *Object {
+ if name != "_" {
+ for _, obj := range s.Objects {
+ if obj.Name == name {
+ return obj
+ }
+ }
+ }
+ return nil
+}
+
+
+// Insert attempts to insert a named object into the scope s.
+// If the scope does not contain an object with that name yet
+// or if the object is named "_", Insert inserts the object
+// and returns it. Otherwise, Insert leaves the scope unchanged
+// and returns the object found in the scope instead.
+//
+func (s *Scope) Insert(obj *Object) *Object {
+ alt := s.Lookup(obj.Name)
+ if alt == nil {
+ s.append(obj)
+ alt = obj
+ }
+ return alt
+}
+
+
+func (s *Scope) append(obj *Object) {
+ s.Objects = append(s.Objects, obj)
+}
+
+// ----------------------------------------------------------------------------
+// Objects
+
+// An Object describes a language entity such as a package,
+// constant, type, variable, or function (incl. methods).
+//
+type Object struct {
+ Kind Kind
+ Name string // declared name
+ Type *Type
+ Decl interface{} // corresponding Field, XxxSpec or FuncDecl
+ N int // value of iota for this declaration
+}
+
+
+// NewObj creates a new object of a given kind and name.
+func NewObj(kind Kind, name string) *Object {
+ return &Object{Kind: kind, Name: name}
+}
+
-type ObjKind int
+// Kind describes what an object represents.
+type Kind int
// The list of possible Object kinds.
const (
- Err ObjKind = iota // object kind unknown (forward reference or error)
- Pkg // package
- Con // constant
- Typ // type
- Var // variable
- Fun // function or method
+ Bad Kind = iota // for error handling
+ Pkg // package
+ Con // constant
+ Typ // type
+ Var // variable
+ Fun // function or method
)
var objKindStrings = [...]string{
- Err: "<unknown object kind>",
+ Bad: "bad",
Pkg: "package",
Con: "const",
Typ: "type",
@@ -29,65 +114,129 @@ var objKindStrings = [...]string{
}
-func (kind ObjKind) String() string { return objKindStrings[kind] }
+func (kind Kind) String() string { return objKindStrings[kind] }
-// An Object describes a language entity such as a package,
-// constant, type, variable, or function (incl. methods).
-//
-type Object struct {
- Kind ObjKind
- Pos token.Position // declaration position
- Name string // declared name
+// IsExported returns whether obj is exported.
+func (obj *Object) IsExported() bool { return IsExported(obj.Name) }
+
+
+// ----------------------------------------------------------------------------
+// Types
+
+// A Type represents a Go type.
+type Type struct {
+ Form Form
+ Obj *Object // corresponding type name, or nil
+ Scope *Scope // fields and methods, always present
+ N uint // basic type id, array length, number of function results, or channel direction
+ Key, Elt *Type // map key and array, pointer, slice, map or channel element
+ Params *Scope // function (receiver, input and result) parameters, tuple expressions (results of function calls), or nil
+ Expr Expr // corresponding AST expression
}
-func NewObj(kind ObjKind, pos token.Position, name string) *Object {
- return &Object{kind, pos, name}
+// NewType creates a new type of a given form.
+func NewType(form Form) *Type {
+ return &Type{Form: form, Scope: NewScope(nil)}
}
-// IsExported returns whether obj is exported.
-func (obj *Object) IsExported() bool { return IsExported(obj.Name) }
+// 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
+)
-// A Scope maintains the set of named language entities visible
-// in the scope and a link to the immediately surrounding (outer)
-// scope.
-//
-type Scope struct {
- Outer *Scope
- Objects map[string]*Object
+
+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",
}
-// NewScope creates a new scope nested in the outer scope.
-func NewScope(outer *Scope) *Scope { return &Scope{outer, make(map[string]*Object)} }
-
-
-// Declare attempts to insert a named object into the scope s.
-// If the scope does not contain an object with that name yet,
-// Declare inserts the object, and returns it. Otherwise, the
-// scope remains unchanged and Declare returns the object found
-// in the scope instead.
-func (s *Scope) Declare(obj *Object) *Object {
- decl, found := s.Objects[obj.Name]
- if !found {
- s.Objects[obj.Name] = obj
- decl = obj
- }
- return decl
-}
+func (form Form) String() string { return formStrings[form] }
-// Lookup looks up an object in the current scope chain.
-// The result is nil if the object is not found.
-//
-func (s *Scope) Lookup(name string) *Object {
- for ; s != nil; s = s.Outer {
- if obj, found := s.Objects[name]; found {
- return obj
- }
- }
- return nil
+// 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/ast/walk.go b/src/pkg/go/ast/walk.go
index 6c9837a01..875a92f3f 100644
--- a/src/pkg/go/ast/walk.go
+++ b/src/pkg/go/ast/walk.go
@@ -10,51 +10,57 @@ import "fmt"
// If the result visitor w is not nil, Walk visits each of the children
// of node with the visitor w, followed by a call of w.Visit(nil).
type Visitor interface {
- Visit(node interface{}) (w Visitor)
+ Visit(node Node) (w Visitor)
}
-func walkIdent(v Visitor, x *Ident) {
- if x != nil {
+// Helper functions for common node lists. They may be empty.
+
+func walkIdentList(v Visitor, list []*Ident) {
+ for _, x := range list {
Walk(v, x)
}
}
-func walkCommentGroup(v Visitor, g *CommentGroup) {
- if g != nil {
- Walk(v, g)
+func walkExprList(v Visitor, list []Expr) {
+ for _, x := range list {
+ Walk(v, x)
}
}
-func walkBlockStmt(v Visitor, b *BlockStmt) {
- if b != nil {
- Walk(v, b)
+func walkStmtList(v Visitor, list []Stmt) {
+ for _, x := range list {
+ Walk(v, x)
}
}
-// Walk traverses an AST in depth-first order: If node != nil, it
-// invokes v.Visit(node). If the visitor w returned by v.Visit(node) is
-// not nil, Walk visits each of the children of node with the visitor w,
-// followed by a call of w.Visit(nil).
-//
-// Walk may be called with any of the named ast node types. It also
-// accepts arguments of type []*Field, []*Ident, []Expr, []Stmt and []Decl;
-// the respective children are the slice elements.
-//
-func Walk(v Visitor, node interface{}) {
- if node == nil {
- return
+func walkDeclList(v Visitor, list []Decl) {
+ for _, x := range list {
+ Walk(v, x)
}
+}
+
+
+// TODO(gri): Investigate if providing a closure to Walk leads to
+// simpler use (and may help eliminate Inspect in turn).
+
+// Walk traverses an AST in depth-first order: It starts by calling
+// v.Visit(node); node must not be nil. If the visitor w returned by
+// v.Visit(node) is not nil, Walk is invoked recursively with visitor
+// w for each of the non-nil children of node, followed by a call of
+// w.Visit(nil).
+//
+func Walk(v Visitor, node Node) {
if v = v.Visit(node); v == nil {
return
}
// walk children
// (the order of the cases matches the order
- // of the corresponding declaration in ast.go)
+ // of the corresponding node types in ast.go)
switch n := node.(type) {
// Comments and fields
case *Comment:
@@ -66,11 +72,17 @@ func Walk(v Visitor, node interface{}) {
}
case *Field:
- walkCommentGroup(v, n.Doc)
- Walk(v, n.Names)
+ if n.Doc != nil {
+ Walk(v, n.Doc)
+ }
+ walkIdentList(v, n.Names)
Walk(v, n.Type)
- Walk(v, n.Tag)
- walkCommentGroup(v, n.Comment)
+ if n.Tag != nil {
+ Walk(v, n.Tag)
+ }
+ if n.Comment != nil {
+ Walk(v, n.Comment)
+ }
case *FieldList:
for _, f := range n.List {
@@ -78,25 +90,30 @@ func Walk(v Visitor, node interface{}) {
}
// Expressions
- case *BadExpr, *Ident, *Ellipsis, *BasicLit:
+ case *BadExpr, *Ident, *BasicLit:
// nothing to do
- case *FuncLit:
- if n != nil {
- Walk(v, n.Type)
+ case *Ellipsis:
+ if n.Elt != nil {
+ Walk(v, n.Elt)
}
- walkBlockStmt(v, n.Body)
- case *CompositeLit:
+ case *FuncLit:
Walk(v, n.Type)
- Walk(v, n.Elts)
+ Walk(v, n.Body)
+
+ case *CompositeLit:
+ if n.Type != nil {
+ Walk(v, n.Type)
+ }
+ walkExprList(v, n.Elts)
case *ParenExpr:
Walk(v, n.X)
case *SelectorExpr:
Walk(v, n.X)
- walkIdent(v, n.Sel)
+ Walk(v, n.Sel)
case *IndexExpr:
Walk(v, n.X)
@@ -104,16 +121,22 @@ func Walk(v Visitor, node interface{}) {
case *SliceExpr:
Walk(v, n.X)
- Walk(v, n.Index)
- Walk(v, n.End)
+ if n.Low != nil {
+ Walk(v, n.Low)
+ }
+ if n.High != nil {
+ Walk(v, n.High)
+ }
case *TypeAssertExpr:
Walk(v, n.X)
- Walk(v, n.Type)
+ if n.Type != nil {
+ Walk(v, n.Type)
+ }
case *CallExpr:
Walk(v, n.Fun)
- Walk(v, n.Args)
+ walkExprList(v, n.Args)
case *StarExpr:
Walk(v, n.X)
@@ -131,7 +154,9 @@ func Walk(v Visitor, node interface{}) {
// Types
case *ArrayType:
- Walk(v, n.Len)
+ if n.Len != nil {
+ Walk(v, n.Len)
+ }
Walk(v, n.Elt)
case *StructType:
@@ -164,7 +189,7 @@ func Walk(v Visitor, node interface{}) {
// nothing to do
case *LabeledStmt:
- walkIdent(v, n.Label)
+ Walk(v, n.Label)
Walk(v, n.Stmt)
case *ExprStmt:
@@ -174,150 +199,198 @@ func Walk(v Visitor, node interface{}) {
Walk(v, n.X)
case *AssignStmt:
- Walk(v, n.Lhs)
- Walk(v, n.Rhs)
+ walkExprList(v, n.Lhs)
+ walkExprList(v, n.Rhs)
case *GoStmt:
- if n.Call != nil {
- Walk(v, n.Call)
- }
+ Walk(v, n.Call)
case *DeferStmt:
- if n.Call != nil {
- Walk(v, n.Call)
- }
+ Walk(v, n.Call)
case *ReturnStmt:
- Walk(v, n.Results)
+ walkExprList(v, n.Results)
case *BranchStmt:
- walkIdent(v, n.Label)
+ if n.Label != nil {
+ Walk(v, n.Label)
+ }
case *BlockStmt:
- Walk(v, n.List)
+ walkStmtList(v, n.List)
case *IfStmt:
- Walk(v, n.Init)
- Walk(v, n.Cond)
- walkBlockStmt(v, n.Body)
- Walk(v, n.Else)
+ if n.Init != nil {
+ Walk(v, n.Init)
+ }
+ if n.Cond != nil {
+ Walk(v, n.Cond)
+ }
+ Walk(v, n.Body)
+ if n.Else != nil {
+ Walk(v, n.Else)
+ }
case *CaseClause:
- Walk(v, n.Values)
- Walk(v, n.Body)
+ walkExprList(v, n.Values)
+ walkStmtList(v, n.Body)
case *SwitchStmt:
- Walk(v, n.Init)
- Walk(v, n.Tag)
- walkBlockStmt(v, n.Body)
+ if n.Init != nil {
+ Walk(v, n.Init)
+ }
+ if n.Tag != nil {
+ Walk(v, n.Tag)
+ }
+ Walk(v, n.Body)
case *TypeCaseClause:
- Walk(v, n.Types)
- Walk(v, n.Body)
+ for _, x := range n.Types {
+ Walk(v, x)
+ }
+ walkStmtList(v, n.Body)
case *TypeSwitchStmt:
- Walk(v, n.Init)
+ if n.Init != nil {
+ Walk(v, n.Init)
+ }
Walk(v, n.Assign)
- walkBlockStmt(v, n.Body)
+ Walk(v, n.Body)
case *CommClause:
- Walk(v, n.Lhs)
- Walk(v, n.Rhs)
- Walk(v, n.Body)
+ if n.Lhs != nil {
+ Walk(v, n.Lhs)
+ }
+ if n.Rhs != nil {
+ Walk(v, n.Rhs)
+ }
+ walkStmtList(v, n.Body)
case *SelectStmt:
- walkBlockStmt(v, n.Body)
+ Walk(v, n.Body)
case *ForStmt:
- Walk(v, n.Init)
- Walk(v, n.Cond)
- Walk(v, n.Post)
- walkBlockStmt(v, n.Body)
+ if n.Init != nil {
+ Walk(v, n.Init)
+ }
+ if n.Cond != nil {
+ Walk(v, n.Cond)
+ }
+ if n.Post != nil {
+ Walk(v, n.Post)
+ }
+ Walk(v, n.Body)
case *RangeStmt:
Walk(v, n.Key)
- Walk(v, n.Value)
+ if n.Value != nil {
+ Walk(v, n.Value)
+ }
Walk(v, n.X)
- walkBlockStmt(v, n.Body)
+ Walk(v, n.Body)
// Declarations
case *ImportSpec:
- walkCommentGroup(v, n.Doc)
- walkIdent(v, n.Name)
+ if n.Doc != nil {
+ Walk(v, n.Doc)
+ }
+ if n.Name != nil {
+ Walk(v, n.Name)
+ }
Walk(v, n.Path)
- walkCommentGroup(v, n.Comment)
+ if n.Comment != nil {
+ Walk(v, n.Comment)
+ }
case *ValueSpec:
- walkCommentGroup(v, n.Doc)
- Walk(v, n.Names)
- Walk(v, n.Type)
- Walk(v, n.Values)
- walkCommentGroup(v, n.Comment)
+ if n.Doc != nil {
+ Walk(v, n.Doc)
+ }
+ walkIdentList(v, n.Names)
+ if n.Type != nil {
+ Walk(v, n.Type)
+ }
+ walkExprList(v, n.Values)
+ if n.Comment != nil {
+ Walk(v, n.Comment)
+ }
case *TypeSpec:
- walkCommentGroup(v, n.Doc)
- walkIdent(v, n.Name)
+ if n.Doc != nil {
+ Walk(v, n.Doc)
+ }
+ Walk(v, n.Name)
Walk(v, n.Type)
- walkCommentGroup(v, n.Comment)
+ if n.Comment != nil {
+ Walk(v, n.Comment)
+ }
case *BadDecl:
// nothing to do
case *GenDecl:
- walkCommentGroup(v, n.Doc)
+ if n.Doc != nil {
+ Walk(v, n.Doc)
+ }
for _, s := range n.Specs {
Walk(v, s)
}
case *FuncDecl:
- walkCommentGroup(v, n.Doc)
+ if n.Doc != nil {
+ Walk(v, n.Doc)
+ }
if n.Recv != nil {
Walk(v, n.Recv)
}
- walkIdent(v, n.Name)
- if n.Type != nil {
- Walk(v, n.Type)
+ Walk(v, n.Name)
+ Walk(v, n.Type)
+ if n.Body != nil {
+ Walk(v, n.Body)
}
- walkBlockStmt(v, n.Body)
// Files and packages
case *File:
- walkCommentGroup(v, n.Doc)
- walkIdent(v, n.Name)
- Walk(v, n.Decls)
+ if n.Doc != nil {
+ Walk(v, n.Doc)
+ }
+ Walk(v, n.Name)
+ walkDeclList(v, n.Decls)
for _, g := range n.Comments {
Walk(v, g)
}
+ // don't walk n.Comments - they have been
+ // visited already through the individual
+ // nodes
case *Package:
for _, f := range n.Files {
Walk(v, f)
}
- case []*Ident:
- for _, x := range n {
- Walk(v, x)
- }
+ default:
+ fmt.Printf("ast.Walk: unexpected node type %T", n)
+ panic("ast.Walk")
+ }
- case []Expr:
- for _, x := range n {
- Walk(v, x)
- }
+ v.Visit(nil)
+}
- case []Stmt:
- for _, x := range n {
- Walk(v, x)
- }
- case []Decl:
- for _, x := range n {
- Walk(v, x)
- }
+type inspector func(Node) bool
- default:
- fmt.Printf("ast.Walk: unexpected type %T", n)
- panic("ast.Walk")
+func (f inspector) Visit(node Node) Visitor {
+ if f(node) {
+ return f
}
+ return nil
+}
- v.Visit(nil)
+
+// Inspect traverses an AST in depth-first order: It starts by calling
+// f(node); node must not be nil. If f returns true, Inspect invokes f
+// for all the non-nil children of node, recursively.
+//
+func Inspect(node Node, f func(Node) bool) {
+ Walk(inspector(f), node)
}
diff --git a/src/pkg/go/doc/Makefile b/src/pkg/go/doc/Makefile
index 1558ac30a..a5152c793 100644
--- a/src/pkg/go/doc/Makefile
+++ b/src/pkg/go/doc/Makefile
@@ -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 ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=go/doc
GOFILES=\
diff --git a/src/pkg/go/doc/comment.go b/src/pkg/go/doc/comment.go
index bbbc6a3c2..9ff0bd536 100644
--- a/src/pkg/go/doc/comment.go
+++ b/src/pkg/go/doc/comment.go
@@ -8,7 +8,6 @@ package doc
import (
"go/ast"
- "http" // for URLEscape
"io"
"regexp"
"strings"
@@ -63,16 +62,7 @@ func CommentText(comment *ast.CommentGroup) string {
// Walk lines, stripping trailing white space and adding to list.
for _, l := range cl {
- l = stripTrailingWhitespace(l)
- // Add to list.
- n := len(lines)
- if n+1 >= cap(lines) {
- newlines := make([]string, n, 2*cap(lines))
- copy(newlines, lines)
- lines = newlines
- }
- lines = lines[0 : n+1]
- lines[n] = l
+ lines = append(lines, stripTrailingWhitespace(l))
}
}
@@ -88,10 +78,8 @@ func CommentText(comment *ast.CommentGroup) string {
lines = lines[0:n]
// Add final "" entry to get trailing newline from Join.
- // The original loop always leaves room for one more.
if n > 0 && lines[n-1] != "" {
- lines = lines[0 : n+1]
- lines[n] = ""
+ lines = append(lines, "")
}
return strings.Join(lines, "\n")
@@ -195,12 +183,12 @@ var (
// into a link). Go identifiers that appear in the words map are italicized; if
// the corresponding map value is not the empty string, it is considered a URL
// and the word is converted into a link. If nice is set, the remaining text's
-// appearance is improved where is makes sense (e.g., `` is turned into &ldquo;
+// appearance is improved where it makes sense (e.g., `` is turned into &ldquo;
// and '' into &rdquo;).
func emphasize(w io.Writer, line []byte, words map[string]string, nice bool) {
for {
- m := matchRx.Execute(line)
- if len(m) == 0 {
+ m := matchRx.FindSubmatchIndex(line)
+ if m == nil {
break
}
// m >= 6 (two parenthesized sub-regexps in matchRx, 1st one is identRx)
@@ -224,11 +212,10 @@ func emphasize(w io.Writer, line []byte, words map[string]string, nice bool) {
italics = false // don't italicize URLs
}
-
// write match
if len(url) > 0 {
w.Write(html_a)
- w.Write([]byte(http.URLEscape(url)))
+ template.HTMLEscape(w, []byte(url))
w.Write(html_aq)
}
if italics {
diff --git a/src/pkg/go/doc/doc.go b/src/pkg/go/doc/doc.go
index b73fd285c..fb1c4e03d 100644
--- a/src/pkg/go/doc/doc.go
+++ b/src/pkg/go/doc/doc.go
@@ -6,7 +6,6 @@
package doc
import (
- "container/vector"
"go/ast"
"go/token"
"regexp"
@@ -21,7 +20,7 @@ type typeDoc struct {
// 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 *vector.Vector // list of *ast.GenDecl (consts and vars)
+ values []*ast.GenDecl // consts and vars
factories map[string]*ast.FuncDecl
methods map[string]*ast.FuncDecl
}
@@ -37,19 +36,17 @@ type typeDoc struct {
type docReader struct {
doc *ast.CommentGroup // package documentation, if any
pkgName string
- values *vector.Vector // list of *ast.GenDecl (consts and vars)
+ values []*ast.GenDecl // consts and vars
types map[string]*typeDoc
funcs map[string]*ast.FuncDecl
- bugs *vector.Vector // list of *ast.CommentGroup
+ bugs []*ast.CommentGroup
}
func (doc *docReader) init(pkgName string) {
doc.pkgName = pkgName
- doc.values = new(vector.Vector)
doc.types = make(map[string]*typeDoc)
doc.funcs = make(map[string]*ast.FuncDecl)
- doc.bugs = new(vector.Vector)
}
@@ -69,7 +66,7 @@ func (doc *docReader) addDoc(comments *ast.CommentGroup) {
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.Position{}, []byte("//")} // separator line
+ list[n1] = &ast.Comment{token.NoPos, []byte("//")} // separator line
copy(list[n1+1:], comments.List)
doc.doc = &ast.CommentGroup{list}
}
@@ -77,7 +74,7 @@ func (doc *docReader) addDoc(comments *ast.CommentGroup) {
func (doc *docReader) addType(decl *ast.GenDecl) {
spec := decl.Specs[0].(*ast.TypeSpec)
- typ := doc.lookupTypeDoc(spec.Name.Name())
+ typ := doc.lookupTypeDoc(spec.Name.Name)
// typ should always be != nil since declared types
// are always named - be conservative and check
if typ != nil {
@@ -96,7 +93,7 @@ func (doc *docReader) lookupTypeDoc(name string) *typeDoc {
return tdoc
}
// type wasn't found - add one without declaration
- tdoc := &typeDoc{nil, new(vector.Vector), make(map[string]*ast.FuncDecl), make(map[string]*ast.FuncDecl)}
+ tdoc := &typeDoc{nil, nil, make(map[string]*ast.FuncDecl), make(map[string]*ast.FuncDecl)}
doc.types[name] = tdoc
return tdoc
}
@@ -108,7 +105,7 @@ func baseTypeName(typ ast.Expr) string {
// if the type is not exported, the effect to
// a client is as if there were no type name
if t.IsExported() {
- return string(t.Name())
+ return string(t.Name)
}
case *ast.StarExpr:
return baseTypeName(t.X)
@@ -130,7 +127,7 @@ func (doc *docReader) addValue(decl *ast.GenDecl) {
name := ""
switch {
case v.Type != nil:
- // a type is present; determine it's name
+ // 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;
@@ -156,16 +153,16 @@ func (doc *docReader) addValue(decl *ast.GenDecl) {
// determine values list
const threshold = 0.75
- values := doc.values
+ values := &doc.values
if domName != "" && domFreq >= int(float(len(decl.Specs))*threshold) {
// typed entries are sufficiently frequent
typ := doc.lookupTypeDoc(domName)
if typ != nil {
- values = typ.values // associate with that type
+ values = &typ.values // associate with that type
}
}
- values.Push(decl)
+ *values = append(*values, decl)
}
@@ -173,7 +170,7 @@ func (doc *docReader) addValue(decl *ast.GenDecl) {
// 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()
+ 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
@@ -188,7 +185,7 @@ func setFunc(table map[string]*ast.FuncDecl, f *ast.FuncDecl) {
func (doc *docReader) addFunc(fun *ast.FuncDecl) {
- name := fun.Name.Name()
+ name := fun.Name.Name
// determine if it should be associated with a type
if fun.Recv != nil {
@@ -252,7 +249,6 @@ func (doc *docReader) addDecl(decl ast.Decl) {
doc.addValue(d)
case token.TYPE:
// types are handled individually
- var noPos token.Position
for _, spec := range d.Specs {
// make a (fake) GenDecl node for this TypeSpec
// (we need to do this here - as opposed to just
@@ -265,7 +261,7 @@ func (doc *docReader) addDecl(decl ast.Decl) {
// 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, noPos, []ast.Spec{spec}, noPos})
+ 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.
}
}
@@ -277,14 +273,9 @@ func (doc *docReader) addDecl(decl ast.Decl) {
func copyCommentList(list []*ast.Comment) []*ast.Comment {
- copy := make([]*ast.Comment, len(list))
- for i, c := range list {
- copy[i] = c
- }
- return copy
+ 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
@@ -309,13 +300,13 @@ func (doc *docReader) addFile(src *ast.File) {
// collect BUG(...) comments
for _, c := range src.Comments {
text := c.List[0].Text
- if m := bug_markers.Execute(text); len(m) > 0 {
+ if m := bug_markers.FindIndex(text); m != nil {
// found a BUG comment; maybe empty
if btxt := text[m[1]:]; bug_content.Match(btxt) {
// non-empty BUG comment; collect comment without BUG prefix
list := copyCommentList(c.List)
list[0].Text = text[m[1]:]
- doc.bugs.Push(&ast.CommentGroup{list})
+ doc.bugs = append(doc.bugs, &ast.CommentGroup{list})
}
}
}
@@ -325,7 +316,7 @@ func (doc *docReader) addFile(src *ast.File) {
func NewFileDoc(file *ast.File) *PackageDoc {
var r docReader
- r.init(file.Name.Name())
+ r.init(file.Name.Name)
r.addFile(file)
return r.newDoc("", nil)
}
@@ -370,9 +361,9 @@ func declName(d *ast.GenDecl) string {
switch v := d.Specs[0].(type) {
case *ast.ValueSpec:
- return v.Names[0].Name()
+ return v.Names[0].Name
case *ast.TypeSpec:
- return v.Name.Name()
+ return v.Name.Name
}
return ""
@@ -390,11 +381,10 @@ func (p sortValueDoc) Less(i, j int) bool {
}
-func makeValueDocs(v *vector.Vector, tok token.Token) []*ValueDoc {
- d := make([]*ValueDoc, v.Len()) // big enough in any case
+func makeValueDocs(list []*ast.GenDecl, tok token.Token) []*ValueDoc {
+ d := make([]*ValueDoc, len(list)) // big enough in any case
n := 0
- for i := range d {
- decl := v.At(i).(*ast.GenDecl)
+ for i, decl := range list {
if decl.Tok == tok {
d[n] = &ValueDoc{CommentText(decl.Doc), decl, i}
n++
@@ -434,7 +424,7 @@ func makeFuncDocs(m map[string]*ast.FuncDecl) []*FuncDoc {
if f.Recv != nil {
doc.Recv = f.Recv.List[0].Type
}
- doc.Name = f.Name.Name()
+ doc.Name = f.Name.Name
doc.Decl = f
d[i] = doc
i++
@@ -467,7 +457,7 @@ 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 {
+ 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
@@ -511,7 +501,7 @@ func (doc *docReader) makeTypeDocs(m map[string]*typeDoc) []*TypeDoc {
// file containing the explicit type declaration is missing or if
// an unqualified type name was used after a "." import)
// 1) move values
- doc.values.AppendVector(old.values)
+ doc.values = append(doc.values, old.values...)
// 2) move factory functions
for name, f := range old.factories {
doc.funcs[name] = f
@@ -531,10 +521,10 @@ func (doc *docReader) makeTypeDocs(m map[string]*typeDoc) []*TypeDoc {
}
-func makeBugDocs(v *vector.Vector) []string {
- d := make([]string, v.Len())
- for i := 0; i < v.Len(); i++ {
- d[i] = CommentText(v.At(i).(*ast.CommentGroup))
+func makeBugDocs(list []*ast.CommentGroup) []string {
+ d := make([]string, len(list))
+ for i, g := range list {
+ d[i] = CommentText(g)
}
return d
}
@@ -587,12 +577,12 @@ func matchDecl(d *ast.GenDecl, f Filter) bool {
switch v := d.(type) {
case *ast.ValueSpec:
for _, name := range v.Names {
- if f(name.Name()) {
+ if f(name.Name) {
return true
}
}
case *ast.TypeSpec:
- if f(v.Name.Name()) {
+ if f(v.Name.Name) {
return true
}
}
diff --git a/src/pkg/go/parser/Makefile b/src/pkg/go/parser/Makefile
index d9b52a7d9..d301f41eb 100644
--- a/src/pkg/go/parser/Makefile
+++ b/src/pkg/go/parser/Makefile
@@ -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 ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=go/parser
GOFILES=\
diff --git a/src/pkg/go/parser/interface.go b/src/pkg/go/parser/interface.go
index e1ddb37c3..84d699a67 100644
--- a/src/pkg/go/parser/interface.go
+++ b/src/pkg/go/parser/interface.go
@@ -57,72 +57,73 @@ func (p *parser) parseEOF() os.Error {
// ParseExpr parses a Go expression and returns the corresponding
-// AST node. The filename, src, and scope arguments have the same interpretation
+// 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(filename string, src interface{}, scope *ast.Scope) (ast.Expr, os.Error) {
+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(filename, data, scope, 0)
- return p.parseExpr(), p.parseEOF()
+ p.init(fset, filename, data, 0)
+ x := p.parseExpr()
+ if p.tok == token.SEMICOLON {
+ p.next() // consume automatically inserted semicolon, if any
+ }
+ return x, p.parseEOF()
}
// ParseStmtList parses a list of Go statements and returns the list
-// of corresponding AST nodes. The filename, src, and scope arguments have the same
+// of corresponding AST nodes. The fset, filename, and src arguments have the same
// interpretation as for ParseFile. If there is an error, the node
// list may be nil or contain partial ASTs.
//
-func ParseStmtList(filename string, src interface{}, scope *ast.Scope) ([]ast.Stmt, os.Error) {
+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(filename, data, scope, 0)
+ p.init(fset, filename, data, 0)
return p.parseStmtList(), p.parseEOF()
}
// ParseDeclList parses a list of Go declarations and returns the list
-// of corresponding AST nodes. The filename, src, and scope arguments have the same
+// 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(filename string, src interface{}, scope *ast.Scope) ([]ast.Decl, os.Error) {
+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(filename, data, scope, 0)
+ p.init(fset, filename, data, 0)
return p.parseDeclList(), p.parseEOF()
}
-// ParseFile parses a Go source file and returns a File node.
+// ParseFile parses the source code of a single Go source file and returns
+// the corresponding ast.File node. The source code may be provided via
+// the filename of the source file, or via the src parameter.
//
-// If src != nil, ParseFile parses the file source from src. src may
-// be provided in a variety of formats. At the moment the following types
-// are supported: string, []byte, and io.Reader. In this case, filename is
-// only used for source position information and error messages.
+// 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.
//
-// If scope != nil, it is the immediately surrounding scope for the file
-// (the package scope) and it is used to lookup and declare identifiers.
-// When parsing multiple files belonging to a package, the same scope should
-// be provided to all files.
-//
// The mode parameter controls the amount of source text parsed and other
-// optional parser functionality.
+// optional parser functionality. Position information is recorded in the
+// file set fset.
//
// If the source couldn't be read, the returned AST is nil and the error
// indicates the specific failure. If the source was read but syntax
@@ -130,57 +131,57 @@ func ParseDeclList(filename string, src interface{}, scope *ast.Scope) ([]ast.De
// representing the fragments of erroneous source code). Multiple errors
// are returned via a scanner.ErrorList which is sorted by file position.
//
-func ParseFile(filename string, src interface{}, scope *ast.Scope, mode uint) (*ast.File, os.Error) {
+func ParseFile(fset *token.FileSet, filename string, src interface{}, mode uint) (*ast.File, os.Error) {
data, err := readSource(filename, src)
if err != nil {
return nil, err
}
var p parser
- p.init(filename, data, scope, mode)
+ p.init(fset, filename, data, mode)
return p.parseFile(), p.GetError(scanner.NoMultiples) // parseFile() reads to EOF
}
// ParseFiles calls ParseFile for each file in the filenames list and returns
// a map of package name -> package AST with all the packages found. The mode
-// bits are passed to ParseFile unchanged.
+// 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 last
+// be incomplete (missing packages and/or incomplete packages) and the first
// error encountered is returned.
//
-func ParseFiles(filenames []string, scope *ast.Scope, mode uint) (map[string]*ast.Package, os.Error) {
- pkgs := make(map[string]*ast.Package)
- var err os.Error
+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 {
- var src *ast.File
- src, err = ParseFile(filename, nil, scope, mode)
- if err == nil {
- name := src.Name.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, scope, make(map[string]*ast.File)}
+ pkg = &ast.Package{name, nil, make(map[string]*ast.File)}
pkgs[name] = pkg
}
pkg.Files[filename] = src
+ } else if first == nil {
+ first = err
}
}
-
- return pkgs, err
+ return
}
// ParseDir calls ParseFile for the files in the directory specified by path and
// returns a map of package name -> package AST with all the packages found. If
// filter != nil, only the files with os.FileInfo entries passing through the filter
-// are considered. The mode bits are passed to ParseFile unchanged.
+// are considered. The mode bits are passed to ParseFile unchanged. Position
+// information is recorded in the file set fset.
//
// If the directory couldn't be read, a nil map and the respective error are
-// returned. If a parse error occured, a non-nil but incomplete map and the
+// returned. If a parse error occurred, a non-nil but incomplete map and the
// error are returned.
//
-func ParseDir(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 uint) (map[string]*ast.Package, os.Error) {
fd, err := os.Open(path, os.O_RDONLY, 0)
if err != nil {
return nil, err
@@ -203,6 +204,5 @@ func ParseDir(path string, filter func(*os.FileInfo) bool, mode uint) (map[strin
}
filenames = filenames[0:n]
- var scope *ast.Scope = nil // for now tracking of declarations is disabled
- return ParseFiles(filenames, scope, mode)
+ return ParseFiles(fset, filenames, mode)
}
diff --git a/src/pkg/go/parser/parser.go b/src/pkg/go/parser/parser.go
index c1914005a..3b2fe4577 100644
--- a/src/pkg/go/parser/parser.go
+++ b/src/pkg/go/parser/parser.go
@@ -10,7 +10,6 @@
package parser
import (
- "container/vector"
"fmt"
"go/ast"
"go/scanner"
@@ -36,6 +35,7 @@ const (
// The parser structure holds the parser's internal state.
type parser struct {
+ file *token.File
scanner.ErrorVector
scanner scanner.Scanner
@@ -45,23 +45,17 @@ type parser struct {
indent uint // indentation used for tracing output
// Comments
- comments vector.Vector // list of *CommentGroup
+ comments []*ast.CommentGroup
leadComment *ast.CommentGroup // the last lead comment
lineComment *ast.CommentGroup // the last line comment
// Next token
- pos token.Position // token position
- tok token.Token // one token look-ahead
- lit []byte // token literal
+ pos token.Pos // token position
+ tok token.Token // one token look-ahead
+ lit []byte // token literal
// Non-syntactic parser control
exprLev int // < 0: in control clause, >= 0: in expression
-
- // Scopes
- checkDecl bool // if set, check declarations
- pkgScope *ast.Scope
- fileScope *ast.Scope
- funcScope *ast.Scope
}
@@ -75,16 +69,10 @@ func scannerMode(mode uint) uint {
}
-func (p *parser) init(filename string, src []byte, scope *ast.Scope, mode uint) {
- p.scanner.Init(filename, src, p, scannerMode(mode))
+func (p *parser) init(fset *token.FileSet, filename string, src []byte, mode uint) {
+ p.file = p.scanner.Init(fset, filename, src, p, scannerMode(mode))
p.mode = mode
p.trace = mode&Trace != 0 // for convenience (p.trace is used frequently)
- if scope != nil {
- p.checkDecl = true
- } else {
- scope = ast.NewScope(nil) // provide a dummy scope
- }
- p.pkgScope = scope
p.next()
}
@@ -96,13 +84,14 @@ func (p *parser) printTrace(a ...interface{}) {
const dots = ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . " +
". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . "
const n = uint(len(dots))
- fmt.Printf("%5d:%3d: ", p.pos.Line, p.pos.Column)
+ pos := p.file.Position(p.pos)
+ fmt.Printf("%5d:%3d: ", pos.Line, pos.Column)
i := 2 * p.indent
for ; i > n; i -= n {
fmt.Print(dots)
}
fmt.Print(dots[0:i])
- fmt.Println(a)
+ fmt.Println(a...)
}
@@ -124,9 +113,9 @@ func un(p *parser) {
func (p *parser) next0() {
// Because of one-token look-ahead, print the previous token
// when tracing as it provides a more readable output. The
- // very first token (p.pos.Line == 0) is not initialized (it
- // is token.ILLEGAL), so don't print it .
- if p.trace && p.pos.Line > 0 {
+ // very first token (!p.pos.IsValid()) is not initialized
+ // (it is token.ILLEGAL), so don't print it .
+ if p.trace && p.pos.IsValid() {
s := p.tok.String()
switch {
case p.tok.IsLiteral():
@@ -145,7 +134,7 @@ func (p *parser) next0() {
func (p *parser) consumeComment() (comment *ast.Comment, endline int) {
// /*-style comments may end on a different line than where they start.
// Scan the comment for '\n' chars and adjust endline accordingly.
- endline = p.pos.Line
+ endline = p.file.Line(p.pos)
if p.lit[1] == '*' {
for _, b := range p.lit {
if b == '\n' {
@@ -167,23 +156,17 @@ func (p *parser) consumeComment() (comment *ast.Comment, endline int) {
// token terminates a comment group.
//
func (p *parser) consumeCommentGroup() (comments *ast.CommentGroup, endline int) {
- var list vector.Vector
- endline = p.pos.Line
- for p.tok == token.COMMENT && endline+1 >= p.pos.Line {
+ var list []*ast.Comment
+ endline = p.file.Line(p.pos)
+ for p.tok == token.COMMENT && endline+1 >= p.file.Line(p.pos) {
var comment *ast.Comment
comment, endline = p.consumeComment()
- list.Push(comment)
- }
-
- // convert list
- group := make([]*ast.Comment, len(list))
- for i, x := range list {
- group[i] = x.(*ast.Comment)
+ list = append(list, comment)
}
// add comment group to the comments list
- comments = &ast.CommentGroup{group}
- p.comments.Push(comments)
+ comments = &ast.CommentGroup{list}
+ p.comments = append(p.comments, comments)
return
}
@@ -207,18 +190,18 @@ func (p *parser) consumeCommentGroup() (comments *ast.CommentGroup, endline int)
func (p *parser) next() {
p.leadComment = nil
p.lineComment = nil
- line := p.pos.Line // current line
+ line := p.file.Line(p.pos) // current line
p.next0()
if p.tok == token.COMMENT {
var comment *ast.CommentGroup
var endline int
- if p.pos.Line == line {
+ if p.file.Line(p.pos) == line {
// The comment is on same line as previous token; it
// cannot be a lead comment but may be a line comment.
comment, endline = p.consumeCommentGroup()
- if p.pos.Line != endline {
+ if p.file.Line(p.pos) != endline {
// The next token is on a different line, thus
// the last comment group is a line comment.
p.lineComment = comment
@@ -231,7 +214,7 @@ func (p *parser) next() {
comment, endline = p.consumeCommentGroup()
}
- if endline+1 == p.pos.Line {
+ if endline+1 == p.file.Line(p.pos) {
// The next token is following on the line immediately after the
// comment group, thus the last comment group is a lead comment.
p.leadComment = comment
@@ -240,26 +223,35 @@ func (p *parser) next() {
}
-func (p *parser) errorExpected(pos token.Position, msg string) {
+func (p *parser) error(pos token.Pos, msg string) {
+ p.Error(p.file.Position(pos), msg)
+}
+
+
+func (p *parser) errorExpected(pos token.Pos, msg string) {
msg = "expected " + msg
- if pos.Offset == p.pos.Offset {
+ if pos == p.pos {
// the error happened at the current position;
// make the error message more specific
- msg += ", found '" + p.tok.String() + "'"
- if p.tok.IsLiteral() {
- msg += " " + string(p.lit)
+ if p.tok == token.SEMICOLON && p.lit[0] == '\n' {
+ msg += ", found newline"
+ } else {
+ msg += ", found '" + p.tok.String() + "'"
+ if p.tok.IsLiteral() {
+ msg += " " + string(p.lit)
+ }
}
}
- p.Error(pos, msg)
+ p.error(pos, msg)
}
-func (p *parser) expect(tok token.Token) token.Position {
+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
+ p.next() // make progress
return pos
}
@@ -272,152 +264,51 @@ func (p *parser) expectSemi() {
// ----------------------------------------------------------------------------
-// Scope support
-
-func (p *parser) openScope() *ast.Scope {
- p.funcScope = ast.NewScope(p.funcScope)
- return p.funcScope
-}
-
-
-func (p *parser) closeScope() { p.funcScope = p.funcScope.Outer }
-
+// Identifiers
-func (p *parser) parseIdent(kind ast.ObjKind) *ast.Ident {
- obj := ast.NewObj(kind, p.pos, "_")
+func (p *parser) parseIdent() *ast.Ident {
+ pos := p.pos
+ name := "_"
if p.tok == token.IDENT {
- obj.Name = string(p.lit)
+ name = string(p.lit)
p.next()
} else {
p.expect(token.IDENT) // use expect() error handling
}
- return &ast.Ident{obj.Pos, obj}
+ return &ast.Ident{pos, name, nil}
}
-func (p *parser) parseIdentList(kind ast.ObjKind) []*ast.Ident {
+func (p *parser) parseIdentList() (list []*ast.Ident) {
if p.trace {
defer un(trace(p, "IdentList"))
}
- var list vector.Vector
- list.Push(p.parseIdent(kind))
+ list = append(list, p.parseIdent())
for p.tok == token.COMMA {
p.next()
- list.Push(p.parseIdent(kind))
+ list = append(list, p.parseIdent())
}
- // convert vector
- idents := make([]*ast.Ident, len(list))
- for i, x := range list {
- idents[i] = x.(*ast.Ident)
- }
-
- return idents
-}
-
-
-func (p *parser) declIdent(scope *ast.Scope, id *ast.Ident) {
- decl := scope.Declare(id.Obj)
- if p.checkDecl && decl != id.Obj {
- if decl.Kind == ast.Err {
- // declared object is a forward declaration - update it
- *decl = *id.Obj
- id.Obj = decl
- return
- }
- p.Error(id.Pos(), "'"+id.Name()+"' declared already at "+decl.Pos.String())
- }
-}
-
-
-func (p *parser) declIdentList(scope *ast.Scope, list []*ast.Ident) {
- for _, id := range list {
- p.declIdent(scope, id)
- }
-}
-
-
-func (p *parser) declFieldList(scope *ast.Scope, list []*ast.Field) {
- for _, f := range list {
- p.declIdentList(scope, f.Names)
- }
-}
-
-
-func (p *parser) findIdent() *ast.Ident {
- pos := p.pos
- name := "_"
- var obj *ast.Object
- if p.tok == token.IDENT {
- name = string(p.lit)
- obj = p.funcScope.Lookup(name)
- p.next()
- } else {
- p.expect(token.IDENT) // use expect() error handling
- }
- if obj == nil {
- // No declaration found: either we are outside any function
- // (p.funcScope == nil) or the identifier is not declared
- // in any function. Try the file and package scope.
- obj = p.fileScope.Lookup(name) // file scope is nested in package scope
- if obj == nil {
- // No declaration found anywhere: track as
- // unresolved identifier in the package scope.
- obj = ast.NewObj(ast.Err, pos, name)
- p.pkgScope.Declare(obj)
- }
- }
- return &ast.Ident{pos, obj}
-}
-
-
-func (p *parser) findIdentInScope(scope *ast.Scope) *ast.Ident {
- pos := p.pos
- name := "_"
- var obj *ast.Object
- if p.tok == token.IDENT {
- name = string(p.lit)
- obj = scope.Lookup(name)
- p.next()
- } else {
- p.expect(token.IDENT) // use expect() error handling
- }
- if obj == nil {
- // TODO(gri) At the moment we always arrive here because
- // we don't track the lookup scope (and sometimes
- // we can't). Just create a useable ident for now.
- obj = ast.NewObj(ast.Err, pos, name)
- }
- return &ast.Ident{pos, obj}
+ return
}
// ----------------------------------------------------------------------------
// Common productions
-func makeExprList(list *vector.Vector) []ast.Expr {
- exprs := make([]ast.Expr, len(*list))
- for i, x := range *list {
- exprs[i] = x.(ast.Expr)
- }
- return exprs
-}
-
-
-func (p *parser) parseExprList() []ast.Expr {
+func (p *parser) parseExprList() (list []ast.Expr) {
if p.trace {
defer un(trace(p, "ExpressionList"))
}
- var list vector.Vector
- list.Push(p.parseExpr())
+ list = append(list, p.parseExpr())
for p.tok == token.COMMA {
p.next()
- list.Push(p.parseExpr())
+ list = append(list, p.parseExpr())
}
- return makeExprList(&list)
+ return
}
@@ -432,9 +323,10 @@ func (p *parser) parseType() ast.Expr {
typ := p.tryType()
if typ == nil {
- p.errorExpected(p.pos, "type")
+ pos := p.pos
+ p.errorExpected(pos, "type")
p.next() // make progress
- return &ast.BadExpr{p.pos}
+ return &ast.BadExpr{pos, p.pos}
}
return typ
@@ -446,11 +338,11 @@ func (p *parser) parseQualifiedIdent() ast.Expr {
defer un(trace(p, "QualifiedIdent"))
}
- var x ast.Expr = p.findIdent()
+ var x ast.Expr = p.parseIdent()
if p.tok == token.PERIOD {
// first identifier is a package identifier
p.next()
- sel := p.findIdentInScope(nil)
+ sel := p.parseIdent()
x = &ast.SelectorExpr{x, sel}
}
return x
@@ -486,14 +378,14 @@ func (p *parser) parseArrayType(ellipsisOk bool) ast.Expr {
}
-func (p *parser) makeIdentList(list *vector.Vector) []*ast.Ident {
- idents := make([]*ast.Ident, len(*list))
- for i, x := range *list {
+func (p *parser) makeIdentList(list []ast.Expr) []*ast.Ident {
+ idents := make([]*ast.Ident, len(list))
+ for i, x := range list {
ident, isIdent := x.(*ast.Ident)
if !isIdent {
pos := x.(ast.Expr).Pos()
p.errorExpected(pos, "identifier")
- ident = &ast.Ident{pos, ast.NewObj(ast.Err, pos, "_")}
+ ident = &ast.Ident{pos, "_", nil}
}
idents[i] = ident
}
@@ -508,19 +400,8 @@ func (p *parser) parseFieldDecl() *ast.Field {
doc := p.leadComment
- // a list of identifiers looks like a list of type names
- var list vector.Vector
- for {
- // TODO(gri): do not allow ()'s here
- list.Push(p.parseType())
- if p.tok != token.COMMA {
- break
- }
- p.next()
- }
-
- // if we had a list of identifiers, it must be followed by a type
- typ := p.tryType()
+ // fields
+ list, typ := p.parseVarList(false)
// optional tag
var tag *ast.BasicLit
@@ -533,15 +414,14 @@ func (p *parser) parseFieldDecl() *ast.Field {
var idents []*ast.Ident
if typ != nil {
// IdentifierList Type
- idents = p.makeIdentList(&list)
+ idents = p.makeIdentList(list)
} else {
- // Type (anonymous field)
- if len(list) == 1 {
- // TODO(gri): check that this looks like a type
- typ = list.At(0).(ast.Expr)
- } else {
- p.errorExpected(p.pos, "anonymous field")
- typ = &ast.BadExpr{p.pos}
+ // ["*"] TypeName (AnonymousField)
+ typ = list[0] // we always have at least one element
+ if n := len(list); n > 1 || !isTypeName(deref(typ)) {
+ pos := typ.Pos()
+ p.errorExpected(pos, "anonymous field")
+ typ = &ast.BadExpr{pos, list[n-1].End()}
}
}
@@ -558,22 +438,16 @@ func (p *parser) parseStructType() *ast.StructType {
pos := p.expect(token.STRUCT)
lbrace := p.expect(token.LBRACE)
- var list vector.Vector
- for p.tok == token.IDENT || p.tok == token.MUL {
- list.Push(p.parseFieldDecl())
+ var list []*ast.Field
+ for p.tok == token.IDENT || p.tok == token.MUL || p.tok == token.LPAREN {
+ // a field declaration cannot start with a '(' but we accept
+ // it here for more robust parsing and better error messages
+ // (parseFieldDecl will check and complain if necessary)
+ list = append(list, p.parseFieldDecl())
}
rbrace := p.expect(token.RBRACE)
- // convert vector
- fields := make([]*ast.Field, len(list))
- for i, x := range list {
- fields[i] = x.(*ast.Field)
- }
-
- // TODO(gri) The struct scope shouldn't get lost.
- p.declFieldList(ast.NewScope(nil), fields)
-
- return &ast.StructType{pos, &ast.FieldList{lbrace, fields, rbrace}, false}
+ return &ast.StructType{pos, &ast.FieldList{lbrace, list, rbrace}, false}
}
@@ -589,13 +463,17 @@ func (p *parser) parsePointerType() *ast.StarExpr {
}
-func (p *parser) tryParameterType(ellipsisOk bool) ast.Expr {
- if ellipsisOk && p.tok == token.ELLIPSIS {
+func (p *parser) tryVarType(isParam bool) ast.Expr {
+ if isParam && p.tok == token.ELLIPSIS {
pos := p.pos
p.next()
- typ := p.tryType()
+ typ := p.tryType() // don't use parseType so we can provide better error message
+ if typ == nil {
+ p.error(pos, "'...' parameter is missing type")
+ typ = &ast.BadExpr{pos, p.pos}
+ }
if p.tok != token.RPAREN {
- p.Error(pos, "can use '...' for last parameter only")
+ p.error(pos, "can use '...' with last parameter type only")
}
return &ast.Ellipsis{pos, typ}
}
@@ -603,27 +481,30 @@ func (p *parser) tryParameterType(ellipsisOk bool) ast.Expr {
}
-func (p *parser) parseParameterType(ellipsisOk bool) ast.Expr {
- typ := p.tryParameterType(ellipsisOk)
+func (p *parser) parseVarType(isParam bool) ast.Expr {
+ typ := p.tryVarType(isParam)
if typ == nil {
- p.errorExpected(p.pos, "type")
+ pos := p.pos
+ p.errorExpected(pos, "type")
p.next() // make progress
- typ = &ast.BadExpr{p.pos}
+ typ = &ast.BadExpr{pos, p.pos}
}
return typ
}
-func (p *parser) parseParameterDecl(ellipsisOk bool) (*vector.Vector, ast.Expr) {
+func (p *parser) parseVarList(isParam bool) (list []ast.Expr, typ ast.Expr) {
if p.trace {
- defer un(trace(p, "ParameterDecl"))
+ defer un(trace(p, "VarList"))
}
// a list of identifiers looks like a list of type names
- var list vector.Vector
for {
- // TODO(gri): do not allow ()'s here
- list.Push(p.parseParameterType(ellipsisOk))
+ // parseVarType accepts any type (including parenthesized ones)
+ // even though the syntax does not permit them here: we
+ // accept them all for more robust parsing and complain
+ // afterwards
+ list = append(list, p.parseVarType(isParam))
if p.tok != token.COMMA {
break
}
@@ -631,31 +512,30 @@ func (p *parser) parseParameterDecl(ellipsisOk bool) (*vector.Vector, ast.Expr)
}
// if we had a list of identifiers, it must be followed by a type
- typ := p.tryParameterType(ellipsisOk)
+ typ = p.tryVarType(isParam)
- return &list, typ
+ return
}
-func (p *parser) parseParameterList(ellipsisOk bool) []*ast.Field {
+func (p *parser) parseParameterList(ellipsisOk bool) (params []*ast.Field) {
if p.trace {
defer un(trace(p, "ParameterList"))
}
- list, typ := p.parseParameterDecl(ellipsisOk)
+ list, typ := p.parseVarList(ellipsisOk)
if typ != nil {
// IdentifierList Type
idents := p.makeIdentList(list)
- list.Resize(0, 0)
- list.Push(&ast.Field{nil, idents, typ, nil, nil})
+ params = append(params, &ast.Field{nil, idents, typ, nil, nil})
if p.tok == token.COMMA {
p.next()
}
for p.tok != token.RPAREN && p.tok != token.EOF {
- idents := p.parseIdentList(ast.Var)
- typ := p.parseParameterType(ellipsisOk)
- list.Push(&ast.Field{nil, idents, typ, nil, nil})
+ idents := p.parseIdentList()
+ typ := p.parseVarType(ellipsisOk)
+ params = append(params, &ast.Field{nil, idents, typ, nil, nil})
if p.tok != token.COMMA {
break
}
@@ -664,23 +544,17 @@ func (p *parser) parseParameterList(ellipsisOk bool) []*ast.Field {
} else {
// Type { "," Type } (anonymous parameters)
- // convert list of types into list of *Param
- for i, x := range *list {
- list.Set(i, &ast.Field{Type: x.(ast.Expr)})
+ params = make([]*ast.Field, len(list))
+ for i, x := range list {
+ params[i] = &ast.Field{Type: x}
}
}
- // convert list
- params := make([]*ast.Field, len(*list))
- for i, x := range *list {
- params[i] = x.(*ast.Field)
- }
-
- return params
+ return
}
-func (p *parser) parseParameters(scope *ast.Scope, ellipsisOk bool) *ast.FieldList {
+func (p *parser) parseParameters(ellipsisOk bool) *ast.FieldList {
if p.trace {
defer un(trace(p, "Parameters"))
}
@@ -689,7 +563,6 @@ func (p *parser) parseParameters(scope *ast.Scope, ellipsisOk bool) *ast.FieldLi
lparen := p.expect(token.LPAREN)
if p.tok != token.RPAREN {
params = p.parseParameterList(ellipsisOk)
- p.declFieldList(scope, params)
}
rparen := p.expect(token.RPAREN)
@@ -697,13 +570,13 @@ func (p *parser) parseParameters(scope *ast.Scope, ellipsisOk bool) *ast.FieldLi
}
-func (p *parser) parseResult(scope *ast.Scope) *ast.FieldList {
+func (p *parser) parseResult() *ast.FieldList {
if p.trace {
defer un(trace(p, "Result"))
}
if p.tok == token.LPAREN {
- return p.parseParameters(scope, false)
+ return p.parseParameters(false)
}
typ := p.tryType()
@@ -717,28 +590,27 @@ func (p *parser) parseResult(scope *ast.Scope) *ast.FieldList {
}
-func (p *parser) parseSignature(scope *ast.Scope) (params, results *ast.FieldList) {
+func (p *parser) parseSignature() (params, results *ast.FieldList) {
if p.trace {
defer un(trace(p, "Signature"))
}
- params = p.parseParameters(scope, true)
- results = p.parseResult(scope)
+ params = p.parseParameters(true)
+ results = p.parseResult()
return
}
-func (p *parser) parseFuncType() (*ast.Scope, *ast.FuncType) {
+func (p *parser) parseFuncType() *ast.FuncType {
if p.trace {
defer un(trace(p, "FuncType"))
}
pos := p.expect(token.FUNC)
- scope := ast.NewScope(p.funcScope)
- params, results := p.parseSignature(scope)
+ params, results := p.parseSignature()
- return scope, &ast.FuncType{pos, params, results}
+ return &ast.FuncType{pos, params, results}
}
@@ -754,8 +626,8 @@ func (p *parser) parseMethodSpec() *ast.Field {
if ident, isIdent := x.(*ast.Ident); isIdent && p.tok == token.LPAREN {
// method
idents = []*ast.Ident{ident}
- params, results := p.parseSignature(ast.NewScope(p.funcScope))
- typ = &ast.FuncType{noPos, params, results}
+ params, results := p.parseSignature()
+ typ = &ast.FuncType{token.NoPos, params, results}
} else {
// embedded interface
typ = x
@@ -773,22 +645,13 @@ func (p *parser) parseInterfaceType() *ast.InterfaceType {
pos := p.expect(token.INTERFACE)
lbrace := p.expect(token.LBRACE)
- var list vector.Vector
+ var list []*ast.Field
for p.tok == token.IDENT {
- list.Push(p.parseMethodSpec())
+ list = append(list, p.parseMethodSpec())
}
rbrace := p.expect(token.RBRACE)
- // convert vector
- methods := make([]*ast.Field, len(list))
- for i, x := range list {
- methods[i] = x.(*ast.Field)
- }
-
- // TODO(gri) The interface scope shouldn't get lost.
- p.declFieldList(ast.NewScope(nil), methods)
-
- return &ast.InterfaceType{pos, &ast.FieldList{lbrace, methods, rbrace}, false}
+ return &ast.InterfaceType{pos, &ast.FieldList{lbrace, list, rbrace}, false}
}
@@ -842,8 +705,7 @@ func (p *parser) tryRawType(ellipsisOk bool) ast.Expr {
case token.MUL:
return p.parsePointerType()
case token.FUNC:
- _, typ := p.parseFuncType()
- return typ
+ return p.parseFuncType()
case token.INTERFACE:
return p.parseInterfaceType()
case token.MAP:
@@ -869,43 +731,28 @@ func (p *parser) tryType() ast.Expr { return p.tryRawType(false) }
// ----------------------------------------------------------------------------
// Blocks
-func makeStmtList(list *vector.Vector) []ast.Stmt {
- stats := make([]ast.Stmt, len(*list))
- for i, x := range *list {
- stats[i] = x.(ast.Stmt)
- }
- return stats
-}
-
-
-func (p *parser) parseStmtList() []ast.Stmt {
+func (p *parser) parseStmtList() (list []ast.Stmt) {
if p.trace {
defer un(trace(p, "StatementList"))
}
- var list vector.Vector
for p.tok != token.CASE && p.tok != token.DEFAULT && p.tok != token.RBRACE && p.tok != token.EOF {
- list.Push(p.parseStmt())
+ list = append(list, p.parseStmt())
}
- return makeStmtList(&list)
+ return
}
-func (p *parser) parseBody(scope *ast.Scope) *ast.BlockStmt {
+func (p *parser) parseBody() *ast.BlockStmt {
if p.trace {
defer un(trace(p, "Body"))
}
- savedScope := p.funcScope
- p.funcScope = scope
-
lbrace := p.expect(token.LBRACE)
list := p.parseStmtList()
rbrace := p.expect(token.RBRACE)
- p.funcScope = savedScope
-
return &ast.BlockStmt{lbrace, list, rbrace}
}
@@ -915,9 +762,6 @@ func (p *parser) parseBlockStmt() *ast.BlockStmt {
defer un(trace(p, "BlockStmt"))
}
- p.openScope()
- defer p.closeScope()
-
lbrace := p.expect(token.LBRACE)
list := p.parseStmtList()
rbrace := p.expect(token.RBRACE)
@@ -934,14 +778,14 @@ func (p *parser) parseFuncTypeOrLit() ast.Expr {
defer un(trace(p, "FuncTypeOrLit"))
}
- scope, typ := p.parseFuncType()
+ typ := p.parseFuncType()
if p.tok != token.LBRACE {
// function type only
return typ
}
p.exprLev++
- body := p.parseBody(scope)
+ body := p.parseBody()
p.exprLev--
return &ast.FuncLit{typ, body}
@@ -958,7 +802,7 @@ func (p *parser) parseOperand() ast.Expr {
switch p.tok {
case token.IDENT:
- return p.findIdent()
+ return p.parseIdent()
case token.INT, token.FLOAT, token.IMAG, token.CHAR, token.STRING:
x := &ast.BasicLit{p.pos, p.tok, p.lit}
@@ -984,9 +828,10 @@ func (p *parser) parseOperand() ast.Expr {
}
}
- p.errorExpected(p.pos, "operand")
+ pos := p.pos
+ p.errorExpected(pos, "operand")
p.next() // make progress
- return &ast.BadExpr{p.pos}
+ return &ast.BadExpr{pos, p.pos}
}
@@ -998,7 +843,7 @@ func (p *parser) parseSelectorOrTypeAssertion(x ast.Expr) ast.Expr {
p.expect(token.PERIOD)
if p.tok == token.IDENT {
// selector
- sel := p.findIdentInScope(nil)
+ sel := p.parseIdent()
return &ast.SelectorExpr{x, sel}
}
@@ -1022,23 +867,27 @@ func (p *parser) parseIndexOrSlice(x ast.Expr) ast.Expr {
defer un(trace(p, "IndexOrSlice"))
}
- p.expect(token.LBRACK)
+ lbrack := p.expect(token.LBRACK)
p.exprLev++
- index := p.parseExpr()
+ var low, high ast.Expr
+ isSlice := false
+ if p.tok != token.COLON {
+ low = p.parseExpr()
+ }
if p.tok == token.COLON {
+ isSlice = true
p.next()
- var end ast.Expr
if p.tok != token.RBRACK {
- end = p.parseExpr()
+ high = p.parseExpr()
}
- x = &ast.SliceExpr{x, index, end}
- } else {
- x = &ast.IndexExpr{x, index}
}
p.exprLev--
- p.expect(token.RBRACK)
+ rbrack := p.expect(token.RBRACK)
- return x
+ if isSlice {
+ return &ast.SliceExpr{x, lbrack, low, high, rbrack}
+ }
+ return &ast.IndexExpr{x, lbrack, low, rbrack}
}
@@ -1049,9 +898,14 @@ func (p *parser) parseCallOrConversion(fun ast.Expr) *ast.CallExpr {
lparen := p.expect(token.LPAREN)
p.exprLev++
- var list vector.Vector
- for p.tok != token.RPAREN && p.tok != token.EOF {
- list.Push(p.parseExpr())
+ var list []ast.Expr
+ var ellipsis token.Pos
+ for p.tok != token.RPAREN && p.tok != token.EOF && !ellipsis.IsValid() {
+ list = append(list, p.parseExpr())
+ if p.tok == token.ELLIPSIS {
+ ellipsis = p.pos
+ p.next()
+ }
if p.tok != token.COMMA {
break
}
@@ -1060,47 +914,49 @@ func (p *parser) parseCallOrConversion(fun ast.Expr) *ast.CallExpr {
p.exprLev--
rparen := p.expect(token.RPAREN)
- return &ast.CallExpr{fun, lparen, makeExprList(&list), rparen}
+ return &ast.CallExpr{fun, lparen, list, ellipsis, rparen}
}
-func (p *parser) parseElement() ast.Expr {
+func (p *parser) parseElement(keyOk bool) ast.Expr {
if p.trace {
defer un(trace(p, "Element"))
}
+ if p.tok == token.LBRACE {
+ return p.parseLiteralValue(nil)
+ }
+
x := p.parseExpr()
- if p.tok == token.COLON {
+ if keyOk && p.tok == token.COLON {
colon := p.pos
p.next()
- x = &ast.KeyValueExpr{x, colon, p.parseExpr()}
+ x = &ast.KeyValueExpr{x, colon, p.parseElement(false)}
}
-
return x
}
-func (p *parser) parseElementList() []ast.Expr {
+func (p *parser) parseElementList() (list []ast.Expr) {
if p.trace {
defer un(trace(p, "ElementList"))
}
- var list vector.Vector
for p.tok != token.RBRACE && p.tok != token.EOF {
- list.Push(p.parseElement())
+ list = append(list, p.parseElement(true))
if p.tok != token.COMMA {
break
}
p.next()
}
- return makeExprList(&list)
+ return
}
-func (p *parser) parseCompositeLit(typ ast.Expr) ast.Expr {
+func (p *parser) parseLiteralValue(typ ast.Expr) ast.Expr {
if p.trace {
- defer un(trace(p, "CompositeLit"))
+ defer un(trace(p, "LiteralValue"))
}
lbrace := p.expect(token.LBRACE)
@@ -1115,21 +971,16 @@ func (p *parser) parseCompositeLit(typ ast.Expr) ast.Expr {
}
-// TODO(gri): Consider different approach to checking syntax after parsing:
-// Provide a arguments (set of flags) to parsing functions
-// restricting what they are supposed to accept depending
-// on context.
-
// checkExpr checks that x is an expression (and not a type).
func (p *parser) checkExpr(x ast.Expr) ast.Expr {
- // TODO(gri): should provide predicate in AST nodes
- switch t := x.(type) {
+ switch t := unparen(x).(type) {
case *ast.BadExpr:
case *ast.Ident:
case *ast.BasicLit:
case *ast.FuncLit:
case *ast.CompositeLit:
case *ast.ParenExpr:
+ panic("unreachable")
case *ast.SelectorExpr:
case *ast.IndexExpr:
case *ast.SliceExpr:
@@ -1137,7 +988,7 @@ func (p *parser) checkExpr(x ast.Expr) ast.Expr {
if t.Type == nil {
// the form X.(type) is only allowed in type switch expressions
p.errorExpected(x.Pos(), "expression")
- x = &ast.BadExpr{x.Pos()}
+ x = &ast.BadExpr{x.Pos(), x.End()}
}
case *ast.CallExpr:
case *ast.StarExpr:
@@ -1145,28 +996,26 @@ func (p *parser) checkExpr(x ast.Expr) ast.Expr {
if t.Op == token.RANGE {
// the range operator is only allowed at the top of a for statement
p.errorExpected(x.Pos(), "expression")
- x = &ast.BadExpr{x.Pos()}
+ x = &ast.BadExpr{x.Pos(), x.End()}
}
case *ast.BinaryExpr:
default:
// all other nodes are not proper expressions
p.errorExpected(x.Pos(), "expression")
- x = &ast.BadExpr{x.Pos()}
+ x = &ast.BadExpr{x.Pos(), x.End()}
}
return x
}
-// isTypeName returns true iff x is type name.
+// isTypeName returns true iff x is a (qualified) TypeName.
func isTypeName(x ast.Expr) bool {
- // TODO(gri): should provide predicate in AST nodes
switch t := x.(type) {
case *ast.BadExpr:
case *ast.Ident:
- case *ast.ParenExpr:
- return isTypeName(t.X) // TODO(gri): should (TypeName) be illegal?
case *ast.SelectorExpr:
- return isTypeName(t.X)
+ _, isIdent := t.X.(*ast.Ident)
+ return isIdent
default:
return false // all other nodes are not type names
}
@@ -1174,16 +1023,14 @@ func isTypeName(x ast.Expr) bool {
}
-// isCompositeLitType returns true iff x is a legal composite literal type.
-func isCompositeLitType(x ast.Expr) bool {
- // TODO(gri): should provide predicate in AST nodes
+// isLiteralType returns true iff x is a legal composite literal type.
+func isLiteralType(x ast.Expr) bool {
switch t := x.(type) {
case *ast.BadExpr:
case *ast.Ident:
- case *ast.ParenExpr:
- return isCompositeLitType(t.X)
case *ast.SelectorExpr:
- return isTypeName(t.X)
+ _, isIdent := t.X.(*ast.Ident)
+ return isIdent
case *ast.ArrayType:
case *ast.StructType:
case *ast.MapType:
@@ -1194,22 +1041,41 @@ func isCompositeLitType(x ast.Expr) bool {
}
+// If x is of the form *T, deref returns T, otherwise it returns x.
+func deref(x ast.Expr) ast.Expr {
+ if p, isPtr := x.(*ast.StarExpr); isPtr {
+ x = p.X
+ }
+ return x
+}
+
+
+// If x is of the form (T), unparen returns unparen(T), otherwise it returns x.
+func unparen(x ast.Expr) ast.Expr {
+ if p, isParen := x.(*ast.ParenExpr); isParen {
+ x = unparen(p.X)
+ }
+ return x
+}
+
+
// checkExprOrType checks that x is an expression or a type
// (and not a raw type such as [...]T).
//
func (p *parser) checkExprOrType(x ast.Expr) ast.Expr {
- // TODO(gri): should provide predicate in AST nodes
- switch t := x.(type) {
+ switch t := unparen(x).(type) {
+ case *ast.ParenExpr:
+ panic("unreachable")
case *ast.UnaryExpr:
if t.Op == token.RANGE {
// the range operator is only allowed at the top of a for statement
p.errorExpected(x.Pos(), "expression")
- x = &ast.BadExpr{x.Pos()}
+ x = &ast.BadExpr{x.Pos(), x.End()}
}
case *ast.ArrayType:
if len, isEllipsis := t.Len.(*ast.Ellipsis); isEllipsis {
- p.Error(len.Pos(), "expected array length, found '...'")
- x = &ast.BadExpr{x.Pos()}
+ p.error(len.Pos(), "expected array length, found '...'")
+ x = &ast.BadExpr{x.Pos(), x.End()}
}
}
@@ -1234,8 +1100,8 @@ L:
case token.LPAREN:
x = p.parseCallOrConversion(p.checkExprOrType(x))
case token.LBRACE:
- if isCompositeLitType(x) && (p.exprLev >= 0 || !isTypeName(x)) {
- x = p.parseCompositeLit(x)
+ if isLiteralType(x) && (p.exprLev >= 0 || !isTypeName(x)) {
+ x = p.parseLiteralValue(x)
} else {
break L
}
@@ -1328,14 +1194,15 @@ func (p *parser) parseSimpleStmt(labelOk bool) ast.Stmt {
switch p.tok {
case token.COLON:
// labeled statement
+ colon := p.pos
p.next()
if labelOk && len(x) == 1 {
if label, isIdent := x[0].(*ast.Ident); isIdent {
- return &ast.LabeledStmt{label, p.parseStmt()}
+ return &ast.LabeledStmt{label, colon, p.parseStmt()}
}
}
- p.Error(x[0].Pos(), "illegal label declaration")
- return &ast.BadStmt{x[0].Pos()}
+ p.error(x[0].Pos(), "illegal label declaration")
+ return &ast.BadStmt{x[0].Pos(), colon + 1}
case
token.DEFINE, token.ASSIGN, token.ADD_ASSIGN,
@@ -1350,13 +1217,13 @@ func (p *parser) parseSimpleStmt(labelOk bool) ast.Stmt {
}
if len(x) > 1 {
- p.Error(x[0].Pos(), "only one expression allowed")
+ p.error(x[0].Pos(), "only one expression allowed")
// continue with first expression
}
if p.tok == token.INC || p.tok == token.DEC {
// increment or decrement
- s := &ast.IncDecStmt{x[0], p.tok}
+ s := &ast.IncDecStmt{x[0], p.pos, p.tok}
p.next() // consume "++" or "--"
return s
}
@@ -1385,7 +1252,7 @@ func (p *parser) parseGoStmt() ast.Stmt {
call := p.parseCallExpr()
p.expectSemi()
if call == nil {
- return &ast.BadStmt{pos}
+ return &ast.BadStmt{pos, pos + 2} // len("go")
}
return &ast.GoStmt{pos, call}
@@ -1401,7 +1268,7 @@ func (p *parser) parseDeferStmt() ast.Stmt {
call := p.parseCallExpr()
p.expectSemi()
if call == nil {
- return &ast.BadStmt{pos}
+ return &ast.BadStmt{pos, pos + 5} // len("defer")
}
return &ast.DeferStmt{pos, call}
@@ -1433,7 +1300,7 @@ func (p *parser) parseBranchStmt(tok token.Token) *ast.BranchStmt {
s := &ast.BranchStmt{p.pos, tok, nil}
p.expect(tok)
if tok != token.FALLTHROUGH && p.tok == token.IDENT {
- s.Label = p.findIdentInScope(nil)
+ s.Label = p.parseIdent()
}
p.expectSemi()
@@ -1448,8 +1315,8 @@ func (p *parser) makeExpr(s ast.Stmt) ast.Expr {
if es, isExpr := s.(*ast.ExprStmt); isExpr {
return p.checkExpr(es.X)
}
- p.Error(s.Pos(), "expected condition, found simple statement")
- return &ast.BadExpr{s.Pos()}
+ p.error(s.Pos(), "expected condition, found simple statement")
+ return &ast.BadExpr{s.Pos(), s.End()}
}
@@ -1489,10 +1356,6 @@ func (p *parser) parseIfStmt() *ast.IfStmt {
defer un(trace(p, "IfStmt"))
}
- // IfStmt block
- p.openScope()
- defer p.closeScope()
-
pos := p.expect(token.IF)
s1, s2, _ := p.parseControlClause(false)
body := p.parseBlockStmt()
@@ -1513,10 +1376,6 @@ func (p *parser) parseCaseClause() *ast.CaseClause {
defer un(trace(p, "CaseClause"))
}
- // CaseClause block
- p.openScope()
- defer p.closeScope()
-
// SwitchCase
pos := p.pos
var x []ast.Expr
@@ -1534,19 +1393,18 @@ func (p *parser) parseCaseClause() *ast.CaseClause {
}
-func (p *parser) parseTypeList() []ast.Expr {
+func (p *parser) parseTypeList() (list []ast.Expr) {
if p.trace {
defer un(trace(p, "TypeList"))
}
- var list vector.Vector
- list.Push(p.parseType())
+ list = append(list, p.parseType())
for p.tok == token.COMMA {
p.next()
- list.Push(p.parseType())
+ list = append(list, p.parseType())
}
- return makeExprList(&list)
+ return
}
@@ -1555,10 +1413,6 @@ func (p *parser) parseTypeCaseClause() *ast.TypeCaseClause {
defer un(trace(p, "TypeCaseClause"))
}
- // TypeCaseClause block
- p.openScope()
- defer p.closeScope()
-
// TypeSwitchCase
pos := p.pos
var types []ast.Expr
@@ -1595,21 +1449,17 @@ func (p *parser) parseSwitchStmt() ast.Stmt {
defer un(trace(p, "SwitchStmt"))
}
- // SwitchStmt block
- p.openScope()
- defer p.closeScope()
-
pos := p.expect(token.SWITCH)
s1, s2, _ := p.parseControlClause(false)
if isExprSwitch(s2) {
lbrace := p.expect(token.LBRACE)
- var cases vector.Vector
+ var list []ast.Stmt
for p.tok == token.CASE || p.tok == token.DEFAULT {
- cases.Push(p.parseCaseClause())
+ list = append(list, p.parseCaseClause())
}
rbrace := p.expect(token.RBRACE)
- body := &ast.BlockStmt{lbrace, makeStmtList(&cases), rbrace}
+ body := &ast.BlockStmt{lbrace, list, rbrace}
p.expectSemi()
return &ast.SwitchStmt{pos, s1, p.makeExpr(s2), body}
}
@@ -1617,13 +1467,13 @@ func (p *parser) parseSwitchStmt() ast.Stmt {
// type switch
// TODO(gri): do all the checks!
lbrace := p.expect(token.LBRACE)
- var cases vector.Vector
+ var list []ast.Stmt
for p.tok == token.CASE || p.tok == token.DEFAULT {
- cases.Push(p.parseTypeCaseClause())
+ list = append(list, p.parseTypeCaseClause())
}
rbrace := p.expect(token.RBRACE)
p.expectSemi()
- body := &ast.BlockStmt{lbrace, makeStmtList(&cases), rbrace}
+ body := &ast.BlockStmt{lbrace, list, rbrace}
return &ast.TypeSwitchStmt{pos, s1, s2, body}
}
@@ -1633,10 +1483,6 @@ func (p *parser) parseCommClause() *ast.CommClause {
defer un(trace(p, "CommClause"))
}
- // CommClause block
- p.openScope()
- defer p.closeScope()
-
// CommCase
pos := p.pos
var tok token.Token
@@ -1680,13 +1526,13 @@ func (p *parser) parseSelectStmt() *ast.SelectStmt {
pos := p.expect(token.SELECT)
lbrace := p.expect(token.LBRACE)
- var cases vector.Vector
+ var list []ast.Stmt
for p.tok == token.CASE || p.tok == token.DEFAULT {
- cases.Push(p.parseCommClause())
+ list = append(list, p.parseCommClause())
}
rbrace := p.expect(token.RBRACE)
p.expectSemi()
- body := &ast.BlockStmt{lbrace, makeStmtList(&cases), rbrace}
+ body := &ast.BlockStmt{lbrace, list, rbrace}
return &ast.SelectStmt{pos, body}
}
@@ -1697,10 +1543,6 @@ func (p *parser) parseForStmt() ast.Stmt {
defer un(trace(p, "ForStmt"))
}
- // ForStmt block
- p.openScope()
- defer p.closeScope()
-
pos := p.expect(token.FOR)
s1, s2, s3 := p.parseControlClause(true)
body := p.parseBlockStmt()
@@ -1710,7 +1552,7 @@ func (p *parser) parseForStmt() ast.Stmt {
// possibly a for statement with a range clause; check assignment operator
if as.Tok != token.ASSIGN && as.Tok != token.DEFINE {
p.errorExpected(as.TokPos, "'=' or ':='")
- return &ast.BadStmt{pos}
+ return &ast.BadStmt{pos, body.End()}
}
// check lhs
var key, value ast.Expr
@@ -1721,19 +1563,19 @@ 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}
+ return &ast.BadStmt{pos, body.End()}
}
// check rhs
if len(as.Rhs) != 1 {
p.errorExpected(as.Rhs[0].Pos(), "1 expressions")
- return &ast.BadStmt{pos}
+ return &ast.BadStmt{pos, body.End()}
}
if rhs, isUnary := as.Rhs[0].(*ast.UnaryExpr); isUnary && rhs.Op == token.RANGE {
// rhs is range expression; check lhs
return &ast.RangeStmt{pos, key, value, as.TokPos, as.Tok, rhs.X, body}
} else {
p.errorExpected(s2.Pos(), "range clause")
- return &ast.BadStmt{pos}
+ return &ast.BadStmt{pos, body.End()}
}
} else {
// regular for statement
@@ -1791,9 +1633,10 @@ func (p *parser) parseStmt() (s ast.Stmt) {
s = &ast.EmptyStmt{p.pos}
default:
// no statement found
- p.errorExpected(p.pos, "statement")
+ pos := p.pos
+ p.errorExpected(pos, "statement")
p.next() // make progress
- s = &ast.BadStmt{p.pos}
+ s = &ast.BadStmt{pos, p.pos}
}
return
@@ -1813,14 +1656,10 @@ func parseImportSpec(p *parser, doc *ast.CommentGroup) ast.Spec {
var ident *ast.Ident
if p.tok == token.PERIOD {
- ident = &ast.Ident{p.pos, ast.NewObj(ast.Pkg, p.pos, ".")}
+ ident = &ast.Ident{p.pos, ".", nil}
p.next()
} else if p.tok == token.IDENT {
- ident = p.parseIdent(ast.Pkg)
- // TODO(gri) Make sure the ident is not already declared in the
- // package scope. Also, cannot add the same name to
- // the package scope later.
- p.declIdent(p.fileScope, ident)
+ ident = p.parseIdent()
}
var path *ast.BasicLit
@@ -1841,23 +1680,13 @@ func parseConstSpec(p *parser, doc *ast.CommentGroup) ast.Spec {
defer un(trace(p, "ConstSpec"))
}
- idents := p.parseIdentList(ast.Con)
- if p.funcScope == nil {
- // the scope of a constant outside any function
- // is the package scope
- p.declIdentList(p.pkgScope, idents)
- }
+ idents := p.parseIdentList()
typ := p.tryType()
var values []ast.Expr
if typ != nil || p.tok == token.ASSIGN {
p.expect(token.ASSIGN)
values = p.parseExprList()
}
- if p.funcScope != nil {
- // the scope of a constant inside a function
- // begins after the the ConstSpec
- p.declIdentList(p.funcScope, idents)
- }
p.expectSemi()
return &ast.ValueSpec{doc, idents, typ, values, p.lineComment}
@@ -1869,15 +1698,7 @@ func parseTypeSpec(p *parser, doc *ast.CommentGroup) ast.Spec {
defer un(trace(p, "TypeSpec"))
}
- ident := p.parseIdent(ast.Typ)
- // the scope of a type outside any function is
- // the package scope; the scope of a type inside
- // a function starts at the type identifier
- scope := p.funcScope
- if scope == nil {
- scope = p.pkgScope
- }
- p.declIdent(scope, ident)
+ ident := p.parseIdent()
typ := p.parseType()
p.expectSemi()
@@ -1890,23 +1711,13 @@ func parseVarSpec(p *parser, doc *ast.CommentGroup) ast.Spec {
defer un(trace(p, "VarSpec"))
}
- idents := p.parseIdentList(ast.Var)
- if p.funcScope == nil {
- // the scope of a variable outside any function
- // is the pkgScope
- p.declIdentList(p.pkgScope, idents)
- }
+ idents := p.parseIdentList()
typ := p.tryType()
var values []ast.Expr
if typ == nil || p.tok == token.ASSIGN {
p.expect(token.ASSIGN)
values = p.parseExprList()
}
- if p.funcScope != nil {
- // the scope of a variable inside a function
- // begins after the the VarSpec
- p.declIdentList(p.funcScope, idents)
- }
p.expectSemi()
return &ast.ValueSpec{doc, idents, typ, values, p.lineComment}
@@ -1915,58 +1726,51 @@ func parseVarSpec(p *parser, doc *ast.CommentGroup) ast.Spec {
func (p *parser) parseGenDecl(keyword token.Token, f parseSpecFunction) *ast.GenDecl {
if p.trace {
- defer un(trace(p, keyword.String()+"Decl"))
+ defer un(trace(p, "GenDecl("+keyword.String()+")"))
}
doc := p.leadComment
pos := p.expect(keyword)
- var lparen, rparen token.Position
- var list vector.Vector
+ var lparen, rparen token.Pos
+ var list []ast.Spec
if p.tok == token.LPAREN {
lparen = p.pos
p.next()
for p.tok != token.RPAREN && p.tok != token.EOF {
- list.Push(f(p, p.leadComment))
+ list = append(list, f(p, p.leadComment))
}
rparen = p.expect(token.RPAREN)
p.expectSemi()
} else {
- list.Push(f(p, nil))
+ list = append(list, f(p, nil))
}
- // convert vector
- specs := make([]ast.Spec, len(list))
- for i, x := range list {
- specs[i] = x.(ast.Spec)
- }
-
- return &ast.GenDecl{doc, pos, keyword, lparen, specs, rparen}
+ return &ast.GenDecl{doc, pos, keyword, lparen, list, rparen}
}
-func (p *parser) parseReceiver(scope *ast.Scope) *ast.FieldList {
+func (p *parser) parseReceiver() *ast.FieldList {
if p.trace {
defer un(trace(p, "Receiver"))
}
pos := p.pos
- par := p.parseParameters(scope, false)
+ par := p.parseParameters(false)
// must have exactly one receiver
if par.NumFields() != 1 {
p.errorExpected(pos, "exactly one receiver")
- par.List = []*ast.Field{&ast.Field{Type: &ast.BadExpr{noPos}}}
+ // TODO determine a better range for BadExpr below
+ par.List = []*ast.Field{&ast.Field{Type: &ast.BadExpr{pos, pos}}}
+ return par
}
+ // recv type must be of the form ["*"] identifier
recv := par.List[0]
-
- // recv type must be TypeName or *TypeName
- base := recv.Type
- if ptr, isPtr := base.(*ast.StarExpr); isPtr {
- base = ptr.X
- }
- if !isTypeName(base) {
- p.errorExpected(base.Pos(), "type name")
+ base := deref(recv.Type)
+ if _, isIdent := base.(*ast.Ident); !isIdent {
+ p.errorExpected(base.Pos(), "(unqualified) identifier")
+ par.List = []*ast.Field{&ast.Field{Type: &ast.BadExpr{recv.Pos(), recv.End()}}}
}
return par
@@ -1980,20 +1784,18 @@ func (p *parser) parseFuncDecl() *ast.FuncDecl {
doc := p.leadComment
pos := p.expect(token.FUNC)
- scope := ast.NewScope(p.funcScope)
var recv *ast.FieldList
if p.tok == token.LPAREN {
- recv = p.parseReceiver(scope)
+ recv = p.parseReceiver()
}
- ident := p.parseIdent(ast.Fun)
- p.declIdent(p.pkgScope, ident) // there are no local function declarations
- params, results := p.parseSignature(scope)
+ ident := p.parseIdent()
+ params, results := p.parseSignature()
var body *ast.BlockStmt
if p.tok == token.LBRACE {
- body = p.parseBody(scope)
+ body = p.parseBody()
}
p.expectSemi()
@@ -2023,8 +1825,8 @@ func (p *parser) parseDecl() ast.Decl {
default:
pos := p.pos
p.errorExpected(pos, "declaration")
- decl := &ast.BadDecl{pos}
- p.next() // make progress in any case
+ p.next() // make progress
+ decl := &ast.BadDecl{pos, p.pos}
return decl
}
@@ -2032,23 +1834,16 @@ func (p *parser) parseDecl() ast.Decl {
}
-func (p *parser) parseDeclList() []ast.Decl {
+func (p *parser) parseDeclList() (list []ast.Decl) {
if p.trace {
defer un(trace(p, "DeclList"))
}
- var list vector.Vector
for p.tok != token.EOF {
- list.Push(p.parseDecl())
+ list = append(list, p.parseDecl())
}
- // convert vector
- decls := make([]ast.Decl, len(list))
- for i, x := range list {
- decls[i] = x.(ast.Decl)
- }
-
- return decls
+ return
}
@@ -2063,10 +1858,9 @@ func (p *parser) parseFile() *ast.File {
// package clause
doc := p.leadComment
pos := p.expect(token.PACKAGE)
- ident := p.parseIdent(ast.Pkg) // package name is in no scope
+ ident := p.parseIdent()
p.expectSemi()
- p.fileScope = ast.NewScope(p.pkgScope)
var decls []ast.Decl
// Don't bother parsing the rest if we had errors already.
@@ -2074,30 +1868,17 @@ func (p *parser) parseFile() *ast.File {
if p.ErrorCount() == 0 && p.mode&PackageClauseOnly == 0 {
// import decls
- var list vector.Vector
for p.tok == token.IMPORT {
- list.Push(p.parseGenDecl(token.IMPORT, parseImportSpec))
+ decls = append(decls, p.parseGenDecl(token.IMPORT, parseImportSpec))
}
if p.mode&ImportsOnly == 0 {
// rest of package body
for p.tok != token.EOF {
- list.Push(p.parseDecl())
+ decls = append(decls, p.parseDecl())
}
}
-
- // convert declaration list
- decls = make([]ast.Decl, len(list))
- for i, x := range list {
- decls[i] = x.(ast.Decl)
- }
- }
-
- // convert comments list
- comments := make([]*ast.CommentGroup, len(p.comments))
- for i, x := range p.comments {
- comments[i] = x.(*ast.CommentGroup)
}
- return &ast.File{doc, pos, ident, decls, comments}
+ return &ast.File{doc, pos, ident, decls, p.comments}
}
diff --git a/src/pkg/go/parser/parser_test.go b/src/pkg/go/parser/parser_test.go
index 01327a41d..56bd80ef1 100644
--- a/src/pkg/go/parser/parser_test.go
+++ b/src/pkg/go/parser/parser_test.go
@@ -5,12 +5,14 @@
package parser
import (
- "go/ast"
+ "go/token"
"os"
"testing"
)
+var fset = token.NewFileSet()
+
var illegalInputs = []interface{}{
nil,
3.14,
@@ -21,7 +23,7 @@ var illegalInputs = []interface{}{
func TestParseIllegalInputs(t *testing.T) {
for _, src := range illegalInputs {
- _, err := ParseFile("", src, nil, 0)
+ _, err := ParseFile(fset, "", src, 0)
if err == nil {
t.Errorf("ParseFile(%v) should have failed", src)
}
@@ -30,23 +32,26 @@ func TestParseIllegalInputs(t *testing.T) {
var validPrograms = []interface{}{
+ "package main\n",
`package main;`,
- `package main; import "fmt"; func main() { fmt.Println("Hello, World!") }` + "\n",
- `package main; func main() { if f(T{}) {} }` + "\n",
- `package main; func main() { _ = (<-chan int)(x) }` + "\n",
- `package main; func main() { _ = (<-chan <-chan int)(x) }` + "\n",
- `package main; func f(func() func() func())` + "\n",
- `package main; func f(...)` + "\n",
- `package main; func f(float, ...int)` + "\n",
- `package main; type T []int; var a []bool; func f() { if a[T{42}[0]] {} }` + "\n",
- `package main; type T []int; func g(int) bool { return true }; func f() { if g(T{42}[0]) {} }` + "\n",
- `package main; type T []int; func f() { for _ = range []int{T{42}[0]} {} }` + "\n",
+ `package main; import "fmt"; func main() { fmt.Println("Hello, World!") };`,
+ `package main; func main() { if f(T{}) {} };`,
+ `package main; func main() { _ = (<-chan int)(x) };`,
+ `package main; func main() { _ = (<-chan <-chan int)(x) };`,
+ `package main; func f(func() func() func());`,
+ `package main; func f(...T);`,
+ `package main; func f(float, ...int);`,
+ `package main; func f(x int, a ...int) { f(0, a...); f(1, a...,) };`,
+ `package main; type T []int; var a []bool; func f() { if a[T{42}[0]] {} };`,
+ `package main; type T []int; func g(int) bool { return true }; func f() { if g(T{42}[0]) {} };`,
+ `package main; type T []int; func f() { for _ = range []int{T{42}[0]} {} };`,
+ `package main; var a = T{{1, 2}, {3, 4}}`,
}
func TestParseValidPrograms(t *testing.T) {
for _, src := range validPrograms {
- _, err := ParseFile("", src, ast.NewScope(nil), 0)
+ _, err := ParseFile(fset, "", src, 0)
if err != nil {
t.Errorf("ParseFile(%q): %v", src, err)
}
@@ -62,7 +67,7 @@ var validFiles = []string{
func TestParse3(t *testing.T) {
for _, filename := range validFiles {
- _, err := ParseFile(filename, nil, ast.NewScope(nil), 0)
+ _, err := ParseFile(fset, filename, nil, 0)
if err != nil {
t.Errorf("ParseFile(%s): %v", filename, err)
}
@@ -87,7 +92,7 @@ func dirFilter(f *os.FileInfo) bool { return nameFilter(f.Name) }
func TestParse4(t *testing.T) {
path := "."
- pkgs, err := ParseDir(path, dirFilter, 0)
+ pkgs, err := ParseDir(fset, path, dirFilter, 0)
if err != nil {
t.Fatalf("ParseDir(%s): %v", path, err)
}
@@ -99,7 +104,7 @@ func TestParse4(t *testing.T) {
t.Errorf(`package "parser" not found`)
return
}
- for filename, _ := range pkg.Files {
+ for filename := range pkg.Files {
if !nameFilter(filename) {
t.Errorf("unexpected package file: %s", filename)
}
diff --git a/src/pkg/go/printer/Makefile b/src/pkg/go/printer/Makefile
index a0fe22e42..6a71efc93 100644
--- a/src/pkg/go/printer/Makefile
+++ b/src/pkg/go/printer/Makefile
@@ -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 ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=go/printer
GOFILES=\
diff --git a/src/pkg/go/printer/nodes.go b/src/pkg/go/printer/nodes.go
index a98af4a2a..1ee0846f6 100644
--- a/src/pkg/go/printer/nodes.go
+++ b/src/pkg/go/printer/nodes.go
@@ -10,7 +10,6 @@ package printer
import (
"bytes"
- "container/vector"
"go/ast"
"go/token"
)
@@ -28,32 +27,30 @@ import (
// ----------------------------------------------------------------------------
// Common AST nodes.
-// Print as many newlines as necessary (but at least min and and at most
-// max newlines) to get to the current line. ws is printed before the first
-// line break. If newSection is set, the first line break is printed as
-// formfeed. Returns true if any line break was printed; returns false otherwise.
+// Print as many newlines as necessary (but at least min newlines) to get to
+// the current line. ws is printed before the first line break. If newSection
+// is set, the first line break is printed as formfeed. Returns true if any
+// line break was printed; returns false otherwise.
//
-// TODO(gri): Reconsider signature (provide position instead of line)
+// TODO(gri): linebreak may add too many lines if the next statement at "line"
+// is preceeded by comments because the computation of n assumes
+// the current position before the comment and the target position
+// after the comment. Thus, after interspersing such comments, the
+// space taken up by them is not considered to reduce the number of
+// linebreaks. At the moment there is no easy way to know about
+// future (not yet interspersed) comments in this function.
//
-func (p *printer) linebreak(line, min, max int, ws whiteSpace, newSection bool) (printedBreak bool) {
- n := line - p.pos.Line
- switch {
- case n < min:
- n = min
- case n > max:
- n = max
- }
-
+func (p *printer) linebreak(line, min int, ws whiteSpace, newSection bool) (printedBreak bool) {
+ n := p.nlines(line-p.pos.Line, min)
if n > 0 {
p.print(ws)
if newSection {
p.print(formfeed)
n--
- printedBreak = true
}
- }
- for ; n > 0; n-- {
- p.print(newline)
+ for ; n > 0; n-- {
+ p.print(newline)
+ }
printedBreak = true
}
return
@@ -75,7 +72,7 @@ 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(g.List[0].Pos(), token.ILLEGAL)
+ p.flush(p.fset.Position(g.List[0].Pos()), token.ILLEGAL)
}
p.comments[0] = g
p.cindex = 0
@@ -95,7 +92,7 @@ const (
// Sets multiLine to true if the identifier list spans multiple lines.
-// If ident is set, a multi-line identifier list is indented after the
+// If indent is set, a multi-line identifier list is indented after the
// first linebreak encountered.
func (p *printer) identList(list []*ast.Ident, indent bool, multiLine *bool) {
// convert into an expression list so we can re-use exprList formatting
@@ -107,7 +104,7 @@ func (p *printer) identList(list []*ast.Ident, indent bool, multiLine *bool) {
if !indent {
mode |= noIndent
}
- p.exprList(noPos, xlist, 1, mode, multiLine, noPos)
+ p.exprList(token.NoPos, xlist, 1, mode, multiLine, token.NoPos)
}
@@ -130,7 +127,7 @@ func (p *printer) keySize(pair *ast.KeyValueExpr) int {
// 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(prev token.Position, list []ast.Expr, depth int, mode exprListMode, multiLine *bool, next token.Position) {
+func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exprListMode, multiLine *bool, next0 token.Pos) {
if len(list) == 0 {
return
}
@@ -139,14 +136,10 @@ func (p *printer) exprList(prev token.Position, list []ast.Expr, depth int, mode
p.print(blank)
}
- line := list[0].Pos().Line
- endLine := next.Line
- if endLine == 0 {
- // TODO(gri): endLine may be incorrect as it is really the beginning
- // of the last list entry. There may be only one, very long
- // entry in which case line == endLine.
- endLine = list[len(list)-1].Pos().Line
- }
+ prev := p.fset.Position(prev0)
+ next := p.fset.Position(next0)
+ line := p.fset.Position(list[0].Pos()).Line
+ endLine := p.fset.Position(list[len(list)-1].End()).Line
if prev.IsValid() && prev.Line == line && line == endLine {
// all list entries on a single line
@@ -190,7 +183,7 @@ func (p *printer) exprList(prev token.Position, list []ast.Expr, depth int, mode
// lines for them.
linebreakMin = 0
}
- if prev.IsValid() && prev.Line < line && p.linebreak(line, linebreakMin, 2, ws, true) {
+ if prev.IsValid() && prev.Line < line && p.linebreak(line, linebreakMin, ws, true) {
ws = ignore
*multiLine = true
prevBreak = 0
@@ -202,7 +195,7 @@ func (p *printer) exprList(prev token.Position, list []ast.Expr, depth int, mode
// print all list elements
for i, x := range list {
prevLine := line
- line = x.Pos().Line
+ line = p.fset.Position(x.Pos()).Line
// determine if the next linebreak, if any, needs to use formfeed:
// in general, use the entire node size to make the decision; for
@@ -252,7 +245,7 @@ func (p *printer) exprList(prev token.Position, list []ast.Expr, depth int, mode
// unless forceFF is set or there are multiple expressions on
// the same line in which case formfeed is used
// broken with a formfeed
- if p.linebreak(line, linebreakMin, 2, ws, useFF || prevBreak+1 < i) {
+ if p.linebreak(line, linebreakMin, ws, useFF || prevBreak+1 < i) {
ws = ignore
*multiLine = true
prevBreak = i
@@ -301,15 +294,27 @@ func (p *printer) exprList(prev token.Position, list []ast.Expr, depth int, mode
func (p *printer) parameters(fields *ast.FieldList, multiLine *bool) {
p.print(fields.Opening, token.LPAREN)
if len(fields.List) > 0 {
+ var prevLine, line int
for i, par := range fields.List {
if i > 0 {
- p.print(token.COMMA, blank)
+ p.print(token.COMMA)
+ if len(par.Names) > 0 {
+ line = p.fset.Position(par.Names[0].Pos()).Line
+ } else {
+ line = p.fset.Position(par.Type.Pos()).Line
+ }
+ if 0 < prevLine && prevLine < line && p.linebreak(line, 0, ignore, true) {
+ *multiLine = true
+ } else {
+ p.print(blank)
+ }
}
if len(par.Names) > 0 {
p.identList(par.Names, false, multiLine)
p.print(blank)
}
p.expr(par.Type, multiLine)
+ prevLine = p.fset.Position(par.Type.Pos()).Line
}
}
p.print(fields.Closing, token.RPAREN)
@@ -337,7 +342,7 @@ func identListSize(list []*ast.Ident, maxSize int) (size int) {
if i > 0 {
size += 2 // ", "
}
- size += len(x.Name())
+ size += len(x.Name)
if size >= maxSize {
break
}
@@ -366,16 +371,21 @@ func (p *printer) isOneLineFieldList(list []*ast.Field) bool {
func (p *printer) setLineComment(text string) {
- p.setComment(&ast.CommentGroup{[]*ast.Comment{&ast.Comment{noPos, []byte(text)}}})
+ p.setComment(&ast.CommentGroup{[]*ast.Comment{&ast.Comment{token.NoPos, []byte(text)}}})
}
func (p *printer) fieldList(fields *ast.FieldList, isIncomplete bool, ctxt exprContext) {
+ p.nesting++
+ defer func() {
+ p.nesting--
+ }()
+
lbrace := fields.Opening
list := fields.List
rbrace := fields.Closing
- if !isIncomplete && !p.commentBefore(rbrace) {
+ if !isIncomplete && !p.commentBefore(p.fset.Position(rbrace)) {
// possibly a one-line struct/interface
if len(list) == 0 {
// no blank between keyword and {} in this case
@@ -413,7 +423,7 @@ func (p *printer) fieldList(fields *ast.FieldList, isIncomplete bool, ctxt exprC
var ml bool
for i, f := range list {
if i > 0 {
- p.linebreak(f.Pos().Line, 1, 2, ignore, ml)
+ p.linebreak(p.fset.Position(f.Pos()).Line, 1, ignore, ml)
}
ml = false
extraTabs := 0
@@ -448,7 +458,7 @@ func (p *printer) fieldList(fields *ast.FieldList, isIncomplete bool, ctxt exprC
if len(list) > 0 {
p.print(formfeed)
}
- p.flush(rbrace, token.RBRACE) // make sure we don't loose the last line comment
+ p.flush(p.fset.Position(rbrace), token.RBRACE) // make sure we don't loose the last line comment
p.setLineComment("// contains unexported fields")
}
@@ -457,7 +467,7 @@ func (p *printer) fieldList(fields *ast.FieldList, isIncomplete bool, ctxt exprC
var ml bool
for i, f := range list {
if i > 0 {
- p.linebreak(f.Pos().Line, 1, 2, ignore, ml)
+ p.linebreak(p.fset.Position(f.Pos()).Line, 1, ignore, ml)
}
ml = false
p.setComment(f.Doc)
@@ -475,7 +485,7 @@ func (p *printer) fieldList(fields *ast.FieldList, isIncomplete bool, ctxt exprC
if len(list) > 0 {
p.print(formfeed)
}
- p.flush(rbrace, token.RBRACE) // make sure we don't loose the last line comment
+ p.flush(p.fset.Position(rbrace), token.RBRACE) // make sure we don't loose the last line comment
p.setLineComment("// contains unexported methods")
}
@@ -540,7 +550,7 @@ func walkBinary(e *ast.BinaryExpr) (has5, has6 bool, maxProblem int) {
case *ast.UnaryExpr:
switch e.Op.String() + r.Op.String() {
- case "/*":
+ case "/*", "&&", "&^":
maxProblem = 6
case "++", "--":
if maxProblem < 5 {
@@ -609,11 +619,14 @@ func reduceDepth(depth int) int {
// 1) If there is a binary operator with a right side unary operand
// that would clash without a space, the cutoff must be (in order):
//
-// &^ 7
// /* 7
+// && 7
+// &^ 7
// ++ 6
// -- 6
//
+// (Comparison operators always have spaces around them.)
+//
// 2) If there is a mix of level 6 and level 5 operators, then the cutoff
// is 6 (use spaces to distinguish precedence) in Normal mode
// and 5 (never use spaces) in Compact mode.
@@ -643,12 +656,12 @@ func (p *printer) binaryExpr(x *ast.BinaryExpr, prec1, cutoff, depth int, multiL
p.print(blank)
}
xline := p.pos.Line // before the operator (it may be on the next line!)
- yline := x.Y.Pos().Line
+ yline := p.fset.Position(x.Y.Pos()).Line
p.print(x.OpPos, x.Op)
if xline != yline && xline > 0 && yline > 0 {
// at least one line break, but respect an extra empty line
// in the source
- if p.linebreak(yline, 1, 2, ws, true) {
+ if p.linebreak(yline, 1, ws, true) {
ws = ignore
*multiLine = true
printBlank = false // no blank after line break
@@ -683,19 +696,19 @@ func splitSelector(expr ast.Expr) (body, suffix ast.Expr) {
case *ast.CallExpr:
body, suffix = splitSelector(x.Fun)
if body != nil {
- suffix = &ast.CallExpr{suffix, x.Lparen, x.Args, x.Rparen}
+ 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.Index}
+ 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.Index, x.End}
+ suffix = &ast.SliceExpr{suffix, x.Lbrack, x.Low, x.High, x.Rbrack}
return
}
case *ast.TypeAssertExpr:
@@ -712,23 +725,20 @@ func splitSelector(expr ast.Expr) (body, suffix ast.Expr) {
// Convert an expression into an expression list split at the periods of
// selector expressions.
-func selectorExprList(expr ast.Expr) []ast.Expr {
+func selectorExprList(expr ast.Expr) (list []ast.Expr) {
// split expression
- var list vector.Vector
for expr != nil {
var suffix ast.Expr
expr, suffix = splitSelector(expr)
- list.Push(suffix)
+ list = append(list, suffix)
}
- // convert expression list
- result := make([]ast.Expr, len(list))
- i := len(result)
- for _, x := range list {
- i--
- result[i] = x.(ast.Expr)
+ // 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 result
+
+ return
}
@@ -791,16 +801,22 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, ctxt exprContext, multi
case *ast.FuncLit:
p.expr(x.Type, multiLine)
- p.funcBody(x.Body, distance(x.Type.Pos(), p.pos), true, multiLine)
+ p.funcBody(x.Body, p.distance(x.Type.Pos(), p.pos), true, multiLine)
case *ast.ParenExpr:
- p.print(token.LPAREN)
- p.expr0(x.X, reduceDepth(depth), multiLine) // parentheses undo one level of depth
- p.print(x.Rparen, token.RPAREN)
+ if _, hasParens := x.X.(*ast.ParenExpr); hasParens {
+ // don't print parentheses around an already parenthesized expression
+ // TODO(gri) consider making this more general and incorporate precedence levels
+ p.expr0(x.X, reduceDepth(depth), multiLine) // parentheses undo one level of depth
+ } else {
+ p.print(token.LPAREN)
+ p.expr0(x.X, reduceDepth(depth), multiLine) // parentheses undo one level of depth
+ p.print(x.Rparen, token.RPAREN)
+ }
case *ast.SelectorExpr:
parts := selectorExprList(expr)
- p.exprList(noPos, parts, depth, periodSep, multiLine, noPos)
+ p.exprList(token.NoPos, parts, depth, periodSep, multiLine, token.NoPos)
case *ast.TypeAssertExpr:
p.expr1(x.X, token.HighestPrec, depth, 0, multiLine)
@@ -815,25 +831,27 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, ctxt exprContext, multi
case *ast.IndexExpr:
// TODO(gri): should treat[] like parentheses and undo one level of depth
p.expr1(x.X, token.HighestPrec, 1, 0, multiLine)
- p.print(token.LBRACK)
+ p.print(x.Lbrack, token.LBRACK)
p.expr0(x.Index, depth+1, multiLine)
- p.print(token.RBRACK)
+ p.print(x.Rbrack, token.RBRACK)
case *ast.SliceExpr:
// TODO(gri): should treat[] like parentheses and undo one level of depth
p.expr1(x.X, token.HighestPrec, 1, 0, multiLine)
- p.print(token.LBRACK)
- p.expr0(x.Index, depth+1, multiLine)
+ p.print(x.Lbrack, token.LBRACK)
+ if x.Low != nil {
+ p.expr0(x.Low, depth+1, multiLine)
+ }
// blanks around ":" if both sides exist and either side is a binary expression
- if depth <= 1 && x.End != nil && (isBinary(x.Index) || isBinary(x.End)) {
+ if depth <= 1 && x.Low != nil && x.High != nil && (isBinary(x.Low) || isBinary(x.High)) {
p.print(blank, token.COLON, blank)
} else {
p.print(token.COLON)
}
- if x.End != nil {
- p.expr0(x.End, depth+1, multiLine)
+ if x.High != nil {
+ p.expr0(x.High, depth+1, multiLine)
}
- p.print(token.RBRACK)
+ p.print(x.Rbrack, token.RBRACK)
case *ast.CallExpr:
if len(x.Args) > 1 {
@@ -842,10 +860,16 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int, ctxt exprContext, multi
p.expr1(x.Fun, token.HighestPrec, depth, 0, multiLine)
p.print(x.Lparen, token.LPAREN)
p.exprList(x.Lparen, x.Args, depth, commaSep|commaTerm, multiLine, x.Rparen)
+ if x.Ellipsis.IsValid() {
+ p.print(x.Ellipsis, token.ELLIPSIS)
+ }
p.print(x.Rparen, token.RPAREN)
case *ast.CompositeLit:
- p.expr1(x.Type, token.HighestPrec, depth, compositeLit, multiLine)
+ // composite literal elements that are composite literals themselves may have the type omitted
+ if x.Type != nil {
+ p.expr1(x.Type, token.HighestPrec, depth, compositeLit, multiLine)
+ }
p.print(x.Lbrace, token.LBRACE)
p.exprList(x.Lbrace, x.Elts, 1, commaSep|commaTerm, multiLine, x.Rbrace)
p.print(x.Rbrace, token.RBRACE)
@@ -917,8 +941,6 @@ func (p *printer) expr(x ast.Expr, multiLine *bool) {
// ----------------------------------------------------------------------------
// Statements
-const maxStmtNewlines = 2 // maximum number of newlines between statements
-
// Print the statement list indented, but without a newline after the last statement.
// Extra line breaks between statements in the source are respected but at most one
// empty line is printed between statements.
@@ -931,7 +953,7 @@ func (p *printer) stmtList(list []ast.Stmt, _indent int, nextIsRBrace bool) {
for i, s := range list {
// _indent == 0 only for lists of switch/select case clauses;
// in those cases each clause is a new section
- p.linebreak(s.Pos().Line, 1, maxStmtNewlines, ignore, i == 0 || _indent == 0 || multiLine)
+ 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)
}
@@ -945,7 +967,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(s.Rbrace.Line, 1, maxStmtNewlines, ignore, true)
+ p.linebreak(p.fset.Position(s.Rbrace).Line, 1, ignore, true)
p.print(s.Rbrace, token.RBRACE)
}
@@ -961,16 +983,27 @@ func isTypeName(x ast.Expr) bool {
}
-// TODO(gri): Decide if this should be used more broadly. The printing code
-// knows when to insert parentheses for precedence reasons, but
-// need to be careful to keep them around type expressions.
-func stripParens(x ast.Expr, inControlClause bool) ast.Expr {
- for px, hasParens := x.(*ast.ParenExpr); hasParens; px, hasParens = x.(*ast.ParenExpr) {
- x = px.X
- if cx, isCompositeLit := x.(*ast.CompositeLit); inControlClause && isCompositeLit && isTypeName(cx.Type) {
- // composite literals inside control clauses need parens if they start with a type name;
- // don't strip innermost layer
- return px
+func stripParens(x ast.Expr) ast.Expr {
+ if px, strip := x.(*ast.ParenExpr); strip {
+ // parentheses must not be stripped if there are any
+ // unparenthesized composite literals starting with
+ // a type name
+ ast.Inspect(px.X, func(node ast.Node) bool {
+ switch x := node.(type) {
+ case *ast.ParenExpr:
+ // parentheses protect enclosed composite literals
+ return false
+ case *ast.CompositeLit:
+ if isTypeName(x.Type) {
+ strip = false // do not strip parentheses
+ }
+ return false
+ }
+ // in all other cases, keep inspecting
+ return true
+ })
+ if strip {
+ return stripParens(px.X)
}
}
return x
@@ -983,7 +1016,7 @@ 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, true), ignoreMultiLine)
+ p.expr(stripParens(expr), ignoreMultiLine)
needsBlank = true
}
} else {
@@ -994,7 +1027,7 @@ func (p *printer) controlClause(isForStmt bool, init ast.Stmt, expr ast.Expr, po
}
p.print(token.SEMICOLON, blank)
if expr != nil {
- p.expr(stripParens(expr, true), ignoreMultiLine)
+ p.expr(stripParens(expr), ignoreMultiLine)
needsBlank = true
}
if isForStmt {
@@ -1032,14 +1065,14 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) {
// between (see writeWhitespace)
p.print(unindent)
p.expr(s.Label, multiLine)
- p.print(token.COLON, indent)
+ p.print(s.Colon, token.COLON, indent)
if e, isEmpty := s.Stmt.(*ast.EmptyStmt); isEmpty {
if !nextIsRBrace {
p.print(newline, e.Pos(), token.SEMICOLON)
break
}
} else {
- p.print(newline)
+ p.linebreak(p.fset.Position(s.Stmt.Pos()).Line, 1, ignore, true)
}
p.stmt(s.Stmt, nextIsRBrace, multiLine)
@@ -1050,7 +1083,7 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) {
case *ast.IncDecStmt:
const depth = 1
p.expr0(s.X, depth+1, multiLine)
- p.print(s.Tok)
+ p.print(s.TokPos, s.Tok)
case *ast.AssignStmt:
var depth = 1
@@ -1059,7 +1092,7 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) {
}
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, noPos)
+ p.exprList(s.TokPos, s.Rhs, depth, blankStart|commaSep, multiLine, token.NoPos)
case *ast.GoStmt:
p.print(token.GO, blank)
@@ -1072,7 +1105,7 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) {
case *ast.ReturnStmt:
p.print(token.RETURN)
if s.Results != nil {
- p.exprList(s.Pos(), s.Results, 1, blankStart|commaSep, multiLine, noPos)
+ p.exprList(s.Pos(), s.Results, 1, blankStart|commaSep, multiLine, token.NoPos)
}
case *ast.BranchStmt:
@@ -1175,7 +1208,7 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) {
p.expr(s.Value, multiLine)
}
p.print(blank, s.TokPos, s.Tok, blank, token.RANGE, blank)
- p.expr(stripParens(s.X, true), multiLine)
+ p.expr(stripParens(s.X), multiLine)
p.print(blank)
p.block(s.Body, 1)
*multiLine = true
@@ -1191,25 +1224,25 @@ func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool, multiLine *bool) {
// ----------------------------------------------------------------------------
// Declarations
-// The parameter n is the number of specs in the group. If indent is set,
+// 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, indent bool, multiLine *bool) {
+func (p *printer) spec(spec ast.Spec, n int, doIndent bool, multiLine *bool) {
switch s := spec.(type) {
case *ast.ImportSpec:
p.setComment(s.Doc)
if s.Name != nil {
p.expr(s.Name, multiLine)
- p.print(blank)
+ p.print(vtab)
}
p.expr(s.Path, multiLine)
p.setComment(s.Comment)
case *ast.ValueSpec:
p.setComment(s.Doc)
- p.identList(s.Names, indent, multiLine) // always present
+ p.identList(s.Names, doIndent, multiLine) // always present
if n == 1 {
if s.Type != nil {
p.print(blank)
@@ -1217,7 +1250,7 @@ func (p *printer) spec(spec ast.Spec, n int, indent bool, multiLine *bool) {
}
if s.Values != nil {
p.print(blank, token.ASSIGN)
- p.exprList(noPos, s.Values, 1, blankStart|commaSep, multiLine, noPos)
+ p.exprList(token.NoPos, s.Values, 1, blankStart|commaSep, multiLine, token.NoPos)
}
p.setComment(s.Comment)
@@ -1230,7 +1263,7 @@ func (p *printer) spec(spec ast.Spec, n int, indent bool, multiLine *bool) {
}
if s.Values != nil {
p.print(vtab, token.ASSIGN)
- p.exprList(noPos, s.Values, 1, blankStart|commaSep, multiLine, noPos)
+ p.exprList(token.NoPos, s.Values, 1, blankStart|commaSep, multiLine, token.NoPos)
extraTabs--
}
if s.Comment != nil {
@@ -1271,7 +1304,7 @@ func (p *printer) genDecl(d *ast.GenDecl, multiLine *bool) {
var ml bool
for i, s := range d.Specs {
if i > 0 {
- p.linebreak(s.Pos().Line, 1, 2, ignore, ml)
+ p.linebreak(p.fset.Position(s.Pos()).Line, 1, ignore, ml)
}
ml = false
p.spec(s, len(d.Specs), false, &ml)
@@ -1300,7 +1333,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, n); err != nil {
+ if _, err := cfg.Fprint(&buf, p.fset, n); err != nil {
return
}
if buf.Len() <= maxSize {
@@ -1318,11 +1351,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() && pos1.Line != pos2.Line {
+ if pos1.IsValid() && pos2.IsValid() && p.fset.Position(pos1).Line != p.fset.Position(pos2).Line {
// opening and closing brace are on different lines - don't make it a one-liner
return false
}
- if len(b.List) > 5 || p.commentBefore(pos2) {
+ if len(b.List) > 5 || p.commentBefore(p.fset.Position(pos2)) {
// too many statements or there is a comment inside - don't make it a one-liner
return false
}
@@ -1345,6 +1378,11 @@ func (p *printer) funcBody(b *ast.BlockStmt, headerSize int, isLit bool, multiLi
return
}
+ p.nesting++
+ defer func() {
+ p.nesting--
+ }()
+
if p.isOneLineFunc(b, headerSize) {
sep := vtab
if isLit {
@@ -1374,7 +1412,8 @@ func (p *printer) funcBody(b *ast.BlockStmt, headerSize int, isLit bool, multiLi
// 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 distance(from, to token.Position) int {
+func (p *printer) distance(from0 token.Pos, to token.Position) int {
+ from := p.fset.Position(from0)
if from.IsValid() && to.IsValid() && from.Line == to.Line {
return to.Column - from.Column
}
@@ -1392,7 +1431,7 @@ func (p *printer) funcDecl(d *ast.FuncDecl, multiLine *bool) {
}
p.expr(d.Name, multiLine)
p.signature(d.Type.Params, d.Type.Results, multiLine)
- p.funcBody(d.Body, distance(d.Pos(), p.pos), false, multiLine)
+ p.funcBody(d.Body, p.distance(d.Pos(), p.pos), false, multiLine)
}
@@ -1414,8 +1453,6 @@ func (p *printer) decl(decl ast.Decl, multiLine *bool) {
// ----------------------------------------------------------------------------
// Files
-const maxDeclNewlines = 3 // maximum number of newlines between declarations
-
func declToken(decl ast.Decl) (tok token.Token) {
tok = token.ILLEGAL
switch d := decl.(type) {
@@ -1444,7 +1481,7 @@ func (p *printer) file(src *ast.File) {
if prev != tok {
min = 2
}
- p.linebreak(d.Pos().Line, min, maxDeclNewlines, ignore, false)
+ p.linebreak(p.fset.Position(d.Pos()).Line, min, ignore, false)
p.decl(d, ignoreMultiLine)
}
}
diff --git a/src/pkg/go/printer/printer.go b/src/pkg/go/printer/printer.go
index 53632c83d..a4ddad50e 100644
--- a/src/pkg/go/printer/printer.go
+++ b/src/pkg/go/printer/printer.go
@@ -18,10 +18,7 @@ import (
)
-const (
- debug = false // enable for debugging
- maxNewlines = 3 // maximum vertical white space
-)
+const debug = false // enable for debugging
type whiteSpace int
@@ -41,8 +38,8 @@ 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 maxNewlines
- formfeeds = []byte("\f\f\f\f\f\f\f\f") // more than maxNewlines
+ newlines = []byte("\n\n\n\n\n\n\n\n") // more than the max determined by nlines
+ formfeeds = []byte("\f\f\f\f\f\f\f\f") // more than the max determined by nlines
esc_quot = []byte("&#34;") // shorter than "&quot;"
esc_apos = []byte("&#39;") // shorter than "&apos;"
@@ -65,12 +62,15 @@ type printer struct {
// Configuration (does not change after initialization)
output io.Writer
Config
+ fset *token.FileSet
errors chan os.Error
// Current state
- written int // number of bytes written
- indent int // current indentation
- escape bool // true if in escape sequence
+ nesting int // nesting level (0: top-level (package scope), >0: functions/decls.)
+ written int // number of bytes written
+ indent int // current indentation
+ escape bool // true if in escape sequence
+ lastTok token.Token // the last token printed (token.ILLEGAL if it's whitespace)
// Buffered whitespace
buffer []whiteSpace
@@ -95,9 +95,10 @@ type printer struct {
}
-func (p *printer) init(output io.Writer, cfg *Config) {
+func (p *printer) init(output io.Writer, cfg *Config, fset *token.FileSet) {
p.output = output
p.Config = *cfg
+ p.fset = fset
p.errors = make(chan os.Error)
p.buffer = make([]whiteSpace, 0, 16) // whitespace sequences are short
}
@@ -106,12 +107,31 @@ func (p *printer) init(output io.Writer, cfg *Config) {
func (p *printer) internalError(msg ...interface{}) {
if debug {
fmt.Print(p.pos.String() + ": ")
- fmt.Println(msg)
+ fmt.Println(msg...)
panic("go/printer")
}
}
+// nlines returns the adjusted number of linebreaks given the desired number
+// of breaks n such that min <= result <= max where max depends on the current
+// nesting level.
+//
+func (p *printer) nlines(n, min int) int {
+ if n < min {
+ return min
+ }
+ max := 3 // max. number of newlines at the top level (p.nesting == 0)
+ if p.nesting > 0 {
+ max = 2 // max. number of newlines everywhere else
+ }
+ if n > max {
+ return max
+ }
+ return n
+}
+
+
// write0 writes raw (uninterpreted) data to p.output and handles errors.
// write0 does not indent after newlines, and does not HTML-escape or update p.pos.
//
@@ -192,6 +212,11 @@ func (p *printer) write(data []byte) {
case tabwriter.Escape:
p.escape = !p.escape
+
+ // ignore escape chars introduced by printer - they are
+ // invisible and must not affect p.pos (was issue #1089)
+ p.pos.Offset--
+ p.pos.Column--
}
}
@@ -207,9 +232,7 @@ func (p *printer) write(data []byte) {
func (p *printer) writeNewlines(n int, useFF bool) {
if n > 0 {
- if n > maxNewlines {
- n = maxNewlines
- }
+ n = p.nlines(n, 0)
if useFF {
p.write(formfeeds[0:n])
} else {
@@ -292,8 +315,8 @@ func (p *printer) writeCommentPrefix(pos, next token.Position, isFirst, isKeywor
}
if pos.IsValid() && pos.Filename != p.last.Filename {
- // comment in a different file - separate with newlines
- p.writeNewlines(maxNewlines, true)
+ // comment in a different file - separate with newlines (writeNewlines will limit the number)
+ p.writeNewlines(10, true)
return
}
@@ -380,7 +403,6 @@ func (p *printer) writeCommentPrefix(pos, next token.Position, isFirst, isKeywor
func (p *printer) writeCommentLine(comment *ast.Comment, pos token.Position, line []byte) {
// line must pass through unchanged, bracket it with tabwriter.Escape
- esc := []byte{tabwriter.Escape}
line = bytes.Join([][]byte{esc, line, esc}, nil)
// apply styler, if any
@@ -576,7 +598,7 @@ func (p *printer) writeComment(comment *ast.Comment) {
// shortcut common case of //-style comments
if text[1] == '/' {
- p.writeCommentLine(comment, comment.Pos(), text)
+ p.writeCommentLine(comment, p.fset.Position(comment.Pos()), text)
return
}
@@ -588,7 +610,7 @@ func (p *printer) writeComment(comment *ast.Comment) {
// write comment lines, separated by formfeed,
// without a line break after the last line
linebreak := formfeeds[0:1]
- pos := comment.Pos()
+ pos := p.fset.Position(comment.Pos())
for i, line := range lines {
if i > 0 {
p.write(linebreak)
@@ -649,14 +671,14 @@ func (p *printer) intersperseComments(next token.Position, tok token.Token) (dro
var last *ast.Comment
for ; p.commentBefore(next); p.cindex++ {
for _, c := range p.comments[p.cindex].List {
- p.writeCommentPrefix(c.Pos(), next, last == nil, tok.IsKeyword())
+ p.writeCommentPrefix(p.fset.Position(c.Pos()), next, last == nil, tok.IsKeyword())
p.writeComment(c)
last = c
}
}
if last != nil {
- if last.Text[1] == '*' && last.Pos().Line == next.Line {
+ 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{' '})
@@ -726,6 +748,26 @@ func (p *printer) writeWhitespace(n int) {
// ----------------------------------------------------------------------------
// Printing interface
+
+func mayCombine(prev token.Token, next byte) (b bool) {
+ switch prev {
+ case token.INT:
+ b = next == '.' // 1.
+ case token.ADD:
+ b = next == '+' // ++
+ case token.SUB:
+ b = next == '-' // --
+ case token.QUO:
+ b = next == '*' // /*
+ case token.LSS:
+ b = next == '-' || next == '<' // <- or <<
+ case token.AND:
+ b = next == '&' || next == '^' // && or &^
+ }
+ return
+}
+
+
// print prints a list of "items" (roughly corresponding to syntactic
// tokens, but also including whitespace and formatting information).
// It is the only print function that should be called directly from
@@ -743,6 +785,7 @@ func (p *printer) print(args ...interface{}) {
var data []byte
var tag HTMLTag
var tok token.Token
+
switch x := f.(type) {
case whiteSpace:
if x == ignore {
@@ -765,7 +808,7 @@ func (p *printer) print(args ...interface{}) {
if p.Styler != nil {
data, tag = p.Styler.Ident(x)
} else {
- data = []byte(x.Name())
+ data = []byte(x.Name)
}
tok = token.IDENT
case *ast.BasicLit:
@@ -779,22 +822,38 @@ func (p *printer) print(args ...interface{}) {
// bytes since they do not appear in legal UTF-8 sequences)
// TODO(gri): do this more efficiently.
data = []byte("\xff" + string(data) + "\xff")
- tok = token.INT // representing all literal tokens
+ tok = x.Kind
case token.Token:
+ s := x.String()
+ if mayCombine(p.lastTok, s[0]) {
+ // the previous and the current token must be
+ // separated by a blank otherwise they combine
+ // into a different incorrect token sequence
+ // (except for token.INT followed by a '.' this
+ // should never happen because it is taken care
+ // of via binary expression formatting)
+ if len(p.buffer) != 0 {
+ p.internalError("whitespace buffer not empty")
+ }
+ p.buffer = p.buffer[0:1]
+ p.buffer[0] = ' '
+ }
if p.Styler != nil {
data, tag = p.Styler.Token(x)
} else {
- data = []byte(x.String())
+ data = []byte(s)
}
tok = x
- case token.Position:
+ case token.Pos:
if x.IsValid() {
- next = x // accurate position of next item
+ next = p.fset.Position(x) // accurate position of next item
}
+ tok = p.lastTok
default:
fmt.Fprintf(os.Stderr, "print: unsupported argument type %T\n", f)
panic("go/printer type")
}
+ p.lastTok = tok
p.pos = next
if data != nil {
@@ -816,11 +875,11 @@ func (p *printer) print(args ...interface{}) {
// before the next position in the source code.
//
func (p *printer) commentBefore(next token.Position) bool {
- return p.cindex < len(p.comments) && p.comments[p.cindex].List[0].Pos().Offset < next.Offset
+ return p.cindex < len(p.comments) && p.fset.Position(p.comments[p.cindex].List[0].Pos()).Offset < next.Offset
}
-// Flush prints any pending comments and whitespace occuring
+// 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
@@ -844,81 +903,85 @@ func (p *printer) flush(next token.Position, tok token.Token) (droppedFF bool) {
// A trimmer is an io.Writer filter for stripping tabwriter.Escape
// characters, trailing blanks and tabs, and for converting formfeed
// and vtab characters into newlines and htabs (in case no tabwriter
-// is used).
+// is used). Text bracketed by tabwriter.Escape characters is passed
+// through unchanged.
//
type trimmer struct {
output io.Writer
- buf bytes.Buffer
+ space bytes.Buffer
+ state int
}
-// Design note: It is tempting to eliminate extra blanks occuring in
+// trimmer is implemented as a state machine.
+// It can be in one of the following states:
+const (
+ inSpace = iota
+ inEscape
+ inText
+)
+
+
+// Design note: It is tempting to eliminate extra blanks occurring in
// whitespace in this function as it could simplify some
// of the blanks logic in the node printing functions.
// However, this would mess up any formatting done by
// the tabwriter.
func (p *trimmer) Write(data []byte) (n int, err os.Error) {
- // m < 0: no unwritten data except for whitespace
- // m >= 0: data[m:n] unwritten and no whitespace
- m := 0
- if p.buf.Len() > 0 {
- m = -1
- }
-
+ m := 0 // if p.state != inSpace, data[m:n] is unwritten
var b byte
for n, b = range data {
- switch b {
- default:
- // write any pending whitespace
- if m < 0 {
- if _, err = p.output.Write(p.buf.Bytes()); err != nil {
- return
- }
- p.buf.Reset()
- m = n
- }
-
- case '\v':
+ if b == '\v' {
b = '\t' // convert to htab
- fallthrough
-
- case '\t', ' ', tabwriter.Escape:
- // write any pending (non-whitespace) data
- if m >= 0 {
- if _, err = p.output.Write(data[m:n]); err != nil {
- return
- }
- m = -1
+ }
+ switch p.state {
+ case inSpace:
+ switch b {
+ case '\t', ' ':
+ p.space.WriteByte(b) // WriteByte returns no errors
+ case '\f', '\n':
+ p.space.Reset() // discard trailing space
+ _, err = p.output.Write(newlines[0:1]) // write newline
+ case tabwriter.Escape:
+ _, err = p.output.Write(p.space.Bytes())
+ p.space.Reset()
+ p.state = inEscape
+ m = n + 1 // drop tabwriter.Escape
+ default:
+ _, err = p.output.Write(p.space.Bytes())
+ p.space.Reset()
+ p.state = inText
+ m = n
}
- // collect whitespace but discard tabwriter.Escapes.
- if b != tabwriter.Escape {
- p.buf.WriteByte(b) // WriteByte returns no errors
+ case inEscape:
+ if b == tabwriter.Escape {
+ _, err = p.output.Write(data[m:n])
+ p.state = inSpace
}
-
- case '\f', '\n':
- // discard whitespace
- p.buf.Reset()
- // write any pending (non-whitespace) data
- if m >= 0 {
- if _, err = p.output.Write(data[m:n]); err != nil {
- return
- }
- m = -1
- }
- // convert formfeed into newline
- if _, err = p.output.Write(newlines[0:1]); err != nil {
- return
+ case inText:
+ switch b {
+ case '\t', ' ':
+ _, err = p.output.Write(data[m:n])
+ p.state = inSpace
+ p.space.WriteByte(b) // WriteByte returns no errors
+ case '\f':
+ data[n] = '\n' // convert to newline
+ case tabwriter.Escape:
+ _, err = p.output.Write(data[m:n])
+ p.state = inEscape
+ m = n + 1 // drop tabwriter.Escape
}
}
+ if err != nil {
+ return
+ }
}
n = len(data)
- // write any pending non-whitespace
- if m >= 0 {
- if _, err = p.output.Write(data[m:n]); err != nil {
- return
- }
+ if p.state != inSpace {
+ _, err = p.output.Write(data[m:n])
+ p.state = inSpace
}
return
@@ -965,10 +1028,11 @@ type Config struct {
// Fprint "pretty-prints" an AST node to output and returns the number
// of bytes written and an error (if any) for a given configuration cfg.
+// Position information is interpreted relative to the file set fset.
// The node type must be *ast.File, or assignment-compatible to ast.Expr,
// ast.Decl, ast.Spec, or ast.Stmt.
//
-func (cfg *Config) Fprint(output io.Writer, node interface{}) (int, os.Error) {
+func (cfg *Config) Fprint(output io.Writer, fset *token.FileSet, node interface{}) (int, os.Error) {
// redirect output through a trimmer to eliminate trailing whitespace
// (Input to a tabwriter must be untrimmed since trailing tabs provide
// formatting information. The tabwriter could provide trimming
@@ -1000,13 +1064,15 @@ func (cfg *Config) Fprint(output io.Writer, node interface{}) (int, os.Error) {
// setup printer and print node
var p printer
- p.init(output, cfg)
+ p.init(output, cfg, fset)
go func() {
switch n := node.(type) {
case ast.Expr:
+ p.nesting = 1
p.useNodeComments = true
p.expr(n, ignoreMultiLine)
case ast.Stmt:
+ p.nesting = 1
p.useNodeComments = true
// A labeled statement will un-indent to position the
// label. Set indent to 1 so we don't get indent "underflow".
@@ -1015,17 +1081,20 @@ func (cfg *Config) Fprint(output io.Writer, node interface{}) (int, os.Error) {
}
p.stmt(n, false, ignoreMultiLine)
case ast.Decl:
+ p.nesting = 1
p.useNodeComments = true
p.decl(n, ignoreMultiLine)
case ast.Spec:
+ p.nesting = 1
p.useNodeComments = true
p.spec(n, 1, false, ignoreMultiLine)
case *ast.File:
+ p.nesting = 0
p.comments = n.Comments
p.useNodeComments = n.Comments == nil
p.file(n)
default:
- p.errors <- os.NewError(fmt.Sprintf("printer.Fprint: unsupported node type %T", n))
+ p.errors <- fmt.Errorf("printer.Fprint: unsupported node type %T", n)
runtime.Goexit()
}
p.flush(token.Position{Offset: infinity, Line: infinity}, token.EOF)
@@ -1045,7 +1114,7 @@ func (cfg *Config) Fprint(output io.Writer, node interface{}) (int, os.Error) {
// Fprint "pretty-prints" an AST node to output.
// It calls Config.Fprint with default settings.
//
-func Fprint(output io.Writer, node interface{}) os.Error {
- _, err := (&Config{Tabwidth: 8}).Fprint(output, node) // don't care about number of bytes written
+func Fprint(output io.Writer, fset *token.FileSet, node interface{}) os.Error {
+ _, err := (&Config{Tabwidth: 8}).Fprint(output, fset, node) // don't care about number of bytes written
return err
}
diff --git a/src/pkg/go/printer/printer_test.go b/src/pkg/go/printer/printer_test.go
index a5de3774a..c66471b92 100644
--- a/src/pkg/go/printer/printer_test.go
+++ b/src/pkg/go/printer/printer_test.go
@@ -10,6 +10,7 @@ import (
"io/ioutil"
"go/ast"
"go/parser"
+ "go/token"
"path"
"testing"
)
@@ -24,6 +25,9 @@ const (
var update = flag.Bool("update", false, "update golden files")
+var fset = token.NewFileSet()
+
+
func lineString(text []byte, i int) string {
i0 := i
for i < len(text) && text[i] != '\n' {
@@ -43,7 +47,7 @@ const (
func check(t *testing.T, source, golden string, mode checkMode) {
// parse source
- prog, err := parser.ParseFile(source, nil, nil, parser.ParseComments)
+ prog, err := parser.ParseFile(fset, source, nil, parser.ParseComments)
if err != nil {
t.Error(err)
return
@@ -63,7 +67,7 @@ func check(t *testing.T, source, golden string, mode checkMode) {
// format source
var buf bytes.Buffer
- if _, err := cfg.Fprint(&buf, prog); err != nil {
+ if _, err := cfg.Fprint(&buf, fset, prog); err != nil {
t.Error(err)
}
res := buf.Bytes()
@@ -112,14 +116,14 @@ type entry struct {
// Use gotest -update to create/update the respective golden files.
var data = []entry{
- entry{"empty.input", "empty.golden", 0},
- entry{"comments.input", "comments.golden", 0},
- entry{"comments.input", "comments.x", export},
- entry{"linebreaks.input", "linebreaks.golden", 0},
- entry{"expressions.input", "expressions.golden", 0},
- entry{"expressions.input", "expressions.raw", rawFormat},
- entry{"declarations.input", "declarations.golden", 0},
- entry{"statements.input", "statements.golden", 0},
+ {"empty.input", "empty.golden", 0},
+ {"comments.input", "comments.golden", 0},
+ {"comments.input", "comments.x", export},
+ {"linebreaks.input", "linebreaks.golden", 0},
+ {"expressions.input", "expressions.golden", 0},
+ {"expressions.input", "expressions.raw", rawFormat},
+ {"declarations.input", "declarations.golden", 0},
+ {"statements.input", "statements.golden", 0},
}
diff --git a/src/pkg/go/printer/testdata/comments.golden b/src/pkg/go/printer/testdata/comments.golden
index 4c9f71d95..200ea332f 100644
--- a/src/pkg/go/printer/testdata/comments.golden
+++ b/src/pkg/go/printer/testdata/comments.golden
@@ -431,6 +431,38 @@ func _() {
}
+// Comments immediately adjacent to punctuation (for which the go/printer
+// may obly have estimated position information) must remain after the punctuation.
+func _() {
+ _ = T{
+ 1, // comment after comma
+ 2, /* comment after comma */
+ 3, // comment after comma
+ }
+ _ = T{
+ 1, // comment after comma
+ 2, /* comment after comma */
+ 3, // comment after comma
+ }
+ _ = T{
+ /* comment before literal */ 1,
+ 2, /* comment before comma - ok to move after comma */
+ 3, /* comment before comma - ok to move after comma */
+ }
+
+ for i = 0; // comment after semicolon
+ i < 9; /* comment after semicolon */
+ i++ { // comment after opening curly brace
+ }
+
+ // TODO(gri) the last comment in this example should be aligned */
+ for i = 0; // comment after semicolon
+ i < 9; /* comment before semicolon - ok to move after semicolon */
+ i++ /* comment before opening curly brace */ {
+ }
+}
+
+
// Line comments with tabs
func _() {
var finput *bufio.Reader // input file
diff --git a/src/pkg/go/printer/testdata/comments.input b/src/pkg/go/printer/testdata/comments.input
index 335e81391..4a9ea4742 100644
--- a/src/pkg/go/printer/testdata/comments.input
+++ b/src/pkg/go/printer/testdata/comments.input
@@ -429,6 +429,40 @@ func _() {
/* closing curly brace should be on new line */ }
+// Comments immediately adjacent to punctuation (for which the go/printer
+// may obly have estimated position information) must remain after the punctuation.
+func _() {
+ _ = T{
+ 1, // comment after comma
+ 2, /* comment after comma */
+ 3 , // comment after comma
+ }
+ _ = T{
+ 1 ,// comment after comma
+ 2 ,/* comment after comma */
+ 3,// comment after comma
+ }
+ _ = T{
+ /* comment before literal */1,
+ 2/* comment before comma - ok to move after comma */,
+ 3 /* comment before comma - ok to move after comma */ ,
+ }
+
+ for
+ i=0;// comment after semicolon
+ i<9;/* comment after semicolon */
+ i++{// comment after opening curly brace
+ }
+
+ // TODO(gri) the last comment in this example should be aligned */
+ for
+ i=0;// comment after semicolon
+ i<9/* comment before semicolon - ok to move after semicolon */;
+ i++ /* comment before opening curly brace */ {
+ }
+}
+
+
// Line comments with tabs
func _() {
var finput *bufio.Reader // input file
diff --git a/src/pkg/go/printer/testdata/declarations.golden b/src/pkg/go/printer/testdata/declarations.golden
index 67f16b805..1c091b929 100644
--- a/src/pkg/go/printer/testdata/declarations.golden
+++ b/src/pkg/go/printer/testdata/declarations.golden
@@ -7,10 +7,10 @@ package imports
import "io"
import (
- _ "io"
+ _ "io"
)
-import _ "io"
+import _ "io"
import (
"io"
@@ -20,40 +20,60 @@ import (
import (
"io"
- aLongRename "io"
+ aLongRename "io"
- b "io"
+ b "io"
+)
+
+import (
+ "unrenamed"
+ renamed "renameMe"
+ . "io"
+ _ "io"
+ "io"
+ . "os"
)
// no newlines between consecutive single imports, but
// respect extra line breaks in the source (at most one empty line)
-import _ "io"
-import _ "io"
-import _ "io"
+import _ "io"
+import _ "io"
+import _ "io"
-import _ "os"
-import _ "os"
-import _ "os"
+import _ "os"
+import _ "os"
+import _ "os"
-import _ "fmt"
-import _ "fmt"
-import _ "fmt"
+import _ "fmt"
+import _ "fmt"
+import _ "fmt"
import "foo" // a comment
import "bar" // a comment
import (
- _ "foo"
+ _ "foo"
// a comment
"bar"
"foo" // a comment
"bar" // a comment
)
+// comments + renames
+import (
+ "unrenamed" // a comment
+ renamed "renameMe"
+ . "io" /* a comment */
+ _ "io/ioutil" // a comment
+ "io" // testing alignment
+ . "os"
+ // a comment
+)
+
// a case that caused problems in the past (comment placement)
import (
- . "fmt"
+ . "fmt"
"io"
"malloc" // for the malloc count test only
"math"
@@ -63,7 +83,7 @@ import (
// at least one empty line between declarations of different kind
-import _ "io"
+import _ "io"
var _ int
@@ -617,24 +637,79 @@ func _() {
// ellipsis parameters
-func _(...)
func _(...int)
func _(...*int)
func _(...[]int)
func _(...struct{})
func _(bool, ...interface{})
func _(bool, ...func())
-func _(bool, ...func(...))
+func _(bool, ...func(...int))
func _(bool, ...map[string]int)
func _(bool, ...chan int)
-func _(b bool, x ...)
func _(b bool, x ...int)
func _(b bool, x ...*int)
func _(b bool, x ...[]int)
func _(b bool, x ...struct{})
func _(x ...interface{})
func _(x ...func())
-func _(x ...func(...))
+func _(x ...func(...int))
func _(x ...map[string]int)
func _(x ...chan int)
+
+
+// these parameter lists must remain multi-line since they are multi-line in the source
+func _(bool,
+int) {
+}
+func _(x bool,
+y int) {
+}
+func _(x,
+y bool) {
+}
+func _(bool, // comment
+int) {
+}
+func _(x bool, // comment
+y int) {
+}
+func _(x, // comment
+y bool) {
+}
+func _(bool, // comment
+// comment
+int) {
+}
+func _(x bool, // comment
+// comment
+y int) {
+}
+func _(x, // comment
+// comment
+y bool) {
+}
+func _(bool,
+// comment
+int) {
+}
+func _(x bool,
+// comment
+y int) {
+}
+func _(x,
+// comment
+y bool) {
+}
+func _(x, // comment
+y, // comment
+z bool) {
+}
+func _(x, // comment
+y, // comment
+z bool) {
+}
+func _(x int, // comment
+y float, // comment
+z bool) {
+}
diff --git a/src/pkg/go/printer/testdata/declarations.input b/src/pkg/go/printer/testdata/declarations.input
index 095d1ddac..c826462f9 100644
--- a/src/pkg/go/printer/testdata/declarations.input
+++ b/src/pkg/go/printer/testdata/declarations.input
@@ -25,6 +25,15 @@ import (
b "io"
)
+import (
+ "unrenamed"
+ renamed "renameMe"
+ . "io"
+ _ "io"
+ "io"
+ . "os"
+)
+
// no newlines between consecutive single imports, but
// respect extra line breaks in the source (at most one empty line)
import _ "io"
@@ -51,6 +60,17 @@ import (
"bar" // a comment
)
+// comments + renames
+import (
+ "unrenamed" // a comment
+ renamed "renameMe"
+ . "io" /* a comment */
+ _ "io/ioutil" // a comment
+ "io" // testing alignment
+ . "os"
+ // a comment
+)
+
// a case that caused problems in the past (comment placement)
import (
. "fmt"
@@ -605,24 +625,79 @@ func _() {
// ellipsis parameters
-func _(...)
func _(...int)
func _(...*int)
func _(...[]int)
func _(...struct{})
func _(bool, ...interface{})
func _(bool, ...func())
-func _(bool, ...func(...))
+func _(bool, ...func(...int))
func _(bool, ...map[string]int)
func _(bool, ...chan int)
-func _(b bool, x ...)
func _(b bool, x ...int)
func _(b bool, x ...*int)
func _(b bool, x ...[]int)
func _(b bool, x ...struct{})
func _(x ...interface{})
func _(x ...func())
-func _(x ...func(...))
+func _(x ...func(...int))
func _(x ...map[string]int)
func _(x ...chan int)
+
+
+// these parameter lists must remain multi-line since they are multi-line in the source
+func _(bool,
+int) {
+}
+func _(x bool,
+y int) {
+}
+func _(x,
+y bool) {
+}
+func _(bool, // comment
+int) {
+}
+func _(x bool, // comment
+y int) {
+}
+func _(x, // comment
+y bool) {
+}
+func _(bool, // comment
+// comment
+int) {
+}
+func _(x bool, // comment
+// comment
+y int) {
+}
+func _(x, // comment
+// comment
+y bool) {
+}
+func _(bool,
+// comment
+int) {
+}
+func _(x bool,
+// comment
+y int) {
+}
+func _(x,
+// comment
+y bool) {
+}
+func _(x, // comment
+y,// comment
+z bool) {
+}
+func _(x, // comment
+ y,// comment
+ z bool) {
+}
+func _(x int, // comment
+ y float, // comment
+ z bool) {
+}
diff --git a/src/pkg/go/printer/testdata/expressions.golden b/src/pkg/go/printer/testdata/expressions.golden
index 95e5502d3..882c7624c 100644
--- a/src/pkg/go/printer/testdata/expressions.golden
+++ b/src/pkg/go/printer/testdata/expressions.golden
@@ -31,6 +31,9 @@ func _() {
_ = 1 + a
_ = a + 1
_ = a + b + 1
+ _ = s[a]
+ _ = s[a:]
+ _ = s[:b]
_ = s[1:2]
_ = s[a:b]
_ = s[0:len(s)]
@@ -56,6 +59,7 @@ func _() {
_ = s[a : b-c]
_ = s[0:]
_ = s[a+b]
+ _ = s[:b-c]
_ = s[a+b:]
_ = a[a<<b+1]
_ = a[a<<b+1:]
@@ -165,6 +169,45 @@ func _() {
}
+func f(x int, args ...int) {
+ f(0, args...)
+ f(1, args)
+ f(2, args[0])
+
+ // make sure syntactically legal code remains syntactically legal
+ f(3, 42 ...) // a blank must remain between 42 and ...
+ f(4, 42....)
+ f(5, 42....)
+ f(6, 42.0...)
+ f(7, 42.0...)
+ f(8, .42...)
+ f(9, .42...)
+ f(10, 42e0...)
+ f(11, 42e0...)
+
+ _ = 42 .x // a blank must remain between 42 and .x
+ _ = 42..x
+ _ = 42..x
+ _ = 42.0.x
+ _ = 42.0.x
+ _ = .42.x
+ _ = .42.x
+ _ = 42e0.x
+ _ = 42e0.x
+
+ // a blank must remain between the binary operator and the 2nd operand
+ _ = x / *y
+ _ = x < -1
+ _ = x < <-1
+ _ = x + +1
+ _ = x - -1
+ _ = x & &x
+ _ = x & ^x
+
+ _ = f(x / *y, x < -1, x < <-1, x + +1, x - -1, x & &x, x & ^x)
+}
+
+
func _() {
_ = T{}
_ = struct{}{}
@@ -172,13 +215,6 @@ func _() {
_ = [...]T{}
_ = []T{}
_ = map[int]T{}
-
- _ = (T){}
- _ = (struct{}){}
- _ = ([10]T){}
- _ = ([...]T){}
- _ = ([]T){}
- _ = (map[int]T){}
}
@@ -206,6 +242,8 @@ func _() {
`
_ = `foo
bar`
+ _ = `three spaces before the end of the line starting here:
+they must not be removed`
}
@@ -239,6 +277,27 @@ func _() {
func _() {
+ _ = [][]int{
+ []int{1},
+ []int{1, 2},
+ []int{1, 2, 3},
+ }
+ _ = [][]int{
+ {1},
+ []int{1, 2},
+ []int{1, 2, 3},
+ }
+ _ = [][]int{
+ {1},
+ {1, 2},
+ {1, 2, 3},
+ }
+ _ = [][]int{{1}, {1, 2}, {1, 2, 3}}
+}
+
+
+// various multi-line expressions
+func _() {
// do not add extra indentation to multi-line string lists
_ = "foo" + "bar"
_ = "foo" +
@@ -336,7 +395,6 @@ func _() {
2,
3,
)
- // TODO(gri) the cases below are not correct yet
f(1,
2,
3) // comment
@@ -349,8 +407,7 @@ func _() {
3) // comment
f(1,
2,
- 3 // comment
- ,
+ 3, // comment
)
}
diff --git a/src/pkg/go/printer/testdata/expressions.input b/src/pkg/go/printer/testdata/expressions.input
index 13891d971..647706b09 100644
--- a/src/pkg/go/printer/testdata/expressions.input
+++ b/src/pkg/go/printer/testdata/expressions.input
@@ -31,6 +31,9 @@ func _() {
_ = 1+a
_ = a+1
_ = a+b+1
+ _ = s[a]
+ _ = s[a:]
+ _ = s[:b]
_ = s[1:2]
_ = s[a:b]
_ = s[0:len(s)]
@@ -56,6 +59,7 @@ func _() {
_ = s[a : b-c]
_ = s[0:]
_ = s[a+b]
+ _ = s[: b-c]
_ = s[a+b :]
_ = a[a<<b+1]
_ = a[a<<b+1 :]
@@ -165,6 +169,45 @@ func _() {
}
+func f(x int, args ...int) {
+ f(0, args...)
+ f(1, args)
+ f(2, args[0])
+
+ // make sure syntactically legal code remains syntactically legal
+ f(3, 42 ...) // a blank must remain between 42 and ...
+ f(4, 42. ...)
+ f(5, 42....)
+ f(6, 42.0 ...)
+ f(7, 42.0...)
+ f(8, .42 ...)
+ f(9, .42...)
+ f(10, 42e0 ...)
+ f(11, 42e0...)
+
+ _ = 42 .x // a blank must remain between 42 and .x
+ _ = 42. .x
+ _ = 42..x
+ _ = 42.0 .x
+ _ = 42.0.x
+ _ = .42 .x
+ _ = .42.x
+ _ = 42e0 .x
+ _ = 42e0.x
+
+ // a blank must remain between the binary operator and the 2nd operand
+ _ = x/ *y
+ _ = x< -1
+ _ = x< <-1
+ _ = x+ +1
+ _ = x- -1
+ _ = x& &x
+ _ = x& ^x
+
+ _ = f(x/ *y, x< -1, x< <-1, x+ +1, x- -1, x& &x, x& ^x)
+}
+
+
func _() {
_ = T{}
_ = struct{}{}
@@ -172,13 +215,6 @@ func _() {
_ = [...]T{}
_ = []T{}
_ = map[int]T{}
-
- _ = (T){}
- _ = (struct{}){}
- _ = ([10]T){}
- _ = ([...]T){}
- _ = ([]T){}
- _ = (map[int]T){}
}
@@ -202,6 +238,8 @@ func _() {
`
_ = `foo
bar`
+ _ = `three spaces before the end of the line starting here:
+they must not be removed`
}
@@ -231,6 +269,27 @@ func _() {
func _() {
+ _ = [][]int {
+ []int{1},
+ []int{1, 2},
+ []int{1, 2, 3},
+ }
+ _ = [][]int {
+ {1},
+ []int{1, 2},
+ []int{1, 2, 3},
+ }
+ _ = [][]int {
+ {1},
+ {1, 2},
+ {1, 2, 3},
+ }
+ _ = [][]int {{1}, {1, 2}, {1, 2, 3}}
+}
+
+
+// various multi-line expressions
+func _() {
// do not add extra indentation to multi-line string lists
_ = "foo" + "bar"
_ = "foo" +
@@ -329,7 +388,6 @@ func _() {
2,
3,
)
- // TODO(gri) the cases below are not correct yet
f(1,
2,
3) // comment
diff --git a/src/pkg/go/printer/testdata/expressions.raw b/src/pkg/go/printer/testdata/expressions.raw
index dccc8d122..62be00cc3 100644
--- a/src/pkg/go/printer/testdata/expressions.raw
+++ b/src/pkg/go/printer/testdata/expressions.raw
@@ -31,6 +31,9 @@ func _() {
_ = 1 + a
_ = a + 1
_ = a + b + 1
+ _ = s[a]
+ _ = s[a:]
+ _ = s[:b]
_ = s[1:2]
_ = s[a:b]
_ = s[0:len(s)]
@@ -56,6 +59,7 @@ func _() {
_ = s[a : b-c]
_ = s[0:]
_ = s[a+b]
+ _ = s[:b-c]
_ = s[a+b:]
_ = a[a<<b+1]
_ = a[a<<b+1:]
@@ -165,6 +169,45 @@ func _() {
}
+func f(x int, args ...int) {
+ f(0, args...)
+ f(1, args)
+ f(2, args[0])
+
+ // make sure syntactically legal code remains syntactically legal
+ f(3, 42 ...) // a blank must remain between 42 and ...
+ f(4, 42....)
+ f(5, 42....)
+ f(6, 42.0...)
+ f(7, 42.0...)
+ f(8, .42...)
+ f(9, .42...)
+ f(10, 42e0...)
+ f(11, 42e0...)
+
+ _ = 42 .x // a blank must remain between 42 and .x
+ _ = 42..x
+ _ = 42..x
+ _ = 42.0.x
+ _ = 42.0.x
+ _ = .42.x
+ _ = .42.x
+ _ = 42e0.x
+ _ = 42e0.x
+
+ // a blank must remain between the binary operator and the 2nd operand
+ _ = x / *y
+ _ = x < -1
+ _ = x < <-1
+ _ = x + +1
+ _ = x - -1
+ _ = x & &x
+ _ = x & ^x
+
+ _ = f(x / *y, x < -1, x < <-1, x + +1, x - -1, x & &x, x & ^x)
+}
+
+
func _() {
_ = T{}
_ = struct{}{}
@@ -172,13 +215,6 @@ func _() {
_ = [...]T{}
_ = []T{}
_ = map[int]T{}
-
- _ = (T){}
- _ = (struct{}){}
- _ = ([10]T){}
- _ = ([...]T){}
- _ = ([]T){}
- _ = (map[int]T){}
}
@@ -206,6 +242,8 @@ func _() {
`
_ = `foo
bar`
+ _ = `three spaces before the end of the line starting here:
+they must not be removed`
}
@@ -239,6 +277,27 @@ func _() {
func _() {
+ _ = [][]int{
+ []int{1},
+ []int{1, 2},
+ []int{1, 2, 3},
+ }
+ _ = [][]int{
+ {1},
+ []int{1, 2},
+ []int{1, 2, 3},
+ }
+ _ = [][]int{
+ {1},
+ {1, 2},
+ {1, 2, 3},
+ }
+ _ = [][]int{{1}, {1, 2}, {1, 2, 3}}
+}
+
+
+// various multi-line expressions
+func _() {
// do not add extra indentation to multi-line string lists
_ = "foo" + "bar"
_ = "foo" +
@@ -336,7 +395,6 @@ func _() {
2,
3,
)
- // TODO(gri) the cases below are not correct yet
f(1,
2,
3) // comment
@@ -349,8 +407,7 @@ func _() {
3) // comment
f(1,
2,
- 3 // comment
- ,
+ 3, // comment
)
}
diff --git a/src/pkg/go/printer/testdata/statements.golden b/src/pkg/go/printer/testdata/statements.golden
index 73a3e1236..5eceb7dd5 100644
--- a/src/pkg/go/printer/testdata/statements.golden
+++ b/src/pkg/go/printer/testdata/statements.golden
@@ -209,6 +209,38 @@ func _() {
for _ = range (T1{T{42}}) {
}
+
+ if x == (T{42}[0]) {
+ }
+ if (x == T{42}[0]) {
+ }
+ if x == (T{42}[0]) {
+ }
+ if x == (T{42}[0]) {
+ }
+ if x == (T{42}[0]) {
+ }
+ if x == a+b*(T{42}[0]) {
+ }
+ if (x == a+b*T{42}[0]) {
+ }
+ if x == a+b*(T{42}[0]) {
+ }
+ if x == a+(b * (T{42}[0])) {
+ }
+ if x == a+b*(T{42}[0]) {
+ }
+ if (a + b*(T{42}[0])) == x {
+ }
+ if (a + b*(T{42}[0])) == x {
+ }
+
+ if struct{ x bool }{false}.x {
+ }
+ if (struct{ x bool }{false}.x) == false {
+ }
+ if struct{ x bool }{false}.x == false {
+ }
}
@@ -227,7 +259,8 @@ func _() {
var x = 1
// Each use(x) call below should have at most one empty line before and after.
-
+ // Known bug: The first use call may have more than one empty line before
+ // (see go/printer/nodes.go, func linebreak).
use(x)
@@ -336,3 +369,49 @@ AnOverlongLabel:
L:
_ = 0
}
+
+
+func _() {
+ for {
+ goto L
+ }
+L:
+
+ MoreCode()
+}
+
+
+func _() {
+ for {
+ goto L
+ }
+L: // A comment on the same line as the label, followed by a single empty line.
+ // Known bug: There may be more than one empty line before MoreCode()
+ // (see go/printer/nodes.go, func linebreak).
+
+
+ MoreCode()
+}
+
+
+func _() {
+ for {
+ goto L
+ }
+L:
+
+ // There should be a single empty line before this comment.
+ MoreCode()
+}
+
+
+func _() {
+ for {
+ goto AVeryLongLabelThatShouldNotAffectFormatting
+ }
+AVeryLongLabelThatShouldNotAffectFormatting:
+ // There should be a single empty line after this comment.
+
+ // There should be a single empty line before this comment.
+ MoreCode()
+}
diff --git a/src/pkg/go/printer/testdata/statements.input b/src/pkg/go/printer/testdata/statements.input
index 53f16c050..7819820ed 100644
--- a/src/pkg/go/printer/testdata/statements.input
+++ b/src/pkg/go/printer/testdata/statements.input
@@ -146,6 +146,23 @@ func _() {
switch ; ((((T{})))) {}
for _ = range (((T1{T{42}}))) {}
+
+ if x == (T{42}[0]) {}
+ if (x == T{42}[0]) {}
+ if (x == (T{42}[0])) {}
+ if (x == (((T{42}[0])))) {}
+ if (((x == (T{42}[0])))) {}
+ if x == a + b*(T{42}[0]) {}
+ if (x == a + b*T{42}[0]) {}
+ if (x == a + b*(T{42}[0])) {}
+ if (x == a + ((b * (T{42}[0])))) {}
+ if (((x == a + b * (T{42}[0])))) {}
+ if (((a + b * (T{42}[0])) == x)) {}
+ if (((a + b * (T{42}[0])))) == x {}
+
+ if (struct{x bool}{false}.x) {}
+ if (struct{x bool}{false}.x) == false {}
+ if (struct{x bool}{false}.x == false) {}
}
@@ -164,6 +181,8 @@ func _() {
var x = 1
// Each use(x) call below should have at most one empty line before and after.
+ // Known bug: The first use call may have more than one empty line before
+ // (see go/printer/nodes.go, func linebreak).
@@ -266,3 +285,54 @@ AnOverlongLabel:
L: _ = 0
}
+
+
+func _() {
+ for {
+ goto L
+ }
+L:
+
+ MoreCode()
+}
+
+
+func _() {
+ for {
+ goto L
+ }
+L: // A comment on the same line as the label, followed by a single empty line.
+ // Known bug: There may be more than one empty line before MoreCode()
+ // (see go/printer/nodes.go, func linebreak).
+
+
+
+
+ MoreCode()
+}
+
+
+func _() {
+ for {
+ goto L
+ }
+L:
+
+
+
+
+ // There should be a single empty line before this comment.
+ MoreCode()
+}
+
+
+func _() {
+ for {
+ goto AVeryLongLabelThatShouldNotAffectFormatting
+ }
+AVeryLongLabelThatShouldNotAffectFormatting:
+ // There should be a single empty line after this comment.
+
+ // There should be a single empty line before this comment.
+ MoreCode()
+}
diff --git a/src/pkg/go/scanner/Makefile b/src/pkg/go/scanner/Makefile
index 70d21a972..453faac00 100644
--- a/src/pkg/go/scanner/Makefile
+++ b/src/pkg/go/scanner/Makefile
@@ -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 ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=go/scanner
GOFILES=\
diff --git a/src/pkg/go/scanner/scanner.go b/src/pkg/go/scanner/scanner.go
index e5ac9d772..6ce846cd8 100644
--- a/src/pkg/go/scanner/scanner.go
+++ b/src/pkg/go/scanner/scanner.go
@@ -4,13 +4,25 @@
// A scanner for Go source text. Takes a []byte as source which can
// then be tokenized through repeated calls to the Scan function.
-// For a sample use of a scanner, see the implementation of Tokenize.
+// Typical use:
+//
+// var s Scanner
+// fset := token.NewFileSet() // position information is relative to fset
+// s.Init(fset, filename, src, nil /* no error handler */, 0)
+// for {
+// pos, tok, lit := s.Scan()
+// if tok == token.EOF {
+// break
+// }
+// // do something here with pos, tok, and lit
+// }
//
package scanner
import (
"bytes"
"go/token"
+ "path"
"strconv"
"unicode"
"utf8"
@@ -19,20 +31,22 @@ import (
// 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. For
-// a sample use, see the implementation of Tokenize.
+// structure but must be initialized via Init before use.
//
type Scanner struct {
// immutable state
+ file *token.File // source file handle
+ dir string // directory portion of file.Name()
src []byte // source
err ErrorHandler // error reporting; or nil
mode uint // scanning mode
// scanning state
- pos token.Position // previous reading position (position before ch)
- offset int // current reading offset (position after ch)
- ch int // one char look-ahead
- insertSemi bool // insert a semicolon before next newline
+ ch int // current character
+ offset int // character offset
+ rdOffset int // reading offset (position after current character)
+ lineOffset int // current line offset
+ insertSemi bool // insert a semicolon before next newline
// public state - ok to modify
ErrorCount int // number of errors encountered
@@ -43,29 +57,31 @@ type Scanner struct {
// S.ch < 0 means end-of-file.
//
func (S *Scanner) next() {
- if S.offset < len(S.src) {
- S.pos.Offset = S.offset
- S.pos.Column++
+ if S.rdOffset < len(S.src) {
+ S.offset = S.rdOffset
if S.ch == '\n' {
- // next character starts a new line
- S.pos.Line++
- S.pos.Column = 1
+ S.lineOffset = S.offset
+ S.file.AddLine(S.offset)
}
- r, w := int(S.src[S.offset]), 1
+ r, w := int(S.src[S.rdOffset]), 1
switch {
case r == 0:
- S.error(S.pos, "illegal character NUL")
+ S.error(S.offset, "illegal character NUL")
case r >= 0x80:
// not ASCII
- r, w = utf8.DecodeRune(S.src[S.offset:])
+ r, w = utf8.DecodeRune(S.src[S.rdOffset:])
if r == utf8.RuneError && w == 1 {
- S.error(S.pos, "illegal UTF-8 encoding")
+ S.error(S.offset, "illegal UTF-8 encoding")
}
}
- S.offset += w
+ S.rdOffset += w
S.ch = r
} else {
- S.pos.Offset = len(S.src)
+ S.offset = len(S.src)
+ if S.ch == '\n' {
+ S.lineOffset = S.offset
+ S.file.AddLine(S.offset)
+ }
S.ch = -1 // eof
}
}
@@ -80,24 +96,38 @@ const (
InsertSemis // automatically insert semicolons
)
+// TODO(gri) Would it be better to simply provide *token.File to Init
+// instead of fset, and filename, and then return the file?
+// It could cause an error/panic if the provided file.Size()
+// doesn't match len(src).
-// Init prepares the scanner S to tokenize the text src. Calls to Scan
-// will use the error handler err if they encounter a syntax error and
-// err is not nil. Also, for each error encountered, the Scanner field
-// ErrorCount is incremented by one. The filename parameter is used as
-// filename in the token.Position returned by Scan for each token. The
-// mode parameter determines how comments and illegal characters are
-// handled.
+// Init prepares the scanner S to tokenize the text src. It sets the
+// scanner at the beginning of the source text, adds a new file with
+// the given filename to the file set fset, and returns that file.
+//
+// Calls to Scan will use the error handler err if they encounter a
+// syntax error and err is not nil. Also, for each error encountered,
+// the Scanner field ErrorCount is incremented by one. The mode parameter
+// determines how comments, illegal characters, and semicolons are handled.
//
-func (S *Scanner) Init(filename string, src []byte, err ErrorHandler, mode uint) {
+func (S *Scanner) Init(fset *token.FileSet, filename string, src []byte, err ErrorHandler, mode uint) *token.File {
// Explicitly initialize all fields since a scanner may be reused.
+ S.file = fset.AddFile(filename, fset.Base(), len(src))
+ S.dir, _ = path.Split(filename)
S.src = src
S.err = err
S.mode = mode
- S.pos = token.Position{filename, 0, 1, 0}
+
+ S.ch = ' '
S.offset = 0
+ S.rdOffset = 0
+ S.lineOffset = 0
+ S.insertSemi = false
S.ErrorCount = 0
+
S.next()
+
+ return S.file
}
@@ -131,111 +161,109 @@ func charString(ch int) string {
}
-func (S *Scanner) error(pos token.Position, msg string) {
+func (S *Scanner) error(offs int, msg string) {
if S.err != nil {
- S.err.Error(pos, msg)
+ S.err.Error(S.file.Position(S.file.Pos(offs)), msg)
}
S.ErrorCount++
}
-func (S *Scanner) expect(ch int) {
- if S.ch != ch {
- S.error(S.pos, "expected "+charString(ch)+", found "+charString(S.ch))
+var prefix = []byte("//line ")
+
+func (S *Scanner) interpretLineComment(text []byte) {
+ if bytes.HasPrefix(text, prefix) {
+ // get filename and line number, if any
+ if i := bytes.Index(text, []byte{':'}); i > 0 {
+ if line, err := strconv.Atoi(string(text[i+1:])); err == nil && line > 0 {
+ // valid //line filename:line comment;
+ filename := path.Clean(string(text[len(prefix):i]))
+ if filename[0] != '/' {
+ // make filename relative to current directory
+ filename = path.Join(S.dir, filename)
+ }
+ // update scanner position
+ S.file.AddLineInfo(S.lineOffset, filename, line-1) // -1 since comment applies to next line
+ }
+ }
}
- S.next() // always make progress
}
-var prefix = []byte("line ")
-
-func (S *Scanner) scanComment(pos token.Position) {
- // first '/' already consumed
+func (S *Scanner) scanComment() {
+ // initial '/' already consumed; S.ch == '/' || S.ch == '*'
+ offs := S.offset - 1 // position of initial '/'
if S.ch == '/' {
//-style comment
- for S.ch >= 0 {
+ S.next()
+ for S.ch != '\n' && S.ch >= 0 {
S.next()
- if S.ch == '\n' {
- // '\n' is not part of the comment for purposes of scanning
- // (the comment ends on the same line where it started)
- if pos.Column == 1 {
- text := S.src[pos.Offset+2 : S.pos.Offset]
- if bytes.HasPrefix(text, prefix) {
- // comment starts at beginning of line with "//line ";
- // get filename and line number, if any
- i := bytes.Index(text, []byte{':'})
- if i >= 0 {
- if line, err := strconv.Atoi(string(text[i+1:])); err == nil && line > 0 {
- // valid //line filename:line comment;
- // update scanner position
- S.pos.Filename = string(text[len(prefix):i])
- S.pos.Line = line - 1 // -1 since the '\n' has not been consumed yet
- }
- }
- }
- }
- return
- }
}
+ if offs == S.lineOffset {
+ // comment starts at the beginning of the current line
+ S.interpretLineComment(S.src[offs:S.offset])
+ }
+ return
+ }
- } else {
- /*-style comment */
- S.expect('*')
- for S.ch >= 0 {
- ch := S.ch
+ /*-style comment */
+ S.next()
+ for S.ch >= 0 {
+ ch := S.ch
+ S.next()
+ if ch == '*' && S.ch == '/' {
S.next()
- if ch == '*' && S.ch == '/' {
- S.next()
- return
- }
+ return
}
}
- S.error(pos, "comment not terminated")
+ S.error(offs, "comment not terminated")
}
-func (S *Scanner) findNewline(pos token.Position) bool {
- // first '/' already consumed; assume S.ch == '/' || S.ch == '*'
+func (S *Scanner) findLineEnd() bool {
+ // initial '/' already consumed
+
+ defer func(offs int) {
+ // reset scanner state to where it was upon calling findLineEnd
+ S.ch = '/'
+ S.offset = offs
+ S.rdOffset = offs + 1
+ S.next() // consume initial '/' again
+ }(S.offset - 1)
- // read ahead until a newline or non-comment token is found
- newline := false
- for pos1 := pos; S.ch >= 0; {
+ // read ahead until a newline, EOF, or non-comment token is found
+ for S.ch == '/' || S.ch == '*' {
if S.ch == '/' {
//-style comment always contains a newline
- newline = true
- break
+ return true
}
- S.scanComment(pos1)
- if pos1.Line < S.pos.Line {
- /*-style comment contained a newline */
- newline = true
- break
+ /*-style comment: look for newline */
+ S.next()
+ for S.ch >= 0 {
+ ch := S.ch
+ if ch == '\n' {
+ return true
+ }
+ S.next()
+ if ch == '*' && S.ch == '/' {
+ S.next()
+ break
+ }
}
S.skipWhitespace() // S.insertSemi is set
- if S.ch == '\n' {
- newline = true
- break
+ if S.ch < 0 || S.ch == '\n' {
+ return true
}
if S.ch != '/' {
// non-comment token
- break
- }
- pos1 = S.pos
- S.next()
- if S.ch != '/' && S.ch != '*' {
- // non-comment token
- break
+ return false
}
+ S.next() // consume '/'
}
- // reset position to where it was upon calling findNewline
- S.pos = pos
- S.offset = pos.Offset + 1
- S.next()
-
- return newline
+ return false
}
@@ -250,11 +278,11 @@ func isDigit(ch int) bool {
func (S *Scanner) scanIdentifier() token.Token {
- pos := S.pos.Offset
+ offs := S.offset
for isLetter(S.ch) || isDigit(S.ch) {
S.next()
}
- return token.Lookup(S.src[pos:S.pos.Offset])
+ return token.Lookup(S.src[offs:S.offset])
}
@@ -278,7 +306,7 @@ func (S *Scanner) scanMantissa(base int) {
}
-func (S *Scanner) scanNumber(pos token.Position, seenDecimalPoint bool) token.Token {
+func (S *Scanner) scanNumber(seenDecimalPoint bool) token.Token {
// digitVal(S.ch) < 10
tok := token.INT
@@ -290,6 +318,7 @@ func (S *Scanner) scanNumber(pos token.Position, seenDecimalPoint bool) token.To
if S.ch == '0' {
// int or float
+ offs := S.offset
S.next()
if S.ch == 'x' || S.ch == 'X' {
// hexadecimal int
@@ -309,7 +338,7 @@ func (S *Scanner) scanNumber(pos token.Position, seenDecimalPoint bool) token.To
}
// octal int
if seenDecimalDigit {
- S.error(pos, "illegal octal number")
+ S.error(offs, "illegal octal number")
}
}
goto exit
@@ -346,7 +375,7 @@ exit:
func (S *Scanner) scanEscape(quote int) {
- pos := S.pos
+ offs := S.offset
var i, base, max uint32
switch S.ch {
@@ -366,28 +395,33 @@ func (S *Scanner) scanEscape(quote int) {
i, base, max = 8, 16, unicode.MaxRune
default:
S.next() // always make progress
- S.error(pos, "unknown escape sequence")
+ S.error(offs, "unknown escape sequence")
return
}
var x uint32
- for ; i > 0; i-- {
+ for ; i > 0 && S.ch != quote && S.ch >= 0; i-- {
d := uint32(digitVal(S.ch))
- if d > base {
- S.error(S.pos, "illegal character in escape sequence")
- return
+ if d >= base {
+ S.error(S.offset, "illegal character in escape sequence")
+ break
}
x = x*base + d
S.next()
}
+ // in case of an error, consume remaining chars
+ for ; i > 0 && S.ch != quote && S.ch >= 0; i-- {
+ S.next()
+ }
if x > max || 0xd800 <= x && x < 0xe000 {
- S.error(pos, "escape sequence is invalid Unicode code point")
+ S.error(offs, "escape sequence is invalid Unicode code point")
}
}
-func (S *Scanner) scanChar(pos token.Position) {
- // '\'' already consumed
+func (S *Scanner) scanChar() {
+ // '\'' opening already consumed
+ offs := S.offset - 1
n := 0
for S.ch != '\'' {
@@ -395,7 +429,7 @@ func (S *Scanner) scanChar(pos token.Position) {
n++
S.next()
if ch == '\n' || ch < 0 {
- S.error(pos, "character literal not terminated")
+ S.error(offs, "character literal not terminated")
n = 1
break
}
@@ -407,19 +441,20 @@ func (S *Scanner) scanChar(pos token.Position) {
S.next()
if n != 1 {
- S.error(pos, "illegal character literal")
+ S.error(offs, "illegal character literal")
}
}
-func (S *Scanner) scanString(pos token.Position) {
- // '"' already consumed
+func (S *Scanner) scanString() {
+ // '"' opening already consumed
+ offs := S.offset - 1
for S.ch != '"' {
ch := S.ch
S.next()
if ch == '\n' || ch < 0 {
- S.error(pos, "string not terminated")
+ S.error(offs, "string not terminated")
break
}
if ch == '\\' {
@@ -431,14 +466,15 @@ func (S *Scanner) scanString(pos token.Position) {
}
-func (S *Scanner) scanRawString(pos token.Position) {
- // '`' already consumed
+func (S *Scanner) scanRawString() {
+ // '`' opening already consumed
+ offs := S.offset - 1
for S.ch != '`' {
ch := S.ch
S.next()
if ch < 0 {
- S.error(pos, "string not terminated")
+ S.error(offs, "string not terminated")
break
}
}
@@ -499,12 +535,17 @@ func (S *Scanner) switch4(tok0, tok1 token.Token, ch2 int, tok2, tok3 token.Toke
}
-var semicolon = []byte{';'}
+var newline = []byte{'\n'}
// Scan scans the next token and returns the token position pos,
// the token tok, and the literal text lit corresponding to the
// token. The source end is indicated by token.EOF.
//
+// If the returned token is token.SEMICOLON, the corresponding
+// literal value is ";" if the semicolon was present in the source,
+// and "\n" if the semicolon was inserted because of a newline or
+// at EOF.
+//
// For more tolerant parsing, Scan will return a valid token if
// possible even if a syntax error was encountered. Thus, even
// if the resulting token sequence contains no illegal tokens,
@@ -512,13 +553,18 @@ var semicolon = []byte{';'}
// must check the scanner's ErrorCount or the number of calls
// of the error handler, if there was one installed.
//
-func (S *Scanner) Scan() (pos token.Position, tok token.Token, lit []byte) {
+// Scan adds line information to the file added to the file
+// set with Init. Token positions are relative to that file
+// and thus relative to the file set.
+//
+func (S *Scanner) Scan() (token.Pos, token.Token, []byte) {
scanAgain:
S.skipWhitespace()
// current token start
insertSemi := false
- pos, tok = S.pos, token.ILLEGAL
+ offs := S.offset
+ tok := token.ILLEGAL
// determine token value
switch ch := S.ch; {
@@ -530,36 +576,40 @@ scanAgain:
}
case digitVal(ch) < 10:
insertSemi = true
- tok = S.scanNumber(pos, false)
+ tok = S.scanNumber(false)
default:
S.next() // always make progress
switch ch {
case -1:
+ if S.insertSemi {
+ S.insertSemi = false // EOF consumed
+ return S.file.Pos(offs), token.SEMICOLON, newline
+ }
tok = token.EOF
case '\n':
// we only reach here if S.insertSemi was
// set in the first place and exited early
// from S.skipWhitespace()
S.insertSemi = false // newline consumed
- return pos, token.SEMICOLON, semicolon
+ return S.file.Pos(offs), token.SEMICOLON, newline
case '"':
insertSemi = true
tok = token.STRING
- S.scanString(pos)
+ S.scanString()
case '\'':
insertSemi = true
tok = token.CHAR
- S.scanChar(pos)
+ S.scanChar()
case '`':
insertSemi = true
tok = token.STRING
- S.scanRawString(pos)
+ S.scanRawString()
case ':':
tok = S.switch2(token.COLON, token.DEFINE)
case '.':
if digitVal(S.ch) < 10 {
insertSemi = true
- tok = S.scanNumber(pos, true)
+ tok = S.scanNumber(true)
} else if S.ch == '.' {
S.next()
if S.ch == '.' {
@@ -603,15 +653,15 @@ scanAgain:
case '/':
if S.ch == '/' || S.ch == '*' {
// comment
- if S.insertSemi && S.findNewline(pos) {
+ if S.insertSemi && S.findLineEnd() {
// reset position to the beginning of the comment
- S.pos = pos
- S.offset = pos.Offset + 1
S.ch = '/'
+ S.offset = offs
+ S.rdOffset = offs + 1
S.insertSemi = false // newline consumed
- return pos, token.SEMICOLON, semicolon
+ return S.file.Pos(offs), token.SEMICOLON, newline
}
- S.scanComment(pos)
+ S.scanComment()
if S.mode&ScanComments == 0 {
// skip comment
S.insertSemi = false // newline consumed
@@ -649,7 +699,7 @@ scanAgain:
tok = S.switch3(token.OR, token.OR_ASSIGN, '|', token.LOR)
default:
if S.mode&AllowIllegalChars == 0 {
- S.error(pos, "illegal character "+charString(ch))
+ S.error(offs, "illegal character "+charString(ch))
}
insertSemi = S.insertSemi // preserve insertSemi info
}
@@ -658,21 +708,5 @@ scanAgain:
if S.mode&InsertSemis != 0 {
S.insertSemi = insertSemi
}
- return pos, tok, S.src[pos.Offset:S.pos.Offset]
-}
-
-
-// Tokenize calls a function f with the token position, token value, and token
-// text for each token in the source src. The other parameters have the same
-// meaning as for the Init function. Tokenize keeps scanning until f returns
-// false (usually when the token value is token.EOF). The result is the number
-// of errors encountered.
-//
-func Tokenize(filename string, src []byte, err ErrorHandler, mode uint, f func(pos token.Position, tok token.Token, lit []byte) bool) int {
- var s Scanner
- s.Init(filename, src, err, mode)
- for f(s.Scan()) {
- // action happens in f
- }
- return s.ErrorCount
+ return S.file.Pos(offs), tok, S.src[offs:S.offset]
}
diff --git a/src/pkg/go/scanner/scanner_test.go b/src/pkg/go/scanner/scanner_test.go
index 002a81dd9..b1004f89d 100644
--- a/src/pkg/go/scanner/scanner_test.go
+++ b/src/pkg/go/scanner/scanner_test.go
@@ -11,6 +11,9 @@ import (
)
+var fset = token.NewFileSet()
+
+
const /* class */ (
special = iota
literal
@@ -41,136 +44,136 @@ type elt struct {
var tokens = [...]elt{
// Special tokens
- elt{token.COMMENT, "/* a comment */", special},
- elt{token.COMMENT, "// a comment \n", special},
+ {token.COMMENT, "/* a comment */", special},
+ {token.COMMENT, "// a comment \n", special},
// Identifiers and basic type literals
- elt{token.IDENT, "foobar", literal},
- elt{token.IDENT, "a۰۱۸", literal},
- elt{token.IDENT, "foo६४", literal},
- elt{token.IDENT, "bar9876", literal},
- elt{token.INT, "0", literal},
- elt{token.INT, "1", literal},
- elt{token.INT, "123456789012345678890", literal},
- elt{token.INT, "01234567", literal},
- elt{token.INT, "0xcafebabe", literal},
- elt{token.FLOAT, "0.", literal},
- elt{token.FLOAT, ".0", literal},
- elt{token.FLOAT, "3.14159265", literal},
- elt{token.FLOAT, "1e0", literal},
- elt{token.FLOAT, "1e+100", literal},
- elt{token.FLOAT, "1e-100", literal},
- elt{token.FLOAT, "2.71828e-1000", literal},
- elt{token.IMAG, "0i", literal},
- elt{token.IMAG, "1i", literal},
- elt{token.IMAG, "012345678901234567889i", literal},
- elt{token.IMAG, "123456789012345678890i", literal},
- elt{token.IMAG, "0.i", literal},
- elt{token.IMAG, ".0i", literal},
- elt{token.IMAG, "3.14159265i", literal},
- elt{token.IMAG, "1e0i", literal},
- elt{token.IMAG, "1e+100i", literal},
- elt{token.IMAG, "1e-100i", literal},
- elt{token.IMAG, "2.71828e-1000i", literal},
- elt{token.CHAR, "'a'", literal},
- elt{token.CHAR, "'\\000'", literal},
- elt{token.CHAR, "'\\xFF'", literal},
- elt{token.CHAR, "'\\uff16'", literal},
- elt{token.CHAR, "'\\U0000ff16'", literal},
- elt{token.STRING, "`foobar`", literal},
- elt{token.STRING, "`" + `foo
+ {token.IDENT, "foobar", literal},
+ {token.IDENT, "a۰۱۸", literal},
+ {token.IDENT, "foo६४", literal},
+ {token.IDENT, "bar9876", literal},
+ {token.INT, "0", literal},
+ {token.INT, "1", literal},
+ {token.INT, "123456789012345678890", literal},
+ {token.INT, "01234567", literal},
+ {token.INT, "0xcafebabe", literal},
+ {token.FLOAT, "0.", literal},
+ {token.FLOAT, ".0", literal},
+ {token.FLOAT, "3.14159265", literal},
+ {token.FLOAT, "1e0", literal},
+ {token.FLOAT, "1e+100", literal},
+ {token.FLOAT, "1e-100", literal},
+ {token.FLOAT, "2.71828e-1000", literal},
+ {token.IMAG, "0i", literal},
+ {token.IMAG, "1i", literal},
+ {token.IMAG, "012345678901234567889i", literal},
+ {token.IMAG, "123456789012345678890i", literal},
+ {token.IMAG, "0.i", literal},
+ {token.IMAG, ".0i", literal},
+ {token.IMAG, "3.14159265i", literal},
+ {token.IMAG, "1e0i", literal},
+ {token.IMAG, "1e+100i", literal},
+ {token.IMAG, "1e-100i", literal},
+ {token.IMAG, "2.71828e-1000i", literal},
+ {token.CHAR, "'a'", literal},
+ {token.CHAR, "'\\000'", literal},
+ {token.CHAR, "'\\xFF'", literal},
+ {token.CHAR, "'\\uff16'", literal},
+ {token.CHAR, "'\\U0000ff16'", literal},
+ {token.STRING, "`foobar`", literal},
+ {token.STRING, "`" + `foo
bar` +
"`",
literal,
},
// Operators and delimitors
- elt{token.ADD, "+", operator},
- elt{token.SUB, "-", operator},
- elt{token.MUL, "*", operator},
- elt{token.QUO, "/", operator},
- elt{token.REM, "%", operator},
-
- elt{token.AND, "&", operator},
- elt{token.OR, "|", operator},
- elt{token.XOR, "^", operator},
- elt{token.SHL, "<<", operator},
- elt{token.SHR, ">>", operator},
- elt{token.AND_NOT, "&^", operator},
-
- elt{token.ADD_ASSIGN, "+=", operator},
- elt{token.SUB_ASSIGN, "-=", operator},
- elt{token.MUL_ASSIGN, "*=", operator},
- elt{token.QUO_ASSIGN, "/=", operator},
- elt{token.REM_ASSIGN, "%=", operator},
-
- elt{token.AND_ASSIGN, "&=", operator},
- elt{token.OR_ASSIGN, "|=", operator},
- elt{token.XOR_ASSIGN, "^=", operator},
- elt{token.SHL_ASSIGN, "<<=", operator},
- elt{token.SHR_ASSIGN, ">>=", operator},
- elt{token.AND_NOT_ASSIGN, "&^=", operator},
-
- elt{token.LAND, "&&", operator},
- elt{token.LOR, "||", operator},
- elt{token.ARROW, "<-", operator},
- elt{token.INC, "++", operator},
- elt{token.DEC, "--", operator},
-
- elt{token.EQL, "==", operator},
- elt{token.LSS, "<", operator},
- elt{token.GTR, ">", operator},
- elt{token.ASSIGN, "=", operator},
- elt{token.NOT, "!", operator},
-
- elt{token.NEQ, "!=", operator},
- elt{token.LEQ, "<=", operator},
- elt{token.GEQ, ">=", operator},
- elt{token.DEFINE, ":=", operator},
- elt{token.ELLIPSIS, "...", operator},
-
- elt{token.LPAREN, "(", operator},
- elt{token.LBRACK, "[", operator},
- elt{token.LBRACE, "{", operator},
- elt{token.COMMA, ",", operator},
- elt{token.PERIOD, ".", operator},
-
- elt{token.RPAREN, ")", operator},
- elt{token.RBRACK, "]", operator},
- elt{token.RBRACE, "}", operator},
- elt{token.SEMICOLON, ";", operator},
- elt{token.COLON, ":", operator},
+ {token.ADD, "+", operator},
+ {token.SUB, "-", operator},
+ {token.MUL, "*", operator},
+ {token.QUO, "/", operator},
+ {token.REM, "%", operator},
+
+ {token.AND, "&", operator},
+ {token.OR, "|", operator},
+ {token.XOR, "^", operator},
+ {token.SHL, "<<", operator},
+ {token.SHR, ">>", operator},
+ {token.AND_NOT, "&^", operator},
+
+ {token.ADD_ASSIGN, "+=", operator},
+ {token.SUB_ASSIGN, "-=", operator},
+ {token.MUL_ASSIGN, "*=", operator},
+ {token.QUO_ASSIGN, "/=", operator},
+ {token.REM_ASSIGN, "%=", operator},
+
+ {token.AND_ASSIGN, "&=", operator},
+ {token.OR_ASSIGN, "|=", operator},
+ {token.XOR_ASSIGN, "^=", operator},
+ {token.SHL_ASSIGN, "<<=", operator},
+ {token.SHR_ASSIGN, ">>=", operator},
+ {token.AND_NOT_ASSIGN, "&^=", operator},
+
+ {token.LAND, "&&", operator},
+ {token.LOR, "||", operator},
+ {token.ARROW, "<-", operator},
+ {token.INC, "++", operator},
+ {token.DEC, "--", operator},
+
+ {token.EQL, "==", operator},
+ {token.LSS, "<", operator},
+ {token.GTR, ">", operator},
+ {token.ASSIGN, "=", operator},
+ {token.NOT, "!", operator},
+
+ {token.NEQ, "!=", operator},
+ {token.LEQ, "<=", operator},
+ {token.GEQ, ">=", operator},
+ {token.DEFINE, ":=", operator},
+ {token.ELLIPSIS, "...", operator},
+
+ {token.LPAREN, "(", operator},
+ {token.LBRACK, "[", operator},
+ {token.LBRACE, "{", operator},
+ {token.COMMA, ",", operator},
+ {token.PERIOD, ".", operator},
+
+ {token.RPAREN, ")", operator},
+ {token.RBRACK, "]", operator},
+ {token.RBRACE, "}", operator},
+ {token.SEMICOLON, ";", operator},
+ {token.COLON, ":", operator},
// Keywords
- elt{token.BREAK, "break", keyword},
- elt{token.CASE, "case", keyword},
- elt{token.CHAN, "chan", keyword},
- elt{token.CONST, "const", keyword},
- elt{token.CONTINUE, "continue", keyword},
-
- elt{token.DEFAULT, "default", keyword},
- elt{token.DEFER, "defer", keyword},
- elt{token.ELSE, "else", keyword},
- elt{token.FALLTHROUGH, "fallthrough", keyword},
- elt{token.FOR, "for", keyword},
-
- elt{token.FUNC, "func", keyword},
- elt{token.GO, "go", keyword},
- elt{token.GOTO, "goto", keyword},
- elt{token.IF, "if", keyword},
- elt{token.IMPORT, "import", keyword},
-
- elt{token.INTERFACE, "interface", keyword},
- elt{token.MAP, "map", keyword},
- elt{token.PACKAGE, "package", keyword},
- elt{token.RANGE, "range", keyword},
- elt{token.RETURN, "return", keyword},
-
- elt{token.SELECT, "select", keyword},
- elt{token.STRUCT, "struct", keyword},
- elt{token.SWITCH, "switch", keyword},
- elt{token.TYPE, "type", keyword},
- elt{token.VAR, "var", keyword},
+ {token.BREAK, "break", keyword},
+ {token.CASE, "case", keyword},
+ {token.CHAN, "chan", keyword},
+ {token.CONST, "const", keyword},
+ {token.CONTINUE, "continue", keyword},
+
+ {token.DEFAULT, "default", keyword},
+ {token.DEFER, "defer", keyword},
+ {token.ELSE, "else", keyword},
+ {token.FALLTHROUGH, "fallthrough", keyword},
+ {token.FOR, "for", keyword},
+
+ {token.FUNC, "func", keyword},
+ {token.GO, "go", keyword},
+ {token.GOTO, "goto", keyword},
+ {token.IF, "if", keyword},
+ {token.IMPORT, "import", keyword},
+
+ {token.INTERFACE, "interface", keyword},
+ {token.MAP, "map", keyword},
+ {token.PACKAGE, "package", keyword},
+ {token.RANGE, "range", keyword},
+ {token.RETURN, "return", keyword},
+
+ {token.SELECT, "select", keyword},
+ {token.STRUCT, "struct", keyword},
+ {token.SWITCH, "switch", keyword},
+ {token.TYPE, "type", keyword},
+ {token.VAR, "var", keyword},
}
@@ -196,18 +199,19 @@ func newlineCount(s string) int {
}
-func checkPos(t *testing.T, lit string, pos, expected token.Position) {
+func checkPos(t *testing.T, lit string, p token.Pos, expected token.Position) {
+ pos := fset.Position(p)
if pos.Filename != expected.Filename {
- t.Errorf("bad filename for %s: got %s, expected %s", lit, pos.Filename, expected.Filename)
+ t.Errorf("bad filename for %q: got %s, expected %s", lit, pos.Filename, expected.Filename)
}
if pos.Offset != expected.Offset {
- t.Errorf("bad position for %s: got %d, expected %d", lit, pos.Offset, expected.Offset)
+ t.Errorf("bad position for %q: got %d, expected %d", lit, pos.Offset, expected.Offset)
}
if pos.Line != expected.Line {
- t.Errorf("bad line for %s: got %d, expected %d", lit, pos.Line, expected.Line)
+ t.Errorf("bad line for %q: got %d, expected %d", lit, pos.Line, expected.Line)
}
if pos.Column != expected.Column {
- t.Errorf("bad column for %s: got %d, expected %d", lit, pos.Column, expected.Column)
+ t.Errorf("bad column for %q: got %d, expected %d", lit, pos.Column, expected.Column)
}
}
@@ -219,66 +223,76 @@ func TestScan(t *testing.T) {
for _, e := range tokens {
src += e.lit + whitespace
}
- src_linecount := newlineCount(src)
+ src_linecount := newlineCount(src) + 1
whitespace_linecount := newlineCount(whitespace)
// verify scan
+ var s Scanner
+ s.Init(fset, "", []byte(src), &testErrorHandler{t}, ScanComments)
index := 0
epos := token.Position{"", 0, 1, 1} // expected position
- nerrors := Tokenize("", []byte(src), &testErrorHandler{t}, ScanComments,
- func(pos token.Position, tok token.Token, litb []byte) bool {
- e := elt{token.EOF, "", special}
- if index < len(tokens) {
- e = tokens[index]
- }
- lit := string(litb)
- if tok == token.EOF {
- lit = "<EOF>"
- epos.Line = src_linecount
- epos.Column = 1
- }
- checkPos(t, lit, pos, epos)
- if tok != e.tok {
- t.Errorf("bad token for %q: got %s, expected %s", lit, tok.String(), e.tok.String())
- }
- if e.tok.IsLiteral() && lit != e.lit {
- t.Errorf("bad literal for %q: got %q, expected %q", lit, lit, e.lit)
- }
- if tokenclass(tok) != e.class {
- t.Errorf("bad class for %q: got %d, expected %d", lit, tokenclass(tok), e.class)
- }
- epos.Offset += len(lit) + len(whitespace)
- epos.Line += newlineCount(lit) + whitespace_linecount
- if tok == token.COMMENT && litb[1] == '/' {
- // correct for unaccounted '/n' in //-style comment
- epos.Offset++
- epos.Line++
- }
- index++
- return tok != token.EOF
- })
- if nerrors != 0 {
- t.Errorf("found %d errors", nerrors)
+ for {
+ pos, tok, litb := s.Scan()
+ e := elt{token.EOF, "", special}
+ if index < len(tokens) {
+ e = tokens[index]
+ }
+ lit := string(litb)
+ if tok == token.EOF {
+ lit = "<EOF>"
+ epos.Line = src_linecount
+ epos.Column = 1
+ }
+ checkPos(t, lit, pos, epos)
+ if tok != e.tok {
+ t.Errorf("bad token for %q: got %s, expected %s", lit, tok.String(), e.tok.String())
+ }
+ if e.tok.IsLiteral() && lit != e.lit {
+ t.Errorf("bad literal for %q: got %q, expected %q", lit, lit, e.lit)
+ }
+ if tokenclass(tok) != e.class {
+ t.Errorf("bad class for %q: got %d, expected %d", lit, tokenclass(tok), e.class)
+ }
+ epos.Offset += len(lit) + len(whitespace)
+ epos.Line += newlineCount(lit) + whitespace_linecount
+ if tok == token.COMMENT && litb[1] == '/' {
+ // correct for unaccounted '/n' in //-style comment
+ epos.Offset++
+ epos.Line++
+ }
+ index++
+ if tok == token.EOF {
+ break
+ }
+ }
+ if s.ErrorCount != 0 {
+ t.Errorf("found %d errors", s.ErrorCount)
}
}
func checkSemi(t *testing.T, line string, mode uint) {
var S Scanner
- S.Init("TestSemis", []byte(line), nil, mode)
+ file := S.Init(fset, "TestSemis", []byte(line), nil, mode)
pos, tok, lit := S.Scan()
for tok != token.EOF {
if tok == token.ILLEGAL {
+ // the illegal token literal indicates what
+ // kind of semicolon literal to expect
+ semiLit := "\n"
+ if lit[0] == '#' {
+ semiLit = ";"
+ }
// next token must be a semicolon
- offs := pos.Offset + 1
+ semiPos := file.Position(pos)
+ semiPos.Offset++
+ semiPos.Column++
pos, tok, lit = S.Scan()
if tok == token.SEMICOLON {
- if pos.Offset != offs {
- t.Errorf("bad offset for %q: got %d, expected %d", line, pos.Offset, offs)
- }
- if string(lit) != ";" {
- t.Errorf(`bad literal for %q: got %q, expected ";"`, line, lit)
+ if string(lit) != semiLit {
+ t.Errorf(`bad literal for %q: got %q, expected %q`, line, lit, semiLit)
}
+ checkPos(t, line, pos, semiPos)
} else {
t.Errorf("bad token for %q: got %s, expected ;", line, tok.String())
}
@@ -291,9 +305,10 @@ func checkSemi(t *testing.T, line string, mode uint) {
var lines = []string{
- // the $ character indicates where a semicolon is expected
+ // # indicates a semicolon present in the source
+ // $ indicates an automatically inserted semicolon
"",
- "$;",
+ "#;",
"foo$\n",
"123$\n",
"1.2$\n",
@@ -354,7 +369,7 @@ var lines = []string{
")$\n",
"]$\n",
"}$\n",
- "$;\n",
+ "#;\n",
":\n",
"break$\n",
@@ -388,57 +403,66 @@ var lines = []string{
"var\n",
"foo$//comment\n",
+ "foo$//comment",
"foo$/*comment*/\n",
"foo$/*\n*/",
"foo$/*comment*/ \n",
"foo$/*\n*/ ",
+
"foo $// comment\n",
+ "foo $// comment",
"foo $/*comment*/\n",
"foo $/*\n*/",
-
- "foo $/*comment*/\n",
+ "foo $/* */ /* \n */ bar$/**/\n",
"foo $/*0*/ /*1*/ /*2*/\n",
+
"foo $/*comment*/ \n",
"foo $/*0*/ /*1*/ /*2*/ \n",
- "foo $/**/ /*-------------*/ /*----\n*/bar $/* \n*/baa",
+ "foo $/**/ /*-------------*/ /*----\n*/bar $/* \n*/baa$\n",
+ "foo $/* an EOF terminates a line */",
+ "foo $/* an EOF terminates a line */ /*",
+ "foo $/* an EOF terminates a line */ //",
"package main$\n\nfunc main() {\n\tif {\n\t\treturn /* */ }$\n}$\n",
+ "package main$",
}
func TestSemis(t *testing.T) {
for _, line := range lines {
checkSemi(t, line, AllowIllegalChars|InsertSemis)
- }
- for _, line := range lines {
checkSemi(t, line, AllowIllegalChars|InsertSemis|ScanComments)
+
+ // if the input ended in newlines, the input must tokenize the
+ // same with or without those newlines
+ for i := len(line) - 1; i >= 0 && line[i] == '\n'; i-- {
+ checkSemi(t, line[0:i], AllowIllegalChars|InsertSemis)
+ checkSemi(t, line[0:i], AllowIllegalChars|InsertSemis|ScanComments)
+ }
}
}
-type seg struct {
+var segments = []struct {
srcline string // a line of source text
filename string // filename for current token
line int // line number for current token
-}
-
-
-var segments = []seg{
+}{
// exactly one token per line since the test consumes one token per segment
- seg{" line1", "TestLineComments", 1},
- seg{"\nline2", "TestLineComments", 2},
- seg{"\nline3 //line File1.go:100", "TestLineComments", 3}, // bad line comment, ignored
- seg{"\nline4", "TestLineComments", 4},
- seg{"\n//line File1.go:100\n line100", "File1.go", 100},
- seg{"\n//line File2.go:200\n line200", "File2.go", 200},
- seg{"\n//line :1\n line1", "", 1},
- seg{"\n//line foo:42\n line42", "foo", 42},
- seg{"\n //line foo:42\n line44", "foo", 44}, // bad line comment, ignored
- seg{"\n//line foo 42\n line46", "foo", 46}, // bad line comment, ignored
- seg{"\n//line foo:42 extra text\n line48", "foo", 48}, // bad line comment, ignored
- seg{"\n//line foo:42\n line42", "foo", 42},
- seg{"\n//line foo:42\n line42", "foo", 42},
- seg{"\n//line File1.go:100\n line100", "File1.go", 100},
+ {" line1", "dir/TestLineComments", 1},
+ {"\nline2", "dir/TestLineComments", 2},
+ {"\nline3 //line File1.go:100", "dir/TestLineComments", 3}, // bad line comment, ignored
+ {"\nline4", "dir/TestLineComments", 4},
+ {"\n//line File1.go:100\n line100", "dir/File1.go", 100},
+ {"\n//line File2.go:200\n line200", "dir/File2.go", 200},
+ {"\n//line :1\n line1", "dir", 1},
+ {"\n//line foo:42\n line42", "dir/foo", 42},
+ {"\n //line foo:42\n line44", "dir/foo", 44}, // bad line comment, ignored
+ {"\n//line foo 42\n line46", "dir/foo", 46}, // bad line comment, ignored
+ {"\n//line foo:42 extra text\n line48", "dir/foo", 48}, // bad line comment, ignored
+ {"\n//line /bar:42\n line42", "/bar", 42},
+ {"\n//line ./foo:42\n line42", "dir/foo", 42},
+ {"\n//line a/b/c/File1.go:100\n line100", "dir/a/b/c/File1.go", 100},
}
@@ -452,10 +476,11 @@ func TestLineComments(t *testing.T) {
// verify scan
var S Scanner
- S.Init("TestLineComments", []byte(src), nil, 0)
+ file := S.Init(fset, "dir/TestLineComments", []byte(src), nil, 0)
for _, s := range segments {
- pos, _, lit := S.Scan()
- checkPos(t, string(lit), pos, token.Position{s.filename, pos.Offset, s.line, pos.Column})
+ p, _, lit := S.Scan()
+ pos := file.Position(p)
+ checkPos(t, string(lit), p, token.Position{s.filename, pos.Offset, s.line, pos.Column})
}
if S.ErrorCount != 0 {
@@ -469,7 +494,11 @@ func TestInit(t *testing.T) {
var s Scanner
// 1st init
- s.Init("", []byte("if true { }"), nil, 0)
+ src1 := "if true { }"
+ f1 := s.Init(fset, "", []byte(src1), nil, 0)
+ if f1.Size() != len(src1) {
+ t.Errorf("bad file size: got %d, expected %d", f1.Size(), len(src1))
+ }
s.Scan() // if
s.Scan() // true
_, tok, _ := s.Scan() // {
@@ -478,7 +507,11 @@ func TestInit(t *testing.T) {
}
// 2nd init
- s.Init("", []byte("go true { ]"), nil, 0)
+ src2 := "go true { ]"
+ f2 := s.Init(fset, "", []byte(src2), nil, 0)
+ if f2.Size() != len(src2) {
+ t.Errorf("bad file size: got %d, expected %d", f2.Size(), len(src2))
+ }
_, tok, _ = s.Scan() // go
if tok != token.GO {
t.Errorf("bad token: got %s, expected %s", tok.String(), token.GO)
@@ -494,11 +527,11 @@ func TestIllegalChars(t *testing.T) {
var s Scanner
const src = "*?*$*@*"
- s.Init("", []byte(src), &testErrorHandler{t}, AllowIllegalChars)
+ file := s.Init(fset, "", []byte(src), &testErrorHandler{t}, AllowIllegalChars)
for offs, ch := range src {
pos, tok, lit := s.Scan()
- if pos.Offset != offs {
- t.Errorf("bad position for %s: got %d, expected %d", string(lit), pos.Offset, offs)
+ if poffs := file.Offset(pos); poffs != offs {
+ t.Errorf("bad position for %s: got %d, expected %d", string(lit), poffs, offs)
}
if tok == token.ILLEGAL && string(lit) != string(ch) {
t.Errorf("bad token: got %s, expected %s", string(lit), string(ch))
@@ -522,10 +555,13 @@ func TestStdErrorHander(t *testing.T) {
"@ @ @" // original file, line 1 again
v := new(ErrorVector)
- nerrors := Tokenize("File1", []byte(src), v, 0,
- func(pos token.Position, tok token.Token, litb []byte) bool {
- return tok != token.EOF
- })
+ var s Scanner
+ s.Init(fset, "File1", []byte(src), v, 0)
+ for {
+ if _, tok, _ := s.Scan(); tok == token.EOF {
+ break
+ }
+ }
list := v.GetErrorList(Raw)
if len(list) != 9 {
@@ -545,8 +581,8 @@ func TestStdErrorHander(t *testing.T) {
PrintError(os.Stderr, list)
}
- if v.ErrorCount() != nerrors {
- t.Errorf("found %d errors, expected %d", v.ErrorCount(), nerrors)
+ if v.ErrorCount() != s.ErrorCount {
+ t.Errorf("found %d errors, expected %d", v.ErrorCount(), s.ErrorCount)
}
}
@@ -568,7 +604,7 @@ func (h *errorCollector) Error(pos token.Position, msg string) {
func checkError(t *testing.T, src string, tok token.Token, pos int, err string) {
var s Scanner
var h errorCollector
- s.Init("", []byte(src), &h, ScanComments)
+ s.Init(fset, "", []byte(src), &h, ScanComments)
_, tok0, _ := s.Scan()
_, tok1, _ := s.Scan()
if tok0 != tok {
@@ -593,28 +629,34 @@ func checkError(t *testing.T, src string, tok token.Token, pos int, err string)
}
-type srcerr struct {
+var errors = []struct {
src string
tok token.Token
pos int
err string
-}
-
-var errors = []srcerr{
- srcerr{"\"\"", token.STRING, 0, ""},
- srcerr{"\"", token.STRING, 0, "string not terminated"},
- srcerr{"/**/", token.COMMENT, 0, ""},
- srcerr{"/*", token.COMMENT, 0, "comment not terminated"},
- srcerr{"//\n", token.COMMENT, 0, ""},
- srcerr{"//", token.COMMENT, 0, "comment not terminated"},
- srcerr{"077", token.INT, 0, ""},
- srcerr{"078.", token.FLOAT, 0, ""},
- srcerr{"07801234567.", token.FLOAT, 0, ""},
- srcerr{"078e0", token.FLOAT, 0, ""},
- srcerr{"078", token.INT, 0, "illegal octal number"},
- srcerr{"07800000009", token.INT, 0, "illegal octal number"},
- srcerr{"\"abc\x00def\"", token.STRING, 4, "illegal character NUL"},
- srcerr{"\"abc\x80def\"", token.STRING, 4, "illegal UTF-8 encoding"},
+}{
+ {`#`, token.ILLEGAL, 0, "illegal character '#' (U+23)"},
+ {`' '`, token.CHAR, 0, ""},
+ {`''`, token.CHAR, 0, "illegal character literal"},
+ {`'\8'`, token.CHAR, 2, "unknown escape sequence"},
+ {`'\08'`, token.CHAR, 3, "illegal character in escape sequence"},
+ {`'\x0g'`, token.CHAR, 4, "illegal character in escape sequence"},
+ {`'\Uffffffff'`, token.CHAR, 2, "escape sequence is invalid Unicode code point"},
+ {`'`, token.CHAR, 0, "character literal not terminated"},
+ {`""`, token.STRING, 0, ""},
+ {`"`, token.STRING, 0, "string not terminated"},
+ {"``", token.STRING, 0, ""},
+ {"`", token.STRING, 0, "string not terminated"},
+ {"/**/", token.COMMENT, 0, ""},
+ {"/*", token.COMMENT, 0, "comment not terminated"},
+ {"077", token.INT, 0, ""},
+ {"078.", token.FLOAT, 0, ""},
+ {"07801234567.", token.FLOAT, 0, ""},
+ {"078e0", token.FLOAT, 0, ""},
+ {"078", token.INT, 0, "illegal octal number"},
+ {"07800000009", token.INT, 0, "illegal octal number"},
+ {"\"abc\x00def\"", token.STRING, 4, "illegal character NUL"},
+ {"\"abc\x80def\"", token.STRING, 4, "illegal UTF-8 encoding"},
}
diff --git a/src/pkg/go/token/Makefile b/src/pkg/go/token/Makefile
index 629196c5d..4a4e64dc8 100644
--- a/src/pkg/go/token/Makefile
+++ b/src/pkg/go/token/Makefile
@@ -2,10 +2,11 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../../Make.$(GOARCH)
+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
new file mode 100644
index 000000000..0044a0ed7
--- /dev/null
+++ b/src/pkg/go/token/position.go
@@ -0,0 +1,409 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// TODO(gri) consider making this a separate package outside the go directory.
+
+package token
+
+import (
+ "fmt"
+ "sort"
+ "sync"
+)
+
+
+// Position describes an arbitrary source position
+// including the file, line, and column location.
+// A Position is valid if the line number is > 0.
+//
+type Position struct {
+ Filename string // filename, if any
+ Offset int // offset, starting at 0
+ Line int // line number, starting at 1
+ Column int // column number, starting at 1 (character count)
+}
+
+
+// IsValid returns true if the position is valid.
+func (pos *Position) IsValid() bool { return pos.Line > 0 }
+
+
+// String returns a string in one of several forms:
+//
+// file:line:column valid position with file name
+// line:column valid position without file name
+// file invalid position with file name
+// - invalid position without file name
+//
+func (pos Position) String() string {
+ s := pos.Filename
+ if pos.IsValid() {
+ if s != "" {
+ s += ":"
+ }
+ s += fmt.Sprintf("%d:%d", pos.Line, pos.Column)
+ }
+ if s == "" {
+ s = "-"
+ }
+ return s
+}
+
+
+// Pos is a compact encoding of a source position within a file set.
+// It can be converted into a Position for a more convenient, but much
+// larger, representation.
+//
+// The Pos value for a given file is a number in the range [base, base+size],
+// where base and size are specified when adding the file to the file set via
+// AddFile.
+//
+// To create the Pos value for a specific source offset, first add
+// the respective file to the current file set (via FileSet.AddFile)
+// and then call File.Pos(offset) for that file. Given a Pos value p
+// for a specific file set fset, the corresponding Position value is
+// obtained by calling fset.Position(p).
+//
+// Pos values can be compared directly with the usual comparison operators:
+// If two Pos values p and q are in the same file, comparing p and q is
+// equivalent to comparing the respective source file offsets. If p and q
+// are in different files, p < q is true if the file implied by p was added
+// to the respective file set before the file implied by q.
+//
+type Pos int
+
+
+// The zero value for Pos is NoPos; there is no file and line information
+// associated with it, and NoPos().IsValid() is false. NoPos is always
+// smaller than any other Pos value. The corresponding Position value
+// for NoPos is the zero value for Position.
+//
+const NoPos Pos = 0
+
+
+// IsValid returns true if the position is valid.
+func (p Pos) IsValid() bool {
+ return p != NoPos
+}
+
+
+func searchFiles(a []*File, x int) int {
+ return sort.Search(len(a), func(i int) bool { return a[i].base > x }) - 1
+}
+
+
+func (s *FileSet) file(p Pos) *File {
+ if i := searchFiles(s.files, int(p)); i >= 0 {
+ f := s.files[i]
+ // f.base <= int(p) by definition of searchFiles
+ if int(p) <= f.base+f.size {
+ return f
+ }
+ }
+ return nil
+}
+
+
+// File returns the file which contains the position p.
+// If no such file is found (for instance for p == NoPos),
+// the result is nil.
+//
+func (s *FileSet) File(p Pos) (f *File) {
+ if p != NoPos {
+ s.mutex.RLock()
+ f = s.file(p)
+ s.mutex.RUnlock()
+ }
+ return
+}
+
+
+func (f *File) position(p Pos) (pos Position) {
+ offset := int(p) - f.base
+ pos.Offset = offset
+ pos.Filename, pos.Line, pos.Column = f.info(offset)
+ return
+}
+
+
+// Position converts a Pos in the fileset into a general Position.
+func (s *FileSet) Position(p Pos) (pos Position) {
+ if p != NoPos {
+ // TODO(gri) consider optimizing the case where p
+ // is in the last file addded, or perhaps
+ // looked at - will eliminate one level
+ // of search
+ s.mutex.RLock()
+ if f := s.file(p); f != nil {
+ pos = f.position(p)
+ }
+ s.mutex.RUnlock()
+ }
+ return
+}
+
+
+type lineInfo struct {
+ offset int
+ filename string
+ line int
+}
+
+
+// AddLineInfo adds alternative file and line number information for
+// a given file offset. The offset must be larger than the offset for
+// the previously added alternative line info and not larger than the
+// file size; otherwise the information is ignored.
+//
+// AddLineInfo is typically used to register alternative position
+// information for //line filename:line comments in source files.
+//
+func (f *File) AddLineInfo(offset int, filename string, line int) {
+ f.set.mutex.Lock()
+ if i := len(f.infos); i == 0 || f.infos[i-1].offset < offset && offset <= f.size {
+ f.infos = append(f.infos, lineInfo{offset, filename, line})
+ }
+ f.set.mutex.Unlock()
+}
+
+
+// A File is a handle for a file belonging to a FileSet.
+// A File has a name, size, and line offset table.
+//
+type File struct {
+ set *FileSet
+ name string // file name as provided to AddFile
+ base int // Pos value range for this file is [base...base+size]
+ size int // file size as provided to AddFile
+
+ // lines and infos are protected by set.mutex
+ lines []int
+ infos []lineInfo
+}
+
+
+// Name returns the file name of file f as registered with AddFile.
+func (f *File) Name() string {
+ return f.name
+}
+
+
+// Base returns the base offset of file f as registered with AddFile.
+func (f *File) Base() int {
+ return f.base
+}
+
+
+// Size returns the size of file f as registered with AddFile.
+func (f *File) Size() int {
+ return f.size
+}
+
+
+// LineCount returns the number of lines in file f.
+func (f *File) LineCount() int {
+ f.set.mutex.RLock()
+ n := len(f.lines)
+ f.set.mutex.RUnlock()
+ return n
+}
+
+
+// AddLine adds the line offset for a new line.
+// The line offset must be larger than the offset for the previous line
+// and not larger than the file size; otherwise the line offset is ignored.
+//
+func (f *File) AddLine(offset int) {
+ f.set.mutex.Lock()
+ if i := len(f.lines); (i == 0 || f.lines[i-1] < offset) && offset <= f.size {
+ f.lines = append(f.lines, offset)
+ }
+ f.set.mutex.Unlock()
+}
+
+
+// SetLines sets all line offsets for a file and returns true if successful.
+// Each line offset must be larger than the offset for the previous line
+// and not larger than the file size; otherwise the SetLines fails and returns
+// false.
+//
+func (f *File) SetLines(lines []int) bool {
+ // verify validity of lines table
+ size := f.size
+ for i, offset := range lines {
+ if i > 0 && offset <= lines[i-1] || size < offset {
+ return false
+ }
+ }
+
+ // set lines table
+ f.set.mutex.Lock()
+ f.lines = lines
+ f.set.mutex.Unlock()
+ return true
+}
+
+
+// Pos returns the Pos value for the given file offset;
+// the offset must be <= f.Size().
+// f.Pos(f.Offset(p)) == p.
+//
+func (f *File) Pos(offset int) Pos {
+ if offset > f.size {
+ panic("illegal file offset")
+ }
+ return Pos(f.base + offset)
+}
+
+
+// Offset returns the offset for the given file position p;
+// p must be a valid Pos value in that file.
+// f.Offset(f.Pos(offset)) == offset.
+//
+func (f *File) Offset(p Pos) int {
+ if int(p) < f.base || int(p) > f.base+f.size {
+ panic("illegal Pos value")
+ }
+ return int(p) - f.base
+}
+
+
+// Line returns the line number for the given file position p;
+// p must be a Pos value in that file or NoPos.
+//
+func (f *File) Line(p Pos) int {
+ // TODO(gri) this can be implemented much more efficiently
+ return f.Position(p).Line
+}
+
+
+// Position returns the Position value for the given file position p;
+// p must be a Pos value in that file or NoPos.
+//
+func (f *File) Position(p Pos) (pos Position) {
+ if p != NoPos {
+ if int(p) < f.base || int(p) > f.base+f.size {
+ panic("illegal Pos value")
+ }
+ pos = f.position(p)
+ }
+ return
+}
+
+
+func searchUints(a []int, x int) int {
+ return sort.Search(len(a), func(i int) bool { return a[i] > x }) - 1
+}
+
+
+func searchLineInfos(a []lineInfo, x int) int {
+ return sort.Search(len(a), func(i int) bool { return a[i].offset > x }) - 1
+}
+
+
+// info returns the file name, line, and column number for a file offset.
+func (f *File) info(offset int) (filename string, line, column int) {
+ filename = f.name
+ if i := searchUints(f.lines, offset); i >= 0 {
+ line, column = i+1, offset-f.lines[i]+1
+ }
+ if i := searchLineInfos(f.infos, offset); i >= 0 {
+ alt := &f.infos[i]
+ filename = alt.filename
+ if i := searchUints(f.lines, alt.offset); i >= 0 {
+ line += alt.line - i - 1
+ }
+ }
+ return
+}
+
+
+// A FileSet represents a set of source files.
+// Methods of file sets are synchronized; multiple goroutines
+// may invoke them concurrently.
+//
+type FileSet struct {
+ mutex sync.RWMutex // protects the file set
+ base int // base offset for the next file
+ files []*File // list of files in the order added to the set
+ index map[*File]int // file -> files index for quick lookup
+}
+
+
+// NewFileSet creates a new file set.
+func NewFileSet() *FileSet {
+ s := new(FileSet)
+ s.base = 1 // 0 == NoPos
+ s.index = make(map[*File]int)
+ return s
+}
+
+
+// Base returns the minimum base offset that must be provided to
+// AddFile when adding the next file.
+//
+func (s *FileSet) Base() int {
+ s.mutex.RLock()
+ b := s.base
+ s.mutex.RUnlock()
+ return b
+
+}
+
+
+// AddFile adds a new file with a given filename, base offset, and file size
+// to the file set s and returns the file. Multiple files may have the same
+// name. The base offset must not be smaller than the FileSet's Base(), and
+// size must not be negative.
+//
+// Adding the file will set the file set's Base() value to base + size + 1
+// as the minimum base value for the next file. The following relationship
+// exists between a Pos value p for a given file offset offs:
+//
+// int(p) = base + offs
+//
+// with offs in the range [0, size] and thus p in the range [base, base+size].
+// For convenience, File.Pos may be used to create file-specific position
+// values from a file offset.
+//
+func (s *FileSet) AddFile(filename string, base, size int) *File {
+ s.mutex.Lock()
+ defer s.mutex.Unlock()
+ if base < s.base || size < 0 {
+ panic("illegal base or size")
+ }
+ // base >= s.base && size >= 0
+ f := &File{s, filename, base, size, []int{0}, nil}
+ base += size + 1 // +1 because EOF also has a position
+ if base < 0 {
+ panic("token.Pos offset overflow (> 2G of source code in file set)")
+ }
+ // add the file to the file set
+ s.base = base
+ s.index[f] = len(s.files)
+ s.files = append(s.files, f)
+ return f
+}
+
+
+// Files returns the files added to the file set.
+func (s *FileSet) Files() <-chan *File {
+ ch := make(chan *File)
+ go func() {
+ for i := 0; ; i++ {
+ var f *File
+ s.mutex.RLock()
+ if i < len(s.files) {
+ f = s.files[i]
+ }
+ s.mutex.RUnlock()
+ if f == nil {
+ break
+ }
+ ch <- f
+ }
+ close(ch)
+ }()
+ return ch
+}
diff --git a/src/pkg/go/token/position_test.go b/src/pkg/go/token/position_test.go
new file mode 100644
index 000000000..1cffcc3c2
--- /dev/null
+++ b/src/pkg/go/token/position_test.go
@@ -0,0 +1,158 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package token
+
+import (
+ "fmt"
+ "testing"
+)
+
+
+func checkPos(t *testing.T, msg string, p, q Position) {
+ if p.Filename != q.Filename {
+ t.Errorf("%s: expected filename = %q; got %q", msg, q.Filename, p.Filename)
+ }
+ if p.Offset != q.Offset {
+ t.Errorf("%s: expected offset = %d; got %d", msg, q.Offset, p.Offset)
+ }
+ if p.Line != q.Line {
+ t.Errorf("%s: expected line = %d; got %d", msg, q.Line, p.Line)
+ }
+ if p.Column != q.Column {
+ t.Errorf("%s: expected column = %d; got %d", msg, q.Column, p.Column)
+ }
+}
+
+
+func TestNoPos(t *testing.T) {
+ if NoPos.IsValid() {
+ t.Errorf("NoPos should not be valid")
+ }
+ var fset *FileSet
+ checkPos(t, "nil NoPos", fset.Position(NoPos), Position{})
+ fset = NewFileSet()
+ checkPos(t, "fset NoPos", fset.Position(NoPos), Position{})
+}
+
+
+var tests = []struct {
+ filename string
+ size int
+ lines []int
+}{
+ {"a", 0, []int{}},
+ {"b", 5, []int{0}},
+ {"c", 10, []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}},
+ {"d", 100, []int{0, 5, 10, 20, 30, 70, 71, 72, 80, 85, 90, 99}},
+ {"e", 777, []int{0, 80, 100, 120, 130, 180, 267, 455, 500, 567, 620}},
+}
+
+
+func linecol(lines []int, offs int) (int, int) {
+ prevLineOffs := 0
+ for line, lineOffs := range lines {
+ if offs < lineOffs {
+ return line, offs - prevLineOffs + 1
+ }
+ prevLineOffs = lineOffs
+ }
+ return len(lines), offs - prevLineOffs + 1
+}
+
+
+func verifyPositions(t *testing.T, fset *FileSet, f *File, lines []int) {
+ for offs := 0; offs < f.Size(); offs++ {
+ p := f.Pos(offs)
+ offs2 := f.Offset(p)
+ if offs2 != offs {
+ t.Errorf("%s, Offset: expected offset %d; got %d", f.Name(), offs, offs2)
+ }
+ line, col := linecol(lines, offs)
+ msg := fmt.Sprintf("%s (offs = %d, p = %d)", f.Name(), offs, p)
+ checkPos(t, msg, f.Position(f.Pos(offs)), Position{f.Name(), offs, line, col})
+ checkPos(t, msg, fset.Position(p), Position{f.Name(), offs, line, col})
+ }
+}
+
+
+func TestPositions(t *testing.T) {
+ const delta = 7 // a non-zero base offset increment
+ fset := NewFileSet()
+ for _, test := range tests {
+ // add file and verify name and size
+ f := fset.AddFile(test.filename, fset.Base()+delta, test.size)
+ if f.Name() != test.filename {
+ t.Errorf("expected filename %q; got %q", test.filename, f.Name())
+ }
+ if f.Size() != test.size {
+ t.Errorf("%s: expected file size %d; got %d", f.Name(), test.size, f.Size())
+ }
+ if fset.File(f.Pos(0)) != f {
+ t.Errorf("%s: f.Pos(0) was not found in f", f.Name())
+ }
+
+ // add lines individually and verify all positions
+ for i, offset := range test.lines {
+ f.AddLine(offset)
+ if f.LineCount() != i+1 {
+ t.Errorf("%s, AddLine: expected line count %d; got %d", f.Name(), i+1, f.LineCount())
+ }
+ // adding the same offset again should be ignored
+ f.AddLine(offset)
+ if f.LineCount() != i+1 {
+ t.Errorf("%s, AddLine: expected unchanged line count %d; got %d", f.Name(), i+1, f.LineCount())
+ }
+ verifyPositions(t, fset, f, test.lines[0:i+1])
+ }
+
+ // add lines at once and verify all positions
+ ok := f.SetLines(test.lines)
+ if !ok {
+ t.Errorf("%s: SetLines failed", f.Name())
+ }
+ if f.LineCount() != len(test.lines) {
+ t.Errorf("%s, SetLines: expected line count %d; got %d", f.Name(), len(test.lines), f.LineCount())
+ }
+ verifyPositions(t, fset, f, test.lines)
+ }
+}
+
+
+func TestLineInfo(t *testing.T) {
+ fset := NewFileSet()
+ f := fset.AddFile("foo", fset.Base(), 500)
+ lines := []int{0, 42, 77, 100, 210, 220, 277, 300, 333, 401}
+ // add lines individually and provide alternative line information
+ for _, offs := range lines {
+ f.AddLine(offs)
+ f.AddLineInfo(offs, "bar", 42)
+ }
+ // verify positions for all offsets
+ for offs := 0; offs <= f.Size(); offs++ {
+ p := f.Pos(offs)
+ _, col := linecol(lines, offs)
+ msg := fmt.Sprintf("%s (offs = %d, p = %d)", f.Name(), offs, p)
+ checkPos(t, msg, f.Position(f.Pos(offs)), Position{"bar", offs, 42, col})
+ checkPos(t, msg, fset.Position(p), Position{"bar", offs, 42, col})
+ }
+}
+
+
+func TestFiles(t *testing.T) {
+ fset := NewFileSet()
+ for i, test := range tests {
+ fset.AddFile(test.filename, fset.Base(), test.size)
+ j := 0
+ for g := range fset.Files() {
+ if g.Name() != tests[j].filename {
+ t.Errorf("expected filename = %s; got %s", tests[j].filename, g.Name())
+ }
+ j++
+ }
+ if j != i+1 {
+ t.Errorf("expected %d files; got %d", i+1, j)
+ }
+ }
+}
diff --git a/src/pkg/go/token/token.go b/src/pkg/go/token/token.go
index 70c2501e9..1bd81c1b1 100644
--- a/src/pkg/go/token/token.go
+++ b/src/pkg/go/token/token.go
@@ -8,10 +8,7 @@
//
package token
-import (
- "fmt"
- "strconv"
-)
+import "strconv"
// Token is the set of lexical tokens of the Go programming language.
@@ -321,39 +318,3 @@ func (tok Token) IsOperator() bool { return operator_beg < tok && tok < operator
// returns false otherwise.
//
func (tok Token) IsKeyword() bool { return keyword_beg < tok && tok < keyword_end }
-
-
-// Token source positions are represented by a Position value.
-// A Position is valid if the line number is > 0.
-//
-type Position struct {
- Filename string // filename, if any
- Offset int // byte offset, starting at 0
- Line int // line number, starting at 1
- Column int // column number, starting at 1 (character count)
-}
-
-
-// Pos is an accessor method for anonymous Position fields.
-// It returns its receiver.
-//
-func (pos *Position) Pos() Position { return *pos }
-
-
-// IsValid returns true if the position is valid.
-func (pos *Position) IsValid() bool { return pos.Line > 0 }
-
-
-func (pos Position) String() string {
- s := pos.Filename
- if pos.IsValid() {
- if s != "" {
- s += ":"
- }
- s += fmt.Sprintf("%d:%d", pos.Line, pos.Column)
- }
- if s == "" {
- s = "???"
- }
- return s
-}
diff --git a/src/pkg/go/typechecker/Makefile b/src/pkg/go/typechecker/Makefile
new file mode 100644
index 000000000..62b2aa7fe
--- /dev/null
+++ b/src/pkg/go/typechecker/Makefile
@@ -0,0 +1,13 @@
+# Copyright 2010 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=go/typechecker
+GOFILES=\
+ scope.go\
+ typechecker.go\
+ universe.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/go/typechecker/scope.go b/src/pkg/go/typechecker/scope.go
new file mode 100644
index 000000000..114c93ea8
--- /dev/null
+++ b/src/pkg/go/typechecker/scope.go
@@ -0,0 +1,119 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements scope support functions.
+
+package typechecker
+
+import (
+ "fmt"
+ "go/ast"
+ "go/token"
+)
+
+
+func (tc *typechecker) openScope() *ast.Scope {
+ tc.topScope = ast.NewScope(tc.topScope)
+ return tc.topScope
+}
+
+
+func (tc *typechecker) closeScope() {
+ tc.topScope = tc.topScope.Outer
+}
+
+
+// objPos computes the source position of the declaration of an object name.
+// Only required for error reporting, so doesn't have to be fast.
+func objPos(obj *ast.Object) (pos token.Pos) {
+ switch d := obj.Decl.(type) {
+ case *ast.Field:
+ for _, n := range d.Names {
+ if n.Name == obj.Name {
+ return n.Pos()
+ }
+ }
+ case *ast.ValueSpec:
+ for _, n := range d.Names {
+ if n.Name == obj.Name {
+ return n.Pos()
+ }
+ }
+ case *ast.TypeSpec:
+ return d.Name.Pos()
+ case *ast.FuncDecl:
+ return d.Name.Pos()
+ }
+ if debug {
+ fmt.Printf("decl = %T\n", obj.Decl)
+ }
+ panic("unreachable")
+}
+
+
+// declInScope declares an object of a given kind and name in scope and sets the object's Decl and N fields.
+// It returns the newly allocated object. If an object with the same name already exists in scope, an error
+// is reported and the object is not inserted.
+// (Objects with _ name are always inserted into a scope without errors, but they cannot be found.)
+func (tc *typechecker) declInScope(scope *ast.Scope, kind ast.Kind, name *ast.Ident, decl interface{}, n int) *ast.Object {
+ obj := ast.NewObj(kind, name.Name)
+ obj.Decl = decl
+ obj.N = n
+ name.Obj = obj
+ if alt := scope.Insert(obj); alt != obj {
+ tc.Errorf(name.Pos(), "%s already declared at %s", name.Name, objPos(alt))
+ }
+ return obj
+}
+
+
+// decl is the same as declInScope(tc.topScope, ...)
+func (tc *typechecker) decl(kind ast.Kind, name *ast.Ident, decl interface{}, n int) *ast.Object {
+ return tc.declInScope(tc.topScope, kind, name, decl, n)
+}
+
+
+// find returns the object with the given name if visible in the current scope hierarchy.
+// If no such object is found, an error is reported and a bad object is returned instead.
+func (tc *typechecker) find(name *ast.Ident) (obj *ast.Object) {
+ for s := tc.topScope; s != nil && obj == nil; s = s.Outer {
+ obj = s.Lookup(name.Name)
+ }
+ if obj == nil {
+ tc.Errorf(name.Pos(), "%s not declared", name.Name)
+ obj = ast.NewObj(ast.Bad, name.Name)
+ }
+ name.Obj = obj
+ return
+}
+
+
+// findField returns the object with the given name if visible in the type's scope.
+// If no such object is found, an error is reported and a bad object is returned instead.
+func (tc *typechecker) findField(typ *ast.Type, name *ast.Ident) (obj *ast.Object) {
+ // TODO(gri) This is simplistic at the moment and ignores anonymous fields.
+ obj = typ.Scope.Lookup(name.Name)
+ if obj == nil {
+ tc.Errorf(name.Pos(), "%s not declared", name.Name)
+ obj = ast.NewObj(ast.Bad, name.Name)
+ }
+ return
+}
+
+
+// printScope prints the objects in a scope.
+func printScope(scope *ast.Scope) {
+ fmt.Printf("scope %p {", scope)
+ if scope != nil && len(scope.Objects) > 0 {
+ fmt.Println()
+ for _, obj := range scope.Objects {
+ form := "void"
+ if obj.Type != nil {
+ form = obj.Type.Form.String()
+ }
+ fmt.Printf("\t%s\t%s\n", obj.Name, form)
+ }
+ }
+ fmt.Printf("}\n")
+}
diff --git a/src/pkg/go/typechecker/testdata/test0.go b/src/pkg/go/typechecker/testdata/test0.go
new file mode 100644
index 000000000..4e317f214
--- /dev/null
+++ b/src/pkg/go/typechecker/testdata/test0.go
@@ -0,0 +1,94 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// type declarations
+
+package P0
+
+type (
+ B bool
+ I int32
+ A [10]P
+ T struct {
+ x, y P
+ }
+ P *T
+ R *R
+ F func(A) I
+ Y interface {
+ f(A) I
+ }
+ S []P
+ M map[I]F
+ C chan<- I
+)
+
+type (
+ a/* ERROR "illegal cycle" */ a
+ a/* ERROR "already declared" */ int
+
+ b/* ERROR "illegal cycle" */ c
+ c d
+ d e
+ e b /* ERROR "not a type" */
+
+ t *t
+
+ U V
+ V W
+ W *U
+
+ P1 *S2
+ P2 P1
+
+ S1 struct {
+ a, b, c int
+ u, v, a/* ERROR "already declared" */ float
+ }
+ S2/* ERROR "illegal cycle" */ struct {
+ x S2
+ }
+
+ L1 []L1
+ L2 []int
+
+ A1 [10]int
+ A2/* ERROR "illegal cycle" */ [10]A2
+ A3/* ERROR "illegal cycle" */ [10]struct {
+ x A4
+ }
+ A4 [10]A3
+
+ F1 func()
+ F2 func(x, y, z float)
+ F3 func(x, y, x /* ERROR "already declared" */ float)
+ F4 func() (x, y, x /* ERROR "already declared" */ float)
+ F5 func(x int) (x /* ERROR "already declared" */ float)
+
+ I1 interface{}
+ I2 interface {
+ m1()
+ }
+ I3 interface {
+ m1()
+ m1 /* ERROR "already declared" */ ()
+ }
+ I4 interface {
+ m1(x, y, x /* ERROR "already declared" */ float)
+ m2() (x, y, x /* ERROR "already declared" */ float)
+ m3(x int) (x /* ERROR "already declared" */ float)
+ }
+ I5 interface {
+ m1(I5)
+ }
+
+ C1 chan int
+ C2 <-chan int
+ C3 chan<- C3
+
+ M1 map[Last]string
+ M2 map[string]M2
+
+ Last int
+)
diff --git a/src/pkg/go/typechecker/testdata/test1.go b/src/pkg/go/typechecker/testdata/test1.go
new file mode 100644
index 000000000..b0808ee7a
--- /dev/null
+++ b/src/pkg/go/typechecker/testdata/test1.go
@@ -0,0 +1,13 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// const and var declarations
+
+package P1
+
+const (
+ c1 /* ERROR "missing initializer" */
+ c2 int = 0
+ c3, c4 = 0
+)
diff --git a/src/pkg/go/typechecker/testdata/test3.go b/src/pkg/go/typechecker/testdata/test3.go
new file mode 100644
index 000000000..ea35808a0
--- /dev/null
+++ b/src/pkg/go/typechecker/testdata/test3.go
@@ -0,0 +1,38 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package P3
+
+// function and method signatures
+
+func _() {}
+func _() {}
+func _(x, x /* ERROR "already declared" */ int) {}
+
+func f() {}
+func f /* ERROR "already declared" */ () {}
+
+func (*foo /* ERROR "invalid receiver" */ ) m() {}
+func (bar /* ERROR "not a type" */ ) m() {}
+
+func f1(x, _, _ int) (_, _ float) {}
+func f2(x, y, x /* ERROR "already declared" */ int) {}
+func f3(x, y int) (a, b, x /* ERROR "already declared" */ int) {}
+
+func (x *T) m1() {}
+func (x *T) m1 /* ERROR "already declared" */ () {}
+func (x T) m1 /* ERROR "already declared" */ () {}
+func (T) m1 /* ERROR "already declared" */ () {}
+
+func (x *T) m2(u, x /* ERROR "already declared" */ int) {}
+func (x *T) m3(a, b, c int) (u, x /* ERROR "already declared" */ int) {}
+func (T) _(x, x /* ERROR "already declared" */ int) {}
+func (T) _() (x, x /* ERROR "already declared" */ int) {}
+
+//func (PT) _() {}
+
+var bar int
+
+type T struct{}
+type PT (T)
diff --git a/src/pkg/go/typechecker/testdata/test4.go b/src/pkg/go/typechecker/testdata/test4.go
new file mode 100644
index 000000000..bb9aee3ad
--- /dev/null
+++ b/src/pkg/go/typechecker/testdata/test4.go
@@ -0,0 +1,11 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Constant declarations
+
+package P4
+
+const (
+ c0 /* ERROR "missing initializer" */
+)
diff --git a/src/pkg/go/typechecker/typechecker.go b/src/pkg/go/typechecker/typechecker.go
new file mode 100644
index 000000000..e9aefa240
--- /dev/null
+++ b/src/pkg/go/typechecker/typechecker.go
@@ -0,0 +1,484 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// INCOMPLETE PACKAGE.
+// This package implements typechecking of a Go AST.
+// The result of the typecheck is an augmented AST
+// with object and type information for each identifier.
+//
+package typechecker
+
+import (
+ "fmt"
+ "go/ast"
+ "go/token"
+ "go/scanner"
+ "os"
+)
+
+
+// TODO(gri) don't report errors for objects/types that are marked as bad.
+
+
+const debug = true // set for debugging output
+
+
+// An importer takes an import path and returns the data describing the
+// respective package's exported interface. The data format is TBD.
+//
+type Importer func(path string) ([]byte, os.Error)
+
+
+// CheckPackage typechecks a package and augments the AST by setting
+// *ast.Object, *ast.Type, and *ast.Scope fields accordingly. If an
+// importer is provided, it is used to handle imports, otherwise they
+// are ignored (likely leading to typechecking errors).
+//
+// If errors are reported, the AST may be incompletely augmented (fields
+// may be nil) or contain incomplete object, type, or scope information.
+//
+func CheckPackage(fset *token.FileSet, pkg *ast.Package, importer Importer) os.Error {
+ var tc typechecker
+ tc.fset = fset
+ tc.importer = importer
+ tc.checkPackage(pkg)
+ return tc.GetError(scanner.Sorted)
+}
+
+
+// CheckFile typechecks a single file, but otherwise behaves like
+// CheckPackage. If the complete package consists of more than just
+// one file, the file may not typecheck without errors.
+//
+func CheckFile(fset *token.FileSet, file *ast.File, importer Importer) os.Error {
+ // create a single-file dummy package
+ pkg := &ast.Package{file.Name.Name, nil, map[string]*ast.File{fset.Position(file.Name.NamePos).Filename: file}}
+ return CheckPackage(fset, pkg, importer)
+}
+
+
+// ----------------------------------------------------------------------------
+// Typechecker state
+
+type typechecker struct {
+ fset *token.FileSet
+ scanner.ErrorVector
+ importer Importer
+ topScope *ast.Scope // current top-most scope
+ cyclemap map[*ast.Object]bool // for cycle detection
+ iota int // current value of iota
+}
+
+
+func (tc *typechecker) Errorf(pos token.Pos, format string, args ...interface{}) {
+ tc.Error(tc.fset.Position(pos), fmt.Sprintf(format, args...))
+}
+
+
+func assert(pred bool) {
+ if !pred {
+ panic("internal error")
+ }
+}
+
+
+/*
+Typechecking is done in several phases:
+
+phase 1: declare all global objects; also collect all function and method declarations
+ - all objects have kind, name, decl fields; the decl field permits
+ quick lookup of an object's declaration
+ - constant objects have an iota value
+ - type objects have unresolved types with empty scopes, all others have nil types
+ - report global double declarations
+
+phase 2: bind methods to their receiver base types
+ - received base types must be declared in the package, thus for
+ each method a corresponding (unresolved) type must exist
+ - report method double declarations and errors with base types
+
+phase 3: resolve all global objects
+ - sequentially iterate through all objects in the global scope
+ - resolve types for all unresolved types and assign types to
+ all attached methods
+ - assign types to all other objects, possibly by evaluating
+ constant and initializer expressions
+ - resolution may recurse; a cyclemap is used to detect cycles
+ - report global typing errors
+
+phase 4: sequentially typecheck function and method bodies
+ - all global objects are declared and have types and values;
+ all methods have types
+ - sequentially process statements in each body; any object
+ referred to must be fully defined at this point
+ - report local typing errors
+*/
+
+func (tc *typechecker) checkPackage(pkg *ast.Package) {
+ // setup package scope
+ tc.topScope = Universe
+ tc.openScope()
+ defer tc.closeScope()
+
+ // TODO(gri) there's no file scope at the moment since we ignore imports
+
+ // phase 1: declare all global objects; also collect all function and method declarations
+ var funcs []*ast.FuncDecl
+ for _, file := range pkg.Files {
+ for _, decl := range file.Decls {
+ tc.declGlobal(decl)
+ if f, isFunc := decl.(*ast.FuncDecl); isFunc {
+ funcs = append(funcs, f)
+ }
+ }
+ }
+
+ // phase 2: bind methods to their receiver base types
+ for _, m := range funcs {
+ if m.Recv != nil {
+ tc.bindMethod(m)
+ }
+ }
+
+ // phase 3: resolve all global objects
+ // (note that objects with _ name are also in the scope)
+ tc.cyclemap = make(map[*ast.Object]bool)
+ for _, obj := range tc.topScope.Objects {
+ tc.resolve(obj)
+ }
+ assert(len(tc.cyclemap) == 0)
+
+ // 4: sequentially typecheck function and method bodies
+ for _, f := range funcs {
+ tc.checkBlock(f.Body.List, f.Name.Obj.Type)
+ }
+
+ pkg.Scope = tc.topScope
+}
+
+
+func (tc *typechecker) declGlobal(global ast.Decl) {
+ switch d := global.(type) {
+ case *ast.BadDecl:
+ // ignore
+
+ case *ast.GenDecl:
+ iota := 0
+ var prev *ast.ValueSpec
+ for _, spec := range d.Specs {
+ switch s := spec.(type) {
+ case *ast.ImportSpec:
+ // TODO(gri) imports go into file scope
+ case *ast.ValueSpec:
+ switch d.Tok {
+ case token.CONST:
+ if s.Values == nil {
+ // create a new spec with type and values from the previous one
+ if prev != nil {
+ s = &ast.ValueSpec{s.Doc, s.Names, prev.Type, prev.Values, s.Comment}
+ } else {
+ // TODO(gri) this should probably go into the const decl code
+ tc.Errorf(s.Pos(), "missing initializer for const %s", s.Names[0].Name)
+ }
+ }
+ for _, name := range s.Names {
+ tc.decl(ast.Con, name, s, iota)
+ }
+ case token.VAR:
+ for _, name := range s.Names {
+ tc.decl(ast.Var, name, s, 0)
+ }
+ default:
+ panic("unreachable")
+ }
+ prev = s
+ iota++
+ case *ast.TypeSpec:
+ obj := tc.decl(ast.Typ, s.Name, s, 0)
+ // give all type objects an unresolved type so
+ // that we can collect methods in the type scope
+ typ := ast.NewType(ast.Unresolved)
+ obj.Type = typ
+ typ.Obj = obj
+ default:
+ panic("unreachable")
+ }
+ }
+
+ case *ast.FuncDecl:
+ if d.Recv == nil {
+ tc.decl(ast.Fun, d.Name, d, 0)
+ }
+
+ default:
+ panic("unreachable")
+ }
+}
+
+
+// If x is of the form *T, deref returns T, otherwise it returns x.
+func deref(x ast.Expr) ast.Expr {
+ if p, isPtr := x.(*ast.StarExpr); isPtr {
+ x = p.X
+ }
+ return x
+}
+
+
+func (tc *typechecker) bindMethod(method *ast.FuncDecl) {
+ // a method is declared in the receiver base type's scope
+ var scope *ast.Scope
+ base := deref(method.Recv.List[0].Type)
+ if name, isIdent := base.(*ast.Ident); isIdent {
+ // if base is not an *ast.Ident, we had a syntax
+ // error and the parser reported an error already
+ obj := tc.topScope.Lookup(name.Name)
+ if obj == nil {
+ tc.Errorf(name.Pos(), "invalid receiver: %s is not declared in this package", name.Name)
+ } else if obj.Kind != ast.Typ {
+ tc.Errorf(name.Pos(), "invalid receiver: %s is not a type", name.Name)
+ } else {
+ typ := obj.Type
+ assert(typ.Form == ast.Unresolved)
+ scope = typ.Scope
+ }
+ }
+ if scope == nil {
+ // no receiver type found; use a dummy scope
+ // (we still want to type-check the method
+ // body, so make sure there is a name object
+ // and type)
+ // TODO(gri) should we record the scope so
+ // that we don't lose the receiver for type-
+ // checking of the method body?
+ scope = ast.NewScope(nil)
+ }
+ tc.declInScope(scope, ast.Fun, method.Name, method, 0)
+}
+
+
+func (tc *typechecker) resolve(obj *ast.Object) {
+ // check for declaration cycles
+ if tc.cyclemap[obj] {
+ tc.Errorf(objPos(obj), "illegal cycle in declaration of %s", obj.Name)
+ obj.Kind = ast.Bad
+ return
+ }
+ tc.cyclemap[obj] = true
+ defer func() {
+ tc.cyclemap[obj] = false, false
+ }()
+
+ // resolve non-type objects
+ typ := obj.Type
+ if typ == nil {
+ switch obj.Kind {
+ case ast.Bad:
+ // ignore
+
+ case ast.Con:
+ tc.declConst(obj)
+
+ case ast.Var:
+ tc.declVar(obj)
+ //obj.Type = tc.typeFor(nil, obj.Decl.(*ast.ValueSpec).Type, false)
+
+ case ast.Fun:
+ obj.Type = ast.NewType(ast.Function)
+ t := obj.Decl.(*ast.FuncDecl).Type
+ tc.declSignature(obj.Type, nil, t.Params, t.Results)
+
+ default:
+ // type objects have non-nil types when resolve is called
+ if debug {
+ fmt.Printf("kind = %s\n", obj.Kind)
+ }
+ panic("unreachable")
+ }
+ return
+ }
+
+ // resolve type objects
+ if typ.Form == ast.Unresolved {
+ tc.typeFor(typ, typ.Obj.Decl.(*ast.TypeSpec).Type, false)
+
+ // provide types for all methods
+ for _, obj := range typ.Scope.Objects {
+ if obj.Kind == ast.Fun {
+ assert(obj.Type == nil)
+ obj.Type = ast.NewType(ast.Method)
+ f := obj.Decl.(*ast.FuncDecl)
+ t := f.Type
+ tc.declSignature(obj.Type, f.Recv, t.Params, t.Results)
+ }
+ }
+ }
+}
+
+
+func (tc *typechecker) checkBlock(body []ast.Stmt, ftype *ast.Type) {
+ tc.openScope()
+ defer tc.closeScope()
+
+ // inject function/method parameters into block scope, if any
+ if ftype != nil {
+ for _, par := range ftype.Params.Objects {
+ obj := tc.topScope.Insert(par)
+ assert(obj == par) // ftype has no double declarations
+ }
+ }
+
+ for _, stmt := range body {
+ tc.checkStmt(stmt)
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+// Types
+
+// unparen removes parentheses around x, if any.
+func unparen(x ast.Expr) ast.Expr {
+ if ux, hasParens := x.(*ast.ParenExpr); hasParens {
+ return unparen(ux.X)
+ }
+ return x
+}
+
+
+func (tc *typechecker) declFields(scope *ast.Scope, fields *ast.FieldList, ref bool) (n uint) {
+ if fields != nil {
+ for _, f := range fields.List {
+ typ := tc.typeFor(nil, f.Type, ref)
+ for _, name := range f.Names {
+ fld := tc.declInScope(scope, ast.Var, name, f, 0)
+ fld.Type = typ
+ n++
+ }
+ }
+ }
+ return n
+}
+
+
+func (tc *typechecker) declSignature(typ *ast.Type, recv, params, results *ast.FieldList) {
+ assert((typ.Form == ast.Method) == (recv != nil))
+ typ.Params = ast.NewScope(nil)
+ tc.declFields(typ.Params, recv, true)
+ tc.declFields(typ.Params, params, true)
+ typ.N = tc.declFields(typ.Params, results, true)
+}
+
+
+func (tc *typechecker) typeFor(def *ast.Type, x ast.Expr, ref bool) (typ *ast.Type) {
+ x = unparen(x)
+
+ // type name
+ if t, isIdent := x.(*ast.Ident); isIdent {
+ obj := tc.find(t)
+
+ if obj.Kind != ast.Typ {
+ tc.Errorf(t.Pos(), "%s is not a type", t.Name)
+ if def == nil {
+ typ = ast.NewType(ast.BadType)
+ } else {
+ typ = def
+ typ.Form = ast.BadType
+ }
+ typ.Expr = x
+ return
+ }
+
+ if !ref {
+ tc.resolve(obj) // check for cycles even if type resolved
+ }
+ typ = obj.Type
+
+ if def != nil {
+ // new type declaration: copy type structure
+ def.Form = typ.Form
+ def.N = typ.N
+ def.Key, def.Elt = typ.Key, typ.Elt
+ def.Params = typ.Params
+ def.Expr = x
+ typ = def
+ }
+ return
+ }
+
+ // type literal
+ typ = def
+ if typ == nil {
+ typ = ast.NewType(ast.BadType)
+ }
+ typ.Expr = x
+
+ switch t := x.(type) {
+ case *ast.SelectorExpr:
+ if debug {
+ fmt.Println("qualified identifier unimplemented")
+ }
+ typ.Form = ast.BadType
+
+ case *ast.StarExpr:
+ typ.Form = ast.Pointer
+ typ.Elt = tc.typeFor(nil, t.X, true)
+
+ case *ast.ArrayType:
+ if t.Len != nil {
+ typ.Form = ast.Array
+ // TODO(gri) compute the real length
+ // (this may call resolve recursively)
+ (*typ).N = 42
+ } else {
+ typ.Form = ast.Slice
+ }
+ typ.Elt = tc.typeFor(nil, t.Elt, t.Len == nil)
+
+ case *ast.StructType:
+ typ.Form = ast.Struct
+ tc.declFields(typ.Scope, t.Fields, false)
+
+ case *ast.FuncType:
+ typ.Form = ast.Function
+ tc.declSignature(typ, nil, t.Params, t.Results)
+
+ case *ast.InterfaceType:
+ typ.Form = ast.Interface
+ tc.declFields(typ.Scope, t.Methods, true)
+
+ case *ast.MapType:
+ typ.Form = ast.Map
+ typ.Key = tc.typeFor(nil, t.Key, true)
+ typ.Elt = tc.typeFor(nil, t.Value, true)
+
+ case *ast.ChanType:
+ typ.Form = ast.Channel
+ typ.N = uint(t.Dir)
+ typ.Elt = tc.typeFor(nil, t.Value, true)
+
+ default:
+ if debug {
+ fmt.Printf("x is %T\n", x)
+ }
+ panic("unreachable")
+ }
+
+ return
+}
+
+
+// ----------------------------------------------------------------------------
+// TODO(gri) implement these place holders
+
+func (tc *typechecker) declConst(*ast.Object) {
+}
+
+
+func (tc *typechecker) declVar(*ast.Object) {
+}
+
+
+func (tc *typechecker) checkStmt(ast.Stmt) {
+}
diff --git a/src/pkg/go/typechecker/typechecker_test.go b/src/pkg/go/typechecker/typechecker_test.go
new file mode 100644
index 000000000..9c5b52e41
--- /dev/null
+++ b/src/pkg/go/typechecker/typechecker_test.go
@@ -0,0 +1,167 @@
+// Copyright 2010 The Go 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
+ s.Init(fset, filename, src, nil, scanner.ScanComments)
+ var prev token.Pos // position of last non-comment token
+ loop:
+ for {
+ pos, tok, lit := s.Scan()
+ switch tok {
+ case token.EOF:
+ break loop
+ case token.COMMENT:
+ s := errRx.FindSubmatch(lit)
+ if len(s) == 2 {
+ list = append(list, &scanner.Error{fset.Position(prev), string(s[1])})
+ }
+ default:
+ prev = pos
+ }
+ }
+ }
+ sort.Sort(list) // multiple files may not be sorted
+ return
+}
+
+
+func testFilter(f *os.FileInfo) bool {
+ return strings.HasSuffix(f.Name, ".go") && f.Name[0] != '.'
+}
+
+
+func checkError(t *testing.T, expected, found *scanner.Error) {
+ rx, err := regexp.Compile(expected.Msg)
+ if err != nil {
+ t.Errorf("%s: %v", expected.Pos, err)
+ return
+ }
+
+ match := rx.MatchString(found.Msg)
+
+ if expected.Pos.Offset != found.Pos.Offset {
+ if match {
+ t.Errorf("%s: expected error should have been at %s", expected.Pos, found.Pos)
+ } else {
+ t.Errorf("%s: error matching %q expected", expected.Pos, expected.Msg)
+ return
+ }
+ }
+
+ if !match {
+ t.Errorf("%s: %q does not match %q", expected.Pos, expected.Msg, found.Msg)
+ }
+}
+
+
+func TestTypeCheck(t *testing.T) {
+ flag.Parse()
+ pkgRx, err := regexp.Compile(*pkgPat)
+ if err != nil {
+ t.Fatalf("illegal flag value %q: %s", *pkgPat, err)
+ }
+
+ pkgs, err := parser.ParseDir(fset, testDir, testFilter, 0)
+ if err != nil {
+ scanner.PrintError(os.Stderr, err)
+ t.Fatalf("packages in %s contain syntax errors", testDir)
+ }
+
+ for _, pkg := range pkgs {
+ if !pkgRx.MatchString(pkg.Name) {
+ continue // only test selected packages
+ }
+
+ if *trace {
+ fmt.Println(pkg.Name)
+ }
+
+ xlist := expectedErrors(t, pkg)
+ err := CheckPackage(fset, pkg, nil)
+ if err != nil {
+ if elist, ok := err.(scanner.ErrorList); ok {
+ // verify that errors match
+ for i := 0; i < len(xlist) && i < len(elist); i++ {
+ checkError(t, xlist[i], elist[i])
+ }
+ // the correct number or errors must have been found
+ if len(xlist) != len(elist) {
+ fmt.Fprintf(os.Stderr, "%s\n", pkg.Name)
+ scanner.PrintError(os.Stderr, elist)
+ fmt.Fprintln(os.Stderr)
+ t.Errorf("TypeCheck(%s): %d errors expected but %d reported", pkg.Name, len(xlist), len(elist))
+ }
+ } else {
+ t.Errorf("TypeCheck(%s): %v", pkg.Name, err)
+ }
+ } else if len(xlist) > 0 {
+ t.Errorf("TypeCheck(%s): %d errors expected but 0 reported", pkg.Name, len(xlist))
+ }
+ }
+}
diff --git a/src/pkg/go/typechecker/universe.go b/src/pkg/go/typechecker/universe.go
new file mode 100644
index 000000000..db950737f
--- /dev/null
+++ b/src/pkg/go/typechecker/universe.go
@@ -0,0 +1,38 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package typechecker
+
+import "go/ast"
+
+// TODO(gri) should this be in package ast?
+
+// The Universe scope contains all predeclared identifiers.
+var Universe *ast.Scope
+
+
+func def(obj *ast.Object) {
+ alt := Universe.Insert(obj)
+ if alt != obj {
+ panic("object declared twice")
+ }
+}
+
+
+func init() {
+ Universe = ast.NewScope(nil)
+
+ // basic types
+ for n, name := range ast.BasicTypes {
+ typ := ast.NewType(ast.Basic)
+ typ.N = n
+ obj := ast.NewObj(ast.Typ, name)
+ obj.Type = typ
+ typ.Obj = obj
+ def(obj)
+ }
+
+ // built-in functions
+ // TODO(gri) implement this
+}
diff --git a/src/pkg/gob/Makefile b/src/pkg/gob/Makefile
index 1091adb01..68007c189 100644
--- a/src/pkg/gob/Makefile
+++ b/src/pkg/gob/Makefile
@@ -2,14 +2,16 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=gob
GOFILES=\
decode.go\
decoder.go\
+ doc.go\
encode.go\
encoder.go\
+ error.go\
type.go\
include ../../Make.pkg
diff --git a/src/pkg/gob/codec_test.go b/src/pkg/gob/codec_test.go
index 2caaaa43f..d150dbe9a 100644
--- a/src/pkg/gob/codec_test.go
+++ b/src/pkg/gob/codec_test.go
@@ -21,50 +21,50 @@ type EncodeT struct {
}
var encodeT = []EncodeT{
- EncodeT{0x00, []byte{0x00}},
- EncodeT{0x0F, []byte{0x0F}},
- EncodeT{0xFF, []byte{0xFF, 0xFF}},
- EncodeT{0xFFFF, []byte{0xFE, 0xFF, 0xFF}},
- EncodeT{0xFFFFFF, []byte{0xFD, 0xFF, 0xFF, 0xFF}},
- EncodeT{0xFFFFFFFF, []byte{0xFC, 0xFF, 0xFF, 0xFF, 0xFF}},
- EncodeT{0xFFFFFFFFFF, []byte{0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}},
- EncodeT{0xFFFFFFFFFFFF, []byte{0xFA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}},
- EncodeT{0xFFFFFFFFFFFFFF, []byte{0xF9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}},
- EncodeT{0xFFFFFFFFFFFFFFFF, []byte{0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}},
- EncodeT{0x1111, []byte{0xFE, 0x11, 0x11}},
- EncodeT{0x1111111111111111, []byte{0xF8, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}},
- EncodeT{0x8888888888888888, []byte{0xF8, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88}},
- EncodeT{1 << 63, []byte{0xF8, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {0x00, []byte{0x00}},
+ {0x0F, []byte{0x0F}},
+ {0xFF, []byte{0xFF, 0xFF}},
+ {0xFFFF, []byte{0xFE, 0xFF, 0xFF}},
+ {0xFFFFFF, []byte{0xFD, 0xFF, 0xFF, 0xFF}},
+ {0xFFFFFFFF, []byte{0xFC, 0xFF, 0xFF, 0xFF, 0xFF}},
+ {0xFFFFFFFFFF, []byte{0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}},
+ {0xFFFFFFFFFFFF, []byte{0xFA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}},
+ {0xFFFFFFFFFFFFFF, []byte{0xF9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}},
+ {0xFFFFFFFFFFFFFFFF, []byte{0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}},
+ {0x1111, []byte{0xFE, 0x11, 0x11}},
+ {0x1111111111111111, []byte{0xF8, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}},
+ {0x8888888888888888, []byte{0xF8, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88}},
+ {1 << 63, []byte{0xF8, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+}
+
+// testError is meant to be used as a deferred function to turn a panic(gobError) into a
+// plain test.Error call.
+func testError(t *testing.T) {
+ if e := recover(); e != nil {
+ t.Error(e.(gobError).Error) // Will re-panic if not one of our errors, such as a runtime error.
+ }
+ return
}
// Test basic encode/decode routines for unsigned integers
func TestUintCodec(t *testing.T) {
+ defer testError(t)
b := new(bytes.Buffer)
- encState := new(encoderState)
- encState.b = b
+ encState := newEncoderState(nil, b)
for _, tt := range encodeT {
b.Reset()
- encodeUint(encState, tt.x)
- if encState.err != nil {
- t.Error("encodeUint:", tt.x, encState.err)
- }
+ encState.encodeUint(tt.x)
if !bytes.Equal(tt.b, b.Bytes()) {
t.Errorf("encodeUint: %#x encode: expected % x got % x", tt.x, tt.b, b.Bytes())
}
}
- decState := newDecodeState(b)
+ decState := newDecodeState(nil, &b)
for u := uint64(0); ; u = (u + 1) * 7 {
b.Reset()
- encodeUint(encState, u)
- if encState.err != nil {
- t.Error("encodeUint:", u, encState.err)
- }
- v := decodeUint(decState)
- if decState.err != nil {
- t.Error("DecodeUint:", u, decState.err)
- }
+ encState.encodeUint(u)
+ v := decState.decodeUint()
if u != v {
- t.Errorf("Encode/Decode: sent %#x received %#x\n", u, v)
+ t.Errorf("Encode/Decode: sent %#x received %#x", u, v)
}
if u&(1<<63) != 0 {
break
@@ -73,21 +73,15 @@ func TestUintCodec(t *testing.T) {
}
func verifyInt(i int64, t *testing.T) {
+ defer testError(t)
var b = new(bytes.Buffer)
- encState := new(encoderState)
- encState.b = b
- encodeInt(encState, i)
- if encState.err != nil {
- t.Error("encodeInt:", i, encState.err)
- }
- decState := newDecodeState(b)
+ encState := newEncoderState(nil, b)
+ encState.encodeInt(i)
+ decState := newDecodeState(nil, &b)
decState.buf = make([]byte, 8)
- j := decodeInt(decState)
- if decState.err != nil {
- t.Error("DecodeInt:", i, decState.err)
- }
+ j := decState.decodeInt()
if i != j {
- t.Errorf("Encode/Decode: sent %#x received %#x\n", uint64(i), uint64(j))
+ t.Errorf("Encode/Decode: sent %#x received %#x", uint64(i), uint64(j))
}
}
@@ -119,8 +113,7 @@ var bytesResult = []byte{0x07, 0x05, 'h', 'e', 'l', 'l', 'o'}
func newencoderState(b *bytes.Buffer) *encoderState {
b.Reset()
- state := new(encoderState)
- state.b = b
+ state := newEncoderState(nil, b)
state.fieldnum = -1
return state
}
@@ -323,10 +316,8 @@ func TestScalarEncInstructions(t *testing.T) {
}
func execDec(typ string, instr *decInstr, state *decodeState, t *testing.T, p unsafe.Pointer) {
- v := int(decodeUint(state))
- if state.err != nil {
- t.Fatalf("decoding %s field: %v", typ, state.err)
- }
+ defer testError(t)
+ v := int(state.decodeUint())
if v+state.fieldnum != 6 {
t.Fatalf("decoding field number %d, got %d", 6, v+state.fieldnum)
}
@@ -335,7 +326,8 @@ func execDec(typ string, instr *decInstr, state *decodeState, t *testing.T, p un
}
func newDecodeStateFromData(data []byte) *decodeState {
- state := newDecodeState(bytes.NewBuffer(data))
+ b := bytes.NewBuffer(data)
+ state := newDecodeState(nil, &b)
state.fieldnum = -1
return state
}
@@ -607,35 +599,35 @@ func TestScalarDecInstructions(t *testing.T) {
func TestEndToEnd(t *testing.T) {
type T2 struct {
- t string
+ T string
}
s1 := "string1"
s2 := "string2"
type T1 struct {
- a, b, c int
- m map[string]*float
- n *[3]float
- strs *[2]string
- int64s *[]int64
- ri complex64
- s string
- y []byte
- t *T2
+ A, B, C int
+ M map[string]*float
+ N *[3]float
+ Strs *[2]string
+ Int64s *[]int64
+ RI complex64
+ S string
+ Y []byte
+ T *T2
}
pi := 3.14159
e := 2.71828
t1 := &T1{
- a: 17,
- b: 18,
- c: -5,
- m: map[string]*float{"pi": &pi, "e": &e},
- n: &[3]float{1.5, 2.5, 3.5},
- strs: &[2]string{s1, s2},
- int64s: &[]int64{77, 89, 123412342134},
- ri: 17 - 23i,
- s: "Now is the time",
- y: []byte("hello, sailor"),
- t: &T2{"this is T2"},
+ A: 17,
+ B: 18,
+ C: -5,
+ M: map[string]*float{"pi": &pi, "e": &e},
+ N: &[3]float{1.5, 2.5, 3.5},
+ Strs: &[2]string{s1, s2},
+ Int64s: &[]int64{77, 89, 123412342134},
+ RI: 17 - 23i,
+ S: "Now is the time",
+ Y: []byte("hello, sailor"),
+ T: &T2{"this is T2"},
}
b := new(bytes.Buffer)
err := NewEncoder(b).Encode(t1)
@@ -654,13 +646,13 @@ func TestEndToEnd(t *testing.T) {
func TestOverflow(t *testing.T) {
type inputT struct {
- maxi int64
- mini int64
- maxu uint64
- maxf float64
- minf float64
- maxc complex128
- minc complex128
+ Maxi int64
+ Mini int64
+ Maxu uint64
+ Maxf float64
+ Minf float64
+ Maxc complex128
+ Minc complex128
}
var it inputT
var err os.Error
@@ -671,152 +663,152 @@ func TestOverflow(t *testing.T) {
// int8
b.Reset()
it = inputT{
- maxi: math.MaxInt8 + 1,
+ Maxi: math.MaxInt8 + 1,
}
type outi8 struct {
- maxi int8
- mini int8
+ Maxi int8
+ Mini int8
}
var o1 outi8
enc.Encode(it)
err = dec.Decode(&o1)
- if err == nil || err.String() != `value for "maxi" out of range` {
+ if err == nil || err.String() != `value for "Maxi" out of range` {
t.Error("wrong overflow error for int8:", err)
}
it = inputT{
- mini: math.MinInt8 - 1,
+ Mini: math.MinInt8 - 1,
}
b.Reset()
enc.Encode(it)
err = dec.Decode(&o1)
- if err == nil || err.String() != `value for "mini" out of range` {
+ if err == nil || err.String() != `value for "Mini" out of range` {
t.Error("wrong underflow error for int8:", err)
}
// int16
b.Reset()
it = inputT{
- maxi: math.MaxInt16 + 1,
+ Maxi: math.MaxInt16 + 1,
}
type outi16 struct {
- maxi int16
- mini int16
+ Maxi int16
+ Mini int16
}
var o2 outi16
enc.Encode(it)
err = dec.Decode(&o2)
- if err == nil || err.String() != `value for "maxi" out of range` {
+ if err == nil || err.String() != `value for "Maxi" out of range` {
t.Error("wrong overflow error for int16:", err)
}
it = inputT{
- mini: math.MinInt16 - 1,
+ Mini: math.MinInt16 - 1,
}
b.Reset()
enc.Encode(it)
err = dec.Decode(&o2)
- if err == nil || err.String() != `value for "mini" out of range` {
+ if err == nil || err.String() != `value for "Mini" out of range` {
t.Error("wrong underflow error for int16:", err)
}
// int32
b.Reset()
it = inputT{
- maxi: math.MaxInt32 + 1,
+ Maxi: math.MaxInt32 + 1,
}
type outi32 struct {
- maxi int32
- mini int32
+ Maxi int32
+ Mini int32
}
var o3 outi32
enc.Encode(it)
err = dec.Decode(&o3)
- if err == nil || err.String() != `value for "maxi" out of range` {
+ if err == nil || err.String() != `value for "Maxi" out of range` {
t.Error("wrong overflow error for int32:", err)
}
it = inputT{
- mini: math.MinInt32 - 1,
+ Mini: math.MinInt32 - 1,
}
b.Reset()
enc.Encode(it)
err = dec.Decode(&o3)
- if err == nil || err.String() != `value for "mini" out of range` {
+ if err == nil || err.String() != `value for "Mini" out of range` {
t.Error("wrong underflow error for int32:", err)
}
// uint8
b.Reset()
it = inputT{
- maxu: math.MaxUint8 + 1,
+ Maxu: math.MaxUint8 + 1,
}
type outu8 struct {
- maxu uint8
+ Maxu uint8
}
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.String() != `value for "Maxu" out of range` {
t.Error("wrong overflow error for uint8:", err)
}
// uint16
b.Reset()
it = inputT{
- maxu: math.MaxUint16 + 1,
+ Maxu: math.MaxUint16 + 1,
}
type outu16 struct {
- maxu uint16
+ Maxu uint16
}
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.String() != `value for "Maxu" out of range` {
t.Error("wrong overflow error for uint16:", err)
}
// uint32
b.Reset()
it = inputT{
- maxu: math.MaxUint32 + 1,
+ Maxu: math.MaxUint32 + 1,
}
type outu32 struct {
- maxu uint32
+ Maxu uint32
}
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.String() != `value for "Maxu" out of range` {
t.Error("wrong overflow error for uint32:", err)
}
// float32
b.Reset()
it = inputT{
- maxf: math.MaxFloat32 * 2,
+ Maxf: math.MaxFloat32 * 2,
}
type outf32 struct {
- maxf float32
- minf float32
+ Maxf float32
+ Minf float32
}
var o7 outf32
enc.Encode(it)
err = dec.Decode(&o7)
- if err == nil || err.String() != `value for "maxf" out of range` {
+ if err == nil || err.String() != `value for "Maxf" out of range` {
t.Error("wrong overflow error for float32:", err)
}
// complex64
b.Reset()
it = inputT{
- maxc: cmplx(math.MaxFloat32*2, math.MaxFloat32*2),
+ Maxc: cmplx(math.MaxFloat32*2, math.MaxFloat32*2),
}
type outc64 struct {
- maxc complex64
- minc complex64
+ Maxc complex64
+ Minc complex64
}
var o8 outc64
enc.Encode(it)
err = dec.Decode(&o8)
- if err == nil || err.String() != `value for "maxc" out of range` {
+ if err == nil || err.String() != `value for "Maxc" out of range` {
t.Error("wrong overflow error for complex64:", err)
}
}
@@ -824,92 +816,92 @@ func TestOverflow(t *testing.T) {
func TestNesting(t *testing.T) {
type RT struct {
- a string
- next *RT
+ A string
+ Next *RT
}
rt := new(RT)
- rt.a = "level1"
- rt.next = new(RT)
- rt.next.a = "level2"
+ rt.A = "level1"
+ rt.Next = new(RT)
+ rt.Next.A = "level2"
b := new(bytes.Buffer)
NewEncoder(b).Encode(rt)
var drt RT
dec := NewDecoder(b)
err := dec.Decode(&drt)
if err != nil {
- t.Errorf("decoder error:", err)
+ t.Fatal("decoder error:", err)
}
- if drt.a != rt.a {
+ if drt.A != rt.A {
t.Errorf("nesting: encode expected %v got %v", *rt, drt)
}
- if drt.next == nil {
+ if drt.Next == nil {
t.Errorf("nesting: recursion failed")
}
- if drt.next.a != rt.next.a {
- t.Errorf("nesting: encode expected %v got %v", *rt.next, *drt.next)
+ if drt.Next.A != rt.Next.A {
+ t.Errorf("nesting: encode expected %v got %v", *rt.Next, *drt.Next)
}
}
// These three structures have the same data with different indirections
type T0 struct {
- a int
- b int
- c int
- d int
+ A int
+ B int
+ C int
+ D int
}
type T1 struct {
- a int
- b *int
- c **int
- d ***int
+ A int
+ B *int
+ C **int
+ D ***int
}
type T2 struct {
- a ***int
- b **int
- c *int
- d int
+ A ***int
+ B **int
+ C *int
+ D int
}
func TestAutoIndirection(t *testing.T) {
// First transfer t1 into t0
var t1 T1
- t1.a = 17
- t1.b = new(int)
- *t1.b = 177
- t1.c = new(*int)
- *t1.c = new(int)
- **t1.c = 1777
- t1.d = new(**int)
- *t1.d = new(*int)
- **t1.d = new(int)
- ***t1.d = 17777
+ t1.A = 17
+ t1.B = new(int)
+ *t1.B = 177
+ t1.C = new(*int)
+ *t1.C = new(int)
+ **t1.C = 1777
+ t1.D = new(**int)
+ *t1.D = new(*int)
+ **t1.D = new(int)
+ ***t1.D = 17777
b := new(bytes.Buffer)
enc := NewEncoder(b)
enc.Encode(t1)
dec := NewDecoder(b)
var t0 T0
dec.Decode(&t0)
- if t0.a != 17 || t0.b != 177 || t0.c != 1777 || t0.d != 17777 {
+ if t0.A != 17 || t0.B != 177 || t0.C != 1777 || t0.D != 17777 {
t.Errorf("t1->t0: expected {17 177 1777 17777}; got %v", t0)
}
// Now transfer t2 into t0
var t2 T2
- t2.d = 17777
- t2.c = new(int)
- *t2.c = 1777
- t2.b = new(*int)
- *t2.b = new(int)
- **t2.b = 177
- t2.a = new(**int)
- *t2.a = new(*int)
- **t2.a = new(int)
- ***t2.a = 17
+ t2.D = 17777
+ t2.C = new(int)
+ *t2.C = 1777
+ t2.B = new(*int)
+ *t2.B = new(int)
+ **t2.B = 177
+ t2.A = new(**int)
+ *t2.A = new(*int)
+ **t2.A = new(int)
+ ***t2.A = 17
b.Reset()
enc.Encode(t2)
t0 = T0{}
dec.Decode(&t0)
- if t0.a != 17 || t0.b != 177 || t0.c != 1777 || t0.d != 17777 {
+ if t0.A != 17 || t0.B != 177 || t0.C != 1777 || t0.D != 17777 {
t.Errorf("t2->t0 expected {17 177 1777 17777}; got %v", t0)
}
@@ -919,8 +911,8 @@ func TestAutoIndirection(t *testing.T) {
enc.Encode(t0)
t1 = T1{}
dec.Decode(&t1)
- if t1.a != 17 || *t1.b != 177 || **t1.c != 1777 || ***t1.d != 17777 {
- t.Errorf("t0->t1 expected {17 177 1777 17777}; got {%d %d %d %d}", t1.a, *t1.b, **t1.c, ***t1.d)
+ if t1.A != 17 || *t1.B != 177 || **t1.C != 1777 || ***t1.D != 17777 {
+ t.Errorf("t0->t1 expected {17 177 1777 17777}; got {%d %d %d %d}", t1.A, *t1.B, **t1.C, ***t1.D)
}
// Now transfer t0 into t2
@@ -928,40 +920,40 @@ func TestAutoIndirection(t *testing.T) {
enc.Encode(t0)
t2 = T2{}
dec.Decode(&t2)
- if ***t2.a != 17 || **t2.b != 177 || *t2.c != 1777 || t2.d != 17777 {
- t.Errorf("t0->t2 expected {17 177 1777 17777}; got {%d %d %d %d}", ***t2.a, **t2.b, *t2.c, t2.d)
+ if ***t2.A != 17 || **t2.B != 177 || *t2.C != 1777 || t2.D != 17777 {
+ t.Errorf("t0->t2 expected {17 177 1777 17777}; got {%d %d %d %d}", ***t2.A, **t2.B, *t2.C, t2.D)
}
// Now do t2 again but without pre-allocated pointers.
b.Reset()
enc.Encode(t0)
- ***t2.a = 0
- **t2.b = 0
- *t2.c = 0
- t2.d = 0
+ ***t2.A = 0
+ **t2.B = 0
+ *t2.C = 0
+ t2.D = 0
dec.Decode(&t2)
- if ***t2.a != 17 || **t2.b != 177 || *t2.c != 1777 || t2.d != 17777 {
- t.Errorf("t0->t2 expected {17 177 1777 17777}; got {%d %d %d %d}", ***t2.a, **t2.b, *t2.c, t2.d)
+ if ***t2.A != 17 || **t2.B != 177 || *t2.C != 1777 || t2.D != 17777 {
+ t.Errorf("t0->t2 expected {17 177 1777 17777}; got {%d %d %d %d}", ***t2.A, **t2.B, *t2.C, t2.D)
}
}
type RT0 struct {
- a int
- b string
- c float
+ A int
+ B string
+ C float
}
type RT1 struct {
- c float
- b string
- a int
- notSet string
+ C float
+ B string
+ A int
+ NotSet string
}
func TestReorderedFields(t *testing.T) {
var rt0 RT0
- rt0.a = 17
- rt0.b = "hello"
- rt0.c = 3.14159
+ rt0.A = 17
+ rt0.B = "hello"
+ rt0.C = 3.14159
b := new(bytes.Buffer)
NewEncoder(b).Encode(rt0)
dec := NewDecoder(b)
@@ -969,41 +961,41 @@ func TestReorderedFields(t *testing.T) {
// Wire type is RT0, local type is RT1.
err := dec.Decode(&rt1)
if err != nil {
- t.Error("decode error:", err)
+ t.Fatal("decode error:", err)
}
- if rt0.a != rt1.a || rt0.b != rt1.b || rt0.c != rt1.c {
+ if rt0.A != rt1.A || rt0.B != rt1.B || rt0.C != rt1.C {
t.Errorf("rt1->rt0: expected %v; got %v", rt0, rt1)
}
}
// Like an RT0 but with fields we'll ignore on the decode side.
type IT0 struct {
- a int64
- b string
- ignore_d []int
- ignore_e [3]float
- ignore_f bool
- ignore_g string
- ignore_h []byte
- ignore_i *RT1
- ignore_m map[string]int
- c float
+ A int64
+ B string
+ Ignore_d []int
+ Ignore_e [3]float
+ Ignore_f bool
+ Ignore_g string
+ Ignore_h []byte
+ Ignore_i *RT1
+ Ignore_m map[string]int
+ C float
}
func TestIgnoredFields(t *testing.T) {
var it0 IT0
- it0.a = 17
- it0.b = "hello"
- it0.c = 3.14159
- it0.ignore_d = []int{1, 2, 3}
- it0.ignore_e[0] = 1.0
- it0.ignore_e[1] = 2.0
- it0.ignore_e[2] = 3.0
- it0.ignore_f = true
- it0.ignore_g = "pay no attention"
- it0.ignore_h = []byte("to the curtain")
- it0.ignore_i = &RT1{3.1, "hi", 7, "hello"}
- it0.ignore_m = map[string]int{"one": 1, "two": 2}
+ it0.A = 17
+ it0.B = "hello"
+ it0.C = 3.14159
+ it0.Ignore_d = []int{1, 2, 3}
+ it0.Ignore_e[0] = 1.0
+ it0.Ignore_e[1] = 2.0
+ it0.Ignore_e[2] = 3.0
+ it0.Ignore_f = true
+ it0.Ignore_g = "pay no attention"
+ it0.Ignore_h = []byte("to the curtain")
+ it0.Ignore_i = &RT1{3.1, "hi", 7, "hello"}
+ it0.Ignore_m = map[string]int{"one": 1, "two": 2}
b := new(bytes.Buffer)
NewEncoder(b).Encode(it0)
@@ -1014,56 +1006,58 @@ func TestIgnoredFields(t *testing.T) {
if err != nil {
t.Error("error: ", err)
}
- if int(it0.a) != rt1.a || it0.b != rt1.b || it0.c != rt1.c {
- t.Errorf("rt1->rt0: expected %v; got %v", it0, rt1)
+ if int(it0.A) != rt1.A || it0.B != rt1.B || it0.C != rt1.C {
+ t.Errorf("rt0->rt1: expected %v; got %v", it0, rt1)
}
}
type Bad0 struct {
- inter interface{}
- c float
+ ch chan int
+ c float
}
+var nilEncoder *Encoder
+
func TestInvalidField(t *testing.T) {
var bad0 Bad0
- bad0.inter = 17
+ bad0.ch = make(chan int)
b := new(bytes.Buffer)
- err := encode(b, reflect.NewValue(&bad0))
+ err := nilEncoder.encode(b, reflect.NewValue(&bad0))
if err == nil {
t.Error("expected error; got none")
- } else if strings.Index(err.String(), "interface") < 0 {
+ } else if strings.Index(err.String(), "type") < 0 {
t.Error("expected type error; got", err)
}
}
type Indirect struct {
- a ***[3]int
- s ***[]int
- m ****map[string]int
+ A ***[3]int
+ S ***[]int
+ M ****map[string]int
}
type Direct struct {
- a [3]int
- s []int
- m map[string]int
+ A [3]int
+ S []int
+ M map[string]int
}
func TestIndirectSliceMapArray(t *testing.T) {
// Marshal indirect, unmarshal to direct.
i := new(Indirect)
- i.a = new(**[3]int)
- *i.a = new(*[3]int)
- **i.a = new([3]int)
- ***i.a = [3]int{1, 2, 3}
- i.s = new(**[]int)
- *i.s = new(*[]int)
- **i.s = new([]int)
- ***i.s = []int{4, 5, 6}
- i.m = new(***map[string]int)
- *i.m = new(**map[string]int)
- **i.m = new(*map[string]int)
- ***i.m = new(map[string]int)
- ****i.m = map[string]int{"one": 1, "two": 2, "three": 3}
+ i.A = new(**[3]int)
+ *i.A = new(*[3]int)
+ **i.A = new([3]int)
+ ***i.A = [3]int{1, 2, 3}
+ i.S = new(**[]int)
+ *i.S = new(*[]int)
+ **i.S = new([]int)
+ ***i.S = []int{4, 5, 6}
+ i.M = new(***map[string]int)
+ *i.M = new(**map[string]int)
+ **i.M = new(*map[string]int)
+ ***i.M = new(map[string]int)
+ ****i.M = map[string]int{"one": 1, "two": 2, "three": 3}
b := new(bytes.Buffer)
NewEncoder(b).Encode(i)
dec := NewDecoder(b)
@@ -1072,34 +1066,328 @@ func TestIndirectSliceMapArray(t *testing.T) {
if err != nil {
t.Error("error: ", err)
}
- if len(d.a) != 3 || d.a[0] != 1 || d.a[1] != 2 || d.a[2] != 3 {
- t.Errorf("indirect to direct: d.a is %v not %v", d.a, ***i.a)
+ if len(d.A) != 3 || d.A[0] != 1 || d.A[1] != 2 || d.A[2] != 3 {
+ t.Errorf("indirect to direct: d.A is %v not %v", d.A, ***i.A)
}
- if len(d.s) != 3 || d.s[0] != 4 || d.s[1] != 5 || d.s[2] != 6 {
- t.Errorf("indirect to direct: d.s is %v not %v", d.s, ***i.s)
+ if len(d.S) != 3 || d.S[0] != 4 || d.S[1] != 5 || d.S[2] != 6 {
+ t.Errorf("indirect to direct: d.S is %v not %v", d.S, ***i.S)
}
- if len(d.m) != 3 || d.m["one"] != 1 || d.m["two"] != 2 || d.m["three"] != 3 {
- t.Errorf("indirect to direct: d.m is %v not %v", d.m, ***i.m)
+ if len(d.M) != 3 || d.M["one"] != 1 || d.M["two"] != 2 || d.M["three"] != 3 {
+ t.Errorf("indirect to direct: d.M is %v not %v", d.M, ***i.M)
}
// Marshal direct, unmarshal to indirect.
- d.a = [3]int{11, 22, 33}
- d.s = []int{44, 55, 66}
- d.m = map[string]int{"four": 4, "five": 5, "six": 6}
+ d.A = [3]int{11, 22, 33}
+ d.S = []int{44, 55, 66}
+ d.M = map[string]int{"four": 4, "five": 5, "six": 6}
i = new(Indirect)
b.Reset()
NewEncoder(b).Encode(d)
dec = NewDecoder(b)
err = dec.Decode(&i)
if err != nil {
- t.Error("error: ", err)
+ t.Fatal("error: ", err)
+ }
+ if len(***i.A) != 3 || (***i.A)[0] != 11 || (***i.A)[1] != 22 || (***i.A)[2] != 33 {
+ t.Errorf("direct to indirect: ***i.A is %v not %v", ***i.A, d.A)
+ }
+ if len(***i.S) != 3 || (***i.S)[0] != 44 || (***i.S)[1] != 55 || (***i.S)[2] != 66 {
+ t.Errorf("direct to indirect: ***i.S is %v not %v", ***i.S, ***i.S)
+ }
+ if len(****i.M) != 3 || (****i.M)["four"] != 4 || (****i.M)["five"] != 5 || (****i.M)["six"] != 6 {
+ t.Errorf("direct to indirect: ****i.M is %v not %v", ****i.M, d.M)
+ }
+}
+
+// An interface with several implementations
+type Squarer interface {
+ Square() int
+}
+
+type Int int
+
+func (i Int) Square() int {
+ return int(i * i)
+}
+
+type Float float
+
+func (f Float) Square() int {
+ return int(f * f)
+}
+
+type Vector []int
+
+func (v Vector) Square() int {
+ sum := 0
+ for _, x := range v {
+ sum += x * x
+ }
+ return sum
+}
+
+type Point struct {
+ a, b int
+}
+
+func (p Point) Square() int {
+ return p.a*p.a + p.b*p.b
+}
+
+// A struct with interfaces in it.
+type InterfaceItem struct {
+ I int
+ Sq1, Sq2, Sq3 Squarer
+ F float
+ Sq []Squarer
+}
+
+// The same struct without interfaces
+type NoInterfaceItem struct {
+ I int
+ F float
+}
+
+func TestInterface(t *testing.T) {
+ iVal := Int(3)
+ fVal := Float(5)
+ // Sending a Vector will require that the receiver define a type in the middle of
+ // receiving the value for item2.
+ vVal := Vector{1, 2, 3}
+ b := new(bytes.Buffer)
+ item1 := &InterfaceItem{1, iVal, fVal, vVal, 11.5, []Squarer{iVal, fVal, nil, vVal}}
+ // Register the types.
+ Register(Int(0))
+ Register(Float(0))
+ Register(Vector{})
+ err := NewEncoder(b).Encode(item1)
+ if err != nil {
+ t.Error("expected no encode error; got", err)
+ }
+
+ item2 := InterfaceItem{}
+ err = NewDecoder(b).Decode(&item2)
+ if err != nil {
+ t.Fatal("decode:", err)
+ }
+ if item2.I != item1.I {
+ t.Error("normal int did not decode correctly")
+ }
+ if item2.Sq1 == nil || item2.Sq1.Square() != iVal.Square() {
+ t.Error("Int did not decode correctly")
+ }
+ if item2.Sq2 == nil || item2.Sq2.Square() != fVal.Square() {
+ t.Error("Float did not decode correctly")
+ }
+ if item2.Sq3 == nil || item2.Sq3.Square() != vVal.Square() {
+ t.Error("Vector did not decode correctly")
+ }
+ if item2.F != item1.F {
+ t.Error("normal float did not decode correctly")
}
- if len(***i.a) != 3 || (***i.a)[0] != 11 || (***i.a)[1] != 22 || (***i.a)[2] != 33 {
- t.Errorf("direct to indirect: ***i.a is %v not %v", ***i.a, d.a)
+ // Now check that we received a slice of Squarers correctly, including a nil element
+ if len(item1.Sq) != len(item2.Sq) {
+ t.Fatalf("[]Squarer length wrong: got %d; expected %d", len(item2.Sq), len(item1.Sq))
}
- if len(***i.s) != 3 || (***i.s)[0] != 44 || (***i.s)[1] != 55 || (***i.s)[2] != 66 {
- t.Errorf("direct to indirect: ***i.s is %v not %v", ***i.s, ***i.s)
+ for i, v1 := range item1.Sq {
+ v2 := item2.Sq[i]
+ if v1 == nil || v2 == nil {
+ if v1 != nil || v2 != nil {
+ t.Errorf("item %d inconsistent nils", i)
+ }
+ continue
+ if v1.Square() != v2.Square() {
+ t.Errorf("item %d inconsistent values: %v %v", i, v1, v2)
+ }
+ }
}
- if len(****i.m) != 3 || (****i.m)["four"] != 4 || (****i.m)["five"] != 5 || (****i.m)["six"] != 6 {
- t.Errorf("direct to indirect: ****i.m is %v not %v", ****i.m, d.m)
+
+}
+
+// A struct with all basic types, stored in interfaces.
+type BasicInterfaceItem struct {
+ Int, Int8, Int16, Int32, Int64 interface{}
+ Uint, Uint8, Uint16, Uint32, Uint64 interface{}
+ Float, Float32, Float64 interface{}
+ Complex, Complex64, Complex128 interface{}
+ Bool interface{}
+ String interface{}
+ Bytes interface{}
+}
+
+func TestInterfaceBasic(t *testing.T) {
+ b := new(bytes.Buffer)
+ item1 := &BasicInterfaceItem{
+ int(1), int8(1), int16(1), int32(1), int64(1),
+ uint(1), uint8(1), uint16(1), uint32(1), uint64(1),
+ float(1), float32(1), float64(1),
+ complex(0i), complex64(0i), complex128(0i),
+ true,
+ "hello",
+ []byte("sailor"),
+ }
+ err := NewEncoder(b).Encode(item1)
+ if err != nil {
+ t.Error("expected no encode error; got", err)
+ }
+
+ item2 := &BasicInterfaceItem{}
+ err = NewDecoder(b).Decode(&item2)
+ if err != nil {
+ t.Fatal("decode:", err)
+ }
+ if !reflect.DeepEqual(item1, item2) {
+ t.Errorf("encode expected %v got %v", item1, item2)
+ }
+ // Hand check a couple for correct types.
+ if v, ok := item2.Bool.(bool); !ok || !v {
+ t.Error("boolean should be true")
+ }
+ if v, ok := item2.String.(string); !ok || v != item1.String.(string) {
+ t.Errorf("string should be %v is %v", item1.String, v)
+ }
+}
+
+type String string
+
+type PtrInterfaceItem struct {
+ Str1 interface{} // basic
+ Str2 interface{} // derived
+}
+
+// We'll send pointers; should receive values.
+// Also check that we can register T but send *T.
+func TestInterfacePointer(t *testing.T) {
+ b := new(bytes.Buffer)
+ str1 := "howdy"
+ str2 := String("kiddo")
+ item1 := &PtrInterfaceItem{
+ &str1,
+ &str2,
+ }
+ // Register the type.
+ Register(str2)
+ err := NewEncoder(b).Encode(item1)
+ if err != nil {
+ t.Error("expected no encode error; got", err)
+ }
+
+ item2 := &PtrInterfaceItem{}
+ err = NewDecoder(b).Decode(&item2)
+ if err != nil {
+ t.Fatal("decode:", err)
+ }
+ // Hand test for correct types and values.
+ if v, ok := item2.Str1.(string); !ok || v != str1 {
+ t.Errorf("basic string failed: %q should be %q", v, str1)
+ }
+ if v, ok := item2.Str2.(String); !ok || v != str2 {
+ t.Errorf("derived type String failed: %q should be %q", v, str2)
+ }
+}
+
+func TestIgnoreInterface(t *testing.T) {
+ iVal := Int(3)
+ fVal := Float(5)
+ // Sending a Point will require that the receiver define a type in the middle of
+ // receiving the value for item2.
+ pVal := Point{2, 3}
+ b := new(bytes.Buffer)
+ item1 := &InterfaceItem{1, iVal, fVal, pVal, 11.5, nil}
+ // Register the types.
+ Register(Int(0))
+ Register(Float(0))
+ Register(Point{})
+ err := NewEncoder(b).Encode(item1)
+ if err != nil {
+ t.Error("expected no encode error; got", err)
+ }
+
+ item2 := NoInterfaceItem{}
+ err = NewDecoder(b).Decode(&item2)
+ if err != nil {
+ t.Fatal("decode:", err)
+ }
+ if item2.I != item1.I {
+ t.Error("normal int did not decode correctly")
+ }
+ if item2.F != item2.F {
+ t.Error("normal float did not decode correctly")
+ }
+}
+
+type U struct {
+ A int
+ B string
+ c float
+ D uint
+}
+
+func TestUnexportedFields(t *testing.T) {
+ var u0 U
+ u0.A = 17
+ u0.B = "hello"
+ u0.c = 3.14159
+ u0.D = 23
+ b := new(bytes.Buffer)
+ NewEncoder(b).Encode(u0)
+ dec := NewDecoder(b)
+ var u1 U
+ u1.c = 1234.
+ err := dec.Decode(&u1)
+ if err != nil {
+ t.Fatal("decode error:", err)
+ }
+ if u0.A != u0.A || u0.B != u1.B || u0.D != u1.D {
+ t.Errorf("u1->u0: expected %v; got %v", u0, u1)
+ }
+ if u1.c != 1234. {
+ t.Error("u1.c modified")
+ }
+}
+
+// A type that won't be defined in the gob until we send it in an interface value.
+type OnTheFly struct {
+ A int
+}
+
+type DT struct {
+ // X OnTheFly
+ A int
+ B string
+ C float
+ I interface{}
+ J interface{}
+ I_nil interface{}
+ M map[string]int
+ T [3]int
+ S []string
+}
+
+func TestDebug(t *testing.T) {
+ if debugFunc == nil {
+ return
+ }
+ Register(OnTheFly{})
+ var dt DT
+ dt.A = 17
+ dt.B = "hello"
+ dt.C = 3.14159
+ dt.I = 271828
+ dt.J = OnTheFly{3}
+ dt.I_nil = nil
+ dt.M = map[string]int{"one": 1, "two": 2}
+ dt.T = [3]int{11, 22, 33}
+ dt.S = []string{"hi", "joe"}
+ b := new(bytes.Buffer)
+ err := NewEncoder(b).Encode(dt)
+ if err != nil {
+ t.Fatal("encode:", err)
+ }
+ debugBuffer := bytes.NewBuffer(b.Bytes())
+ dt2 := &DT{}
+ err = NewDecoder(b).Decode(&dt2)
+ if err != nil {
+ t.Error("decode:", err)
}
+ debugFunc(debugBuffer)
}
diff --git a/src/pkg/gob/debug.go b/src/pkg/gob/debug.go
index 02f2602ed..f3632a080 100644
--- a/src/pkg/gob/debug.go
+++ b/src/pkg/gob/debug.go
@@ -1,157 +1,236 @@
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.
import (
"bytes"
"fmt"
"io"
- "log"
"os"
+ "reflect"
+ "runtime"
)
-// Debug prints a human-readable representation of the gob data read from r.
-func Debug(r io.Reader) { NewDecoder(r).debug() }
+var dump = false // If true, print the remaining bytes in the input buffer at each item.
-// debug is like Decode but just prints what it finds. It should be safe even for corrupted data.
-func (dec *Decoder) debug() {
- dec.state.err = nil
- for {
- // Read a count.
- var nbytes uint64
- nbytes, dec.state.err = decodeUintReader(dec.r, dec.countBuf[0:])
- if dec.state.err != nil {
- break
- }
+// Init installs the debugging facility. If this file is not compiled in the
+// package, the test in codec_test.go is a no-op.
+func init() {
+ debugFunc = Debug
+}
- // Allocate the buffer.
- if nbytes > uint64(len(dec.buf)) {
- dec.buf = make([]byte, nbytes+1000)
+// Debug prints a human-readable representation of the gob data read from r.
+func Debug(r io.Reader) {
+ defer func() {
+ if e := recover(); e != nil {
+ if _, ok := e.(runtime.Error); ok {
+ panic(e)
+ }
+ fmt.Printf("error during debugging: %v\n", e)
}
- dec.state.b = bytes.NewBuffer(dec.buf[0:nbytes])
+ }()
+ NewDecoder(r).debug()
+}
- // Read the data
- _, dec.state.err = io.ReadFull(dec.r, dec.buf[0:nbytes])
- if dec.state.err != nil {
- if dec.state.err == os.EOF {
- dec.state.err = io.ErrUnexpectedEOF
- }
- break
+// debugRecv is like recv but prints what it sees.
+func (dec *Decoder) debugRecv() {
+ if dec.byteBuffer != nil && dec.byteBuffer.Len() != 0 {
+ fmt.Printf("error in recv: %d bytes left in input buffer\n", dec.byteBuffer.Len())
+ return
+ }
+ // Read a count.
+ var nbytes uint64
+ nbytes, dec.err = decodeUintReader(dec.r, dec.countBuf[0:])
+ if dec.err != nil {
+ fmt.Printf("receiver error on count: %s\n", dec.err)
+ return
+ }
+ // Allocate the buffer.
+ if nbytes > uint64(len(dec.buf)) {
+ dec.buf = make([]byte, nbytes+1000)
+ }
+ dec.byteBuffer = bytes.NewBuffer(dec.buf[0:nbytes])
+
+ // Read the data
+ _, dec.err = io.ReadFull(dec.r, dec.buf[0:nbytes])
+ if dec.err != nil {
+ fmt.Printf("receiver error on data: %s\n", dec.err)
+ if dec.err == os.EOF {
+ dec.err = io.ErrUnexpectedEOF
}
+ return
+ }
+ if dump {
+ fmt.Printf("received %d bytes:\n\t% x\n", nbytes, dec.byteBuffer.Bytes())
+ }
+}
+
+// debug is like Decode but just prints what it finds. It should be safe even for corrupted data.
+func (dec *Decoder) debug() {
+ // Make sure we're single-threaded through here.
+ dec.mutex.Lock()
+ defer dec.mutex.Unlock()
+
+ dec.err = nil
+ dec.debugRecv()
+ if dec.err != nil {
+ return
+ }
+ dec.debugFromBuffer(0, false)
+}
+
+// printFromBuffer prints the next value. The buffer contains data, but it may
+// be a type descriptor and we may need to load more data to see the value;
+// printType takes care of that.
+func (dec *Decoder) debugFromBuffer(indent int, countPresent bool) {
+ for dec.state.b.Len() > 0 {
// Receive a type id.
- id := typeId(decodeInt(dec.state))
- if dec.state.err != nil {
- break
- }
+ id := typeId(dec.state.decodeInt())
// Is it a new type?
if id < 0 { // 0 is the error state, handled above
// If the id is negative, we have a type.
- fmt.Printf("new type id %d\n", -id)
- dec.printType(-id)
- if dec.state.err != nil {
+ dec.debugRecvType(-id)
+ if dec.err != nil {
break
}
continue
}
- fmt.Printf("type id %d\n", id)
// No, it's a value.
- // Make sure the type has been defined already.
- _, ok := dec.wireType[id]
- if !ok {
- dec.state.err = errBadType
+ // Make sure the type has been defined already or is a builtin type (for
+ // top-level singleton values).
+ if dec.wireType[id] == nil && builtinIdToType[id] == nil {
+ dec.err = errBadType
break
}
- fmt.Printf("\t%d bytes:\t% x\n", nbytes, dec.state.b.Bytes())
- dec.printData(0, id)
+ if countPresent {
+ dec.state.decodeUint()
+ }
+ dec.debugPrint(indent, id)
break
}
- if dec.state.err != nil {
- log.Stderr("debug:", dec.state.err)
- }
}
-func (dec *Decoder) printType(id typeId) {
+func (dec *Decoder) debugRecvType(id typeId) {
// Have we already seen this type? That's an error
if _, alreadySeen := dec.wireType[id]; alreadySeen {
- dec.state.err = os.ErrorString("gob: duplicate type received")
+ dec.err = os.ErrorString("gob: duplicate type received")
return
}
// Type:
wire := new(wireType)
- dec.state.err = dec.decode(tWireType, wire)
- if dec.state.err == nil {
+ dec.err = dec.decode(tWireType, reflect.NewValue(wire))
+ if dec.err == nil {
printWireType(wire)
}
// Remember we've seen this type.
dec.wireType[id] = wire
+
+ // Load the next parcel.
+ dec.debugRecv()
}
func printWireType(wire *wireType) {
+ fmt.Printf("type definition {\n")
switch {
- case wire.array != nil:
- printCommonType("array", &wire.array.commonType)
- fmt.Printf("\tlen %d\n\telemid %d\n", wire.array.Len, wire.array.Elem)
- case wire.slice != nil:
- printCommonType("slice", &wire.slice.commonType)
- fmt.Printf("\telemid %d\n", wire.slice.Elem)
- case wire.strct != nil:
- printCommonType("struct", &wire.strct.commonType)
- for i, field := range wire.strct.field {
- fmt.Printf("\tfield %d:\t%s\tid=%d\n", i, field.name, field.id)
+ case wire.ArrayT != nil:
+ printCommonType("array", &wire.ArrayT.CommonType)
+ fmt.Printf("\tlen %d\n\telemid %d\n", wire.ArrayT.Len, wire.ArrayT.Elem)
+ case wire.MapT != nil:
+ printCommonType("map", &wire.MapT.CommonType)
+ fmt.Printf("\tkeyid %d\n", wire.MapT.Key)
+ fmt.Printf("\telemid %d\n", wire.MapT.Elem)
+ case wire.SliceT != nil:
+ printCommonType("slice", &wire.SliceT.CommonType)
+ fmt.Printf("\telemid %d\n", wire.SliceT.Elem)
+ case wire.StructT != nil:
+ printCommonType("struct", &wire.StructT.CommonType)
+ for i, field := range wire.StructT.Field {
+ fmt.Printf("\tfield %d:\t%s\tid=%d\n", i, field.Name, field.Id)
}
}
+ fmt.Printf("}\n")
}
-func printCommonType(kind string, common *commonType) {
- fmt.Printf("\t%s %s\n\tid: %d\n", kind, common.name, common._id)
+func printCommonType(kind string, common *CommonType) {
+ fmt.Printf("\t%s %q\n\tid: %d\n", kind, common.Name, common.Id)
}
-func (dec *Decoder) printData(indent int, id typeId) {
- if dec.state.err != nil {
- return
+func (dec *Decoder) debugPrint(indent int, id typeId) {
+ wire, ok := dec.wireType[id]
+ if ok && wire.StructT != nil {
+ dec.debugStruct(indent+1, id, wire)
+ } else {
+ dec.debugSingle(indent+1, id, wire)
}
+}
+
+func (dec *Decoder) debugSingle(indent int, id typeId, wire *wireType) {
// is it a builtin type?
_, ok := builtinIdToType[id]
+ if !ok && wire == nil {
+ errorf("type id %d not defined\n", id)
+ }
+ dec.state.decodeUint()
+ dec.printItem(indent, id)
+}
+
+func (dec *Decoder) printItem(indent int, id typeId) {
+ if dump {
+ fmt.Printf("print item %d bytes: % x\n", dec.state.b.Len(), dec.state.b.Bytes())
+ }
+ _, ok := builtinIdToType[id]
if ok {
dec.printBuiltin(indent, id)
return
}
wire, ok := dec.wireType[id]
if !ok {
- fmt.Printf("type id %d not defined\n", id)
- return
+ errorf("type id %d not defined\n", id)
}
switch {
- case wire.array != nil:
- dec.printArray(indent+1, wire)
- case wire.slice != nil:
- dec.printSlice(indent+1, wire)
- case wire.strct != nil:
- dec.printStruct(indent+1, wire)
+ case wire.ArrayT != nil:
+ dec.printArray(indent, wire)
+ case wire.MapT != nil:
+ dec.printMap(indent, wire)
+ case wire.SliceT != nil:
+ dec.printSlice(indent, wire)
+ case wire.StructT != nil:
+ dec.debugStruct(indent, id, wire)
}
}
func (dec *Decoder) printArray(indent int, wire *wireType) {
- elemId := wire.array.Elem
- n := int(decodeUint(dec.state))
- for i := 0; i < n && dec.state.err == nil; i++ {
- dec.printData(indent, elemId)
+ elemId := wire.ArrayT.Elem
+ n := int(dec.state.decodeUint())
+ for i := 0; i < n && dec.err == nil; i++ {
+ dec.printItem(indent, elemId)
}
- if n != wire.array.Len {
+ if n != wire.ArrayT.Len {
tab(indent)
- fmt.Printf("(wrong length for array: %d should be %d)\n", n, wire.array.Len)
+ fmt.Printf("(wrong length for array: %d should be %d)\n", n, wire.ArrayT.Len)
+ }
+}
+
+func (dec *Decoder) printMap(indent int, wire *wireType) {
+ keyId := wire.MapT.Key
+ elemId := wire.MapT.Elem
+ n := int(dec.state.decodeUint())
+ for i := 0; i < n && dec.err == nil; i++ {
+ dec.printItem(indent, keyId)
+ dec.printItem(indent+1, elemId)
}
}
func (dec *Decoder) printSlice(indent int, wire *wireType) {
- elemId := wire.slice.Elem
- n := int(decodeUint(dec.state))
- for i := 0; i < n && dec.state.err == nil; i++ {
- dec.printData(indent, elemId)
+ elemId := wire.SliceT.Elem
+ n := int(dec.state.decodeUint())
+ for i := 0; i < n && dec.err == nil; i++ {
+ dec.printItem(indent, elemId)
}
}
@@ -159,58 +238,73 @@ func (dec *Decoder) printBuiltin(indent int, id typeId) {
tab(indent)
switch id {
case tBool:
- if decodeInt(dec.state) == 0 {
- fmt.Printf("false")
+ if dec.state.decodeInt() == 0 {
+ fmt.Printf("false\n")
} else {
- fmt.Printf("true")
+ fmt.Printf("true\n")
}
case tInt:
- fmt.Printf("%d", decodeInt(dec.state))
+ fmt.Printf("%d\n", dec.state.decodeInt())
case tUint:
- fmt.Printf("%d", decodeUint(dec.state))
+ fmt.Printf("%d\n", dec.state.decodeUint())
case tFloat:
- fmt.Printf("%g", floatFromBits(decodeUint(dec.state)))
+ fmt.Printf("%g\n", floatFromBits(dec.state.decodeUint()))
case tBytes:
- b := make([]byte, decodeUint(dec.state))
+ b := make([]byte, dec.state.decodeUint())
dec.state.b.Read(b)
- fmt.Printf("% x", b)
+ fmt.Printf("% x\n", b)
case tString:
- b := make([]byte, decodeUint(dec.state))
+ b := make([]byte, dec.state.decodeUint())
+ dec.state.b.Read(b)
+ fmt.Printf("%q\n", b)
+ case tInterface:
+ b := make([]byte, dec.state.decodeUint())
dec.state.b.Read(b)
- fmt.Printf("%q", b)
+ if len(b) == 0 {
+ fmt.Printf("nil interface")
+ } else {
+ fmt.Printf("interface value; type %q\n", b)
+ dec.debugFromBuffer(indent, true)
+ }
default:
- fmt.Print("unknown")
+ fmt.Print("unknown\n")
}
- fmt.Print("\n")
}
-func (dec *Decoder) printStruct(indent int, wire *wireType) {
- strct := wire.strct
- state := newDecodeState(dec.state.b)
+func (dec *Decoder) debugStruct(indent int, id typeId, wire *wireType) {
+ tab(indent)
+ fmt.Printf("%s struct {\n", id.name())
+ strct := wire.StructT
+ state := newDecodeState(dec, dec.state.b)
state.fieldnum = -1
- for state.err == nil {
- delta := int(decodeUint(state))
+ for dec.err == nil {
+ delta := int(state.decodeUint())
if delta < 0 {
- dec.state.err = os.ErrorString("gob decode: corrupted data: negative delta")
- return
+ errorf("gob decode: corrupted data: negative delta")
}
- if state.err != nil || delta == 0 { // struct terminator is zero delta fieldnum
- return
+ if delta == 0 { // struct terminator is zero delta fieldnum
+ break
}
- fieldnum := state.fieldnum + delta
- if fieldnum < 0 || fieldnum >= len(strct.field) {
- dec.state.err = os.ErrorString("field number out of range")
- return
+ fieldNum := state.fieldnum + delta
+ if fieldNum < 0 || fieldNum >= len(strct.Field) {
+ errorf("field number out of range")
+ break
}
tab(indent)
- fmt.Printf("field %d:\n", fieldnum)
- dec.printData(indent+1, strct.field[fieldnum].id)
- state.fieldnum = fieldnum
+ fmt.Printf("%s(%d):\n", wire.StructT.Field[fieldNum].Name, fieldNum)
+ dec.printItem(indent+1, strct.Field[fieldNum].Id)
+ state.fieldnum = fieldNum
}
+ tab(indent)
+ fmt.Printf(" } // end %s struct\n", id.name())
}
func tab(indent int) {
- for i := 0; i < indent; i++ {
- fmt.Print("\t")
+ for i, w := 0, 0; i < indent; i += w {
+ w = 10
+ if i+w > indent {
+ w = indent - i
+ }
+ fmt.Print("\t\t\t\t\t\t\t\t\t\t"[:w])
}
}
diff --git a/src/pkg/gob/decode.go b/src/pkg/gob/decode.go
index a70799e9a..f88ca72da 100644
--- a/src/pkg/gob/decode.go
+++ b/src/pkg/gob/decode.go
@@ -13,7 +13,9 @@ import (
"math"
"os"
"reflect"
+ "unicode"
"unsafe"
+ "utf8"
)
var (
@@ -22,16 +24,20 @@ var (
errRange = os.ErrorString("gob: internal error: field numbers out of bounds")
)
-// The global execution state of an instance of the decoder.
+// The execution state of an instance of the decoder. A new state
+// is created for nested objects.
type decodeState struct {
- b *bytes.Buffer
- err os.Error
+ dec *Decoder
+ // The buffer is stored with an extra indirection because it may be replaced
+ // if we load a type during decode (when reading an interface value).
+ b **bytes.Buffer
fieldnum int // the last field number read.
buf []byte
}
-func newDecodeState(b *bytes.Buffer) *decodeState {
+func newDecodeState(dec *Decoder, b **bytes.Buffer) *decodeState {
d := new(decodeState)
+ d.dec = dec
d.b = b
d.buf = make([]byte, uint64Size)
return d
@@ -74,24 +80,23 @@ func decodeUintReader(r io.Reader, buf []byte) (x uint64, err os.Error) {
}
// decodeUint reads an encoded unsigned integer from state.r.
-// Sets state.err. If state.err is already non-nil, it does nothing.
// Does not check for overflow.
-func decodeUint(state *decodeState) (x uint64) {
- if state.err != nil {
- return
+func (state *decodeState) decodeUint() (x uint64) {
+ b, err := state.b.ReadByte()
+ if err != nil {
+ error(err)
}
- var b uint8
- b, state.err = state.b.ReadByte()
- if b <= 0x7f { // includes state.err != nil
+ if b <= 0x7f {
return uint64(b)
}
nb := -int(int8(b))
if nb > uint64Size {
- state.err = errBadUint
- return
+ error(errBadUint)
+ }
+ n, err := state.b.Read(state.buf[0:nb])
+ if err != nil {
+ error(err)
}
- var n int
- n, state.err = state.b.Read(state.buf[0:nb])
// 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++ {
@@ -102,13 +107,9 @@ func decodeUint(state *decodeState) (x uint64) {
}
// decodeInt reads an encoded signed integer from state.r.
-// Sets state.err. If state.err is already non-nil, it does nothing.
// Does not check for overflow.
-func decodeInt(state *decodeState) int64 {
- x := decodeUint(state)
- if state.err != nil {
- return 0
- }
+func (state *decodeState) decodeInt() int64 {
+ x := state.decodeUint()
if x&1 != 0 {
return ^int64(x >> 1)
}
@@ -146,12 +147,12 @@ func decIndirect(p unsafe.Pointer, indir int) unsafe.Pointer {
}
func ignoreUint(i *decInstr, state *decodeState, p unsafe.Pointer) {
- decodeUint(state)
+ state.decodeUint()
}
func ignoreTwoUints(i *decInstr, state *decodeState, p unsafe.Pointer) {
- decodeUint(state)
- decodeUint(state)
+ state.decodeUint()
+ state.decodeUint()
}
func decBool(i *decInstr, state *decodeState, p unsafe.Pointer) {
@@ -161,7 +162,7 @@ func decBool(i *decInstr, state *decodeState, p unsafe.Pointer) {
}
p = *(*unsafe.Pointer)(p)
}
- *(*bool)(p) = decodeInt(state) != 0
+ *(*bool)(p) = state.decodeInt() != 0
}
func decInt8(i *decInstr, state *decodeState, p unsafe.Pointer) {
@@ -171,9 +172,9 @@ func decInt8(i *decInstr, state *decodeState, p unsafe.Pointer) {
}
p = *(*unsafe.Pointer)(p)
}
- v := decodeInt(state)
+ v := state.decodeInt()
if v < math.MinInt8 || math.MaxInt8 < v {
- state.err = i.ovfl
+ error(i.ovfl)
} else {
*(*int8)(p) = int8(v)
}
@@ -186,9 +187,9 @@ func decUint8(i *decInstr, state *decodeState, p unsafe.Pointer) {
}
p = *(*unsafe.Pointer)(p)
}
- v := decodeUint(state)
+ v := state.decodeUint()
if math.MaxUint8 < v {
- state.err = i.ovfl
+ error(i.ovfl)
} else {
*(*uint8)(p) = uint8(v)
}
@@ -201,9 +202,9 @@ func decInt16(i *decInstr, state *decodeState, p unsafe.Pointer) {
}
p = *(*unsafe.Pointer)(p)
}
- v := decodeInt(state)
+ v := state.decodeInt()
if v < math.MinInt16 || math.MaxInt16 < v {
- state.err = i.ovfl
+ error(i.ovfl)
} else {
*(*int16)(p) = int16(v)
}
@@ -216,9 +217,9 @@ func decUint16(i *decInstr, state *decodeState, p unsafe.Pointer) {
}
p = *(*unsafe.Pointer)(p)
}
- v := decodeUint(state)
+ v := state.decodeUint()
if math.MaxUint16 < v {
- state.err = i.ovfl
+ error(i.ovfl)
} else {
*(*uint16)(p) = uint16(v)
}
@@ -231,9 +232,9 @@ func decInt32(i *decInstr, state *decodeState, p unsafe.Pointer) {
}
p = *(*unsafe.Pointer)(p)
}
- v := decodeInt(state)
+ v := state.decodeInt()
if v < math.MinInt32 || math.MaxInt32 < v {
- state.err = i.ovfl
+ error(i.ovfl)
} else {
*(*int32)(p) = int32(v)
}
@@ -246,9 +247,9 @@ func decUint32(i *decInstr, state *decodeState, p unsafe.Pointer) {
}
p = *(*unsafe.Pointer)(p)
}
- v := decodeUint(state)
+ v := state.decodeUint()
if math.MaxUint32 < v {
- state.err = i.ovfl
+ error(i.ovfl)
} else {
*(*uint32)(p) = uint32(v)
}
@@ -261,7 +262,7 @@ func decInt64(i *decInstr, state *decodeState, p unsafe.Pointer) {
}
p = *(*unsafe.Pointer)(p)
}
- *(*int64)(p) = int64(decodeInt(state))
+ *(*int64)(p) = int64(state.decodeInt())
}
func decUint64(i *decInstr, state *decodeState, p unsafe.Pointer) {
@@ -271,7 +272,7 @@ func decUint64(i *decInstr, state *decodeState, p unsafe.Pointer) {
}
p = *(*unsafe.Pointer)(p)
}
- *(*uint64)(p) = uint64(decodeUint(state))
+ *(*uint64)(p) = uint64(state.decodeUint())
}
// Floating-point numbers are transmitted as uint64s holding the bits
@@ -290,14 +291,14 @@ func floatFromBits(u uint64) float64 {
}
func storeFloat32(i *decInstr, state *decodeState, p unsafe.Pointer) {
- v := floatFromBits(decodeUint(state))
+ v := floatFromBits(state.decodeUint())
av := v
if av < 0 {
av = -av
}
// +Inf is OK in both 32- and 64-bit floats. Underflow is always OK.
if math.MaxFloat32 < av && av <= math.MaxFloat64 {
- state.err = i.ovfl
+ error(i.ovfl)
} else {
*(*float32)(p) = float32(v)
}
@@ -320,7 +321,7 @@ func decFloat64(i *decInstr, state *decodeState, p unsafe.Pointer) {
}
p = *(*unsafe.Pointer)(p)
}
- *(*float64)(p) = floatFromBits(uint64(decodeUint(state)))
+ *(*float64)(p) = floatFromBits(uint64(state.decodeUint()))
}
// Complex numbers are just a pair of floating-point numbers, real part first.
@@ -342,8 +343,8 @@ func decComplex128(i *decInstr, state *decodeState, p unsafe.Pointer) {
}
p = *(*unsafe.Pointer)(p)
}
- real := floatFromBits(uint64(decodeUint(state)))
- imag := floatFromBits(uint64(decodeUint(state)))
+ real := floatFromBits(uint64(state.decodeUint()))
+ imag := floatFromBits(uint64(state.decodeUint()))
*(*complex128)(p) = cmplx(real, imag)
}
@@ -355,7 +356,7 @@ func decUint8Array(i *decInstr, state *decodeState, p unsafe.Pointer) {
}
p = *(*unsafe.Pointer)(p)
}
- b := make([]uint8, decodeUint(state))
+ b := make([]uint8, state.decodeUint())
state.b.Read(b)
*(*[]uint8)(p) = b
}
@@ -368,13 +369,13 @@ func decString(i *decInstr, state *decodeState, p unsafe.Pointer) {
}
p = *(*unsafe.Pointer)(p)
}
- b := make([]byte, decodeUint(state))
+ b := make([]byte, state.decodeUint())
state.b.Read(b)
*(*string)(p) = string(b)
}
func ignoreUint8Array(i *decInstr, state *decodeState, p unsafe.Pointer) {
- b := make([]byte, decodeUint(state))
+ b := make([]byte, state.decodeUint())
state.b.Read(b)
}
@@ -404,15 +405,15 @@ func allocate(rtyp reflect.Type, p uintptr, indir int) uintptr {
return *(*uintptr)(up)
}
-func decodeSingle(engine *decEngine, rtyp reflect.Type, b *bytes.Buffer, p uintptr, indir int) os.Error {
+func (dec *Decoder) decodeSingle(engine *decEngine, rtyp reflect.Type, b **bytes.Buffer, p uintptr, indir int) (err os.Error) {
+ defer catchError(&err)
p = allocate(rtyp, p, indir)
- state := newDecodeState(b)
+ state := newDecodeState(dec, b)
state.fieldnum = singletonField
basep := p
- delta := int(decodeUint(state))
+ delta := int(state.decodeUint())
if delta != 0 {
- state.err = os.ErrorString("gob decode: corrupted data: non-zero delta for singleton")
- return state.err
+ errorf("gob decode: corrupted data: non-zero delta for singleton")
}
instr := &engine.instr[singletonField]
ptr := unsafe.Pointer(basep) // offset will be zero
@@ -420,26 +421,26 @@ func decodeSingle(engine *decEngine, rtyp reflect.Type, b *bytes.Buffer, p uintp
ptr = decIndirect(ptr, instr.indir)
}
instr.op(instr, state, ptr)
- return state.err
+ return nil
}
-func decodeStruct(engine *decEngine, rtyp *reflect.StructType, b *bytes.Buffer, p uintptr, indir int) os.Error {
+func (dec *Decoder) decodeStruct(engine *decEngine, rtyp *reflect.StructType, b **bytes.Buffer, p uintptr, indir int) (err os.Error) {
+ defer catchError(&err)
p = allocate(rtyp, p, indir)
- state := newDecodeState(b)
+ state := newDecodeState(dec, b)
state.fieldnum = -1
basep := p
- for state.err == nil {
- delta := int(decodeUint(state))
+ for state.b.Len() > 0 {
+ delta := int(state.decodeUint())
if delta < 0 {
- state.err = os.ErrorString("gob decode: corrupted data: negative delta")
- break
+ errorf("gob decode: corrupted data: negative delta")
}
- if state.err != nil || delta == 0 { // struct terminator is zero delta fieldnum
+ if delta == 0 { // struct terminator is zero delta fieldnum
break
}
fieldnum := state.fieldnum + delta
if fieldnum >= len(engine.instr) {
- state.err = errRange
+ error(errRange)
break
}
instr := &engine.instr[fieldnum]
@@ -450,36 +451,35 @@ func decodeStruct(engine *decEngine, rtyp *reflect.StructType, b *bytes.Buffer,
instr.op(instr, state, p)
state.fieldnum = fieldnum
}
- return state.err
+ return nil
}
-func ignoreStruct(engine *decEngine, b *bytes.Buffer) os.Error {
- state := newDecodeState(b)
+func (dec *Decoder) ignoreStruct(engine *decEngine, b **bytes.Buffer) (err os.Error) {
+ defer catchError(&err)
+ state := newDecodeState(dec, b)
state.fieldnum = -1
- for state.err == nil {
- delta := int(decodeUint(state))
+ for state.b.Len() > 0 {
+ delta := int(state.decodeUint())
if delta < 0 {
- state.err = os.ErrorString("gob ignore decode: corrupted data: negative delta")
- break
+ errorf("gob ignore decode: corrupted data: negative delta")
}
- if state.err != nil || delta == 0 { // struct terminator is zero delta fieldnum
+ if delta == 0 { // struct terminator is zero delta fieldnum
break
}
fieldnum := state.fieldnum + delta
if fieldnum >= len(engine.instr) {
- state.err = errRange
- break
+ error(errRange)
}
instr := &engine.instr[fieldnum]
instr.op(instr, state, unsafe.Pointer(nil))
state.fieldnum = fieldnum
}
- return state.err
+ return nil
}
-func decodeArrayHelper(state *decodeState, p uintptr, elemOp decOp, elemWid uintptr, length, elemIndir int, ovfl os.ErrorString) os.Error {
+func (dec *Decoder) decodeArrayHelper(state *decodeState, p uintptr, elemOp decOp, elemWid uintptr, length, elemIndir int, ovfl os.ErrorString) {
instr := &decInstr{elemOp, 0, elemIndir, 0, ovfl}
- for i := 0; i < length && state.err == nil; i++ {
+ for i := 0; i < length; i++ {
up := unsafe.Pointer(p)
if elemIndir > 1 {
up = decIndirect(up, elemIndir)
@@ -487,17 +487,16 @@ func decodeArrayHelper(state *decodeState, p uintptr, elemOp decOp, elemWid uint
elemOp(instr, state, up)
p += uintptr(elemWid)
}
- return state.err
}
-func decodeArray(atyp *reflect.ArrayType, state *decodeState, p uintptr, elemOp decOp, elemWid uintptr, length, indir, elemIndir int, ovfl os.ErrorString) os.Error {
+func (dec *Decoder) decodeArray(atyp *reflect.ArrayType, state *decodeState, p uintptr, elemOp decOp, elemWid uintptr, length, indir, elemIndir int, ovfl os.ErrorString) {
if indir > 0 {
p = allocate(atyp, p, 1) // All but the last level has been allocated by dec.Indirect
}
- if n := decodeUint(state); n != uint64(length) {
- return os.ErrorString("gob: length mismatch in decodeArray")
+ if n := state.decodeUint(); n != uint64(length) {
+ errorf("gob: length mismatch in decodeArray")
}
- return decodeArrayHelper(state, p, elemOp, elemWid, length, elemIndir, ovfl)
+ dec.decodeArrayHelper(state, p, elemOp, elemWid, length, elemIndir, ovfl)
}
func decodeIntoValue(state *decodeState, op decOp, indir int, v reflect.Value, ovfl os.ErrorString) reflect.Value {
@@ -510,7 +509,7 @@ func decodeIntoValue(state *decodeState, op decOp, indir int, v reflect.Value, o
return v
}
-func decodeMap(mtyp *reflect.MapType, state *decodeState, p uintptr, keyOp, elemOp decOp, indir, keyIndir, elemIndir int, ovfl os.ErrorString) os.Error {
+func (dec *Decoder) decodeMap(mtyp *reflect.MapType, state *decodeState, p uintptr, keyOp, elemOp decOp, indir, keyIndir, elemIndir int, ovfl os.ErrorString) {
if indir > 0 {
p = allocate(mtyp, p, 1) // All but the last level has been allocated by dec.Indirect
}
@@ -523,50 +522,40 @@ func decodeMap(mtyp *reflect.MapType, state *decodeState, p uintptr, keyOp, elem
// that slices etc. can. We must recover a full reflection value for
// the iteration.
v := reflect.NewValue(unsafe.Unreflect(mtyp, unsafe.Pointer((p)))).(*reflect.MapValue)
- n := int(decodeUint(state))
- for i := 0; i < n && state.err == nil; i++ {
+ n := int(state.decodeUint())
+ for i := 0; i < n; i++ {
key := decodeIntoValue(state, keyOp, keyIndir, reflect.MakeZero(mtyp.Key()), ovfl)
- if state.err != nil {
- break
- }
elem := decodeIntoValue(state, elemOp, elemIndir, reflect.MakeZero(mtyp.Elem()), ovfl)
- if state.err != nil {
- break
- }
v.SetElem(key, elem)
}
- return state.err
}
-func ignoreArrayHelper(state *decodeState, elemOp decOp, length int) os.Error {
+func (dec *Decoder) ignoreArrayHelper(state *decodeState, elemOp decOp, length int) {
instr := &decInstr{elemOp, 0, 0, 0, os.ErrorString("no error")}
- for i := 0; i < length && state.err == nil; i++ {
+ for i := 0; i < length; i++ {
elemOp(instr, state, nil)
}
- return state.err
}
-func ignoreArray(state *decodeState, elemOp decOp, length int) os.Error {
- if n := decodeUint(state); n != uint64(length) {
- return os.ErrorString("gob: length mismatch in ignoreArray")
+func (dec *Decoder) ignoreArray(state *decodeState, elemOp decOp, length int) {
+ if n := state.decodeUint(); n != uint64(length) {
+ errorf("gob: length mismatch in ignoreArray")
}
- return ignoreArrayHelper(state, elemOp, length)
+ dec.ignoreArrayHelper(state, elemOp, length)
}
-func ignoreMap(state *decodeState, keyOp, elemOp decOp) os.Error {
- n := int(decodeUint(state))
+func (dec *Decoder) ignoreMap(state *decodeState, keyOp, elemOp decOp) {
+ n := int(state.decodeUint())
keyInstr := &decInstr{keyOp, 0, 0, 0, os.ErrorString("no error")}
elemInstr := &decInstr{elemOp, 0, 0, 0, os.ErrorString("no error")}
- for i := 0; i < n && state.err == nil; i++ {
+ for i := 0; i < n; i++ {
keyOp(keyInstr, state, nil)
elemOp(elemInstr, state, nil)
}
- return state.err
}
-
-func decodeSlice(atyp *reflect.SliceType, state *decodeState, p uintptr, elemOp decOp, elemWid uintptr, indir, elemIndir int, ovfl os.ErrorString) os.Error {
- n := int(uintptr(decodeUint(state)))
+func (dec *Decoder) decodeSlice(atyp *reflect.SliceType, state *decodeState, p uintptr, elemOp decOp, elemWid uintptr, indir, elemIndir int, ovfl os.ErrorString) {
+ n := int(uintptr(state.decodeUint()))
if indir > 0 {
up := unsafe.Pointer(p)
if *(*unsafe.Pointer)(up) == nil {
@@ -581,11 +570,77 @@ func decodeSlice(atyp *reflect.SliceType, state *decodeState, p uintptr, elemOp
hdrp.Data = uintptr(unsafe.NewArray(atyp.Elem(), n))
hdrp.Len = n
hdrp.Cap = n
- return decodeArrayHelper(state, hdrp.Data, elemOp, elemWid, n, elemIndir, ovfl)
+ dec.decodeArrayHelper(state, hdrp.Data, elemOp, elemWid, n, elemIndir, ovfl)
}
-func ignoreSlice(state *decodeState, elemOp decOp) os.Error {
- return ignoreArrayHelper(state, elemOp, int(decodeUint(state)))
+func (dec *Decoder) ignoreSlice(state *decodeState, elemOp decOp) {
+ dec.ignoreArrayHelper(state, elemOp, int(state.decodeUint()))
+}
+
+// setInterfaceValue sets an interface value to a concrete value through
+// reflection. If the concrete value does not implement the interface, the
+// setting will panic. This routine turns the panic into an error return.
+// This dance avoids manually checking that the value satisfies the
+// interface.
+// TODO(rsc): avoid panic+recover after fixing issue 327.
+func setInterfaceValue(ivalue *reflect.InterfaceValue, value reflect.Value) {
+ defer func() {
+ if e := recover(); e != nil {
+ error(e.(os.Error))
+ }
+ }()
+ ivalue.Set(value)
+}
+
+// decodeInterface receives the name of a concrete type followed by its value.
+// If the name is empty, the value is nil and no value is sent.
+func (dec *Decoder) decodeInterface(ityp *reflect.InterfaceType, state *decodeState, p uintptr, indir int) {
+ // Create an interface reflect.Value. We need one even for the nil case.
+ ivalue := reflect.MakeZero(ityp).(*reflect.InterfaceValue)
+ // Read the name of the concrete type.
+ b := make([]byte, state.decodeUint())
+ state.b.Read(b)
+ name := string(b)
+ if name == "" {
+ // Copy the representation of the nil interface value to the target.
+ // This is horribly unsafe and special.
+ *(*[2]uintptr)(unsafe.Pointer(p)) = ivalue.Get()
+ return
+ }
+ // The concrete type must be registered.
+ typ, ok := nameToConcreteType[name]
+ if !ok {
+ errorf("gob: name not registered for interface: %q", name)
+ }
+ // Read the concrete value.
+ value := reflect.MakeZero(typ)
+ dec.decodeValueFromBuffer(value, false, true)
+ if dec.err != nil {
+ error(dec.err)
+ }
+ // Allocate the destination interface value.
+ if indir > 0 {
+ p = allocate(ityp, p, 1) // All but the last level has been allocated by dec.Indirect
+ }
+ // Assign the concrete value to the interface.
+ // Tread carefully; it might not satisfy the interface.
+ setInterfaceValue(ivalue, value)
+ // Copy the representation of the interface value to the target.
+ // This is horribly unsafe and special.
+ *(*[2]uintptr)(unsafe.Pointer(p)) = ivalue.Get()
+}
+
+func (dec *Decoder) ignoreInterface(state *decodeState) {
+ // Read the name of the concrete type.
+ b := make([]byte, state.decodeUint())
+ _, err := state.b.Read(b)
+ if err != nil {
+ error(err)
+ }
+ dec.decodeValueFromBuffer(nil, true, true)
+ if dec.err != nil {
+ error(err)
+ }
}
// Index by Go types.
@@ -608,17 +663,18 @@ var decOpMap = []decOp{
// Indexed by gob types. tComplex will be added during type.init().
var decIgnoreOpMap = map[typeId]decOp{
- tBool: ignoreUint,
- tInt: ignoreUint,
- tUint: ignoreUint,
- tFloat: ignoreUint,
- tBytes: ignoreUint8Array,
- tString: ignoreUint8Array,
+ tBool: ignoreUint,
+ tInt: ignoreUint,
+ tUint: ignoreUint,
+ tFloat: ignoreUint,
+ tBytes: ignoreUint8Array,
+ tString: ignoreUint8Array,
+ tComplex: ignoreTwoUints,
}
// Return the decoding op for the base type under rt and
// the indirection count to reach it.
-func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string) (decOp, int, os.Error) {
+func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string) (decOp, int) {
typ, indir := indirect(rt)
var op decOp
k := typ.Kind()
@@ -630,32 +686,23 @@ func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string) (decOp
switch t := typ.(type) {
case *reflect.ArrayType:
name = "element of " + name
- elemId := dec.wireType[wireId].arrayT.Elem
- elemOp, elemIndir, err := dec.decOpFor(elemId, t.Elem(), name)
- if err != nil {
- return nil, 0, err
- }
+ elemId := dec.wireType[wireId].ArrayT.Elem
+ elemOp, elemIndir := dec.decOpFor(elemId, t.Elem(), name)
ovfl := overflow(name)
op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
- state.err = decodeArray(t, state, uintptr(p), elemOp, t.Elem().Size(), t.Len(), i.indir, elemIndir, ovfl)
+ state.dec.decodeArray(t, state, uintptr(p), elemOp, t.Elem().Size(), t.Len(), i.indir, elemIndir, ovfl)
}
case *reflect.MapType:
name = "element of " + name
- keyId := dec.wireType[wireId].mapT.Key
- elemId := dec.wireType[wireId].mapT.Elem
- keyOp, keyIndir, err := dec.decOpFor(keyId, t.Key(), name)
- if err != nil {
- return nil, 0, err
- }
- elemOp, elemIndir, err := dec.decOpFor(elemId, t.Elem(), name)
- if err != nil {
- return nil, 0, err
- }
+ keyId := dec.wireType[wireId].MapT.Key
+ elemId := dec.wireType[wireId].MapT.Elem
+ keyOp, keyIndir := dec.decOpFor(keyId, t.Key(), name)
+ elemOp, elemIndir := dec.decOpFor(elemId, t.Elem(), name)
ovfl := overflow(name)
op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
up := unsafe.Pointer(p)
- state.err = decodeMap(t, state, uintptr(up), keyOp, elemOp, i.indir, keyIndir, elemIndir, ovfl)
+ state.dec.decodeMap(t, state, uintptr(up), keyOp, elemOp, i.indir, keyIndir, elemIndir, ovfl)
}
case *reflect.SliceType:
@@ -668,111 +715,105 @@ func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string) (decOp
if tt, ok := builtinIdToType[wireId]; ok {
elemId = tt.(*sliceType).Elem
} else {
- elemId = dec.wireType[wireId].sliceT.Elem
- }
- elemOp, elemIndir, err := dec.decOpFor(elemId, t.Elem(), name)
- if err != nil {
- return nil, 0, err
+ elemId = dec.wireType[wireId].SliceT.Elem
}
+ elemOp, elemIndir := dec.decOpFor(elemId, t.Elem(), name)
ovfl := overflow(name)
op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
- state.err = decodeSlice(t, state, uintptr(p), elemOp, t.Elem().Size(), i.indir, elemIndir, ovfl)
+ state.dec.decodeSlice(t, state, uintptr(p), elemOp, t.Elem().Size(), i.indir, elemIndir, ovfl)
}
case *reflect.StructType:
// Generate a closure that calls out to the engine for the nested type.
enginePtr, err := dec.getDecEnginePtr(wireId, typ)
if err != nil {
- return nil, 0, err
+ error(err)
}
op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
// indirect through enginePtr to delay evaluation for recursive structs
- state.err = decodeStruct(*enginePtr, t, state.b, uintptr(p), i.indir)
+ err = dec.decodeStruct(*enginePtr, t, state.b, uintptr(p), i.indir)
+ if err != nil {
+ error(err)
+ }
+ }
+ case *reflect.InterfaceType:
+ op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
+ dec.decodeInterface(t, state, uintptr(p), i.indir)
}
}
}
if op == nil {
- return nil, 0, os.ErrorString("gob: decode can't handle type " + rt.String())
+ errorf("gob: decode can't handle type %s", rt.String())
}
- return op, indir, nil
+ return op, indir
}
// Return the decoding op for a field that has no destination.
-func (dec *Decoder) decIgnoreOpFor(wireId typeId) (decOp, os.Error) {
+func (dec *Decoder) decIgnoreOpFor(wireId typeId) decOp {
op, ok := decIgnoreOpMap[wireId]
if !ok {
+ if wireId == tInterface {
+ // Special case because it's a method: the ignored item might
+ // define types and we need to record their state in the decoder.
+ op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
+ dec.ignoreInterface(state)
+ }
+ return op
+ }
// Special cases
wire := dec.wireType[wireId]
switch {
case wire == nil:
panic("internal error: can't find ignore op for type " + wireId.string())
- case wire.arrayT != nil:
- elemId := wire.arrayT.Elem
- elemOp, err := dec.decIgnoreOpFor(elemId)
- if err != nil {
- return nil, err
- }
+ case wire.ArrayT != nil:
+ elemId := wire.ArrayT.Elem
+ elemOp := dec.decIgnoreOpFor(elemId)
op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
- state.err = ignoreArray(state, elemOp, wire.arrayT.Len)
+ state.dec.ignoreArray(state, elemOp, wire.ArrayT.Len)
}
- case wire.mapT != nil:
- keyId := dec.wireType[wireId].mapT.Key
- elemId := dec.wireType[wireId].mapT.Elem
- keyOp, err := dec.decIgnoreOpFor(keyId)
- if err != nil {
- return nil, err
- }
- elemOp, err := dec.decIgnoreOpFor(elemId)
- if err != nil {
- return nil, err
- }
+ case wire.MapT != nil:
+ keyId := dec.wireType[wireId].MapT.Key
+ elemId := dec.wireType[wireId].MapT.Elem
+ keyOp := dec.decIgnoreOpFor(keyId)
+ elemOp := dec.decIgnoreOpFor(elemId)
op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
- state.err = ignoreMap(state, keyOp, elemOp)
+ state.dec.ignoreMap(state, keyOp, elemOp)
}
- case wire.sliceT != nil:
- elemId := wire.sliceT.Elem
- elemOp, err := dec.decIgnoreOpFor(elemId)
- if err != nil {
- return nil, err
- }
+ case wire.SliceT != nil:
+ elemId := wire.SliceT.Elem
+ elemOp := dec.decIgnoreOpFor(elemId)
op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
- state.err = ignoreSlice(state, elemOp)
+ state.dec.ignoreSlice(state, elemOp)
}
- case wire.structT != nil:
+ case wire.StructT != nil:
// Generate a closure that calls out to the engine for the nested type.
enginePtr, err := dec.getIgnoreEnginePtr(wireId)
if err != nil {
- return nil, err
+ error(err)
}
op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
// indirect through enginePtr to delay evaluation for recursive structs
- state.err = ignoreStruct(*enginePtr, state.b)
+ state.dec.ignoreStruct(*enginePtr, state.b)
}
}
}
if op == nil {
- return nil, os.ErrorString("ignore can't handle type " + wireId.string())
+ errorf("ignore can't handle type %s", wireId.string())
}
- return op, nil
+ return op
}
// Are these two gob Types compatible?
// Answers the question for basic types, arrays, and slices.
// Structs are considered ok; fields will be checked later.
func (dec *Decoder) compatibleType(fr reflect.Type, fw typeId) bool {
- for {
- if pt, ok := fr.(*reflect.PtrType); ok {
- fr = pt.Elem()
- continue
- }
- break
- }
+ fr, _ = indirect(fr)
switch t := fr.(type) {
default:
- // interface, map, chan, etc: cannot handle.
+ // map, chan, etc: cannot handle.
return false
case *reflect.BoolType:
return fw == tBool
@@ -786,20 +827,22 @@ func (dec *Decoder) compatibleType(fr reflect.Type, fw typeId) bool {
return fw == tComplex
case *reflect.StringType:
return fw == tString
+ case *reflect.InterfaceType:
+ return fw == tInterface
case *reflect.ArrayType:
wire, ok := dec.wireType[fw]
- if !ok || wire.arrayT == nil {
+ if !ok || wire.ArrayT == nil {
return false
}
- array := wire.arrayT
+ array := wire.ArrayT
return t.Len() == array.Len && dec.compatibleType(t.Elem(), array.Elem)
case *reflect.MapType:
wire, ok := dec.wireType[fw]
- if !ok || wire.mapT == nil {
+ if !ok || wire.MapT == nil {
return false
}
- mapType := wire.mapT
- return dec.compatibleType(t.Key(), mapType.Key) && dec.compatibleType(t.Elem(), mapType.Elem)
+ MapType := wire.MapT
+ return dec.compatibleType(t.Key(), MapType.Key) && dec.compatibleType(t.Elem(), MapType.Elem)
case *reflect.SliceType:
// Is it an array of bytes?
if t.Elem().Kind() == reflect.Uint8 {
@@ -810,7 +853,7 @@ func (dec *Decoder) compatibleType(fr reflect.Type, fw typeId) bool {
if tt, ok := builtinIdToType[fw]; ok {
sw = tt.(*sliceType)
} else {
- sw = dec.wireType[fw].sliceT
+ sw = dec.wireType[fw].SliceT
}
elem, _ := indirect(t.Elem())
return sw != nil && dec.compatibleType(elem, sw.Elem)
@@ -820,61 +863,74 @@ func (dec *Decoder) compatibleType(fr reflect.Type, fw typeId) bool {
return true
}
+// typeString returns a human-readable description of the type identified by remoteId.
+func (dec *Decoder) typeString(remoteId typeId) string {
+ if t := idToType[remoteId]; t != nil {
+ // globally known type.
+ return t.string()
+ }
+ return dec.wireType[remoteId].string()
+}
+
+
func (dec *Decoder) compileSingle(remoteId typeId, rt reflect.Type) (engine *decEngine, err os.Error) {
engine = new(decEngine)
engine.instr = make([]decInstr, 1) // one item
name := rt.String() // best we can do
if !dec.compatibleType(rt, remoteId) {
- return nil, os.ErrorString("gob: wrong type received for local value " + name)
- }
- op, indir, err := dec.decOpFor(remoteId, rt, name)
- if err != nil {
- return nil, err
+ return nil, os.ErrorString("gob: wrong type received for local value " + name + ": " + dec.typeString(remoteId))
}
+ op, indir := dec.decOpFor(remoteId, rt, name)
ovfl := os.ErrorString(`value for "` + name + `" out of range`)
engine.instr[singletonField] = decInstr{op, singletonField, indir, 0, ovfl}
engine.numInstr = 1
return
}
+// Is this an exported - upper case - name?
+func isExported(name string) bool {
+ rune, _ := utf8.DecodeRuneInString(name)
+ return unicode.IsUpper(rune)
+}
+
func (dec *Decoder) compileDec(remoteId typeId, rt reflect.Type) (engine *decEngine, err os.Error) {
+ defer catchError(&err)
srt, ok := rt.(*reflect.StructType)
if !ok {
return dec.compileSingle(remoteId, rt)
}
var wireStruct *structType
- // Builtin types can come from global pool; the rest must be defined by the decoder
+ // Builtin types can come from global pool; the rest must be defined by the decoder.
+ // Also we know we're decoding a struct now, so the client must have sent one.
if t, ok := builtinIdToType[remoteId]; ok {
- wireStruct = t.(*structType)
+ wireStruct, _ = t.(*structType)
} else {
- wireStruct = dec.wireType[remoteId].structT
+ wireStruct = dec.wireType[remoteId].StructT
+ }
+ if wireStruct == nil {
+ errorf("gob: type mismatch in decoder: want struct type %s; got non-struct", rt.String())
}
engine = new(decEngine)
- engine.instr = make([]decInstr, len(wireStruct.field))
+ engine.instr = make([]decInstr, len(wireStruct.Field))
// Loop over the fields of the wire type.
- for fieldnum := 0; fieldnum < len(wireStruct.field); fieldnum++ {
- wireField := wireStruct.field[fieldnum]
+ for fieldnum := 0; fieldnum < len(wireStruct.Field); fieldnum++ {
+ wireField := wireStruct.Field[fieldnum]
+ if wireField.Name == "" {
+ errorf("gob: empty name for remote field of type %s", wireStruct.Name)
+ }
+ ovfl := overflow(wireField.Name)
// Find the field of the local type with the same name.
- localField, present := srt.FieldByName(wireField.name)
- ovfl := overflow(wireField.name)
+ localField, present := srt.FieldByName(wireField.Name)
// TODO(r): anonymous names
- if !present {
- op, err := dec.decIgnoreOpFor(wireField.id)
- if err != nil {
- return nil, err
- }
+ if !present || !isExported(wireField.Name) {
+ op := dec.decIgnoreOpFor(wireField.Id)
engine.instr[fieldnum] = decInstr{op, fieldnum, 0, 0, ovfl}
continue
}
- if !dec.compatibleType(localField.Type, wireField.id) {
- return nil, os.ErrorString("gob: wrong type (" +
- localField.Type.String() + ") for received field " +
- wireStruct.name + "." + wireField.name)
- }
- op, indir, err := dec.decOpFor(wireField.id, localField.Type, localField.Name)
- if err != nil {
- return nil, err
+ if !dec.compatibleType(localField.Type, wireField.Id) {
+ errorf("gob: wrong type (%s) for received field %s.%s", localField.Type, wireStruct.Name, wireField.Name)
}
+ op, indir := dec.decOpFor(wireField.Id, localField.Type, localField.Name)
engine.instr[fieldnum] = decInstr{op, fieldnum, indir, uintptr(localField.Offset), ovfl}
engine.numInstr++
}
@@ -899,7 +955,7 @@ func (dec *Decoder) getDecEnginePtr(remoteId typeId, rt reflect.Type) (enginePtr
return
}
-// When ignoring data, in effect we compile it into this type
+// When ignoring struct data, in effect we compile it into this type
type emptyStruct struct{}
var emptyStructType = reflect.Typeof(emptyStruct{})
@@ -927,13 +983,13 @@ func (dec *Decoder) decode(wireId typeId, val reflect.Value) os.Error {
}
engine := *enginePtr
if st, ok := rt.(*reflect.StructType); ok {
- if engine.numInstr == 0 && st.NumField() > 0 && len(dec.wireType[wireId].structT.field) > 0 {
+ if engine.numInstr == 0 && st.NumField() > 0 && len(dec.wireType[wireId].StructT.Field) > 0 {
name := rt.Name()
return os.ErrorString("gob: type mismatch: no fields matched compiling decoder for " + name)
}
- return decodeStruct(engine, st, dec.state.b, uintptr(val.Addr()), indir)
+ return dec.decodeStruct(engine, st, dec.state.b, uintptr(val.Addr()), indir)
}
- return decodeSingle(engine, rt, dec.state.b, uintptr(val.Addr()), indir)
+ return dec.decodeSingle(engine, rt, dec.state.b, uintptr(val.Addr()), indir)
}
func init() {
diff --git a/src/pkg/gob/decoder.go b/src/pkg/gob/decoder.go
index cf16433eb..664001a4b 100644
--- a/src/pkg/gob/decoder.go
+++ b/src/pkg/gob/decoder.go
@@ -24,6 +24,8 @@ type Decoder struct {
countState *decodeState // reads counts from wire
buf []byte
countBuf [9]byte // counts may be uint64s (unlikely!), require 9 bytes
+ byteBuffer *bytes.Buffer
+ err os.Error
}
// NewDecoder returns a new decoder that reads from the io.Reader.
@@ -31,25 +33,32 @@ func NewDecoder(r io.Reader) *Decoder {
dec := new(Decoder)
dec.r = r
dec.wireType = make(map[typeId]*wireType)
- dec.state = newDecodeState(nil) // buffer set in Decode(); rest is unimportant
+ dec.state = newDecodeState(dec, &dec.byteBuffer) // buffer set in Decode()
dec.decoderCache = make(map[reflect.Type]map[typeId]**decEngine)
dec.ignorerCache = make(map[typeId]**decEngine)
return dec
}
+// recvType loads the definition of a type and reloads the Decoder's buffer.
func (dec *Decoder) recvType(id typeId) {
// Have we already seen this type? That's an error
if dec.wireType[id] != nil {
- dec.state.err = os.ErrorString("gob: duplicate type received")
+ dec.err = os.ErrorString("gob: duplicate type received")
return
}
// Type:
wire := new(wireType)
- dec.state.err = dec.decode(tWireType, reflect.NewValue(wire))
+ dec.err = dec.decode(tWireType, reflect.NewValue(wire))
+ if dec.err != nil {
+ return
+ }
// Remember we've seen this type.
dec.wireType[id] = wire
+
+ // Load the next parcel.
+ dec.recv()
}
// Decode reads the next value from the connection and stores
@@ -61,69 +70,95 @@ 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.state.err = os.ErrorString("gob: attempt to decode into a non-pointer")
- return dec.state.err
+ dec.err = os.ErrorString("gob: attempt to decode into a non-pointer")
+ return dec.err
}
return dec.DecodeValue(value)
}
-// DecodeValue reads the next value from the connection and stores
-// it in the data represented by the reflection value.
-// The value must be the correct type for the next
-// data item received.
-func (dec *Decoder) DecodeValue(value reflect.Value) os.Error {
- // Make sure we're single-threaded through here.
- dec.mutex.Lock()
- defer dec.mutex.Unlock()
-
- dec.state.err = nil
- for {
- // Read a count.
- var nbytes uint64
- nbytes, dec.state.err = decodeUintReader(dec.r, dec.countBuf[0:])
- if dec.state.err != nil {
- break
- }
- // Allocate the buffer.
- if nbytes > uint64(len(dec.buf)) {
- dec.buf = make([]byte, nbytes+1000)
- }
- dec.state.b = bytes.NewBuffer(dec.buf[0:nbytes])
+// recv reads the next count-delimited item from the input. It is the converse
+// of Encoder.send.
+func (dec *Decoder) recv() {
+ // Read a count.
+ var nbytes uint64
+ nbytes, dec.err = decodeUintReader(dec.r, dec.countBuf[0:])
+ if dec.err != nil {
+ return
+ }
+ // Allocate the buffer.
+ if nbytes > uint64(len(dec.buf)) {
+ dec.buf = make([]byte, nbytes+1000)
+ }
+ dec.byteBuffer = bytes.NewBuffer(dec.buf[0:nbytes])
- // Read the data
- _, dec.state.err = io.ReadFull(dec.r, dec.buf[0:nbytes])
- if dec.state.err != nil {
- if dec.state.err == os.EOF {
- dec.state.err = io.ErrUnexpectedEOF
- }
- break
+ // Read the data
+ _, dec.err = io.ReadFull(dec.r, dec.buf[0:nbytes])
+ if dec.err != nil {
+ if dec.err == os.EOF {
+ dec.err = io.ErrUnexpectedEOF
}
+ return
+ }
+}
+// decodeValueFromBuffer grabs the next value from the input. The Decoder's
+// buffer already contains data. If the next item in the buffer is a type
+// descriptor, it may be necessary to reload the buffer, but recvType does that.
+func (dec *Decoder) decodeValueFromBuffer(value reflect.Value, ignoreInterfaceValue, countPresent bool) {
+ for dec.state.b.Len() > 0 {
// Receive a type id.
- id := typeId(decodeInt(dec.state))
- if dec.state.err != nil {
- break
- }
+ id := typeId(dec.state.decodeInt())
// Is it a new type?
if id < 0 { // 0 is the error state, handled above
// If the id is negative, we have a type.
dec.recvType(-id)
- if dec.state.err != nil {
+ if dec.err != nil {
break
}
continue
}
- // No, it's a value.
// Make sure the type has been defined already or is a builtin type (for
// top-level singleton values).
if dec.wireType[id] == nil && builtinIdToType[id] == nil {
- dec.state.err = errBadType
+ dec.err = errBadType
break
}
- dec.state.err = dec.decode(id, value)
+ // An interface value is preceded by a byte count.
+ if countPresent {
+ count := int(dec.state.decodeUint())
+ if ignoreInterfaceValue {
+ // An interface value is preceded by a byte count. Just skip that many bytes.
+ dec.state.b.Next(int(count))
+ break
+ }
+ // Otherwise fall through and decode it.
+ }
+ dec.err = dec.decode(id, value)
break
}
- return dec.state.err
}
+
+// DecodeValue reads the next value from the connection and stores
+// it in the data represented by the reflection value.
+// The value must be the correct type for the next
+// data item received.
+func (dec *Decoder) DecodeValue(value reflect.Value) os.Error {
+ // Make sure we're single-threaded through here.
+ dec.mutex.Lock()
+ defer dec.mutex.Unlock()
+
+ dec.err = nil
+ dec.recv()
+ if dec.err != nil {
+ return dec.err
+ }
+ dec.decodeValueFromBuffer(value, false, false)
+ return dec.err
+}
+
+// If debug.go is compiled into the program , debugFunc prints a human-readable
+// representation of the gob data read from r by calling that file's Debug function.
+// Otherwise it is nil.
+var debugFunc func(io.Reader)
diff --git a/src/pkg/gob/doc.go b/src/pkg/gob/doc.go
new file mode 100644
index 000000000..31253f16d
--- /dev/null
+++ b/src/pkg/gob/doc.go
@@ -0,0 +1,307 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+The gob package manages streams of gobs - binary values exchanged between an
+Encoder (transmitter) and a Decoder (receiver). A typical use is transporting
+arguments and results of remote procedure calls (RPCs) such as those provided by
+package "rpc".
+
+A stream of gobs is self-describing. Each data item in the stream is preceded by
+a specification of its type, expressed in terms of a small set of predefined
+types. Pointers are not transmitted, but the things they point to are
+transmitted; that is, the values are flattened. Recursive types work fine, but
+recursive values (data with cycles) are problematic. This may change.
+
+To use gobs, create an Encoder and present it with a series of data items as
+values or addresses that can be dereferenced to values. The Encoder makes sure
+all type information is sent before it is needed. At the receive side, a
+Decoder retrieves values from the encoded stream and unpacks them into local
+variables.
+
+The source and destination values/types need not correspond exactly. For structs,
+fields (identified by name) that are in the source but absent from the receiving
+variable will be ignored. Fields that are in the receiving variable but missing
+from the transmitted type or value will be ignored in the destination. If a field
+with the same name is present in both, their types must be compatible. Both the
+receiver and transmitter will do all necessary indirection and dereferencing to
+convert between gobs and actual Go values. For instance, a gob type that is
+schematically,
+
+ struct { a, b int }
+
+can be sent from or received into any of these Go types:
+
+ struct { a, b int } // the same
+ *struct { a, b int } // extra indirection of the struct
+ struct { *a, **b int } // extra indirection of the fields
+ struct { a, b int64 } // different concrete value type; see below
+
+It may also be received into any of these:
+
+ struct { a, b int } // the same
+ struct { b, a int } // ordering doesn't matter; matching is by name
+ struct { a, b, c int } // extra field (c) ignored
+ struct { b int } // missing field (a) ignored; data will be dropped
+ struct { b, c int } // missing field (a) ignored; extra field (c) ignored.
+
+Attempting to receive into these types will draw a decode error:
+
+ struct { a int; b uint } // change of signedness for b
+ struct { a int; b float } // change of type for b
+ struct { } // no field names in common
+ struct { c, d int } // no field names in common
+
+Integers are transmitted two ways: arbitrary precision signed integers or
+arbitrary precision unsigned integers. There is no int8, int16 etc.
+discrimination in the gob format; there are only signed and unsigned integers. As
+described below, the transmitter sends the value in a variable-length encoding;
+the receiver accepts the value and stores it in the destination variable.
+Floating-point numbers are always sent using IEEE-754 64-bit precision (see
+below).
+
+Signed integers may be received into any signed integer variable: int, int16, etc.;
+unsigned integers may be received into any unsigned integer variable; and floating
+point values may be received into any floating point variable. However,
+the destination variable must be able to represent the value or the decode
+operation will fail.
+
+Structs, arrays and slices are also supported. Strings and arrays of bytes are
+supported with a special, efficient representation (see below).
+
+Functions and channels cannot be sent in a gob. Attempting
+to encode a value that contains one will fail.
+
+The rest of this comment documents the encoding, details that are not important
+for most users. Details are presented bottom-up.
+
+An unsigned integer is sent one of two ways. If it is less than 128, it is sent
+as a byte with that value. Otherwise it is sent as a minimal-length big-endian
+(high byte first) byte stream holding the value, preceded by one byte holding the
+byte count, negated. Thus 0 is transmitted as (00), 7 is transmitted as (07) and
+256 is transmitted as (FE 01 00).
+
+A boolean is encoded within an unsigned integer: 0 for false, 1 for true.
+
+A signed integer, i, is encoded within an unsigned integer, u. Within u, bits 1
+upward contain the value; bit 0 says whether they should be complemented upon
+receipt. The encode algorithm looks like this:
+
+ uint u;
+ if i < 0 {
+ u = (^i << 1) | 1 // complement i, bit 0 is 1
+ } else {
+ u = (i << 1) // do not complement i, bit 0 is 0
+ }
+ encodeUnsigned(u)
+
+The low bit is therefore analogous to a sign bit, but making it the complement bit
+instead guarantees that the largest negative integer is not a special case. For
+example, -129=^128=(^256>>1) encodes as (FE 01 01).
+
+Floating-point numbers are always sent as a representation of a float64 value.
+That value is converted to a uint64 using math.Float64bits. The uint64 is then
+byte-reversed and sent as a regular unsigned integer. The byte-reversal means the
+exponent and high-precision part of the mantissa go first. Since the low bits are
+often zero, this can save encoding bytes. For instance, 17.0 is encoded in only
+three bytes (FE 31 40).
+
+Strings and slices of bytes are sent as an unsigned count followed by that many
+uninterpreted bytes of the value.
+
+All other slices and arrays are sent as an unsigned count followed by that many
+elements using the standard gob encoding for their type, recursively.
+
+Structs are sent as a sequence of (field number, field value) pairs. The field
+value is sent using the standard gob encoding for its type, recursively. If a
+field has the zero value for its type, it is omitted from the transmission. The
+field number is defined by the type of the encoded struct: the first field of the
+encoded type is field 0, the second is field 1, etc. When encoding a value, the
+field numbers are delta encoded for efficiency and the fields are always sent in
+order of increasing field number; the deltas are therefore unsigned. The
+initialization for the delta encoding sets the field number to -1, so an unsigned
+integer field 0 with value 7 is transmitted as unsigned delta = 1, unsigned value
+= 7 or (01 07). Finally, after all the fields have been sent a terminating mark
+denotes the end of the struct. That mark is a delta=0 value, which has
+representation (00).
+
+Interface types are not checked for compatibility; all interface types are
+treated, for transmission, as members of a single "interface" type, analogous to
+int or []byte - in effect they're all treated as interface{}. Interface values
+are transmitted as a string identifying the concrete type being sent (a name
+that must be pre-defined by calling Register), followed by a byte count of the
+length of the following data (so the value can be skipped if it cannot be
+stored), followed by the usual encoding of concrete (dynamic) value stored in
+the interface value. (A nil interface value is identified by the empty string
+and transmits no value.) Upon receipt, the decoder verifies that the unpacked
+concrete item satisfies the interface of the receiving variable.
+
+The representation of types is described below. When a type is defined on a given
+connection between an Encoder and Decoder, it is assigned a signed integer type
+id. When Encoder.Encode(v) is called, it makes sure there is an id assigned for
+the type of v and all its elements and then it sends the pair (typeid, encoded-v)
+where typeid is the type id of the encoded type of v and encoded-v is the gob
+encoding of the value v.
+
+To define a type, the encoder chooses an unused, positive type id and sends the
+pair (-type id, encoded-type) where encoded-type is the gob encoding of a wireType
+description, constructed from these types:
+
+ type wireType struct {
+ ArrayT *ArrayType
+ SliceT *SliceType
+ StructT *StructType
+ MapT *MapType
+ }
+ type ArrayType struct {
+ CommonType
+ Elem typeId
+ Len int
+ }
+ type CommonType {
+ Name string // the name of the struct type
+ Id int // the id of the type, repeated so it's inside the type
+ }
+ type SliceType struct {
+ CommonType
+ Elem typeId
+ }
+ type StructType struct {
+ CommonType
+ Field []*fieldType // the fields of the struct.
+ }
+ type FieldType struct {
+ Name string // the name of the field.
+ Id int // the type id of the field, which must be already defined
+ }
+ type MapType struct {
+ CommonType
+ Key typeId
+ Elem typeId
+ }
+
+If there are nested type ids, the types for all inner type ids must be defined
+before the top-level type id is used to describe an encoded-v.
+
+For simplicity in setup, the connection is defined to understand these types a
+priori, as well as the basic gob types int, uint, etc. Their ids are:
+
+ bool 1
+ int 2
+ uint 3
+ float 4
+ []byte 5
+ string 6
+ complex 7
+ interface 8
+ // gap for reserved ids.
+ WireType 16
+ ArrayType 17
+ CommonType 18
+ SliceType 19
+ StructType 20
+ FieldType 21
+ // 22 is slice of fieldType.
+ MapType 23
+
+Finally, each message created by a call to Encode is preceded by an encoded
+unsigned integer count of the number of bytes remaining in the message. After
+the initial type name, interface values are wrapped the same way; in effect, the
+interface value acts like a recursive invocation of Encode.
+
+In summary, a gob stream looks like
+
+ (byteCount (-type id, encoding of a wireType)* (type id, encoding of a value))*
+
+where * signifies zero or more repetitions and the type id of a value must
+be predefined or be defined before the value in the stream.
+*/
+package gob
+
+/*
+For implementers and the curious, here is an encoded example. Given
+ type Point struct {x, y int}
+and the value
+ p := Point{22, 33}
+the bytes transmitted that encode p will be:
+ 1f ff 81 03 01 01 05 50 6f 69 6e 74 01 ff 82 00
+ 01 02 01 01 78 01 04 00 01 01 79 01 04 00 00 00
+ 07 ff 82 01 2c 01 42 00
+They are determined as follows.
+
+Since this is the first transmission of type Point, the type descriptor
+for Point itself must be sent before the value. This is the first type
+we've sent on this Encoder, so it has type id 65 (0 through 64 are
+reserved).
+
+ 1f // This item (a type descriptor) is 31 bytes long.
+ ff 81 // The negative of the id for the type we're defining, -65.
+ // This is one byte (indicated by FF = -1) followed by
+ // ^-65<<1 | 1. The low 1 bit signals to complement the
+ // rest upon receipt.
+
+ // Now we send a type descriptor, which is itself a struct (wireType).
+ // The type of wireType itself is known (it's built in, as is the type of
+ // all its components), so we just need to send a *value* of type wireType
+ // that represents type "Point".
+ // Here starts the encoding of that value.
+ // Set the field number implicitly to -1; this is done at the beginning
+ // of every struct, including nested structs.
+ 03 // Add 3 to field number; now 2 (wireType.structType; this is a struct).
+ // structType starts with an embedded commonType, which appears
+ // as a regular structure here too.
+ 01 // add 1 to field number (now 0); start of embedded commonType.
+ 01 // add 1 to field number (now 0, the name of the type)
+ 05 // string is (unsigned) 5 bytes long
+ 50 6f 69 6e 74 // wireType.structType.commonType.name = "Point"
+ 01 // add 1 to field number (now 1, the id of the type)
+ ff 82 // wireType.structType.commonType._id = 65
+ 00 // end of embedded wiretype.structType.commonType struct
+ 01 // add 1 to field number (now 1, the field array in wireType.structType)
+ 02 // There are two fields in the type (len(structType.field))
+ 01 // Start of first field structure; add 1 to get field number 0: field[0].name
+ 01 // 1 byte
+ 78 // structType.field[0].name = "x"
+ 01 // Add 1 to get field number 1: field[0].id
+ 04 // structType.field[0].typeId is 2 (signed int).
+ 00 // End of structType.field[0]; start structType.field[1]; set field number to -1.
+ 01 // Add 1 to get field number 0: field[1].name
+ 01 // 1 byte
+ 79 // structType.field[1].name = "y"
+ 01 // Add 1 to get field number 1: field[0].id
+ 04 // struct.Type.field[1].typeId is 2 (signed int).
+ 00 // End of structType.field[1]; end of structType.field.
+ 00 // end of wireType.structType structure
+ 00 // end of wireType structure
+
+Now we can send the Point value. Again the field number resets to -1:
+
+ 07 // this value is 7 bytes long
+ ff 82 // the type number, 65 (1 byte (-FF) followed by 65<<1)
+ 01 // add one to field number, yielding field 0
+ 2c // encoding of signed "22" (0x22 = 44 = 22<<1); Point.x = 22
+ 01 // add one to field number, yielding field 1
+ 42 // encoding of signed "33" (0x42 = 66 = 33<<1); Point.y = 33
+ 00 // end of structure
+
+The type encoding is long and fairly intricate but we send it only once.
+If p is transmitted a second time, the type is already known so the
+output will be just:
+
+ 07 ff 82 01 2c 01 42 00
+
+A single non-struct value at top level is transmitted like a field with
+delta tag 0. For instance, a signed integer with value 3 presented as
+the argument to Encode will emit:
+
+ 03 04 00 06
+
+Which represents:
+
+ 03 // this value is 3 bytes long
+ 04 // the type number, 2, represents an integer
+ 00 // tag delta 0
+ 06 // value 3
+
+*/
diff --git a/src/pkg/gob/encode.go b/src/pkg/gob/encode.go
index 00548868b..3431eafa7 100644
--- a/src/pkg/gob/encode.go
+++ b/src/pkg/gob/encode.go
@@ -2,270 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-/*
- The gob package manages streams of gobs - binary values exchanged between an
- Encoder (transmitter) and a Decoder (receiver). A typical use is transporting
- arguments and results of remote procedure calls (RPCs) such as those provided by
- package "rpc".
-
- A stream of gobs is self-describing. Each data item in the stream is preceded by
- a specification of its type, expressed in terms of a small set of predefined
- types. Pointers are not transmitted, but the things they point to are
- transmitted; that is, the values are flattened. Recursive types work fine, but
- recursive values (data with cycles) are problematic. This may change.
-
- To use gobs, create an Encoder and present it with a series of data items as
- values or addresses that can be dereferenced to values. The Encoder makes sure
- all type information is sent before it is needed. At the receive side, a
- Decoder retrieves values from the encoded stream and unpacks them into local
- variables.
-
- The source and destination values/types need not correspond exactly. For structs,
- fields (identified by name) that are in the source but absent from the receiving
- variable will be ignored. Fields that are in the receiving variable but missing
- from the transmitted type or value will be ignored in the destination. If a field
- with the same name is present in both, their types must be compatible. Both the
- receiver and transmitter will do all necessary indirection and dereferencing to
- convert between gobs and actual Go values. For instance, a gob type that is
- schematically,
-
- struct { a, b int }
-
- can be sent from or received into any of these Go types:
-
- struct { a, b int } // the same
- *struct { a, b int } // extra indirection of the struct
- struct { *a, **b int } // extra indirection of the fields
- struct { a, b int64 } // different concrete value type; see below
-
- It may also be received into any of these:
-
- struct { a, b int } // the same
- struct { b, a int } // ordering doesn't matter; matching is by name
- struct { a, b, c int } // extra field (c) ignored
- struct { b int } // missing field (a) ignored; data will be dropped
- struct { b, c int } // missing field (a) ignored; extra field (c) ignored.
-
- Attempting to receive into these types will draw a decode error:
-
- struct { a int; b uint } // change of signedness for b
- struct { a int; b float } // change of type for b
- struct { } // no field names in common
- struct { c, d int } // no field names in common
-
- Integers are transmitted two ways: arbitrary precision signed integers or
- arbitrary precision unsigned integers. There is no int8, int16 etc.
- discrimination in the gob format; there are only signed and unsigned integers. As
- described below, the transmitter sends the value in a variable-length encoding;
- the receiver accepts the value and stores it in the destination variable.
- Floating-point numbers are always sent using IEEE-754 64-bit precision (see
- below).
-
- Signed integers may be received into any signed integer variable: int, int16, etc.;
- unsigned integers may be received into any unsigned integer variable; and floating
- point values may be received into any floating point variable. However,
- the destination variable must be able to represent the value or the decode
- operation will fail.
-
- Structs, arrays and slices are also supported. Strings and arrays of bytes are
- supported with a special, efficient representation (see below).
-
- Interfaces, functions, and channels cannot be sent in a gob. Attempting
- to encode a value that contains one will fail.
-
- The rest of this comment documents the encoding, details that are not important
- for most users. Details are presented bottom-up.
-
- An unsigned integer is sent one of two ways. If it is less than 128, it is sent
- as a byte with that value. Otherwise it is sent as a minimal-length big-endian
- (high byte first) byte stream holding the value, preceded by one byte holding the
- byte count, negated. Thus 0 is transmitted as (00), 7 is transmitted as (07) and
- 256 is transmitted as (FE 01 00).
-
- A boolean is encoded within an unsigned integer: 0 for false, 1 for true.
-
- A signed integer, i, is encoded within an unsigned integer, u. Within u, bits 1
- upward contain the value; bit 0 says whether they should be complemented upon
- receipt. The encode algorithm looks like this:
-
- uint u;
- if i < 0 {
- u = (^i << 1) | 1 // complement i, bit 0 is 1
- } else {
- u = (i << 1) // do not complement i, bit 0 is 0
- }
- encodeUnsigned(u)
-
- The low bit is therefore analogous to a sign bit, but making it the complement bit
- instead guarantees that the largest negative integer is not a special case. For
- example, -129=^128=(^256>>1) encodes as (FE 01 01).
-
- Floating-point numbers are always sent as a representation of a float64 value.
- That value is converted to a uint64 using math.Float64bits. The uint64 is then
- byte-reversed and sent as a regular unsigned integer. The byte-reversal means the
- exponent and high-precision part of the mantissa go first. Since the low bits are
- often zero, this can save encoding bytes. For instance, 17.0 is encoded in only
- three bytes (FE 31 40).
-
- Strings and slices of bytes are sent as an unsigned count followed by that many
- uninterpreted bytes of the value.
-
- All other slices and arrays are sent as an unsigned count followed by that many
- elements using the standard gob encoding for their type, recursively.
-
- Structs are sent as a sequence of (field number, field value) pairs. The field
- value is sent using the standard gob encoding for its type, recursively. If a
- field has the zero value for its type, it is omitted from the transmission. The
- field number is defined by the type of the encoded struct: the first field of the
- encoded type is field 0, the second is field 1, etc. When encoding a value, the
- field numbers are delta encoded for efficiency and the fields are always sent in
- order of increasing field number; the deltas are therefore unsigned. The
- initialization for the delta encoding sets the field number to -1, so an unsigned
- integer field 0 with value 7 is transmitted as unsigned delta = 1, unsigned value
- = 7 or (01 0E). Finally, after all the fields have been sent a terminating mark
- denotes the end of the struct. That mark is a delta=0 value, which has
- representation (00).
-
- The representation of types is described below. When a type is defined on a given
- connection between an Encoder and Decoder, it is assigned a signed integer type
- id. When Encoder.Encode(v) is called, it makes sure there is an id assigned for
- the type of v and all its elements and then it sends the pair (typeid, encoded-v)
- where typeid is the type id of the encoded type of v and encoded-v is the gob
- encoding of the value v.
-
- To define a type, the encoder chooses an unused, positive type id and sends the
- pair (-type id, encoded-type) where encoded-type is the gob encoding of a wireType
- description, constructed from these types:
-
- type wireType struct {
- s structType;
- }
- type fieldType struct {
- name string; // the name of the field.
- id int; // the type id of the field, which must be already defined
- }
- type commonType {
- name string; // the name of the struct type
- id int; // the id of the type, repeated for so it's inside the type
- }
- type structType struct {
- commonType;
- field []fieldType; // the fields of the struct.
- }
-
- If there are nested type ids, the types for all inner type ids must be defined
- before the top-level type id is used to describe an encoded-v.
-
- For simplicity in setup, the connection is defined to understand these types a
- priori, as well as the basic gob types int, uint, etc. Their ids are:
-
- bool 1
- int 2
- uint 3
- float 4
- []byte 5
- string 6
- wireType 7
- structType 8
- commonType 9
- fieldType 10
-
- In summary, a gob stream looks like
-
- ((-type id, encoding of a wireType)* (type id, encoding of a value))*
-
- where * signifies zero or more repetitions and the type id of a value must
- be predefined or be defined before the value in the stream.
-*/
package gob
-/*
- For implementers and the curious, here is an encoded example. Given
- type Point {x, y int}
- and the value
- p := Point{22, 33}
- the bytes transmitted that encode p will be:
- 1f ff 81 03 01 01 05 50 6f 69 6e 74 01 ff 82 00 01 02 01 01 78
- 01 04 00 01 01 79 01 04 00 00 00 07 ff 82 01 2c 01 42 00 07 ff
- 82 01 2c 01 42 00
- They are determined as follows.
-
- Since this is the first transmission of type Point, the type descriptor
- for Point itself must be sent before the value. This is the first type
- we've sent on this Encoder, so it has type id 65 (0 through 64 are
- reserved).
-
- 1f // This item (a type descriptor) is 31 bytes long.
- ff 81 // The negative of the id for the type we're defining, -65.
- // This is one byte (indicated by FF = -1) followed by
- // ^-65<<1 | 1. The low 1 bit signals to complement the
- // rest upon receipt.
-
- // Now we send a type descriptor, which is itself a struct (wireType).
- // The type of wireType itself is known (it's built in, as is the type of
- // all its components), so we just need to send a *value* of type wireType
- // that represents type "Point".
- // Here starts the encoding of that value.
- // Set the field number implicitly to zero; this is done at the beginning
- // of every struct, including nested structs.
- 03 // Add 3 to field number; now 3 (wireType.structType; this is a struct).
- // structType starts with an embedded commonType, which appears
- // as a regular structure here too.
- 01 // add 1 to field number (now 1); start of embedded commonType.
- 01 // add one to field number (now 1, the name of the type)
- 05 // string is (unsigned) 5 bytes long
- 50 6f 69 6e 74 // wireType.structType.commonType.name = "Point"
- 01 // add one to field number (now 2, the id of the type)
- ff 82 // wireType.structType.commonType._id = 65
- 00 // end of embedded wiretype.structType.commonType struct
- 01 // add one to field number (now 2, 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 1: field[0].name
- 01 // 1 byte
- 78 // structType.field[0].name = "x"
- 01 // Add 1 to get field number 2: field[0].id
- 04 // structType.field[0].typeId is 2 (signed int).
- 00 // End of structType.field[0]; start structType.field[1]; set field number to 0.
- 01 // Add 1 to get field number 1: field[1].name
- 01 // 1 byte
- 79 // structType.field[1].name = "y"
- 01 // Add 1 to get field number 2: field[0].id
- 04 // struct.Type.field[1].typeId is 2 (signed int).
- 00 // End of structType.field[1]; end of structType.field.
- 00 // end of wireType.structType structure
- 00 // end of wireType structure
-
- Now we can send the Point value. Again the field number resets to zero:
-
- 07 // this value is 7 bytes long
- ff 82 // the type number, 65 (1 byte (-FF) followed by 65<<1)
- 01 // add one to field number, yielding field 1
- 2c // encoding of signed "22" (0x22 = 44 = 22<<1); Point.x = 22
- 01 // add one to field number, yielding field 2
- 42 // encoding of signed "33" (0x42 = 66 = 33<<1); Point.y = 33
- 00 // end of structure
-
- The type encoding is long and fairly intricate but we send it only once.
- If p is transmitted a second time, the type is already known so the
- output will be just:
-
- 07 ff 82 01 2c 01 42 00
-
- A single non-struct value at top level is transmitted like a field with
- delta tag 0. For instance, a signed integer with value 3 presented as
- the argument to Encode will emit:
-
- 03 04 00 06
-
- Which represents:
-
- 03 // this value is 3 bytes long
- 04 // the type number, 2, represents an integer
- 00 // tag delta 0
- 06 // value 3
-
-*/
-
import (
"bytes"
"io"
@@ -282,26 +20,29 @@ const uint64Size = unsafe.Sizeof(uint64(0))
// number is initialized to -1 so 0 comes out as delta(1). A delta of
// 0 terminates the structure.
type encoderState struct {
+ enc *Encoder
b *bytes.Buffer
- err os.Error // error encountered during encoding.
sendZero bool // encoding an array element or map key/value pair; send zero values
fieldnum int // the last field number written.
buf [1 + uint64Size]byte // buffer used by the encoder; here to avoid allocation.
}
+func newEncoderState(enc *Encoder, b *bytes.Buffer) *encoderState {
+ return &encoderState{enc: enc, b: b}
+}
+
// Unsigned integers have a two-state encoding. If the number is less
// than 128 (0 through 0x7F), its value is written directly.
// Otherwise the value is written in big-endian byte order preceded
// by the byte length, negated.
-// encodeUint writes an encoded unsigned integer to state.b. Sets state.err.
-// If state.err is already non-nil, it does nothing.
-func encodeUint(state *encoderState, x uint64) {
- if state.err != nil {
- return
- }
+// encodeUint writes an encoded unsigned integer to state.b.
+func (state *encoderState) encodeUint(x uint64) {
if x <= 0x7F {
- state.err = state.b.WriteByte(uint8(x))
+ err := state.b.WriteByte(uint8(x))
+ if err != nil {
+ error(err)
+ }
return
}
var n, m int
@@ -312,20 +53,23 @@ func encodeUint(state *encoderState, x uint64) {
m--
}
state.buf[m] = uint8(-(n - 1))
- n, state.err = state.b.Write(state.buf[m : uint64Size+1])
+ n, err := state.b.Write(state.buf[m : uint64Size+1])
+ if err != nil {
+ error(err)
+ }
}
// encodeInt writes an encoded signed integer to state.w.
-// The low bit of the encoding says whether to bit complement the (other bits of the) uint to recover the int.
-// Sets state.err. If state.err is already non-nil, it does nothing.
-func encodeInt(state *encoderState, i int64) {
+// The low bit of the encoding says whether to bit complement the (other bits of the)
+// uint to recover the int.
+func (state *encoderState) encodeInt(i int64) {
var x uint64
if i < 0 {
x = uint64(^i<<1) | 1
} else {
x = uint64(i << 1)
}
- encodeUint(state, uint64(x))
+ state.encodeUint(uint64(x))
}
type encOp func(i *encInstr, state *encoderState, p unsafe.Pointer)
@@ -342,7 +86,7 @@ type encInstr struct {
// If the instruction pointer is nil, do nothing
func (state *encoderState) update(instr *encInstr) {
if instr != nil {
- encodeUint(state, uint64(instr.field-state.fieldnum))
+ state.encodeUint(uint64(instr.field - state.fieldnum))
state.fieldnum = instr.field
}
}
@@ -368,9 +112,9 @@ func encBool(i *encInstr, state *encoderState, p unsafe.Pointer) {
if b || state.sendZero {
state.update(i)
if b {
- encodeUint(state, 1)
+ state.encodeUint(1)
} else {
- encodeUint(state, 0)
+ state.encodeUint(0)
}
}
}
@@ -379,7 +123,7 @@ func encInt(i *encInstr, state *encoderState, p unsafe.Pointer) {
v := int64(*(*int)(p))
if v != 0 || state.sendZero {
state.update(i)
- encodeInt(state, v)
+ state.encodeInt(v)
}
}
@@ -387,7 +131,7 @@ func encUint(i *encInstr, state *encoderState, p unsafe.Pointer) {
v := uint64(*(*uint)(p))
if v != 0 || state.sendZero {
state.update(i)
- encodeUint(state, v)
+ state.encodeUint(v)
}
}
@@ -395,7 +139,7 @@ func encInt8(i *encInstr, state *encoderState, p unsafe.Pointer) {
v := int64(*(*int8)(p))
if v != 0 || state.sendZero {
state.update(i)
- encodeInt(state, v)
+ state.encodeInt(v)
}
}
@@ -403,7 +147,7 @@ func encUint8(i *encInstr, state *encoderState, p unsafe.Pointer) {
v := uint64(*(*uint8)(p))
if v != 0 || state.sendZero {
state.update(i)
- encodeUint(state, v)
+ state.encodeUint(v)
}
}
@@ -411,7 +155,7 @@ func encInt16(i *encInstr, state *encoderState, p unsafe.Pointer) {
v := int64(*(*int16)(p))
if v != 0 || state.sendZero {
state.update(i)
- encodeInt(state, v)
+ state.encodeInt(v)
}
}
@@ -419,7 +163,7 @@ func encUint16(i *encInstr, state *encoderState, p unsafe.Pointer) {
v := uint64(*(*uint16)(p))
if v != 0 || state.sendZero {
state.update(i)
- encodeUint(state, v)
+ state.encodeUint(v)
}
}
@@ -427,7 +171,7 @@ func encInt32(i *encInstr, state *encoderState, p unsafe.Pointer) {
v := int64(*(*int32)(p))
if v != 0 || state.sendZero {
state.update(i)
- encodeInt(state, v)
+ state.encodeInt(v)
}
}
@@ -435,7 +179,7 @@ func encUint32(i *encInstr, state *encoderState, p unsafe.Pointer) {
v := uint64(*(*uint32)(p))
if v != 0 || state.sendZero {
state.update(i)
- encodeUint(state, v)
+ state.encodeUint(v)
}
}
@@ -443,7 +187,7 @@ func encInt64(i *encInstr, state *encoderState, p unsafe.Pointer) {
v := *(*int64)(p)
if v != 0 || state.sendZero {
state.update(i)
- encodeInt(state, v)
+ state.encodeInt(v)
}
}
@@ -451,7 +195,7 @@ func encUint64(i *encInstr, state *encoderState, p unsafe.Pointer) {
v := *(*uint64)(p)
if v != 0 || state.sendZero {
state.update(i)
- encodeUint(state, v)
+ state.encodeUint(v)
}
}
@@ -459,7 +203,7 @@ func encUintptr(i *encInstr, state *encoderState, p unsafe.Pointer) {
v := uint64(*(*uintptr)(p))
if v != 0 || state.sendZero {
state.update(i)
- encodeUint(state, v)
+ state.encodeUint(v)
}
}
@@ -484,7 +228,7 @@ func encFloat(i *encInstr, state *encoderState, p unsafe.Pointer) {
if f != 0 || state.sendZero {
v := floatBits(float64(f))
state.update(i)
- encodeUint(state, v)
+ state.encodeUint(v)
}
}
@@ -493,7 +237,7 @@ func encFloat32(i *encInstr, state *encoderState, p unsafe.Pointer) {
if f != 0 || state.sendZero {
v := floatBits(float64(f))
state.update(i)
- encodeUint(state, v)
+ state.encodeUint(v)
}
}
@@ -502,7 +246,7 @@ func encFloat64(i *encInstr, state *encoderState, p unsafe.Pointer) {
if f != 0 || state.sendZero {
state.update(i)
v := floatBits(f)
- encodeUint(state, v)
+ state.encodeUint(v)
}
}
@@ -513,8 +257,8 @@ func encComplex(i *encInstr, state *encoderState, p unsafe.Pointer) {
rpart := floatBits(float64(real(c)))
ipart := floatBits(float64(imag(c)))
state.update(i)
- encodeUint(state, rpart)
- encodeUint(state, ipart)
+ state.encodeUint(rpart)
+ state.encodeUint(ipart)
}
}
@@ -524,8 +268,8 @@ func encComplex64(i *encInstr, state *encoderState, p unsafe.Pointer) {
rpart := floatBits(float64(real(c)))
ipart := floatBits(float64(imag(c)))
state.update(i)
- encodeUint(state, rpart)
- encodeUint(state, ipart)
+ state.encodeUint(rpart)
+ state.encodeUint(ipart)
}
}
@@ -535,17 +279,20 @@ func encComplex128(i *encInstr, state *encoderState, p unsafe.Pointer) {
rpart := floatBits(real(c))
ipart := floatBits(imag(c))
state.update(i)
- encodeUint(state, rpart)
- encodeUint(state, ipart)
+ state.encodeUint(rpart)
+ state.encodeUint(ipart)
}
}
+func encNoOp(i *encInstr, state *encoderState, p unsafe.Pointer) {
+}
+
// Byte arrays are encoded as an unsigned count followed by the raw bytes.
func encUint8Array(i *encInstr, state *encoderState, p unsafe.Pointer) {
b := *(*[]byte)(p)
if len(b) > 0 || state.sendZero {
state.update(i)
- encodeUint(state, uint64(len(b)))
+ state.encodeUint(uint64(len(b)))
state.b.Write(b)
}
}
@@ -555,14 +302,14 @@ func encString(i *encInstr, state *encoderState, p unsafe.Pointer) {
s := *(*string)(p)
if len(s) > 0 || state.sendZero {
state.update(i)
- encodeUint(state, uint64(len(s)))
+ state.encodeUint(uint64(len(s)))
io.WriteString(state.b, s)
}
}
// The end of a struct is marked by a delta field number of 0.
func encStructTerminator(i *encInstr, state *encoderState, p unsafe.Pointer) {
- encodeUint(state, 0)
+ state.encodeUint(0)
}
// Execution engine
@@ -575,9 +322,8 @@ type encEngine struct {
const singletonField = 0
-func encodeSingle(engine *encEngine, b *bytes.Buffer, basep uintptr) os.Error {
- state := new(encoderState)
- state.b = b
+func (enc *Encoder) encodeSingle(b *bytes.Buffer, engine *encEngine, basep uintptr) {
+ state := newEncoderState(enc, b)
state.fieldnum = singletonField
// There is no surrounding struct to frame the transmission, so we must
// generate data even if the item is zero. To do this, set sendZero.
@@ -586,16 +332,14 @@ func encodeSingle(engine *encEngine, b *bytes.Buffer, basep uintptr) os.Error {
p := unsafe.Pointer(basep) // offset will be zero
if instr.indir > 0 {
if p = encIndirect(p, instr.indir); p == nil {
- return nil
+ return
}
}
instr.op(instr, state, p)
- return state.err
}
-func encodeStruct(engine *encEngine, b *bytes.Buffer, basep uintptr) os.Error {
- state := new(encoderState)
- state.b = b
+func (enc *Encoder) encodeStruct(b *bytes.Buffer, engine *encEngine, basep uintptr) {
+ state := newEncoderState(enc, b)
state.fieldnum = -1
for i := 0; i < len(engine.instr); i++ {
instr := &engine.instr[i]
@@ -606,33 +350,26 @@ func encodeStruct(engine *encEngine, b *bytes.Buffer, basep uintptr) os.Error {
}
}
instr.op(instr, state, p)
- if state.err != nil {
- break
- }
}
- return state.err
}
-func encodeArray(b *bytes.Buffer, p uintptr, op encOp, elemWid uintptr, elemIndir int, length int) os.Error {
- state := new(encoderState)
- state.b = b
+func (enc *Encoder) encodeArray(b *bytes.Buffer, p uintptr, op encOp, elemWid uintptr, elemIndir int, length int) {
+ state := newEncoderState(enc, b)
state.fieldnum = -1
state.sendZero = true
- encodeUint(state, uint64(length))
- for i := 0; i < length && state.err == nil; i++ {
+ state.encodeUint(uint64(length))
+ for i := 0; i < length; i++ {
elemp := p
up := unsafe.Pointer(elemp)
if elemIndir > 0 {
if up = encIndirect(up, elemIndir); up == nil {
- state.err = os.ErrorString("gob: encodeArray: nil element")
- break
+ errorf("gob: encodeArray: nil element")
}
elemp = uintptr(up)
}
op(nil, state, unsafe.Pointer(elemp))
p += uintptr(elemWid)
}
- return state.err
}
func encodeReflectValue(state *encoderState, v reflect.Value, op encOp, indir int) {
@@ -640,27 +377,60 @@ func encodeReflectValue(state *encoderState, v reflect.Value, op encOp, indir in
v = reflect.Indirect(v)
}
if v == nil {
- state.err = os.ErrorString("gob: encodeReflectValue: nil element")
- return
+ errorf("gob: encodeReflectValue: nil element")
}
op(nil, state, unsafe.Pointer(v.Addr()))
}
-func encodeMap(b *bytes.Buffer, mv *reflect.MapValue, keyOp, elemOp encOp, keyIndir, elemIndir int) os.Error {
- state := new(encoderState)
- state.b = b
+func (enc *Encoder) encodeMap(b *bytes.Buffer, mv *reflect.MapValue, keyOp, elemOp encOp, keyIndir, elemIndir int) {
+ state := newEncoderState(enc, b)
state.fieldnum = -1
state.sendZero = true
keys := mv.Keys()
- encodeUint(state, uint64(len(keys)))
+ state.encodeUint(uint64(len(keys)))
for _, key := range keys {
- if state.err != nil {
- break
- }
encodeReflectValue(state, key, keyOp, keyIndir)
encodeReflectValue(state, mv.Elem(key), elemOp, elemIndir)
}
- return state.err
+}
+
+// To send an interface, we send a string identifying the concrete type, followed
+// by the type identifier (which might require defining that type right now), followed
+// by the concrete value. A nil value gets sent as the empty string for the name,
+// followed by no value.
+func (enc *Encoder) encodeInterface(b *bytes.Buffer, iv *reflect.InterfaceValue) {
+ state := newEncoderState(enc, b)
+ state.fieldnum = -1
+ state.sendZero = true
+ if iv.IsNil() {
+ state.encodeUint(0)
+ return
+ }
+
+ typ, _ := indirect(iv.Elem().Type())
+ name, ok := concreteTypeToName[typ]
+ if !ok {
+ errorf("gob: type not registered for interface: %s", typ)
+ }
+ // Send the name.
+ state.encodeUint(uint64(len(name)))
+ _, err := io.WriteString(state.b, name)
+ if err != nil {
+ error(err)
+ }
+ // Send (and maybe first define) the type id.
+ enc.sendTypeDescriptor(typ)
+ // Encode the value into a new buffer.
+ data := new(bytes.Buffer)
+ err = enc.encode(data, iv.Elem())
+ if err != nil {
+ error(err)
+ }
+ state.encodeUint(uint64(data.Len()))
+ _, err = state.b.Write(data.Bytes())
+ if err != nil {
+ error(err)
+ }
}
var encOpMap = []encOp{
@@ -687,7 +457,7 @@ var encOpMap = []encOp{
// Return the encoding op for the base type under rt and
// the indirection count to reach it.
-func encOpFor(rt reflect.Type) (encOp, int, os.Error) {
+func (enc *Encoder) encOpFor(rt reflect.Type) (encOp, int) {
typ, indir := indirect(rt)
var op encOp
k := typ.Kind()
@@ -703,128 +473,123 @@ func encOpFor(rt reflect.Type) (encOp, int, os.Error) {
break
}
// Slices have a header; we decode it to find the underlying array.
- elemOp, indir, err := encOpFor(t.Elem())
- if err != nil {
- return nil, 0, err
- }
+ elemOp, indir := enc.encOpFor(t.Elem())
op = func(i *encInstr, state *encoderState, p unsafe.Pointer) {
slice := (*reflect.SliceHeader)(p)
- if slice.Len == 0 {
+ if !state.sendZero && slice.Len == 0 {
return
}
state.update(i)
- state.err = encodeArray(state.b, slice.Data, elemOp, t.Elem().Size(), indir, int(slice.Len))
+ state.enc.encodeArray(state.b, slice.Data, elemOp, t.Elem().Size(), indir, int(slice.Len))
}
case *reflect.ArrayType:
// True arrays have size in the type.
- elemOp, indir, err := encOpFor(t.Elem())
- if err != nil {
- return nil, 0, err
- }
+ elemOp, indir := enc.encOpFor(t.Elem())
op = func(i *encInstr, state *encoderState, p unsafe.Pointer) {
- slice := (*reflect.SliceHeader)(p)
- if slice.Len == 0 {
- return
- }
state.update(i)
- state.err = encodeArray(state.b, uintptr(p), elemOp, t.Elem().Size(), indir, t.Len())
+ state.enc.encodeArray(state.b, uintptr(p), elemOp, t.Elem().Size(), indir, t.Len())
}
case *reflect.MapType:
- keyOp, keyIndir, err := encOpFor(t.Key())
- if err != nil {
- return nil, 0, err
- }
- elemOp, elemIndir, err := encOpFor(t.Elem())
- if err != nil {
- return nil, 0, err
- }
+ keyOp, keyIndir := enc.encOpFor(t.Key())
+ elemOp, elemIndir := enc.encOpFor(t.Elem())
op = func(i *encInstr, state *encoderState, p unsafe.Pointer) {
// Maps cannot be accessed by moving addresses around the way
// that slices etc. can. We must recover a full reflection value for
// the iteration.
v := reflect.NewValue(unsafe.Unreflect(t, unsafe.Pointer((p))))
mv := reflect.Indirect(v).(*reflect.MapValue)
- if mv.Len() == 0 {
+ if !state.sendZero && mv.Len() == 0 {
return
}
state.update(i)
- state.err = encodeMap(state.b, mv, keyOp, elemOp, keyIndir, elemIndir)
+ state.enc.encodeMap(state.b, mv, keyOp, elemOp, keyIndir, elemIndir)
}
case *reflect.StructType:
// Generate a closure that calls out to the engine for the nested type.
- _, err := getEncEngine(typ)
- if err != nil {
- return nil, 0, err
- }
+ enc.getEncEngine(typ)
info := mustGetTypeInfo(typ)
op = func(i *encInstr, state *encoderState, p unsafe.Pointer) {
state.update(i)
// indirect through info to delay evaluation for recursive structs
- state.err = encodeStruct(info.encoder, state.b, uintptr(p))
+ state.enc.encodeStruct(state.b, info.encoder, uintptr(p))
+ }
+ case *reflect.InterfaceType:
+ op = func(i *encInstr, state *encoderState, p unsafe.Pointer) {
+ // Interfaces transmit the name and contents of the concrete
+ // value they contain.
+ v := reflect.NewValue(unsafe.Unreflect(t, unsafe.Pointer((p))))
+ iv := reflect.Indirect(v).(*reflect.InterfaceValue)
+ if !state.sendZero && (iv == nil || iv.IsNil()) {
+ return
+ }
+ state.update(i)
+ state.enc.encodeInterface(state.b, iv)
}
}
}
if op == nil {
- return op, indir, os.ErrorString("gob enc: can't happen: encode type " + rt.String())
+ errorf("gob enc: can't happen: encode type %s", rt.String())
}
- return op, indir, nil
+ return op, indir
}
// The local Type was compiled from the actual value, so we know it's compatible.
-func compileEnc(rt reflect.Type) (*encEngine, os.Error) {
+func (enc *Encoder) compileEnc(rt reflect.Type) *encEngine {
srt, isStruct := rt.(*reflect.StructType)
engine := new(encEngine)
if isStruct {
engine.instr = make([]encInstr, srt.NumField()+1) // +1 for terminator
for fieldnum := 0; fieldnum < srt.NumField(); fieldnum++ {
f := srt.Field(fieldnum)
- op, indir, err := encOpFor(f.Type)
- if err != nil {
- return nil, err
+ op, indir := enc.encOpFor(f.Type)
+ if !isExported(f.Name) {
+ op = encNoOp
}
engine.instr[fieldnum] = encInstr{op, fieldnum, indir, uintptr(f.Offset)}
}
engine.instr[srt.NumField()] = encInstr{encStructTerminator, 0, 0, 0}
} else {
engine.instr = make([]encInstr, 1)
- op, indir, err := encOpFor(rt)
- if err != nil {
- return nil, err
- }
+ op, indir := enc.encOpFor(rt)
engine.instr[0] = encInstr{op, singletonField, indir, 0} // offset is zero
}
- return engine, nil
+ return engine
}
// typeLock must be held (or we're in initialization and guaranteed single-threaded).
// The reflection type must have all its indirections processed out.
-func getEncEngine(rt reflect.Type) (*encEngine, os.Error) {
- info, err := getTypeInfo(rt)
- if err != nil {
- return nil, err
+func (enc *Encoder) getEncEngine(rt reflect.Type) *encEngine {
+ info, err1 := getTypeInfo(rt)
+ if err1 != nil {
+ error(err1)
}
if info.encoder == nil {
// mark this engine as underway before compiling to handle recursive types.
info.encoder = new(encEngine)
- info.encoder, err = compileEnc(rt)
+ info.encoder = enc.compileEnc(rt)
}
- return info.encoder, err
+ return info.encoder
+}
+
+// Put this in a function so we can hold the lock only while compiling, not when encoding.
+func (enc *Encoder) lockAndGetEncEngine(rt reflect.Type) *encEngine {
+ typeLock.Lock()
+ defer typeLock.Unlock()
+ return enc.getEncEngine(rt)
}
-func encode(b *bytes.Buffer, value reflect.Value) os.Error {
+func (enc *Encoder) encode(b *bytes.Buffer, value reflect.Value) (err os.Error) {
+ defer catchError(&err)
// Dereference down to the underlying object.
rt, indir := indirect(value.Type())
for i := 0; i < indir; i++ {
value = reflect.Indirect(value)
}
- typeLock.Lock()
- engine, err := getEncEngine(rt)
- typeLock.Unlock()
- if err != nil {
- return err
- }
+ engine := enc.lockAndGetEncEngine(rt)
if value.Type().Kind() == reflect.Struct {
- return encodeStruct(engine, b, value.Addr())
+ enc.encodeStruct(b, engine, value.Addr())
+ } else {
+ enc.encodeSingle(b, engine, value.Addr())
}
- return encodeSingle(engine, b, value.Addr())
+ return nil
}
diff --git a/src/pkg/gob/encoder.go b/src/pkg/gob/encoder.go
index aba8d0e5c..8869b2629 100644
--- a/src/pkg/gob/encoder.go
+++ b/src/pkg/gob/encoder.go
@@ -21,6 +21,7 @@ type Encoder struct {
state *encoderState // so we can encode integers, strings directly
countState *encoderState // stage for writing counts
buf []byte // for collecting the output.
+ err os.Error
}
// NewEncoder returns a new encoder that will transmit on the io.Writer.
@@ -28,10 +29,8 @@ func NewEncoder(w io.Writer) *Encoder {
enc := new(Encoder)
enc.w = w
enc.sent = make(map[reflect.Type]typeId)
- enc.state = new(encoderState)
- enc.state.b = new(bytes.Buffer) // the rest isn't important; all we need is buffer and writer
- enc.countState = new(encoderState)
- enc.countState.b = new(bytes.Buffer) // the rest isn't important; all we need is buffer and writer
+ enc.state = newEncoderState(enc, new(bytes.Buffer))
+ enc.countState = newEncoderState(enc, new(bytes.Buffer))
return enc
}
@@ -40,8 +39,8 @@ func (enc *Encoder) badType(rt reflect.Type) {
}
func (enc *Encoder) setError(err os.Error) {
- if enc.state.err == nil { // remember the first.
- enc.state.err = err
+ if enc.err == nil { // remember the first.
+ enc.err = err
}
enc.state.b.Reset()
}
@@ -49,7 +48,7 @@ func (enc *Encoder) setError(err os.Error) {
// Send the data item preceded by a unsigned count of its length.
func (enc *Encoder) send() {
// Encode the length.
- encodeUint(enc.countState, uint64(enc.state.b.Len()))
+ enc.countState.encodeUint(uint64(enc.state.b.Len()))
// Build the buffer.
countLen := enc.countState.b.Len()
total := countLen + enc.state.b.Len()
@@ -74,7 +73,7 @@ func (enc *Encoder) sendType(origt reflect.Type) (sent bool) {
switch rt := rt.(type) {
default:
- // Basic types do not need to be described.
+ // Basic types and interfaces do not need to be described.
return
case *reflect.SliceType:
// If it's []uint8, don't send; it's considered basic.
@@ -92,7 +91,7 @@ func (enc *Encoder) sendType(origt reflect.Type) (sent bool) {
case *reflect.StructType:
// structs must be sent so we know their fields.
break
- case *reflect.ChanType, *reflect.FuncType, *reflect.InterfaceType:
+ case *reflect.ChanType, *reflect.FuncType:
// Probably a bad field in a struct.
enc.badType(rt)
return
@@ -113,11 +112,11 @@ func (enc *Encoder) sendType(origt reflect.Type) (sent bool) {
}
// Send the pair (-id, type)
// Id:
- encodeInt(enc.state, -int64(info.id))
+ enc.state.encodeInt(-int64(info.id))
// Type:
- encode(enc.state.b, reflect.NewValue(info.wire))
+ enc.encode(enc.state.b, reflect.NewValue(info.wire))
enc.send()
- if enc.state.err != nil {
+ if enc.err != nil {
return
}
@@ -134,7 +133,7 @@ func (enc *Encoder) sendType(origt reflect.Type) (sent bool) {
case reflect.ArrayOrSliceType:
enc.sendType(st.Elem())
}
- return
+ return true
}
// Encode transmits the data item represented by the empty interface value,
@@ -143,30 +142,17 @@ func (enc *Encoder) Encode(e interface{}) os.Error {
return enc.EncodeValue(reflect.NewValue(e))
}
-// EncodeValue transmits the data item represented by the reflection value,
-// guaranteeing that all necessary type information has been transmitted first.
-func (enc *Encoder) EncodeValue(value reflect.Value) os.Error {
- // Make sure we're single-threaded through here, so multiple
- // goroutines can share an encoder.
- enc.mutex.Lock()
- defer enc.mutex.Unlock()
-
- enc.state.err = nil
- rt, _ := indirect(value.Type())
-
- // Sanity check only: encoder should never come in with data present.
- if enc.state.b.Len() > 0 || enc.countState.b.Len() > 0 {
- enc.state.err = os.ErrorString("encoder: buffer not empty")
- return enc.state.err
- }
-
+// sendTypeId makes sure the remote side knows about this type.
+// It will send a descriptor if this is the first time the type has been
+// sent. Regardless, it sends the id.
+func (enc *Encoder) sendTypeDescriptor(rt reflect.Type) {
// Make sure the type is known to the other side.
// First, have we already sent this type?
if _, alreadySent := enc.sent[rt]; !alreadySent {
// No, so send it.
sent := enc.sendType(rt)
- if enc.state.err != nil {
- return enc.state.err
+ if enc.err != nil {
+ return
}
// If the type info has still not been transmitted, it means we have
// a singleton basic type (int, []byte etc.) at top level. We don't
@@ -177,22 +163,45 @@ func (enc *Encoder) EncodeValue(value reflect.Value) os.Error {
typeLock.Unlock()
if err != nil {
enc.setError(err)
- return err
+ return
}
enc.sent[rt] = info.id
}
}
// Identify the type of this top-level value.
- encodeInt(enc.state, int64(enc.sent[rt]))
+ enc.state.encodeInt(int64(enc.sent[rt]))
+}
+
+// EncodeValue transmits the data item represented by the reflection value,
+// guaranteeing that all necessary type information has been transmitted first.
+func (enc *Encoder) EncodeValue(value reflect.Value) os.Error {
+ // Make sure we're single-threaded through here, so multiple
+ // goroutines can share an encoder.
+ enc.mutex.Lock()
+ defer enc.mutex.Unlock()
+
+ enc.err = nil
+ rt, _ := indirect(value.Type())
+
+ // Sanity check only: encoder should never come in with data present.
+ if enc.state.b.Len() > 0 || enc.countState.b.Len() > 0 {
+ enc.err = os.ErrorString("encoder: buffer not empty")
+ return enc.err
+ }
+
+ enc.sendTypeDescriptor(rt)
+ if enc.err != nil {
+ return enc.err
+ }
// Encode the object.
- err := encode(enc.state.b, value)
+ err := enc.encode(enc.state.b, value)
if err != nil {
enc.setError(err)
} else {
enc.send()
}
- return enc.state.err
+ return enc.err
}
diff --git a/src/pkg/gob/encoder_test.go b/src/pkg/gob/encoder_test.go
index b578cd0f8..db0b7db66 100644
--- a/src/pkg/gob/encoder_test.go
+++ b/src/pkg/gob/encoder_test.go
@@ -14,48 +14,48 @@ import (
)
type ET2 struct {
- x string
+ X string
}
type ET1 struct {
- a int
- et2 *ET2
- next *ET1
+ A int
+ Et2 *ET2
+ Next *ET1
}
// Like ET1 but with a different name for a field
type ET3 struct {
- a int
- et2 *ET2
- differentNext *ET1
+ A int
+ Et2 *ET2
+ DifferentNext *ET1
}
// Like ET1 but with a different type for a field
type ET4 struct {
- a int
- et2 float
- next int
+ A int
+ Et2 float
+ Next int
}
func TestEncoderDecoder(t *testing.T) {
b := new(bytes.Buffer)
enc := NewEncoder(b)
et1 := new(ET1)
- et1.a = 7
- et1.et2 = new(ET2)
- enc.Encode(et1)
- if enc.state.err != nil {
- t.Error("encoder fail:", enc.state.err)
+ et1.A = 7
+ et1.Et2 = new(ET2)
+ err := enc.Encode(et1)
+ if err != nil {
+ t.Error("encoder fail:", err)
}
dec := NewDecoder(b)
newEt1 := new(ET1)
- dec.Decode(newEt1)
- if dec.state.err != nil {
- t.Fatal("error decoding ET1:", dec.state.err)
+ err = dec.Decode(newEt1)
+ if err != nil {
+ t.Fatal("error decoding ET1:", err)
}
if !reflect.DeepEqual(et1, newEt1) {
- t.Fatalf("invalid data for et1: expected %+v; got %+v\n", *et1, *newEt1)
+ t.Fatalf("invalid data for et1: expected %+v; got %+v", *et1, *newEt1)
}
if b.Len() != 0 {
t.Error("not at eof;", b.Len(), "bytes left")
@@ -63,25 +63,25 @@ func TestEncoderDecoder(t *testing.T) {
enc.Encode(et1)
newEt1 = new(ET1)
- dec.Decode(newEt1)
- if dec.state.err != nil {
- t.Fatal("round 2: error decoding ET1:", dec.state.err)
+ err = dec.Decode(newEt1)
+ if err != nil {
+ t.Fatal("round 2: error decoding ET1:", err)
}
if !reflect.DeepEqual(et1, newEt1) {
- t.Fatalf("round 2: invalid data for et1: expected %+v; got %+v\n", *et1, *newEt1)
+ t.Fatalf("round 2: invalid data for et1: expected %+v; got %+v", *et1, *newEt1)
}
if b.Len() != 0 {
t.Error("round 2: not at eof;", b.Len(), "bytes left")
}
// Now test with a running encoder/decoder pair that we recognize a type mismatch.
- enc.Encode(et1)
- if enc.state.err != nil {
- t.Error("round 3: encoder fail:", enc.state.err)
+ err = enc.Encode(et1)
+ if err != nil {
+ t.Error("round 3: encoder fail:", err)
}
newEt2 := new(ET2)
- dec.Decode(newEt2)
- if dec.state.err == nil {
+ err = dec.Decode(newEt2)
+ if err == nil {
t.Fatal("round 3: expected `bad type' error decoding ET2")
}
}
@@ -92,19 +92,19 @@ func badTypeCheck(e interface{}, shouldFail bool, msg string, t *testing.T) {
b := new(bytes.Buffer)
enc := NewEncoder(b)
et1 := new(ET1)
- et1.a = 7
- et1.et2 = new(ET2)
- enc.Encode(et1)
- if enc.state.err != nil {
- t.Error("encoder fail:", enc.state.err)
+ et1.A = 7
+ et1.Et2 = new(ET2)
+ err := enc.Encode(et1)
+ if err != nil {
+ t.Error("encoder fail:", err)
}
dec := NewDecoder(b)
- dec.Decode(e)
- if shouldFail && (dec.state.err == nil) {
+ err = dec.Decode(e)
+ if shouldFail && err == nil {
t.Error("expected error for", msg)
}
- if !shouldFail && (dec.state.err != nil) {
- t.Error("unexpected error for", msg, dec.state.err)
+ if !shouldFail && err != nil {
+ t.Error("unexpected error for", msg, err)
}
}
@@ -118,9 +118,9 @@ func TestWrongTypeDecoder(t *testing.T) {
func corruptDataCheck(s string, err os.Error, t *testing.T) {
b := bytes.NewBufferString(s)
dec := NewDecoder(b)
- dec.Decode(new(ET2))
- if dec.state.err != err {
- t.Error("expected error", err, "got", dec.state.err)
+ err1 := dec.Decode(new(ET2))
+ if err1 != err {
+ t.Error("expected error", err, "got", err1)
}
}
@@ -135,7 +135,6 @@ func TestBadData(t *testing.T) {
var unsupportedValues = []interface{}{
make(chan int),
func(a int) bool { return true },
- new(interface{}),
}
func TestUnsupported(t *testing.T) {
@@ -152,14 +151,14 @@ func TestUnsupported(t *testing.T) {
func encAndDec(in, out interface{}) os.Error {
b := new(bytes.Buffer)
enc := NewEncoder(b)
- enc.Encode(in)
- if enc.state.err != nil {
- return enc.state.err
+ err := enc.Encode(in)
+ if err != nil {
+ return err
}
dec := NewDecoder(b)
- dec.Decode(out)
- if dec.state.err != nil {
- return dec.state.err
+ err = dec.Decode(out)
+ if err != nil {
+ return err
}
return nil
}
@@ -167,7 +166,7 @@ func encAndDec(in, out interface{}) os.Error {
func TestTypeToPtrType(t *testing.T) {
// Encode a T, decode a *T
type Type0 struct {
- a int
+ A int
}
t0 := Type0{7}
t0p := (*Type0)(nil)
@@ -179,7 +178,7 @@ func TestTypeToPtrType(t *testing.T) {
func TestPtrTypeToType(t *testing.T) {
// Encode a *T, decode a T
type Type1 struct {
- a uint
+ A uint
}
t1p := &Type1{17}
var t1 Type1
@@ -190,26 +189,26 @@ func TestPtrTypeToType(t *testing.T) {
func TestTypeToPtrPtrPtrPtrType(t *testing.T) {
type Type2 struct {
- a ****float
+ A ****float
}
t2 := Type2{}
- t2.a = new(***float)
- *t2.a = new(**float)
- **t2.a = new(*float)
- ***t2.a = new(float)
- ****t2.a = 27.4
+ t2.A = new(***float)
+ *t2.A = new(**float)
+ **t2.A = new(*float)
+ ***t2.A = new(float)
+ ****t2.A = 27.4
t2pppp := new(***Type2)
if err := encAndDec(t2, t2pppp); err != nil {
- t.Error(err)
+ t.Fatal(err)
}
- if ****(****t2pppp).a != ****t2.a {
- t.Errorf("wrong value after decode: %g not %g", ****(****t2pppp).a, ****t2.a)
+ if ****(****t2pppp).A != ****t2.A {
+ t.Errorf("wrong value after decode: %g not %g", ****(****t2pppp).A, ****t2.A)
}
}
func TestSlice(t *testing.T) {
type Type3 struct {
- a []string
+ A []string
}
t3p := &Type3{[]string{"hello", "world"}}
var t3 Type3
@@ -232,11 +231,11 @@ func TestValueError(t *testing.T) {
func TestArray(t *testing.T) {
type Type5 struct {
- a [3]string
- b [3]byte
+ A [3]string
+ B [3]byte
}
type Type6 struct {
- a [2]string // can't hold t5.a
+ A [2]string // can't hold t5.a
}
t5 := Type5{[3]string{"hello", ",", "world"}, [3]byte{1, 2, 3}}
var t5p Type5
@@ -252,10 +251,10 @@ func TestArray(t *testing.T) {
// Regression test for bug: must send zero values inside arrays
func TestDefaultsInArray(t *testing.T) {
type Type7 struct {
- b []bool
- i []int
- s []string
- f []float
+ B []bool
+ I []int
+ S []string
+ F []float
}
t7 := Type7{
[]bool{false, false, true},
@@ -274,6 +273,7 @@ var testFloat32 float32
var testString string
var testSlice []string
var testMap map[string]int
+var testArray [7]int
type SingleTest struct {
in interface{}
@@ -282,14 +282,16 @@ type SingleTest struct {
}
var singleTests = []SingleTest{
- SingleTest{17, &testInt, ""},
- SingleTest{float32(17.5), &testFloat32, ""},
- SingleTest{"bike shed", &testString, ""},
- SingleTest{[]string{"bike", "shed", "paint", "color"}, &testSlice, ""},
- SingleTest{map[string]int{"seven": 7, "twelve": 12}, &testMap, ""},
+ {17, &testInt, ""},
+ {float32(17.5), &testFloat32, ""},
+ {"bike shed", &testString, ""},
+ {[]string{"bike", "shed", "paint", "color"}, &testSlice, ""},
+ {map[string]int{"seven": 7, "twelve": 12}, &testMap, ""},
+ {[7]int{4, 55, 0, 0, 0, 0, 0}, &testArray, ""}, // case that once triggered a bug
+ {[7]int{4, 55, 1, 44, 22, 66, 1234}, &testArray, ""},
// Decode errors
- SingleTest{172, &testFloat32, "wrong type"},
+ {172, &testFloat32, "wrong type"},
}
func TestSingletons(t *testing.T) {
@@ -320,7 +322,64 @@ func TestSingletons(t *testing.T) {
// Get rid of the pointer in the rhs
val := reflect.NewValue(test.out).(*reflect.PtrValue).Elem().Interface()
if !reflect.DeepEqual(test.in, val) {
- t.Errorf("decoding int: expected %v got %v", test.in, val)
+ t.Errorf("decoding singleton: expected %v got %v", test.in, val)
}
}
}
+
+func TestStructNonStruct(t *testing.T) {
+ type Struct struct {
+ A string
+ }
+ type NonStruct string
+ s := Struct{"hello"}
+ var sp Struct
+ if err := encAndDec(s, &sp); err != nil {
+ t.Error(err)
+ }
+ var ns NonStruct
+ if err := encAndDec(s, &ns); err == nil {
+ t.Error("should get error for struct/non-struct")
+ } else if strings.Index(err.String(), "type") < 0 {
+ t.Error("for struct/non-struct expected type error; got", err)
+ }
+ // Now try the other way
+ var nsp NonStruct
+ if err := encAndDec(ns, &nsp); err != nil {
+ t.Error(err)
+ }
+ if err := encAndDec(ns, &s); err == nil {
+ t.Error("should get error for non-struct/struct")
+ } else if strings.Index(err.String(), "type") < 0 {
+ t.Error("for non-struct/struct expected type error; got", err)
+ }
+}
+
+type interfaceIndirectTestI interface {
+ F() bool
+}
+
+type interfaceIndirectTestT struct{}
+
+func (this *interfaceIndirectTestT) F() bool {
+ return true
+}
+
+// A version of a bug reported on golang-nuts. Also tests top-level
+// slice of interfaces. The issue was registering *T caused T to be
+// stored as the concrete type.
+func TestInterfaceIndirect(t *testing.T) {
+ Register(&interfaceIndirectTestT{})
+ b := new(bytes.Buffer)
+ w := []interfaceIndirectTestI{&interfaceIndirectTestT{}}
+ err := NewEncoder(b).Encode(w)
+ if err != nil {
+ t.Fatal("encode error:", err)
+ }
+
+ var r []interfaceIndirectTestI
+ err = NewDecoder(b).Decode(&r)
+ if err != nil {
+ t.Fatal("decode error:", err)
+ }
+}
diff --git a/src/pkg/gob/error.go b/src/pkg/gob/error.go
new file mode 100644
index 000000000..b053761fb
--- /dev/null
+++ b/src/pkg/gob/error.go
@@ -0,0 +1,41 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gob
+
+import (
+ "fmt"
+ "os"
+)
+
+// Errors in decoding and encoding are handled using panic and recover.
+// Panics caused by user error (that is, everything except run-time panics
+// such as "index out of bounds" errors) do not leave the file that caused
+// them, but are instead turned into plain os.Error returns. Encoding and
+// decoding functions and methods that do not return an os.Error either use
+// panic to report an error or are guaranteed error-free.
+
+// A gobError wraps an os.Error and is used to distinguish errors (panics) generated in this package.
+type gobError struct {
+ os.Error
+}
+
+// errorf is like error but takes Printf-style arguments to construct an os.Error.
+func errorf(format string, args ...interface{}) {
+ error(fmt.Errorf(format, args...))
+}
+
+// error wraps the argument error and uses it as the argument to panic.
+func error(err os.Error) {
+ panic(gobError{Error: err})
+}
+
+// catchError is meant to be used as a deferred function to turn a panic(gobError) into a
+// plain os.Error. It overwrites the error return of the function that deferred its call.
+func catchError(err *os.Error) {
+ if e := recover(); e != nil {
+ *err = e.(gobError).Error // Will re-panic if not one of our errors, such as a runtime error.
+ }
+ return
+}
diff --git a/src/pkg/gob/type.go b/src/pkg/gob/type.go
index 0b01b74dc..c00af87bf 100644
--- a/src/pkg/gob/type.go
+++ b/src/pkg/gob/type.go
@@ -29,7 +29,7 @@ const firstUserId = 64 // lowest id number granted to user
type gobType interface {
id() typeId
setId(id typeId)
- Name() string
+ name() string
string() string // not public; only for debugging
safeString(seen map[typeId]bool) string
}
@@ -52,42 +52,60 @@ func (t typeId) gobType() gobType {
}
// string returns the string representation of the type associated with the typeId.
-func (t typeId) string() string { return t.gobType().string() }
+func (t typeId) string() string {
+ if t.gobType() == nil {
+ return "<nil>"
+ }
+ return t.gobType().string()
+}
// Name returns the name of the type associated with the typeId.
-func (t typeId) Name() string { return t.gobType().Name() }
+func (t typeId) name() string {
+ if t.gobType() == nil {
+ return "<nil>"
+ }
+ return t.gobType().name()
+}
// Common elements of all types.
-type commonType struct {
- name string
- _id typeId
+type CommonType struct {
+ Name string
+ Id typeId
}
-func (t *commonType) id() typeId { return t._id }
+func (t *CommonType) id() typeId { return t.Id }
-func (t *commonType) setId(id typeId) { t._id = id }
+func (t *CommonType) setId(id typeId) { t.Id = id }
-func (t *commonType) string() string { return t.name }
+func (t *CommonType) string() string { return t.Name }
-func (t *commonType) safeString(seen map[typeId]bool) string {
- return t.name
+func (t *CommonType) safeString(seen map[typeId]bool) string {
+ return t.Name
}
-func (t *commonType) Name() string { return t.name }
+func (t *CommonType) name() string { return t.Name }
// Create and check predefined types
// The string for tBytes is "bytes" not "[]byte" to signify its specialness.
var (
// Primordial types, needed during initialization.
- tBool = bootstrapType("bool", false, 1)
- tInt = bootstrapType("int", int(0), 2)
- tUint = bootstrapType("uint", uint(0), 3)
- tFloat = bootstrapType("float", float64(0), 4)
- tBytes = bootstrapType("bytes", make([]byte, 0), 5)
- tString = bootstrapType("string", "", 6)
- // Types added to the language later, not needed during initialization.
- tComplex typeId
+ tBool = bootstrapType("bool", false, 1)
+ tInt = bootstrapType("int", int(0), 2)
+ tUint = bootstrapType("uint", uint(0), 3)
+ tFloat = bootstrapType("float", float64(0), 4)
+ tBytes = bootstrapType("bytes", make([]byte, 0), 5)
+ tString = bootstrapType("string", "", 6)
+ tComplex = bootstrapType("complex", 0+0i, 7)
+ tInterface = bootstrapType("interface", interface{}(nil), 8)
+ // Reserve some Ids for compatible expansion
+ tReserved7 = bootstrapType("_reserved1", struct{ r7 int }{}, 9)
+ tReserved6 = bootstrapType("_reserved1", struct{ r6 int }{}, 10)
+ tReserved5 = bootstrapType("_reserved1", struct{ r5 int }{}, 11)
+ tReserved4 = bootstrapType("_reserved1", struct{ r4 int }{}, 12)
+ tReserved3 = bootstrapType("_reserved1", struct{ r3 int }{}, 13)
+ tReserved2 = bootstrapType("_reserved1", struct{ r2 int }{}, 14)
+ tReserved1 = bootstrapType("_reserved1", struct{ r1 int }{}, 15)
)
// Predefined because it's needed by the Decoder
@@ -95,15 +113,13 @@ var tWireType = mustGetTypeInfo(reflect.Typeof(wireType{})).id
func init() {
// Some magic numbers to make sure there are no surprises.
- checkId(7, tWireType)
- checkId(9, mustGetTypeInfo(reflect.Typeof(commonType{})).id)
- checkId(11, mustGetTypeInfo(reflect.Typeof(structType{})).id)
- checkId(12, mustGetTypeInfo(reflect.Typeof(fieldType{})).id)
-
- // Complex was added after gob was written, so appears after the
- // fundamental types are built.
- tComplex = bootstrapType("complex", 0+0i, 15)
- decIgnoreOpMap[tComplex] = ignoreTwoUints
+ checkId(16, tWireType)
+ checkId(17, mustGetTypeInfo(reflect.Typeof(arrayType{})).id)
+ checkId(18, mustGetTypeInfo(reflect.Typeof(CommonType{})).id)
+ checkId(19, mustGetTypeInfo(reflect.Typeof(sliceType{})).id)
+ checkId(20, mustGetTypeInfo(reflect.Typeof(structType{})).id)
+ checkId(21, mustGetTypeInfo(reflect.Typeof(fieldType{})).id)
+ checkId(23, mustGetTypeInfo(reflect.Typeof(mapType{})).id)
builtinIdToType = make(map[typeId]gobType)
for k, v := range idToType {
@@ -116,26 +132,27 @@ func init() {
panic(fmt.Sprintln("nextId too large:", nextId))
}
nextId = firstUserId
+ registerBasics()
}
// Array type
type arrayType struct {
- commonType
+ CommonType
Elem typeId
Len int
}
func newArrayType(name string, elem gobType, length int) *arrayType {
- a := &arrayType{commonType{name: name}, elem.id(), length}
+ a := &arrayType{CommonType{Name: name}, elem.id(), length}
setTypeId(a)
return a
}
func (a *arrayType) safeString(seen map[typeId]bool) string {
- if seen[a._id] {
- return a.name
+ if seen[a.Id] {
+ return a.Name
}
- seen[a._id] = true
+ seen[a.Id] = true
return fmt.Sprintf("[%d]%s", a.Len, a.Elem.gobType().safeString(seen))
}
@@ -143,22 +160,22 @@ func (a *arrayType) string() string { return a.safeString(make(map[typeId]bool))
// Map type
type mapType struct {
- commonType
+ CommonType
Key typeId
Elem typeId
}
func newMapType(name string, key, elem gobType) *mapType {
- m := &mapType{commonType{name: name}, key.id(), elem.id()}
+ m := &mapType{CommonType{Name: name}, key.id(), elem.id()}
setTypeId(m)
return m
}
func (m *mapType) safeString(seen map[typeId]bool) string {
- if seen[m._id] {
- return m.name
+ if seen[m.Id] {
+ return m.Name
}
- seen[m._id] = true
+ seen[m.Id] = true
key := m.Key.gobType().safeString(seen)
elem := m.Elem.gobType().safeString(seen)
return fmt.Sprintf("map[%s]%s", key, elem)
@@ -168,21 +185,21 @@ func (m *mapType) string() string { return m.safeString(make(map[typeId]bool)) }
// Slice type
type sliceType struct {
- commonType
+ CommonType
Elem typeId
}
func newSliceType(name string, elem gobType) *sliceType {
- s := &sliceType{commonType{name: name}, elem.id()}
+ s := &sliceType{CommonType{Name: name}, elem.id()}
setTypeId(s)
return s
}
func (s *sliceType) safeString(seen map[typeId]bool) string {
- if seen[s._id] {
- return s.name
+ if seen[s.Id] {
+ return s.Name
}
- seen[s._id] = true
+ seen[s.Id] = true
return fmt.Sprintf("[]%s", s.Elem.gobType().safeString(seen))
}
@@ -190,26 +207,26 @@ func (s *sliceType) string() string { return s.safeString(make(map[typeId]bool))
// Struct type
type fieldType struct {
- name string
- id typeId
+ Name string
+ Id typeId
}
type structType struct {
- commonType
- field []*fieldType
+ CommonType
+ Field []*fieldType
}
func (s *structType) safeString(seen map[typeId]bool) string {
if s == nil {
return "<nil>"
}
- if _, ok := seen[s._id]; ok {
- return s.name
+ if _, ok := seen[s.Id]; ok {
+ return s.Name
}
- seen[s._id] = true
- str := s.name + " = struct { "
- for _, f := range s.field {
- str += fmt.Sprintf("%s %s; ", f.name, f.id.gobType().safeString(seen))
+ seen[s.Id] = true
+ str := s.Name + " = struct { "
+ for _, f := range s.Field {
+ str += fmt.Sprintf("%s %s; ", f.Name, f.Id.gobType().safeString(seen))
}
str += "}"
return str
@@ -218,13 +235,13 @@ func (s *structType) safeString(seen map[typeId]bool) string {
func (s *structType) string() string { return s.safeString(make(map[typeId]bool)) }
func newStructType(name string) *structType {
- s := &structType{commonType{name: name}, nil}
+ s := &structType{CommonType{Name: name}, nil}
setTypeId(s)
return s
}
// Step through the indirections on a type to discover the base type.
-// Return the number of indirections.
+// Return the base type and the number of indirections.
func indirect(t reflect.Type) (rt reflect.Type, count int) {
rt = t
for {
@@ -259,6 +276,9 @@ func newTypeObject(name string, rt reflect.Type) (gobType, os.Error) {
case *reflect.StringType:
return tString.gobType(), nil
+ case *reflect.InterfaceType:
+ return tInterface.gobType(), nil
+
case *reflect.ArrayType:
gt, err := getType("", t.Elem())
if err != nil {
@@ -300,7 +320,8 @@ func newTypeObject(name string, rt reflect.Type) (gobType, os.Error) {
typ, _ := indirect(f.Type)
tname := typ.Name()
if tname == "" {
- tname = f.Type.String()
+ t, _ := indirect(f.Type)
+ tname = t.String()
}
gt, err := getType(tname, f.Type)
if err != nil {
@@ -308,7 +329,7 @@ func newTypeObject(name string, rt reflect.Type) (gobType, os.Error) {
}
field[i] = &fieldType{f.Name, gt.id()}
}
- strType.field = field
+ strType.Field = field
return strType, nil
default:
@@ -320,14 +341,7 @@ func newTypeObject(name string, rt reflect.Type) (gobType, os.Error) {
// getType returns the Gob type describing the given reflect.Type.
// typeLock must be held.
func getType(name string, rt reflect.Type) (gobType, os.Error) {
- // Flatten the data structure by collapsing out pointers
- for {
- pt, ok := rt.(*reflect.PtrType)
- if !ok {
- break
- }
- rt = pt.Elem()
- }
+ rt, _ = indirect(rt)
typ, present := types[rt]
if present {
return typ, nil
@@ -341,7 +355,8 @@ func getType(name string, rt reflect.Type) (gobType, os.Error) {
func checkId(want, got typeId) {
if want != got {
- panic("bootstrap type wrong id: " + got.Name() + " " + got.string() + " not " + want.string())
+ fmt.Fprintf(os.Stderr, "checkId: %d should be %d\n", int(want), int(got))
+ panic("bootstrap type wrong id: " + got.name() + " " + got.string() + " not " + want.string())
}
}
@@ -352,7 +367,7 @@ func bootstrapType(name string, e interface{}, expect typeId) typeId {
if present {
panic("bootstrap type already present: " + name + ", " + rt.String())
}
- typ := &commonType{name: name}
+ typ := &CommonType{Name: name}
types[rt] = typ
setTypeId(typ)
checkId(expect, nextId)
@@ -371,17 +386,28 @@ func bootstrapType(name string, e interface{}, expect typeId) typeId {
// To maintain binary compatibility, if you extend this type, always put
// the new fields last.
type wireType struct {
- arrayT *arrayType
- sliceT *sliceType
- structT *structType
- mapT *mapType
+ ArrayT *arrayType
+ SliceT *sliceType
+ StructT *structType
+ MapT *mapType
}
-func (w *wireType) name() string {
- if w.structT != nil {
- return w.structT.name
+func (w *wireType) string() string {
+ const unknown = "unknown type"
+ if w == nil {
+ return unknown
}
- return "unknown"
+ switch {
+ case w.ArrayT != nil:
+ return w.ArrayT.Name
+ case w.SliceT != nil:
+ return w.SliceT.Name
+ case w.StructT != nil:
+ return w.StructT.Name
+ case w.MapT != nil:
+ return w.MapT.Name
+ }
+ return unknown
}
type typeInfo struct {
@@ -410,16 +436,16 @@ func getTypeInfo(rt reflect.Type) (*typeInfo, os.Error) {
t := info.id.gobType()
switch typ := rt.(type) {
case *reflect.ArrayType:
- info.wire = &wireType{arrayT: t.(*arrayType)}
+ info.wire = &wireType{ArrayT: t.(*arrayType)}
case *reflect.MapType:
- info.wire = &wireType{mapT: t.(*mapType)}
+ info.wire = &wireType{MapT: t.(*mapType)}
case *reflect.SliceType:
// []byte == []uint8 is a special case handled separately
if typ.Elem().Kind() != reflect.Uint8 {
- info.wire = &wireType{sliceT: t.(*sliceType)}
+ info.wire = &wireType{SliceT: t.(*sliceType)}
}
case *reflect.StructType:
- info.wire = &wireType{structT: t.(*structType)}
+ info.wire = &wireType{StructT: t.(*structType)}
}
typeInfoMap[rt] = info
}
@@ -434,3 +460,82 @@ func mustGetTypeInfo(rt reflect.Type) *typeInfo {
}
return t
}
+
+var (
+ nameToConcreteType = make(map[string]reflect.Type)
+ concreteTypeToName = make(map[reflect.Type]string)
+)
+
+// RegisterName is like Register but uses the provided name rather than the
+// type's default.
+func RegisterName(name string, value interface{}) {
+ if name == "" {
+ // reserved for nil
+ panic("attempt to register empty name")
+ }
+ rt, _ := indirect(reflect.Typeof(value))
+ // Check for incompatible duplicates.
+ if t, ok := nameToConcreteType[name]; ok && t != rt {
+ panic("gob: registering duplicate types for " + name)
+ }
+ if n, ok := concreteTypeToName[rt]; ok && n != name {
+ panic("gob: registering duplicate names for " + rt.String())
+ }
+ // Store the name and type provided by the user....
+ nameToConcreteType[name] = reflect.Typeof(value)
+ // but the flattened type in the type table, since that's what decode needs.
+ concreteTypeToName[rt] = name
+}
+
+// Register records a type, identified by a value for that type, under its
+// internal type name. That name will identify the concrete type of a value
+// sent or received as an interface variable. Only types that will be
+// transferred as implementations of interface values need to be registered.
+// Expecting to be used only during initialization, it panics if the mapping
+// between types and names is not a bijection.
+func Register(value interface{}) {
+ // Default to printed representation for unnamed types
+ rt := reflect.Typeof(value)
+ name := rt.String()
+
+ // But for named types (or pointers to them), qualify with import path.
+ // Dereference one pointer looking for a named type.
+ star := ""
+ if rt.Name() == "" {
+ if pt, ok := rt.(*reflect.PtrType); ok {
+ star = "*"
+ rt = pt
+ }
+ }
+ if rt.Name() != "" {
+ if rt.PkgPath() == "" {
+ name = star + rt.Name()
+ } else {
+ name = star + rt.PkgPath() + "." + rt.Name()
+ }
+ }
+
+ RegisterName(name, value)
+}
+
+func registerBasics() {
+ Register(int(0))
+ Register(int8(0))
+ Register(int16(0))
+ Register(int32(0))
+ Register(int64(0))
+ Register(uint(0))
+ Register(uint8(0))
+ Register(uint16(0))
+ Register(uint32(0))
+ Register(uint64(0))
+ Register(float(0))
+ Register(float32(0))
+ Register(float64(0))
+ Register(complex(0i))
+ Register(complex64(0i))
+ Register(complex128(0i))
+ Register(false)
+ Register("")
+ Register([]byte(nil))
+}
diff --git a/src/pkg/gob/type_test.go b/src/pkg/gob/type_test.go
index 6acfa7135..106e4f10b 100644
--- a/src/pkg/gob/type_test.go
+++ b/src/pkg/gob/type_test.go
@@ -15,12 +15,12 @@ type typeT struct {
}
var basicTypes = []typeT{
- typeT{tBool, "bool"},
- typeT{tInt, "int"},
- typeT{tUint, "uint"},
- typeT{tFloat, "float"},
- typeT{tBytes, "bytes"},
- typeT{tString, "string"},
+ {tBool, "bool"},
+ {tInt, "int"},
+ {tUint, "uint"},
+ {tFloat, "float"},
+ {tBytes, "bytes"},
+ {tString, "string"},
}
func getTypeUnlocked(name string, rt reflect.Type) gobType {
diff --git a/src/pkg/hash/Makefile b/src/pkg/hash/Makefile
index aaa641f7c..56071cb33 100644
--- a/src/pkg/hash/Makefile
+++ b/src/pkg/hash/Makefile
@@ -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 ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=hash
GOFILES=\
diff --git a/src/pkg/hash/adler32/Makefile b/src/pkg/hash/adler32/Makefile
index 6f6d66fd0..38ce537ba 100644
--- a/src/pkg/hash/adler32/Makefile
+++ b/src/pkg/hash/adler32/Makefile
@@ -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 ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=hash/adler32
GOFILES=\
diff --git a/src/pkg/hash/adler32/adler32_test.go b/src/pkg/hash/adler32/adler32_test.go
index cfe9c9547..ffa5569bc 100644
--- a/src/pkg/hash/adler32/adler32_test.go
+++ b/src/pkg/hash/adler32/adler32_test.go
@@ -15,38 +15,38 @@ type _Adler32Test struct {
}
var golden = []_Adler32Test{
- _Adler32Test{0x1, ""},
- _Adler32Test{0x620062, "a"},
- _Adler32Test{0x12600c4, "ab"},
- _Adler32Test{0x24d0127, "abc"},
- _Adler32Test{0x3d8018b, "abcd"},
- _Adler32Test{0x5c801f0, "abcde"},
- _Adler32Test{0x81e0256, "abcdef"},
- _Adler32Test{0xadb02bd, "abcdefg"},
- _Adler32Test{0xe000325, "abcdefgh"},
- _Adler32Test{0x118e038e, "abcdefghi"},
- _Adler32Test{0x158603f8, "abcdefghij"},
- _Adler32Test{0x3f090f02, "Discard medicine more than two years old."},
- _Adler32Test{0x46d81477, "He who has a shady past knows that nice guys finish last."},
- _Adler32Test{0x40ee0ee1, "I wouldn't marry him with a ten foot pole."},
- _Adler32Test{0x16661315, "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
- _Adler32Test{0x5b2e1480, "The days of the digital watch are numbered. -Tom Stoppard"},
- _Adler32Test{0x8c3c09ea, "Nepal premier won't resign."},
- _Adler32Test{0x45ac18fd, "For every action there is an equal and opposite government program."},
- _Adler32Test{0x53c61462, "His money is twice tainted: 'taint yours and 'taint mine."},
- _Adler32Test{0x7e511e63, "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
- _Adler32Test{0xe4801a6a, "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
- _Adler32Test{0x61b507df, "size: a.out: bad magic"},
- _Adler32Test{0xb8631171, "The major problem is with sendmail. -Mark Horton"},
- _Adler32Test{0x8b5e1904, "Give me a rock, paper and scissors and I will move the world. CCFestoon"},
- _Adler32Test{0x7cc6102b, "If the enemy is within range, then so are you."},
- _Adler32Test{0x700318e7, "It's well we cannot hear the screams/That we create in others' dreams."},
- _Adler32Test{0x1e601747, "You remind me of a TV show, but that's all right: I watch it anyway."},
- _Adler32Test{0xb55b0b09, "C is as portable as Stonehedge!!"},
- _Adler32Test{0x39111dd0, "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
- _Adler32Test{0x91dd304f, "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"},
- _Adler32Test{0x2e5d1316, "How can you write a big system without C++? -Paul Glick"},
- _Adler32Test{0xd0201df6, "'Invariant assertions' is the most elegant programming technique! -Tom Szymanski"},
+ {0x1, ""},
+ {0x620062, "a"},
+ {0x12600c4, "ab"},
+ {0x24d0127, "abc"},
+ {0x3d8018b, "abcd"},
+ {0x5c801f0, "abcde"},
+ {0x81e0256, "abcdef"},
+ {0xadb02bd, "abcdefg"},
+ {0xe000325, "abcdefgh"},
+ {0x118e038e, "abcdefghi"},
+ {0x158603f8, "abcdefghij"},
+ {0x3f090f02, "Discard medicine more than two years old."},
+ {0x46d81477, "He who has a shady past knows that nice guys finish last."},
+ {0x40ee0ee1, "I wouldn't marry him with a ten foot pole."},
+ {0x16661315, "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
+ {0x5b2e1480, "The days of the digital watch are numbered. -Tom Stoppard"},
+ {0x8c3c09ea, "Nepal premier won't resign."},
+ {0x45ac18fd, "For every action there is an equal and opposite government program."},
+ {0x53c61462, "His money is twice tainted: 'taint yours and 'taint mine."},
+ {0x7e511e63, "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
+ {0xe4801a6a, "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
+ {0x61b507df, "size: a.out: bad magic"},
+ {0xb8631171, "The major problem is with sendmail. -Mark Horton"},
+ {0x8b5e1904, "Give me a rock, paper and scissors and I will move the world. CCFestoon"},
+ {0x7cc6102b, "If the enemy is within range, then so are you."},
+ {0x700318e7, "It's well we cannot hear the screams/That we create in others' dreams."},
+ {0x1e601747, "You remind me of a TV show, but that's all right: I watch it anyway."},
+ {0xb55b0b09, "C is as portable as Stonehedge!!"},
+ {0x39111dd0, "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
+ {0x91dd304f, "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"},
+ {0x2e5d1316, "How can you write a big system without C++? -Paul Glick"},
+ {0xd0201df6, "'Invariant assertions' is the most elegant programming technique! -Tom Szymanski"},
}
func TestGolden(t *testing.T) {
diff --git a/src/pkg/hash/crc32/Makefile b/src/pkg/hash/crc32/Makefile
index 071d89823..31b205185 100644
--- a/src/pkg/hash/crc32/Makefile
+++ b/src/pkg/hash/crc32/Makefile
@@ -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 ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=hash/crc32
GOFILES=\
diff --git a/src/pkg/hash/crc32/crc32_test.go b/src/pkg/hash/crc32/crc32_test.go
index 45ad84be7..cf5743c99 100644
--- a/src/pkg/hash/crc32/crc32_test.go
+++ b/src/pkg/hash/crc32/crc32_test.go
@@ -15,37 +15,37 @@ type test struct {
}
var golden = []test{
- test{0x0, ""},
- test{0xe8b7be43, "a"},
- test{0x9e83486d, "ab"},
- test{0x352441c2, "abc"},
- test{0xed82cd11, "abcd"},
- test{0x8587d865, "abcde"},
- test{0x4b8e39ef, "abcdef"},
- test{0x312a6aa6, "abcdefg"},
- test{0xaeef2a50, "abcdefgh"},
- test{0x8da988af, "abcdefghi"},
- test{0x3981703a, "abcdefghij"},
- test{0x6b9cdfe7, "Discard medicine more than two years old."},
- test{0xc90ef73f, "He who has a shady past knows that nice guys finish last."},
- test{0xb902341f, "I wouldn't marry him with a ten foot pole."},
- test{0x42080e8, "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
- test{0x154c6d11, "The days of the digital watch are numbered. -Tom Stoppard"},
- test{0x4c418325, "Nepal premier won't resign."},
- test{0x33955150, "For every action there is an equal and opposite government program."},
- test{0x26216a4b, "His money is twice tainted: 'taint yours and 'taint mine."},
- test{0x1abbe45e, "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
- test{0xc89a94f7, "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
- test{0xab3abe14, "size: a.out: bad magic"},
- test{0xbab102b6, "The major problem is with sendmail. -Mark Horton"},
- test{0x999149d7, "Give me a rock, paper and scissors and I will move the world. CCFestoon"},
- test{0x6d52a33c, "If the enemy is within range, then so are you."},
- test{0x90631e8d, "It's well we cannot hear the screams/That we create in others' dreams."},
- test{0x78309130, "You remind me of a TV show, but that's all right: I watch it anyway."},
- test{0x7d0a377f, "C is as portable as Stonehedge!!"},
- test{0x8c79fd79, "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
- test{0xa20b7167, "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"},
- test{0x8e0bb443, "How can you write a big system without C++? -Paul Glick"},
+ {0x0, ""},
+ {0xe8b7be43, "a"},
+ {0x9e83486d, "ab"},
+ {0x352441c2, "abc"},
+ {0xed82cd11, "abcd"},
+ {0x8587d865, "abcde"},
+ {0x4b8e39ef, "abcdef"},
+ {0x312a6aa6, "abcdefg"},
+ {0xaeef2a50, "abcdefgh"},
+ {0x8da988af, "abcdefghi"},
+ {0x3981703a, "abcdefghij"},
+ {0x6b9cdfe7, "Discard medicine more than two years old."},
+ {0xc90ef73f, "He who has a shady past knows that nice guys finish last."},
+ {0xb902341f, "I wouldn't marry him with a ten foot pole."},
+ {0x42080e8, "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
+ {0x154c6d11, "The days of the digital watch are numbered. -Tom Stoppard"},
+ {0x4c418325, "Nepal premier won't resign."},
+ {0x33955150, "For every action there is an equal and opposite government program."},
+ {0x26216a4b, "His money is twice tainted: 'taint yours and 'taint mine."},
+ {0x1abbe45e, "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
+ {0xc89a94f7, "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
+ {0xab3abe14, "size: a.out: bad magic"},
+ {0xbab102b6, "The major problem is with sendmail. -Mark Horton"},
+ {0x999149d7, "Give me a rock, paper and scissors and I will move the world. CCFestoon"},
+ {0x6d52a33c, "If the enemy is within range, then so are you."},
+ {0x90631e8d, "It's well we cannot hear the screams/That we create in others' dreams."},
+ {0x78309130, "You remind me of a TV show, but that's all right: I watch it anyway."},
+ {0x7d0a377f, "C is as portable as Stonehedge!!"},
+ {0x8c79fd79, "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
+ {0xa20b7167, "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"},
+ {0x8e0bb443, "How can you write a big system without C++? -Paul Glick"},
}
func TestGolden(t *testing.T) {
diff --git a/src/pkg/hash/crc64/Makefile b/src/pkg/hash/crc64/Makefile
index 01b755b3e..5f6c3de69 100644
--- a/src/pkg/hash/crc64/Makefile
+++ b/src/pkg/hash/crc64/Makefile
@@ -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 ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=hash/crc64
GOFILES=\
diff --git a/src/pkg/hash/crc64/crc64.go b/src/pkg/hash/crc64/crc64.go
index 89e431977..844386564 100644
--- a/src/pkg/hash/crc64/crc64.go
+++ b/src/pkg/hash/crc64/crc64.go
@@ -80,7 +80,7 @@ func (d *digest) Sum64() uint64 { return d.crc }
func (d *digest) Sum() []byte {
p := make([]byte, 8)
s := d.Sum64()
- p[0] = byte(s >> 54)
+ p[0] = byte(s >> 56)
p[1] = byte(s >> 48)
p[2] = byte(s >> 40)
p[3] = byte(s >> 32)
diff --git a/src/pkg/hash/crc64/crc64_test.go b/src/pkg/hash/crc64/crc64_test.go
index 664e1aeb3..e932524e0 100644
--- a/src/pkg/hash/crc64/crc64_test.go
+++ b/src/pkg/hash/crc64/crc64_test.go
@@ -15,37 +15,37 @@ type test struct {
}
var golden = []test{
- test{0x0, ""},
- test{0x3420000000000000, "a"},
- test{0x36c4200000000000, "ab"},
- test{0x3776c42000000000, "abc"},
- test{0x336776c420000000, "abcd"},
- test{0x32d36776c4200000, "abcde"},
- test{0x3002d36776c42000, "abcdef"},
- test{0x31b002d36776c420, "abcdefg"},
- test{0xe21b002d36776c4, "abcdefgh"},
- test{0x8b6e21b002d36776, "abcdefghi"},
- test{0x7f5b6e21b002d367, "abcdefghij"},
- test{0x8ec0e7c835bf9cdf, "Discard medicine more than two years old."},
- test{0xc7db1759e2be5ab4, "He who has a shady past knows that nice guys finish last."},
- test{0xfbf9d9603a6fa020, "I wouldn't marry him with a ten foot pole."},
- test{0xeafc4211a6daa0ef, "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
- test{0x3e05b21c7a4dc4da, "The days of the digital watch are numbered. -Tom Stoppard"},
- test{0x5255866ad6ef28a6, "Nepal premier won't resign."},
- test{0x8a79895be1e9c361, "For every action there is an equal and opposite government program."},
- test{0x8878963a649d4916, "His money is twice tainted: 'taint yours and 'taint mine."},
- test{0xa7b9d53ea87eb82f, "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
- test{0xdb6805c0966a2f9c, "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
- test{0xf3553c65dacdadd2, "size: a.out: bad magic"},
- test{0x9d5e034087a676b9, "The major problem is with sendmail. -Mark Horton"},
- test{0xa6db2d7f8da96417, "Give me a rock, paper and scissors and I will move the world. CCFestoon"},
- test{0x325e00cd2fe819f9, "If the enemy is within range, then so are you."},
- test{0x88c6600ce58ae4c6, "It's well we cannot hear the screams/That we create in others' dreams."},
- test{0x28c4a3f3b769e078, "You remind me of a TV show, but that's all right: I watch it anyway."},
- test{0xa698a34c9d9f1dca, "C is as portable as Stonehedge!!"},
- test{0xf6c1e2a8c26c5cfc, "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
- test{0xd402559dfe9b70c, "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"},
- test{0xdb6efff26aa94946, "How can you write a big system without C++? -Paul Glick"},
+ {0x0, ""},
+ {0x3420000000000000, "a"},
+ {0x36c4200000000000, "ab"},
+ {0x3776c42000000000, "abc"},
+ {0x336776c420000000, "abcd"},
+ {0x32d36776c4200000, "abcde"},
+ {0x3002d36776c42000, "abcdef"},
+ {0x31b002d36776c420, "abcdefg"},
+ {0xe21b002d36776c4, "abcdefgh"},
+ {0x8b6e21b002d36776, "abcdefghi"},
+ {0x7f5b6e21b002d367, "abcdefghij"},
+ {0x8ec0e7c835bf9cdf, "Discard medicine more than two years old."},
+ {0xc7db1759e2be5ab4, "He who has a shady past knows that nice guys finish last."},
+ {0xfbf9d9603a6fa020, "I wouldn't marry him with a ten foot pole."},
+ {0xeafc4211a6daa0ef, "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
+ {0x3e05b21c7a4dc4da, "The days of the digital watch are numbered. -Tom Stoppard"},
+ {0x5255866ad6ef28a6, "Nepal premier won't resign."},
+ {0x8a79895be1e9c361, "For every action there is an equal and opposite government program."},
+ {0x8878963a649d4916, "His money is twice tainted: 'taint yours and 'taint mine."},
+ {0xa7b9d53ea87eb82f, "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
+ {0xdb6805c0966a2f9c, "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
+ {0xf3553c65dacdadd2, "size: a.out: bad magic"},
+ {0x9d5e034087a676b9, "The major problem is with sendmail. -Mark Horton"},
+ {0xa6db2d7f8da96417, "Give me a rock, paper and scissors and I will move the world. CCFestoon"},
+ {0x325e00cd2fe819f9, "If the enemy is within range, then so are you."},
+ {0x88c6600ce58ae4c6, "It's well we cannot hear the screams/That we create in others' dreams."},
+ {0x28c4a3f3b769e078, "You remind me of a TV show, but that's all right: I watch it anyway."},
+ {0xa698a34c9d9f1dca, "C is as portable as Stonehedge!!"},
+ {0xf6c1e2a8c26c5cfc, "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
+ {0xd402559dfe9b70c, "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"},
+ {0xdb6efff26aa94946, "How can you write a big system without C++? -Paul Glick"},
}
var tab = MakeTable(ISO)
diff --git a/src/pkg/html/Makefile b/src/pkg/html/Makefile
new file mode 100644
index 000000000..00e1c0550
--- /dev/null
+++ b/src/pkg/html/Makefile
@@ -0,0 +1,15 @@
+# Copyright 2010 The Go Authors. 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=\
+ doc.go\
+ entity.go\
+ escape.go\
+ parse.go\
+ token.go\
+
+include ../../Make.pkg
diff --git a/src/pkg/html/doc.go b/src/pkg/html/doc.go
new file mode 100644
index 000000000..c5338d078
--- /dev/null
+++ b/src/pkg/html/doc.go
@@ -0,0 +1,106 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+The html package implements an HTML5-compliant tokenizer and parser.
+
+Tokenization is done by creating a Tokenizer for an io.Reader r. It is the
+caller's responsibility to ensure that r provides UTF-8 encoded HTML.
+
+ z := html.NewTokenizer(r)
+
+Given a Tokenizer z, the HTML is tokenized by repeatedly calling z.Next(),
+which parses the next token and returns its type, or an error:
+
+ for {
+ tt := z.Next()
+ if tt == html.ErrorToken {
+ // ...
+ return ...
+ }
+ // Process the current token.
+ }
+
+There are two APIs for retrieving the current token. The high-level API is to
+call Token; the low-level API is to call Text or TagName / TagAttr. Both APIs
+allow optionally calling Raw after Next but before Token, Text, TagName, or
+TagAttr. In EBNF notation, the valid call sequence per token is:
+
+ Next {Raw} [ Token | Text | TagName {TagAttr} ]
+
+Token returns an independent data structure that completely describes a token.
+Entities (such as "&lt;") are unescaped, tag names and attribute keys are
+lower-cased, and attributes are collected into a []Attribute. For example:
+
+ for {
+ if z.Next() == html.ErrorToken {
+ // Returning os.EOF indicates success.
+ return z.Error()
+ }
+ emitToken(z.Token())
+ }
+
+The low-level API performs fewer allocations and copies, but the contents of
+the []byte values returned by Text, TagName and TagAttr may change on the next
+call to Next. For example, to extract an HTML page's anchor text:
+
+ depth := 0
+ for {
+ tt := z.Next()
+ switch tt {
+ case ErrorToken:
+ return z.Error()
+ case TextToken:
+ if depth > 0 {
+ // emitBytes should copy the []byte it receives,
+ // if it doesn't process it immediately.
+ emitBytes(z.Text())
+ }
+ case StartTagToken, EndTagToken:
+ tn, _ := z.TagName()
+ if len(tn) == 1 && tn[0] == 'a' {
+ if tt == StartTag {
+ depth++
+ } else {
+ depth--
+ }
+ }
+ }
+ }
+
+Parsing is done by calling Parse with an io.Reader, which returns the root of
+the parse tree (the document element) as a *Node. It is the caller's
+responsibility to ensure that the Reader provides UTF-8 encoded HTML. For
+example, to process each anchor node in depth-first order:
+
+ doc, err := html.Parse(r)
+ if err != nil {
+ // ...
+ }
+ var f func(*html.Node)
+ f = func(n *html.Node) {
+ if n.Type == html.ElementNode && n.Data == "a" {
+ // Do something with n...
+ }
+ for _, c := range n.Child {
+ f(c)
+ }
+ }
+ f(doc)
+
+The relevant specifications include:
+http://www.whatwg.org/specs/web-apps/current-work/multipage/syntax.html and
+http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html
+*/
+package html
+
+// The tokenization algorithm implemented by this package is not a line-by-line
+// transliteration of the relatively verbose state-machine in the WHATWG
+// specification. A more direct approach is used instead, where the program
+// counter implies the state, such as whether it is tokenizing a tag or a text
+// node. Specification compliance is verified by checking expected and actual
+// outputs over a test suite rather than aiming for algorithmic fidelity.
+
+// TODO(nigeltao): Does a DOM API belong in this package or a separate one?
+// TODO(nigeltao): How does parsing interact with a JavaScript engine?
diff --git a/src/pkg/html/entity.go b/src/pkg/html/entity.go
new file mode 100644
index 000000000..1530290cb
--- /dev/null
+++ b/src/pkg/html/entity.go
@@ -0,0 +1,2250 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package html
+
+// entity is a map from HTML entity names to their values. The semicolon matters:
+// http://www.whatwg.org/specs/web-apps/current-work/multipage/named-character-references.html
+// lists both "amp" and "amp;" as two separate entries.
+//
+// Note that the HTML5 list is larger than the HTML4 list at
+// http://www.w3.org/TR/html4/sgml/entities.html
+var entity = map[string]int{
+ "AElig;": '\U000000C6',
+ "AMP;": '\U00000026',
+ "Aacute;": '\U000000C1',
+ "Abreve;": '\U00000102',
+ "Acirc;": '\U000000C2',
+ "Acy;": '\U00000410',
+ "Afr;": '\U0001D504',
+ "Agrave;": '\U000000C0',
+ "Alpha;": '\U00000391',
+ "Amacr;": '\U00000100',
+ "And;": '\U00002A53',
+ "Aogon;": '\U00000104',
+ "Aopf;": '\U0001D538',
+ "ApplyFunction;": '\U00002061',
+ "Aring;": '\U000000C5',
+ "Ascr;": '\U0001D49C',
+ "Assign;": '\U00002254',
+ "Atilde;": '\U000000C3',
+ "Auml;": '\U000000C4',
+ "Backslash;": '\U00002216',
+ "Barv;": '\U00002AE7',
+ "Barwed;": '\U00002306',
+ "Bcy;": '\U00000411',
+ "Because;": '\U00002235',
+ "Bernoullis;": '\U0000212C',
+ "Beta;": '\U00000392',
+ "Bfr;": '\U0001D505',
+ "Bopf;": '\U0001D539',
+ "Breve;": '\U000002D8',
+ "Bscr;": '\U0000212C',
+ "Bumpeq;": '\U0000224E',
+ "CHcy;": '\U00000427',
+ "COPY;": '\U000000A9',
+ "Cacute;": '\U00000106',
+ "Cap;": '\U000022D2',
+ "CapitalDifferentialD;": '\U00002145',
+ "Cayleys;": '\U0000212D',
+ "Ccaron;": '\U0000010C',
+ "Ccedil;": '\U000000C7',
+ "Ccirc;": '\U00000108',
+ "Cconint;": '\U00002230',
+ "Cdot;": '\U0000010A',
+ "Cedilla;": '\U000000B8',
+ "CenterDot;": '\U000000B7',
+ "Cfr;": '\U0000212D',
+ "Chi;": '\U000003A7',
+ "CircleDot;": '\U00002299',
+ "CircleMinus;": '\U00002296',
+ "CirclePlus;": '\U00002295',
+ "CircleTimes;": '\U00002297',
+ "ClockwiseContourIntegral;": '\U00002232',
+ "CloseCurlyDoubleQuote;": '\U0000201D',
+ "CloseCurlyQuote;": '\U00002019',
+ "Colon;": '\U00002237',
+ "Colone;": '\U00002A74',
+ "Congruent;": '\U00002261',
+ "Conint;": '\U0000222F',
+ "ContourIntegral;": '\U0000222E',
+ "Copf;": '\U00002102',
+ "Coproduct;": '\U00002210',
+ "CounterClockwiseContourIntegral;": '\U00002233',
+ "Cross;": '\U00002A2F',
+ "Cscr;": '\U0001D49E',
+ "Cup;": '\U000022D3',
+ "CupCap;": '\U0000224D',
+ "DD;": '\U00002145',
+ "DDotrahd;": '\U00002911',
+ "DJcy;": '\U00000402',
+ "DScy;": '\U00000405',
+ "DZcy;": '\U0000040F',
+ "Dagger;": '\U00002021',
+ "Darr;": '\U000021A1',
+ "Dashv;": '\U00002AE4',
+ "Dcaron;": '\U0000010E',
+ "Dcy;": '\U00000414',
+ "Del;": '\U00002207',
+ "Delta;": '\U00000394',
+ "Dfr;": '\U0001D507',
+ "DiacriticalAcute;": '\U000000B4',
+ "DiacriticalDot;": '\U000002D9',
+ "DiacriticalDoubleAcute;": '\U000002DD',
+ "DiacriticalGrave;": '\U00000060',
+ "DiacriticalTilde;": '\U000002DC',
+ "Diamond;": '\U000022C4',
+ "DifferentialD;": '\U00002146',
+ "Dopf;": '\U0001D53B',
+ "Dot;": '\U000000A8',
+ "DotDot;": '\U000020DC',
+ "DotEqual;": '\U00002250',
+ "DoubleContourIntegral;": '\U0000222F',
+ "DoubleDot;": '\U000000A8',
+ "DoubleDownArrow;": '\U000021D3',
+ "DoubleLeftArrow;": '\U000021D0',
+ "DoubleLeftRightArrow;": '\U000021D4',
+ "DoubleLeftTee;": '\U00002AE4',
+ "DoubleLongLeftArrow;": '\U000027F8',
+ "DoubleLongLeftRightArrow;": '\U000027FA',
+ "DoubleLongRightArrow;": '\U000027F9',
+ "DoubleRightArrow;": '\U000021D2',
+ "DoubleRightTee;": '\U000022A8',
+ "DoubleUpArrow;": '\U000021D1',
+ "DoubleUpDownArrow;": '\U000021D5',
+ "DoubleVerticalBar;": '\U00002225',
+ "DownArrow;": '\U00002193',
+ "DownArrowBar;": '\U00002913',
+ "DownArrowUpArrow;": '\U000021F5',
+ "DownBreve;": '\U00000311',
+ "DownLeftRightVector;": '\U00002950',
+ "DownLeftTeeVector;": '\U0000295E',
+ "DownLeftVector;": '\U000021BD',
+ "DownLeftVectorBar;": '\U00002956',
+ "DownRightTeeVector;": '\U0000295F',
+ "DownRightVector;": '\U000021C1',
+ "DownRightVectorBar;": '\U00002957',
+ "DownTee;": '\U000022A4',
+ "DownTeeArrow;": '\U000021A7',
+ "Downarrow;": '\U000021D3',
+ "Dscr;": '\U0001D49F',
+ "Dstrok;": '\U00000110',
+ "ENG;": '\U0000014A',
+ "ETH;": '\U000000D0',
+ "Eacute;": '\U000000C9',
+ "Ecaron;": '\U0000011A',
+ "Ecirc;": '\U000000CA',
+ "Ecy;": '\U0000042D',
+ "Edot;": '\U00000116',
+ "Efr;": '\U0001D508',
+ "Egrave;": '\U000000C8',
+ "Element;": '\U00002208',
+ "Emacr;": '\U00000112',
+ "EmptySmallSquare;": '\U000025FB',
+ "EmptyVerySmallSquare;": '\U000025AB',
+ "Eogon;": '\U00000118',
+ "Eopf;": '\U0001D53C',
+ "Epsilon;": '\U00000395',
+ "Equal;": '\U00002A75',
+ "EqualTilde;": '\U00002242',
+ "Equilibrium;": '\U000021CC',
+ "Escr;": '\U00002130',
+ "Esim;": '\U00002A73',
+ "Eta;": '\U00000397',
+ "Euml;": '\U000000CB',
+ "Exists;": '\U00002203',
+ "ExponentialE;": '\U00002147',
+ "Fcy;": '\U00000424',
+ "Ffr;": '\U0001D509',
+ "FilledSmallSquare;": '\U000025FC',
+ "FilledVerySmallSquare;": '\U000025AA',
+ "Fopf;": '\U0001D53D',
+ "ForAll;": '\U00002200',
+ "Fouriertrf;": '\U00002131',
+ "Fscr;": '\U00002131',
+ "GJcy;": '\U00000403',
+ "GT;": '\U0000003E',
+ "Gamma;": '\U00000393',
+ "Gammad;": '\U000003DC',
+ "Gbreve;": '\U0000011E',
+ "Gcedil;": '\U00000122',
+ "Gcirc;": '\U0000011C',
+ "Gcy;": '\U00000413',
+ "Gdot;": '\U00000120',
+ "Gfr;": '\U0001D50A',
+ "Gg;": '\U000022D9',
+ "Gopf;": '\U0001D53E',
+ "GreaterEqual;": '\U00002265',
+ "GreaterEqualLess;": '\U000022DB',
+ "GreaterFullEqual;": '\U00002267',
+ "GreaterGreater;": '\U00002AA2',
+ "GreaterLess;": '\U00002277',
+ "GreaterSlantEqual;": '\U00002A7E',
+ "GreaterTilde;": '\U00002273',
+ "Gscr;": '\U0001D4A2',
+ "Gt;": '\U0000226B',
+ "HARDcy;": '\U0000042A',
+ "Hacek;": '\U000002C7',
+ "Hat;": '\U0000005E',
+ "Hcirc;": '\U00000124',
+ "Hfr;": '\U0000210C',
+ "HilbertSpace;": '\U0000210B',
+ "Hopf;": '\U0000210D',
+ "HorizontalLine;": '\U00002500',
+ "Hscr;": '\U0000210B',
+ "Hstrok;": '\U00000126',
+ "HumpDownHump;": '\U0000224E',
+ "HumpEqual;": '\U0000224F',
+ "IEcy;": '\U00000415',
+ "IJlig;": '\U00000132',
+ "IOcy;": '\U00000401',
+ "Iacute;": '\U000000CD',
+ "Icirc;": '\U000000CE',
+ "Icy;": '\U00000418',
+ "Idot;": '\U00000130',
+ "Ifr;": '\U00002111',
+ "Igrave;": '\U000000CC',
+ "Im;": '\U00002111',
+ "Imacr;": '\U0000012A',
+ "ImaginaryI;": '\U00002148',
+ "Implies;": '\U000021D2',
+ "Int;": '\U0000222C',
+ "Integral;": '\U0000222B',
+ "Intersection;": '\U000022C2',
+ "InvisibleComma;": '\U00002063',
+ "InvisibleTimes;": '\U00002062',
+ "Iogon;": '\U0000012E',
+ "Iopf;": '\U0001D540',
+ "Iota;": '\U00000399',
+ "Iscr;": '\U00002110',
+ "Itilde;": '\U00000128',
+ "Iukcy;": '\U00000406',
+ "Iuml;": '\U000000CF',
+ "Jcirc;": '\U00000134',
+ "Jcy;": '\U00000419',
+ "Jfr;": '\U0001D50D',
+ "Jopf;": '\U0001D541',
+ "Jscr;": '\U0001D4A5',
+ "Jsercy;": '\U00000408',
+ "Jukcy;": '\U00000404',
+ "KHcy;": '\U00000425',
+ "KJcy;": '\U0000040C',
+ "Kappa;": '\U0000039A',
+ "Kcedil;": '\U00000136',
+ "Kcy;": '\U0000041A',
+ "Kfr;": '\U0001D50E',
+ "Kopf;": '\U0001D542',
+ "Kscr;": '\U0001D4A6',
+ "LJcy;": '\U00000409',
+ "LT;": '\U0000003C',
+ "Lacute;": '\U00000139',
+ "Lambda;": '\U0000039B',
+ "Lang;": '\U000027EA',
+ "Laplacetrf;": '\U00002112',
+ "Larr;": '\U0000219E',
+ "Lcaron;": '\U0000013D',
+ "Lcedil;": '\U0000013B',
+ "Lcy;": '\U0000041B',
+ "LeftAngleBracket;": '\U000027E8',
+ "LeftArrow;": '\U00002190',
+ "LeftArrowBar;": '\U000021E4',
+ "LeftArrowRightArrow;": '\U000021C6',
+ "LeftCeiling;": '\U00002308',
+ "LeftDoubleBracket;": '\U000027E6',
+ "LeftDownTeeVector;": '\U00002961',
+ "LeftDownVector;": '\U000021C3',
+ "LeftDownVectorBar;": '\U00002959',
+ "LeftFloor;": '\U0000230A',
+ "LeftRightArrow;": '\U00002194',
+ "LeftRightVector;": '\U0000294E',
+ "LeftTee;": '\U000022A3',
+ "LeftTeeArrow;": '\U000021A4',
+ "LeftTeeVector;": '\U0000295A',
+ "LeftTriangle;": '\U000022B2',
+ "LeftTriangleBar;": '\U000029CF',
+ "LeftTriangleEqual;": '\U000022B4',
+ "LeftUpDownVector;": '\U00002951',
+ "LeftUpTeeVector;": '\U00002960',
+ "LeftUpVector;": '\U000021BF',
+ "LeftUpVectorBar;": '\U00002958',
+ "LeftVector;": '\U000021BC',
+ "LeftVectorBar;": '\U00002952',
+ "Leftarrow;": '\U000021D0',
+ "Leftrightarrow;": '\U000021D4',
+ "LessEqualGreater;": '\U000022DA',
+ "LessFullEqual;": '\U00002266',
+ "LessGreater;": '\U00002276',
+ "LessLess;": '\U00002AA1',
+ "LessSlantEqual;": '\U00002A7D',
+ "LessTilde;": '\U00002272',
+ "Lfr;": '\U0001D50F',
+ "Ll;": '\U000022D8',
+ "Lleftarrow;": '\U000021DA',
+ "Lmidot;": '\U0000013F',
+ "LongLeftArrow;": '\U000027F5',
+ "LongLeftRightArrow;": '\U000027F7',
+ "LongRightArrow;": '\U000027F6',
+ "Longleftarrow;": '\U000027F8',
+ "Longleftrightarrow;": '\U000027FA',
+ "Longrightarrow;": '\U000027F9',
+ "Lopf;": '\U0001D543',
+ "LowerLeftArrow;": '\U00002199',
+ "LowerRightArrow;": '\U00002198',
+ "Lscr;": '\U00002112',
+ "Lsh;": '\U000021B0',
+ "Lstrok;": '\U00000141',
+ "Lt;": '\U0000226A',
+ "Map;": '\U00002905',
+ "Mcy;": '\U0000041C',
+ "MediumSpace;": '\U0000205F',
+ "Mellintrf;": '\U00002133',
+ "Mfr;": '\U0001D510',
+ "MinusPlus;": '\U00002213',
+ "Mopf;": '\U0001D544',
+ "Mscr;": '\U00002133',
+ "Mu;": '\U0000039C',
+ "NJcy;": '\U0000040A',
+ "Nacute;": '\U00000143',
+ "Ncaron;": '\U00000147',
+ "Ncedil;": '\U00000145',
+ "Ncy;": '\U0000041D',
+ "NegativeMediumSpace;": '\U0000200B',
+ "NegativeThickSpace;": '\U0000200B',
+ "NegativeThinSpace;": '\U0000200B',
+ "NegativeVeryThinSpace;": '\U0000200B',
+ "NestedGreaterGreater;": '\U0000226B',
+ "NestedLessLess;": '\U0000226A',
+ "NewLine;": '\U0000000A',
+ "Nfr;": '\U0001D511',
+ "NoBreak;": '\U00002060',
+ "NonBreakingSpace;": '\U000000A0',
+ "Nopf;": '\U00002115',
+ "Not;": '\U00002AEC',
+ "NotCongruent;": '\U00002262',
+ "NotCupCap;": '\U0000226D',
+ "NotDoubleVerticalBar;": '\U00002226',
+ "NotElement;": '\U00002209',
+ "NotEqual;": '\U00002260',
+ "NotExists;": '\U00002204',
+ "NotGreater;": '\U0000226F',
+ "NotGreaterEqual;": '\U00002271',
+ "NotGreaterLess;": '\U00002279',
+ "NotGreaterTilde;": '\U00002275',
+ "NotLeftTriangle;": '\U000022EA',
+ "NotLeftTriangleEqual;": '\U000022EC',
+ "NotLess;": '\U0000226E',
+ "NotLessEqual;": '\U00002270',
+ "NotLessGreater;": '\U00002278',
+ "NotLessTilde;": '\U00002274',
+ "NotPrecedes;": '\U00002280',
+ "NotPrecedesSlantEqual;": '\U000022E0',
+ "NotReverseElement;": '\U0000220C',
+ "NotRightTriangle;": '\U000022EB',
+ "NotRightTriangleEqual;": '\U000022ED',
+ "NotSquareSubsetEqual;": '\U000022E2',
+ "NotSquareSupersetEqual;": '\U000022E3',
+ "NotSubsetEqual;": '\U00002288',
+ "NotSucceeds;": '\U00002281',
+ "NotSucceedsSlantEqual;": '\U000022E1',
+ "NotSupersetEqual;": '\U00002289',
+ "NotTilde;": '\U00002241',
+ "NotTildeEqual;": '\U00002244',
+ "NotTildeFullEqual;": '\U00002247',
+ "NotTildeTilde;": '\U00002249',
+ "NotVerticalBar;": '\U00002224',
+ "Nscr;": '\U0001D4A9',
+ "Ntilde;": '\U000000D1',
+ "Nu;": '\U0000039D',
+ "OElig;": '\U00000152',
+ "Oacute;": '\U000000D3',
+ "Ocirc;": '\U000000D4',
+ "Ocy;": '\U0000041E',
+ "Odblac;": '\U00000150',
+ "Ofr;": '\U0001D512',
+ "Ograve;": '\U000000D2',
+ "Omacr;": '\U0000014C',
+ "Omega;": '\U000003A9',
+ "Omicron;": '\U0000039F',
+ "Oopf;": '\U0001D546',
+ "OpenCurlyDoubleQuote;": '\U0000201C',
+ "OpenCurlyQuote;": '\U00002018',
+ "Or;": '\U00002A54',
+ "Oscr;": '\U0001D4AA',
+ "Oslash;": '\U000000D8',
+ "Otilde;": '\U000000D5',
+ "Otimes;": '\U00002A37',
+ "Ouml;": '\U000000D6',
+ "OverBar;": '\U0000203E',
+ "OverBrace;": '\U000023DE',
+ "OverBracket;": '\U000023B4',
+ "OverParenthesis;": '\U000023DC',
+ "PartialD;": '\U00002202',
+ "Pcy;": '\U0000041F',
+ "Pfr;": '\U0001D513',
+ "Phi;": '\U000003A6',
+ "Pi;": '\U000003A0',
+ "PlusMinus;": '\U000000B1',
+ "Poincareplane;": '\U0000210C',
+ "Popf;": '\U00002119',
+ "Pr;": '\U00002ABB',
+ "Precedes;": '\U0000227A',
+ "PrecedesEqual;": '\U00002AAF',
+ "PrecedesSlantEqual;": '\U0000227C',
+ "PrecedesTilde;": '\U0000227E',
+ "Prime;": '\U00002033',
+ "Product;": '\U0000220F',
+ "Proportion;": '\U00002237',
+ "Proportional;": '\U0000221D',
+ "Pscr;": '\U0001D4AB',
+ "Psi;": '\U000003A8',
+ "QUOT;": '\U00000022',
+ "Qfr;": '\U0001D514',
+ "Qopf;": '\U0000211A',
+ "Qscr;": '\U0001D4AC',
+ "RBarr;": '\U00002910',
+ "REG;": '\U000000AE',
+ "Racute;": '\U00000154',
+ "Rang;": '\U000027EB',
+ "Rarr;": '\U000021A0',
+ "Rarrtl;": '\U00002916',
+ "Rcaron;": '\U00000158',
+ "Rcedil;": '\U00000156',
+ "Rcy;": '\U00000420',
+ "Re;": '\U0000211C',
+ "ReverseElement;": '\U0000220B',
+ "ReverseEquilibrium;": '\U000021CB',
+ "ReverseUpEquilibrium;": '\U0000296F',
+ "Rfr;": '\U0000211C',
+ "Rho;": '\U000003A1',
+ "RightAngleBracket;": '\U000027E9',
+ "RightArrow;": '\U00002192',
+ "RightArrowBar;": '\U000021E5',
+ "RightArrowLeftArrow;": '\U000021C4',
+ "RightCeiling;": '\U00002309',
+ "RightDoubleBracket;": '\U000027E7',
+ "RightDownTeeVector;": '\U0000295D',
+ "RightDownVector;": '\U000021C2',
+ "RightDownVectorBar;": '\U00002955',
+ "RightFloor;": '\U0000230B',
+ "RightTee;": '\U000022A2',
+ "RightTeeArrow;": '\U000021A6',
+ "RightTeeVector;": '\U0000295B',
+ "RightTriangle;": '\U000022B3',
+ "RightTriangleBar;": '\U000029D0',
+ "RightTriangleEqual;": '\U000022B5',
+ "RightUpDownVector;": '\U0000294F',
+ "RightUpTeeVector;": '\U0000295C',
+ "RightUpVector;": '\U000021BE',
+ "RightUpVectorBar;": '\U00002954',
+ "RightVector;": '\U000021C0',
+ "RightVectorBar;": '\U00002953',
+ "Rightarrow;": '\U000021D2',
+ "Ropf;": '\U0000211D',
+ "RoundImplies;": '\U00002970',
+ "Rrightarrow;": '\U000021DB',
+ "Rscr;": '\U0000211B',
+ "Rsh;": '\U000021B1',
+ "RuleDelayed;": '\U000029F4',
+ "SHCHcy;": '\U00000429',
+ "SHcy;": '\U00000428',
+ "SOFTcy;": '\U0000042C',
+ "Sacute;": '\U0000015A',
+ "Sc;": '\U00002ABC',
+ "Scaron;": '\U00000160',
+ "Scedil;": '\U0000015E',
+ "Scirc;": '\U0000015C',
+ "Scy;": '\U00000421',
+ "Sfr;": '\U0001D516',
+ "ShortDownArrow;": '\U00002193',
+ "ShortLeftArrow;": '\U00002190',
+ "ShortRightArrow;": '\U00002192',
+ "ShortUpArrow;": '\U00002191',
+ "Sigma;": '\U000003A3',
+ "SmallCircle;": '\U00002218',
+ "Sopf;": '\U0001D54A',
+ "Sqrt;": '\U0000221A',
+ "Square;": '\U000025A1',
+ "SquareIntersection;": '\U00002293',
+ "SquareSubset;": '\U0000228F',
+ "SquareSubsetEqual;": '\U00002291',
+ "SquareSuperset;": '\U00002290',
+ "SquareSupersetEqual;": '\U00002292',
+ "SquareUnion;": '\U00002294',
+ "Sscr;": '\U0001D4AE',
+ "Star;": '\U000022C6',
+ "Sub;": '\U000022D0',
+ "Subset;": '\U000022D0',
+ "SubsetEqual;": '\U00002286',
+ "Succeeds;": '\U0000227B',
+ "SucceedsEqual;": '\U00002AB0',
+ "SucceedsSlantEqual;": '\U0000227D',
+ "SucceedsTilde;": '\U0000227F',
+ "SuchThat;": '\U0000220B',
+ "Sum;": '\U00002211',
+ "Sup;": '\U000022D1',
+ "Superset;": '\U00002283',
+ "SupersetEqual;": '\U00002287',
+ "Supset;": '\U000022D1',
+ "THORN;": '\U000000DE',
+ "TRADE;": '\U00002122',
+ "TSHcy;": '\U0000040B',
+ "TScy;": '\U00000426',
+ "Tab;": '\U00000009',
+ "Tau;": '\U000003A4',
+ "Tcaron;": '\U00000164',
+ "Tcedil;": '\U00000162',
+ "Tcy;": '\U00000422',
+ "Tfr;": '\U0001D517',
+ "Therefore;": '\U00002234',
+ "Theta;": '\U00000398',
+ "ThinSpace;": '\U00002009',
+ "Tilde;": '\U0000223C',
+ "TildeEqual;": '\U00002243',
+ "TildeFullEqual;": '\U00002245',
+ "TildeTilde;": '\U00002248',
+ "Topf;": '\U0001D54B',
+ "TripleDot;": '\U000020DB',
+ "Tscr;": '\U0001D4AF',
+ "Tstrok;": '\U00000166',
+ "Uacute;": '\U000000DA',
+ "Uarr;": '\U0000219F',
+ "Uarrocir;": '\U00002949',
+ "Ubrcy;": '\U0000040E',
+ "Ubreve;": '\U0000016C',
+ "Ucirc;": '\U000000DB',
+ "Ucy;": '\U00000423',
+ "Udblac;": '\U00000170',
+ "Ufr;": '\U0001D518',
+ "Ugrave;": '\U000000D9',
+ "Umacr;": '\U0000016A',
+ "UnderBar;": '\U0000005F',
+ "UnderBrace;": '\U000023DF',
+ "UnderBracket;": '\U000023B5',
+ "UnderParenthesis;": '\U000023DD',
+ "Union;": '\U000022C3',
+ "UnionPlus;": '\U0000228E',
+ "Uogon;": '\U00000172',
+ "Uopf;": '\U0001D54C',
+ "UpArrow;": '\U00002191',
+ "UpArrowBar;": '\U00002912',
+ "UpArrowDownArrow;": '\U000021C5',
+ "UpDownArrow;": '\U00002195',
+ "UpEquilibrium;": '\U0000296E',
+ "UpTee;": '\U000022A5',
+ "UpTeeArrow;": '\U000021A5',
+ "Uparrow;": '\U000021D1',
+ "Updownarrow;": '\U000021D5',
+ "UpperLeftArrow;": '\U00002196',
+ "UpperRightArrow;": '\U00002197',
+ "Upsi;": '\U000003D2',
+ "Upsilon;": '\U000003A5',
+ "Uring;": '\U0000016E',
+ "Uscr;": '\U0001D4B0',
+ "Utilde;": '\U00000168',
+ "Uuml;": '\U000000DC',
+ "VDash;": '\U000022AB',
+ "Vbar;": '\U00002AEB',
+ "Vcy;": '\U00000412',
+ "Vdash;": '\U000022A9',
+ "Vdashl;": '\U00002AE6',
+ "Vee;": '\U000022C1',
+ "Verbar;": '\U00002016',
+ "Vert;": '\U00002016',
+ "VerticalBar;": '\U00002223',
+ "VerticalLine;": '\U0000007C',
+ "VerticalSeparator;": '\U00002758',
+ "VerticalTilde;": '\U00002240',
+ "VeryThinSpace;": '\U0000200A',
+ "Vfr;": '\U0001D519',
+ "Vopf;": '\U0001D54D',
+ "Vscr;": '\U0001D4B1',
+ "Vvdash;": '\U000022AA',
+ "Wcirc;": '\U00000174',
+ "Wedge;": '\U000022C0',
+ "Wfr;": '\U0001D51A',
+ "Wopf;": '\U0001D54E',
+ "Wscr;": '\U0001D4B2',
+ "Xfr;": '\U0001D51B',
+ "Xi;": '\U0000039E',
+ "Xopf;": '\U0001D54F',
+ "Xscr;": '\U0001D4B3',
+ "YAcy;": '\U0000042F',
+ "YIcy;": '\U00000407',
+ "YUcy;": '\U0000042E',
+ "Yacute;": '\U000000DD',
+ "Ycirc;": '\U00000176',
+ "Ycy;": '\U0000042B',
+ "Yfr;": '\U0001D51C',
+ "Yopf;": '\U0001D550',
+ "Yscr;": '\U0001D4B4',
+ "Yuml;": '\U00000178',
+ "ZHcy;": '\U00000416',
+ "Zacute;": '\U00000179',
+ "Zcaron;": '\U0000017D',
+ "Zcy;": '\U00000417',
+ "Zdot;": '\U0000017B',
+ "ZeroWidthSpace;": '\U0000200B',
+ "Zeta;": '\U00000396',
+ "Zfr;": '\U00002128',
+ "Zopf;": '\U00002124',
+ "Zscr;": '\U0001D4B5',
+ "aacute;": '\U000000E1',
+ "abreve;": '\U00000103',
+ "ac;": '\U0000223E',
+ "acd;": '\U0000223F',
+ "acirc;": '\U000000E2',
+ "acute;": '\U000000B4',
+ "acy;": '\U00000430',
+ "aelig;": '\U000000E6',
+ "af;": '\U00002061',
+ "afr;": '\U0001D51E',
+ "agrave;": '\U000000E0',
+ "alefsym;": '\U00002135',
+ "aleph;": '\U00002135',
+ "alpha;": '\U000003B1',
+ "amacr;": '\U00000101',
+ "amalg;": '\U00002A3F',
+ "amp;": '\U00000026',
+ "and;": '\U00002227',
+ "andand;": '\U00002A55',
+ "andd;": '\U00002A5C',
+ "andslope;": '\U00002A58',
+ "andv;": '\U00002A5A',
+ "ang;": '\U00002220',
+ "ange;": '\U000029A4',
+ "angle;": '\U00002220',
+ "angmsd;": '\U00002221',
+ "angmsdaa;": '\U000029A8',
+ "angmsdab;": '\U000029A9',
+ "angmsdac;": '\U000029AA',
+ "angmsdad;": '\U000029AB',
+ "angmsdae;": '\U000029AC',
+ "angmsdaf;": '\U000029AD',
+ "angmsdag;": '\U000029AE',
+ "angmsdah;": '\U000029AF',
+ "angrt;": '\U0000221F',
+ "angrtvb;": '\U000022BE',
+ "angrtvbd;": '\U0000299D',
+ "angsph;": '\U00002222',
+ "angst;": '\U000000C5',
+ "angzarr;": '\U0000237C',
+ "aogon;": '\U00000105',
+ "aopf;": '\U0001D552',
+ "ap;": '\U00002248',
+ "apE;": '\U00002A70',
+ "apacir;": '\U00002A6F',
+ "ape;": '\U0000224A',
+ "apid;": '\U0000224B',
+ "apos;": '\U00000027',
+ "approx;": '\U00002248',
+ "approxeq;": '\U0000224A',
+ "aring;": '\U000000E5',
+ "ascr;": '\U0001D4B6',
+ "ast;": '\U0000002A',
+ "asymp;": '\U00002248',
+ "asympeq;": '\U0000224D',
+ "atilde;": '\U000000E3',
+ "auml;": '\U000000E4',
+ "awconint;": '\U00002233',
+ "awint;": '\U00002A11',
+ "bNot;": '\U00002AED',
+ "backcong;": '\U0000224C',
+ "backepsilon;": '\U000003F6',
+ "backprime;": '\U00002035',
+ "backsim;": '\U0000223D',
+ "backsimeq;": '\U000022CD',
+ "barvee;": '\U000022BD',
+ "barwed;": '\U00002305',
+ "barwedge;": '\U00002305',
+ "bbrk;": '\U000023B5',
+ "bbrktbrk;": '\U000023B6',
+ "bcong;": '\U0000224C',
+ "bcy;": '\U00000431',
+ "bdquo;": '\U0000201E',
+ "becaus;": '\U00002235',
+ "because;": '\U00002235',
+ "bemptyv;": '\U000029B0',
+ "bepsi;": '\U000003F6',
+ "bernou;": '\U0000212C',
+ "beta;": '\U000003B2',
+ "beth;": '\U00002136',
+ "between;": '\U0000226C',
+ "bfr;": '\U0001D51F',
+ "bigcap;": '\U000022C2',
+ "bigcirc;": '\U000025EF',
+ "bigcup;": '\U000022C3',
+ "bigodot;": '\U00002A00',
+ "bigoplus;": '\U00002A01',
+ "bigotimes;": '\U00002A02',
+ "bigsqcup;": '\U00002A06',
+ "bigstar;": '\U00002605',
+ "bigtriangledown;": '\U000025BD',
+ "bigtriangleup;": '\U000025B3',
+ "biguplus;": '\U00002A04',
+ "bigvee;": '\U000022C1',
+ "bigwedge;": '\U000022C0',
+ "bkarow;": '\U0000290D',
+ "blacklozenge;": '\U000029EB',
+ "blacksquare;": '\U000025AA',
+ "blacktriangle;": '\U000025B4',
+ "blacktriangledown;": '\U000025BE',
+ "blacktriangleleft;": '\U000025C2',
+ "blacktriangleright;": '\U000025B8',
+ "blank;": '\U00002423',
+ "blk12;": '\U00002592',
+ "blk14;": '\U00002591',
+ "blk34;": '\U00002593',
+ "block;": '\U00002588',
+ "bnot;": '\U00002310',
+ "bopf;": '\U0001D553',
+ "bot;": '\U000022A5',
+ "bottom;": '\U000022A5',
+ "bowtie;": '\U000022C8',
+ "boxDL;": '\U00002557',
+ "boxDR;": '\U00002554',
+ "boxDl;": '\U00002556',
+ "boxDr;": '\U00002553',
+ "boxH;": '\U00002550',
+ "boxHD;": '\U00002566',
+ "boxHU;": '\U00002569',
+ "boxHd;": '\U00002564',
+ "boxHu;": '\U00002567',
+ "boxUL;": '\U0000255D',
+ "boxUR;": '\U0000255A',
+ "boxUl;": '\U0000255C',
+ "boxUr;": '\U00002559',
+ "boxV;": '\U00002551',
+ "boxVH;": '\U0000256C',
+ "boxVL;": '\U00002563',
+ "boxVR;": '\U00002560',
+ "boxVh;": '\U0000256B',
+ "boxVl;": '\U00002562',
+ "boxVr;": '\U0000255F',
+ "boxbox;": '\U000029C9',
+ "boxdL;": '\U00002555',
+ "boxdR;": '\U00002552',
+ "boxdl;": '\U00002510',
+ "boxdr;": '\U0000250C',
+ "boxh;": '\U00002500',
+ "boxhD;": '\U00002565',
+ "boxhU;": '\U00002568',
+ "boxhd;": '\U0000252C',
+ "boxhu;": '\U00002534',
+ "boxminus;": '\U0000229F',
+ "boxplus;": '\U0000229E',
+ "boxtimes;": '\U000022A0',
+ "boxuL;": '\U0000255B',
+ "boxuR;": '\U00002558',
+ "boxul;": '\U00002518',
+ "boxur;": '\U00002514',
+ "boxv;": '\U00002502',
+ "boxvH;": '\U0000256A',
+ "boxvL;": '\U00002561',
+ "boxvR;": '\U0000255E',
+ "boxvh;": '\U0000253C',
+ "boxvl;": '\U00002524',
+ "boxvr;": '\U0000251C',
+ "bprime;": '\U00002035',
+ "breve;": '\U000002D8',
+ "brvbar;": '\U000000A6',
+ "bscr;": '\U0001D4B7',
+ "bsemi;": '\U0000204F',
+ "bsim;": '\U0000223D',
+ "bsime;": '\U000022CD',
+ "bsol;": '\U0000005C',
+ "bsolb;": '\U000029C5',
+ "bsolhsub;": '\U000027C8',
+ "bull;": '\U00002022',
+ "bullet;": '\U00002022',
+ "bump;": '\U0000224E',
+ "bumpE;": '\U00002AAE',
+ "bumpe;": '\U0000224F',
+ "bumpeq;": '\U0000224F',
+ "cacute;": '\U00000107',
+ "cap;": '\U00002229',
+ "capand;": '\U00002A44',
+ "capbrcup;": '\U00002A49',
+ "capcap;": '\U00002A4B',
+ "capcup;": '\U00002A47',
+ "capdot;": '\U00002A40',
+ "caret;": '\U00002041',
+ "caron;": '\U000002C7',
+ "ccaps;": '\U00002A4D',
+ "ccaron;": '\U0000010D',
+ "ccedil;": '\U000000E7',
+ "ccirc;": '\U00000109',
+ "ccups;": '\U00002A4C',
+ "ccupssm;": '\U00002A50',
+ "cdot;": '\U0000010B',
+ "cedil;": '\U000000B8',
+ "cemptyv;": '\U000029B2',
+ "cent;": '\U000000A2',
+ "centerdot;": '\U000000B7',
+ "cfr;": '\U0001D520',
+ "chcy;": '\U00000447',
+ "check;": '\U00002713',
+ "checkmark;": '\U00002713',
+ "chi;": '\U000003C7',
+ "cir;": '\U000025CB',
+ "cirE;": '\U000029C3',
+ "circ;": '\U000002C6',
+ "circeq;": '\U00002257',
+ "circlearrowleft;": '\U000021BA',
+ "circlearrowright;": '\U000021BB',
+ "circledR;": '\U000000AE',
+ "circledS;": '\U000024C8',
+ "circledast;": '\U0000229B',
+ "circledcirc;": '\U0000229A',
+ "circleddash;": '\U0000229D',
+ "cire;": '\U00002257',
+ "cirfnint;": '\U00002A10',
+ "cirmid;": '\U00002AEF',
+ "cirscir;": '\U000029C2',
+ "clubs;": '\U00002663',
+ "clubsuit;": '\U00002663',
+ "colon;": '\U0000003A',
+ "colone;": '\U00002254',
+ "coloneq;": '\U00002254',
+ "comma;": '\U0000002C',
+ "commat;": '\U00000040',
+ "comp;": '\U00002201',
+ "compfn;": '\U00002218',
+ "complement;": '\U00002201',
+ "complexes;": '\U00002102',
+ "cong;": '\U00002245',
+ "congdot;": '\U00002A6D',
+ "conint;": '\U0000222E',
+ "copf;": '\U0001D554',
+ "coprod;": '\U00002210',
+ "copy;": '\U000000A9',
+ "copysr;": '\U00002117',
+ "crarr;": '\U000021B5',
+ "cross;": '\U00002717',
+ "cscr;": '\U0001D4B8',
+ "csub;": '\U00002ACF',
+ "csube;": '\U00002AD1',
+ "csup;": '\U00002AD0',
+ "csupe;": '\U00002AD2',
+ "ctdot;": '\U000022EF',
+ "cudarrl;": '\U00002938',
+ "cudarrr;": '\U00002935',
+ "cuepr;": '\U000022DE',
+ "cuesc;": '\U000022DF',
+ "cularr;": '\U000021B6',
+ "cularrp;": '\U0000293D',
+ "cup;": '\U0000222A',
+ "cupbrcap;": '\U00002A48',
+ "cupcap;": '\U00002A46',
+ "cupcup;": '\U00002A4A',
+ "cupdot;": '\U0000228D',
+ "cupor;": '\U00002A45',
+ "curarr;": '\U000021B7',
+ "curarrm;": '\U0000293C',
+ "curlyeqprec;": '\U000022DE',
+ "curlyeqsucc;": '\U000022DF',
+ "curlyvee;": '\U000022CE',
+ "curlywedge;": '\U000022CF',
+ "curren;": '\U000000A4',
+ "curvearrowleft;": '\U000021B6',
+ "curvearrowright;": '\U000021B7',
+ "cuvee;": '\U000022CE',
+ "cuwed;": '\U000022CF',
+ "cwconint;": '\U00002232',
+ "cwint;": '\U00002231',
+ "cylcty;": '\U0000232D',
+ "dArr;": '\U000021D3',
+ "dHar;": '\U00002965',
+ "dagger;": '\U00002020',
+ "daleth;": '\U00002138',
+ "darr;": '\U00002193',
+ "dash;": '\U00002010',
+ "dashv;": '\U000022A3',
+ "dbkarow;": '\U0000290F',
+ "dblac;": '\U000002DD',
+ "dcaron;": '\U0000010F',
+ "dcy;": '\U00000434',
+ "dd;": '\U00002146',
+ "ddagger;": '\U00002021',
+ "ddarr;": '\U000021CA',
+ "ddotseq;": '\U00002A77',
+ "deg;": '\U000000B0',
+ "delta;": '\U000003B4',
+ "demptyv;": '\U000029B1',
+ "dfisht;": '\U0000297F',
+ "dfr;": '\U0001D521',
+ "dharl;": '\U000021C3',
+ "dharr;": '\U000021C2',
+ "diam;": '\U000022C4',
+ "diamond;": '\U000022C4',
+ "diamondsuit;": '\U00002666',
+ "diams;": '\U00002666',
+ "die;": '\U000000A8',
+ "digamma;": '\U000003DD',
+ "disin;": '\U000022F2',
+ "div;": '\U000000F7',
+ "divide;": '\U000000F7',
+ "divideontimes;": '\U000022C7',
+ "divonx;": '\U000022C7',
+ "djcy;": '\U00000452',
+ "dlcorn;": '\U0000231E',
+ "dlcrop;": '\U0000230D',
+ "dollar;": '\U00000024',
+ "dopf;": '\U0001D555',
+ "dot;": '\U000002D9',
+ "doteq;": '\U00002250',
+ "doteqdot;": '\U00002251',
+ "dotminus;": '\U00002238',
+ "dotplus;": '\U00002214',
+ "dotsquare;": '\U000022A1',
+ "doublebarwedge;": '\U00002306',
+ "downarrow;": '\U00002193',
+ "downdownarrows;": '\U000021CA',
+ "downharpoonleft;": '\U000021C3',
+ "downharpoonright;": '\U000021C2',
+ "drbkarow;": '\U00002910',
+ "drcorn;": '\U0000231F',
+ "drcrop;": '\U0000230C',
+ "dscr;": '\U0001D4B9',
+ "dscy;": '\U00000455',
+ "dsol;": '\U000029F6',
+ "dstrok;": '\U00000111',
+ "dtdot;": '\U000022F1',
+ "dtri;": '\U000025BF',
+ "dtrif;": '\U000025BE',
+ "duarr;": '\U000021F5',
+ "duhar;": '\U0000296F',
+ "dwangle;": '\U000029A6',
+ "dzcy;": '\U0000045F',
+ "dzigrarr;": '\U000027FF',
+ "eDDot;": '\U00002A77',
+ "eDot;": '\U00002251',
+ "eacute;": '\U000000E9',
+ "easter;": '\U00002A6E',
+ "ecaron;": '\U0000011B',
+ "ecir;": '\U00002256',
+ "ecirc;": '\U000000EA',
+ "ecolon;": '\U00002255',
+ "ecy;": '\U0000044D',
+ "edot;": '\U00000117',
+ "ee;": '\U00002147',
+ "efDot;": '\U00002252',
+ "efr;": '\U0001D522',
+ "eg;": '\U00002A9A',
+ "egrave;": '\U000000E8',
+ "egs;": '\U00002A96',
+ "egsdot;": '\U00002A98',
+ "el;": '\U00002A99',
+ "elinters;": '\U000023E7',
+ "ell;": '\U00002113',
+ "els;": '\U00002A95',
+ "elsdot;": '\U00002A97',
+ "emacr;": '\U00000113',
+ "empty;": '\U00002205',
+ "emptyset;": '\U00002205',
+ "emptyv;": '\U00002205',
+ "emsp;": '\U00002003',
+ "emsp13;": '\U00002004',
+ "emsp14;": '\U00002005',
+ "eng;": '\U0000014B',
+ "ensp;": '\U00002002',
+ "eogon;": '\U00000119',
+ "eopf;": '\U0001D556',
+ "epar;": '\U000022D5',
+ "eparsl;": '\U000029E3',
+ "eplus;": '\U00002A71',
+ "epsi;": '\U000003B5',
+ "epsilon;": '\U000003B5',
+ "epsiv;": '\U000003F5',
+ "eqcirc;": '\U00002256',
+ "eqcolon;": '\U00002255',
+ "eqsim;": '\U00002242',
+ "eqslantgtr;": '\U00002A96',
+ "eqslantless;": '\U00002A95',
+ "equals;": '\U0000003D',
+ "equest;": '\U0000225F',
+ "equiv;": '\U00002261',
+ "equivDD;": '\U00002A78',
+ "eqvparsl;": '\U000029E5',
+ "erDot;": '\U00002253',
+ "erarr;": '\U00002971',
+ "escr;": '\U0000212F',
+ "esdot;": '\U00002250',
+ "esim;": '\U00002242',
+ "eta;": '\U000003B7',
+ "eth;": '\U000000F0',
+ "euml;": '\U000000EB',
+ "euro;": '\U000020AC',
+ "excl;": '\U00000021',
+ "exist;": '\U00002203',
+ "expectation;": '\U00002130',
+ "exponentiale;": '\U00002147',
+ "fallingdotseq;": '\U00002252',
+ "fcy;": '\U00000444',
+ "female;": '\U00002640',
+ "ffilig;": '\U0000FB03',
+ "fflig;": '\U0000FB00',
+ "ffllig;": '\U0000FB04',
+ "ffr;": '\U0001D523',
+ "filig;": '\U0000FB01',
+ "flat;": '\U0000266D',
+ "fllig;": '\U0000FB02',
+ "fltns;": '\U000025B1',
+ "fnof;": '\U00000192',
+ "fopf;": '\U0001D557',
+ "forall;": '\U00002200',
+ "fork;": '\U000022D4',
+ "forkv;": '\U00002AD9',
+ "fpartint;": '\U00002A0D',
+ "frac12;": '\U000000BD',
+ "frac13;": '\U00002153',
+ "frac14;": '\U000000BC',
+ "frac15;": '\U00002155',
+ "frac16;": '\U00002159',
+ "frac18;": '\U0000215B',
+ "frac23;": '\U00002154',
+ "frac25;": '\U00002156',
+ "frac34;": '\U000000BE',
+ "frac35;": '\U00002157',
+ "frac38;": '\U0000215C',
+ "frac45;": '\U00002158',
+ "frac56;": '\U0000215A',
+ "frac58;": '\U0000215D',
+ "frac78;": '\U0000215E',
+ "frasl;": '\U00002044',
+ "frown;": '\U00002322',
+ "fscr;": '\U0001D4BB',
+ "gE;": '\U00002267',
+ "gEl;": '\U00002A8C',
+ "gacute;": '\U000001F5',
+ "gamma;": '\U000003B3',
+ "gammad;": '\U000003DD',
+ "gap;": '\U00002A86',
+ "gbreve;": '\U0000011F',
+ "gcirc;": '\U0000011D',
+ "gcy;": '\U00000433',
+ "gdot;": '\U00000121',
+ "ge;": '\U00002265',
+ "gel;": '\U000022DB',
+ "geq;": '\U00002265',
+ "geqq;": '\U00002267',
+ "geqslant;": '\U00002A7E',
+ "ges;": '\U00002A7E',
+ "gescc;": '\U00002AA9',
+ "gesdot;": '\U00002A80',
+ "gesdoto;": '\U00002A82',
+ "gesdotol;": '\U00002A84',
+ "gesles;": '\U00002A94',
+ "gfr;": '\U0001D524',
+ "gg;": '\U0000226B',
+ "ggg;": '\U000022D9',
+ "gimel;": '\U00002137',
+ "gjcy;": '\U00000453',
+ "gl;": '\U00002277',
+ "glE;": '\U00002A92',
+ "gla;": '\U00002AA5',
+ "glj;": '\U00002AA4',
+ "gnE;": '\U00002269',
+ "gnap;": '\U00002A8A',
+ "gnapprox;": '\U00002A8A',
+ "gne;": '\U00002A88',
+ "gneq;": '\U00002A88',
+ "gneqq;": '\U00002269',
+ "gnsim;": '\U000022E7',
+ "gopf;": '\U0001D558',
+ "grave;": '\U00000060',
+ "gscr;": '\U0000210A',
+ "gsim;": '\U00002273',
+ "gsime;": '\U00002A8E',
+ "gsiml;": '\U00002A90',
+ "gt;": '\U0000003E',
+ "gtcc;": '\U00002AA7',
+ "gtcir;": '\U00002A7A',
+ "gtdot;": '\U000022D7',
+ "gtlPar;": '\U00002995',
+ "gtquest;": '\U00002A7C',
+ "gtrapprox;": '\U00002A86',
+ "gtrarr;": '\U00002978',
+ "gtrdot;": '\U000022D7',
+ "gtreqless;": '\U000022DB',
+ "gtreqqless;": '\U00002A8C',
+ "gtrless;": '\U00002277',
+ "gtrsim;": '\U00002273',
+ "hArr;": '\U000021D4',
+ "hairsp;": '\U0000200A',
+ "half;": '\U000000BD',
+ "hamilt;": '\U0000210B',
+ "hardcy;": '\U0000044A',
+ "harr;": '\U00002194',
+ "harrcir;": '\U00002948',
+ "harrw;": '\U000021AD',
+ "hbar;": '\U0000210F',
+ "hcirc;": '\U00000125',
+ "hearts;": '\U00002665',
+ "heartsuit;": '\U00002665',
+ "hellip;": '\U00002026',
+ "hercon;": '\U000022B9',
+ "hfr;": '\U0001D525',
+ "hksearow;": '\U00002925',
+ "hkswarow;": '\U00002926',
+ "hoarr;": '\U000021FF',
+ "homtht;": '\U0000223B',
+ "hookleftarrow;": '\U000021A9',
+ "hookrightarrow;": '\U000021AA',
+ "hopf;": '\U0001D559',
+ "horbar;": '\U00002015',
+ "hscr;": '\U0001D4BD',
+ "hslash;": '\U0000210F',
+ "hstrok;": '\U00000127',
+ "hybull;": '\U00002043',
+ "hyphen;": '\U00002010',
+ "iacute;": '\U000000ED',
+ "ic;": '\U00002063',
+ "icirc;": '\U000000EE',
+ "icy;": '\U00000438',
+ "iecy;": '\U00000435',
+ "iexcl;": '\U000000A1',
+ "iff;": '\U000021D4',
+ "ifr;": '\U0001D526',
+ "igrave;": '\U000000EC',
+ "ii;": '\U00002148',
+ "iiiint;": '\U00002A0C',
+ "iiint;": '\U0000222D',
+ "iinfin;": '\U000029DC',
+ "iiota;": '\U00002129',
+ "ijlig;": '\U00000133',
+ "imacr;": '\U0000012B',
+ "image;": '\U00002111',
+ "imagline;": '\U00002110',
+ "imagpart;": '\U00002111',
+ "imath;": '\U00000131',
+ "imof;": '\U000022B7',
+ "imped;": '\U000001B5',
+ "in;": '\U00002208',
+ "incare;": '\U00002105',
+ "infin;": '\U0000221E',
+ "infintie;": '\U000029DD',
+ "inodot;": '\U00000131',
+ "int;": '\U0000222B',
+ "intcal;": '\U000022BA',
+ "integers;": '\U00002124',
+ "intercal;": '\U000022BA',
+ "intlarhk;": '\U00002A17',
+ "intprod;": '\U00002A3C',
+ "iocy;": '\U00000451',
+ "iogon;": '\U0000012F',
+ "iopf;": '\U0001D55A',
+ "iota;": '\U000003B9',
+ "iprod;": '\U00002A3C',
+ "iquest;": '\U000000BF',
+ "iscr;": '\U0001D4BE',
+ "isin;": '\U00002208',
+ "isinE;": '\U000022F9',
+ "isindot;": '\U000022F5',
+ "isins;": '\U000022F4',
+ "isinsv;": '\U000022F3',
+ "isinv;": '\U00002208',
+ "it;": '\U00002062',
+ "itilde;": '\U00000129',
+ "iukcy;": '\U00000456',
+ "iuml;": '\U000000EF',
+ "jcirc;": '\U00000135',
+ "jcy;": '\U00000439',
+ "jfr;": '\U0001D527',
+ "jmath;": '\U00000237',
+ "jopf;": '\U0001D55B',
+ "jscr;": '\U0001D4BF',
+ "jsercy;": '\U00000458',
+ "jukcy;": '\U00000454',
+ "kappa;": '\U000003BA',
+ "kappav;": '\U000003F0',
+ "kcedil;": '\U00000137',
+ "kcy;": '\U0000043A',
+ "kfr;": '\U0001D528',
+ "kgreen;": '\U00000138',
+ "khcy;": '\U00000445',
+ "kjcy;": '\U0000045C',
+ "kopf;": '\U0001D55C',
+ "kscr;": '\U0001D4C0',
+ "lAarr;": '\U000021DA',
+ "lArr;": '\U000021D0',
+ "lAtail;": '\U0000291B',
+ "lBarr;": '\U0000290E',
+ "lE;": '\U00002266',
+ "lEg;": '\U00002A8B',
+ "lHar;": '\U00002962',
+ "lacute;": '\U0000013A',
+ "laemptyv;": '\U000029B4',
+ "lagran;": '\U00002112',
+ "lambda;": '\U000003BB',
+ "lang;": '\U000027E8',
+ "langd;": '\U00002991',
+ "langle;": '\U000027E8',
+ "lap;": '\U00002A85',
+ "laquo;": '\U000000AB',
+ "larr;": '\U00002190',
+ "larrb;": '\U000021E4',
+ "larrbfs;": '\U0000291F',
+ "larrfs;": '\U0000291D',
+ "larrhk;": '\U000021A9',
+ "larrlp;": '\U000021AB',
+ "larrpl;": '\U00002939',
+ "larrsim;": '\U00002973',
+ "larrtl;": '\U000021A2',
+ "lat;": '\U00002AAB',
+ "latail;": '\U00002919',
+ "late;": '\U00002AAD',
+ "lbarr;": '\U0000290C',
+ "lbbrk;": '\U00002772',
+ "lbrace;": '\U0000007B',
+ "lbrack;": '\U0000005B',
+ "lbrke;": '\U0000298B',
+ "lbrksld;": '\U0000298F',
+ "lbrkslu;": '\U0000298D',
+ "lcaron;": '\U0000013E',
+ "lcedil;": '\U0000013C',
+ "lceil;": '\U00002308',
+ "lcub;": '\U0000007B',
+ "lcy;": '\U0000043B',
+ "ldca;": '\U00002936',
+ "ldquo;": '\U0000201C',
+ "ldquor;": '\U0000201E',
+ "ldrdhar;": '\U00002967',
+ "ldrushar;": '\U0000294B',
+ "ldsh;": '\U000021B2',
+ "le;": '\U00002264',
+ "leftarrow;": '\U00002190',
+ "leftarrowtail;": '\U000021A2',
+ "leftharpoondown;": '\U000021BD',
+ "leftharpoonup;": '\U000021BC',
+ "leftleftarrows;": '\U000021C7',
+ "leftrightarrow;": '\U00002194',
+ "leftrightarrows;": '\U000021C6',
+ "leftrightharpoons;": '\U000021CB',
+ "leftrightsquigarrow;": '\U000021AD',
+ "leftthreetimes;": '\U000022CB',
+ "leg;": '\U000022DA',
+ "leq;": '\U00002264',
+ "leqq;": '\U00002266',
+ "leqslant;": '\U00002A7D',
+ "les;": '\U00002A7D',
+ "lescc;": '\U00002AA8',
+ "lesdot;": '\U00002A7F',
+ "lesdoto;": '\U00002A81',
+ "lesdotor;": '\U00002A83',
+ "lesges;": '\U00002A93',
+ "lessapprox;": '\U00002A85',
+ "lessdot;": '\U000022D6',
+ "lesseqgtr;": '\U000022DA',
+ "lesseqqgtr;": '\U00002A8B',
+ "lessgtr;": '\U00002276',
+ "lesssim;": '\U00002272',
+ "lfisht;": '\U0000297C',
+ "lfloor;": '\U0000230A',
+ "lfr;": '\U0001D529',
+ "lg;": '\U00002276',
+ "lgE;": '\U00002A91',
+ "lhard;": '\U000021BD',
+ "lharu;": '\U000021BC',
+ "lharul;": '\U0000296A',
+ "lhblk;": '\U00002584',
+ "ljcy;": '\U00000459',
+ "ll;": '\U0000226A',
+ "llarr;": '\U000021C7',
+ "llcorner;": '\U0000231E',
+ "llhard;": '\U0000296B',
+ "lltri;": '\U000025FA',
+ "lmidot;": '\U00000140',
+ "lmoust;": '\U000023B0',
+ "lmoustache;": '\U000023B0',
+ "lnE;": '\U00002268',
+ "lnap;": '\U00002A89',
+ "lnapprox;": '\U00002A89',
+ "lne;": '\U00002A87',
+ "lneq;": '\U00002A87',
+ "lneqq;": '\U00002268',
+ "lnsim;": '\U000022E6',
+ "loang;": '\U000027EC',
+ "loarr;": '\U000021FD',
+ "lobrk;": '\U000027E6',
+ "longleftarrow;": '\U000027F5',
+ "longleftrightarrow;": '\U000027F7',
+ "longmapsto;": '\U000027FC',
+ "longrightarrow;": '\U000027F6',
+ "looparrowleft;": '\U000021AB',
+ "looparrowright;": '\U000021AC',
+ "lopar;": '\U00002985',
+ "lopf;": '\U0001D55D',
+ "loplus;": '\U00002A2D',
+ "lotimes;": '\U00002A34',
+ "lowast;": '\U00002217',
+ "lowbar;": '\U0000005F',
+ "loz;": '\U000025CA',
+ "lozenge;": '\U000025CA',
+ "lozf;": '\U000029EB',
+ "lpar;": '\U00000028',
+ "lparlt;": '\U00002993',
+ "lrarr;": '\U000021C6',
+ "lrcorner;": '\U0000231F',
+ "lrhar;": '\U000021CB',
+ "lrhard;": '\U0000296D',
+ "lrm;": '\U0000200E',
+ "lrtri;": '\U000022BF',
+ "lsaquo;": '\U00002039',
+ "lscr;": '\U0001D4C1',
+ "lsh;": '\U000021B0',
+ "lsim;": '\U00002272',
+ "lsime;": '\U00002A8D',
+ "lsimg;": '\U00002A8F',
+ "lsqb;": '\U0000005B',
+ "lsquo;": '\U00002018',
+ "lsquor;": '\U0000201A',
+ "lstrok;": '\U00000142',
+ "lt;": '\U0000003C',
+ "ltcc;": '\U00002AA6',
+ "ltcir;": '\U00002A79',
+ "ltdot;": '\U000022D6',
+ "lthree;": '\U000022CB',
+ "ltimes;": '\U000022C9',
+ "ltlarr;": '\U00002976',
+ "ltquest;": '\U00002A7B',
+ "ltrPar;": '\U00002996',
+ "ltri;": '\U000025C3',
+ "ltrie;": '\U000022B4',
+ "ltrif;": '\U000025C2',
+ "lurdshar;": '\U0000294A',
+ "luruhar;": '\U00002966',
+ "mDDot;": '\U0000223A',
+ "macr;": '\U000000AF',
+ "male;": '\U00002642',
+ "malt;": '\U00002720',
+ "maltese;": '\U00002720',
+ "map;": '\U000021A6',
+ "mapsto;": '\U000021A6',
+ "mapstodown;": '\U000021A7',
+ "mapstoleft;": '\U000021A4',
+ "mapstoup;": '\U000021A5',
+ "marker;": '\U000025AE',
+ "mcomma;": '\U00002A29',
+ "mcy;": '\U0000043C',
+ "mdash;": '\U00002014',
+ "measuredangle;": '\U00002221',
+ "mfr;": '\U0001D52A',
+ "mho;": '\U00002127',
+ "micro;": '\U000000B5',
+ "mid;": '\U00002223',
+ "midast;": '\U0000002A',
+ "midcir;": '\U00002AF0',
+ "middot;": '\U000000B7',
+ "minus;": '\U00002212',
+ "minusb;": '\U0000229F',
+ "minusd;": '\U00002238',
+ "minusdu;": '\U00002A2A',
+ "mlcp;": '\U00002ADB',
+ "mldr;": '\U00002026',
+ "mnplus;": '\U00002213',
+ "models;": '\U000022A7',
+ "mopf;": '\U0001D55E',
+ "mp;": '\U00002213',
+ "mscr;": '\U0001D4C2',
+ "mstpos;": '\U0000223E',
+ "mu;": '\U000003BC',
+ "multimap;": '\U000022B8',
+ "mumap;": '\U000022B8',
+ "nLeftarrow;": '\U000021CD',
+ "nLeftrightarrow;": '\U000021CE',
+ "nRightarrow;": '\U000021CF',
+ "nVDash;": '\U000022AF',
+ "nVdash;": '\U000022AE',
+ "nabla;": '\U00002207',
+ "nacute;": '\U00000144',
+ "nap;": '\U00002249',
+ "napos;": '\U00000149',
+ "napprox;": '\U00002249',
+ "natur;": '\U0000266E',
+ "natural;": '\U0000266E',
+ "naturals;": '\U00002115',
+ "nbsp;": '\U000000A0',
+ "ncap;": '\U00002A43',
+ "ncaron;": '\U00000148',
+ "ncedil;": '\U00000146',
+ "ncong;": '\U00002247',
+ "ncup;": '\U00002A42',
+ "ncy;": '\U0000043D',
+ "ndash;": '\U00002013',
+ "ne;": '\U00002260',
+ "neArr;": '\U000021D7',
+ "nearhk;": '\U00002924',
+ "nearr;": '\U00002197',
+ "nearrow;": '\U00002197',
+ "nequiv;": '\U00002262',
+ "nesear;": '\U00002928',
+ "nexist;": '\U00002204',
+ "nexists;": '\U00002204',
+ "nfr;": '\U0001D52B',
+ "nge;": '\U00002271',
+ "ngeq;": '\U00002271',
+ "ngsim;": '\U00002275',
+ "ngt;": '\U0000226F',
+ "ngtr;": '\U0000226F',
+ "nhArr;": '\U000021CE',
+ "nharr;": '\U000021AE',
+ "nhpar;": '\U00002AF2',
+ "ni;": '\U0000220B',
+ "nis;": '\U000022FC',
+ "nisd;": '\U000022FA',
+ "niv;": '\U0000220B',
+ "njcy;": '\U0000045A',
+ "nlArr;": '\U000021CD',
+ "nlarr;": '\U0000219A',
+ "nldr;": '\U00002025',
+ "nle;": '\U00002270',
+ "nleftarrow;": '\U0000219A',
+ "nleftrightarrow;": '\U000021AE',
+ "nleq;": '\U00002270',
+ "nless;": '\U0000226E',
+ "nlsim;": '\U00002274',
+ "nlt;": '\U0000226E',
+ "nltri;": '\U000022EA',
+ "nltrie;": '\U000022EC',
+ "nmid;": '\U00002224',
+ "nopf;": '\U0001D55F',
+ "not;": '\U000000AC',
+ "notin;": '\U00002209',
+ "notinva;": '\U00002209',
+ "notinvb;": '\U000022F7',
+ "notinvc;": '\U000022F6',
+ "notni;": '\U0000220C',
+ "notniva;": '\U0000220C',
+ "notnivb;": '\U000022FE',
+ "notnivc;": '\U000022FD',
+ "npar;": '\U00002226',
+ "nparallel;": '\U00002226',
+ "npolint;": '\U00002A14',
+ "npr;": '\U00002280',
+ "nprcue;": '\U000022E0',
+ "nprec;": '\U00002280',
+ "nrArr;": '\U000021CF',
+ "nrarr;": '\U0000219B',
+ "nrightarrow;": '\U0000219B',
+ "nrtri;": '\U000022EB',
+ "nrtrie;": '\U000022ED',
+ "nsc;": '\U00002281',
+ "nsccue;": '\U000022E1',
+ "nscr;": '\U0001D4C3',
+ "nshortmid;": '\U00002224',
+ "nshortparallel;": '\U00002226',
+ "nsim;": '\U00002241',
+ "nsime;": '\U00002244',
+ "nsimeq;": '\U00002244',
+ "nsmid;": '\U00002224',
+ "nspar;": '\U00002226',
+ "nsqsube;": '\U000022E2',
+ "nsqsupe;": '\U000022E3',
+ "nsub;": '\U00002284',
+ "nsube;": '\U00002288',
+ "nsubseteq;": '\U00002288',
+ "nsucc;": '\U00002281',
+ "nsup;": '\U00002285',
+ "nsupe;": '\U00002289',
+ "nsupseteq;": '\U00002289',
+ "ntgl;": '\U00002279',
+ "ntilde;": '\U000000F1',
+ "ntlg;": '\U00002278',
+ "ntriangleleft;": '\U000022EA',
+ "ntrianglelefteq;": '\U000022EC',
+ "ntriangleright;": '\U000022EB',
+ "ntrianglerighteq;": '\U000022ED',
+ "nu;": '\U000003BD',
+ "num;": '\U00000023',
+ "numero;": '\U00002116',
+ "numsp;": '\U00002007',
+ "nvDash;": '\U000022AD',
+ "nvHarr;": '\U00002904',
+ "nvdash;": '\U000022AC',
+ "nvinfin;": '\U000029DE',
+ "nvlArr;": '\U00002902',
+ "nvrArr;": '\U00002903',
+ "nwArr;": '\U000021D6',
+ "nwarhk;": '\U00002923',
+ "nwarr;": '\U00002196',
+ "nwarrow;": '\U00002196',
+ "nwnear;": '\U00002927',
+ "oS;": '\U000024C8',
+ "oacute;": '\U000000F3',
+ "oast;": '\U0000229B',
+ "ocir;": '\U0000229A',
+ "ocirc;": '\U000000F4',
+ "ocy;": '\U0000043E',
+ "odash;": '\U0000229D',
+ "odblac;": '\U00000151',
+ "odiv;": '\U00002A38',
+ "odot;": '\U00002299',
+ "odsold;": '\U000029BC',
+ "oelig;": '\U00000153',
+ "ofcir;": '\U000029BF',
+ "ofr;": '\U0001D52C',
+ "ogon;": '\U000002DB',
+ "ograve;": '\U000000F2',
+ "ogt;": '\U000029C1',
+ "ohbar;": '\U000029B5',
+ "ohm;": '\U000003A9',
+ "oint;": '\U0000222E',
+ "olarr;": '\U000021BA',
+ "olcir;": '\U000029BE',
+ "olcross;": '\U000029BB',
+ "oline;": '\U0000203E',
+ "olt;": '\U000029C0',
+ "omacr;": '\U0000014D',
+ "omega;": '\U000003C9',
+ "omicron;": '\U000003BF',
+ "omid;": '\U000029B6',
+ "ominus;": '\U00002296',
+ "oopf;": '\U0001D560',
+ "opar;": '\U000029B7',
+ "operp;": '\U000029B9',
+ "oplus;": '\U00002295',
+ "or;": '\U00002228',
+ "orarr;": '\U000021BB',
+ "ord;": '\U00002A5D',
+ "order;": '\U00002134',
+ "orderof;": '\U00002134',
+ "ordf;": '\U000000AA',
+ "ordm;": '\U000000BA',
+ "origof;": '\U000022B6',
+ "oror;": '\U00002A56',
+ "orslope;": '\U00002A57',
+ "orv;": '\U00002A5B',
+ "oscr;": '\U00002134',
+ "oslash;": '\U000000F8',
+ "osol;": '\U00002298',
+ "otilde;": '\U000000F5',
+ "otimes;": '\U00002297',
+ "otimesas;": '\U00002A36',
+ "ouml;": '\U000000F6',
+ "ovbar;": '\U0000233D',
+ "par;": '\U00002225',
+ "para;": '\U000000B6',
+ "parallel;": '\U00002225',
+ "parsim;": '\U00002AF3',
+ "parsl;": '\U00002AFD',
+ "part;": '\U00002202',
+ "pcy;": '\U0000043F',
+ "percnt;": '\U00000025',
+ "period;": '\U0000002E',
+ "permil;": '\U00002030',
+ "perp;": '\U000022A5',
+ "pertenk;": '\U00002031',
+ "pfr;": '\U0001D52D',
+ "phi;": '\U000003C6',
+ "phiv;": '\U000003D5',
+ "phmmat;": '\U00002133',
+ "phone;": '\U0000260E',
+ "pi;": '\U000003C0',
+ "pitchfork;": '\U000022D4',
+ "piv;": '\U000003D6',
+ "planck;": '\U0000210F',
+ "planckh;": '\U0000210E',
+ "plankv;": '\U0000210F',
+ "plus;": '\U0000002B',
+ "plusacir;": '\U00002A23',
+ "plusb;": '\U0000229E',
+ "pluscir;": '\U00002A22',
+ "plusdo;": '\U00002214',
+ "plusdu;": '\U00002A25',
+ "pluse;": '\U00002A72',
+ "plusmn;": '\U000000B1',
+ "plussim;": '\U00002A26',
+ "plustwo;": '\U00002A27',
+ "pm;": '\U000000B1',
+ "pointint;": '\U00002A15',
+ "popf;": '\U0001D561',
+ "pound;": '\U000000A3',
+ "pr;": '\U0000227A',
+ "prE;": '\U00002AB3',
+ "prap;": '\U00002AB7',
+ "prcue;": '\U0000227C',
+ "pre;": '\U00002AAF',
+ "prec;": '\U0000227A',
+ "precapprox;": '\U00002AB7',
+ "preccurlyeq;": '\U0000227C',
+ "preceq;": '\U00002AAF',
+ "precnapprox;": '\U00002AB9',
+ "precneqq;": '\U00002AB5',
+ "precnsim;": '\U000022E8',
+ "precsim;": '\U0000227E',
+ "prime;": '\U00002032',
+ "primes;": '\U00002119',
+ "prnE;": '\U00002AB5',
+ "prnap;": '\U00002AB9',
+ "prnsim;": '\U000022E8',
+ "prod;": '\U0000220F',
+ "profalar;": '\U0000232E',
+ "profline;": '\U00002312',
+ "profsurf;": '\U00002313',
+ "prop;": '\U0000221D',
+ "propto;": '\U0000221D',
+ "prsim;": '\U0000227E',
+ "prurel;": '\U000022B0',
+ "pscr;": '\U0001D4C5',
+ "psi;": '\U000003C8',
+ "puncsp;": '\U00002008',
+ "qfr;": '\U0001D52E',
+ "qint;": '\U00002A0C',
+ "qopf;": '\U0001D562',
+ "qprime;": '\U00002057',
+ "qscr;": '\U0001D4C6',
+ "quaternions;": '\U0000210D',
+ "quatint;": '\U00002A16',
+ "quest;": '\U0000003F',
+ "questeq;": '\U0000225F',
+ "quot;": '\U00000022',
+ "rAarr;": '\U000021DB',
+ "rArr;": '\U000021D2',
+ "rAtail;": '\U0000291C',
+ "rBarr;": '\U0000290F',
+ "rHar;": '\U00002964',
+ "racute;": '\U00000155',
+ "radic;": '\U0000221A',
+ "raemptyv;": '\U000029B3',
+ "rang;": '\U000027E9',
+ "rangd;": '\U00002992',
+ "range;": '\U000029A5',
+ "rangle;": '\U000027E9',
+ "raquo;": '\U000000BB',
+ "rarr;": '\U00002192',
+ "rarrap;": '\U00002975',
+ "rarrb;": '\U000021E5',
+ "rarrbfs;": '\U00002920',
+ "rarrc;": '\U00002933',
+ "rarrfs;": '\U0000291E',
+ "rarrhk;": '\U000021AA',
+ "rarrlp;": '\U000021AC',
+ "rarrpl;": '\U00002945',
+ "rarrsim;": '\U00002974',
+ "rarrtl;": '\U000021A3',
+ "rarrw;": '\U0000219D',
+ "ratail;": '\U0000291A',
+ "ratio;": '\U00002236',
+ "rationals;": '\U0000211A',
+ "rbarr;": '\U0000290D',
+ "rbbrk;": '\U00002773',
+ "rbrace;": '\U0000007D',
+ "rbrack;": '\U0000005D',
+ "rbrke;": '\U0000298C',
+ "rbrksld;": '\U0000298E',
+ "rbrkslu;": '\U00002990',
+ "rcaron;": '\U00000159',
+ "rcedil;": '\U00000157',
+ "rceil;": '\U00002309',
+ "rcub;": '\U0000007D',
+ "rcy;": '\U00000440',
+ "rdca;": '\U00002937',
+ "rdldhar;": '\U00002969',
+ "rdquo;": '\U0000201D',
+ "rdquor;": '\U0000201D',
+ "rdsh;": '\U000021B3',
+ "real;": '\U0000211C',
+ "realine;": '\U0000211B',
+ "realpart;": '\U0000211C',
+ "reals;": '\U0000211D',
+ "rect;": '\U000025AD',
+ "reg;": '\U000000AE',
+ "rfisht;": '\U0000297D',
+ "rfloor;": '\U0000230B',
+ "rfr;": '\U0001D52F',
+ "rhard;": '\U000021C1',
+ "rharu;": '\U000021C0',
+ "rharul;": '\U0000296C',
+ "rho;": '\U000003C1',
+ "rhov;": '\U000003F1',
+ "rightarrow;": '\U00002192',
+ "rightarrowtail;": '\U000021A3',
+ "rightharpoondown;": '\U000021C1',
+ "rightharpoonup;": '\U000021C0',
+ "rightleftarrows;": '\U000021C4',
+ "rightleftharpoons;": '\U000021CC',
+ "rightrightarrows;": '\U000021C9',
+ "rightsquigarrow;": '\U0000219D',
+ "rightthreetimes;": '\U000022CC',
+ "ring;": '\U000002DA',
+ "risingdotseq;": '\U00002253',
+ "rlarr;": '\U000021C4',
+ "rlhar;": '\U000021CC',
+ "rlm;": '\U0000200F',
+ "rmoust;": '\U000023B1',
+ "rmoustache;": '\U000023B1',
+ "rnmid;": '\U00002AEE',
+ "roang;": '\U000027ED',
+ "roarr;": '\U000021FE',
+ "robrk;": '\U000027E7',
+ "ropar;": '\U00002986',
+ "ropf;": '\U0001D563',
+ "roplus;": '\U00002A2E',
+ "rotimes;": '\U00002A35',
+ "rpar;": '\U00000029',
+ "rpargt;": '\U00002994',
+ "rppolint;": '\U00002A12',
+ "rrarr;": '\U000021C9',
+ "rsaquo;": '\U0000203A',
+ "rscr;": '\U0001D4C7',
+ "rsh;": '\U000021B1',
+ "rsqb;": '\U0000005D',
+ "rsquo;": '\U00002019',
+ "rsquor;": '\U00002019',
+ "rthree;": '\U000022CC',
+ "rtimes;": '\U000022CA',
+ "rtri;": '\U000025B9',
+ "rtrie;": '\U000022B5',
+ "rtrif;": '\U000025B8',
+ "rtriltri;": '\U000029CE',
+ "ruluhar;": '\U00002968',
+ "rx;": '\U0000211E',
+ "sacute;": '\U0000015B',
+ "sbquo;": '\U0000201A',
+ "sc;": '\U0000227B',
+ "scE;": '\U00002AB4',
+ "scap;": '\U00002AB8',
+ "scaron;": '\U00000161',
+ "sccue;": '\U0000227D',
+ "sce;": '\U00002AB0',
+ "scedil;": '\U0000015F',
+ "scirc;": '\U0000015D',
+ "scnE;": '\U00002AB6',
+ "scnap;": '\U00002ABA',
+ "scnsim;": '\U000022E9',
+ "scpolint;": '\U00002A13',
+ "scsim;": '\U0000227F',
+ "scy;": '\U00000441',
+ "sdot;": '\U000022C5',
+ "sdotb;": '\U000022A1',
+ "sdote;": '\U00002A66',
+ "seArr;": '\U000021D8',
+ "searhk;": '\U00002925',
+ "searr;": '\U00002198',
+ "searrow;": '\U00002198',
+ "sect;": '\U000000A7',
+ "semi;": '\U0000003B',
+ "seswar;": '\U00002929',
+ "setminus;": '\U00002216',
+ "setmn;": '\U00002216',
+ "sext;": '\U00002736',
+ "sfr;": '\U0001D530',
+ "sfrown;": '\U00002322',
+ "sharp;": '\U0000266F',
+ "shchcy;": '\U00000449',
+ "shcy;": '\U00000448',
+ "shortmid;": '\U00002223',
+ "shortparallel;": '\U00002225',
+ "shy;": '\U000000AD',
+ "sigma;": '\U000003C3',
+ "sigmaf;": '\U000003C2',
+ "sigmav;": '\U000003C2',
+ "sim;": '\U0000223C',
+ "simdot;": '\U00002A6A',
+ "sime;": '\U00002243',
+ "simeq;": '\U00002243',
+ "simg;": '\U00002A9E',
+ "simgE;": '\U00002AA0',
+ "siml;": '\U00002A9D',
+ "simlE;": '\U00002A9F',
+ "simne;": '\U00002246',
+ "simplus;": '\U00002A24',
+ "simrarr;": '\U00002972',
+ "slarr;": '\U00002190',
+ "smallsetminus;": '\U00002216',
+ "smashp;": '\U00002A33',
+ "smeparsl;": '\U000029E4',
+ "smid;": '\U00002223',
+ "smile;": '\U00002323',
+ "smt;": '\U00002AAA',
+ "smte;": '\U00002AAC',
+ "softcy;": '\U0000044C',
+ "sol;": '\U0000002F',
+ "solb;": '\U000029C4',
+ "solbar;": '\U0000233F',
+ "sopf;": '\U0001D564',
+ "spades;": '\U00002660',
+ "spadesuit;": '\U00002660',
+ "spar;": '\U00002225',
+ "sqcap;": '\U00002293',
+ "sqcup;": '\U00002294',
+ "sqsub;": '\U0000228F',
+ "sqsube;": '\U00002291',
+ "sqsubset;": '\U0000228F',
+ "sqsubseteq;": '\U00002291',
+ "sqsup;": '\U00002290',
+ "sqsupe;": '\U00002292',
+ "sqsupset;": '\U00002290',
+ "sqsupseteq;": '\U00002292',
+ "squ;": '\U000025A1',
+ "square;": '\U000025A1',
+ "squarf;": '\U000025AA',
+ "squf;": '\U000025AA',
+ "srarr;": '\U00002192',
+ "sscr;": '\U0001D4C8',
+ "ssetmn;": '\U00002216',
+ "ssmile;": '\U00002323',
+ "sstarf;": '\U000022C6',
+ "star;": '\U00002606',
+ "starf;": '\U00002605',
+ "straightepsilon;": '\U000003F5',
+ "straightphi;": '\U000003D5',
+ "strns;": '\U000000AF',
+ "sub;": '\U00002282',
+ "subE;": '\U00002AC5',
+ "subdot;": '\U00002ABD',
+ "sube;": '\U00002286',
+ "subedot;": '\U00002AC3',
+ "submult;": '\U00002AC1',
+ "subnE;": '\U00002ACB',
+ "subne;": '\U0000228A',
+ "subplus;": '\U00002ABF',
+ "subrarr;": '\U00002979',
+ "subset;": '\U00002282',
+ "subseteq;": '\U00002286',
+ "subseteqq;": '\U00002AC5',
+ "subsetneq;": '\U0000228A',
+ "subsetneqq;": '\U00002ACB',
+ "subsim;": '\U00002AC7',
+ "subsub;": '\U00002AD5',
+ "subsup;": '\U00002AD3',
+ "succ;": '\U0000227B',
+ "succapprox;": '\U00002AB8',
+ "succcurlyeq;": '\U0000227D',
+ "succeq;": '\U00002AB0',
+ "succnapprox;": '\U00002ABA',
+ "succneqq;": '\U00002AB6',
+ "succnsim;": '\U000022E9',
+ "succsim;": '\U0000227F',
+ "sum;": '\U00002211',
+ "sung;": '\U0000266A',
+ "sup;": '\U00002283',
+ "sup1;": '\U000000B9',
+ "sup2;": '\U000000B2',
+ "sup3;": '\U000000B3',
+ "supE;": '\U00002AC6',
+ "supdot;": '\U00002ABE',
+ "supdsub;": '\U00002AD8',
+ "supe;": '\U00002287',
+ "supedot;": '\U00002AC4',
+ "suphsol;": '\U000027C9',
+ "suphsub;": '\U00002AD7',
+ "suplarr;": '\U0000297B',
+ "supmult;": '\U00002AC2',
+ "supnE;": '\U00002ACC',
+ "supne;": '\U0000228B',
+ "supplus;": '\U00002AC0',
+ "supset;": '\U00002283',
+ "supseteq;": '\U00002287',
+ "supseteqq;": '\U00002AC6',
+ "supsetneq;": '\U0000228B',
+ "supsetneqq;": '\U00002ACC',
+ "supsim;": '\U00002AC8',
+ "supsub;": '\U00002AD4',
+ "supsup;": '\U00002AD6',
+ "swArr;": '\U000021D9',
+ "swarhk;": '\U00002926',
+ "swarr;": '\U00002199',
+ "swarrow;": '\U00002199',
+ "swnwar;": '\U0000292A',
+ "szlig;": '\U000000DF',
+ "target;": '\U00002316',
+ "tau;": '\U000003C4',
+ "tbrk;": '\U000023B4',
+ "tcaron;": '\U00000165',
+ "tcedil;": '\U00000163',
+ "tcy;": '\U00000442',
+ "tdot;": '\U000020DB',
+ "telrec;": '\U00002315',
+ "tfr;": '\U0001D531',
+ "there4;": '\U00002234',
+ "therefore;": '\U00002234',
+ "theta;": '\U000003B8',
+ "thetasym;": '\U000003D1',
+ "thetav;": '\U000003D1',
+ "thickapprox;": '\U00002248',
+ "thicksim;": '\U0000223C',
+ "thinsp;": '\U00002009',
+ "thkap;": '\U00002248',
+ "thksim;": '\U0000223C',
+ "thorn;": '\U000000FE',
+ "tilde;": '\U000002DC',
+ "times;": '\U000000D7',
+ "timesb;": '\U000022A0',
+ "timesbar;": '\U00002A31',
+ "timesd;": '\U00002A30',
+ "tint;": '\U0000222D',
+ "toea;": '\U00002928',
+ "top;": '\U000022A4',
+ "topbot;": '\U00002336',
+ "topcir;": '\U00002AF1',
+ "topf;": '\U0001D565',
+ "topfork;": '\U00002ADA',
+ "tosa;": '\U00002929',
+ "tprime;": '\U00002034',
+ "trade;": '\U00002122',
+ "triangle;": '\U000025B5',
+ "triangledown;": '\U000025BF',
+ "triangleleft;": '\U000025C3',
+ "trianglelefteq;": '\U000022B4',
+ "triangleq;": '\U0000225C',
+ "triangleright;": '\U000025B9',
+ "trianglerighteq;": '\U000022B5',
+ "tridot;": '\U000025EC',
+ "trie;": '\U0000225C',
+ "triminus;": '\U00002A3A',
+ "triplus;": '\U00002A39',
+ "trisb;": '\U000029CD',
+ "tritime;": '\U00002A3B',
+ "trpezium;": '\U000023E2',
+ "tscr;": '\U0001D4C9',
+ "tscy;": '\U00000446',
+ "tshcy;": '\U0000045B',
+ "tstrok;": '\U00000167',
+ "twixt;": '\U0000226C',
+ "twoheadleftarrow;": '\U0000219E',
+ "twoheadrightarrow;": '\U000021A0',
+ "uArr;": '\U000021D1',
+ "uHar;": '\U00002963',
+ "uacute;": '\U000000FA',
+ "uarr;": '\U00002191',
+ "ubrcy;": '\U0000045E',
+ "ubreve;": '\U0000016D',
+ "ucirc;": '\U000000FB',
+ "ucy;": '\U00000443',
+ "udarr;": '\U000021C5',
+ "udblac;": '\U00000171',
+ "udhar;": '\U0000296E',
+ "ufisht;": '\U0000297E',
+ "ufr;": '\U0001D532',
+ "ugrave;": '\U000000F9',
+ "uharl;": '\U000021BF',
+ "uharr;": '\U000021BE',
+ "uhblk;": '\U00002580',
+ "ulcorn;": '\U0000231C',
+ "ulcorner;": '\U0000231C',
+ "ulcrop;": '\U0000230F',
+ "ultri;": '\U000025F8',
+ "umacr;": '\U0000016B',
+ "uml;": '\U000000A8',
+ "uogon;": '\U00000173',
+ "uopf;": '\U0001D566',
+ "uparrow;": '\U00002191',
+ "updownarrow;": '\U00002195',
+ "upharpoonleft;": '\U000021BF',
+ "upharpoonright;": '\U000021BE',
+ "uplus;": '\U0000228E',
+ "upsi;": '\U000003C5',
+ "upsih;": '\U000003D2',
+ "upsilon;": '\U000003C5',
+ "upuparrows;": '\U000021C8',
+ "urcorn;": '\U0000231D',
+ "urcorner;": '\U0000231D',
+ "urcrop;": '\U0000230E',
+ "uring;": '\U0000016F',
+ "urtri;": '\U000025F9',
+ "uscr;": '\U0001D4CA',
+ "utdot;": '\U000022F0',
+ "utilde;": '\U00000169',
+ "utri;": '\U000025B5',
+ "utrif;": '\U000025B4',
+ "uuarr;": '\U000021C8',
+ "uuml;": '\U000000FC',
+ "uwangle;": '\U000029A7',
+ "vArr;": '\U000021D5',
+ "vBar;": '\U00002AE8',
+ "vBarv;": '\U00002AE9',
+ "vDash;": '\U000022A8',
+ "vangrt;": '\U0000299C',
+ "varepsilon;": '\U000003F5',
+ "varkappa;": '\U000003F0',
+ "varnothing;": '\U00002205',
+ "varphi;": '\U000003D5',
+ "varpi;": '\U000003D6',
+ "varpropto;": '\U0000221D',
+ "varr;": '\U00002195',
+ "varrho;": '\U000003F1',
+ "varsigma;": '\U000003C2',
+ "vartheta;": '\U000003D1',
+ "vartriangleleft;": '\U000022B2',
+ "vartriangleright;": '\U000022B3',
+ "vcy;": '\U00000432',
+ "vdash;": '\U000022A2',
+ "vee;": '\U00002228',
+ "veebar;": '\U000022BB',
+ "veeeq;": '\U0000225A',
+ "vellip;": '\U000022EE',
+ "verbar;": '\U0000007C',
+ "vert;": '\U0000007C',
+ "vfr;": '\U0001D533',
+ "vltri;": '\U000022B2',
+ "vopf;": '\U0001D567',
+ "vprop;": '\U0000221D',
+ "vrtri;": '\U000022B3',
+ "vscr;": '\U0001D4CB',
+ "vzigzag;": '\U0000299A',
+ "wcirc;": '\U00000175',
+ "wedbar;": '\U00002A5F',
+ "wedge;": '\U00002227',
+ "wedgeq;": '\U00002259',
+ "weierp;": '\U00002118',
+ "wfr;": '\U0001D534',
+ "wopf;": '\U0001D568',
+ "wp;": '\U00002118',
+ "wr;": '\U00002240',
+ "wreath;": '\U00002240',
+ "wscr;": '\U0001D4CC',
+ "xcap;": '\U000022C2',
+ "xcirc;": '\U000025EF',
+ "xcup;": '\U000022C3',
+ "xdtri;": '\U000025BD',
+ "xfr;": '\U0001D535',
+ "xhArr;": '\U000027FA',
+ "xharr;": '\U000027F7',
+ "xi;": '\U000003BE',
+ "xlArr;": '\U000027F8',
+ "xlarr;": '\U000027F5',
+ "xmap;": '\U000027FC',
+ "xnis;": '\U000022FB',
+ "xodot;": '\U00002A00',
+ "xopf;": '\U0001D569',
+ "xoplus;": '\U00002A01',
+ "xotime;": '\U00002A02',
+ "xrArr;": '\U000027F9',
+ "xrarr;": '\U000027F6',
+ "xscr;": '\U0001D4CD',
+ "xsqcup;": '\U00002A06',
+ "xuplus;": '\U00002A04',
+ "xutri;": '\U000025B3',
+ "xvee;": '\U000022C1',
+ "xwedge;": '\U000022C0',
+ "yacute;": '\U000000FD',
+ "yacy;": '\U0000044F',
+ "ycirc;": '\U00000177',
+ "ycy;": '\U0000044B',
+ "yen;": '\U000000A5',
+ "yfr;": '\U0001D536',
+ "yicy;": '\U00000457',
+ "yopf;": '\U0001D56A',
+ "yscr;": '\U0001D4CE',
+ "yucy;": '\U0000044E',
+ "yuml;": '\U000000FF',
+ "zacute;": '\U0000017A',
+ "zcaron;": '\U0000017E',
+ "zcy;": '\U00000437',
+ "zdot;": '\U0000017C',
+ "zeetrf;": '\U00002128',
+ "zeta;": '\U000003B6',
+ "zfr;": '\U0001D537',
+ "zhcy;": '\U00000436',
+ "zigrarr;": '\U000021DD',
+ "zopf;": '\U0001D56B',
+ "zscr;": '\U0001D4CF',
+ "zwj;": '\U0000200D',
+ "zwnj;": '\U0000200C',
+ "AElig": '\U000000C6',
+ "AMP": '\U00000026',
+ "Aacute": '\U000000C1',
+ "Acirc": '\U000000C2',
+ "Agrave": '\U000000C0',
+ "Aring": '\U000000C5',
+ "Atilde": '\U000000C3',
+ "Auml": '\U000000C4',
+ "COPY": '\U000000A9',
+ "Ccedil": '\U000000C7',
+ "ETH": '\U000000D0',
+ "Eacute": '\U000000C9',
+ "Ecirc": '\U000000CA',
+ "Egrave": '\U000000C8',
+ "Euml": '\U000000CB',
+ "GT": '\U0000003E',
+ "Iacute": '\U000000CD',
+ "Icirc": '\U000000CE',
+ "Igrave": '\U000000CC',
+ "Iuml": '\U000000CF',
+ "LT": '\U0000003C',
+ "Ntilde": '\U000000D1',
+ "Oacute": '\U000000D3',
+ "Ocirc": '\U000000D4',
+ "Ograve": '\U000000D2',
+ "Oslash": '\U000000D8',
+ "Otilde": '\U000000D5',
+ "Ouml": '\U000000D6',
+ "QUOT": '\U00000022',
+ "REG": '\U000000AE',
+ "THORN": '\U000000DE',
+ "Uacute": '\U000000DA',
+ "Ucirc": '\U000000DB',
+ "Ugrave": '\U000000D9',
+ "Uuml": '\U000000DC',
+ "Yacute": '\U000000DD',
+ "aacute": '\U000000E1',
+ "acirc": '\U000000E2',
+ "acute": '\U000000B4',
+ "aelig": '\U000000E6',
+ "agrave": '\U000000E0',
+ "amp": '\U00000026',
+ "aring": '\U000000E5',
+ "atilde": '\U000000E3',
+ "auml": '\U000000E4',
+ "brvbar": '\U000000A6',
+ "ccedil": '\U000000E7',
+ "cedil": '\U000000B8',
+ "cent": '\U000000A2',
+ "copy": '\U000000A9',
+ "curren": '\U000000A4',
+ "deg": '\U000000B0',
+ "divide": '\U000000F7',
+ "eacute": '\U000000E9',
+ "ecirc": '\U000000EA',
+ "egrave": '\U000000E8',
+ "eth": '\U000000F0',
+ "euml": '\U000000EB',
+ "frac12": '\U000000BD',
+ "frac14": '\U000000BC',
+ "frac34": '\U000000BE',
+ "gt": '\U0000003E',
+ "iacute": '\U000000ED',
+ "icirc": '\U000000EE',
+ "iexcl": '\U000000A1',
+ "igrave": '\U000000EC',
+ "iquest": '\U000000BF',
+ "iuml": '\U000000EF',
+ "laquo": '\U000000AB',
+ "lt": '\U0000003C',
+ "macr": '\U000000AF',
+ "micro": '\U000000B5',
+ "middot": '\U000000B7',
+ "nbsp": '\U000000A0',
+ "not": '\U000000AC',
+ "ntilde": '\U000000F1',
+ "oacute": '\U000000F3',
+ "ocirc": '\U000000F4',
+ "ograve": '\U000000F2',
+ "ordf": '\U000000AA',
+ "ordm": '\U000000BA',
+ "oslash": '\U000000F8',
+ "otilde": '\U000000F5',
+ "ouml": '\U000000F6',
+ "para": '\U000000B6',
+ "plusmn": '\U000000B1',
+ "pound": '\U000000A3',
+ "quot": '\U00000022',
+ "raquo": '\U000000BB',
+ "reg": '\U000000AE',
+ "sect": '\U000000A7',
+ "shy": '\U000000AD',
+ "sup1": '\U000000B9',
+ "sup2": '\U000000B2',
+ "sup3": '\U000000B3',
+ "szlig": '\U000000DF',
+ "thorn": '\U000000FE',
+ "times": '\U000000D7',
+ "uacute": '\U000000FA',
+ "ucirc": '\U000000FB',
+ "ugrave": '\U000000F9',
+ "uml": '\U000000A8',
+ "uuml": '\U000000FC',
+ "yacute": '\U000000FD',
+ "yen": '\U000000A5',
+ "yuml": '\U000000FF',
+}
+
+// HTML entities that are two unicode codepoints.
+var entity2 = map[string][2]int{
+ // TODO(nigeltao): Handle replacements that are wider than their names.
+ // "nLt;": {'\u226A', '\u20D2'},
+ // "nGt;": {'\u226B', '\u20D2'},
+ "NotEqualTilde;": {'\u2242', '\u0338'},
+ "NotGreaterFullEqual;": {'\u2267', '\u0338'},
+ "NotGreaterGreater;": {'\u226B', '\u0338'},
+ "NotGreaterSlantEqual;": {'\u2A7E', '\u0338'},
+ "NotHumpDownHump;": {'\u224E', '\u0338'},
+ "NotHumpEqual;": {'\u224F', '\u0338'},
+ "NotLeftTriangleBar;": {'\u29CF', '\u0338'},
+ "NotLessLess;": {'\u226A', '\u0338'},
+ "NotLessSlantEqual;": {'\u2A7D', '\u0338'},
+ "NotNestedGreaterGreater;": {'\u2AA2', '\u0338'},
+ "NotNestedLessLess;": {'\u2AA1', '\u0338'},
+ "NotPrecedesEqual;": {'\u2AAF', '\u0338'},
+ "NotRightTriangleBar;": {'\u29D0', '\u0338'},
+ "NotSquareSubset;": {'\u228F', '\u0338'},
+ "NotSquareSuperset;": {'\u2290', '\u0338'},
+ "NotSubset;": {'\u2282', '\u20D2'},
+ "NotSucceedsEqual;": {'\u2AB0', '\u0338'},
+ "NotSucceedsTilde;": {'\u227F', '\u0338'},
+ "NotSuperset;": {'\u2283', '\u20D2'},
+ "ThickSpace;": {'\u205F', '\u200A'},
+ "acE;": {'\u223E', '\u0333'},
+ "bne;": {'\u003D', '\u20E5'},
+ "bnequiv;": {'\u2261', '\u20E5'},
+ "caps;": {'\u2229', '\uFE00'},
+ "cups;": {'\u222A', '\uFE00'},
+ "fjlig;": {'\u0066', '\u006A'},
+ "gesl;": {'\u22DB', '\uFE00'},
+ "gvertneqq;": {'\u2269', '\uFE00'},
+ "gvnE;": {'\u2269', '\uFE00'},
+ "lates;": {'\u2AAD', '\uFE00'},
+ "lesg;": {'\u22DA', '\uFE00'},
+ "lvertneqq;": {'\u2268', '\uFE00'},
+ "lvnE;": {'\u2268', '\uFE00'},
+ "nGg;": {'\u22D9', '\u0338'},
+ "nGtv;": {'\u226B', '\u0338'},
+ "nLl;": {'\u22D8', '\u0338'},
+ "nLtv;": {'\u226A', '\u0338'},
+ "nang;": {'\u2220', '\u20D2'},
+ "napE;": {'\u2A70', '\u0338'},
+ "napid;": {'\u224B', '\u0338'},
+ "nbump;": {'\u224E', '\u0338'},
+ "nbumpe;": {'\u224F', '\u0338'},
+ "ncongdot;": {'\u2A6D', '\u0338'},
+ "nedot;": {'\u2250', '\u0338'},
+ "nesim;": {'\u2242', '\u0338'},
+ "ngE;": {'\u2267', '\u0338'},
+ "ngeqq;": {'\u2267', '\u0338'},
+ "ngeqslant;": {'\u2A7E', '\u0338'},
+ "nges;": {'\u2A7E', '\u0338'},
+ "nlE;": {'\u2266', '\u0338'},
+ "nleqq;": {'\u2266', '\u0338'},
+ "nleqslant;": {'\u2A7D', '\u0338'},
+ "nles;": {'\u2A7D', '\u0338'},
+ "notinE;": {'\u22F9', '\u0338'},
+ "notindot;": {'\u22F5', '\u0338'},
+ "nparsl;": {'\u2AFD', '\u20E5'},
+ "npart;": {'\u2202', '\u0338'},
+ "npre;": {'\u2AAF', '\u0338'},
+ "npreceq;": {'\u2AAF', '\u0338'},
+ "nrarrc;": {'\u2933', '\u0338'},
+ "nrarrw;": {'\u219D', '\u0338'},
+ "nsce;": {'\u2AB0', '\u0338'},
+ "nsubE;": {'\u2AC5', '\u0338'},
+ "nsubset;": {'\u2282', '\u20D2'},
+ "nsubseteqq;": {'\u2AC5', '\u0338'},
+ "nsucceq;": {'\u2AB0', '\u0338'},
+ "nsupE;": {'\u2AC6', '\u0338'},
+ "nsupset;": {'\u2283', '\u20D2'},
+ "nsupseteqq;": {'\u2AC6', '\u0338'},
+ "nvap;": {'\u224D', '\u20D2'},
+ "nvge;": {'\u2265', '\u20D2'},
+ "nvgt;": {'\u003E', '\u20D2'},
+ "nvle;": {'\u2264', '\u20D2'},
+ "nvlt;": {'\u003C', '\u20D2'},
+ "nvltrie;": {'\u22B4', '\u20D2'},
+ "nvrtrie;": {'\u22B5', '\u20D2'},
+ "nvsim;": {'\u223C', '\u20D2'},
+ "race;": {'\u223D', '\u0331'},
+ "smtes;": {'\u2AAC', '\uFE00'},
+ "sqcaps;": {'\u2293', '\uFE00'},
+ "sqcups;": {'\u2294', '\uFE00'},
+ "varsubsetneq;": {'\u228A', '\uFE00'},
+ "varsubsetneqq;": {'\u2ACB', '\uFE00'},
+ "varsupsetneq;": {'\u228B', '\uFE00'},
+ "varsupsetneqq;": {'\u2ACC', '\uFE00'},
+ "vnsub;": {'\u2282', '\u20D2'},
+ "vnsup;": {'\u2283', '\u20D2'},
+ "vsubnE;": {'\u2ACB', '\uFE00'},
+ "vsubne;": {'\u228A', '\uFE00'},
+ "vsupnE;": {'\u2ACC', '\uFE00'},
+ "vsupne;": {'\u228B', '\uFE00'},
+}
diff --git a/src/pkg/html/entity_test.go b/src/pkg/html/entity_test.go
new file mode 100644
index 000000000..a1eb4d4f0
--- /dev/null
+++ b/src/pkg/html/entity_test.go
@@ -0,0 +1,26 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package html
+
+import (
+ "testing"
+ "utf8"
+)
+
+func TestEntityLength(t *testing.T) {
+ // We verify that the length of UTF-8 encoding of each value is <= 1 + len(key).
+ // The +1 comes from the leading "&". This property implies that the length of
+ // unescaped text is <= the length of escaped text.
+ for k, v := range entity {
+ if 1+len(k) < utf8.RuneLen(v) {
+ t.Error("escaped entity &" + k + " is shorter than its UTF-8 encoding " + string(v))
+ }
+ }
+ for k, v := range entity2 {
+ if 1+len(k) < utf8.RuneLen(v[0])+utf8.RuneLen(v[1]) {
+ t.Error("escaped entity &" + k + " is shorter than its UTF-8 encoding " + string(v[0]) + string(v[1]))
+ }
+ }
+}
diff --git a/src/pkg/html/escape.go b/src/pkg/html/escape.go
new file mode 100644
index 000000000..2799f6908
--- /dev/null
+++ b/src/pkg/html/escape.go
@@ -0,0 +1,224 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package html
+
+import (
+ "bytes"
+ "strings"
+ "utf8"
+)
+
+// These replacements permit compatibility with old numeric entities that
+// assumed Windows-1252 encoding.
+// http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#consume-a-character-reference
+var replacementTable = [...]int{
+ '\u20AC', // First entry is what 0x80 should be replaced with.
+ '\u0081',
+ '\u201A',
+ '\u0192',
+ '\u201E',
+ '\u2026',
+ '\u2020',
+ '\u2021',
+ '\u02C6',
+ '\u2030',
+ '\u0160',
+ '\u2039',
+ '\u0152',
+ '\u008D',
+ '\u017D',
+ '\u008F',
+ '\u0090',
+ '\u2018',
+ '\u2019',
+ '\u201C',
+ '\u201D',
+ '\u2022',
+ '\u2013',
+ '\u2014',
+ '\u02DC',
+ '\u2122',
+ '\u0161',
+ '\u203A',
+ '\u0153',
+ '\u009D',
+ '\u017E',
+ '\u0178', // Last entry is 0x9F.
+ // 0x00->'\uFFFD' is handled programmatically.
+ // 0x0D->'\u000D' is a no-op.
+}
+
+// unescapeEntity reads an entity like "&lt;" from b[src:] and writes the
+// corresponding "<" to b[dst:], returning the incremented dst and src cursors.
+// Precondition: b[src] == '&' && dst <= src.
+func unescapeEntity(b []byte, dst, src int) (dst1, src1 int) {
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#consume-a-character-reference
+
+ // i starts at 1 because we already know that s[0] == '&'.
+ i, s := 1, b[src:]
+
+ if len(s) <= 1 {
+ b[dst] = b[src]
+ return dst + 1, src + 1
+ }
+
+ if s[i] == '#' {
+ if len(s) <= 3 { // We need to have at least "&#.".
+ b[dst] = b[src]
+ return dst + 1, src + 1
+ }
+ i++
+ c := s[i]
+ hex := false
+ if c == 'x' || c == 'X' {
+ hex = true
+ i++
+ }
+
+ x := 0
+ for i < len(s) {
+ c = s[i]
+ i++
+ if hex {
+ if '0' <= c && c <= '9' {
+ x = 16*x + int(c) - '0'
+ continue
+ } else if 'a' <= c && c <= 'f' {
+ x = 16*x + int(c) - 'a' + 10
+ continue
+ } else if 'A' <= c && c <= 'F' {
+ x = 16*x + int(c) - 'A' + 10
+ continue
+ }
+ } else if '0' <= c && c <= '9' {
+ x = 10*x + int(c) - '0'
+ continue
+ }
+ if c != ';' {
+ i--
+ }
+ break
+ }
+
+ if i <= 3 { // No characters matched.
+ b[dst] = b[src]
+ return dst + 1, src + 1
+ }
+
+ if 0x80 <= x && x <= 0x9F {
+ // Replace characters from Windows-1252 with UTF-8 equivalents.
+ x = replacementTable[x-0x80]
+ } else if x == 0 || (0xD800 <= x && x <= 0xDFFF) || x > 0x10FFFF {
+ // Replace invalid characters with the replacement character.
+ x = '\uFFFD'
+ }
+
+ return dst + utf8.EncodeRune(b[dst:], x), src + i
+ }
+
+ // Consume the maximum number of characters possible, with the
+ // consumed characters matching one of the named references.
+
+ // TODO(nigeltao): unescape("&notit;") should be "¬it;"
+ for i < len(s) {
+ c := s[i]
+ i++
+ // Lower-cased characters are more common in entities, so we check for them first.
+ if 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' {
+ continue
+ }
+ if c != ';' {
+ i--
+ }
+ break
+ }
+
+ entityName := string(s[1:i])
+ if x := entity[entityName]; x != 0 {
+ return dst + utf8.EncodeRune(b[dst:], x), src + i
+ } else if x := entity2[entityName]; x[0] != 0 { // Check if it's a two-character entity.
+ dst1 := dst + utf8.EncodeRune(b[dst:], x[0])
+ return dst1 + utf8.EncodeRune(b[dst1:], x[1]), src + i
+ }
+
+ dst1, src1 = dst+i, src+i
+ copy(b[dst:dst1], b[src:src1])
+ return dst1, src1
+}
+
+// unescape unescapes b's entities in-place, so that "a&lt;b" becomes "a<b".
+func unescape(b []byte) []byte {
+ for i, c := range b {
+ if c == '&' {
+ dst, src := unescapeEntity(b, i, i)
+ for src < len(b) {
+ c := b[src]
+ if c == '&' {
+ dst, src = unescapeEntity(b, dst, src)
+ } else {
+ b[dst] = c
+ dst, src = dst+1, src+1
+ }
+ }
+ return b[0:dst]
+ }
+ }
+ return b
+}
+
+const escapedChars = `&'<>"`
+
+func escape(buf *bytes.Buffer, s string) {
+ i := strings.IndexAny(s, escapedChars)
+ for i != -1 {
+ buf.WriteString(s[0:i])
+ var esc string
+ switch s[i] {
+ case '&':
+ esc = "&amp;"
+ case '\'':
+ esc = "&apos;"
+ case '<':
+ esc = "&lt;"
+ case '>':
+ esc = "&gt;"
+ case '"':
+ esc = "&quot;"
+ default:
+ panic("unrecognized escape character")
+ }
+ s = s[i+1:]
+ buf.WriteString(esc)
+ i = strings.IndexAny(s, escapedChars)
+ }
+ buf.WriteString(s)
+}
+
+// EscapeString escapes special characters like "<" to become "&lt;". It
+// escapes only five such characters: amp, apos, lt, gt and quot.
+// UnescapeString(EscapeString(s)) == s always holds, but the converse isn't
+// always true.
+func EscapeString(s string) string {
+ if strings.IndexAny(s, escapedChars) == -1 {
+ return s
+ }
+ buf := bytes.NewBuffer(nil)
+ escape(buf, s)
+ return buf.String()
+}
+
+// UnescapeString unescapes entities like "&lt;" to become "<". It unescapes a
+// larger range of entities than EscapeString escapes. For example, "&aacute;"
+// unescapes to "á", as does "&#225;" and "&xE1;".
+// UnescapeString(EscapeString(s)) == s always holds, but the converse isn't
+// always true.
+func UnescapeString(s string) string {
+ for _, c := range s {
+ if c == '&' {
+ return string(unescape([]byte(s)))
+ }
+ }
+ return s
+}
diff --git a/src/pkg/html/parse.go b/src/pkg/html/parse.go
new file mode 100644
index 000000000..2ef90a873
--- /dev/null
+++ b/src/pkg/html/parse.go
@@ -0,0 +1,666 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package html
+
+import (
+ "io"
+ "os"
+)
+
+// A NodeType is the type of a Node.
+type NodeType int
+
+const (
+ ErrorNode NodeType = iota
+ TextNode
+ DocumentNode
+ ElementNode
+ CommentNode
+)
+
+// A Node consists of a NodeType and some Data (tag name for element nodes,
+// content for text) and are part of a tree of Nodes. Element nodes may also
+// contain a slice of Attributes. Data is unescaped, so that it looks like
+// "a<b" rather than "a&lt;b".
+type Node struct {
+ Parent *Node
+ Child []*Node
+ Type NodeType
+ Data string
+ Attr []Attribute
+}
+
+// A parser implements the HTML5 parsing algorithm:
+// http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#tree-construction
+type parser struct {
+ // tokenizer provides the tokens for the parser.
+ tokenizer *Tokenizer
+ // tok is the most recently read token.
+ tok Token
+ // Self-closing tags like <hr/> are re-interpreted as a two-token sequence:
+ // <hr> followed by </hr>. hasSelfClosingToken is true if we have just read
+ // the synthetic start tag and the next one due is the matching end tag.
+ hasSelfClosingToken bool
+ // doc is the document root element.
+ doc *Node
+ // The stack of open elements (section 10.2.3.2).
+ stack []*Node
+ // Element pointers (section 10.2.3.4).
+ head, form *Node
+ // Other parsing state flags (section 10.2.3.5).
+ scripting, framesetOK bool
+}
+
+// push pushes onto the stack of open elements.
+func (p *parser) push(n *Node) {
+ p.stack = append(p.stack, n)
+}
+
+// top returns the top of the stack of open elements.
+// This is also known as the current node.
+func (p *parser) top() *Node {
+ if n := len(p.stack); n > 0 {
+ return p.stack[n-1]
+ }
+ return p.doc
+}
+
+// pop pops the top of the stack of open elements.
+// It will panic if the stack is empty.
+func (p *parser) pop() *Node {
+ n := len(p.stack)
+ ret := p.stack[n-1]
+ p.stack = p.stack[:n-1]
+ return ret
+}
+
+// stopTags for use in popUntil. These come from section 10.2.3.2.
+var (
+ defaultScopeStopTags = []string{"applet", "caption", "html", "table", "td", "th", "marquee", "object"}
+ listItemScopeStopTags = []string{"applet", "caption", "html", "table", "td", "th", "marquee", "object", "ol", "ul"}
+ buttonScopeStopTags = []string{"applet", "caption", "html", "table", "td", "th", "marquee", "object", "button"}
+ tableScopeStopTags = []string{"html", "table"}
+)
+
+// popUntil pops the stack of open elements at the highest element whose tag
+// is in matchTags, provided there is no higher element in stopTags. It returns
+// whether or not there was such an element. If there was not, popUntil leaves
+// the stack unchanged.
+//
+// For example, if the stack was:
+// ["html", "body", "font", "table", "b", "i", "u"]
+// then popUntil([]string{"html, "table"}, "font") would return false, but
+// popUntil([]string{"html, "table"}, "i") would return true and the resultant
+// stack would be:
+// ["html", "body", "font", "table", "b"]
+//
+// If an element's tag is in both stopTags and matchTags, then the stack will
+// be popped and the function returns true (provided, of course, there was no
+// higher element in the stack that was also in stopTags). For example,
+// popUntil([]string{"html, "table"}, "table") would return true and leave:
+// ["html", "body", "font"]
+func (p *parser) popUntil(stopTags []string, matchTags ...string) bool {
+ for i := len(p.stack) - 1; i >= 0; i-- {
+ tag := p.stack[i].Data
+ for _, t := range matchTags {
+ if t == tag {
+ p.stack = p.stack[:i]
+ return true
+ }
+ }
+ for _, t := range stopTags {
+ if t == tag {
+ return false
+ }
+ }
+ }
+ return false
+}
+
+// addChild adds a child node n to the top element, and pushes n if it is an
+// element node (text nodes are not part of the stack of open elements).
+func (p *parser) addChild(n *Node) {
+ m := p.top()
+ m.Child = append(m.Child, n)
+ if n.Type == ElementNode {
+ p.push(n)
+ }
+}
+
+// addText calls addChild with a text node.
+func (p *parser) addText(text string) {
+ // TODO: merge s with previous text, if the preceding node is a text node.
+ // TODO: distinguish whitespace text from others.
+ p.addChild(&Node{
+ Type: TextNode,
+ Data: text,
+ })
+}
+
+// addElement calls addChild with an element node.
+func (p *parser) addElement(tag string, attr []Attribute) {
+ p.addChild(&Node{
+ Type: ElementNode,
+ Data: tag,
+ Attr: attr,
+ })
+}
+
+// Section 10.2.3.3.
+func (p *parser) addFormattingElement(tag string, attr []Attribute) {
+ p.addElement(tag, attr)
+ // TODO.
+}
+
+// Section 10.2.3.3.
+func (p *parser) reconstructActiveFormattingElements() {
+ // TODO.
+}
+
+// read reads the next token. This is usually from the tokenizer, but it may
+// be the synthesized end tag implied by a self-closing tag.
+func (p *parser) read() os.Error {
+ if p.hasSelfClosingToken {
+ p.hasSelfClosingToken = false
+ p.tok.Type = EndTagToken
+ p.tok.Attr = nil
+ return nil
+ }
+ p.tokenizer.Next()
+ p.tok = p.tokenizer.Token()
+ switch p.tok.Type {
+ case ErrorToken:
+ return p.tokenizer.Error()
+ case SelfClosingTagToken:
+ p.hasSelfClosingToken = true
+ p.tok.Type = StartTagToken
+ }
+ return nil
+}
+
+// Section 10.2.4.
+func (p *parser) acknowledgeSelfClosingTag() {
+ p.hasSelfClosingToken = false
+}
+
+// An insertion mode (section 10.2.3.1) is the state transition function from
+// a particular state in the HTML5 parser's state machine. It updates the
+// parser's fields depending on parser.token (where ErrorToken means EOF). In
+// addition to returning the next insertionMode state, it also returns whether
+// the token was consumed.
+type insertionMode func(*parser) (insertionMode, bool)
+
+// useTheRulesFor runs the delegate insertionMode over p, returning the actual
+// insertionMode unless the delegate caused a state transition.
+// Section 10.2.3.1, "using the rules for".
+func useTheRulesFor(p *parser, actual, delegate insertionMode) (insertionMode, bool) {
+ im, consumed := delegate(p)
+ if im != delegate {
+ return im, consumed
+ }
+ return actual, consumed
+}
+
+// Section 10.2.5.4.
+func initialIM(p *parser) (insertionMode, bool) {
+ // TODO: check p.tok for DOCTYPE.
+ return beforeHTMLIM, false
+}
+
+// Section 10.2.5.5.
+func beforeHTMLIM(p *parser) (insertionMode, bool) {
+ var (
+ add bool
+ attr []Attribute
+ implied bool
+ )
+ switch p.tok.Type {
+ case ErrorToken:
+ implied = true
+ case TextToken:
+ // TODO: distinguish whitespace text from others.
+ implied = true
+ case StartTagToken:
+ if p.tok.Data == "html" {
+ add = true
+ attr = p.tok.Attr
+ } else {
+ implied = true
+ }
+ case EndTagToken:
+ switch p.tok.Data {
+ case "head", "body", "html", "br":
+ implied = true
+ default:
+ // Ignore the token.
+ }
+ }
+ if add || implied {
+ p.addElement("html", attr)
+ }
+ return beforeHeadIM, !implied
+}
+
+// Section 10.2.5.6.
+func beforeHeadIM(p *parser) (insertionMode, bool) {
+ var (
+ add bool
+ attr []Attribute
+ implied bool
+ )
+ switch p.tok.Type {
+ case ErrorToken:
+ implied = true
+ case TextToken:
+ // TODO: distinguish whitespace text from others.
+ implied = true
+ case StartTagToken:
+ switch p.tok.Data {
+ case "head":
+ add = true
+ attr = p.tok.Attr
+ case "html":
+ return useTheRulesFor(p, beforeHeadIM, inBodyIM)
+ default:
+ implied = true
+ }
+ case EndTagToken:
+ switch p.tok.Data {
+ case "head", "body", "html", "br":
+ implied = true
+ default:
+ // Ignore the token.
+ }
+ }
+ if add || implied {
+ p.addElement("head", attr)
+ }
+ return inHeadIM, !implied
+}
+
+// Section 10.2.5.7.
+func inHeadIM(p *parser) (insertionMode, bool) {
+ var (
+ pop bool
+ implied bool
+ )
+ switch p.tok.Type {
+ case ErrorToken, TextToken:
+ implied = true
+ case StartTagToken:
+ switch p.tok.Data {
+ case "meta":
+ // TODO.
+ case "script":
+ // TODO.
+ default:
+ implied = true
+ }
+ case EndTagToken:
+ if p.tok.Data == "head" {
+ pop = true
+ }
+ // TODO.
+ }
+ if pop || implied {
+ n := p.pop()
+ if n.Data != "head" {
+ panic("html: bad parser state")
+ }
+ return afterHeadIM, !implied
+ }
+ return inHeadIM, !implied
+}
+
+// Section 10.2.5.9.
+func afterHeadIM(p *parser) (insertionMode, bool) {
+ var (
+ add bool
+ attr []Attribute
+ framesetOK bool
+ implied bool
+ )
+ switch p.tok.Type {
+ case ErrorToken, TextToken:
+ implied = true
+ framesetOK = true
+ case StartTagToken:
+ switch p.tok.Data {
+ case "html":
+ // TODO.
+ case "body":
+ add = true
+ attr = p.tok.Attr
+ framesetOK = false
+ case "frameset":
+ // TODO.
+ case "base", "basefont", "bgsound", "link", "meta", "noframes", "script", "style", "title":
+ // TODO.
+ case "head":
+ // TODO.
+ default:
+ implied = true
+ framesetOK = true
+ }
+ case EndTagToken:
+ // TODO.
+ }
+ if add || implied {
+ p.addElement("body", attr)
+ p.framesetOK = framesetOK
+ }
+ return inBodyIM, !implied
+}
+
+// Section 10.2.5.10.
+func inBodyIM(p *parser) (insertionMode, bool) {
+ var endP bool
+ switch p.tok.Type {
+ case TextToken:
+ p.addText(p.tok.Data)
+ p.framesetOK = false
+ case StartTagToken:
+ switch p.tok.Data {
+ case "address", "article", "aside", "blockquote", "center", "details", "dir", "div", "dl", "fieldset", "figcaption", "figure", "footer", "header", "hgroup", "menu", "nav", "ol", "p", "section", "summary", "ul":
+ // TODO: Do the proper "does the stack of open elements has a p element in button scope" algorithm in section 10.2.3.2.
+ n := p.top()
+ if n.Type == ElementNode && n.Data == "p" {
+ endP = true
+ } else {
+ p.addElement(p.tok.Data, p.tok.Attr)
+ }
+ case "h1", "h2", "h3", "h4", "h5", "h6":
+ // TODO: auto-insert </p> if necessary.
+ switch n := p.top(); n.Data {
+ case "h1", "h2", "h3", "h4", "h5", "h6":
+ p.pop()
+ }
+ p.addElement(p.tok.Data, p.tok.Attr)
+ case "b", "big", "code", "em", "font", "i", "s", "small", "strike", "strong", "tt", "u":
+ p.reconstructActiveFormattingElements()
+ p.addFormattingElement(p.tok.Data, p.tok.Attr)
+ case "area", "br", "embed", "img", "input", "keygen", "wbr":
+ p.reconstructActiveFormattingElements()
+ p.addElement(p.tok.Data, p.tok.Attr)
+ p.pop()
+ p.acknowledgeSelfClosingTag()
+ p.framesetOK = false
+ case "table":
+ // TODO: auto-insert </p> if necessary, depending on quirks mode.
+ p.addElement(p.tok.Data, p.tok.Attr)
+ p.framesetOK = false
+ return inTableIM, true
+ case "hr":
+ // TODO: auto-insert </p> if necessary.
+ p.addElement(p.tok.Data, p.tok.Attr)
+ p.pop()
+ p.acknowledgeSelfClosingTag()
+ p.framesetOK = false
+ default:
+ // TODO.
+ }
+ case EndTagToken:
+ switch p.tok.Data {
+ case "body":
+ // TODO: autoclose the stack of open elements.
+ return afterBodyIM, true
+ case "a", "b", "big", "code", "em", "font", "i", "nobr", "s", "small", "strike", "strong", "tt", "u":
+ // TODO: implement the "adoption agency" algorithm:
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#adoptionAgency
+ if p.tok.Data == p.top().Data {
+ p.pop()
+ }
+ default:
+ // TODO.
+ }
+ }
+ if endP {
+ // TODO: do the proper algorithm.
+ n := p.pop()
+ if n.Type != ElementNode || n.Data != "p" {
+ panic("unreachable")
+ }
+ }
+ return inBodyIM, !endP
+}
+
+// Section 10.2.5.12.
+func inTableIM(p *parser) (insertionMode, bool) {
+ var (
+ add bool
+ data string
+ attr []Attribute
+ consumed bool
+ )
+ switch p.tok.Type {
+ case ErrorToken:
+ // Stop parsing.
+ return nil, true
+ case TextToken:
+ // TODO.
+ case StartTagToken:
+ switch p.tok.Data {
+ case "tbody", "tfoot", "thead":
+ add = true
+ data = p.tok.Data
+ attr = p.tok.Attr
+ consumed = true
+ case "td", "th", "tr":
+ add = true
+ data = "tbody"
+ default:
+ // TODO.
+ }
+ case EndTagToken:
+ switch p.tok.Data {
+ case "table":
+ if p.popUntil(tableScopeStopTags, "table") {
+ // TODO: "reset the insertion mode appropriately" as per 10.2.3.1.
+ return inBodyIM, false
+ }
+ // Ignore the token.
+ return inTableIM, true
+ case "body", "caption", "col", "colgroup", "html", "tbody", "td", "tfoot", "th", "thead", "tr":
+ // Ignore the token.
+ return inTableIM, true
+ }
+ }
+ if add {
+ // TODO: clear the stack back to a table context.
+ p.addElement(data, attr)
+ return inTableBodyIM, consumed
+ }
+ // TODO: return useTheRulesFor(inTableIM, inBodyIM, p) unless etc. etc. foster parenting.
+ return inTableIM, true
+}
+
+// Section 10.2.5.16.
+func inTableBodyIM(p *parser) (insertionMode, bool) {
+ var (
+ add bool
+ data string
+ attr []Attribute
+ consumed bool
+ )
+ switch p.tok.Type {
+ case ErrorToken:
+ // TODO.
+ case TextToken:
+ // TODO.
+ case StartTagToken:
+ switch p.tok.Data {
+ case "tr":
+ add = true
+ data = p.tok.Data
+ attr = p.tok.Attr
+ consumed = true
+ case "td", "th":
+ add = true
+ data = "tr"
+ consumed = false
+ default:
+ // TODO.
+ }
+ case EndTagToken:
+ switch p.tok.Data {
+ case "table":
+ if p.popUntil(tableScopeStopTags, "tbody", "thead", "tfoot") {
+ return inTableIM, false
+ }
+ // Ignore the token.
+ return inTableBodyIM, true
+ case "body", "caption", "col", "colgroup", "html", "td", "th", "tr":
+ // Ignore the token.
+ return inTableBodyIM, true
+ }
+ }
+ if add {
+ // TODO: clear the stack back to a table body context.
+ p.addElement(data, attr)
+ return inRowIM, consumed
+ }
+ return useTheRulesFor(p, inTableBodyIM, inTableIM)
+}
+
+// Section 10.2.5.17.
+func inRowIM(p *parser) (insertionMode, bool) {
+ switch p.tok.Type {
+ case ErrorToken:
+ // TODO.
+ case TextToken:
+ // TODO.
+ case StartTagToken:
+ switch p.tok.Data {
+ case "td", "th":
+ // TODO: clear the stack back to a table row context.
+ p.addElement(p.tok.Data, p.tok.Attr)
+ // TODO: insert a marker at the end of the list of active formatting elements.
+ return inCellIM, true
+ default:
+ // TODO.
+ }
+ case EndTagToken:
+ switch p.tok.Data {
+ case "tr":
+ // TODO.
+ case "table":
+ if p.popUntil(tableScopeStopTags, "tr") {
+ return inTableBodyIM, false
+ }
+ // Ignore the token.
+ return inRowIM, true
+ case "tbody", "tfoot", "thead":
+ // TODO.
+ case "body", "caption", "col", "colgroup", "html", "td", "th":
+ // Ignore the token.
+ return inRowIM, true
+ default:
+ // TODO.
+ }
+ }
+ return useTheRulesFor(p, inRowIM, inTableIM)
+}
+
+// Section 10.2.5.18.
+func inCellIM(p *parser) (insertionMode, bool) {
+ var (
+ closeTheCellAndReprocess bool
+ )
+ switch p.tok.Type {
+ case StartTagToken:
+ switch p.tok.Data {
+ case "caption", "col", "colgroup", "tbody", "td", "tfoot", "th", "thead", "tr":
+ // TODO: check for "td" or "th" in table scope.
+ closeTheCellAndReprocess = true
+ }
+ case EndTagToken:
+ switch p.tok.Data {
+ case "td", "th":
+ // TODO.
+ case "body", "caption", "col", "colgroup", "html":
+ // TODO.
+ case "table", "tbody", "tfoot", "thead", "tr":
+ // TODO: check for matching element in table scope.
+ closeTheCellAndReprocess = true
+ }
+ }
+ if closeTheCellAndReprocess {
+ if p.popUntil(tableScopeStopTags, "td") || p.popUntil(tableScopeStopTags, "th") {
+ // TODO: clear the list of active formatting elements up to the last marker.
+ return inRowIM, false
+ }
+ }
+ return useTheRulesFor(p, inCellIM, inBodyIM)
+}
+
+// Section 10.2.5.22.
+func afterBodyIM(p *parser) (insertionMode, bool) {
+ switch p.tok.Type {
+ case ErrorToken:
+ // TODO.
+ case TextToken:
+ // TODO.
+ case StartTagToken:
+ // TODO.
+ case EndTagToken:
+ switch p.tok.Data {
+ case "html":
+ // TODO: autoclose the stack of open elements.
+ return afterAfterBodyIM, true
+ default:
+ // TODO.
+ }
+ }
+ return afterBodyIM, true
+}
+
+// Section 10.2.5.25.
+func afterAfterBodyIM(p *parser) (insertionMode, bool) {
+ switch p.tok.Type {
+ case ErrorToken:
+ // Stop parsing.
+ return nil, true
+ case TextToken:
+ // TODO.
+ case StartTagToken:
+ if p.tok.Data == "html" {
+ return useTheRulesFor(p, afterAfterBodyIM, inBodyIM)
+ }
+ }
+ return inBodyIM, false
+}
+
+// Parse returns the parse tree for the HTML from the given Reader.
+// The input is assumed to be UTF-8 encoded.
+func Parse(r io.Reader) (*Node, os.Error) {
+ p := &parser{
+ tokenizer: NewTokenizer(r),
+ doc: &Node{
+ Type: DocumentNode,
+ },
+ scripting: true,
+ framesetOK: true,
+ }
+ // Iterate until EOF. Any other error will cause an early return.
+ im, consumed := initialIM, true
+ for {
+ if consumed {
+ if err := p.read(); err != nil {
+ if err == os.EOF {
+ break
+ }
+ return nil, err
+ }
+ }
+ im, consumed = im(p)
+ }
+ // Loop until the final token (the ErrorToken signifying EOF) is consumed.
+ for {
+ if im, consumed = im(p); consumed {
+ break
+ }
+ }
+ return p.doc, nil
+}
diff --git a/src/pkg/html/parse_test.go b/src/pkg/html/parse_test.go
new file mode 100644
index 000000000..d153533b5
--- /dev/null
+++ b/src/pkg/html/parse_test.go
@@ -0,0 +1,158 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package html
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "strings"
+ "testing"
+)
+
+type devNull struct{}
+
+func (devNull) Write(p []byte) (int, os.Error) {
+ return len(p), nil
+}
+
+func pipeErr(err os.Error) io.Reader {
+ pr, pw := io.Pipe()
+ pw.CloseWithError(err)
+ return pr
+}
+
+func readDat(filename string, c chan io.Reader) {
+ f, err := os.Open("testdata/webkit/"+filename, os.O_RDONLY, 0600)
+ if err != nil {
+ c <- pipeErr(err)
+ return
+ }
+ defer f.Close()
+
+ // Loop through the lines of the file. Each line beginning with "#" denotes
+ // a new section, which is returned as a separate io.Reader.
+ r := bufio.NewReader(f)
+ var pw *io.PipeWriter
+ for {
+ line, err := r.ReadSlice('\n')
+ if err != nil {
+ if pw != nil {
+ pw.CloseWithError(err)
+ pw = nil
+ } else {
+ c <- pipeErr(err)
+ }
+ return
+ }
+ if len(line) == 0 {
+ continue
+ }
+ if line[0] == '#' {
+ if pw != nil {
+ pw.Close()
+ }
+ var pr *io.PipeReader
+ pr, pw = io.Pipe()
+ c <- pr
+ continue
+ }
+ if line[0] != '|' {
+ // Strip the trailing '\n'.
+ line = line[:len(line)-1]
+ }
+ if pw != nil {
+ if _, err := pw.Write(line); err != nil {
+ pw.CloseWithError(err)
+ pw = nil
+ }
+ }
+ }
+}
+
+func dumpLevel(w io.Writer, n *Node, level int) os.Error {
+ io.WriteString(w, "| ")
+ for i := 0; i < level; i++ {
+ io.WriteString(w, " ")
+ }
+ switch n.Type {
+ case ErrorNode:
+ return os.NewError("unexpected ErrorNode")
+ case DocumentNode:
+ return os.NewError("unexpected DocumentNode")
+ case ElementNode:
+ fmt.Fprintf(w, "<%s>", EscapeString(n.Data))
+ case TextNode:
+ fmt.Fprintf(w, "%q", EscapeString(n.Data))
+ case CommentNode:
+ return os.NewError("COMMENT")
+ default:
+ return os.NewError("unknown node type")
+ }
+ io.WriteString(w, "\n")
+ for _, c := range n.Child {
+ if err := dumpLevel(w, c, level+1); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func dump(n *Node) (string, os.Error) {
+ if n == nil || len(n.Child) == 0 {
+ return "", nil
+ }
+ b := bytes.NewBuffer(nil)
+ for _, child := range n.Child {
+ if err := dumpLevel(b, child, 0); err != nil {
+ return "", err
+ }
+ }
+ return b.String(), nil
+}
+
+func TestParser(t *testing.T) {
+ // TODO(nigeltao): Process all the .dat files, not just the first one.
+ filenames := []string{
+ "tests1.dat",
+ }
+ for _, filename := range filenames {
+ rc := make(chan io.Reader)
+ go readDat(filename, rc)
+ // TODO(nigeltao): Process all test cases, not just a subset.
+ for i := 0; i < 22; i++ {
+ // Parse the #data section.
+ b, err := ioutil.ReadAll(<-rc)
+ if err != nil {
+ t.Fatal(err)
+ }
+ text := string(b)
+ doc, err := Parse(strings.NewReader(text))
+ if err != nil {
+ t.Fatal(err)
+ }
+ actual, err := dump(doc)
+ if err != nil {
+ t.Fatal(err)
+ }
+ // Skip the #error section.
+ if _, err := io.Copy(devNull{}, <-rc); err != nil {
+ t.Fatal(err)
+ }
+ // Compare the parsed tree to the #document section.
+ b, err = ioutil.ReadAll(<-rc)
+ if err != nil {
+ t.Fatal(err)
+ }
+ expected := string(b)
+ if actual != expected {
+ t.Errorf("%s test #%d %q, actual vs expected:\n----\n%s----\n%s----", filename, i, text, actual, expected)
+ }
+ }
+ }
+}
diff --git a/src/pkg/html/token.go b/src/pkg/html/token.go
new file mode 100644
index 000000000..d63883850
--- /dev/null
+++ b/src/pkg/html/token.go
@@ -0,0 +1,398 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package html
+
+import (
+ "bytes"
+ "io"
+ "os"
+ "strconv"
+)
+
+// A TokenType is the type of a Token.
+type TokenType int
+
+const (
+ // ErrorToken means that an error occurred during tokenization.
+ ErrorToken TokenType = iota
+ // TextToken means a text node.
+ TextToken
+ // A StartTagToken looks like <a>.
+ StartTagToken
+ // An EndTagToken looks like </a>.
+ EndTagToken
+ // A SelfClosingTagToken tag looks like <br/>.
+ SelfClosingTagToken
+)
+
+// String returns a string representation of the TokenType.
+func (t TokenType) String() string {
+ switch t {
+ case ErrorToken:
+ return "Error"
+ case TextToken:
+ return "Text"
+ case StartTagToken:
+ return "StartTag"
+ case EndTagToken:
+ return "EndTag"
+ case SelfClosingTagToken:
+ return "SelfClosingTag"
+ }
+ return "Invalid(" + strconv.Itoa(int(t)) + ")"
+}
+
+// An Attribute is an attribute key-value pair. Key is alphabetic (and hence
+// does not contain escapable characters like '&', '<' or '>'), and Val is
+// unescaped (it looks like "a<b" rather than "a&lt;b").
+type Attribute struct {
+ Key, Val string
+}
+
+// A Token consists of a TokenType and some Data (tag name for start and end
+// tags, content for text). A tag Token may also contain a slice of Attributes.
+// Data is unescaped for both tag and text Tokens (it looks like "a<b" rather
+// than "a&lt;b").
+type Token struct {
+ Type TokenType
+ Data string
+ Attr []Attribute
+}
+
+// tagString returns a string representation of a tag Token's Data and Attr.
+func (t Token) tagString() string {
+ if len(t.Attr) == 0 {
+ return t.Data
+ }
+ buf := bytes.NewBuffer(nil)
+ buf.WriteString(t.Data)
+ for _, a := range t.Attr {
+ buf.WriteByte(' ')
+ buf.WriteString(a.Key)
+ buf.WriteString(`="`)
+ escape(buf, a.Val)
+ buf.WriteByte('"')
+ }
+ return buf.String()
+}
+
+// String returns a string representation of the Token.
+func (t Token) String() string {
+ switch t.Type {
+ case ErrorToken:
+ return ""
+ case TextToken:
+ return EscapeString(t.Data)
+ case StartTagToken:
+ return "<" + t.tagString() + ">"
+ case EndTagToken:
+ return "</" + t.tagString() + ">"
+ case SelfClosingTagToken:
+ return "<" + t.tagString() + "/>"
+ }
+ return "Invalid(" + strconv.Itoa(int(t.Type)) + ")"
+}
+
+// A Tokenizer returns a stream of HTML Tokens.
+type Tokenizer struct {
+ // r is the source of the HTML text.
+ r io.Reader
+ // tt is the TokenType of the most recently read token. If tt == Error
+ // then err is the error associated with trying to read that token.
+ tt TokenType
+ err os.Error
+ // buf[p0:p1] holds the raw data of the most recent token.
+ // buf[p1:] is buffered input that will yield future tokens.
+ p0, p1 int
+ buf []byte
+}
+
+// Error returns the error associated with the most recent ErrorToken token.
+// This is typically os.EOF, meaning the end of tokenization.
+func (z *Tokenizer) Error() os.Error {
+ if z.tt != ErrorToken {
+ return nil
+ }
+ return z.err
+}
+
+// Raw returns the unmodified text of the current token. Calling Next, Token,
+// Text, TagName or TagAttr may change the contents of the returned slice.
+func (z *Tokenizer) Raw() []byte {
+ return z.buf[z.p0:z.p1]
+}
+
+// readByte returns the next byte from the input stream, doing a buffered read
+// from z.r into z.buf if necessary. z.buf[z.p0:z.p1] remains a contiguous byte
+// slice that holds all the bytes read so far for the current token.
+func (z *Tokenizer) readByte() (byte, os.Error) {
+ if z.p1 >= len(z.buf) {
+ // Our buffer is exhausted and we have to read from z.r.
+ // We copy z.buf[z.p0:z.p1] to the beginning of z.buf. If the length
+ // z.p1 - z.p0 is more than half the capacity of z.buf, then we
+ // allocate a new buffer before the copy.
+ c := cap(z.buf)
+ d := z.p1 - z.p0
+ var buf1 []byte
+ if 2*d > c {
+ buf1 = make([]byte, d, 2*c)
+ } else {
+ buf1 = z.buf[0:d]
+ }
+ copy(buf1, z.buf[z.p0:z.p1])
+ z.p0, z.p1, z.buf = 0, d, buf1[0:d]
+ // Now that we have copied the live bytes to the start of the buffer,
+ // we read from z.r into the remainder.
+ n, err := z.r.Read(buf1[d:cap(buf1)])
+ if err != nil {
+ return 0, err
+ }
+ z.buf = buf1[0 : d+n]
+ }
+ x := z.buf[z.p1]
+ z.p1++
+ return x, nil
+}
+
+// readTo keeps reading bytes until x is found.
+func (z *Tokenizer) readTo(x uint8) os.Error {
+ for {
+ c, err := z.readByte()
+ if err != nil {
+ return err
+ }
+ switch c {
+ case x:
+ return nil
+ case '\\':
+ _, err = z.readByte()
+ if err != nil {
+ return err
+ }
+ }
+ }
+ panic("unreachable")
+}
+
+// nextTag returns the next TokenType starting from the tag open state.
+func (z *Tokenizer) nextTag() (tt TokenType, err os.Error) {
+ c, err := z.readByte()
+ if err != nil {
+ return ErrorToken, err
+ }
+ switch {
+ case c == '/':
+ tt = EndTagToken
+ // Lower-cased characters are more common in tag names, so we check for them first.
+ case 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z':
+ tt = StartTagToken
+ case c == '!':
+ return ErrorToken, os.NewError("html: TODO(nigeltao): implement comments")
+ case c == '?':
+ return ErrorToken, os.NewError("html: TODO(nigeltao): implement XML processing instructions")
+ default:
+ return ErrorToken, os.NewError("html: TODO(nigeltao): handle malformed tags")
+ }
+ for {
+ c, err := z.readByte()
+ if err != nil {
+ return TextToken, err
+ }
+ switch c {
+ case '"':
+ err = z.readTo('"')
+ if err != nil {
+ return TextToken, err
+ }
+ case '\'':
+ err = z.readTo('\'')
+ if err != nil {
+ return TextToken, err
+ }
+ case '>':
+ if z.buf[z.p1-2] == '/' && tt == StartTagToken {
+ return SelfClosingTagToken, nil
+ }
+ return tt, nil
+ }
+ }
+ panic("unreachable")
+}
+
+// Next scans the next token and returns its type.
+func (z *Tokenizer) Next() TokenType {
+ if z.err != nil {
+ z.tt = ErrorToken
+ return z.tt
+ }
+ z.p0 = z.p1
+ c, err := z.readByte()
+ if err != nil {
+ z.tt, z.err = ErrorToken, err
+ return z.tt
+ }
+ if c == '<' {
+ z.tt, z.err = z.nextTag()
+ return z.tt
+ }
+ for {
+ c, err := z.readByte()
+ if err != nil {
+ z.tt, z.err = ErrorToken, err
+ if err == os.EOF {
+ z.tt = TextToken
+ }
+ return z.tt
+ }
+ if c == '<' {
+ z.p1--
+ z.tt = TextToken
+ return z.tt
+ }
+ }
+ panic("unreachable")
+}
+
+// trim returns the largest j such that z.buf[i:j] contains only white space,
+// or only white space plus the final ">" or "/>" of the raw data.
+func (z *Tokenizer) trim(i int) int {
+ k := z.p1
+ for ; i < k; i++ {
+ switch z.buf[i] {
+ case ' ', '\n', '\t', '\f':
+ continue
+ case '>':
+ if i == k-1 {
+ return k
+ }
+ case '/':
+ if i == k-2 {
+ return k
+ }
+ }
+ return i
+ }
+ return k
+}
+
+// lower finds the largest alphabetic [0-9A-Za-z]* word at the start of z.buf[i:]
+// and returns that word lower-cased, as well as the trimmed cursor location
+// after that word.
+func (z *Tokenizer) lower(i int) ([]byte, int) {
+ i0 := i
+loop:
+ for ; i < z.p1; i++ {
+ c := z.buf[i]
+ switch {
+ case '0' <= c && c <= '9':
+ // No-op.
+ case 'A' <= c && c <= 'Z':
+ z.buf[i] = c + 'a' - 'A'
+ case 'a' <= c && c <= 'z':
+ // No-op.
+ default:
+ break loop
+ }
+ }
+ return z.buf[i0:i], z.trim(i)
+}
+
+// Text returns the raw data after unescaping.
+// The contents of the returned slice may change on the next call to Next.
+func (z *Tokenizer) Text() []byte {
+ s := unescape(z.Raw())
+ z.p0 = z.p1
+ return s
+}
+
+// TagName returns the lower-cased name of a tag token (the `img` out of
+// `<IMG SRC="foo">`), and whether the tag has attributes.
+// The contents of the returned slice may change on the next call to Next.
+func (z *Tokenizer) TagName() (name []byte, remaining bool) {
+ i := z.p0 + 1
+ if i >= z.p1 {
+ z.p0 = z.p1
+ return nil, false
+ }
+ if z.buf[i] == '/' {
+ i++
+ }
+ name, z.p0 = z.lower(i)
+ remaining = z.p0 != z.p1
+ return
+}
+
+// TagAttr returns the lower-cased key and unescaped value of the next unparsed
+// attribute for the current tag token, and whether there are more attributes.
+// The contents of the returned slices may change on the next call to Next.
+func (z *Tokenizer) TagAttr() (key, val []byte, remaining bool) {
+ key, i := z.lower(z.p0)
+ // Get past the "=\"".
+ if i == z.p1 || z.buf[i] != '=' {
+ return
+ }
+ i = z.trim(i + 1)
+ if i == z.p1 || z.buf[i] != '"' {
+ return
+ }
+ i = z.trim(i + 1)
+ // Copy and unescape everything up to the closing '"'.
+ dst, src := i, i
+loop:
+ for src < z.p1 {
+ c := z.buf[src]
+ switch c {
+ case '"':
+ src++
+ break loop
+ case '&':
+ dst, src = unescapeEntity(z.buf, dst, src)
+ case '\\':
+ if src == z.p1 {
+ z.buf[dst] = '\\'
+ dst++
+ } else {
+ z.buf[dst] = z.buf[src+1]
+ dst, src = dst+1, src+2
+ }
+ default:
+ z.buf[dst] = c
+ dst, src = dst+1, src+1
+ }
+ }
+ val, z.p0 = z.buf[i:dst], z.trim(src)
+ remaining = z.p0 != z.p1
+ return
+}
+
+// Token returns the next Token. The result's Data and Attr values remain valid
+// after subsequent Next calls.
+func (z *Tokenizer) Token() Token {
+ t := Token{Type: z.tt}
+ switch z.tt {
+ case TextToken:
+ t.Data = string(z.Text())
+ case StartTagToken, EndTagToken, SelfClosingTagToken:
+ var attr []Attribute
+ name, remaining := z.TagName()
+ for remaining {
+ var key, val []byte
+ key, val, remaining = z.TagAttr()
+ attr = append(attr, Attribute{string(key), string(val)})
+ }
+ t.Data = string(name)
+ t.Attr = attr
+ }
+ return t
+}
+
+// NewTokenizer returns a new HTML Tokenizer for the given Reader.
+// The input is assumed to be UTF-8 encoded.
+func NewTokenizer(r io.Reader) *Tokenizer {
+ return &Tokenizer{
+ r: r,
+ buf: make([]byte, 0, 4096),
+ }
+}
diff --git a/src/pkg/html/token_test.go b/src/pkg/html/token_test.go
new file mode 100644
index 000000000..e07999ca5
--- /dev/null
+++ b/src/pkg/html/token_test.go
@@ -0,0 +1,231 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package html
+
+import (
+ "bytes"
+ "os"
+ "testing"
+)
+
+type tokenTest struct {
+ // A short description of the test case.
+ desc string
+ // The HTML to parse.
+ html string
+ // The string representations of the expected tokens.
+ tokens []string
+}
+
+var tokenTests = []tokenTest{
+ // A single text node. The tokenizer should not break text nodes on whitespace,
+ // nor should it normalize whitespace within a text node.
+ {
+ "text",
+ "foo bar",
+ []string{
+ "foo bar",
+ },
+ },
+ // An entity.
+ {
+ "entity",
+ "one &lt; two",
+ []string{
+ "one &lt; two",
+ },
+ },
+ // A start, self-closing and end tag. The tokenizer does not care if the start
+ // and end tokens don't match; that is the job of the parser.
+ {
+ "tags",
+ "<a>b<c/>d</e>",
+ []string{
+ "<a>",
+ "b",
+ "<c/>",
+ "d",
+ "</e>",
+ },
+ },
+ // An attribute with a backslash.
+ {
+ "backslash",
+ `<p id="a\"b">`,
+ []string{
+ `<p id="a&quot;b">`,
+ },
+ },
+ // Entities, tag name and attribute key lower-casing, and whitespace
+ // normalization within a tag.
+ {
+ "tricky",
+ "<p \t\n iD=\"a&quot;B\" foo=\"bar\"><EM>te&lt;&amp;;xt</em></p>",
+ []string{
+ `<p id="a&quot;B" foo="bar">`,
+ "<em>",
+ "te&lt;&amp;;xt",
+ "</em>",
+ "</p>",
+ },
+ },
+ // A non-existant entity. Tokenizing and converting back to a string should
+ // escape the "&" to become "&amp;".
+ {
+ "noSuchEntity",
+ `<a b="c&noSuchEntity;d">&lt;&alsoDoesntExist;&`,
+ []string{
+ `<a b="c&amp;noSuchEntity;d">`,
+ "&lt;&amp;alsoDoesntExist;&amp;",
+ },
+ },
+}
+
+func TestTokenizer(t *testing.T) {
+loop:
+ for _, tt := range tokenTests {
+ z := NewTokenizer(bytes.NewBuffer([]byte(tt.html)))
+ for i, s := range tt.tokens {
+ if z.Next() == ErrorToken {
+ t.Errorf("%s token %d: want %q got error %v", tt.desc, i, s, z.Error())
+ continue loop
+ }
+ actual := z.Token().String()
+ if s != actual {
+ t.Errorf("%s token %d: want %q got %q", tt.desc, i, s, actual)
+ continue loop
+ }
+ }
+ z.Next()
+ if z.Error() != os.EOF {
+ t.Errorf("%s: want EOF got %q", tt.desc, z.Token().String())
+ }
+ }
+}
+
+type unescapeTest struct {
+ // A short description of the test case.
+ desc string
+ // The HTML text.
+ html string
+ // The unescaped text.
+ unescaped string
+}
+
+var unescapeTests = []unescapeTest{
+ // Handle no entities.
+ {
+ "copy",
+ "A\ttext\nstring",
+ "A\ttext\nstring",
+ },
+ // Handle simple named entities.
+ {
+ "simple",
+ "&amp; &gt; &lt;",
+ "& > <",
+ },
+ // Handle hitting the end of the string.
+ {
+ "stringEnd",
+ "&amp &amp",
+ "& &",
+ },
+ // Handle entities with two codepoints.
+ {
+ "multiCodepoint",
+ "text &gesl; blah",
+ "text \u22db\ufe00 blah",
+ },
+ // Handle decimal numeric entities.
+ {
+ "decimalEntity",
+ "Delta = &#916; ",
+ "Delta = Δ ",
+ },
+ // Handle hexadecimal numeric entities.
+ {
+ "hexadecimalEntity",
+ "Lambda = &#x3bb; = &#X3Bb ",
+ "Lambda = λ = λ ",
+ },
+ // Handle numeric early termination.
+ {
+ "numericEnds",
+ "&# &#x &#128;43 &copy = &#169f = &#xa9",
+ "&# &#x €43 © = ©f = ©",
+ },
+ // Handle numeric ISO-8859-1 entity replacements.
+ {
+ "numericReplacements",
+ "Footnote&#x87;",
+ "Footnote‡",
+ },
+}
+
+func TestUnescape(t *testing.T) {
+ for _, tt := range unescapeTests {
+ unescaped := UnescapeString(tt.html)
+ if unescaped != tt.unescaped {
+ t.Errorf("TestUnescape %s: want %q, got %q", tt.desc, tt.unescaped, unescaped)
+ }
+ }
+}
+
+func TestUnescapeEscape(t *testing.T) {
+ ss := []string{
+ ``,
+ `abc def`,
+ `a & b`,
+ `a&amp;b`,
+ `a &amp b`,
+ `&quot;`,
+ `"`,
+ `"<&>"`,
+ `&quot;&lt;&amp;&gt;&quot;`,
+ `3&5==1 && 0<1, "0&lt;1", a+acute=&aacute;`,
+ }
+ for _, s := range ss {
+ if s != UnescapeString(EscapeString(s)) {
+ t.Errorf("s != UnescapeString(EscapeString(s)), s=%q", s)
+ }
+ }
+}
+
+func TestBufAPI(t *testing.T) {
+ s := "0<a>1</a>2<b>3<a>4<a>5</a>6</b>7</a>8<a/>9"
+ z := NewTokenizer(bytes.NewBuffer([]byte(s)))
+ result := bytes.NewBuffer(nil)
+ depth := 0
+loop:
+ for {
+ tt := z.Next()
+ switch tt {
+ case ErrorToken:
+ if z.Error() != os.EOF {
+ t.Error(z.Error())
+ }
+ break loop
+ case TextToken:
+ if depth > 0 {
+ result.Write(z.Text())
+ }
+ case StartTagToken, EndTagToken:
+ tn, _ := z.TagName()
+ if len(tn) == 1 && tn[0] == 'a' {
+ if tt == StartTagToken {
+ depth++
+ } else {
+ depth--
+ }
+ }
+ }
+ }
+ u := "14567"
+ v := string(result.Bytes())
+ if u != v {
+ t.Errorf("TestBufAPI: want %q got %q", u, v)
+ }
+}
diff --git a/src/pkg/http/Makefile b/src/pkg/http/Makefile
index 235ff0279..7e4f80c28 100644
--- a/src/pkg/http/Makefile
+++ b/src/pkg/http/Makefile
@@ -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 ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=http
GOFILES=\
diff --git a/src/pkg/http/client.go b/src/pkg/http/client.go
index 54487dac2..29678ee32 100644
--- a/src/pkg/http/client.go
+++ b/src/pkg/http/client.go
@@ -8,11 +8,14 @@ package http
import (
"bufio"
+ "bytes"
+ "crypto/tls"
"encoding/base64"
"fmt"
"io"
"net"
"os"
+ "strconv"
"strings"
)
@@ -21,7 +24,7 @@ import (
func hasPort(s string) bool { return strings.LastIndex(s, ":") > strings.LastIndex(s, "]") }
// Used in Send to implement io.ReadCloser by bundling together the
-// io.BufReader through which we read the response, and the underlying
+// bufio.Reader through which we read the response, and the underlying
// network connection.
type readClose struct {
io.Reader
@@ -34,15 +37,15 @@ type readClose struct {
// send() method is nonpublic because, when we refactor the code for persistent
// connections, it may no longer make sense to have a method with this signature.
func send(req *Request) (resp *Response, err os.Error) {
- if req.URL.Scheme != "http" {
+ if req.URL.Scheme != "http" && req.URL.Scheme != "https" {
return nil, &badStringError{"unsupported protocol scheme", req.URL.Scheme}
}
addr := req.URL.Host
if !hasPort(addr) {
- addr += ":http"
+ addr += ":" + req.URL.Scheme
}
- info := req.URL.Userinfo
+ info := req.URL.RawUserinfo
if len(info) > 0 {
enc := base64.URLEncoding
encoded := make([]byte, enc.EncodedLen(len(info)))
@@ -52,9 +55,25 @@ func send(req *Request) (resp *Response, err os.Error) {
}
req.Header["Authorization"] = "Basic " + string(encoded)
}
- conn, err := net.Dial("tcp", "", addr)
- if err != nil {
- return nil, err
+
+ var conn io.ReadWriteCloser
+ if req.URL.Scheme == "http" {
+ conn, err = net.Dial("tcp", "", addr)
+ if err != nil {
+ return nil, err
+ }
+ } else { // https
+ conn, err = tls.Dial("tcp", "", addr, nil)
+ if err != nil {
+ return nil, err
+ }
+ h := req.URL.Host
+ if hasPort(h) {
+ h = h[0:strings.LastIndex(h, ":")]
+ }
+ if err := conn.(*tls.Conn).VerifyHostname(h); err != nil {
+ return nil, err
+ }
}
err = req.Write(conn)
@@ -111,6 +130,7 @@ func Get(url string) (r *Response, finalURL string, err os.Error) {
if req.URL, err = ParseURL(url); err != nil {
break
}
+ url = req.URL.String()
if r, err = send(&req); err != nil {
break
}
@@ -153,6 +173,41 @@ func Post(url string, bodyType string, body io.Reader) (r *Response, err os.Erro
return send(&req)
}
+// PostForm issues a POST to the specified URL,
+// with data's keys and values urlencoded as the request body.
+//
+// Caller should close r.Body when done reading it.
+func PostForm(url string, data map[string]string) (r *Response, err os.Error) {
+ var req Request
+ req.Method = "POST"
+ req.ProtoMajor = 1
+ req.ProtoMinor = 1
+ req.Close = true
+ body := urlencode(data)
+ req.Body = nopCloser{body}
+ req.Header = map[string]string{
+ "Content-Type": "application/x-www-form-urlencoded",
+ "Content-Length": strconv.Itoa(body.Len()),
+ }
+ req.ContentLength = int64(body.Len())
+
+ req.URL, err = ParseURL(url)
+ if err != nil {
+ return nil, err
+ }
+
+ return send(&req)
+}
+
+// TODO: remove this function when PostForm takes a multimap.
+func urlencode(data map[string]string) (b *bytes.Buffer) {
+ m := make(map[string][]string, len(data))
+ for k, v := range data {
+ m[k] = []string{v}
+ }
+ return bytes.NewBuffer([]byte(EncodeQuery(m)))
+}
+
// Head issues a HEAD to the specified URL.
func Head(url string) (r *Response, err os.Error) {
var req Request
@@ -160,6 +215,7 @@ func Head(url string) (r *Response, err os.Error) {
if req.URL, err = ParseURL(url); err != nil {
return
}
+ url = req.URL.String()
if r, err = send(&req); err != nil {
return
}
diff --git a/src/pkg/http/fs.go b/src/pkg/http/fs.go
index 40bb3d138..143a839a8 100644
--- a/src/pkg/http/fs.go
+++ b/src/pkg/http/fs.go
@@ -12,7 +12,9 @@ import (
"mime"
"os"
"path"
+ "strconv"
"strings"
+ "time"
"utf8"
)
@@ -25,7 +27,7 @@ func isText(b []byte) bool {
// decoding error
return false
}
- if 0x80 <= rune && rune <= 0x9F {
+ if 0x7F <= rune && rune <= 0x9F {
return false
}
if rune < ' ' {
@@ -42,8 +44,8 @@ func isText(b []byte) bool {
return true
}
-func dirList(c *Conn, f *os.File) {
- fmt.Fprintf(c, "<pre>\n")
+func dirList(w ResponseWriter, f *os.File) {
+ fmt.Fprintf(w, "<pre>\n")
for {
dirs, err := f.Readdir(100)
if err != nil || len(dirs) == 0 {
@@ -55,26 +57,25 @@ func dirList(c *Conn, f *os.File) {
name += "/"
}
// TODO htmlescape
- fmt.Fprintf(c, "<a href=\"%s\">%s</a>\n", name, name)
+ fmt.Fprintf(w, "<a href=\"%s\">%s</a>\n", name, name)
}
}
- fmt.Fprintf(c, "</pre>\n")
+ fmt.Fprintf(w, "</pre>\n")
}
-
-func serveFileInternal(c *Conn, r *Request, name string, redirect bool) {
+func serveFile(w ResponseWriter, r *Request, name string, redirect bool) {
const indexPage = "/index.html"
// redirect .../index.html to .../
if strings.HasSuffix(r.URL.Path, indexPage) {
- Redirect(c, r.URL.Path[0:len(r.URL.Path)-len(indexPage)+1], StatusMovedPermanently)
+ Redirect(w, r, r.URL.Path[0:len(r.URL.Path)-len(indexPage)+1], StatusMovedPermanently)
return
}
f, err := os.Open(name, os.O_RDONLY, 0)
if err != nil {
// TODO expose actual error?
- NotFound(c, r)
+ NotFound(w, r)
return
}
defer f.Close()
@@ -82,7 +83,7 @@ func serveFileInternal(c *Conn, r *Request, name string, redirect bool) {
d, err1 := f.Stat()
if err1 != nil {
// TODO expose actual error?
- NotFound(c, r)
+ NotFound(w, r)
return
}
@@ -92,17 +93,23 @@ func serveFileInternal(c *Conn, r *Request, name string, redirect bool) {
url := r.URL.Path
if d.IsDirectory() {
if url[len(url)-1] != '/' {
- Redirect(c, url+"/", StatusMovedPermanently)
+ Redirect(w, r, url+"/", StatusMovedPermanently)
return
}
} else {
if url[len(url)-1] == '/' {
- Redirect(c, url[0:len(url)-1], StatusMovedPermanently)
+ Redirect(w, r, url[0:len(url)-1], StatusMovedPermanently)
return
}
}
}
+ if t, _ := time.Parse(TimeFormat, r.Header["If-Modified-Since"]); t != nil && d.Mtime_ns/1e9 <= t.Seconds() {
+ w.WriteHeader(StatusNotModified)
+ return
+ }
+ w.SetHeader("Last-Modified", time.SecondsToUTC(d.Mtime_ns/1e9).Format(TimeFormat))
+
// use contents of index.html for directory, if present
if d.IsDirectory() {
index := name + indexPage
@@ -119,33 +126,60 @@ func serveFileInternal(c *Conn, r *Request, name string, redirect bool) {
}
if d.IsDirectory() {
- dirList(c, f)
+ dirList(w, f)
return
}
// serve file
+ size := d.Size
+ code := StatusOK
+
// use extension to find content type.
ext := path.Ext(name)
if ctype := mime.TypeByExtension(ext); ctype != "" {
- c.SetHeader("Content-Type", ctype)
+ w.SetHeader("Content-Type", ctype)
} else {
// read first chunk to decide between utf-8 text and binary
var buf [1024]byte
- n, _ := io.ReadFull(f, buf[0:])
- b := buf[0:n]
+ n, _ := io.ReadFull(f, buf[:])
+ b := buf[:n]
if isText(b) {
- c.SetHeader("Content-Type", "text-plain; charset=utf-8")
+ w.SetHeader("Content-Type", "text-plain; charset=utf-8")
} else {
- c.SetHeader("Content-Type", "application/octet-stream") // generic binary
+ w.SetHeader("Content-Type", "application/octet-stream") // generic binary
+ }
+ f.Seek(0, 0) // rewind to output whole file
+ }
+
+ // handle Content-Range header.
+ // TODO(adg): handle multiple ranges
+ ranges, err := parseRange(r.Header["Range"], size)
+ if err != nil || len(ranges) > 1 {
+ Error(w, err.String(), StatusRequestedRangeNotSatisfiable)
+ return
+ }
+ if len(ranges) == 1 {
+ ra := ranges[0]
+ if _, err := f.Seek(ra.start, 0); err != nil {
+ Error(w, err.String(), StatusRequestedRangeNotSatisfiable)
+ return
}
- c.Write(b)
+ size = ra.length
+ code = StatusPartialContent
+ w.SetHeader("Content-Range", fmt.Sprintf("%d-%d/%d", ra.start, ra.start+ra.length, d.Size))
}
- io.Copy(c, f)
+
+ w.SetHeader("Accept-Ranges", "bytes")
+ w.SetHeader("Content-Length", strconv.Itoa64(size))
+
+ w.WriteHeader(code)
+
+ io.Copyn(w, f, size)
}
// ServeFile replies to the request with the contents of the named file or directory.
-func ServeFile(c *Conn, r *Request, name string) {
- serveFileInternal(c, r, name, false)
+func ServeFile(w ResponseWriter, r *Request, name string) {
+ serveFile(w, r, name, false)
}
type fileHandler struct {
@@ -159,12 +193,71 @@ type fileHandler struct {
// looking up the file name in the file system.
func FileServer(root, prefix string) Handler { return &fileHandler{root, prefix} }
-func (f *fileHandler) ServeHTTP(c *Conn, r *Request) {
+func (f *fileHandler) ServeHTTP(w ResponseWriter, r *Request) {
path := r.URL.Path
if !strings.HasPrefix(path, f.prefix) {
- NotFound(c, r)
+ NotFound(w, r)
return
}
path = path[len(f.prefix):]
- serveFileInternal(c, r, f.root+"/"+path, true)
+ serveFile(w, r, f.root+"/"+path, true)
+}
+
+// httpRange specifies the byte range to be sent to the client.
+type httpRange struct {
+ start, length int64
+}
+
+// parseRange parses a Range header string as per RFC 2616.
+func parseRange(s string, size int64) ([]httpRange, os.Error) {
+ if s == "" {
+ return nil, nil // header not present
+ }
+ const b = "bytes="
+ if !strings.HasPrefix(s, b) {
+ return nil, os.NewError("invalid range")
+ }
+ var ranges []httpRange
+ for _, ra := range strings.Split(s[len(b):], ",", -1) {
+ i := strings.Index(ra, "-")
+ if i < 0 {
+ return nil, os.NewError("invalid range")
+ }
+ start, end := ra[:i], ra[i+1:]
+ var r httpRange
+ if start == "" {
+ // If no start is specified, end specifies the
+ // range start relative to the end of the file.
+ i, err := strconv.Atoi64(end)
+ if err != nil {
+ return nil, os.NewError("invalid range")
+ }
+ if i > size {
+ i = size
+ }
+ r.start = size - i
+ r.length = size - r.start
+ } else {
+ i, err := strconv.Atoi64(start)
+ if err != nil || i > size || i < 0 {
+ return nil, os.NewError("invalid range")
+ }
+ r.start = i
+ if end == "" {
+ // If no end is specified, range extends to end of the file.
+ r.length = size - r.start
+ } else {
+ i, err := strconv.Atoi64(end)
+ if err != nil || r.start > i {
+ return nil, os.NewError("invalid range")
+ }
+ if i >= size {
+ i = size - 1
+ }
+ r.length = i - r.start + 1
+ }
+ }
+ ranges = append(ranges, r)
+ }
+ return ranges, nil
}
diff --git a/src/pkg/http/fs_test.go b/src/pkg/http/fs_test.go
new file mode 100644
index 000000000..0f7135692
--- /dev/null
+++ b/src/pkg/http/fs_test.go
@@ -0,0 +1,172 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package http
+
+import (
+ "fmt"
+ "io/ioutil"
+ "net"
+ "os"
+ "sync"
+ "testing"
+)
+
+var ParseRangeTests = []struct {
+ s string
+ length int64
+ r []httpRange
+}{
+ {"", 0, nil},
+ {"foo", 0, nil},
+ {"bytes=", 0, nil},
+ {"bytes=5-4", 10, nil},
+ {"bytes=0-2,5-4", 10, nil},
+ {"bytes=0-9", 10, []httpRange{{0, 10}}},
+ {"bytes=0-", 10, []httpRange{{0, 10}}},
+ {"bytes=5-", 10, []httpRange{{5, 5}}},
+ {"bytes=0-20", 10, []httpRange{{0, 10}}},
+ {"bytes=15-,0-5", 10, nil},
+ {"bytes=-5", 10, []httpRange{{5, 5}}},
+ {"bytes=-15", 10, []httpRange{{0, 10}}},
+ {"bytes=0-499", 10000, []httpRange{{0, 500}}},
+ {"bytes=500-999", 10000, []httpRange{{500, 500}}},
+ {"bytes=-500", 10000, []httpRange{{9500, 500}}},
+ {"bytes=9500-", 10000, []httpRange{{9500, 500}}},
+ {"bytes=0-0,-1", 10000, []httpRange{{0, 1}, {9999, 1}}},
+ {"bytes=500-600,601-999", 10000, []httpRange{{500, 101}, {601, 399}}},
+ {"bytes=500-700,601-999", 10000, []httpRange{{500, 201}, {601, 399}}},
+}
+
+func TestParseRange(t *testing.T) {
+ for _, test := range ParseRangeTests {
+ r := test.r
+ ranges, err := parseRange(test.s, test.length)
+ if err != nil && r != nil {
+ t.Errorf("parseRange(%q) returned error %q", test.s, err)
+ }
+ if len(ranges) != len(r) {
+ t.Errorf("len(parseRange(%q)) = %d, want %d", test.s, len(ranges), len(r))
+ continue
+ }
+ for i := range r {
+ if ranges[i].start != r[i].start {
+ t.Errorf("parseRange(%q)[%d].start = %d, want %d", test.s, i, ranges[i].start, r[i].start)
+ }
+ if ranges[i].length != r[i].length {
+ t.Errorf("parseRange(%q)[%d].length = %d, want %d", test.s, i, ranges[i].length, r[i].length)
+ }
+ }
+ }
+}
+
+const (
+ testFile = "testdata/file"
+ testFileLength = 11
+)
+
+var (
+ serverOnce sync.Once
+ serverAddr string
+)
+
+func startServer(t *testing.T) {
+ serverOnce.Do(func() {
+ HandleFunc("/ServeFile", func(w ResponseWriter, r *Request) {
+ ServeFile(w, r, "testdata/file")
+ })
+ l, err := net.Listen("tcp", "127.0.0.1:0")
+ if err != nil {
+ t.Fatal("listen:", err)
+ }
+ serverAddr = l.Addr().String()
+ go Serve(l, nil)
+ })
+}
+
+var ServeFileRangeTests = []struct {
+ start, end int
+ r string
+ code int
+}{
+ {0, testFileLength, "", StatusOK},
+ {0, 5, "0-4", StatusPartialContent},
+ {2, testFileLength, "2-", StatusPartialContent},
+ {testFileLength - 5, testFileLength, "-5", StatusPartialContent},
+ {3, 8, "3-7", StatusPartialContent},
+ {0, 0, "20-", StatusRequestedRangeNotSatisfiable},
+}
+
+func TestServeFile(t *testing.T) {
+ startServer(t)
+ var err os.Error
+
+ file, err := ioutil.ReadFile(testFile)
+ if err != nil {
+ t.Fatal("reading file:", err)
+ }
+
+ // set up the Request (re-used for all tests)
+ var req Request
+ req.Header = make(map[string]string)
+ if req.URL, err = ParseURL("http://" + serverAddr + "/ServeFile"); err != nil {
+ t.Fatal("ParseURL:", err)
+ }
+ req.Method = "GET"
+
+ // straight GET
+ _, body := getBody(t, req)
+ if !equal(body, file) {
+ t.Fatalf("body mismatch: got %q, want %q", body, file)
+ }
+
+ // Range tests
+ for _, rt := range ServeFileRangeTests {
+ req.Header["Range"] = "bytes=" + rt.r
+ if rt.r == "" {
+ req.Header["Range"] = ""
+ }
+ r, body := getBody(t, req)
+ if r.StatusCode != rt.code {
+ t.Errorf("range=%q: StatusCode=%d, want %d", rt.r, r.StatusCode, rt.code)
+ }
+ if rt.code == StatusRequestedRangeNotSatisfiable {
+ continue
+ }
+ h := fmt.Sprintf("%d-%d/%d", rt.start, rt.end, testFileLength)
+ if rt.r == "" {
+ h = ""
+ }
+ if r.Header["Content-Range"] != h {
+ t.Errorf("header mismatch: range=%q: got %q, want %q", rt.r, r.Header["Content-Range"], h)
+ }
+ if !equal(body, file[rt.start:rt.end]) {
+ t.Errorf("body mismatch: range=%q: got %q, want %q", rt.r, body, file[rt.start:rt.end])
+ }
+ }
+}
+
+func getBody(t *testing.T, req Request) (*Response, []byte) {
+ r, err := send(&req)
+ if err != nil {
+ t.Fatal(req.URL.String(), "send:", err)
+ }
+ b, err := ioutil.ReadAll(r.Body)
+ if err != nil {
+ t.Fatal("reading Body:", err)
+ }
+ return r, b
+}
+
+func equal(a, b []byte) bool {
+ if len(a) != len(b) {
+ return false
+ }
+ for i := range a {
+ if a[i] != b[i] {
+ return false
+ }
+ }
+ return true
+}
diff --git a/src/pkg/http/lex_test.go b/src/pkg/http/lex_test.go
index 043430cb7..5386f7534 100644
--- a/src/pkg/http/lex_test.go
+++ b/src/pkg/http/lex_test.go
@@ -15,29 +15,29 @@ type lexTest struct {
}
var lexTests = []lexTest{
- lexTest{
+ {
Raw: `"abc"def,:ghi`,
Parsed: 13,
Result: []string{"abcdef", "ghi"},
},
// My understanding of the RFC is that escape sequences outside of
// quotes are not interpreted?
- lexTest{
+ {
Raw: `"\t"\t"\t"`,
Parsed: 10,
Result: []string{"\t", "t\t"},
},
- lexTest{
+ {
Raw: `"\yab"\r\n`,
Parsed: 10,
Result: []string{"?ab", "r", "n"},
},
- lexTest{
+ {
Raw: "ab\f",
Parsed: 3,
Result: []string{"ab?"},
},
- lexTest{
+ {
Raw: "\"ab \" c,de f, gh, ij\n\t\r",
Parsed: 23,
Result: []string{"ab ", "c", "de", "f", "gh", "ij"},
diff --git a/src/pkg/http/pprof/Makefile b/src/pkg/http/pprof/Makefile
index e0315112f..5858a0efa 100644
--- a/src/pkg/http/pprof/Makefile
+++ b/src/pkg/http/pprof/Makefile
@@ -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 ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=http/pprof
GOFILES=\
diff --git a/src/pkg/http/pprof/pprof.go b/src/pkg/http/pprof/pprof.go
index 38d91afbf..f7db9aab9 100644
--- a/src/pkg/http/pprof/pprof.go
+++ b/src/pkg/http/pprof/pprof.go
@@ -40,28 +40,28 @@ func init() {
// Cmdline responds with the running program's
// command line, with arguments separated by NUL bytes.
// The package initialization registers it as /debug/pprof/cmdline.
-func Cmdline(c *http.Conn, r *http.Request) {
- c.SetHeader("content-type", "text/plain; charset=utf-8")
- fmt.Fprintf(c, strings.Join(os.Args, "\x00"))
+func Cmdline(w http.ResponseWriter, r *http.Request) {
+ w.SetHeader("content-type", "text/plain; charset=utf-8")
+ fmt.Fprintf(w, strings.Join(os.Args, "\x00"))
}
// Heap responds with the pprof-formatted heap profile.
// The package initialization registers it as /debug/pprof/heap.
-func Heap(c *http.Conn, r *http.Request) {
- c.SetHeader("content-type", "text/plain; charset=utf-8")
- pprof.WriteHeapProfile(c)
+func Heap(w http.ResponseWriter, r *http.Request) {
+ w.SetHeader("content-type", "text/plain; charset=utf-8")
+ pprof.WriteHeapProfile(w)
}
// Symbol looks up the program counters listed in the request,
// responding with a table mapping program counters to function names.
// The package initialization registers it as /debug/pprof/symbol.
-func Symbol(c *http.Conn, r *http.Request) {
- c.SetHeader("content-type", "text/plain; charset=utf-8")
+func Symbol(w http.ResponseWriter, r *http.Request) {
+ w.SetHeader("content-type", "text/plain; charset=utf-8")
// We don't know how many symbols we have, but we
// do have symbol information. Pprof only cares whether
// this number is 0 (no symbols available) or > 0.
- fmt.Fprintf(c, "num_symbols: 1\n")
+ fmt.Fprintf(w, "num_symbols: 1\n")
var b *bufio.Reader
if r.Method == "POST" {
@@ -71,15 +71,15 @@ func Symbol(c *http.Conn, r *http.Request) {
}
for {
- w, err := b.ReadSlice('+')
+ word, err := b.ReadSlice('+')
if err == nil {
- w = w[0 : len(w)-1] // trim +
+ word = word[0 : len(word)-1] // trim +
}
- pc, _ := strconv.Btoui64(string(w), 0)
+ pc, _ := strconv.Btoui64(string(word), 0)
if pc != 0 {
f := runtime.FuncForPC(uintptr(pc))
if f != nil {
- fmt.Fprintf(c, "%#x %s\n", pc, f.Name())
+ fmt.Fprintf(w, "%#x %s\n", pc, f.Name())
}
}
diff --git a/src/pkg/http/readrequest_test.go b/src/pkg/http/readrequest_test.go
index 7654dbfc7..067e17dda 100644
--- a/src/pkg/http/readrequest_test.go
+++ b/src/pkg/http/readrequest_test.go
@@ -20,7 +20,7 @@ type reqTest struct {
var reqTests = []reqTest{
// Baseline test; All Request fields included for template use
- reqTest{
+ {
"GET http://www.techcrunch.com/ HTTP/1.1\r\n" +
"Host: www.techcrunch.com\r\n" +
"User-Agent: Fake\r\n" +
@@ -37,15 +37,15 @@ var reqTests = []reqTest{
Method: "GET",
RawURL: "http://www.techcrunch.com/",
URL: &URL{
- Raw: "http://www.techcrunch.com/",
- Scheme: "http",
- RawPath: "/",
- Authority: "www.techcrunch.com",
- Userinfo: "",
- Host: "www.techcrunch.com",
- Path: "/",
- RawQuery: "",
- Fragment: "",
+ Raw: "http://www.techcrunch.com/",
+ Scheme: "http",
+ RawPath: "/",
+ RawAuthority: "www.techcrunch.com",
+ RawUserinfo: "",
+ Host: "www.techcrunch.com",
+ Path: "/",
+ RawQuery: "",
+ Fragment: "",
},
Proto: "HTTP/1.1",
ProtoMajor: 1,
diff --git a/src/pkg/http/request.go b/src/pkg/http/request.go
index 8a72d6cfa..b88689988 100644
--- a/src/pkg/http/request.go
+++ b/src/pkg/http/request.go
@@ -16,6 +16,8 @@ import (
"fmt"
"io"
"io/ioutil"
+ "mime"
+ "mime/multipart"
"os"
"strconv"
"strings"
@@ -40,6 +42,8 @@ var (
ErrNotSupported = &ProtocolError{"feature not supported"}
ErrUnexpectedTrailer = &ProtocolError{"trailer header without chunked transfer encoding"}
ErrMissingContentLength = &ProtocolError{"missing ContentLength in HEAD response"}
+ ErrNotMultipart = &ProtocolError{"request Content-Type isn't multipart/form-data"}
+ ErrMissingBoundary = &ProtocolError{"no multipart boundary param Content-Type"}
)
type badStringError struct {
@@ -67,7 +71,7 @@ type Request struct {
ProtoMajor int // 1
ProtoMinor int // 0
- // A header mapping request lines to their values.
+ // A header maps request lines to their values.
// If the header says
//
// accept-encoding: gzip, deflate
@@ -139,6 +143,24 @@ func (r *Request) ProtoAtLeast(major, minor int) bool {
r.ProtoMajor == major && r.ProtoMinor >= minor
}
+// MultipartReader returns a MIME multipart reader if this is a
+// multipart/form-data POST request, else returns nil and an error.
+func (r *Request) MultipartReader() (multipart.Reader, os.Error) {
+ v, ok := r.Header["Content-Type"]
+ if !ok {
+ return nil, ErrNotMultipart
+ }
+ d, params := mime.ParseMediaType(v)
+ if d != "multipart/form-data" {
+ return nil, ErrNotMultipart
+ }
+ boundary, ok := params["boundary"]
+ if !ok {
+ return nil, ErrMissingBoundary
+ }
+ return multipart.NewReader(r.Body, boundary), nil
+}
+
// Return value if nonempty, def otherwise.
func valueOrDefault(value, def string) string {
if value != "" {
@@ -169,7 +191,7 @@ func (req *Request) Write(w io.Writer) os.Error {
uri := req.RawURL
if uri == "" {
- uri = valueOrDefault(urlEscape(req.URL.Path, false), "/")
+ uri = valueOrDefault(urlEscape(req.URL.Path, encodePath), "/")
if req.URL.RawQuery != "" {
uri += "?" + req.URL.RawQuery
}
@@ -227,6 +249,8 @@ func readLineBytes(b *bufio.Reader) (p []byte, err os.Error) {
// 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
}
@@ -275,7 +299,7 @@ func readKeyValue(b *bufio.Reader) (key, value string, err os.Error) {
}
key = string(line[0:i])
- if strings.Index(key, " ") >= 0 {
+ if strings.Contains(key, " ") {
// Key field has space - no good.
goto Malformed
}
@@ -360,29 +384,30 @@ func parseHTTPVersion(vers string) (int, int, bool) {
return major, minor, true
}
-var cmap = make(map[string]string)
-
// CanonicalHeaderKey returns the canonical format of the
// HTTP header key s. The canonicalization converts the first
// letter and any letter following a hyphen to upper case;
// the rest are converted to lowercase. For example, the
// canonical key for "accept-encoding" is "Accept-Encoding".
func CanonicalHeaderKey(s string) string {
- if t, ok := cmap[s]; ok {
- return t
- }
-
// canonicalize: first letter upper case
// and upper case after each dash.
// (Host, User-Agent, If-Modified-Since).
// HTTP headers are ASCII only, so no Unicode issues.
- a := []byte(s)
+ var a []byte
upper := true
- for i, v := range a {
+ for i := 0; i < len(s); i++ {
+ v := s[i]
if upper && 'a' <= v && v <= 'z' {
+ if a == nil {
+ a = []byte(s)
+ }
a[i] = v + 'A' - 'a'
}
if !upper && 'A' <= v && v <= 'Z' {
+ if a == nil {
+ a = []byte(s)
+ }
a[i] = v + 'a' - 'A'
}
upper = false
@@ -390,9 +415,10 @@ func CanonicalHeaderKey(s string) string {
upper = true
}
}
- t := string(a)
- cmap[s] = t
- return t
+ if a != nil {
+ return string(a)
+ }
+ return s
}
type chunkedReader struct {
@@ -566,9 +592,22 @@ func ReadRequest(b *bufio.Reader) (req *Request, err os.Error) {
return req, nil
}
+// ParseQuery parses the URL-encoded query string and returns
+// a map listing the values specified for each key.
+// ParseQuery always returns a non-nil map containing all the
+// valid query parameters found; err describes the first decoding error
+// encountered, if any.
func ParseQuery(query string) (m map[string][]string, err os.Error) {
m = make(map[string][]string)
+ err = parseQuery(m, query)
+ return
+}
+
+func parseQuery(m map[string][]string, query string) (err os.Error) {
for _, kv := range strings.Split(query, "&", -1) {
+ if len(kv) == 0 {
+ continue
+ }
kvPair := strings.Split(kv, "=", 2)
var key, value string
@@ -579,14 +618,13 @@ func ParseQuery(query string) (m map[string][]string, err os.Error) {
}
if e != nil {
err = e
+ continue
}
-
vec := vector.StringVector(m[key])
vec.Push(value)
m[key] = vec
}
-
- return
+ return err
}
// ParseForm parses the request body as a form for POST requests, or the raw query for GET requests.
@@ -596,32 +634,34 @@ func (r *Request) ParseForm() (err os.Error) {
return
}
- var query string
- switch r.Method {
- case "GET":
- query = r.URL.RawQuery
- case "POST":
+ r.Form = make(map[string][]string)
+ if r.URL != nil {
+ err = parseQuery(r.Form, r.URL.RawQuery)
+ }
+ if r.Method == "POST" {
if r.Body == nil {
- r.Form = make(map[string][]string)
return os.ErrorString("missing form body")
}
ct := r.Header["Content-Type"]
switch strings.Split(ct, ";", 2)[0] {
case "text/plain", "application/x-www-form-urlencoded", "":
- var b []byte
- if b, err = ioutil.ReadAll(r.Body); err != nil {
- r.Form = make(map[string][]string)
- return err
+ b, e := ioutil.ReadAll(r.Body)
+ if e != nil {
+ if err == nil {
+ err = e
+ }
+ break
+ }
+ e = parseQuery(r.Form, string(b))
+ if err == nil {
+ err = e
}
- query = string(b)
// TODO(dsymonds): Handle multipart/form-data
default:
- r.Form = make(map[string][]string)
return &badStringError{"unknown Content-Type", ct}
}
}
- r.Form, err = ParseQuery(query)
- return
+ return err
}
// FormValue returns the first value for the named component of the query.
@@ -640,3 +680,14 @@ func (r *Request) expectsContinue() bool {
expectation, ok := r.Header["Expect"]
return ok && strings.ToLower(expectation) == "100-continue"
}
+
+func (r *Request) wantsHttp10KeepAlive() bool {
+ if r.ProtoMajor != 1 || r.ProtoMinor != 0 {
+ return false
+ }
+ value, exists := r.Header["Connection"]
+ if !exists {
+ return false
+ }
+ return strings.Contains(strings.ToLower(value), "keep-alive")
+}
diff --git a/src/pkg/http/request_test.go b/src/pkg/http/request_test.go
index 98d5342bb..d25e5e5e7 100644
--- a/src/pkg/http/request_test.go
+++ b/src/pkg/http/request_test.go
@@ -6,6 +6,9 @@ package http
import (
"bytes"
+ "reflect"
+ "regexp"
+ "strings"
"testing"
)
@@ -17,15 +20,15 @@ type parseTest struct {
}
var parseTests = []parseTest{
- parseTest{
+ {
query: "a=1&b=2",
out: stringMultimap{"a": []string{"1"}, "b": []string{"2"}},
},
- parseTest{
+ {
query: "a=1&a=2&a=banana",
out: stringMultimap{"a": []string{"1", "2", "banana"}},
},
- parseTest{
+ {
query: "ascii=%3Ckey%3A+0x90%3E",
out: stringMultimap{"ascii": []string{"<key: 0x90>"}},
},
@@ -68,6 +71,22 @@ func TestQuery(t *testing.T) {
}
}
+func TestPostQuery(t *testing.T) {
+ req := &Request{Method: "POST"}
+ req.URL, _ = ParseURL("http://www.google.com/search?q=foo&q=bar&both=x")
+ req.Header = map[string]string{"Content-Type": "application/x-www-form-urlencoded; boo!"}
+ req.Body = nopCloser{strings.NewReader("z=post&both=y")}
+ if q := req.FormValue("q"); q != "foo" {
+ t.Errorf(`req.FormValue("q") = %q, want "foo"`, q)
+ }
+ if z := req.FormValue("z"); z != "post" {
+ t.Errorf(`req.FormValue("z") = %q, want "post"`, z)
+ }
+ if both := req.Form["both"]; !reflect.DeepEqual(both, []string{"x", "y"}) {
+ t.Errorf(`req.FormValue("both") = %q, want ["x", "y"]`, both)
+ }
+}
+
type stringMap map[string]string
type parseContentTypeTest struct {
contentType stringMap
@@ -75,10 +94,10 @@ type parseContentTypeTest struct {
}
var parseContentTypeTests = []parseContentTypeTest{
- parseContentTypeTest{contentType: stringMap{"Content-Type": "text/plain"}},
- parseContentTypeTest{contentType: stringMap{"Content-Type": ""}},
- parseContentTypeTest{contentType: stringMap{"Content-Type": "text/plain; boundary="}},
- parseContentTypeTest{
+ {contentType: stringMap{"Content-Type": "text/plain"}},
+ {contentType: stringMap{"Content-Type": ""}},
+ {contentType: stringMap{"Content-Type": "text/plain; boundary="}},
+ {
contentType: stringMap{"Content-Type": "application/unknown"},
error: true,
},
@@ -101,17 +120,36 @@ func TestPostContentTypeParsing(t *testing.T) {
}
}
+func TestMultipartReader(t *testing.T) {
+ req := &Request{
+ Method: "POST",
+ Header: stringMap{"Content-Type": `multipart/form-data; boundary="foo123"`},
+ Body: nopCloser{new(bytes.Buffer)},
+ }
+ multipart, err := req.MultipartReader()
+ if multipart == nil {
+ t.Errorf("expected multipart; error: %v", err)
+ }
+
+ req.Header = stringMap{"Content-Type": "text/plain"}
+ multipart, err = req.MultipartReader()
+ if multipart != nil {
+ t.Errorf("unexpected multipart for text/plain")
+ }
+}
+
func TestRedirect(t *testing.T) {
const (
- start = "http://codesearch.google.com/"
- end = "http://www.google.com/codesearch"
+ start = "http://google.com/"
+ endRe = "^http://www\\.google\\.[a-z.]+/$"
)
+ var end = regexp.MustCompile(endRe)
r, url, err := Get(start)
if err != nil {
t.Fatal(err)
}
r.Body.Close()
- if r.StatusCode != 200 || url != end {
- t.Fatalf("Get(%s) got status %d at %s, want 200 at %s", start, r.StatusCode, url, end)
+ if r.StatusCode != 200 || !end.MatchString(url) {
+ t.Fatalf("Get(%s) got status %d at %q, want 200 matching %q", start, r.StatusCode, url, endRe)
}
}
diff --git a/src/pkg/http/requestwrite_test.go b/src/pkg/http/requestwrite_test.go
index 469df69d7..3ceabe4ee 100644
--- a/src/pkg/http/requestwrite_test.go
+++ b/src/pkg/http/requestwrite_test.go
@@ -16,20 +16,20 @@ type reqWriteTest struct {
var reqWriteTests = []reqWriteTest{
// HTTP/1.1 => chunked coding; no body; no trailer
- reqWriteTest{
+ {
Request{
Method: "GET",
RawURL: "http://www.techcrunch.com/",
URL: &URL{
- Raw: "http://www.techcrunch.com/",
- Scheme: "http",
- RawPath: "http://www.techcrunch.com/",
- Authority: "www.techcrunch.com",
- Userinfo: "",
- Host: "www.techcrunch.com",
- Path: "/",
- RawQuery: "",
- Fragment: "",
+ Raw: "http://www.techcrunch.com/",
+ Scheme: "http",
+ RawPath: "http://www.techcrunch.com/",
+ RawAuthority: "www.techcrunch.com",
+ RawUserinfo: "",
+ Host: "www.techcrunch.com",
+ Path: "/",
+ RawQuery: "",
+ Fragment: "",
},
Proto: "HTTP/1.1",
ProtoMajor: 1,
@@ -61,7 +61,7 @@ var reqWriteTests = []reqWriteTest{
"Proxy-Connection: keep-alive\r\n\r\n",
},
// HTTP/1.1 => chunked coding; body; empty trailer
- reqWriteTest{
+ {
Request{
Method: "GET",
URL: &URL{
@@ -83,7 +83,7 @@ var reqWriteTests = []reqWriteTest{
"6\r\nabcdef\r\n0\r\n\r\n",
},
// HTTP/1.1 POST => chunked coding; body; empty trailer
- reqWriteTest{
+ {
Request{
Method: "POST",
URL: &URL{
@@ -107,7 +107,7 @@ var reqWriteTests = []reqWriteTest{
"6\r\nabcdef\r\n0\r\n\r\n",
},
// default to HTTP/1.1
- reqWriteTest{
+ {
Request{
Method: "GET",
RawURL: "/search",
diff --git a/src/pkg/http/response.go b/src/pkg/http/response.go
index 6a209c9f8..a24726110 100644
--- a/src/pkg/http/response.go
+++ b/src/pkg/http/response.go
@@ -86,10 +86,14 @@ func ReadResponse(r *bufio.Reader, requestMethod string) (resp *Response, err os
return nil, err
}
f := strings.Split(line, " ", 3)
- if len(f) < 3 {
+ if len(f) < 2 {
return nil, &badStringError{"malformed HTTP response", line}
}
- resp.Status = f[1] + " " + f[2]
+ reasonPhrase := ""
+ if len(f) > 2 {
+ reasonPhrase = f[2]
+ }
+ resp.Status = f[1] + " " + reasonPhrase
resp.StatusCode, err = strconv.Atoi(f[1])
if err != nil {
return nil, &badStringError{"malformed HTTP status code", f[1]}
diff --git a/src/pkg/http/response_test.go b/src/pkg/http/response_test.go
index 889b770be..89a8c3b44 100644
--- a/src/pkg/http/response_test.go
+++ b/src/pkg/http/response_test.go
@@ -21,7 +21,7 @@ type respTest struct {
var respTests = []respTest{
// Unchunked response without Content-Length.
- respTest{
+ {
"HTTP/1.0 200 OK\r\n" +
"Connection: close\r\n" +
"\r\n" +
@@ -45,7 +45,7 @@ var respTests = []respTest{
},
// Unchunked response with Content-Length.
- respTest{
+ {
"HTTP/1.0 200 OK\r\n" +
"Content-Length: 10\r\n" +
"Connection: close\r\n" +
@@ -71,7 +71,7 @@ var respTests = []respTest{
},
// Chunked response without Content-Length.
- respTest{
+ {
"HTTP/1.0 200 OK\r\n" +
"Transfer-Encoding: chunked\r\n" +
"\r\n" +
@@ -97,7 +97,7 @@ var respTests = []respTest{
},
// Chunked response with Content-Length.
- respTest{
+ {
"HTTP/1.0 200 OK\r\n" +
"Transfer-Encoding: chunked\r\n" +
"Content-Length: 10\r\n" +
@@ -122,6 +122,44 @@ var respTests = []respTest{
"Body here\n",
},
+
+ // Status line without a Reason-Phrase, but trailing space.
+ // (permitted by RFC 2616)
+ {
+ "HTTP/1.0 303 \r\n\r\n",
+ Response{
+ Status: "303 ",
+ StatusCode: 303,
+ Proto: "HTTP/1.0",
+ ProtoMajor: 1,
+ ProtoMinor: 0,
+ RequestMethod: "GET",
+ Header: map[string]string{},
+ Close: true,
+ ContentLength: -1,
+ },
+
+ "",
+ },
+
+ // Status line without a Reason-Phrase, and no trailing space.
+ // (not permitted by RFC 2616, but we'll accept it anyway)
+ {
+ "HTTP/1.0 303\r\n\r\n",
+ Response{
+ Status: "303 ",
+ StatusCode: 303,
+ Proto: "HTTP/1.0",
+ ProtoMajor: 1,
+ ProtoMinor: 0,
+ RequestMethod: "GET",
+ Header: map[string]string{},
+ Close: true,
+ ContentLength: -1,
+ },
+
+ "",
+ },
}
func TestReadResponse(t *testing.T) {
diff --git a/src/pkg/http/responsewrite_test.go b/src/pkg/http/responsewrite_test.go
index 768064303..9f10be562 100644
--- a/src/pkg/http/responsewrite_test.go
+++ b/src/pkg/http/responsewrite_test.go
@@ -16,7 +16,7 @@ type respWriteTest struct {
var respWriteTests = []respWriteTest{
// HTTP/1.0, identity coding; no trailer
- respWriteTest{
+ {
Response{
StatusCode: 503,
ProtoMajor: 1,
@@ -31,8 +31,23 @@ var respWriteTests = []respWriteTest{
"Content-Length: 6\r\n\r\n" +
"abcdef",
},
+ // Unchunked response without Content-Length.
+ {
+ Response{
+ StatusCode: 200,
+ ProtoMajor: 1,
+ ProtoMinor: 0,
+ RequestMethod: "GET",
+ Header: map[string]string{},
+ Body: nopCloser{bytes.NewBufferString("abcdef")},
+ ContentLength: -1,
+ },
+ "HTTP/1.0 200 OK\r\n" +
+ "\r\n" +
+ "abcdef",
+ },
// HTTP/1.1, chunked coding; empty trailer; close
- respWriteTest{
+ {
Response{
StatusCode: 200,
ProtoMajor: 1,
diff --git a/src/pkg/http/serve_test.go b/src/pkg/http/serve_test.go
new file mode 100644
index 000000000..43e1b93a5
--- /dev/null
+++ b/src/pkg/http/serve_test.go
@@ -0,0 +1,135 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// End-to-end serving tests
+
+package http
+
+import (
+ "bytes"
+ "os"
+ "net"
+ "testing"
+)
+
+type dummyAddr string
+type oneConnListener struct {
+ conn net.Conn
+}
+
+func (l *oneConnListener) Accept() (c net.Conn, err os.Error) {
+ c = l.conn
+ if c == nil {
+ err = os.EOF
+ return
+ }
+ err = nil
+ l.conn = nil
+ return
+}
+
+func (l *oneConnListener) Close() os.Error {
+ return nil
+}
+
+func (l *oneConnListener) Addr() net.Addr {
+ return dummyAddr("test-address")
+}
+
+func (a dummyAddr) Network() string {
+ return string(a)
+}
+
+func (a dummyAddr) String() string {
+ return string(a)
+}
+
+type testConn struct {
+ readBuf bytes.Buffer
+ writeBuf bytes.Buffer
+}
+
+func (c *testConn) Read(b []byte) (int, os.Error) {
+ return c.readBuf.Read(b)
+}
+
+func (c *testConn) Write(b []byte) (int, os.Error) {
+ return c.writeBuf.Write(b)
+}
+
+func (c *testConn) Close() os.Error {
+ return nil
+}
+
+func (c *testConn) LocalAddr() net.Addr {
+ return dummyAddr("local-addr")
+}
+
+func (c *testConn) RemoteAddr() net.Addr {
+ return dummyAddr("remote-addr")
+}
+
+func (c *testConn) SetTimeout(nsec int64) os.Error {
+ return nil
+}
+
+func (c *testConn) SetReadTimeout(nsec int64) os.Error {
+ return nil
+}
+
+func (c *testConn) SetWriteTimeout(nsec int64) os.Error {
+ return nil
+}
+
+func TestConsumingBodyOnNextConn(t *testing.T) {
+ conn := new(testConn)
+ for i := 0; i < 2; i++ {
+ conn.readBuf.Write([]byte(
+ "POST / HTTP/1.1\r\n" +
+ "Host: test\r\n" +
+ "Content-Length: 11\r\n" +
+ "\r\n" +
+ "foo=1&bar=1"))
+ }
+
+ reqNum := 0
+ ch := make(chan *Request)
+ servech := make(chan os.Error)
+ listener := &oneConnListener{conn}
+ handler := func(res ResponseWriter, req *Request) {
+ reqNum++
+ t.Logf("Got request #%d: %v", reqNum, req)
+ ch <- req
+ }
+
+ go func() {
+ servech <- Serve(listener, HandlerFunc(handler))
+ }()
+
+ var req *Request
+ t.Log("Waiting for first request.")
+ req = <-ch
+ if req == nil {
+ t.Fatal("Got nil first request.")
+ }
+ if req.Method != "POST" {
+ t.Errorf("For request #1's method, got %q; expected %q",
+ req.Method, "POST")
+ }
+
+ t.Log("Waiting for second request.")
+ req = <-ch
+ if req == nil {
+ t.Fatal("Got nil first request.")
+ }
+ if req.Method != "POST" {
+ t.Errorf("For request #2's method, got %q; expected %q",
+ req.Method, "POST")
+ }
+
+ t.Log("Waiting for EOF.")
+ if serveerr := <-servech; serveerr != os.EOF {
+ t.Errorf("Serve returned %q; expected EOF", serveerr)
+ }
+}
diff --git a/src/pkg/http/server.go b/src/pkg/http/server.go
index 81ce98229..b8783da28 100644
--- a/src/pkg/http/server.go
+++ b/src/pkg/http/server.go
@@ -13,6 +13,8 @@ package http
import (
"bufio"
+ "crypto/rand"
+ "crypto/tls"
"fmt"
"io"
"log"
@@ -21,6 +23,7 @@ import (
"path"
"strconv"
"strings"
+ "time"
)
// Errors introduced by the HTTP server.
@@ -34,42 +37,93 @@ var (
// registered to serve a particular path or subtree
// in the HTTP server.
//
-// ServeHTTP should write reply headers and data to the Conn
+// ServeHTTP should write reply headers and data to the ResponseWriter
// and then return. Returning signals that the request is finished
// and that the HTTP server can move on to the next request on
// the connection.
type Handler interface {
- ServeHTTP(*Conn, *Request)
+ ServeHTTP(ResponseWriter, *Request)
}
-// A Conn represents the server side of a single active HTTP connection.
-type Conn struct {
- RemoteAddr string // network address of remote side
- Req *Request // current HTTP request
+// A ResponseWriter interface is used by an HTTP handler to
+// construct an HTTP response.
+type ResponseWriter interface {
+ // RemoteAddr returns the address of the client that sent the current request
+ RemoteAddr() string
+
+ // UsingTLS returns true if the client is connected using TLS
+ UsingTLS() bool
+
+ // SetHeader sets a header line in the eventual response.
+ // For example, SetHeader("Content-Type", "text/html; charset=utf-8")
+ // will result in the header line
+ //
+ // Content-Type: text/html; charset=utf-8
+ //
+ // being sent. UTF-8 encoded HTML is the default setting for
+ // Content-Type in this library, so users need not make that
+ // particular call. Calls to SetHeader after WriteHeader (or Write)
+ // are ignored.
+ SetHeader(string, string)
+
+ // Write writes the data to the connection as part of an HTTP reply.
+ // If WriteHeader has not yet been called, Write calls WriteHeader(http.StatusOK)
+ // before writing the data.
+ Write([]byte) (int, os.Error)
+
+ // WriteHeader sends an HTTP response header with status code.
+ // If WriteHeader is not called explicitly, the first call to Write
+ // will trigger an implicit WriteHeader(http.StatusOK).
+ // Thus explicit calls to WriteHeader are mainly used to
+ // send error codes.
+ WriteHeader(int)
+
+ // Flush sends any buffered data to the client.
+ Flush()
+
+ // Hijack lets the caller take over the connection.
+ // After a call to Hijack(), the HTTP server library
+ // will not do anything else with the connection.
+ // It becomes the caller's responsibility to manage
+ // and close the connection.
+ Hijack() (io.ReadWriteCloser, *bufio.ReadWriter, os.Error)
+}
- rwc io.ReadWriteCloser // i/o connection
- buf *bufio.ReadWriter // buffered rwc
- handler Handler // request handler
- hijacked bool // connection has been hijacked by handler
+// A conn represents the server side of an HTTP connection.
+type conn struct {
+ remoteAddr string // network address of remote side
+ handler Handler // request handler
+ rwc io.ReadWriteCloser // i/o connection
+ buf *bufio.ReadWriter // buffered rwc
+ hijacked bool // connection has been hijacked by handler
+ usingTLS bool // a flag indicating connection over TLS
+}
- // state for the current reply
- closeAfterReply bool // close connection after this reply
- chunking bool // using chunked transfer encoding for reply body
- wroteHeader bool // reply header has been written
- wroteContinue bool // 100 Continue response was written
- header map[string]string // reply header parameters
- written int64 // number of bytes written in body
- status int // status code passed to WriteHeader
+// A response represents the server side of an HTTP response.
+type response struct {
+ conn *conn
+ req *Request // request for this response
+ chunking bool // using chunked transfer encoding for reply body
+ wroteHeader bool // reply header has been written
+ wroteContinue bool // 100 Continue response was written
+ header map[string]string // reply header parameters
+ written int64 // number of bytes written in body
+ status int // status code passed to WriteHeader
+
+ // close connection after this reply. set on request and
+ // updated after response from handler if there's a
+ // "Connection: keep-alive" response header and a
+ // Content-Length.
+ closeAfterReply bool
}
// Create new connection from rwc.
-func newConn(rwc net.Conn, handler Handler) (c *Conn, err os.Error) {
- c = new(Conn)
- if a := rwc.RemoteAddr(); a != nil {
- c.RemoteAddr = a.String()
- }
+func newConn(rwc net.Conn, handler Handler) (c *conn, err os.Error) {
+ c = new(conn)
+ c.remoteAddr = rwc.RemoteAddr().String()
c.handler = handler
c.rwc = rwc
+ _, c.usingTLS = rwc.(*tls.Conn)
br := bufio.NewReader(rwc)
bw := bufio.NewWriter(rwc)
c.buf = bufio.NewReadWriter(br, bw)
@@ -79,17 +133,15 @@ func newConn(rwc net.Conn, handler Handler) (c *Conn, err os.Error) {
// wrapper around io.ReaderCloser which on first read, sends an
// HTTP/1.1 100 Continue header
type expectContinueReader struct {
- conn *Conn
+ resp *response
readCloser io.ReadCloser
}
func (ecr *expectContinueReader) Read(p []byte) (n int, err os.Error) {
- if !ecr.conn.wroteContinue && !ecr.conn.hijacked {
- ecr.conn.wroteContinue = true
- if ecr.conn.Req.ProtoAtLeast(1, 1) {
- io.WriteString(ecr.conn.buf, "HTTP/1.1 100 Continue\r\n\r\n")
- ecr.conn.buf.Flush()
- }
+ if !ecr.resp.wroteContinue && !ecr.resp.conn.hijacked {
+ ecr.resp.wroteContinue = true
+ io.WriteString(ecr.resp.conn.buf, "HTTP/1.1 100 Continue\r\n\r\n")
+ ecr.resp.conn.buf.Flush()
}
return ecr.readCloser.Read(p)
}
@@ -98,88 +150,88 @@ func (ecr *expectContinueReader) Close() os.Error {
return ecr.readCloser.Close()
}
+// TimeFormat is the time format to use with
+// time.Parse and time.Time.Format when parsing
+// or generating times in HTTP headers.
+// It is like time.RFC1123 but hard codes GMT as the time zone.
+const TimeFormat = "Mon, 02 Jan 2006 15:04:05 GMT"
+
// Read next request from connection.
-func (c *Conn) readRequest() (req *Request, err os.Error) {
+func (c *conn) readRequest() (w *response, err os.Error) {
if c.hijacked {
return nil, ErrHijacked
}
+ var req *Request
if req, err = ReadRequest(c.buf.Reader); err != nil {
return nil, err
}
- // Reset per-request connection state.
- c.header = make(map[string]string)
- c.wroteHeader = false
- c.wroteContinue = false
- c.Req = req
+ w = new(response)
+ w.conn = c
+ w.req = req
+ w.header = make(map[string]string)
// Expect 100 Continue support
- if req.expectsContinue() {
+ if req.expectsContinue() && req.ProtoAtLeast(1, 1) {
// Wrap the Body reader with one that replies on the connection
- req.Body = &expectContinueReader{readCloser: req.Body, conn: c}
+ req.Body = &expectContinueReader{readCloser: req.Body, resp: w}
}
// Default output is HTML encoded in UTF-8.
- c.SetHeader("Content-Type", "text/html; charset=utf-8")
+ w.SetHeader("Content-Type", "text/html; charset=utf-8")
+ w.SetHeader("Date", time.UTC().Format(TimeFormat))
if req.ProtoAtLeast(1, 1) {
// HTTP/1.1 or greater: use chunked transfer encoding
// to avoid closing the connection at EOF.
- c.chunking = true
- c.SetHeader("Transfer-Encoding", "chunked")
+ w.chunking = true
+ w.SetHeader("Transfer-Encoding", "chunked")
} else {
// HTTP version < 1.1: cannot do chunked transfer
// encoding, so signal EOF by closing connection.
- // Could avoid closing the connection if there is
- // a Content-Length: header in the response,
- // but everyone who expects persistent connections
- // does HTTP/1.1 now.
- c.closeAfterReply = true
- c.chunking = false
+ // Will be overridden if the HTTP handler ends up
+ // writing a Content-Length and the client requested
+ // "Connection: keep-alive"
+ w.closeAfterReply = true
}
- return req, nil
+ return w, nil
}
-// SetHeader sets a header line in the eventual reply.
-// For example, SetHeader("Content-Type", "text/html; charset=utf-8")
-// will result in the header line
-//
-// Content-Type: text/html; charset=utf-8
-//
-// being sent. UTF-8 encoded HTML is the default setting for
-// Content-Type in this library, so users need not make that
-// particular call. Calls to SetHeader after WriteHeader (or Write)
-// are ignored.
-func (c *Conn) SetHeader(hdr, val string) { c.header[CanonicalHeaderKey(hdr)] = val }
-
-// WriteHeader sends an HTTP response header with status code.
-// If WriteHeader is not called explicitly, the first call to Write
-// will trigger an implicit WriteHeader(http.StatusOK).
-// Thus explicit calls to WriteHeader are mainly used to
-// send error codes.
-func (c *Conn) WriteHeader(code int) {
- if c.hijacked {
- log.Stderr("http: Conn.WriteHeader on hijacked connection")
+// UsingTLS implements the ResponseWriter.UsingTLS
+func (w *response) UsingTLS() bool {
+ return w.conn.usingTLS
+}
+
+// RemoteAddr implements the ResponseWriter.RemoteAddr method
+func (w *response) RemoteAddr() string { return w.conn.remoteAddr }
+
+// SetHeader implements the ResponseWriter.SetHeader method
+func (w *response) SetHeader(hdr, val string) { w.header[CanonicalHeaderKey(hdr)] = val }
+
+// WriteHeader implements the ResponseWriter.WriteHeader method
+func (w *response) WriteHeader(code int) {
+ if w.conn.hijacked {
+ log.Print("http: response.WriteHeader on hijacked connection")
return
}
- if c.wroteHeader {
- log.Stderr("http: multiple Conn.WriteHeader calls")
+ if w.wroteHeader {
+ log.Print("http: multiple response.WriteHeader calls")
return
}
- c.wroteHeader = true
- c.status = code
+ w.wroteHeader = true
+ w.status = code
if code == StatusNotModified {
// Must not have body.
- c.header["Content-Type"] = "", false
- c.header["Transfer-Encoding"] = "", false
+ w.header["Content-Type"] = "", false
+ w.header["Transfer-Encoding"] = "", false
+ w.chunking = false
}
- c.written = 0
- if !c.Req.ProtoAtLeast(1, 0) {
+ if !w.req.ProtoAtLeast(1, 0) {
return
}
proto := "HTTP/1.0"
- if c.Req.ProtoAtLeast(1, 1) {
+ if w.req.ProtoAtLeast(1, 1) {
proto = "HTTP/1.1"
}
codestring := strconv.Itoa(code)
@@ -187,48 +239,55 @@ func (c *Conn) WriteHeader(code int) {
if !ok {
text = "status code " + codestring
}
- io.WriteString(c.buf, proto+" "+codestring+" "+text+"\r\n")
- for k, v := range c.header {
- io.WriteString(c.buf, k+": "+v+"\r\n")
+ io.WriteString(w.conn.buf, proto+" "+codestring+" "+text+"\r\n")
+ for k, v := range w.header {
+ io.WriteString(w.conn.buf, k+": "+v+"\r\n")
}
- io.WriteString(c.buf, "\r\n")
+ io.WriteString(w.conn.buf, "\r\n")
}
-// 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.
-func (c *Conn) Write(data []byte) (n int, err os.Error) {
- if c.hijacked {
- log.Stderr("http: Conn.Write on hijacked connection")
+// Write implements the ResponseWriter.Write method
+func (w *response) Write(data []byte) (n int, err os.Error) {
+ if w.conn.hijacked {
+ log.Print("http: response.Write on hijacked connection")
return 0, ErrHijacked
}
- if !c.wroteHeader {
- c.WriteHeader(StatusOK)
+ if !w.wroteHeader {
+ if w.req.wantsHttp10KeepAlive() {
+ _, hasLength := w.header["Content-Length"]
+ if hasLength {
+ _, connectionHeaderSet := w.header["Connection"]
+ if !connectionHeaderSet {
+ w.header["Connection"] = "keep-alive"
+ }
+ }
+ }
+ w.WriteHeader(StatusOK)
}
if len(data) == 0 {
return 0, nil
}
- if c.status == StatusNotModified {
+ if w.status == StatusNotModified {
// Must not have body.
return 0, ErrBodyNotAllowed
}
- c.written += int64(len(data)) // ignoring errors, for errorKludge
+ w.written += int64(len(data)) // ignoring errors, for errorKludge
// TODO(rsc): if chunking happened after the buffering,
// then there would be fewer chunk headers.
// On the other hand, it would make hijacking more difficult.
- if c.chunking {
- fmt.Fprintf(c.buf, "%x\r\n", len(data)) // TODO(rsc): use strconv not fmt
+ if w.chunking {
+ fmt.Fprintf(w.conn.buf, "%x\r\n", len(data)) // TODO(rsc): use strconv not fmt
}
- n, err = c.buf.Write(data)
- if err == nil && c.chunking {
+ n, err = w.conn.buf.Write(data)
+ if err == nil && w.chunking {
if n != len(data) {
err = io.ErrShortWrite
}
if err == nil {
- io.WriteString(c.buf, "\r\n")
+ io.WriteString(w.conn.buf, "\r\n")
}
}
@@ -242,25 +301,25 @@ func (c *Conn) Write(data []byte) (n int, err os.Error) {
// long enough. The minimum lengths used in those
// browsers are in the 256-512 range.
// Pad to 1024 bytes.
-func errorKludge(c *Conn, req *Request) {
+func errorKludge(w *response) {
const min = 1024
// Is this an error?
- if kind := c.status / 100; kind != 4 && kind != 5 {
+ if kind := w.status / 100; kind != 4 && kind != 5 {
return
}
// Did the handler supply any info? Enough?
- if c.written == 0 || c.written >= min {
+ if w.written == 0 || w.written >= min {
return
}
// Is it a broken browser?
var msg string
- switch agent := req.UserAgent; {
- case strings.Index(agent, "MSIE") >= 0:
+ switch agent := w.req.UserAgent; {
+ case strings.Contains(agent, "MSIE"):
msg = "Internet Explorer"
- case strings.Index(agent, "Chrome/") >= 0:
+ case strings.Contains(agent, "Chrome/"):
msg = "Chrome"
default:
return
@@ -268,45 +327,54 @@ func errorKludge(c *Conn, req *Request) {
msg += " would ignore this error page if this text weren't here.\n"
// Is it text? ("Content-Type" is always in the map)
- baseType := strings.Split(c.header["Content-Type"], ";", 2)[0]
+ baseType := strings.Split(w.header["Content-Type"], ";", 2)[0]
switch baseType {
case "text/html":
- io.WriteString(c, "<!-- ")
- for c.written < min {
- io.WriteString(c, msg)
+ io.WriteString(w, "<!-- ")
+ for w.written < min {
+ io.WriteString(w, msg)
}
- io.WriteString(c, " -->")
+ io.WriteString(w, " -->")
case "text/plain":
- io.WriteString(c, "\n")
- for c.written < min {
- io.WriteString(c, msg)
+ io.WriteString(w, "\n")
+ for w.written < min {
+ io.WriteString(w, msg)
}
}
}
-func (c *Conn) finishRequest() {
- if !c.wroteHeader {
- c.WriteHeader(StatusOK)
+func (w *response) finishRequest() {
+ // If this was an HTTP/1.0 request with keep-alive and we sent a Content-Length
+ // back, we can make this a keep-alive response ...
+ if w.req.wantsHttp10KeepAlive() {
+ _, sentLength := w.header["Content-Length"]
+ if sentLength && w.header["Connection"] == "keep-alive" {
+ w.closeAfterReply = false
+ }
+ }
+ if !w.wroteHeader {
+ w.WriteHeader(StatusOK)
}
- errorKludge(c, c.Req)
- if c.chunking {
- io.WriteString(c.buf, "0\r\n")
+ errorKludge(w)
+ if w.chunking {
+ io.WriteString(w.conn.buf, "0\r\n")
// trailer key/value pairs, followed by blank line
- io.WriteString(c.buf, "\r\n")
+ io.WriteString(w.conn.buf, "\r\n")
}
- c.buf.Flush()
+ w.conn.buf.Flush()
+ w.req.Body.Close()
}
-// Flush sends any buffered data to the client.
-func (c *Conn) Flush() {
- if !c.wroteHeader {
- c.WriteHeader(StatusOK)
+// Flush implements the ResponseWriter.Flush method.
+func (w *response) Flush() {
+ if !w.wroteHeader {
+ w.WriteHeader(StatusOK)
}
- c.buf.Flush()
+ w.conn.buf.Flush()
}
// Close the connection.
-func (c *Conn) close() {
+func (c *conn) close() {
if c.buf != nil {
c.buf.Flush()
c.buf = nil
@@ -318,41 +386,39 @@ func (c *Conn) close() {
}
// Serve a new connection.
-func (c *Conn) serve() {
+func (c *conn) serve() {
for {
- req, err := c.readRequest()
+ w, err := c.readRequest()
if err != nil {
break
}
- // HTTP cannot have multiple simultaneous active requests.
+ // HTTP cannot have multiple simultaneous active requests.[*]
// Until the server replies to this request, it can't read another,
// so we might as well run the handler in this goroutine.
- c.handler.ServeHTTP(c, req)
+ // [*] Not strictly true: HTTP pipelining. We could let them all process
+ // in parallel even if their responses need to be serialized.
+ c.handler.ServeHTTP(w, w.req)
if c.hijacked {
return
}
- c.finishRequest()
- if c.closeAfterReply {
+ w.finishRequest()
+ if w.closeAfterReply {
break
}
}
c.close()
}
-// Hijack lets the caller take over the connection.
-// After a call to c.Hijack(), the HTTP server library
-// will not do anything else with the connection.
-// It becomes the caller's responsibility to manage
-// and close the connection.
-func (c *Conn) Hijack() (rwc io.ReadWriteCloser, buf *bufio.ReadWriter, err os.Error) {
- if c.hijacked {
+// Hijack impements the ResponseWriter.Hijack method.
+func (w *response) Hijack() (rwc io.ReadWriteCloser, buf *bufio.ReadWriter, err os.Error) {
+ if w.conn.hijacked {
return nil, nil, ErrHijacked
}
- c.hijacked = true
- rwc = c.rwc
- buf = c.buf
- c.rwc = nil
- c.buf = nil
+ w.conn.hijacked = true
+ rwc = w.conn.rwc
+ buf = w.conn.buf
+ w.conn.rwc = nil
+ w.conn.buf = nil
return
}
@@ -360,24 +426,24 @@ func (c *Conn) Hijack() (rwc io.ReadWriteCloser, buf *bufio.ReadWriter, err os.E
// ordinary functions as HTTP handlers. If f is a function
// with the appropriate signature, HandlerFunc(f) is a
// Handler object that calls f.
-type HandlerFunc func(*Conn, *Request)
+type HandlerFunc func(ResponseWriter, *Request)
-// ServeHTTP calls f(c, req).
-func (f HandlerFunc) ServeHTTP(c *Conn, req *Request) {
- f(c, req)
+// ServeHTTP calls f(w, req).
+func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
+ f(w, r)
}
// Helper handlers
// Error replies to the request with the specified error message and HTTP code.
-func Error(c *Conn, error string, code int) {
- c.SetHeader("Content-Type", "text/plain; charset=utf-8")
- c.WriteHeader(code)
- fmt.Fprintln(c, error)
+func Error(w ResponseWriter, error string, code int) {
+ w.SetHeader("Content-Type", "text/plain; charset=utf-8")
+ w.WriteHeader(code)
+ fmt.Fprintln(w, error)
}
// NotFound replies to the request with an HTTP 404 not found error.
-func NotFound(c *Conn, req *Request) { Error(c, "404 page not found", StatusNotFound) }
+func NotFound(w ResponseWriter, r *Request) { Error(w, "404 page not found", StatusNotFound) }
// NotFoundHandler returns a simple request handler
// that replies to each request with a ``404 page not found'' reply.
@@ -385,59 +451,64 @@ func NotFoundHandler() Handler { return HandlerFunc(NotFound) }
// Redirect replies to the request with a redirect to url,
// which may be a path relative to the request path.
-func Redirect(c *Conn, url string, code int) {
- // RFC2616 recommends that a short note "SHOULD" be included in the
- // response because older user agents may not understand 301/307.
- note := "<a href=\"%v\">" + statusText[code] + "</a>.\n"
- if c.Req.Method == "POST" {
- note = ""
+func Redirect(w ResponseWriter, r *Request, url string, code int) {
+ if u, err := ParseURL(url); err == nil {
+ // If url was relative, make absolute by
+ // combining with request path.
+ // The browser would probably do this for us,
+ // but doing it ourselves is more reliable.
+
+ // NOTE(rsc): RFC 2616 says that the Location
+ // line must be an absolute URI, like
+ // "http://www.google.com/redirect/",
+ // not a path like "/redirect/".
+ // Unfortunately, we don't know what to
+ // put in the host name section to get the
+ // client to connect to us again, so we can't
+ // know the right absolute URI to send back.
+ // Because of this problem, no one pays attention
+ // to the RFC; they all send back just a new path.
+ // So do we.
+ oldpath := r.URL.Path
+ if oldpath == "" { // should not happen, but avoid a crash if it does
+ oldpath = "/"
+ }
+ if u.Scheme == "" {
+ // no leading http://server
+ if url == "" || url[0] != '/' {
+ // make relative path absolute
+ olddir, _ := path.Split(oldpath)
+ url = olddir + url
+ }
+
+ // clean up but preserve trailing slash
+ trailing := url[len(url)-1] == '/'
+ url = path.Clean(url)
+ if trailing && url[len(url)-1] != '/' {
+ url += "/"
+ }
+ }
}
- u, err := ParseURL(url)
- if err != nil {
- goto finish
- }
-
- // If url was relative, make absolute by
- // combining with request path.
- // The browser would probably do this for us,
- // but doing it ourselves is more reliable.
-
- // NOTE(rsc): RFC 2616 says that the Location
- // line must be an absolute URI, like
- // "http://www.google.com/redirect/",
- // not a path like "/redirect/".
- // Unfortunately, we don't know what to
- // put in the host name section to get the
- // client to connect to us again, so we can't
- // know the right absolute URI to send back.
- // Because of this problem, no one pays attention
- // to the RFC; they all send back just a new path.
- // So do we.
- oldpath := c.Req.URL.Path
- if oldpath == "" { // should not happen, but avoid a crash if it does
- oldpath = "/"
- }
- if u.Scheme == "" {
- // no leading http://server
- if url == "" || url[0] != '/' {
- // make relative path absolute
- olddir, _ := path.Split(oldpath)
- url = olddir + url
- }
+ w.SetHeader("Location", url)
+ w.WriteHeader(code)
- // clean up but preserve trailing slash
- trailing := url[len(url)-1] == '/'
- url = path.Clean(url)
- if trailing && url[len(url)-1] != '/' {
- url += "/"
- }
+ // RFC2616 recommends that a short note "SHOULD" be included in the
+ // response because older user agents may not understand 301/307.
+ note := "<a href=\"" + htmlEscape(url) + "\">" + statusText[code] + "</a>.\n"
+ if r.Method == "POST" {
+ note = ""
}
+ fmt.Fprintln(w, note)
+}
-finish:
- c.SetHeader("Location", url)
- c.WriteHeader(code)
- fmt.Fprintf(c, note, url)
+func htmlEscape(s string) string {
+ s = strings.Replace(s, "&", "&amp;", -1)
+ s = strings.Replace(s, "<", "&lt;", -1)
+ s = strings.Replace(s, ">", "&gt;", -1)
+ s = strings.Replace(s, "\"", "&quot;", -1)
+ s = strings.Replace(s, "'", "&apos;", -1)
+ return s
}
// Redirect to a fixed URL
@@ -446,8 +517,8 @@ type redirectHandler struct {
code int
}
-func (rh *redirectHandler) ServeHTTP(c *Conn, req *Request) {
- Redirect(c, rh.url, rh.code)
+func (rh *redirectHandler) ServeHTTP(w ResponseWriter, r *Request) {
+ Redirect(w, r, rh.url, rh.code)
}
// RedirectHandler returns a request handler that redirects
@@ -523,11 +594,11 @@ func cleanPath(p string) string {
// ServeHTTP dispatches the request to the handler whose
// pattern most closely matches the request URL.
-func (mux *ServeMux) ServeHTTP(c *Conn, req *Request) {
+func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) {
// Clean path to canonical form and redirect.
- if p := cleanPath(req.URL.Path); p != req.URL.Path {
- c.SetHeader("Location", p)
- c.WriteHeader(StatusMovedPermanently)
+ if p := cleanPath(r.URL.Path); p != r.URL.Path {
+ w.SetHeader("Location", p)
+ w.WriteHeader(StatusMovedPermanently)
return
}
@@ -535,7 +606,7 @@ func (mux *ServeMux) ServeHTTP(c *Conn, req *Request) {
var h Handler
var n = 0
for k, v := range mux.m {
- if !pathMatch(k, req.URL.Path) {
+ if !pathMatch(k, r.URL.Path) {
continue
}
if h == nil || len(k) > n {
@@ -546,7 +617,7 @@ func (mux *ServeMux) ServeHTTP(c *Conn, req *Request) {
if h == nil {
h = NotFoundHandler()
}
- h.ServeHTTP(c, req)
+ h.ServeHTTP(w, r)
}
// Handle registers the handler for the given pattern.
@@ -566,7 +637,7 @@ func (mux *ServeMux) Handle(pattern string, handler Handler) {
}
// HandleFunc registers the handler function for the given pattern.
-func (mux *ServeMux) HandleFunc(pattern string, handler func(*Conn, *Request)) {
+func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
mux.Handle(pattern, HandlerFunc(handler))
}
@@ -576,7 +647,7 @@ func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, h
// HandleFunc registers the handler function for the given pattern
// in the DefaultServeMux.
-func HandleFunc(pattern string, handler func(*Conn, *Request)) {
+func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
DefaultServeMux.HandleFunc(pattern, handler)
}
@@ -618,8 +689,8 @@ func Serve(l net.Listener, handler Handler) os.Error {
// )
//
// // hello world, the web server
-// func HelloServer(c *http.Conn, req *http.Request) {
-// io.WriteString(c, "hello, world!\n")
+// func HelloServer(w http.ResponseWriter, req *http.Request) {
+// io.WriteString(w, "hello, world!\n")
// }
//
// func main() {
@@ -638,3 +709,52 @@ func ListenAndServe(addr string, handler Handler) os.Error {
l.Close()
return e
}
+
+// ListenAndServeTLS acts identically to ListenAndServe, except that it
+// expects HTTPS connections. Additionally, files containing a certificate and
+// matching private key for the server must be provided.
+//
+// A trivial example server is:
+//
+// import (
+// "http"
+// "log"
+// )
+//
+// func handler(w http.ResponseWriter, req *http.Request) {
+// w.SetHeader("Content-Type", "text/plain")
+// w.Write([]byte("This is an example server.\n"))
+// }
+//
+// func main() {
+// http.HandleFunc("/", handler)
+// log.Printf("About to listen on 10443. Go to https://127.0.0.1:10443/")
+// err := http.ListenAndServeTLS(":10443", "cert.pem", "key.pem", nil)
+// if err != nil {
+// log.Exit(err)
+// }
+// }
+//
+// One can use generate_cert.go in crypto/tls to generate cert.pem and key.pem.
+func ListenAndServeTLS(addr string, certFile string, keyFile string, handler Handler) os.Error {
+ config := &tls.Config{
+ Rand: rand.Reader,
+ Time: time.Seconds,
+ NextProtos: []string{"http/1.1"},
+ }
+
+ var err os.Error
+ config.Certificates = make([]tls.Certificate, 1)
+ config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
+ if err != nil {
+ return err
+ }
+
+ conn, err := net.Listen("tcp", addr)
+ if err != nil {
+ return err
+ }
+
+ tlsListener := tls.NewListener(conn, config)
+ return Serve(tlsListener, handler)
+}
diff --git a/src/pkg/http/status.go b/src/pkg/http/status.go
index 82a66d7ad..b6e2d65c6 100644
--- a/src/pkg/http/status.go
+++ b/src/pkg/http/status.go
@@ -98,3 +98,9 @@ var statusText = map[int]string{
StatusGatewayTimeout: "Gateway Timeout",
StatusHTTPVersionNotSupported: "HTTP Version Not Supported",
}
+
+// StatusText returns a text for the HTTP status code. It returns the empty
+// string if the code is unknown.
+func StatusText(code int) string {
+ return statusText[code]
+}
diff --git a/src/pkg/http/testdata/file b/src/pkg/http/testdata/file
new file mode 100644
index 000000000..11f11f9be
--- /dev/null
+++ b/src/pkg/http/testdata/file
@@ -0,0 +1 @@
+0123456789
diff --git a/src/pkg/http/transfer.go b/src/pkg/http/transfer.go
index 5e190d74c..e62885d62 100644
--- a/src/pkg/http/transfer.go
+++ b/src/pkg/http/transfer.go
@@ -108,7 +108,7 @@ func (t *transferWriter) WriteHeader(w io.Writer) (err os.Error) {
// writing long headers, using HTTP line splitting
io.WriteString(w, "Trailer: ")
needComma := false
- for k, _ := range t.Trailer {
+ for k := range t.Trailer {
k = CanonicalHeaderKey(k)
switch k {
case "Transfer-Encoding", "Trailer", "Content-Length":
@@ -135,6 +135,8 @@ func (t *transferWriter) WriteBody(w io.Writer) (err os.Error) {
if err == nil {
err = cw.Close()
}
+ } else if t.ContentLength == -1 {
+ _, err = io.Copy(w, t.Body)
} else {
_, err = io.Copy(w, io.LimitReader(t.Body, t.ContentLength))
}
@@ -182,6 +184,7 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err os.Error) {
t.RequestMethod = rr.RequestMethod
t.ProtoMajor = rr.ProtoMajor
t.ProtoMinor = rr.ProtoMinor
+ t.Close = shouldClose(t.ProtoMajor, t.ProtoMinor, t.Header)
case *Request:
t.Header = rr.Header
t.ProtoMajor = rr.ProtoMajor
@@ -208,9 +211,6 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err os.Error) {
return err
}
- // Closing
- t.Close = shouldClose(t.ProtoMajor, t.ProtoMinor, t.Header)
-
// Trailer
t.Trailer, err = fixTrailer(t.Header, t.TransferEncoding)
if err != nil {
@@ -340,7 +340,7 @@ func fixLength(status int, requestMethod string, header map[string]string, te []
// Logic based on media type. The purpose of the following code is just
// to detect whether the unsupported "multipart/byteranges" is being
// used. A proper Content-Type parser is needed in the future.
- if strings.Index(strings.ToLower(header["Content-Type"]), "multipart/byteranges") >= 0 {
+ if strings.Contains(strings.ToLower(header["Content-Type"]), "multipart/byteranges") {
return -1, ErrNotSupported
}
@@ -350,9 +350,20 @@ func fixLength(status int, requestMethod string, header map[string]string, te []
// Determine whether to hang up after sending a request and body, or
// receiving a response and body
+// 'header' is the request headers
func shouldClose(major, minor int, header map[string]string) bool {
- if major < 1 || (major == 1 && minor < 1) {
+ if major < 1 {
return true
+ } else if major == 1 && minor == 0 {
+ v, present := header["Connection"]
+ if !present {
+ return true
+ }
+ v = strings.ToLower(v)
+ if !strings.Contains(v, "keep-alive") {
+ return true
+ }
+ return false
} else if v, present := header["Connection"]; present {
// TODO: Should split on commas, toss surrounding white space,
// and check each field.
diff --git a/src/pkg/http/triv.go b/src/pkg/http/triv.go
index 612b6161e..03cfafa7b 100644
--- a/src/pkg/http/triv.go
+++ b/src/pkg/http/triv.go
@@ -20,9 +20,9 @@ import (
// hello world, the web server
var helloRequests = expvar.NewInt("hello-requests")
-func HelloServer(c *http.Conn, req *http.Request) {
+func HelloServer(w http.ResponseWriter, req *http.Request) {
helloRequests.Add(1)
- io.WriteString(c, "hello, world!\n")
+ io.WriteString(w, "hello, world!\n")
}
// Simple counter server. POSTing to it will set the value.
@@ -34,7 +34,7 @@ type Counter struct {
// it directly.
func (ctr *Counter) String() string { return fmt.Sprintf("%d", ctr.n) }
-func (ctr *Counter) ServeHTTP(c *http.Conn, req *http.Request) {
+func (ctr *Counter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
switch req.Method {
case "GET":
ctr.n++
@@ -43,53 +43,34 @@ func (ctr *Counter) ServeHTTP(c *http.Conn, req *http.Request) {
io.Copy(buf, req.Body)
body := buf.String()
if n, err := strconv.Atoi(body); err != nil {
- fmt.Fprintf(c, "bad POST: %v\nbody: [%v]\n", err, body)
+ fmt.Fprintf(w, "bad POST: %v\nbody: [%v]\n", err, body)
} else {
ctr.n = n
- fmt.Fprint(c, "counter reset\n")
+ fmt.Fprint(w, "counter reset\n")
}
}
- fmt.Fprintf(c, "counter = %d\n", ctr.n)
-}
-
-// simple file server
-var webroot = flag.String("root", "/home/rsc", "web root directory")
-var pathVar = expvar.NewMap("file-requests")
-
-func FileServer(c *http.Conn, req *http.Request) {
- c.SetHeader("content-type", "text/plain; charset=utf-8")
- pathVar.Add(req.URL.Path, 1)
- path := *webroot + req.URL.Path // TODO: insecure: use os.CleanName
- f, err := os.Open(path, os.O_RDONLY, 0)
- if err != nil {
- c.WriteHeader(http.StatusNotFound)
- fmt.Fprintf(c, "open %s: %v\n", path, err)
- return
- }
- n, _ := io.Copy(c, f)
- fmt.Fprintf(c, "[%d bytes]\n", n)
- f.Close()
+ fmt.Fprintf(w, "counter = %d\n", ctr.n)
}
// simple flag server
var booleanflag = flag.Bool("boolean", true, "another flag for testing")
-func FlagServer(c *http.Conn, req *http.Request) {
- c.SetHeader("content-type", "text/plain; charset=utf-8")
- fmt.Fprint(c, "Flags:\n")
+func FlagServer(w http.ResponseWriter, req *http.Request) {
+ w.SetHeader("content-type", "text/plain; charset=utf-8")
+ fmt.Fprint(w, "Flags:\n")
flag.VisitAll(func(f *flag.Flag) {
if f.Value.String() != f.DefValue {
- fmt.Fprintf(c, "%s = %s [default = %s]\n", f.Name, f.Value.String(), f.DefValue)
+ fmt.Fprintf(w, "%s = %s [default = %s]\n", f.Name, f.Value.String(), f.DefValue)
} else {
- fmt.Fprintf(c, "%s = %s\n", f.Name, f.Value.String())
+ fmt.Fprintf(w, "%s = %s\n", f.Name, f.Value.String())
}
})
}
// simple argument server
-func ArgServer(c *http.Conn, req *http.Request) {
+func ArgServer(w http.ResponseWriter, req *http.Request) {
for _, s := range os.Args {
- fmt.Fprint(c, s, " ")
+ fmt.Fprint(w, s, " ")
}
}
@@ -106,44 +87,46 @@ func ChanCreate() Chan {
return c
}
-func (ch Chan) ServeHTTP(c *http.Conn, req *http.Request) {
- io.WriteString(c, fmt.Sprintf("channel send #%d\n", <-ch))
+func (ch Chan) ServeHTTP(w http.ResponseWriter, req *http.Request) {
+ io.WriteString(w, fmt.Sprintf("channel send #%d\n", <-ch))
}
// exec a program, redirecting output
-func DateServer(c *http.Conn, req *http.Request) {
- c.SetHeader("content-type", "text/plain; charset=utf-8")
+func DateServer(rw http.ResponseWriter, req *http.Request) {
+ rw.SetHeader("content-type", "text/plain; charset=utf-8")
r, w, err := os.Pipe()
if err != nil {
- fmt.Fprintf(c, "pipe: %s\n", err)
+ fmt.Fprintf(rw, "pipe: %s\n", err)
return
}
pid, err := os.ForkExec("/bin/date", []string{"date"}, os.Environ(), "", []*os.File{nil, w, w})
defer r.Close()
w.Close()
if err != nil {
- fmt.Fprintf(c, "fork/exec: %s\n", err)
+ fmt.Fprintf(rw, "fork/exec: %s\n", err)
return
}
- io.Copy(c, r)
+ io.Copy(rw, r)
wait, err := os.Wait(pid, 0)
if err != nil {
- fmt.Fprintf(c, "wait: %s\n", err)
+ fmt.Fprintf(rw, "wait: %s\n", err)
return
}
if !wait.Exited() || wait.ExitStatus() != 0 {
- fmt.Fprintf(c, "date: %v\n", wait)
+ fmt.Fprintf(rw, "date: %v\n", wait)
return
}
}
-func Logger(c *http.Conn, req *http.Request) {
- log.Stdout(req.URL.Raw)
- c.WriteHeader(404)
- c.Write([]byte("oops"))
+func Logger(w http.ResponseWriter, req *http.Request) {
+ log.Print(req.URL.Raw)
+ w.WriteHeader(404)
+ w.Write([]byte("oops"))
}
+var webroot = flag.String("root", "/home/rsc", "web root directory")
+
func main() {
flag.Parse()
@@ -153,7 +136,7 @@ func main() {
expvar.Publish("counter", ctr)
http.Handle("/", http.HandlerFunc(Logger))
- http.Handle("/go/", http.HandlerFunc(FileServer))
+ http.Handle("/go/", http.FileServer(*webroot, "/go/"))
http.Handle("/flags", http.HandlerFunc(FlagServer))
http.Handle("/args", http.HandlerFunc(ArgServer))
http.Handle("/go/hello", http.HandlerFunc(HelloServer))
@@ -161,6 +144,6 @@ func main() {
http.Handle("/date", http.HandlerFunc(DateServer))
err := http.ListenAndServe(":12345", nil)
if err != nil {
- log.Crash("ListenAndServe: ", err)
+ log.Panicln("ListenAndServe:", err)
}
}
diff --git a/src/pkg/http/url.go b/src/pkg/http/url.go
index 148ada4b2..f0ac4c1df 100644
--- a/src/pkg/http/url.go
+++ b/src/pkg/http/url.go
@@ -46,6 +46,17 @@ func unhex(c byte) byte {
return 0
}
+type encoding int
+
+const (
+ encodePath encoding = 1 + iota
+ encodeUserPassword
+ encodeQueryComponent
+ encodeFragment
+ encodeOpaque
+)
+
+
type URLEscapeError string
func (e URLEscapeError) String() string {
@@ -54,17 +65,53 @@ func (e URLEscapeError) String() string {
// Return true if the specified character should be escaped when
// appearing in a URL string, according to RFC 2396.
-func shouldEscape(c byte) bool {
- if c <= ' ' || c >= 0x7F {
- return true
+// When 'all' is true the full range of reserved characters are matched.
+func shouldEscape(c byte, mode encoding) bool {
+ // RFC 2396 §2.3 Unreserved characters (alphanum)
+ if 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' {
+ return false
}
switch c {
- case '<', '>', '#', '%', '"', // RFC 2396 delims
- '{', '}', '|', '\\', '^', '[', ']', '`', // RFC2396 unwise
- '?', '&', '=', '+': // RFC 2396 reserved in path
- return true
+ case '-', '_', '.', '!', '~', '*', '\'', '(', ')': // §2.3 Unreserved characters (mark)
+ return false
+
+ case '$', '&', '+', ',', '/', ':', ';', '=', '?', '@': // §2.2 Reserved characters (reserved)
+ // Different sections of the URL allow a few of
+ // the reserved characters to appear unescaped.
+ switch mode {
+ case encodePath: // §3.3
+ // The RFC allows : @ & = + $ , but saves / ; for assigning
+ // meaning to individual path segments. This package
+ // only manipulates the path as a whole, so we allow those
+ // last two as well. Clients that need to distinguish between
+ // `/foo;y=z/bar` and `/foo%3by=z/bar` will have to re-decode RawPath.
+ // That leaves only ? to escape.
+ return c == '?'
+
+ case encodeUserPassword: // §3.2.2
+ // The RFC allows ; : & = + $ , in userinfo, so we must escape only @ and /.
+ // The parsing of userinfo treats : as special so we must escape that too.
+ return c == '@' || c == '/' || c == ':'
+
+ case encodeQueryComponent: // §3.4
+ // The RFC reserves (so we must escape) everything.
+ return true
+
+ case encodeFragment: // §4.1
+ // The RFC text is silent but the grammar allows
+ // everything, so escape nothing.
+ return false
+
+ case encodeOpaque: // §3 opaque_part
+ // The RFC allows opaque_part to use all characters
+ // except that the leading / must be escaped.
+ // (We implement that case in String.)
+ return false
+ }
}
- return false
+
+ // Everything else must be escaped.
+ return true
}
// CanonicalPath applies the algorithm specified in RFC 2396 to
@@ -124,17 +171,19 @@ func CanonicalPath(path string) string {
return string(a)
}
-// URLUnescape unescapes a URL-encoded string,
+// URLUnescape unescapes a string in ``URL encoded'' form,
// converting %AB into the byte 0xAB and '+' into ' ' (space).
// It returns an error if any % is not followed
// by two hexadecimal digits.
-func URLUnescape(s string) (string, os.Error) { return urlUnescape(s, true) }
+// Despite the name, this encoding applies only to individual
+// components of the query portion of the URL.
+func URLUnescape(s string) (string, os.Error) {
+ return urlUnescape(s, encodeQueryComponent)
+}
-// urlUnescape is like URLUnescape but can be told not to
-// convert + into space. URLUnescape implements what is
-// called "URL encoding" but that only applies to query strings.
-// Elsewhere in the URL, + does not mean space.
-func urlUnescape(s string, doPlus bool) (string, os.Error) {
+// urlUnescape is like URLUnescape but mode specifies
+// which section of the URL is being unescaped.
+func urlUnescape(s string, mode encoding) (string, os.Error) {
// Count %, check that they're well-formed.
n := 0
hasPlus := false
@@ -151,7 +200,7 @@ func urlUnescape(s string, doPlus bool) (string, os.Error) {
}
i += 3
case '+':
- hasPlus = doPlus
+ hasPlus = mode == encodeQueryComponent
i++
default:
i++
@@ -171,7 +220,7 @@ func urlUnescape(s string, doPlus bool) (string, os.Error) {
j++
i += 3
case '+':
- if doPlus {
+ if mode == encodeQueryComponent {
t[j] = ' '
} else {
t[j] = '+'
@@ -187,15 +236,19 @@ func urlUnescape(s string, doPlus bool) (string, os.Error) {
return string(t), nil
}
-// URLEscape converts a string into URL-encoded form.
-func URLEscape(s string) string { return urlEscape(s, true) }
+// URLEscape converts a string into ``URL encoded'' form.
+// Despite the name, this encoding applies only to individual
+// components of the query portion of the URL.
+func URLEscape(s string) string {
+ return urlEscape(s, encodeQueryComponent)
+}
-func urlEscape(s string, doPlus bool) string {
+func urlEscape(s string, mode encoding) string {
spaceCount, hexCount := 0, 0
for i := 0; i < len(s); i++ {
c := s[i]
- if shouldEscape(c) {
- if c == ' ' && doPlus {
+ if shouldEscape(c, mode) {
+ if c == ' ' && mode == encodeQueryComponent {
spaceCount++
} else {
hexCount++
@@ -211,10 +264,10 @@ func urlEscape(s string, doPlus bool) string {
j := 0
for i := 0; i < len(s); i++ {
switch c := s[i]; {
- case c == ' ' && doPlus:
+ case c == ' ' && mode == encodeQueryComponent:
t[j] = '+'
j++
- case shouldEscape(c):
+ case shouldEscape(c, mode):
t[j] = '%'
t[j+1] = "0123456789abcdef"[c>>4]
t[j+2] = "0123456789abcdef"[c&15]
@@ -227,25 +280,64 @@ func urlEscape(s string, doPlus bool) 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.
+//
+// This functionality should only be used with legacy web sites.
+// RFC 2396 warns that interpreting Userinfo this way
+// ``is NOT RECOMMENDED, because the passing of authentication
+// information in clear text (such as URI) has proven to be a
+// security risk in almost every case where it has been used.''
+func UnescapeUserinfo(rawUserinfo string) (user, password string, err os.Error) {
+ u, p := split(rawUserinfo, ':', true)
+ if user, err = urlUnescape(u, encodeUserPassword); err != nil {
+ return "", "", err
+ }
+ if password, err = urlUnescape(p, encodeUserPassword); err != nil {
+ return "", "", err
+ }
+ return
+}
+
+// EscapeUserinfo combines user and password in the form
+// user:password (or just user if password is empty) and then
+// escapes it for use as the URL.RawUserinfo field.
+//
+// This functionality should only be used with legacy web sites.
+// RFC 2396 warns that interpreting Userinfo this way
+// ``is NOT RECOMMENDED, because the passing of authentication
+// information in clear text (such as URI) has proven to be a
+// security risk in almost every case where it has been used.''
+func EscapeUserinfo(user, password string) string {
+ raw := urlEscape(user, encodeUserPassword)
+ if password != "" {
+ raw += ":" + urlEscape(password, encodeUserPassword)
+ }
+ return raw
+}
+
// A URL represents a parsed URL (technically, a URI reference).
// The general form represented is:
// scheme://[userinfo@]host/path[?query][#fragment]
-// The Raw, RawPath, and RawQuery fields are in "wire format" (special
-// characters must be hex-escaped if not meant to have special meaning).
+// 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.
//
-// Note, the reason for using wire format for the query is that it needs
-// to be split into key/value pairs before decoding.
+// 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
- Authority string // [userinfo@]host
- Userinfo string // userinfo
- Host string // host
- RawPath string // /path[?query][#fragment]
- Path string // /path
- RawQuery string // query
- Fragment string // fragment
+ Raw string // the original string
+ Scheme string // scheme
+ RawAuthority string // [userinfo@]host
+ RawUserinfo string // userinfo
+ Host string // host
+ RawPath string // /path[?query][#fragment]
+ Path string // /path
+ OpaquePath bool // path is opaque (unrooted when scheme is present)
+ RawQuery string // query
+ Fragment string // fragment
}
// Maybe rawurl is of the form scheme:path.
@@ -301,56 +393,63 @@ func ParseURL(rawurl string) (url *URL, err os.Error) {
url = new(URL)
url.Raw = rawurl
- // split off possible leading "http:", "mailto:", etc.
+ // Split off possible leading "http:", "mailto:", etc.
+ // Cannot contain escaped characters.
var path string
if url.Scheme, path, err = getscheme(rawurl); err != nil {
goto Error
}
- // RFC 2396: a relative URI (no scheme) has a ?query,
- // but absolute URIs only have query if path begins with /
- var query string
- if url.Scheme == "" || len(path) > 0 && path[0] == '/' {
- path, query = split(path, '?', false)
+ if url.Scheme != "" && (len(path) == 0 || path[0] != '/') {
+ // RFC 2396:
+ // Absolute URI (has scheme) with non-rooted path
+ // is uninterpreted. It doesn't even have a ?query.
+ // This is the case that handles mailto:name@example.com.
+ url.RawPath = path
+
+ if url.Path, err = urlUnescape(path, encodeOpaque); err != nil {
+ goto Error
+ }
+ url.OpaquePath = true
+ } else {
+ // 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 len(path) > 2 && path[0:2] == "//" {
- url.Authority, path = split(path[2:], '/', false)
- }
- url.RawPath = path + query
+ // Maybe path is //authority/path
+ if url.Scheme != "" && len(path) > 2 && path[0:2] == "//" {
+ url.RawAuthority, path = split(path[2:], '/', false)
+ url.RawPath = url.RawPath[2+len(url.RawAuthority):]
+ }
- // If there's no @, split's default is wrong. Check explicitly.
- if strings.Index(url.Authority, "@") < 0 {
- url.Host = url.Authority
- } else {
- url.Userinfo, url.Host = split(url.Authority, '@', true)
- }
+ // 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)
+ }
- if url.Path, err = urlUnescape(path, false); err != nil {
- goto Error
- }
+ // 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.
- // Remove escapes from the Authority and Userinfo fields, and verify
- // that Scheme and Host contain no escapes (that would be illegal).
- if url.Authority, err = urlUnescape(url.Authority, false); err != nil {
- goto Error
- }
- if url.Userinfo, err = urlUnescape(url.Userinfo, false); err != nil {
- goto Error
- }
- if strings.Index(url.Scheme, "%") >= 0 {
- err = os.ErrorString("hexadecimal escape in scheme")
- goto Error
- }
- if strings.Index(url.Host, "%") >= 0 {
- err = os.ErrorString("hexadecimal escape in host")
- goto Error
- }
+ if strings.Contains(rawHost, "%") {
+ // Host cannot contain escaped characters.
+ err = os.ErrorString("hexadecimal escape in host")
+ goto Error
+ }
+ url.Host = rawHost
+ if url.Path, err = urlUnescape(path, encodePath); err != nil {
+ goto Error
+ }
+ }
return url, nil
Error:
@@ -369,7 +468,7 @@ func ParseURLReference(rawurlref string) (url *URL, err os.Error) {
url.RawPath += frag
if len(frag) > 1 {
frag = frag[1:]
- if url.Fragment, err = urlUnescape(frag, false); err != nil {
+ if url.Fragment, err = urlUnescape(frag, encodeFragment); err != nil {
return nil, &URLError{"parse", rawurl, err}
}
}
@@ -379,26 +478,52 @@ func ParseURLReference(rawurlref string) (url *URL, err os.Error) {
// String reassembles url into a valid URL string.
//
// There are redundant fields stored in the URL structure:
-// the String method consults Scheme, Path, Host, Userinfo,
+// the String method consults Scheme, Path, Host, RawUserinfo,
// RawQuery, and Fragment, but not Raw, RawPath or Authority.
func (url *URL) String() string {
result := ""
if url.Scheme != "" {
result += url.Scheme + ":"
}
- if url.Host != "" || url.Userinfo != "" {
+ if url.Host != "" || url.RawUserinfo != "" {
result += "//"
- if url.Userinfo != "" {
- result += urlEscape(url.Userinfo, false) + "@"
+ 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
}
- result += urlEscape(url.Path, false)
+ if url.OpaquePath {
+ path := url.Path
+ if strings.HasPrefix(path, "/") {
+ result += "%2f"
+ path = path[1:]
+ }
+ result += urlEscape(path, encodeOpaque)
+ } else {
+ result += urlEscape(url.Path, encodePath)
+ }
if url.RawQuery != "" {
result += "?" + url.RawQuery
}
if url.Fragment != "" {
- result += "#" + urlEscape(url.Fragment, false)
+ result += "#" + urlEscape(url.Fragment, encodeFragment)
}
return result
}
+
+// EncodeQuery encodes the query represented as a multimap.
+func EncodeQuery(m map[string][]string) string {
+ parts := make([]string, 0, len(m)) // will be large enough for most uses
+ for k, vs := range m {
+ prefix := URLEscape(k) + "="
+ for _, v := range vs {
+ parts = append(parts, prefix+URLEscape(v))
+ }
+ }
+ return strings.Join(parts, "&")
+}
diff --git a/src/pkg/http/url_test.go b/src/pkg/http/url_test.go
index 3d665100a..447d5390e 100644
--- a/src/pkg/http/url_test.go
+++ b/src/pkg/http/url_test.go
@@ -24,125 +24,138 @@ type URLTest struct {
var urltests = []URLTest{
// no path
- URLTest{
+ {
"http://www.google.com",
&URL{
- Raw: "http://www.google.com",
- Scheme: "http",
- Authority: "www.google.com",
- Host: "www.google.com",
+ Raw: "http://www.google.com",
+ Scheme: "http",
+ RawAuthority: "www.google.com",
+ Host: "www.google.com",
},
"",
},
// path
- URLTest{
+ {
"http://www.google.com/",
&URL{
- Raw: "http://www.google.com/",
- Scheme: "http",
- Authority: "www.google.com",
- Host: "www.google.com",
- RawPath: "/",
- Path: "/",
+ Raw: "http://www.google.com/",
+ Scheme: "http",
+ RawAuthority: "www.google.com",
+ Host: "www.google.com",
+ RawPath: "/",
+ Path: "/",
},
"",
},
// path with hex escaping
- URLTest{
+ {
"http://www.google.com/file%20one%26two",
&URL{
- Raw: "http://www.google.com/file%20one%26two",
- Scheme: "http",
- Authority: "www.google.com",
- Host: "www.google.com",
- RawPath: "/file%20one%26two",
- Path: "/file one&two",
+ Raw: "http://www.google.com/file%20one%26two",
+ Scheme: "http",
+ RawAuthority: "www.google.com",
+ Host: "www.google.com",
+ RawPath: "/file%20one%26two",
+ Path: "/file one&two",
},
- "http://www.google.com/file%20one%26two",
+ "http://www.google.com/file%20one&two",
},
// user
- URLTest{
+ {
"ftp://webmaster@www.google.com/",
&URL{
- Raw: "ftp://webmaster@www.google.com/",
- Scheme: "ftp",
- Authority: "webmaster@www.google.com",
- Userinfo: "webmaster",
- Host: "www.google.com",
- RawPath: "/",
- Path: "/",
+ Raw: "ftp://webmaster@www.google.com/",
+ Scheme: "ftp",
+ RawAuthority: "webmaster@www.google.com",
+ RawUserinfo: "webmaster",
+ Host: "www.google.com",
+ RawPath: "/",
+ Path: "/",
},
"",
},
// escape sequence in username
- URLTest{
+ {
"ftp://john%20doe@www.google.com/",
&URL{
- Raw: "ftp://john%20doe@www.google.com/",
- Scheme: "ftp",
- Authority: "john doe@www.google.com",
- Userinfo: "john doe",
- Host: "www.google.com",
- RawPath: "/",
- Path: "/",
+ Raw: "ftp://john%20doe@www.google.com/",
+ Scheme: "ftp",
+ RawAuthority: "john%20doe@www.google.com",
+ RawUserinfo: "john%20doe",
+ Host: "www.google.com",
+ RawPath: "/",
+ Path: "/",
},
"ftp://john%20doe@www.google.com/",
},
// query
- URLTest{
+ {
"http://www.google.com/?q=go+language",
&URL{
- Raw: "http://www.google.com/?q=go+language",
- Scheme: "http",
- Authority: "www.google.com",
- Host: "www.google.com",
- RawPath: "/?q=go+language",
- Path: "/",
- RawQuery: "q=go+language",
+ Raw: "http://www.google.com/?q=go+language",
+ Scheme: "http",
+ RawAuthority: "www.google.com",
+ Host: "www.google.com",
+ RawPath: "/?q=go+language",
+ Path: "/",
+ RawQuery: "q=go+language",
},
"",
},
// query with hex escaping: NOT parsed
- URLTest{
+ {
"http://www.google.com/?q=go%20language",
&URL{
- Raw: "http://www.google.com/?q=go%20language",
- Scheme: "http",
- Authority: "www.google.com",
- Host: "www.google.com",
- RawPath: "/?q=go%20language",
- Path: "/",
- RawQuery: "q=go%20language",
+ Raw: "http://www.google.com/?q=go%20language",
+ Scheme: "http",
+ RawAuthority: "www.google.com",
+ Host: "www.google.com",
+ RawPath: "/?q=go%20language",
+ Path: "/",
+ RawQuery: "q=go%20language",
},
"",
},
// %20 outside query
- URLTest{
+ {
"http://www.google.com/a%20b?q=c+d",
&URL{
- Raw: "http://www.google.com/a%20b?q=c+d",
- Scheme: "http",
- Authority: "www.google.com",
- Host: "www.google.com",
- RawPath: "/a%20b?q=c+d",
- Path: "/a b",
- RawQuery: "q=c+d",
+ Raw: "http://www.google.com/a%20b?q=c+d",
+ Scheme: "http",
+ RawAuthority: "www.google.com",
+ Host: "www.google.com",
+ RawPath: "/a%20b?q=c+d",
+ Path: "/a b",
+ RawQuery: "q=c+d",
},
"",
},
- // path without /, so no query parsing
- URLTest{
+ // path without leading /, so no query parsing
+ {
"http:www.google.com/?q=go+language",
&URL{
- Raw: "http:www.google.com/?q=go+language",
- Scheme: "http",
- RawPath: "www.google.com/?q=go+language",
- Path: "www.google.com/?q=go+language",
+ Raw: "http:www.google.com/?q=go+language",
+ Scheme: "http",
+ RawPath: "www.google.com/?q=go+language",
+ Path: "www.google.com/?q=go+language",
+ OpaquePath: true,
+ },
+ "http:www.google.com/?q=go+language",
+ },
+ // path without leading /, so no query parsing
+ {
+ "http:%2f%2fwww.google.com/?q=go+language",
+ &URL{
+ Raw: "http:%2f%2fwww.google.com/?q=go+language",
+ Scheme: "http",
+ RawPath: "%2f%2fwww.google.com/?q=go+language",
+ Path: "//www.google.com/?q=go+language",
+ OpaquePath: true,
},
- "http:www.google.com/%3fq%3dgo%2blanguage",
+ "http:%2f/www.google.com/?q=go+language",
},
// non-authority
- URLTest{
+ {
"mailto:/webmaster@golang.org",
&URL{
Raw: "mailto:/webmaster@golang.org",
@@ -153,18 +166,19 @@ var urltests = []URLTest{
"",
},
// non-authority
- URLTest{
+ {
"mailto:webmaster@golang.org",
&URL{
- Raw: "mailto:webmaster@golang.org",
- Scheme: "mailto",
- RawPath: "webmaster@golang.org",
- Path: "webmaster@golang.org",
+ Raw: "mailto:webmaster@golang.org",
+ Scheme: "mailto",
+ RawPath: "webmaster@golang.org",
+ Path: "webmaster@golang.org",
+ OpaquePath: true,
},
"",
},
// unescaped :// in query should not create a scheme
- URLTest{
+ {
"/foo?query=http://bad",
&URL{
Raw: "/foo?query=http://bad",
@@ -174,59 +188,92 @@ var urltests = []URLTest{
},
"",
},
+ // leading // without scheme shouldn't create an authority
+ {
+ "//foo",
+ &URL{
+ Raw: "//foo",
+ Scheme: "",
+ RawPath: "//foo",
+ Path: "//foo",
+ },
+ "",
+ },
+ {
+ "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{
- URLTest{
+ {
"http://www.google.com/?q=go+language#foo",
&URL{
- Raw: "http://www.google.com/?q=go+language#foo",
- Scheme: "http",
- Authority: "www.google.com",
- Host: "www.google.com",
- RawPath: "/?q=go+language#foo",
- Path: "/",
- RawQuery: "q=go+language#foo",
+ Raw: "http://www.google.com/?q=go+language#foo",
+ Scheme: "http",
+ RawAuthority: "www.google.com",
+ Host: "www.google.com",
+ RawPath: "/?q=go+language#foo",
+ Path: "/",
+ RawQuery: "q=go+language#foo",
},
"",
},
}
var urlfragtests = []URLTest{
- URLTest{
+ {
"http://www.google.com/?q=go+language#foo",
&URL{
- Raw: "http://www.google.com/?q=go+language#foo",
- Scheme: "http",
- Authority: "www.google.com",
- Host: "www.google.com",
- RawPath: "/?q=go+language#foo",
- Path: "/",
- RawQuery: "q=go+language",
- Fragment: "foo",
+ 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",
},
"",
},
- URLTest{
+ {
"http://www.google.com/?q=go+language#foo%26bar",
&URL{
- Raw: "http://www.google.com/?q=go+language#foo%26bar",
- Scheme: "http",
- Authority: "www.google.com",
- Host: "www.google.com",
- RawPath: "/?q=go+language#foo%26bar",
- Path: "/",
- RawQuery: "q=go+language",
- Fragment: "foo&bar",
+ Raw: "http://www.google.com/?q=go+language#foo%26bar",
+ Scheme: "http",
+ RawAuthority: "www.google.com",
+ Host: "www.google.com",
+ RawPath: "/?q=go+language#foo%26bar",
+ Path: "/",
+ RawQuery: "q=go+language",
+ Fragment: "foo&bar",
},
- "",
+ "http://www.google.com/?q=go+language#foo&bar",
},
}
// more useful string for debugging than fmt's struct printer
func ufmt(u *URL) string {
return fmt.Sprintf("%q, %q, %q, %q, %q, %q, %q, %q, %q",
- u.Raw, u.Scheme, u.RawPath, u.Authority, u.Userinfo,
+ u.Raw, u.Scheme, u.RawPath, u.RawAuthority, u.RawUserinfo,
u.Host, u.Path, u.RawQuery, u.Fragment)
}
@@ -274,11 +321,9 @@ func DoTestString(t *testing.T, parse func(string) (*URL, os.Error), name string
func TestURLString(t *testing.T) {
DoTestString(t, ParseURL, "ParseURL", urltests)
- DoTestString(t, ParseURL, "ParseURL", urlfragtests)
DoTestString(t, ParseURL, "ParseURL", urlnofragtests)
DoTestString(t, ParseURLReference, "ParseURLReference", urltests)
DoTestString(t, ParseURLReference, "ParseURLReference", urlfragtests)
- DoTestString(t, ParseURLReference, "ParseURLReference", urlnofragtests)
}
type URLEscapeTest struct {
@@ -288,57 +333,57 @@ type URLEscapeTest struct {
}
var unescapeTests = []URLEscapeTest{
- URLEscapeTest{
+ {
"",
"",
nil,
},
- URLEscapeTest{
+ {
"abc",
"abc",
nil,
},
- URLEscapeTest{
+ {
"1%41",
"1A",
nil,
},
- URLEscapeTest{
+ {
"1%41%42%43",
"1ABC",
nil,
},
- URLEscapeTest{
+ {
"%4a",
"J",
nil,
},
- URLEscapeTest{
+ {
"%6F",
"o",
nil,
},
- URLEscapeTest{
+ {
"%", // not enough characters after %
"",
URLEscapeError("%"),
},
- URLEscapeTest{
+ {
"%a", // not enough characters after %
"",
URLEscapeError("%a"),
},
- URLEscapeTest{
+ {
"%1", // not enough characters after %
"",
URLEscapeError("%1"),
},
- URLEscapeTest{
+ {
"123%45%6", // not enough characters after %
"",
URLEscapeError("%6"),
},
- URLEscapeTest{
+ {
"%zzzzz", // invalid hex digits
"",
URLEscapeError("%zz"),
@@ -355,27 +400,27 @@ func TestURLUnescape(t *testing.T) {
}
var escapeTests = []URLEscapeTest{
- URLEscapeTest{
+ {
"",
"",
nil,
},
- URLEscapeTest{
+ {
"abc",
"abc",
nil,
},
- URLEscapeTest{
+ {
"one two",
"one+two",
nil,
},
- URLEscapeTest{
+ {
"10%",
"10%25",
nil,
},
- URLEscapeTest{
+ {
" ?&=#+%!<>#\"{}|\\^[]`☺\t",
"+%3f%26%3d%23%2b%25!%3c%3e%23%22%7b%7d%7c%5c%5e%5b%5d%60%e2%98%ba%09",
nil,
@@ -403,27 +448,27 @@ type CanonicalPathTest struct {
}
var canonicalTests = []CanonicalPathTest{
- CanonicalPathTest{"", ""},
- CanonicalPathTest{"/", "/"},
- CanonicalPathTest{".", ""},
- CanonicalPathTest{"./", ""},
- CanonicalPathTest{"/a/", "/a/"},
- CanonicalPathTest{"a/", "a/"},
- CanonicalPathTest{"a/./", "a/"},
- CanonicalPathTest{"./a", "a"},
- CanonicalPathTest{"/a/../b", "/b"},
- CanonicalPathTest{"a/../b", "b"},
- CanonicalPathTest{"a/../../b", "../b"},
- CanonicalPathTest{"a/.", "a/"},
- CanonicalPathTest{"../.././a", "../../a"},
- CanonicalPathTest{"/../.././a", "/../../a"},
- CanonicalPathTest{"a/b/g/../..", "a/"},
- CanonicalPathTest{"a/b/..", "a/"},
- CanonicalPathTest{"a/b/.", "a/b/"},
- CanonicalPathTest{"a/b/../../../..", "../.."},
- CanonicalPathTest{"a./", "a./"},
- CanonicalPathTest{"/../a/b/../../../", "/../../"},
- CanonicalPathTest{"../a/b/../../../", "../../"},
+ {"", ""},
+ {"/", "/"},
+ {".", ""},
+ {"./", ""},
+ {"/a/", "/a/"},
+ {"a/", "a/"},
+ {"a/./", "a/"},
+ {"./a", "a"},
+ {"/a/../b", "/b"},
+ {"a/../b", "b"},
+ {"a/../../b", "../b"},
+ {"a/.", "a/"},
+ {"../.././a", "../../a"},
+ {"/../.././a", "/../../a"},
+ {"a/b/g/../..", "a/"},
+ {"a/b/..", "a/"},
+ {"a/b/.", "a/b/"},
+ {"a/b/../../../..", "../.."},
+ {"a./", "a./"},
+ {"/../a/b/../../../", "/../../"},
+ {"../a/b/../../../", "../../"},
}
func TestCanonicalPath(t *testing.T) {
@@ -434,3 +479,53 @@ func TestCanonicalPath(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)
+ }
+ }
+}
+
+type qMap map[string][]string
+
+type EncodeQueryTest struct {
+ m qMap
+ expected string
+ expected1 string
+}
+
+var encodeQueryTests = []EncodeQueryTest{
+ {nil, "", ""},
+ {qMap{"q": {"puppies"}, "oe": {"utf8"}}, "q=puppies&oe=utf8", "oe=utf8&q=puppies"},
+ {qMap{"q": {"dogs", "&", "7"}}, "q=dogs&q=%26&q=7", "q=dogs&q=%26&q=7"},
+}
+
+func TestEncodeQuery(t *testing.T) {
+ for _, tt := range encodeQueryTests {
+ if q := EncodeQuery(tt.m); q != tt.expected && q != tt.expected1 {
+ t.Errorf(`EncodeQuery(%+v) = %q, want %q`, tt.m, q, tt.expected)
+ }
+ }
+}
diff --git a/src/pkg/image/Makefile b/src/pkg/image/Makefile
index 9c886f9f9..739ad804b 100644
--- a/src/pkg/image/Makefile
+++ b/src/pkg/image/Makefile
@@ -2,11 +2,13 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=image
GOFILES=\
color.go\
+ format.go\
+ geom.go\
image.go\
names.go\
diff --git a/src/pkg/image/color.go b/src/pkg/image/color.go
index 8a865a8a0..c1345c025 100644
--- a/src/pkg/image/color.go
+++ b/src/pkg/image/color.go
@@ -103,6 +103,27 @@ func (c Alpha16Color) RGBA() (r, g, b, a uint32) {
return a, a, a, a
}
+// A GrayColor represents an 8-bit grayscale color.
+type GrayColor struct {
+ Y uint8
+}
+
+func (c GrayColor) RGBA() (r, g, b, a uint32) {
+ y := uint32(c.Y)
+ y |= y << 8
+ return y, y, y, 0xffff
+}
+
+// A Gray16Color represents a 16-bit grayscale color.
+type Gray16Color struct {
+ Y uint16
+}
+
+func (c Gray16Color) RGBA() (r, g, b, a uint32) {
+ y := uint32(c.Y)
+ return y, y, y, 0xffff
+}
+
// A ColorModel can convert foreign Colors, with a possible loss of precision,
// to a Color from its own color model.
type ColorModel interface {
@@ -187,6 +208,24 @@ func toAlpha16Color(c Color) Color {
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)
@@ -204,3 +243,9 @@ 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/format.go b/src/pkg/image/format.go
new file mode 100644
index 000000000..1d541b094
--- /dev/null
+++ b/src/pkg/image/format.go
@@ -0,0 +1,86 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package image
+
+import (
+ "bufio"
+ "io"
+ "os"
+)
+
+// An UnknownFormatErr indicates that decoding encountered an unknown format.
+var UnknownFormatErr = os.NewError("image: unknown format")
+
+// A format holds an image format's name, magic header and how to decode it.
+type format struct {
+ name, magic string
+ decode func(io.Reader) (Image, os.Error)
+ decodeConfig func(io.Reader) (Config, os.Error)
+}
+
+// Formats is the list of registered formats.
+var formats []format
+
+// RegisterFormat registers an image format for use by Decode.
+// Name is the name of the format, like "jpeg" or "png".
+// Magic is the magic prefix that identifies the format's encoding.
+// Decode is the function that decodes the encoded image.
+// DecodeConfig is the function that decodes just its configuration.
+func RegisterFormat(name, magic string, decode func(io.Reader) (Image, os.Error), decodeConfig func(io.Reader) (Config, os.Error)) {
+ formats = append(formats, format{name, magic, decode, decodeConfig})
+}
+
+// A reader is an io.Reader that can also peek ahead.
+type reader interface {
+ io.Reader
+ Peek(int) ([]byte, os.Error)
+}
+
+// AsReader converts an io.Reader to a reader.
+func asReader(r io.Reader) reader {
+ if rr, ok := r.(reader); ok {
+ return rr
+ }
+ return bufio.NewReader(r)
+}
+
+// sniff determines the format of r's data.
+func sniff(r reader) format {
+ for _, f := range formats {
+ s, err := r.Peek(len(f.magic))
+ if err == nil && string(s) == f.magic {
+ return f
+ }
+ }
+ return format{}
+}
+
+// Decode decodes an image that has been encoded in a registered format.
+// The string returned is the format name used during format registration.
+// Format registration is typically done by the init method of the codec-
+// specific package.
+func Decode(r io.Reader) (Image, string, os.Error) {
+ rr := asReader(r)
+ f := sniff(rr)
+ if f.decode == nil {
+ return nil, "", UnknownFormatErr
+ }
+ m, err := f.decode(rr)
+ return m, f.name, err
+}
+
+// DecodeConfig decodes the color model and dimensions of an image that has
+// been encoded in a registered format. The string returned is the format name
+// used during format registration. Format registration is typically done by
+// the init method of the codec-specific package.
+func DecodeConfig(r io.Reader) (Config, string, os.Error) {
+ rr := asReader(r)
+ f := sniff(rr)
+ if f.decodeConfig == nil {
+ return Config{}, "", UnknownFormatErr
+ }
+ c, err := f.decodeConfig(rr)
+ return c, f.name, err
+}
diff --git a/src/pkg/image/geom.go b/src/pkg/image/geom.go
new file mode 100644
index 000000000..ccfe9cdb0
--- /dev/null
+++ b/src/pkg/image/geom.go
@@ -0,0 +1,223 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package image
+
+import (
+ "strconv"
+)
+
+// A Point is an X, Y coordinate pair. The axes increase right and down.
+type Point struct {
+ X, Y int
+}
+
+// String returns a string representation of p like "(3,4)".
+func (p Point) String() string {
+ return "(" + strconv.Itoa(p.X) + "," + strconv.Itoa(p.Y) + ")"
+}
+
+// Add returns the vector p+q.
+func (p Point) Add(q Point) Point {
+ return Point{p.X + q.X, p.Y + q.Y}
+}
+
+// Sub returns the vector p-q.
+func (p Point) Sub(q Point) Point {
+ return Point{p.X - q.X, p.Y - q.Y}
+}
+
+// Mul returns the vector p*k.
+func (p Point) Mul(k int) Point {
+ return Point{p.X * k, p.Y * k}
+}
+
+// Div returns the vector p/k.
+func (p Point) Div(k int) Point {
+ return Point{p.X / k, p.Y / k}
+}
+
+// Mod returns the point q in r such that p.X-q.X is a multiple of r's width
+// and p.Y-q.Y is a multiple of r's height.
+func (p Point) Mod(r Rectangle) Point {
+ w, h := r.Dx(), r.Dy()
+ p = p.Sub(r.Min)
+ p.X = p.X % w
+ if p.X < 0 {
+ p.X += w
+ }
+ p.Y = p.Y % h
+ if p.Y < 0 {
+ p.Y += h
+ }
+ return p.Add(r.Min)
+}
+
+// Eq returns whether p and q are equal.
+func (p Point) Eq(q Point) bool {
+ return p.X == q.X && p.Y == q.Y
+}
+
+// ZP is the zero Point.
+var ZP Point
+
+// Pt is shorthand for Point{X, Y}.
+func Pt(X, Y int) Point {
+ return Point{X, Y}
+}
+
+// A Rectangle contains the points with Min.X <= X < Max.X, Min.Y <= Y < Max.Y.
+// It is well-formed if Min.X <= Max.X and likewise for Y. Points are always
+// well-formed. A rectangle's methods always return well-formed outputs for
+// well-formed inputs.
+type Rectangle struct {
+ Min, Max Point
+}
+
+// String returns a string representation of r like "(3,4)-(6,5)".
+func (r Rectangle) String() string {
+ return r.Min.String() + "-" + r.Max.String()
+}
+
+// Dx returns r's width.
+func (r Rectangle) Dx() int {
+ return r.Max.X - r.Min.X
+}
+
+// Dy returns r's height.
+func (r Rectangle) Dy() int {
+ return r.Max.Y - r.Min.Y
+}
+
+// Size returns r's width and height.
+func (r Rectangle) Size() Point {
+ return Point{
+ r.Max.X - r.Min.X,
+ r.Max.Y - r.Min.Y,
+ }
+}
+
+// Add returns the rectangle r translated by p.
+func (r Rectangle) Add(p Point) Rectangle {
+ return Rectangle{
+ Point{r.Min.X + p.X, r.Min.Y + p.Y},
+ Point{r.Max.X + p.X, r.Max.Y + p.Y},
+ }
+}
+
+// Add returns the rectangle r translated by -p.
+func (r Rectangle) Sub(p Point) Rectangle {
+ return Rectangle{
+ Point{r.Min.X - p.X, r.Min.Y - p.Y},
+ Point{r.Max.X - p.X, r.Max.Y - p.Y},
+ }
+}
+
+// Inset returns the rectangle r inset by n, which may be negative. If either
+// of r's dimensions is less than 2*n then an empty rectangle near the center
+// of r will be returned.
+func (r Rectangle) Inset(n int) Rectangle {
+ if r.Dx() < 2*n {
+ r.Min.X = (r.Min.X + r.Max.X) / 2
+ r.Max.X = r.Min.X
+ } else {
+ r.Min.X += n
+ r.Max.X -= n
+ }
+ if r.Dy() < 2*n {
+ r.Min.Y = (r.Min.Y + r.Max.Y) / 2
+ r.Max.Y = r.Min.Y
+ } else {
+ r.Min.Y += n
+ r.Max.Y -= n
+ }
+ return r
+}
+
+// Intersect returns the largest rectangle contained by both r and s. If the
+// two rectangles do not overlap then the zero rectangle will be returned.
+func (r Rectangle) Intersect(s Rectangle) Rectangle {
+ if r.Min.X < s.Min.X {
+ r.Min.X = s.Min.X
+ }
+ if r.Min.Y < s.Min.Y {
+ r.Min.Y = s.Min.Y
+ }
+ if r.Max.X > s.Max.X {
+ r.Max.X = s.Max.X
+ }
+ if r.Max.Y > s.Max.Y {
+ r.Max.Y = s.Max.Y
+ }
+ if r.Min.X > r.Max.X || r.Min.Y > r.Max.Y {
+ return ZR
+ }
+ return r
+}
+
+// Union returns the smallest rectangle that contains both r and s.
+func (r Rectangle) Union(s Rectangle) Rectangle {
+ if r.Min.X > s.Min.X {
+ r.Min.X = s.Min.X
+ }
+ if r.Min.Y > s.Min.Y {
+ r.Min.Y = s.Min.Y
+ }
+ if r.Max.X < s.Max.X {
+ r.Max.X = s.Max.X
+ }
+ if r.Max.Y < s.Max.Y {
+ r.Max.Y = s.Max.Y
+ }
+ return r
+}
+
+// Empty returns whether the rectangle contains no points.
+func (r Rectangle) Empty() bool {
+ return r.Min.X >= r.Max.X || r.Min.Y >= r.Max.Y
+}
+
+// Eq returns whether r and s are equal.
+func (r Rectangle) Eq(s Rectangle) bool {
+ return r.Min.X == s.Min.X && r.Min.Y == s.Min.Y &&
+ r.Max.X == s.Max.X && r.Max.Y == s.Max.Y
+}
+
+// Overlaps returns whether r and s have a non-empty intersection.
+func (r Rectangle) Overlaps(s Rectangle) bool {
+ return r.Min.X < s.Max.X && s.Min.X < r.Max.X &&
+ r.Min.Y < s.Max.Y && s.Min.Y < r.Max.Y
+}
+
+// Contains returns whether r contains p.
+func (r Rectangle) Contains(p Point) bool {
+ return p.X >= r.Min.X && p.X < r.Max.X &&
+ p.Y >= r.Min.Y && p.Y < r.Max.Y
+}
+
+// Canon returns the canonical version of r. The returned rectangle has minimum
+// and maximum coordinates swapped if necessary so that it is well-formed.
+func (r Rectangle) Canon() Rectangle {
+ if r.Max.X < r.Min.X {
+ r.Min.X, r.Max.X = r.Max.X, r.Min.X
+ }
+ if r.Max.Y < r.Min.Y {
+ r.Min.Y, r.Max.Y = r.Max.Y, r.Min.Y
+ }
+ return r
+}
+
+// ZR is the zero Rectangle.
+var ZR Rectangle
+
+// Rect is shorthand for Rectangle{Pt(x0, y0), Pt(x1, y1)}.
+func Rect(x0, y0, x1, y1 int) Rectangle {
+ if x0 > x1 {
+ x0, x1 = x1, x0
+ }
+ if y0 > y1 {
+ y0, y1 = y1, y0
+ }
+ return Rectangle{Point{x0, y0}, Point{x1, y1}}
+}
diff --git a/src/pkg/image/image.go b/src/pkg/image/image.go
index decf1ce43..c0e96e1f7 100644
--- a/src/pkg/image/image.go
+++ b/src/pkg/image/image.go
@@ -5,50 +5,67 @@
// The image package implements a basic 2-D image library.
package image
-// An Image is a rectangular grid of Colors drawn from a ColorModel.
+// A Config consists of an image's color model and dimensions.
+type Config struct {
+ ColorModel ColorModel
+ Width, Height int
+}
+
+// An Image is a finite rectangular grid of Colors drawn from a ColorModel.
type Image interface {
+ // ColorModel returns the Image's ColorModel.
ColorModel() ColorModel
- Width() int
- Height() int
- // At(0, 0) returns the upper-left pixel of the grid.
- // At(Width()-1, Height()-1) returns the lower-right pixel.
+ // Bounds returns the domain for which At can return non-zero color.
+ // The bounds do not necessarily contain the point (0, 0).
+ Bounds() Rectangle
+ // At returns the color of the pixel at (x, y).
+ // At(Bounds().Min.X, Bounds().Min.Y) returns the upper-left pixel of the grid.
+ // At(Bounds().Max.X-1, Bounds().Max.Y-1) returns the lower-right one.
At(x, y int) Color
}
-// An RGBA is an in-memory image backed by a 2-D slice of RGBAColor values.
+// An RGBA is an in-memory image of RGBAColor values.
type RGBA struct {
- // The Pixel field's indices are y first, then x, so that At(x, y) == Pixel[y][x].
- Pixel [][]RGBAColor
+ // Pix holds the image's pixels. The pixel at (x, y) is Pix[y*Stride+x].
+ Pix []RGBAColor
+ Stride int
+ // Rect is the image's bounds.
+ Rect Rectangle
}
func (p *RGBA) ColorModel() ColorModel { return RGBAColorModel }
-func (p *RGBA) Width() int {
- if len(p.Pixel) == 0 {
- return 0
+func (p *RGBA) Bounds() Rectangle { return p.Rect }
+
+func (p *RGBA) At(x, y int) Color {
+ if !p.Rect.Contains(Point{x, y}) {
+ return RGBAColor{}
}
- return len(p.Pixel[0])
+ return p.Pix[y*p.Stride+x]
}
-func (p *RGBA) Height() int { return len(p.Pixel) }
-
-func (p *RGBA) At(x, y int) Color { return p.Pixel[y][x] }
-
-func (p *RGBA) Set(x, y int, c Color) { p.Pixel[y][x] = toRGBAColor(c).(RGBAColor) }
+func (p *RGBA) Set(x, y int, c Color) {
+ if !p.Rect.Contains(Point{x, y}) {
+ return
+ }
+ p.Pix[y*p.Stride+x] = toRGBAColor(c).(RGBAColor)
+}
// Opaque scans the entire image and returns whether or not it is fully opaque.
func (p *RGBA) Opaque() bool {
- h := len(p.Pixel)
- if h > 0 {
- w := len(p.Pixel[0])
- for y := 0; y < h; y++ {
- pix := p.Pixel[y]
- for x := 0; x < w; x++ {
- if pix[x].A != 0xff {
- return false
- }
+ if p.Rect.Empty() {
+ return true
+ }
+ base := p.Rect.Min.Y * p.Stride
+ i0, i1 := base+p.Rect.Min.X, base+p.Rect.Max.X
+ for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
+ for _, c := range p.Pix[i0:i1] {
+ if c.A != 0xff {
+ return false
}
}
+ i0 += p.Stride
+ i1 += p.Stride
}
return true
}
@@ -56,251 +73,343 @@ func (p *RGBA) Opaque() bool {
// NewRGBA returns a new RGBA with the given width and height.
func NewRGBA(w, h int) *RGBA {
buf := make([]RGBAColor, w*h)
- pix := make([][]RGBAColor, h)
- for y := range pix {
- pix[y] = buf[w*y : w*(y+1)]
- }
- return &RGBA{pix}
+ return &RGBA{buf, w, Rectangle{ZP, Point{w, h}}}
}
-// An RGBA64 is an in-memory image backed by a 2-D slice of RGBA64Color values.
+// An RGBA64 is an in-memory image of RGBA64Color values.
type RGBA64 struct {
- // The Pixel field's indices are y first, then x, so that At(x, y) == Pixel[y][x].
- Pixel [][]RGBA64Color
+ // Pix holds the image's pixels. The pixel at (x, y) is Pix[y*Stride+x].
+ Pix []RGBA64Color
+ Stride int
+ // Rect is the image's bounds.
+ Rect Rectangle
}
func (p *RGBA64) ColorModel() ColorModel { return RGBA64ColorModel }
-func (p *RGBA64) Width() int {
- if len(p.Pixel) == 0 {
- return 0
+func (p *RGBA64) Bounds() Rectangle { return p.Rect }
+
+func (p *RGBA64) At(x, y int) Color {
+ if !p.Rect.Contains(Point{x, y}) {
+ return RGBA64Color{}
}
- return len(p.Pixel[0])
+ return p.Pix[y*p.Stride+x]
}
-func (p *RGBA64) Height() int { return len(p.Pixel) }
-
-func (p *RGBA64) At(x, y int) Color { return p.Pixel[y][x] }
-
-func (p *RGBA64) Set(x, y int, c Color) { p.Pixel[y][x] = toRGBA64Color(c).(RGBA64Color) }
+func (p *RGBA64) Set(x, y int, c Color) {
+ if !p.Rect.Contains(Point{x, y}) {
+ return
+ }
+ p.Pix[y*p.Stride+x] = toRGBA64Color(c).(RGBA64Color)
+}
// Opaque scans the entire image and returns whether or not it is fully opaque.
func (p *RGBA64) Opaque() bool {
- h := len(p.Pixel)
- if h > 0 {
- w := len(p.Pixel[0])
- for y := 0; y < h; y++ {
- pix := p.Pixel[y]
- for x := 0; x < w; x++ {
- if pix[x].A != 0xffff {
- return false
- }
+ if p.Rect.Empty() {
+ return true
+ }
+ base := p.Rect.Min.Y * p.Stride
+ i0, i1 := base+p.Rect.Min.X, base+p.Rect.Max.X
+ for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
+ for _, c := range p.Pix[i0:i1] {
+ if c.A != 0xffff {
+ return false
}
}
+ i0 += p.Stride
+ i1 += p.Stride
}
return true
}
// NewRGBA64 returns a new RGBA64 with the given width and height.
func NewRGBA64(w, h int) *RGBA64 {
- buf := make([]RGBA64Color, w*h)
- pix := make([][]RGBA64Color, h)
- for y := range pix {
- pix[y] = buf[w*y : w*(y+1)]
- }
- return &RGBA64{pix}
+ pix := make([]RGBA64Color, w*h)
+ return &RGBA64{pix, w, Rectangle{ZP, Point{w, h}}}
}
-// A NRGBA is an in-memory image backed by a 2-D slice of NRGBAColor values.
+// An NRGBA is an in-memory image of NRGBAColor values.
type NRGBA struct {
- // The Pixel field's indices are y first, then x, so that At(x, y) == Pixel[y][x].
- Pixel [][]NRGBAColor
+ // Pix holds the image's pixels. The pixel at (x, y) is Pix[y*Stride+x].
+ Pix []NRGBAColor
+ Stride int
+ // Rect is the image's bounds.
+ Rect Rectangle
}
func (p *NRGBA) ColorModel() ColorModel { return NRGBAColorModel }
-func (p *NRGBA) Width() int {
- if len(p.Pixel) == 0 {
- return 0
+func (p *NRGBA) Bounds() Rectangle { return p.Rect }
+
+func (p *NRGBA) At(x, y int) Color {
+ if !p.Rect.Contains(Point{x, y}) {
+ return NRGBAColor{}
}
- return len(p.Pixel[0])
+ return p.Pix[y*p.Stride+x]
}
-func (p *NRGBA) Height() int { return len(p.Pixel) }
-
-func (p *NRGBA) At(x, y int) Color { return p.Pixel[y][x] }
-
-func (p *NRGBA) Set(x, y int, c Color) { p.Pixel[y][x] = toNRGBAColor(c).(NRGBAColor) }
+func (p *NRGBA) Set(x, y int, c Color) {
+ if !p.Rect.Contains(Point{x, y}) {
+ return
+ }
+ p.Pix[y*p.Stride+x] = toNRGBAColor(c).(NRGBAColor)
+}
// Opaque scans the entire image and returns whether or not it is fully opaque.
func (p *NRGBA) Opaque() bool {
- h := len(p.Pixel)
- if h > 0 {
- w := len(p.Pixel[0])
- for y := 0; y < h; y++ {
- pix := p.Pixel[y]
- for x := 0; x < w; x++ {
- if pix[x].A != 0xff {
- return false
- }
+ if p.Rect.Empty() {
+ return true
+ }
+ base := p.Rect.Min.Y * p.Stride
+ i0, i1 := base+p.Rect.Min.X, base+p.Rect.Max.X
+ for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
+ for _, c := range p.Pix[i0:i1] {
+ if c.A != 0xff {
+ return false
}
}
+ i0 += p.Stride
+ i1 += p.Stride
}
return true
}
// NewNRGBA returns a new NRGBA with the given width and height.
func NewNRGBA(w, h int) *NRGBA {
- buf := make([]NRGBAColor, w*h)
- pix := make([][]NRGBAColor, h)
- for y := range pix {
- pix[y] = buf[w*y : w*(y+1)]
- }
- return &NRGBA{pix}
+ pix := make([]NRGBAColor, w*h)
+ return &NRGBA{pix, w, Rectangle{ZP, Point{w, h}}}
}
-// A NRGBA64 is an in-memory image backed by a 2-D slice of NRGBA64Color values.
+// An NRGBA64 is an in-memory image of NRGBA64Color values.
type NRGBA64 struct {
- // The Pixel field's indices are y first, then x, so that At(x, y) == Pixel[y][x].
- Pixel [][]NRGBA64Color
+ // Pix holds the image's pixels. The pixel at (x, y) is Pix[y*Stride+x].
+ Pix []NRGBA64Color
+ Stride int
+ // Rect is the image's bounds.
+ Rect Rectangle
}
func (p *NRGBA64) ColorModel() ColorModel { return NRGBA64ColorModel }
-func (p *NRGBA64) Width() int {
- if len(p.Pixel) == 0 {
- return 0
+func (p *NRGBA64) Bounds() Rectangle { return p.Rect }
+
+func (p *NRGBA64) At(x, y int) Color {
+ if !p.Rect.Contains(Point{x, y}) {
+ return NRGBA64Color{}
}
- return len(p.Pixel[0])
+ return p.Pix[y*p.Stride+x]
}
-func (p *NRGBA64) Height() int { return len(p.Pixel) }
-
-func (p *NRGBA64) At(x, y int) Color { return p.Pixel[y][x] }
-
-func (p *NRGBA64) Set(x, y int, c Color) { p.Pixel[y][x] = toNRGBA64Color(c).(NRGBA64Color) }
+func (p *NRGBA64) Set(x, y int, c Color) {
+ if !p.Rect.Contains(Point{x, y}) {
+ return
+ }
+ p.Pix[y*p.Stride+x] = toNRGBA64Color(c).(NRGBA64Color)
+}
// Opaque scans the entire image and returns whether or not it is fully opaque.
func (p *NRGBA64) Opaque() bool {
- h := len(p.Pixel)
- if h > 0 {
- w := len(p.Pixel[0])
- for y := 0; y < h; y++ {
- pix := p.Pixel[y]
- for x := 0; x < w; x++ {
- if pix[x].A != 0xffff {
- return false
- }
+ if p.Rect.Empty() {
+ return true
+ }
+ base := p.Rect.Min.Y * p.Stride
+ i0, i1 := base+p.Rect.Min.X, base+p.Rect.Max.X
+ for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
+ for _, c := range p.Pix[i0:i1] {
+ if c.A != 0xffff {
+ return false
}
}
+ i0 += p.Stride
+ i1 += p.Stride
}
return true
}
// NewNRGBA64 returns a new NRGBA64 with the given width and height.
func NewNRGBA64(w, h int) *NRGBA64 {
- buf := make([]NRGBA64Color, w*h)
- pix := make([][]NRGBA64Color, h)
- for y := range pix {
- pix[y] = buf[w*y : w*(y+1)]
- }
- return &NRGBA64{pix}
+ pix := make([]NRGBA64Color, w*h)
+ return &NRGBA64{pix, w, Rectangle{ZP, Point{w, h}}}
}
-// An Alpha is an in-memory image backed by a 2-D slice of AlphaColor values.
+// An Alpha is an in-memory image of AlphaColor values.
type Alpha struct {
- // The Pixel field's indices are y first, then x, so that At(x, y) == Pixel[y][x].
- Pixel [][]AlphaColor
+ // Pix holds the image's pixels. The pixel at (x, y) is Pix[y*Stride+x].
+ Pix []AlphaColor
+ Stride int
+ // Rect is the image's bounds.
+ Rect Rectangle
}
func (p *Alpha) ColorModel() ColorModel { return AlphaColorModel }
-func (p *Alpha) Width() int {
- if len(p.Pixel) == 0 {
- return 0
+func (p *Alpha) Bounds() Rectangle { return p.Rect }
+
+func (p *Alpha) At(x, y int) Color {
+ if !p.Rect.Contains(Point{x, y}) {
+ return AlphaColor{}
}
- return len(p.Pixel[0])
+ return p.Pix[y*p.Stride+x]
}
-func (p *Alpha) Height() int { return len(p.Pixel) }
-
-func (p *Alpha) At(x, y int) Color { return p.Pixel[y][x] }
-
-func (p *Alpha) Set(x, y int, c Color) { p.Pixel[y][x] = toAlphaColor(c).(AlphaColor) }
+func (p *Alpha) Set(x, y int, c Color) {
+ if !p.Rect.Contains(Point{x, y}) {
+ return
+ }
+ p.Pix[y*p.Stride+x] = toAlphaColor(c).(AlphaColor)
+}
// Opaque scans the entire image and returns whether or not it is fully opaque.
func (p *Alpha) Opaque() bool {
- h := len(p.Pixel)
- if h > 0 {
- w := len(p.Pixel[0])
- for y := 0; y < h; y++ {
- pix := p.Pixel[y]
- for x := 0; x < w; x++ {
- if pix[x].A != 0xff {
- return false
- }
+ if p.Rect.Empty() {
+ return true
+ }
+ base := p.Rect.Min.Y * p.Stride
+ i0, i1 := base+p.Rect.Min.X, base+p.Rect.Max.X
+ for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
+ for _, c := range p.Pix[i0:i1] {
+ if c.A != 0xff {
+ return false
}
}
+ i0 += p.Stride
+ i1 += p.Stride
}
return true
}
// NewAlpha returns a new Alpha with the given width and height.
func NewAlpha(w, h int) *Alpha {
- buf := make([]AlphaColor, w*h)
- pix := make([][]AlphaColor, h)
- for y := range pix {
- pix[y] = buf[w*y : w*(y+1)]
- }
- return &Alpha{pix}
+ pix := make([]AlphaColor, w*h)
+ return &Alpha{pix, w, Rectangle{ZP, Point{w, h}}}
}
-// An Alpha16 is an in-memory image backed by a 2-D slice of Alpha16Color values.
+// An Alpha16 is an in-memory image of Alpha16Color values.
type Alpha16 struct {
- // The Pixel field's indices are y first, then x, so that At(x, y) == Pixel[y][x].
- Pixel [][]Alpha16Color
+ // Pix holds the image's pixels. The pixel at (x, y) is Pix[y*Stride+x].
+ Pix []Alpha16Color
+ Stride int
+ // Rect is the image's bounds.
+ Rect Rectangle
}
func (p *Alpha16) ColorModel() ColorModel { return Alpha16ColorModel }
-func (p *Alpha16) Width() int {
- if len(p.Pixel) == 0 {
- return 0
+func (p *Alpha16) Bounds() Rectangle { return p.Rect }
+
+func (p *Alpha16) At(x, y int) Color {
+ if !p.Rect.Contains(Point{x, y}) {
+ return Alpha16Color{}
}
- return len(p.Pixel[0])
+ return p.Pix[y*p.Stride+x]
}
-func (p *Alpha16) Height() int { return len(p.Pixel) }
-
-func (p *Alpha16) At(x, y int) Color { return p.Pixel[y][x] }
-
-func (p *Alpha16) Set(x, y int, c Color) { p.Pixel[y][x] = toAlpha16Color(c).(Alpha16Color) }
+func (p *Alpha16) Set(x, y int, c Color) {
+ if !p.Rect.Contains(Point{x, y}) {
+ return
+ }
+ p.Pix[y*p.Stride+x] = toAlpha16Color(c).(Alpha16Color)
+}
// Opaque scans the entire image and returns whether or not it is fully opaque.
func (p *Alpha16) Opaque() bool {
- h := len(p.Pixel)
- if h > 0 {
- w := len(p.Pixel[0])
- for y := 0; y < h; y++ {
- pix := p.Pixel[y]
- for x := 0; x < w; x++ {
- if pix[x].A != 0xffff {
- return false
- }
+ if p.Rect.Empty() {
+ return true
+ }
+ base := p.Rect.Min.Y * p.Stride
+ i0, i1 := base+p.Rect.Min.X, base+p.Rect.Max.X
+ for y := p.Rect.Min.Y; y < p.Rect.Max.Y; y++ {
+ for _, c := range p.Pix[i0:i1] {
+ if c.A != 0xffff {
+ return false
}
}
+ i0 += p.Stride
+ i1 += p.Stride
}
return true
}
// NewAlpha16 returns a new Alpha16 with the given width and height.
func NewAlpha16(w, h int) *Alpha16 {
- buf := make([]Alpha16Color, w*h)
- pix := make([][]Alpha16Color, h)
- for y := range pix {
- pix[y] = buf[w*y : w*(y+1)]
+ pix := make([]Alpha16Color, w*h)
+ return &Alpha16{pix, w, Rectangle{ZP, Point{w, h}}}
+}
+
+// A Gray is an in-memory image of GrayColor values.
+type Gray struct {
+ // Pix holds the image's pixels. The pixel at (x, y) is Pix[y*Stride+x].
+ Pix []GrayColor
+ Stride int
+ // Rect is the image's bounds.
+ Rect Rectangle
+}
+
+func (p *Gray) ColorModel() ColorModel { return GrayColorModel }
+
+func (p *Gray) Bounds() Rectangle { return p.Rect }
+
+func (p *Gray) At(x, y int) Color {
+ if !p.Rect.Contains(Point{x, y}) {
+ return GrayColor{}
}
- return &Alpha16{pix}
+ return p.Pix[y*p.Stride+x]
+}
+
+func (p *Gray) Set(x, y int, c Color) {
+ if !p.Rect.Contains(Point{x, y}) {
+ return
+ }
+ p.Pix[y*p.Stride+x] = toGrayColor(c).(GrayColor)
+}
+
+// Opaque scans the entire image and returns whether or not it is fully opaque.
+func (p *Gray) Opaque() bool {
+ return true
+}
+
+// NewGray returns a new Gray with the given width and height.
+func NewGray(w, h int) *Gray {
+ pix := make([]GrayColor, w*h)
+ return &Gray{pix, w, Rectangle{ZP, Point{w, h}}}
+}
+
+// A Gray16 is an in-memory image of Gray16Color values.
+type Gray16 struct {
+ // Pix holds the image's pixels. The pixel at (x, y) is Pix[y*Stride+x].
+ Pix []Gray16Color
+ Stride int
+ // Rect is the image's bounds.
+ Rect Rectangle
+}
+
+func (p *Gray16) ColorModel() ColorModel { return Gray16ColorModel }
+
+func (p *Gray16) Bounds() Rectangle { return p.Rect }
+
+func (p *Gray16) At(x, y int) Color {
+ if !p.Rect.Contains(Point{x, y}) {
+ return Gray16Color{}
+ }
+ return p.Pix[y*p.Stride+x]
+}
+
+func (p *Gray16) Set(x, y int, c Color) {
+ if !p.Rect.Contains(Point{x, y}) {
+ return
+ }
+ p.Pix[y*p.Stride+x] = toGray16Color(c).(Gray16Color)
+}
+
+// Opaque scans the entire image and returns whether or not it is fully opaque.
+func (p *Gray16) Opaque() bool {
+ return true
+}
+
+// NewGray16 returns a new Gray16 with the given width and height.
+func NewGray16(w, h int) *Gray16 {
+ pix := make([]Gray16Color, w*h)
+ return &Gray16{pix, w, Rectangle{ZP, Point{w, h}}}
}
// A PalettedColorModel represents a fixed palette of colors.
@@ -342,30 +451,41 @@ func (p PalettedColorModel) Convert(c Color) Color {
// A Paletted is an in-memory image backed by a 2-D slice of uint8 values and a PalettedColorModel.
type Paletted struct {
- // The Pixel field's indices are y first, then x, so that At(x, y) == Palette[Pixel[y][x]].
- Pixel [][]uint8
+ // Pix holds the image's pixels. The pixel at (x, y) is Pix[y*Stride+x].
+ Pix []uint8
+ Stride int
+ // Rect is the image's bounds.
+ Rect Rectangle
+ // Palette is the image's palette.
Palette PalettedColorModel
}
func (p *Paletted) ColorModel() ColorModel { return p.Palette }
-func (p *Paletted) Width() int {
- if len(p.Pixel) == 0 {
- return 0
+func (p *Paletted) Bounds() Rectangle { return p.Rect }
+
+func (p *Paletted) At(x, y int) Color {
+ if len(p.Palette) == 0 {
+ return nil
+ }
+ if !p.Rect.Contains(Point{x, y}) {
+ return p.Palette[0]
}
- return len(p.Pixel[0])
+ return p.Palette[p.Pix[y*p.Stride+x]]
}
-func (p *Paletted) Height() int { return len(p.Pixel) }
-
-func (p *Paletted) At(x, y int) Color { return p.Palette[p.Pixel[y][x]] }
-
func (p *Paletted) ColorIndexAt(x, y int) uint8 {
- return p.Pixel[y][x]
+ if !p.Rect.Contains(Point{x, y}) {
+ return 0
+ }
+ return p.Pix[y*p.Stride+x]
}
func (p *Paletted) SetColorIndex(x, y int, index uint8) {
- p.Pixel[y][x] = index
+ if !p.Rect.Contains(Point{x, y}) {
+ return
+ }
+ p.Pix[y*p.Stride+x] = index
}
// Opaque scans the entire image and returns whether or not it is fully opaque.
@@ -381,10 +501,6 @@ func (p *Paletted) Opaque() bool {
// NewPaletted returns a new Paletted with the given width, height and palette.
func NewPaletted(w, h int, m PalettedColorModel) *Paletted {
- buf := make([]uint8, w*h)
- pix := make([][]uint8, h)
- for y := range pix {
- pix[y] = buf[w*y : w*(y+1)]
- }
- return &Paletted{pix, m}
+ pix := make([]uint8, w*h)
+ return &Paletted{pix, w, Rectangle{ZP, Point{w, h}}, m}
}
diff --git a/src/pkg/image/jpeg/Makefile b/src/pkg/image/jpeg/Makefile
index c84811d6a..5c5f97e71 100644
--- a/src/pkg/image/jpeg/Makefile
+++ b/src/pkg/image/jpeg/Makefile
@@ -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 $(GOROOT)/src/Make.$(GOARCH)
+include ../../../Make.inc
TARG=image/jpeg
GOFILES=\
@@ -10,4 +10,4 @@ GOFILES=\
idct.go\
reader.go\
-include $(GOROOT)/src/Make.pkg
+include ../../../Make.pkg
diff --git a/src/pkg/image/jpeg/reader.go b/src/pkg/image/jpeg/reader.go
index ec036ef4d..fb9cb11bb 100644
--- a/src/pkg/image/jpeg/reader.go
+++ b/src/pkg/image/jpeg/reader.go
@@ -147,7 +147,6 @@ func (d *decoder) processSOF(n int) os.Error {
}
}
}
- d.image = image.NewRGBA(d.width, d.height)
return nil
}
@@ -206,7 +205,7 @@ func (d *decoder) calcPixel(px, py, lumaBlock, lumaIndex, chromaIndex int) {
} else if b > 255 {
b = 255
}
- d.image.Pixel[py][px] = image.RGBAColor{uint8(r), uint8(g), uint8(b), 0xff}
+ d.image.Pix[py*d.image.Stride+px] = image.RGBAColor{uint8(r), uint8(g), uint8(b), 0xff}
}
// Convert the MCU from YCbCr to RGB.
@@ -240,7 +239,7 @@ func (d *decoder) convertMCU(mx, my, h0, v0 int) {
// Specified in section B.2.3.
func (d *decoder) processSOS(n int) os.Error {
if d.image == nil {
- return FormatError("missing SOF segment")
+ d.image = image.NewRGBA(d.width, d.height)
}
if n != 4+2*nComponent {
return UnsupportedError("SOS has wrong length")
@@ -365,9 +364,8 @@ func (d *decoder) processDRI(n int) os.Error {
return nil
}
-// Decode reads a JPEG formatted image from r and returns it as an image.Image.
-func Decode(r io.Reader) (image.Image, os.Error) {
- var d decoder
+// decode reads a JPEG image from r and returns it as an image.Image.
+func (d *decoder) decode(r io.Reader, configOnly bool) (image.Image, os.Error) {
if rr, ok := r.(Reader); ok {
d.r = rr
} else {
@@ -411,6 +409,9 @@ func Decode(r io.Reader) (image.Image, os.Error) {
switch {
case marker == sof0Marker: // Start Of Frame (Baseline).
err = d.processSOF(n)
+ if configOnly {
+ return nil, err
+ }
case marker == sof2Marker: // Start Of Frame (Progressive).
err = UnsupportedError("progressive mode")
case marker == dhtMarker: // Define Huffman Table.
@@ -432,3 +433,23 @@ func Decode(r io.Reader) (image.Image, os.Error) {
}
return d.image, nil
}
+
+// Decode reads a JPEG image from r and returns it as an image.Image.
+func Decode(r io.Reader) (image.Image, os.Error) {
+ var d decoder
+ return d.decode(r, false)
+}
+
+// DecodeConfig returns the color model and dimensions of a JPEG image without
+// decoding the entire image.
+func DecodeConfig(r io.Reader) (image.Config, os.Error) {
+ var d decoder
+ if _, err := d.decode(r, true); err != nil {
+ return image.Config{}, err
+ }
+ return image.Config{image.RGBAColorModel, d.width, d.height}, nil
+}
+
+func init() {
+ image.RegisterFormat("jpeg", "\xff\xd8", Decode, DecodeConfig)
+}
diff --git a/src/pkg/image/names.go b/src/pkg/image/names.go
index 0b621cff5..c309684ce 100644
--- a/src/pkg/image/names.go
+++ b/src/pkg/image/names.go
@@ -4,53 +4,64 @@
package image
-// Colors from the HTML 4.01 specification: http://www.w3.org/TR/REC-html40/types.html#h-6.5
-// These names do not necessarily match those from other lists, such as the X11 color names.
var (
- Aqua = ColorImage{RGBAColor{0x00, 0xff, 0xff, 0xff}}
- Black = ColorImage{RGBAColor{0x00, 0x00, 0x00, 0xff}}
- Blue = ColorImage{RGBAColor{0x00, 0x00, 0xff, 0xff}}
- Fuchsia = ColorImage{RGBAColor{0xff, 0x00, 0xff, 0xff}}
- Gray = ColorImage{RGBAColor{0x80, 0x80, 0x80, 0xff}}
- Green = ColorImage{RGBAColor{0x00, 0x80, 0x00, 0xff}}
- Lime = ColorImage{RGBAColor{0x00, 0xff, 0x00, 0xff}}
- Maroon = ColorImage{RGBAColor{0x80, 0x00, 0x00, 0xff}}
- Navy = ColorImage{RGBAColor{0x00, 0x00, 0x80, 0xff}}
- Olive = ColorImage{RGBAColor{0x80, 0x80, 0x00, 0xff}}
- Red = ColorImage{RGBAColor{0xff, 0x00, 0x00, 0xff}}
- Purple = ColorImage{RGBAColor{0x80, 0x00, 0x80, 0xff}}
- Silver = ColorImage{RGBAColor{0xc0, 0xc0, 0xc0, 0xff}}
- Teal = ColorImage{RGBAColor{0x00, 0x80, 0x80, 0xff}}
- White = ColorImage{RGBAColor{0xff, 0xff, 0xff, 0xff}}
- Yellow = ColorImage{RGBAColor{0xff, 0xff, 0x00, 0xff}}
-
- // These synonyms are not in HTML 4.01.
- Cyan = Aqua
- Magenta = Fuchsia
+ // Black is an opaque black ColorImage.
+ Black = NewColorImage(Gray16Color{0})
+ // White is an opaque white ColorImage.
+ White = NewColorImage(Gray16Color{0xffff})
+ // Transparent is a fully transparent ColorImage.
+ Transparent = NewColorImage(Alpha16Color{0})
+ // Opaque is a fully opaque ColorImage.
+ Opaque = NewColorImage(Alpha16Color{0xffff})
)
-// A ColorImage is a practically infinite-sized Image of uniform Color.
+// A ColorImage is an infinite-sized Image of uniform Color.
// It implements both the Color and Image interfaces.
type ColorImage struct {
C Color
}
-func (c ColorImage) RGBA() (r, g, b, a uint32) {
+func (c *ColorImage) RGBA() (r, g, b, a uint32) {
return c.C.RGBA()
}
-func (c ColorImage) ColorModel() ColorModel {
+func (c *ColorImage) ColorModel() ColorModel {
return ColorModelFunc(func(Color) Color { return c.C })
}
-func (c ColorImage) Width() int { return 1e9 }
+func (c *ColorImage) Bounds() Rectangle { return Rectangle{Point{-1e9, -1e9}, Point{1e9, 1e9}} }
-func (c ColorImage) Height() int { return 1e9 }
-
-func (c ColorImage) At(x, y int) Color { return c.C }
+func (c *ColorImage) At(x, y int) Color { return c.C }
// Opaque scans the entire image and returns whether or not it is fully opaque.
-func (c ColorImage) Opaque() bool {
+func (c *ColorImage) Opaque() bool {
_, _, _, a := c.C.RGBA()
return a == 0xffff
}
+
+func NewColorImage(c Color) *ColorImage {
+ return &ColorImage{c}
+}
+
+// A Tiled is an infinite-sized Image that repeats another Image in both
+// directions. Tiled{i, p}.At(x, y) will equal i.At(x+p.X, y+p.Y) for all
+// points {x+p.X, y+p.Y} within i's Bounds.
+type Tiled struct {
+ I Image
+ Offset Point
+}
+
+func (t *Tiled) ColorModel() ColorModel {
+ return t.I.ColorModel()
+}
+
+func (t *Tiled) Bounds() Rectangle { return Rectangle{Point{-1e9, -1e9}, Point{1e9, 1e9}} }
+
+func (t *Tiled) At(x, y int) Color {
+ p := Point{x, y}.Add(t.Offset).Mod(t.I.Bounds())
+ return t.I.At(p.X, p.Y)
+}
+
+func NewTiled(i Image, offset Point) *Tiled {
+ return &Tiled{i, offset}
+}
diff --git a/src/pkg/image/png/Makefile b/src/pkg/image/png/Makefile
index 3ba0f44d3..4101f77e1 100644
--- a/src/pkg/image/png/Makefile
+++ b/src/pkg/image/png/Makefile
@@ -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 ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=image/png
GOFILES=\
diff --git a/src/pkg/image/png/reader.go b/src/pkg/image/png/reader.go
index fddb70423..e2d679bb4 100644
--- a/src/pkg/image/png/reader.go
+++ b/src/pkg/image/png/reader.go
@@ -9,6 +9,7 @@ package png
import (
"compress/zlib"
+ "fmt"
"hash"
"hash/crc32"
"image"
@@ -25,6 +26,18 @@ const (
ctTrueColorAlpha = 6
)
+// A cb is a combination of color type and bit depth.
+const (
+ cbInvalid = iota
+ cbG8
+ cbTC8
+ cbP8
+ cbTCA8
+ cbG16
+ cbTC16
+ cbTCA16
+)
+
// Filter type, as per the PNG spec.
const (
ftNone = 0
@@ -50,20 +63,25 @@ const (
const pngHeader = "\x89PNG\r\n\x1a\n"
+type imgOrErr struct {
+ img image.Image
+ err os.Error
+}
+
type decoder struct {
width, height int
- image image.Image
- colorType uint8
+ palette image.PalettedColorModel
+ cb int
stage int
idatWriter io.WriteCloser
- idatDone chan os.Error
+ idatDone chan imgOrErr
tmp [3 * 256]byte
}
// A FormatError reports that the input is not a valid PNG.
type FormatError string
-func (e FormatError) String() string { return "invalid PNG format: " + string(e) }
+func (e FormatError) String() string { return "png: invalid format: " + string(e) }
var chunkOrderError = FormatError("chunk out of order")
@@ -72,12 +90,12 @@ type IDATDecodingError struct {
Err os.Error
}
-func (e IDATDecodingError) String() string { return "IDAT decoding error: " + e.Err.String() }
+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 "unsupported PNG feature: " + string(e) }
+func (e UnsupportedError) String() string { return "png: unsupported feature: " + string(e) }
// Big-endian.
func parseUint32(b []uint8) uint32 {
@@ -107,9 +125,6 @@ func (d *decoder) parseIHDR(r io.Reader, crc hash.Hash32, length uint32) os.Erro
return err
}
crc.Write(d.tmp[0:13])
- if d.tmp[8] != 8 {
- return UnsupportedError("bit depth")
- }
if d.tmp[10] != 0 || d.tmp[11] != 0 || d.tmp[12] != 0 {
return UnsupportedError("compression, filter or interlace method")
}
@@ -122,16 +137,31 @@ func (d *decoder) parseIHDR(r io.Reader, crc hash.Hash32, length uint32) os.Erro
if nPixels != int64(int(nPixels)) {
return UnsupportedError("dimension overflow")
}
- d.colorType = d.tmp[9]
- switch d.colorType {
- case ctTrueColor:
- d.image = image.NewRGBA(int(w), int(h))
- case ctPaletted:
- d.image = image.NewPaletted(int(w), int(h), nil)
- case ctTrueColorAlpha:
- d.image = image.NewNRGBA(int(w), int(h))
- default:
- return UnsupportedError("color type")
+ d.cb = cbInvalid
+ switch d.tmp[8] {
+ case 8:
+ switch d.tmp[9] {
+ case ctGrayscale:
+ d.cb = cbG8
+ case ctTrueColor:
+ d.cb = cbTC8
+ case ctPaletted:
+ d.cb = cbP8
+ case ctTrueColorAlpha:
+ d.cb = cbTCA8
+ }
+ case 16:
+ switch d.tmp[9] {
+ case ctGrayscale:
+ d.cb = cbG16
+ case ctTrueColor:
+ d.cb = cbTC16
+ case ctTrueColorAlpha:
+ d.cb = cbTCA16
+ }
+ }
+ if d.cb == cbInvalid {
+ return UnsupportedError(fmt.Sprintf("bit depth %d, color type %d", d.tmp[8], d.tmp[9]))
}
d.width, d.height = int(w), int(h)
return nil
@@ -147,17 +177,15 @@ func (d *decoder) parsePLTE(r io.Reader, crc hash.Hash32, length uint32) os.Erro
return err
}
crc.Write(d.tmp[0:n])
- switch d.colorType {
- case ctPaletted:
- palette := make([]image.Color, np)
+ switch d.cb {
+ case cbP8:
+ d.palette = image.PalettedColorModel(make([]image.Color, np))
for i := 0; i < np; i++ {
- palette[i] = image.RGBAColor{d.tmp[3*i+0], d.tmp[3*i+1], d.tmp[3*i+2], 0xff}
+ d.palette[i] = image.RGBAColor{d.tmp[3*i+0], d.tmp[3*i+1], d.tmp[3*i+2], 0xff}
}
- d.image.(*image.Paletted).Palette = image.PalettedColorModel(palette)
- case ctTrueColor, ctTrueColorAlpha:
+ case cbTC8, cbTCA8, cbTC16, cbTCA16:
// As per the PNG spec, a PLTE chunk is optional (and for practical purposes,
// ignorable) for the ctTrueColor and ctTrueColorAlpha color types (section 4.1.2).
- return nil
default:
return FormatError("PLTE, color type mismatch")
}
@@ -173,19 +201,20 @@ func (d *decoder) parsetRNS(r io.Reader, crc hash.Hash32, length uint32) os.Erro
return err
}
crc.Write(d.tmp[0:n])
- switch d.colorType {
- case ctTrueColor:
- return UnsupportedError("TrueColor transparency")
- case ctPaletted:
- p := d.image.(*image.Paletted).Palette
- if n > len(p) {
+ switch d.cb {
+ case cbG8, cbG16:
+ return UnsupportedError("grayscale transparency")
+ case cbTC8, cbTC16:
+ return UnsupportedError("truecolor transparency")
+ case cbP8:
+ if n > len(d.palette) {
return FormatError("bad tRNS length")
}
for i := 0; i < n; i++ {
- rgba := p[i].(image.RGBAColor)
- p[i] = image.RGBAColor{rgba.R, rgba.G, rgba.B, d.tmp[i]}
+ rgba := d.palette[i].(image.RGBAColor)
+ d.palette[i] = image.RGBAColor{rgba.R, rgba.G, rgba.B, d.tmp[i]}
}
- case ctTrueColorAlpha:
+ case cbTCA8, cbTCA16:
return FormatError("tRNS, color type mismatch")
}
return nil
@@ -205,30 +234,54 @@ func paeth(a, b, c uint8) uint8 {
return c
}
-func (d *decoder) idatReader(idat io.Reader) os.Error {
+func (d *decoder) idatReader(idat io.Reader) (image.Image, os.Error) {
r, err := zlib.NewReader(idat)
if err != nil {
- return err
+ return nil, err
}
defer r.Close()
bpp := 0 // Bytes per pixel.
maxPalette := uint8(0)
var (
+ gray *image.Gray
rgba *image.RGBA
- nrgba *image.NRGBA
paletted *image.Paletted
+ nrgba *image.NRGBA
+ gray16 *image.Gray16
+ rgba64 *image.RGBA64
+ nrgba64 *image.NRGBA64
+ img image.Image
)
- switch d.colorType {
- case ctTrueColor:
+ switch d.cb {
+ case cbG8:
+ bpp = 1
+ gray = image.NewGray(d.width, d.height)
+ img = gray
+ case cbTC8:
bpp = 3
- rgba = d.image.(*image.RGBA)
- case ctPaletted:
+ rgba = image.NewRGBA(d.width, d.height)
+ img = rgba
+ case cbP8:
bpp = 1
- paletted = d.image.(*image.Paletted)
- maxPalette = uint8(len(paletted.Palette) - 1)
- case ctTrueColorAlpha:
+ paletted = image.NewPaletted(d.width, d.height, d.palette)
+ img = paletted
+ maxPalette = uint8(len(d.palette) - 1)
+ case cbTCA8:
bpp = 4
- nrgba = d.image.(*image.NRGBA)
+ nrgba = image.NewNRGBA(d.width, d.height)
+ img = nrgba
+ case cbG16:
+ bpp = 2
+ gray16 = image.NewGray16(d.width, d.height)
+ img = gray16
+ case cbTC16:
+ bpp = 6
+ rgba64 = image.NewRGBA64(d.width, d.height)
+ img = rgba64
+ case cbTCA16:
+ bpp = 8
+ nrgba64 = image.NewNRGBA64(d.width, d.height)
+ img = nrgba64
}
// cr and pr are the bytes for the current and previous row.
// The +1 is for the per-row filter type, which is at cr[0].
@@ -239,7 +292,7 @@ func (d *decoder) idatReader(idat io.Reader) os.Error {
// Read the decompressed bytes.
_, err := io.ReadFull(r, cr)
if err != nil {
- return err
+ return nil, err
}
// Apply the filter.
@@ -271,32 +324,56 @@ func (d *decoder) idatReader(idat io.Reader) os.Error {
cdat[i] += paeth(cdat[i-bpp], pdat[i], pdat[i-bpp])
}
default:
- return FormatError("bad filter type")
+ return nil, FormatError("bad filter type")
}
// Convert from bytes to colors.
- switch d.colorType {
- case ctTrueColor:
+ switch d.cb {
+ case cbG8:
+ for x := 0; x < d.width; x++ {
+ gray.Set(x, y, image.GrayColor{cdat[x]})
+ }
+ case cbTC8:
for x := 0; x < d.width; x++ {
rgba.Set(x, y, image.RGBAColor{cdat[3*x+0], cdat[3*x+1], cdat[3*x+2], 0xff})
}
- case ctPaletted:
+ case cbP8:
for x := 0; x < d.width; x++ {
if cdat[x] > maxPalette {
- return FormatError("palette index out of range")
+ return nil, FormatError("palette index out of range")
}
paletted.SetColorIndex(x, y, cdat[x])
}
- case ctTrueColorAlpha:
+ case cbTCA8:
for x := 0; x < d.width; x++ {
nrgba.Set(x, y, image.NRGBAColor{cdat[4*x+0], cdat[4*x+1], cdat[4*x+2], cdat[4*x+3]})
}
+ case cbG16:
+ for x := 0; x < d.width; x++ {
+ ycol := uint16(cdat[2*x+0])<<8 | uint16(cdat[2*x+1])
+ gray16.Set(x, y, image.Gray16Color{ycol})
+ }
+ case cbTC16:
+ for x := 0; x < d.width; x++ {
+ rcol := uint16(cdat[6*x+0])<<8 | uint16(cdat[6*x+1])
+ gcol := uint16(cdat[6*x+2])<<8 | uint16(cdat[6*x+3])
+ bcol := uint16(cdat[6*x+4])<<8 | uint16(cdat[6*x+5])
+ rgba64.Set(x, y, image.RGBA64Color{rcol, gcol, bcol, 0xffff})
+ }
+ case cbTCA16:
+ for x := 0; x < d.width; x++ {
+ rcol := uint16(cdat[8*x+0])<<8 | uint16(cdat[8*x+1])
+ gcol := uint16(cdat[8*x+2])<<8 | uint16(cdat[8*x+3])
+ bcol := uint16(cdat[8*x+4])<<8 | uint16(cdat[8*x+5])
+ acol := uint16(cdat[8*x+6])<<8 | uint16(cdat[8*x+7])
+ nrgba64.Set(x, y, image.NRGBA64Color{rcol, gcol, bcol, acol})
+ }
}
// The current row for y is the previous row for y+1.
pr, cr = cr, pr
}
- return nil
+ return img, nil
}
func (d *decoder) parseIDAT(r io.Reader, crc hash.Hash32, length uint32) os.Error {
@@ -308,14 +385,14 @@ func (d *decoder) parseIDAT(r io.Reader, crc hash.Hash32, length uint32) os.Erro
if d.idatWriter == nil {
pr, pw := io.Pipe()
d.idatWriter = pw
- d.idatDone = make(chan os.Error)
+ d.idatDone = make(chan imgOrErr)
go func() {
- err := d.idatReader(pr)
+ img, err := d.idatReader(pr)
if err == os.EOF {
err = FormatError("too little IDAT")
}
pr.CloseWithError(FormatError("too much IDAT"))
- d.idatDone <- err
+ d.idatDone <- imgOrErr{img, err}
}()
}
var buf [4096]byte
@@ -386,7 +463,7 @@ func (d *decoder) parseChunk(r io.Reader) os.Error {
}
err = d.parsetRNS(r, crc, length)
case "IDAT":
- if d.stage < dsSeenIHDR || d.stage > dsSeenIDAT || (d.colorType == ctPaletted && d.stage == dsSeenIHDR) {
+ if d.stage < dsSeenIHDR || d.stage > dsSeenIDAT || (d.cb == cbP8 && d.stage == dsSeenIHDR) {
return chunkOrderError
}
d.stage = dsSeenIDAT
@@ -438,7 +515,7 @@ func (d *decoder) checkHeader(r io.Reader) os.Error {
return nil
}
-// Decode reads a PNG formatted image from r and returns it as an image.Image.
+// 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
@@ -446,21 +523,66 @@ func Decode(r io.Reader) (image.Image, os.Error) {
if err != nil {
return nil, err
}
- for d.stage = dsStart; d.stage != dsSeenIEND; {
+ for d.stage != dsSeenIEND {
err = d.parseChunk(r)
if err != nil {
break
}
}
+ var img image.Image
if d.idatWriter != nil {
d.idatWriter.Close()
- err1 := <-d.idatDone
+ ie := <-d.idatDone
if err == nil {
- err = err1
+ img, err = ie.img, ie.err
}
}
if err != nil {
return nil, err
}
- return d.image, nil
+ return img, nil
+}
+
+// DecodeConfig returns the color model and dimensions of a PNG image without
+// decoding the entire image.
+func DecodeConfig(r io.Reader) (image.Config, os.Error) {
+ var d decoder
+ err := d.checkHeader(r)
+ if err != nil {
+ return image.Config{}, err
+ }
+ for {
+ err = d.parseChunk(r)
+ if err != nil {
+ return image.Config{}, err
+ }
+ if d.stage == dsSeenIHDR && d.cb != cbP8 {
+ break
+ }
+ if d.stage == dsSeenPLTE && d.cb == cbP8 {
+ break
+ }
+ }
+ var cm image.ColorModel
+ switch d.cb {
+ case cbG8:
+ cm = image.GrayColorModel
+ case cbTC8:
+ cm = image.RGBAColorModel
+ case cbP8:
+ cm = d.palette
+ case cbTCA8:
+ cm = image.NRGBAColorModel
+ case cbG16:
+ cm = image.Gray16ColorModel
+ case cbTC16:
+ cm = image.RGBA64ColorModel
+ case cbTCA16:
+ cm = image.NRGBA64ColorModel
+ }
+ return image.Config{cm, d.width, d.height}, nil
+}
+
+func init() {
+ image.RegisterFormat("png", pngHeader, Decode, DecodeConfig)
}
diff --git a/src/pkg/image/png/reader_test.go b/src/pkg/image/png/reader_test.go
index 1dc45992e..fefceee3a 100644
--- a/src/pkg/image/png/reader_test.go
+++ b/src/pkg/image/png/reader_test.go
@@ -14,23 +14,24 @@ import (
)
// The go PNG library currently supports only a subset of the full PNG specification.
-// In particular, bit depths other than 8 are not supported, and neither are grayscale images.
+// In particular, bit depths other than 8 or 16 are not supported, nor are grayscale-
+// alpha images.
var filenames = []string{
- //"basn0g01", // bit depth is not 8
- //"basn0g02", // bit depth is not 8
- //"basn0g04", // bit depth is not 8
- //"basn0g08", // grayscale color model
- //"basn0g16", // bit depth is not 8
+ //"basn0g01", // bit depth is not 8 or 16
+ //"basn0g02", // bit depth is not 8 or 16
+ //"basn0g04", // bit depth is not 8 or 16
+ "basn0g08",
+ "basn0g16",
"basn2c08",
- //"basn2c16", // bit depth is not 8
- //"basn3p01", // bit depth is not 8
- //"basn3p02", // bit depth is not 8
- //"basn3p04", // bit depth is not 8
+ "basn2c16",
+ //"basn3p01", // bit depth is not 8 or 16
+ //"basn3p02", // bit depth is not 8 or 16
+ //"basn3p04", // bit depth is not 8 or 16
"basn3p08",
- //"basn4a08", // grayscale color model
- //"basn4a16", // bit depth is not 8
+ //"basn4a08", // grayscale-alpha color model
+ //"basn4a16", // grayscale-alpha color model
"basn6a08",
- //"basn6a16", // bit depth is not 8
+ "basn6a16",
}
func readPng(filename string) (image.Image, os.Error) {
@@ -45,23 +46,34 @@ func readPng(filename string) (image.Image, os.Error) {
// An approximation of the sng command-line tool.
func sng(w io.WriteCloser, filename string, png image.Image) {
defer w.Close()
- // For now, the go PNG parser only reads bitdepths of 8.
- bitdepth := 8
+ bounds := png.Bounds()
+ cm := png.ColorModel()
+ var bitdepth int
+ switch cm {
+ case image.RGBAColorModel, image.NRGBAColorModel, image.AlphaColorModel, image.GrayColorModel:
+ bitdepth = 8
+ default:
+ bitdepth = 16
+ }
+ cpm, _ := cm.(image.PalettedColorModel)
+ var paletted *image.Paletted
+ if cpm != nil {
+ bitdepth = 8
+ paletted = png.(*image.Paletted)
+ }
// Write the filename and IHDR.
io.WriteString(w, "#SNG: from "+filename+".png\nIHDR {\n")
- fmt.Fprintf(w, " width: %d; height: %d; bitdepth: %d;\n", png.Width(), png.Height(), bitdepth)
- cm := png.ColorModel()
- var paletted *image.Paletted
- cpm, _ := cm.(image.PalettedColorModel)
+ fmt.Fprintf(w, " width: %d; height: %d; bitdepth: %d;\n", bounds.Dx(), bounds.Dy(), bitdepth)
switch {
- case cm == image.RGBAColorModel:
+ case cm == image.RGBAColorModel, cm == image.RGBA64ColorModel:
io.WriteString(w, " using color;\n")
- case cm == image.NRGBAColorModel:
+ case cm == image.NRGBAColorModel, cm == image.NRGBA64ColorModel:
io.WriteString(w, " using color alpha;\n")
+ case cm == image.GrayColorModel, cm == image.Gray16ColorModel:
+ io.WriteString(w, " using grayscale;\n")
case cpm != nil:
io.WriteString(w, " using color palette;\n")
- paletted = png.(*image.Paletted)
default:
io.WriteString(w, "unknown PNG decoder color model\n")
}
@@ -86,20 +98,40 @@ func sng(w io.WriteCloser, filename string, png image.Image) {
// Write the IMAGE.
io.WriteString(w, "IMAGE {\n pixels hex\n")
- for y := 0; y < png.Height(); y++ {
+ for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
switch {
+ case cm == image.GrayColorModel:
+ for x := bounds.Min.X; x < bounds.Max.X; x++ {
+ gray := png.At(x, y).(image.GrayColor)
+ fmt.Fprintf(w, "%02x", gray.Y)
+ }
+ case cm == image.Gray16ColorModel:
+ for x := bounds.Min.X; x < bounds.Max.X; x++ {
+ gray16 := png.At(x, y).(image.Gray16Color)
+ fmt.Fprintf(w, "%04x ", gray16.Y)
+ }
case cm == image.RGBAColorModel:
- for x := 0; x < png.Width(); x++ {
+ for x := bounds.Min.X; x < bounds.Max.X; x++ {
rgba := png.At(x, y).(image.RGBAColor)
fmt.Fprintf(w, "%02x%02x%02x ", rgba.R, rgba.G, rgba.B)
}
+ case cm == image.RGBA64ColorModel:
+ for x := bounds.Min.X; x < bounds.Max.X; x++ {
+ rgba64 := png.At(x, y).(image.RGBA64Color)
+ fmt.Fprintf(w, "%04x%04x%04x ", rgba64.R, rgba64.G, rgba64.B)
+ }
case cm == image.NRGBAColorModel:
- for x := 0; x < png.Width(); x++ {
+ for x := bounds.Min.X; x < bounds.Max.X; x++ {
nrgba := png.At(x, y).(image.NRGBAColor)
fmt.Fprintf(w, "%02x%02x%02x%02x ", nrgba.R, nrgba.G, nrgba.B, nrgba.A)
}
+ case cm == image.NRGBA64ColorModel:
+ for x := bounds.Min.X; x < bounds.Max.X; x++ {
+ nrgba64 := png.At(x, y).(image.NRGBA64Color)
+ fmt.Fprintf(w, "%04x%04x%04x%04x ", nrgba64.R, nrgba64.G, nrgba64.B, nrgba64.A)
+ }
case cpm != nil:
- for x := 0; x < png.Width(); x++ {
+ for x := bounds.Min.X; x < bounds.Max.X; x++ {
fmt.Fprintf(w, "%02x", paletted.ColorIndexAt(x, y))
}
}
diff --git a/src/pkg/image/png/writer.go b/src/pkg/image/png/writer.go
index e186ca819..081d06bf5 100644
--- a/src/pkg/image/png/writer.go
+++ b/src/pkg/image/png/writer.go
@@ -15,13 +15,13 @@ import (
)
type encoder struct {
- w io.Writer
- m image.Image
- colorType uint8
- err os.Error
- header [8]byte
- footer [4]byte
- tmp [3 * 256]byte
+ w io.Writer
+ m image.Image
+ cb int
+ err os.Error
+ header [8]byte
+ footer [4]byte
+ tmp [3 * 256]byte
}
// Big-endian.
@@ -32,10 +32,18 @@ func writeUint32(b []uint8, u uint32) {
b[3] = uint8(u >> 0)
}
+type opaquer interface {
+ Opaque() bool
+}
+
// Returns whether or not the image is fully opaque.
func opaque(m image.Image) bool {
- for y := 0; y < m.Height(); y++ {
- for x := 0; x < m.Width(); x++ {
+ if o, ok := m.(opaquer); ok {
+ return o.Opaque()
+ }
+ b := m.Bounds()
+ for y := b.Min.Y; y < b.Max.Y; y++ {
+ for x := b.Min.X; x < b.Max.X; x++ {
_, _, _, a := m.At(x, y).RGBA()
if a != 0xffff {
return false
@@ -84,10 +92,33 @@ func (e *encoder) writeChunk(b []byte, name string) {
}
func (e *encoder) writeIHDR() {
- writeUint32(e.tmp[0:4], uint32(e.m.Width()))
- writeUint32(e.tmp[4:8], uint32(e.m.Height()))
- e.tmp[8] = 8 // bit depth
- e.tmp[9] = e.colorType
+ b := e.m.Bounds()
+ writeUint32(e.tmp[0:4], uint32(b.Dx()))
+ writeUint32(e.tmp[4:8], uint32(b.Dy()))
+ // Set bit depth and color type.
+ switch e.cb {
+ case cbG8:
+ e.tmp[8] = 8
+ e.tmp[9] = ctGrayscale
+ case cbTC8:
+ e.tmp[8] = 8
+ e.tmp[9] = ctTrueColor
+ case cbP8:
+ e.tmp[8] = 8
+ e.tmp[9] = ctPaletted
+ case cbTCA8:
+ e.tmp[8] = 8
+ e.tmp[9] = ctTrueColorAlpha
+ case cbG16:
+ e.tmp[8] = 16
+ e.tmp[9] = ctGrayscale
+ case cbTC16:
+ e.tmp[8] = 16
+ e.tmp[9] = ctTrueColor
+ case cbTCA16:
+ e.tmp[8] = 16
+ e.tmp[9] = ctTrueColorAlpha
+ }
e.tmp[10] = 0 // default compression method
e.tmp[11] = 0 // default filter method
e.tmp[12] = 0 // non-interlaced
@@ -224,7 +255,7 @@ func filter(cr [][]byte, pr []byte, bpp int) int {
return filter
}
-func writeImage(w io.Writer, m image.Image, ct uint8) os.Error {
+func writeImage(w io.Writer, m image.Image, cb int) os.Error {
zw, err := zlib.NewWriter(w)
if err != nil {
return err
@@ -233,51 +264,94 @@ func writeImage(w io.Writer, m image.Image, ct uint8) os.Error {
bpp := 0 // Bytes per pixel.
var paletted *image.Paletted
- switch ct {
- case ctTrueColor:
+ switch cb {
+ case cbG8:
+ bpp = 1
+ case cbTC8:
bpp = 3
- case ctPaletted:
+ case cbP8:
bpp = 1
paletted = m.(*image.Paletted)
- case ctTrueColorAlpha:
+ case cbTCA8:
bpp = 4
+ case cbTC16:
+ bpp = 6
+ case cbTCA16:
+ bpp = 8
+ case cbG16:
+ bpp = 2
}
// cr[*] and pr are the bytes for the current and previous row.
// cr[0] is unfiltered (or equivalently, filtered with the ftNone filter).
// cr[ft], for non-zero filter types ft, are buffers for transforming cr[0] under the
// other PNG filter types. These buffers are allocated once and re-used for each row.
// The +1 is for the per-row filter type, which is at cr[*][0].
+ b := m.Bounds()
var cr [nFilter][]uint8
for i := 0; i < len(cr); i++ {
- cr[i] = make([]uint8, 1+bpp*m.Width())
+ cr[i] = make([]uint8, 1+bpp*b.Dx())
cr[i][0] = uint8(i)
}
- pr := make([]uint8, 1+bpp*m.Width())
+ pr := make([]uint8, 1+bpp*b.Dx())
- for y := 0; y < m.Height(); y++ {
+ for y := b.Min.Y; y < b.Max.Y; y++ {
// Convert from colors to bytes.
- switch ct {
- case ctTrueColor:
- for x := 0; x < m.Width(); x++ {
+ switch cb {
+ case cbG8:
+ for x := b.Min.X; x < b.Max.X; x++ {
+ c := image.GrayColorModel.Convert(m.At(x, y)).(image.GrayColor)
+ cr[0][x+1] = c.Y
+ }
+ case cbTC8:
+ for x := b.Min.X; x < b.Max.X; x++ {
// We have previously verified that the alpha value is fully opaque.
r, g, b, _ := m.At(x, y).RGBA()
cr[0][3*x+1] = uint8(r >> 8)
cr[0][3*x+2] = uint8(g >> 8)
cr[0][3*x+3] = uint8(b >> 8)
}
- case ctPaletted:
- for x := 0; x < m.Width(); x++ {
- cr[0][x+1] = paletted.ColorIndexAt(x, y)
- }
- case ctTrueColorAlpha:
+ case cbP8:
+ rowOffset := y * paletted.Stride
+ copy(cr[0][b.Min.X+1:], paletted.Pix[rowOffset+b.Min.X:rowOffset+b.Max.X])
+ case cbTCA8:
// Convert from image.Image (which is alpha-premultiplied) to PNG's non-alpha-premultiplied.
- for x := 0; x < m.Width(); x++ {
+ for x := b.Min.X; x < b.Max.X; x++ {
c := image.NRGBAColorModel.Convert(m.At(x, y)).(image.NRGBAColor)
cr[0][4*x+1] = c.R
cr[0][4*x+2] = c.G
cr[0][4*x+3] = c.B
cr[0][4*x+4] = c.A
}
+ case cbG16:
+ for x := b.Min.X; x < b.Max.X; x++ {
+ c := image.Gray16ColorModel.Convert(m.At(x, y)).(image.Gray16Color)
+ cr[0][2*x+1] = uint8(c.Y >> 8)
+ cr[0][2*x+2] = uint8(c.Y)
+ }
+ case cbTC16:
+ for x := b.Min.X; x < b.Max.X; x++ {
+ // We have previously verified that the alpha value is fully opaque.
+ r, g, b, _ := m.At(x, y).RGBA()
+ cr[0][6*x+1] = uint8(r >> 8)
+ cr[0][6*x+2] = uint8(r)
+ cr[0][6*x+3] = uint8(g >> 8)
+ cr[0][6*x+4] = uint8(g)
+ cr[0][6*x+5] = uint8(b >> 8)
+ cr[0][6*x+6] = uint8(b)
+ }
+ case cbTCA16:
+ // Convert from image.Image (which is alpha-premultiplied) to PNG's non-alpha-premultiplied.
+ for x := b.Min.X; x < b.Max.X; x++ {
+ c := image.NRGBA64ColorModel.Convert(m.At(x, y)).(image.NRGBA64Color)
+ cr[0][8*x+1] = uint8(c.R >> 8)
+ cr[0][8*x+2] = uint8(c.R)
+ cr[0][8*x+3] = uint8(c.G >> 8)
+ cr[0][8*x+4] = uint8(c.G)
+ cr[0][8*x+5] = uint8(c.B >> 8)
+ cr[0][8*x+6] = uint8(c.B)
+ cr[0][8*x+7] = uint8(c.A >> 8)
+ cr[0][8*x+8] = uint8(c.A)
+ }
}
// Apply the filter.
@@ -305,7 +379,7 @@ func (e *encoder) writeIDATs() {
if e.err != nil {
return
}
- e.err = writeImage(bw, e.m, e.colorType)
+ e.err = writeImage(bw, e.m, e.cb)
if e.err != nil {
return
}
@@ -320,7 +394,7 @@ func Encode(w io.Writer, m image.Image) os.Error {
// Obviously, negative widths and heights are invalid. Furthermore, the PNG
// spec section 11.2.2 says that zero is invalid. Excessively large images are
// also rejected.
- mw, mh := int64(m.Width()), int64(m.Height())
+ 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))
}
@@ -328,12 +402,28 @@ func Encode(w io.Writer, m image.Image) os.Error {
var e encoder
e.w = w
e.m = m
- e.colorType = uint8(ctTrueColorAlpha)
pal, _ := m.(*image.Paletted)
if pal != nil {
- e.colorType = ctPaletted
- } else if opaque(m) {
- e.colorType = ctTrueColor
+ e.cb = cbP8
+ } else {
+ switch m.ColorModel() {
+ case image.GrayColorModel:
+ e.cb = cbG8
+ case image.Gray16ColorModel:
+ e.cb = cbG16
+ case image.RGBAColorModel, image.NRGBAColorModel, image.AlphaColorModel:
+ if opaque(m) {
+ e.cb = cbTC8
+ } else {
+ e.cb = cbTCA8
+ }
+ default:
+ if opaque(m) {
+ e.cb = cbTC16
+ } else {
+ e.cb = cbTCA16
+ }
+ }
}
_, e.err = io.WriteString(w, pngHeader)
diff --git a/src/pkg/image/png/writer_test.go b/src/pkg/image/png/writer_test.go
index a61e1c95a..f218a5564 100644
--- a/src/pkg/image/png/writer_test.go
+++ b/src/pkg/image/png/writer_test.go
@@ -5,6 +5,7 @@
package png
import (
+ "bytes"
"fmt"
"image"
"io"
@@ -13,15 +14,16 @@ import (
)
func diff(m0, m1 image.Image) os.Error {
- if m0.Width() != m1.Width() || m0.Height() != m1.Height() {
- return os.NewError(fmt.Sprintf("dimensions differ: %dx%d vs %dx%d", m0.Width(), m0.Height(), m1.Width(), m1.Height()))
+ b0, b1 := m0.Bounds(), m1.Bounds()
+ if !b0.Eq(b1) {
+ return fmt.Errorf("dimensions differ: %v vs %v", b0, b1)
}
- for y := 0; y < m0.Height(); y++ {
- for x := 0; x < m0.Width(); x++ {
+ for y := b0.Min.Y; y < b0.Max.Y; y++ {
+ for x := b0.Min.X; x < b0.Max.X; x++ {
r0, g0, b0, a0 := m0.At(x, y).RGBA()
r1, g1, b1, a1 := m1.At(x, y).RGBA()
if r0 != r1 || g0 != g1 || b0 != b1 || a0 != a1 {
- return os.NewError(fmt.Sprintf("colors differ at (%d, %d): %v vs %v", x, y, m0.At(x, y), m1.At(x, y)))
+ return fmt.Errorf("colors differ at (%d, %d): %v vs %v", x, y, m0.At(x, y), m1.At(x, y))
}
}
}
@@ -67,3 +69,18 @@ func TestWriter(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},
+ })
+ b.StartTimer()
+ buffer := new(bytes.Buffer)
+ for i := 0; i < b.N; i++ {
+ buffer.Reset()
+ Encode(buffer, img)
+ }
+}
diff --git a/src/pkg/index/suffixarray/Makefile b/src/pkg/index/suffixarray/Makefile
new file mode 100644
index 000000000..297c4279f
--- /dev/null
+++ b/src/pkg/index/suffixarray/Makefile
@@ -0,0 +1,12 @@
+# Copyright 2010 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+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
new file mode 100644
index 000000000..0e6894a8b
--- /dev/null
+++ b/src/pkg/index/suffixarray/qsufsort.go
@@ -0,0 +1,164 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This algorithm is based on "Faster Suffix Sorting"
+// by N. Jesper Larsson and Kunihiko Sadakane
+// paper: http://www.larsson.dogma.net/ssrev-tr.pdf
+// code: http://www.larsson.dogma.net/qsufsort.c
+
+// This algorithm computes the suffix array sa by computing its inverse.
+// Consecutive groups of suffixes in sa are labeled as sorted groups or
+// unsorted groups. For a given pass of the sorter, all suffixes are ordered
+// up to their first h characters, and sa is h-ordered. Suffixes in their
+// final positions and unambiguouly sorted in h-order are in a sorted group.
+// Consecutive groups of suffixes with identical first h characters are an
+// unsorted group. In each pass of the algorithm, unsorted groups are sorted
+// according to the group number of their following suffix.
+
+// In the implementation, if sa[i] is negative, it indicates that i is
+// the first element of a sorted group of length -sa[i], and can be skipped.
+// An unsorted group sa[i:k] is given the group number of the index of its
+// last element, k-1. The group numbers are stored in the inverse slice (inv),
+// and when all groups are sorted, this slice is the inverse suffix array.
+
+package suffixarray
+
+import "sort"
+
+func qsufsort(data []byte) []int {
+ // initial sorting by first byte of suffix
+ sa := sortedByFirstByte(data)
+ if len(sa) < 2 {
+ return sa
+ }
+ // initialize the group lookup table
+ // this becomes the inverse of the suffix array when all groups are sorted
+ inv := initGroups(sa, data)
+
+ // the index starts 1-ordered
+ sufSortable := &suffixSortable{sa, inv, 1}
+
+ for sa[0] > -len(sa) { // until all suffixes are one big sorted group
+ // The suffixes are h-ordered, make them 2*h-ordered
+ pi := 0 // pi is first position of first group
+ sl := 0 // sl is negated length of sorted groups
+ for pi < len(sa) {
+ if s := sa[pi]; s < 0 { // if pi starts sorted group
+ pi -= s // skip over sorted group
+ sl += s // add negated length to sl
+ } else { // if pi starts unsorted group
+ if sl != 0 {
+ sa[pi+sl] = sl // combine sorted groups before pi
+ sl = 0
+ }
+ pk := inv[s] + 1 // pk-1 is last position of unsorted group
+ sufSortable.sa = sa[pi:pk]
+ sort.Sort(sufSortable)
+ sufSortable.updateGroups(pi)
+ pi = pk // next group
+ }
+ }
+ if sl != 0 { // if the array ends with a sorted group
+ sa[pi+sl] = sl // combine sorted groups at end of sa
+ }
+
+ sufSortable.h *= 2 // double sorted depth
+ }
+
+ for i := range sa { // reconstruct suffix array from inverse
+ sa[inv[i]] = i
+ }
+ return sa
+}
+
+
+func sortedByFirstByte(data []byte) []int {
+ // total byte counts
+ var count [256]int
+ for _, b := range data {
+ count[b]++
+ }
+ // make count[b] equal index of first occurence of b in sorted array
+ sum := 0
+ for b := range count {
+ count[b], sum = sum, count[b]+sum
+ }
+ // iterate through bytes, placing index into the correct spot in sa
+ sa := make([]int, len(data))
+ for i, b := range data {
+ sa[count[b]] = i
+ count[b]++
+ }
+ return sa
+}
+
+
+func initGroups(sa []int, data []byte) []int {
+ // label contiguous same-letter groups with the same group number
+ inv := make([]int, len(data))
+ prevGroup := len(sa) - 1
+ groupByte := data[sa[prevGroup]]
+ for i := len(sa) - 1; i >= 0; i-- {
+ if b := data[sa[i]]; b < groupByte {
+ if prevGroup == i+1 {
+ sa[i+1] = -1
+ }
+ groupByte = b
+ prevGroup = i
+ }
+ inv[sa[i]] = prevGroup
+ if prevGroup == 0 {
+ sa[0] = -1
+ }
+ }
+ // Separate out the final suffix to the start of its group.
+ // This is necessary to ensure the suffix "a" is before "aba"
+ // when using a potentially unstable sort.
+ lastByte := data[len(data)-1]
+ s := -1
+ for i := range sa {
+ if sa[i] >= 0 {
+ if data[sa[i]] == lastByte && s == -1 {
+ s = i
+ }
+ if sa[i] == len(sa)-1 {
+ sa[i], sa[s] = sa[s], sa[i]
+ inv[sa[s]] = s
+ sa[s] = -1 // mark it as an isolated sorted group
+ break
+ }
+ }
+ }
+ return inv
+}
+
+
+type suffixSortable struct {
+ sa []int
+ inv []int
+ h int
+}
+
+func (x *suffixSortable) Len() int { return len(x.sa) }
+func (x *suffixSortable) Less(i, j int) bool { return x.inv[x.sa[i]+x.h] < x.inv[x.sa[j]+x.h] }
+func (x *suffixSortable) Swap(i, j int) { x.sa[i], x.sa[j] = x.sa[j], x.sa[i] }
+
+
+func (x *suffixSortable) updateGroups(offset int) {
+ prev := len(x.sa) - 1
+ group := x.inv[x.sa[prev]+x.h]
+ for i := prev; i >= 0; i-- {
+ if g := x.inv[x.sa[i]+x.h]; g < group {
+ if prev == i+1 { // previous group had size 1 and is thus sorted
+ x.sa[i+1] = -1
+ }
+ group = g
+ prev = i
+ }
+ x.inv[x.sa[i]] = prev + offset
+ if prev == 0 { // first group has size 1 and is thus sorted
+ x.sa[0] = -1
+ }
+ }
+}
diff --git a/src/pkg/index/suffixarray/suffixarray.go b/src/pkg/index/suffixarray/suffixarray.go
new file mode 100644
index 000000000..628e000e1
--- /dev/null
+++ b/src/pkg/index/suffixarray/suffixarray.go
@@ -0,0 +1,182 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The suffixarray package implements substring search in logarithmic time
+// using an in-memory suffix array.
+//
+// Example use:
+//
+// // create index for some data
+// index := suffixarray.New(data)
+//
+// // lookup byte slice s
+// offsets1 := index.Lookup(s, -1) // the list of all indices where s occurs in data
+// offsets2 := index.Lookup(s, 3) // the list of at most 3 indices where s occurs in data
+//
+package suffixarray
+
+import (
+ "bytes"
+ "regexp"
+ "sort"
+)
+
+
+// Index implements a suffix array for fast substring search.
+type Index struct {
+ data []byte
+ sa []int // suffix array for data
+}
+
+
+// New creates a new Index for data.
+// Index creation time is O(N*log(N)) for N = len(data).
+func New(data []byte) *Index {
+ return &Index{data, qsufsort(data)}
+}
+
+
+// Bytes returns the data over which the index was created.
+// It must not be modified.
+//
+func (x *Index) Bytes() []byte {
+ return x.data
+}
+
+
+func (x *Index) at(i int) []byte {
+ return x.data[x.sa[i]:]
+}
+
+
+func (x *Index) search(s []byte) int {
+ return sort.Search(len(x.sa), func(i int) bool { return bytes.Compare(x.at(i), s) >= 0 })
+}
+
+
+// Lookup returns an unsorted list of at most n indices where the byte string s
+// occurs in the indexed data. If n < 0, all occurrences are returned.
+// The result is nil if s is empty, s is not found, or n == 0.
+// Lookup time is O((log(N) + len(result))*len(s)) where N is the
+// size of the indexed data.
+//
+func (x *Index) Lookup(s []byte, n int) (result []int) {
+ if len(s) > 0 && n != 0 {
+ // find matching suffix index i
+ i := x.search(s)
+ // x.at(i-1) < s <= x.at(i)
+
+ // collect the following suffixes with matching prefixes
+ for (n < 0 || len(result) < n) && i < len(x.sa) && bytes.HasPrefix(x.at(i), s) {
+ result = append(result, x.sa[i])
+ i++
+ }
+ }
+ return
+}
+
+
+// FindAllIndex returns a sorted list of non-overlapping matches of the
+// regular expression r, where a match is a pair of indices specifying
+// the matched slice of x.Bytes(). If n < 0, all matches are returned
+// in successive order. Otherwise, at most n matches are returned and
+// they may not be successive. The result is nil if there are no matches,
+// or if n == 0.
+//
+func (x *Index) FindAllIndex(r *regexp.Regexp, n int) (result [][]int) {
+ // a non-empty literal prefix is used to determine possible
+ // match start indices with Lookup
+ prefix, complete := r.LiteralPrefix()
+ lit := []byte(prefix)
+
+ // worst-case scenario: no literal prefix
+ if prefix == "" {
+ return r.FindAllIndex(x.data, n)
+ }
+
+ // if regexp is a literal just use Lookup and convert its
+ // result into match pairs
+ if complete {
+ // Lookup returns indices that may belong to overlapping matches.
+ // After eliminating them, we may end up with fewer than n matches.
+ // If we don't have enough at the end, redo the search with an
+ // increased value n1, but only if Lookup returned all the requested
+ // indices in the first place (if it returned fewer than that then
+ // there cannot be more).
+ for n1 := n; ; n1 += 2 * (n - len(result)) /* overflow ok */ {
+ indices := x.Lookup(lit, n1)
+ if len(indices) == 0 {
+ return
+ }
+ sort.SortInts(indices)
+ pairs := make([]int, 2*len(indices))
+ result = make([][]int, len(indices))
+ count := 0
+ prev := 0
+ for _, i := range indices {
+ if count == n {
+ break
+ }
+ // ignore indices leading to overlapping matches
+ if prev <= i {
+ j := 2 * count
+ pairs[j+0] = i
+ pairs[j+1] = i + len(lit)
+ result[count] = pairs[j : j+2]
+ count++
+ prev = i + len(lit)
+ }
+ }
+ result = result[0:count]
+ if len(result) >= n || len(indices) != n1 {
+ // found all matches or there's no chance to find more
+ // (n and n1 can be negative)
+ break
+ }
+ }
+ if len(result) == 0 {
+ result = nil
+ }
+ return
+ }
+
+ // regexp has a non-empty literal prefix; Lookup(lit) computes
+ // the indices of possible complete matches; use these as starting
+ // points for anchored searches
+ // (regexp "^" matches beginning of input, not beginning of line)
+ r = regexp.MustCompile("^" + r.String()) // compiles because r compiled
+
+ // same comment about Lookup applies here as in the loop above
+ for n1 := n; ; n1 += 2 * (n - len(result)) /* overflow ok */ {
+ indices := x.Lookup(lit, n1)
+ if len(indices) == 0 {
+ return
+ }
+ sort.SortInts(indices)
+ result = result[0:0]
+ prev := 0
+ for _, i := range indices {
+ if len(result) == n {
+ break
+ }
+ m := r.FindIndex(x.data[i:]) // anchored search - will not run off
+ // ignore indices leading to overlapping matches
+ if m != nil && prev <= i {
+ m[0] = i // correct m
+ m[1] += i
+ result = append(result, m)
+ prev = m[1]
+ }
+ }
+ if len(result) >= n || len(indices) != n1 {
+ // found all matches or there's no chance to find more
+ // (n and n1 can be negative)
+ break
+ }
+ }
+ if len(result) == 0 {
+ result = nil
+ }
+ return
+}
diff --git a/src/pkg/index/suffixarray/suffixarray_test.go b/src/pkg/index/suffixarray/suffixarray_test.go
new file mode 100644
index 000000000..b3486a96d
--- /dev/null
+++ b/src/pkg/index/suffixarray/suffixarray_test.go
@@ -0,0 +1,234 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package suffixarray
+
+import (
+ "bytes"
+ "container/vector"
+ "regexp"
+ "sort"
+ "strings"
+ "testing"
+)
+
+
+type testCase struct {
+ name string // name of test case
+ source string // source to index
+ patterns []string // patterns to lookup
+}
+
+
+var testCases = []testCase{
+ {
+ "empty string",
+ "",
+ []string{
+ "",
+ "foo",
+ "(foo)",
+ ".*",
+ "a*",
+ },
+ },
+
+ {
+ "all a's",
+ "aaaaaaaaaa", // 10 a's
+ []string{
+ "",
+ "a",
+ "aa",
+ "aaa",
+ "aaaa",
+ "aaaaa",
+ "aaaaaa",
+ "aaaaaaa",
+ "aaaaaaaa",
+ "aaaaaaaaa",
+ "aaaaaaaaaa",
+ "aaaaaaaaaaa", // 11 a's
+ ".",
+ ".*",
+ "a+",
+ "aa+",
+ "aaaa[b]?",
+ "aaa*",
+ },
+ },
+
+ {
+ "abc",
+ "abc",
+ []string{
+ "a",
+ "b",
+ "c",
+ "ab",
+ "bc",
+ "abc",
+ "a.c",
+ "a(b|c)",
+ "abc?",
+ },
+ },
+
+ {
+ "barbara*3",
+ "barbarabarbarabarbara",
+ []string{
+ "a",
+ "bar",
+ "rab",
+ "arab",
+ "barbar",
+ "bara?bar",
+ },
+ },
+
+ {
+ "typing drill",
+ "Now is the time for all good men to come to the aid of their country.",
+ []string{
+ "Now",
+ "the time",
+ "to come the aid",
+ "is the time for all good men to come to the aid of their",
+ "to (come|the)?",
+ },
+ },
+}
+
+
+// find all occurrences of s in source; report at most n occurences
+func find(src, s string, n int) []int {
+ var res vector.IntVector
+ if s != "" && n != 0 {
+ // find at most n occurrences of s in src
+ for i := -1; n < 0 || len(res) < n; {
+ j := strings.Index(src[i+1:], s)
+ if j < 0 {
+ break
+ }
+ i += j + 1
+ res.Push(i)
+ }
+ }
+ return res
+}
+
+
+func testLookup(t *testing.T, tc *testCase, x *Index, s string, n int) {
+ res := x.Lookup([]byte(s), n)
+ exp := find(tc.source, s, n)
+
+ // check that the lengths match
+ if len(res) != len(exp) {
+ t.Errorf("test %q, lookup %q (n = %d): expected %d results; got %d", tc.name, s, n, len(exp), len(res))
+ }
+
+ // if n >= 0 the number of results is limited --- unless n >= all results,
+ // we may obtain different positions from the Index and from find (because
+ // Index may not find the results in the same order as find) => in general
+ // we cannot simply check that the res and exp lists are equal
+
+ // check that each result is in fact a correct match and there are no duplicates
+ sort.SortInts(res)
+ for i, r := range res {
+ if r < 0 || len(tc.source) <= r {
+ t.Errorf("test %q, lookup %q, result %d (n = %d): index %d out of range [0, %d[", tc.name, s, i, n, r, len(tc.source))
+ } else if !strings.HasPrefix(tc.source[r:], s) {
+ t.Errorf("test %q, lookup %q, result %d (n = %d): index %d not a match", tc.name, s, i, n, r)
+ }
+ if i > 0 && res[i-1] == r {
+ t.Errorf("test %q, lookup %q, result %d (n = %d): found duplicate index %d", tc.name, s, i, n, r)
+ }
+ }
+
+ if n < 0 {
+ // all results computed - sorted res and exp must be equal
+ for i, r := range res {
+ e := exp[i]
+ if r != e {
+ t.Errorf("test %q, lookup %q, result %d: expected index %d; got %d", tc.name, s, i, e, r)
+ }
+ }
+ }
+}
+
+
+func testFindAllIndex(t *testing.T, tc *testCase, x *Index, rx *regexp.Regexp, n int) {
+ res := x.FindAllIndex(rx, n)
+ exp := rx.FindAllStringIndex(tc.source, n)
+
+ // check that the lengths match
+ if len(res) != len(exp) {
+ t.Errorf("test %q, FindAllIndex %q (n = %d): expected %d results; got %d", tc.name, rx, n, len(exp), len(res))
+ }
+
+ // if n >= 0 the number of results is limited --- unless n >= all results,
+ // we may obtain different positions from the Index and from regexp (because
+ // Index may not find the results in the same order as regexp) => in general
+ // we cannot simply check that the res and exp lists are equal
+
+ // check that each result is in fact a correct match and the result is sorted
+ for i, r := range res {
+ if r[0] < 0 || r[0] > r[1] || len(tc.source) < r[1] {
+ t.Errorf("test %q, FindAllIndex %q, result %d (n == %d): illegal match [%d, %d]", tc.name, rx, i, n, r[0], r[1])
+ } else if !rx.MatchString(tc.source[r[0]:r[1]]) {
+ t.Errorf("test %q, FindAllIndex %q, result %d (n = %d): [%d, %d] not a match", tc.name, rx, i, n, r[0], r[1])
+ }
+ }
+
+ if n < 0 {
+ // all results computed - sorted res and exp must be equal
+ for i, r := range res {
+ e := exp[i]
+ if r[0] != e[0] || r[1] != e[1] {
+ t.Errorf("test %q, FindAllIndex %q, result %d: expected match [%d, %d]; got [%d, %d]",
+ tc.name, rx, i, e[0], e[1], r[0], r[1])
+ }
+ }
+ }
+}
+
+
+func testLookups(t *testing.T, tc *testCase, x *Index, n int) {
+ for _, pat := range tc.patterns {
+ testLookup(t, tc, x, pat, n)
+ if rx, err := regexp.Compile(pat); err == nil {
+ testFindAllIndex(t, tc, x, rx, n)
+ }
+ }
+}
+
+
+// index is used to hide the sort.Interface
+type index Index
+
+func (x *index) Len() int { return len(x.sa) }
+func (x *index) Less(i, j int) bool { return bytes.Compare(x.at(i), x.at(j)) < 0 }
+func (x *index) Swap(i, j int) { x.sa[i], x.sa[j] = x.sa[j], x.sa[i] }
+func (a *index) at(i int) []byte { return a.data[a.sa[i]:] }
+
+
+func testConstruction(t *testing.T, tc *testCase, x *Index) {
+ if !sort.IsSorted((*index)(x)) {
+ t.Errorf("testConstruction failed %s", tc.name)
+ }
+}
+
+
+func TestIndex(t *testing.T) {
+ for _, tc := range testCases {
+ x := New([]byte(tc.source))
+ testConstruction(t, &tc, x)
+ testLookups(t, &tc, x, 0)
+ testLookups(t, &tc, x, 1)
+ testLookups(t, &tc, x, 10)
+ testLookups(t, &tc, x, 2e9)
+ testLookups(t, &tc, x, -1)
+ }
+}
diff --git a/src/pkg/io/Makefile b/src/pkg/io/Makefile
index 8c27ce551..9786002f0 100644
--- a/src/pkg/io/Makefile
+++ b/src/pkg/io/Makefile
@@ -2,11 +2,12 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.$(GOARCH)
+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 dcdc883b1..1a6eca95a 100644
--- a/src/pkg/io/io.go
+++ b/src/pkg/io/io.go
@@ -19,6 +19,9 @@ type Error struct {
// but failed to return an explicit error.
var ErrShortWrite os.Error = &Error{"short write"}
+// ErrShortBuffer means that a read required a longer buffer than was provided.
+var ErrShortBuffer os.Error = &Error{"short buffer"}
+
// ErrUnexpectedEOF means that os.EOF was encountered in the
// middle of reading a fixed-size block or data structure.
var ErrUnexpectedEOF os.Error = &Error{"unexpected EOF"}
@@ -165,8 +168,11 @@ func WriteString(w Writer, s string) (n int, err os.Error) {
// The error is os.EOF only if no bytes were read.
// If an EOF happens after reading fewer than min bytes,
// ReadAtLeast returns ErrUnexpectedEOF.
+// If min is greater than the length of buf, ReadAtLeast returns ErrShortBuffer.
func ReadAtLeast(r Reader, buf []byte, min int) (n int, err os.Error) {
- n = 0
+ if len(buf) < min {
+ return 0, ErrShortBuffer
+ }
for n < min {
nn, e := r.Read(buf[n:])
if nn > 0 {
@@ -179,7 +185,7 @@ func ReadAtLeast(r Reader, buf []byte, min int) (n int, err os.Error) {
return n, e
}
}
- return n, nil
+ return
}
// ReadFull reads exactly len(buf) bytes from r into buf.
@@ -197,10 +203,15 @@ func ReadFull(r Reader, buf []byte) (n int, err os.Error) {
// If dst implements the ReaderFrom interface,
// the copy is implemented by calling dst.ReadFrom(src).
func Copyn(dst Writer, src Reader, n int64) (written int64, err os.Error) {
- // If the writer has a ReadFrom method, use it to to do the copy.
+ // 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 {
- return rt.ReadFrom(LimitReader(src, n))
+ written, err = rt.ReadFrom(LimitReader(src, n))
+ if written < n && err == nil {
+ // rt stopped early; must have been EOF.
+ err = os.EOF
+ }
+ return
}
buf := make([]byte, 32*1024)
for written < n {
@@ -240,12 +251,12 @@ func Copyn(dst Writer, src Reader, n int64) (written int64, err os.Error) {
// Otherwise, if src implements the WriterTo interface,
// the copy is implemented by calling src.WriteTo(dst).
func Copy(dst Writer, src Reader) (written int64, err os.Error) {
- // If the writer has a ReadFrom method, use it to to do the copy.
+ // If the writer has a ReadFrom method, use it to do the copy.
// Avoids an allocation and a copy.
if rt, ok := dst.(ReaderFrom); ok {
return rt.ReadFrom(src)
}
- // Similarly, if the reader has a WriteTo method, use it to to do the copy.
+ // Similarly, if the reader has a WriteTo method, use it to do the copy.
if wt, ok := src.(WriterTo); ok {
return wt.WriteTo(dst)
}
@@ -336,7 +347,7 @@ func (s *SectionReader) Seek(offset int64, whence int) (ret int64, err os.Error)
case 2:
offset += s.limit
}
- if offset < s.off || offset > s.limit {
+ if offset < s.base || offset > s.limit {
return 0, os.EINVAL
}
s.off = offset
diff --git a/src/pkg/io/io_test.go b/src/pkg/io/io_test.go
index 4ad1e5951..4fcd85e69 100644
--- a/src/pkg/io/io_test.go
+++ b/src/pkg/io/io_test.go
@@ -7,6 +7,8 @@ package io_test
import (
"bytes"
. "io"
+ "os"
+ "strings"
"testing"
)
@@ -78,3 +80,77 @@ func TestCopynWriteTo(t *testing.T) {
t.Errorf("Copyn did not work properly")
}
}
+
+type noReadFrom struct {
+ w Writer
+}
+
+func (w *noReadFrom) Write(p []byte) (n int, err os.Error) {
+ return w.w.Write(p)
+}
+
+func TestCopynEOF(t *testing.T) {
+ // Test that EOF behavior is the same regardless of whether
+ // argument to Copyn has ReadFrom.
+
+ b := new(bytes.Buffer)
+
+ n, err := Copyn(&noReadFrom{b}, strings.NewReader("foo"), 3)
+ if n != 3 || err != nil {
+ t.Errorf("Copyn(noReadFrom, foo, 3) = %d, %v; want 3, nil", n, err)
+ }
+
+ n, err = Copyn(&noReadFrom{b}, strings.NewReader("foo"), 4)
+ if n != 3 || err != os.EOF {
+ t.Errorf("Copyn(noReadFrom, foo, 4) = %d, %v; want 3, EOF", n, err)
+ }
+
+ n, err = Copyn(b, strings.NewReader("foo"), 3) // b has read from
+ if n != 3 || err != nil {
+ t.Errorf("Copyn(bytes.Buffer, foo, 3) = %d, %v; want 3, nil", n, err)
+ }
+
+ n, err = Copyn(b, strings.NewReader("foo"), 4) // b has read from
+ if n != 3 || err != os.EOF {
+ t.Errorf("Copyn(bytes.Buffer, foo, 4) = %d, %v; want 3, EOF", n, err)
+ }
+}
+
+func TestReadAtLeast(t *testing.T) {
+ var rb bytes.Buffer
+ rb.Write([]byte("0123"))
+ buf := make([]byte, 2)
+ n, err := ReadAtLeast(&rb, buf, 2)
+ if err != nil {
+ t.Error(err)
+ }
+ n, err = ReadAtLeast(&rb, buf, 4)
+ if err != ErrShortBuffer {
+ t.Errorf("expected ErrShortBuffer got %v", err)
+ }
+ if n != 0 {
+ t.Errorf("expected to have read 0 bytes, got %v", n)
+ }
+ n, err = ReadAtLeast(&rb, buf, 1)
+ if err != nil {
+ t.Error(err)
+ }
+ if n != 2 {
+ t.Errorf("expected to have read 2 bytes, got %v", n)
+ }
+ n, err = ReadAtLeast(&rb, buf, 2)
+ if err != os.EOF {
+ t.Errorf("expected EOF, got %v", err)
+ }
+ if n != 0 {
+ t.Errorf("expected to have read 0 bytes, got %v", n)
+ }
+ rb.Write([]byte("4"))
+ n, err = ReadAtLeast(&rb, buf, 2)
+ if err != ErrUnexpectedEOF {
+ t.Errorf("expected ErrUnexpectedEOF, got %v", err)
+ }
+ if n != 1 {
+ t.Errorf("expected to have read 1 bytes, got %v", n)
+ }
+}
diff --git a/src/pkg/io/ioutil/Makefile b/src/pkg/io/ioutil/Makefile
index 77b75bcec..d406d4b7d 100644
--- a/src/pkg/io/ioutil/Makefile
+++ b/src/pkg/io/ioutil/Makefile
@@ -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 ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=io/ioutil
GOFILES=\
diff --git a/src/pkg/io/ioutil/ioutil.go b/src/pkg/io/ioutil/ioutil.go
index d33869380..fb3fdcda1 100644
--- a/src/pkg/io/ioutil/ioutil.go
+++ b/src/pkg/io/ioutil/ioutil.go
@@ -49,7 +49,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 int) os.Error {
+func WriteFile(filename string, data []byte, perm uint32) os.Error {
f, err := os.Open(filename, os.O_WRONLY|os.O_CREAT|os.O_TRUNC, perm)
if err != nil {
return err
diff --git a/src/pkg/io/ioutil/ioutil_test.go b/src/pkg/io/ioutil/ioutil_test.go
index ecbf41ca6..150ee6d63 100644
--- a/src/pkg/io/ioutil/ioutil_test.go
+++ b/src/pkg/io/ioutil/ioutil_test.go
@@ -37,7 +37,7 @@ func TestReadFile(t *testing.T) {
}
func TestWriteFile(t *testing.T) {
- filename := "_obj/rumpelstilzchen"
+ filename := "_test/rumpelstilzchen"
data := "Programming today is a race between software engineers striving to " +
"build bigger and better idiot-proof programs, and the Universe trying " +
"to produce bigger and better idiots. So far, the Universe is winning."
@@ -74,19 +74,19 @@ func TestReadDir(t *testing.T) {
}
foundTest := false
- foundObj := false
+ foundTestDir := false
for _, dir := range list {
switch {
case dir.IsRegular() && dir.Name == "ioutil_test.go":
foundTest = true
- case dir.IsDirectory() && dir.Name == "_obj":
- foundObj = true
+ case dir.IsDirectory() && dir.Name == "_test":
+ foundTestDir = true
}
}
if !foundTest {
t.Fatalf("ReadDir %s: test file not found", dirname)
}
- if !foundObj {
- t.Fatalf("ReadDir %s: _obj directory not found", dirname)
+ if !foundTestDir {
+ t.Fatalf("ReadDir %s: _test directory not found", dirname)
}
}
diff --git a/src/pkg/io/ioutil/tempfile_test.go b/src/pkg/io/ioutil/tempfile_test.go
index fe43f9566..d949a86cf 100644
--- a/src/pkg/io/ioutil/tempfile_test.go
+++ b/src/pkg/io/ioutil/tempfile_test.go
@@ -23,7 +23,7 @@ func TestTempFile(t *testing.T) {
t.Errorf("TempFile(dir, `ioutil_test`) = %v, %v", f, err)
}
if f != nil {
- re := testing.MustCompile("^" + regexp.QuoteMeta(dir) + "/ioutil_test[0-9]+$")
+ re := regexp.MustCompile("^" + regexp.QuoteMeta(dir) + "/ioutil_test[0-9]+$")
if !re.MatchString(f.Name()) {
t.Errorf("TempFile(`"+dir+"`, `ioutil_test`) created bad name %s", f.Name())
}
diff --git a/src/pkg/io/multi.go b/src/pkg/io/multi.go
new file mode 100644
index 000000000..88e4f1b76
--- /dev/null
+++ b/src/pkg/io/multi.go
@@ -0,0 +1,60 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package io
+
+import "os"
+
+type multiReader struct {
+ readers []Reader
+}
+
+func (mr *multiReader) Read(p []byte) (n int, err os.Error) {
+ for len(mr.readers) > 0 {
+ n, err = mr.readers[0].Read(p)
+ if n > 0 || err != os.EOF {
+ if err == os.EOF {
+ // This shouldn't happen.
+ // Well-behaved Readers should never
+ // return non-zero bytes read with an
+ // EOF. But if so, we clean it.
+ err = nil
+ }
+ return
+ }
+ mr.readers = mr.readers[1:]
+ }
+ return 0, os.EOF
+}
+
+// MultiReader returns a Reader that's the logical concatenation of
+// the provided input readers. They're read sequentially. Once all
+// inputs are drained, Read will return os.EOF.
+func MultiReader(readers ...Reader) Reader {
+ return &multiReader{readers}
+}
+
+type multiWriter struct {
+ writers []Writer
+}
+
+func (t *multiWriter) Write(p []byte) (n int, err os.Error) {
+ for _, w := range t.writers {
+ n, err = w.Write(p)
+ if err != nil {
+ return
+ }
+ if n != len(p) {
+ err = ErrShortWrite
+ return
+ }
+ }
+ return len(p), nil
+}
+
+// MultiWriter creates a writer that duplicates its writes to all the
+// provided writers, similar to the Unix tee(1) command.
+func MultiWriter(writers ...Writer) Writer {
+ return &multiWriter{writers}
+}
diff --git a/src/pkg/io/multi_test.go b/src/pkg/io/multi_test.go
new file mode 100644
index 000000000..3ecb7c75d
--- /dev/null
+++ b/src/pkg/io/multi_test.go
@@ -0,0 +1,88 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package io_test
+
+import (
+ . "io"
+ "bytes"
+ "crypto/sha1"
+ "fmt"
+ "os"
+ "strings"
+ "testing"
+)
+
+func TestMultiReader(t *testing.T) {
+ var mr Reader
+ var buf []byte
+ nread := 0
+ withFooBar := func(tests func()) {
+ r1 := strings.NewReader("foo ")
+ r2 := strings.NewReader("bar")
+ mr = MultiReader(r1, r2)
+ buf = make([]byte, 20)
+ tests()
+ }
+ expectRead := func(size int, expected string, eerr os.Error) {
+ nread++
+ n, gerr := mr.Read(buf[0:size])
+ if n != len(expected) {
+ t.Errorf("#%d, expected %d bytes; got %d",
+ nread, len(expected), n)
+ }
+ got := string(buf[0:n])
+ if got != expected {
+ t.Errorf("#%d, expected %q; got %q",
+ nread, expected, got)
+ }
+ if gerr != eerr {
+ t.Errorf("#%d, expected error %v; got %v",
+ nread, eerr, gerr)
+ }
+ buf = buf[n:]
+ }
+ withFooBar(func() {
+ expectRead(2, "fo", nil)
+ expectRead(5, "o ", nil)
+ expectRead(5, "bar", nil)
+ expectRead(5, "", os.EOF)
+ })
+ withFooBar(func() {
+ expectRead(4, "foo ", nil)
+ expectRead(1, "b", nil)
+ expectRead(3, "ar", nil)
+ expectRead(1, "", os.EOF)
+ })
+ withFooBar(func() {
+ expectRead(5, "foo ", nil)
+ })
+}
+
+func TestMultiWriter(t *testing.T) {
+ sha1 := sha1.New()
+ sink := new(bytes.Buffer)
+ mw := MultiWriter(sha1, sink)
+
+ sourceString := "My input text."
+ source := strings.NewReader(sourceString)
+ written, err := Copy(mw, source)
+
+ if written != int64(len(sourceString)) {
+ t.Errorf("short write of %d, not %d", written, len(sourceString))
+ }
+
+ if err != nil {
+ t.Errorf("unexpected error: %v", err)
+ }
+
+ sha1hex := fmt.Sprintf("%x", sha1.Sum())
+ if sha1hex != "01cb303fa8c30a64123067c5aa6284ba7ec2d31b" {
+ t.Error("incorrect sha1 value")
+ }
+
+ if sink.String() != sourceString {
+ t.Errorf("expected %q; got %q", sourceString, sink.String())
+ }
+}
diff --git a/src/pkg/io/pipe.go b/src/pkg/io/pipe.go
index 898526921..df76418b9 100644
--- a/src/pkg/io/pipe.go
+++ b/src/pkg/io/pipe.go
@@ -52,6 +52,13 @@ func (p *pipe) run() {
case <-p.done:
if ndone++; ndone == 2 {
// both reader and writer are gone
+ // close out any existing i/o
+ if r1 == nil {
+ p.r2 <- pipeResult{0, os.EINVAL}
+ }
+ if w1 == nil {
+ p.w2 <- pipeResult{0, os.EINVAL}
+ }
return
}
continue
@@ -89,6 +96,11 @@ func (p *pipe) run() {
p.r2 <- pipeResult{0, werr}
continue
}
+ if rerr != nil {
+ // read end is closed
+ p.r2 <- pipeResult{0, os.EINVAL}
+ continue
+ }
r1 = nil // disable Read until this one is done
case wb = <-w1:
if rerr != nil {
@@ -96,6 +108,11 @@ func (p *pipe) run() {
p.w2 <- pipeResult{0, rerr}
continue
}
+ if werr != nil {
+ // write end is closed
+ p.w2 <- pipeResult{0, os.EINVAL}
+ continue
+ }
w1 = nil // disable Write until this one is done
}
@@ -275,20 +292,14 @@ func Pipe() (*PipeReader, *PipeWriter) {
r.c2 = p.r2
r.cclose = p.rclose
r.done = p.done
- // TODO(rsc): Should be able to write
- // runtime.SetFinalizer(r, (*PipeReader).finalizer)
- // but 6g doesn't see the finalizer method.
- runtime.SetFinalizer(&r.pipeHalf, (*pipeHalf).finalizer)
+ runtime.SetFinalizer(r, (*PipeReader).finalizer)
w := new(PipeWriter)
w.c1 = p.w1
w.c2 = p.w2
w.cclose = p.wclose
w.done = p.done
- // TODO(rsc): Should be able to write
- // runtime.SetFinalizer(w, (*PipeWriter).finalizer)
- // but 6g doesn't see the finalizer method.
- runtime.SetFinalizer(&w.pipeHalf, (*pipeHalf).finalizer)
+ runtime.SetFinalizer(w, (*PipeWriter).finalizer)
return r, w
}
diff --git a/src/pkg/io/pipe_test.go b/src/pkg/io/pipe_test.go
index 902d7a0a3..bd4b94f0a 100644
--- a/src/pkg/io/pipe_test.go
+++ b/src/pkg/io/pipe_test.go
@@ -157,12 +157,12 @@ func (p pipeTest) String() string {
}
var pipeTests = []pipeTest{
- pipeTest{true, nil, false},
- pipeTest{true, nil, true},
- pipeTest{true, ErrShortWrite, true},
- pipeTest{false, nil, false},
- pipeTest{false, nil, true},
- pipeTest{false, ErrShortWrite, true},
+ {true, nil, false},
+ {true, nil, true},
+ {true, ErrShortWrite, true},
+ {false, nil, false},
+ {false, nil, true},
+ {false, ErrShortWrite, true},
}
func delayClose(t *testing.T, cl closer, ch chan int, tt pipeTest) {
diff --git a/src/pkg/json/Makefile b/src/pkg/json/Makefile
index fa34bfd18..4e5a8a139 100644
--- a/src/pkg/json/Makefile
+++ b/src/pkg/json/Makefile
@@ -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 ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=json
GOFILES=\
diff --git a/src/pkg/json/decode.go b/src/pkg/json/decode.go
index 3f6965009..c704cacbd 100644
--- a/src/pkg/json/decode.go
+++ b/src/pkg/json/decode.go
@@ -82,6 +82,18 @@ func (e *UnmarshalTypeError) String() string {
return "json: cannot unmarshal " + e.Value + " into Go value of type " + e.Type.String()
}
+// An UnmarshalFieldError describes a JSON object key that
+// led to an unexported (and therefore unwritable) struct field.
+type UnmarshalFieldError struct {
+ Key string
+ Type *reflect.StructType
+ Field reflect.StructField
+}
+
+func (e *UnmarshalFieldError) String() string {
+ return "json: cannot unmarshal object key " + strconv.Quote(e.Key) + " into unexported field " + e.Field.Name + " of type " + e.Type.String()
+}
+
// An InvalidUnmarshalError describes an invalid argument passed to Unmarshal.
// (The argument to Unmarshal must be a non-nil pointer.)
type InvalidUnmarshalError struct {
@@ -116,7 +128,9 @@ func (d *decodeState) unmarshal(v interface{}) (err os.Error) {
}
d.scan.reset()
- d.value(pv.Elem())
+ // We decode rv not pv.Elem because the Unmarshaler interface
+ // test must be applied at the top level of the value.
+ d.value(rv)
return d.savedError
}
@@ -330,7 +344,7 @@ func (d *decodeState) array(v reflect.Value) {
newcap = 4
}
newv := reflect.MakeSlice(sv.Type().(*reflect.SliceType), sv.Len(), newcap)
- reflect.ArrayCopy(newv, sv)
+ reflect.Copy(newv, sv)
sv.Set(newv)
}
if i >= av.Len() && sv != nil {
@@ -450,20 +464,32 @@ func (d *decodeState) object(v reflect.Value) {
if mv != nil {
subv = reflect.MakeZero(mv.Type().(*reflect.MapType).Elem())
} else {
+ var f reflect.StructField
+ var ok bool
// First try for field with that tag.
+ st := sv.Type().(*reflect.StructType)
for i := 0; i < sv.NumField(); i++ {
- f := sv.Type().(*reflect.StructType).Field(i)
+ f = st.Field(i)
if f.Tag == key {
- subv = sv.Field(i)
+ ok = true
break
}
}
- if subv == nil {
+ if !ok {
// Second, exact match.
- subv = sv.FieldByName(key)
- if subv == nil {
- // Third, case-insensitive match.
- subv = sv.FieldByNameFunc(func(s string) bool { return matchName(key, s) })
+ f, ok = st.FieldByName(key)
+ }
+ if !ok {
+ // Third, case-insensitive match.
+ f, ok = st.FieldByNameFunc(func(s string) bool { return matchName(key, s) })
+ }
+
+ // Extract value; name must be exported.
+ if ok {
+ if f.PkgPath != "" {
+ d.saveError(&UnmarshalFieldError{key, st, f})
+ } else {
+ subv = sv.FieldByIndex(f.Index)
}
}
}
@@ -805,13 +831,13 @@ func unquote(s []byte) (t string, ok bool) {
if dec := utf16.DecodeRune(rune, rune1); dec != unicode.ReplacementChar {
// A valid pair; consume.
r += 6
- w += utf8.EncodeRune(dec, b[w:])
+ w += utf8.EncodeRune(b[w:], dec)
break
}
// Invalid surrogate; fall back to replacement rune.
rune = unicode.ReplacementChar
}
- w += utf8.EncodeRune(rune, b[w:])
+ w += utf8.EncodeRune(b[w:], rune)
}
// Quote, control characters are invalid.
@@ -828,7 +854,7 @@ func unquote(s []byte) (t string, ok bool) {
default:
rune, size := utf8.DecodeRune(s[r:])
r += size
- w += utf8.EncodeRune(rune, b[w:])
+ w += utf8.EncodeRune(b[w:], rune)
}
}
return string(b[0:w]), true
diff --git a/src/pkg/json/decode_test.go b/src/pkg/json/decode_test.go
index e10b2c56e..68cdea051 100644
--- a/src/pkg/json/decode_test.go
+++ b/src/pkg/json/decode_test.go
@@ -17,6 +17,30 @@ type T struct {
Y int
}
+type tx struct {
+ x int
+}
+
+var txType = reflect.Typeof((*tx)(nil)).(*reflect.PtrType).Elem().(*reflect.StructType)
+
+// A type that can unmarshal itself.
+
+type unmarshaler struct {
+ T bool
+}
+
+func (u *unmarshaler) UnmarshalJSON(b []byte) os.Error {
+ *u = unmarshaler{true} // All we need to see that UnmarshalJson is called.
+ return nil
+}
+
+var (
+ um0, um1 unmarshaler // target2 of unmarshaling
+ ump = &um1
+ umtrue = unmarshaler{true}
+)
+
+
type unmarshalTest struct {
in string
ptr interface{}
@@ -26,26 +50,34 @@ type unmarshalTest struct {
var unmarshalTests = []unmarshalTest{
// basic types
- unmarshalTest{`true`, new(bool), true, nil},
- unmarshalTest{`1`, new(int), 1, nil},
- unmarshalTest{`1.2`, new(float), 1.2, nil},
- unmarshalTest{`-5`, new(int16), int16(-5), nil},
- unmarshalTest{`"a\u1234"`, new(string), "a\u1234", nil},
- unmarshalTest{`"http:\/\/"`, new(string), "http://", nil},
- unmarshalTest{`"g-clef: \uD834\uDD1E"`, new(string), "g-clef: \U0001D11E", nil},
- unmarshalTest{`"invalid: \uD834x\uDD1E"`, new(string), "invalid: \uFFFDx\uFFFD", nil},
- unmarshalTest{"null", new(interface{}), nil, nil},
- unmarshalTest{`{"X": [1,2,3], "Y": 4}`, new(T), T{Y: 4}, &UnmarshalTypeError{"array", reflect.Typeof("")}},
+ {`true`, new(bool), true, nil},
+ {`1`, new(int), 1, nil},
+ {`1.2`, new(float), 1.2, nil},
+ {`-5`, new(int16), int16(-5), nil},
+ {`"a\u1234"`, new(string), "a\u1234", nil},
+ {`"http:\/\/"`, new(string), "http://", nil},
+ {`"g-clef: \uD834\uDD1E"`, new(string), "g-clef: \U0001D11E", nil},
+ {`"invalid: \uD834x\uDD1E"`, new(string), "invalid: \uFFFDx\uFFFD", nil},
+ {"null", new(interface{}), nil, nil},
+ {`{"X": [1,2,3], "Y": 4}`, new(T), T{Y: 4}, &UnmarshalTypeError{"array", reflect.Typeof("")}},
+ {`{"x": 1}`, new(tx), tx{}, &UnmarshalFieldError{"x", txType, txType.Field(0)}},
+
+ // syntax errors
+ {`{"X": "foo", "Y"}`, nil, nil, SyntaxError("invalid character '}' after object key")},
// composite tests
- unmarshalTest{allValueIndent, new(All), allValue, nil},
- unmarshalTest{allValueCompact, new(All), allValue, nil},
- unmarshalTest{allValueIndent, new(*All), &allValue, nil},
- unmarshalTest{allValueCompact, new(*All), &allValue, nil},
- unmarshalTest{pallValueIndent, new(All), pallValue, nil},
- unmarshalTest{pallValueCompact, new(All), pallValue, nil},
- unmarshalTest{pallValueIndent, new(*All), &pallValue, nil},
- unmarshalTest{pallValueCompact, new(*All), &pallValue, nil},
+ {allValueIndent, new(All), allValue, nil},
+ {allValueCompact, new(All), allValue, nil},
+ {allValueIndent, new(*All), &allValue, nil},
+ {allValueCompact, new(*All), &allValue, nil},
+ {pallValueIndent, new(All), pallValue, nil},
+ {pallValueCompact, new(All), pallValue, nil},
+ {pallValueIndent, new(*All), &pallValue, nil},
+ {pallValueCompact, new(*All), &pallValue, nil},
+
+ // unmarshal interface test
+ {`{"T":false}`, &um0, umtrue, nil}, // use "false" so test will fail if custom unmarshaler is not called
+ {`{"T":false}`, &ump, &umtrue, nil},
}
func TestMarshal(t *testing.T) {
@@ -70,12 +102,31 @@ func TestMarshal(t *testing.T) {
}
}
+func TestMarshalBadUTF8(t *testing.T) {
+ s := "hello\xffworld"
+ b, err := Marshal(s)
+ if err == nil {
+ t.Fatal("Marshal bad UTF8: no error")
+ }
+ if len(b) != 0 {
+ t.Fatal("Marshal returned data")
+ }
+ if _, ok := err.(*InvalidUTF8Error); !ok {
+ t.Fatalf("Marshal did not return InvalidUTF8Error: %T %v", err, err)
+ }
+}
+
func TestUnmarshal(t *testing.T) {
var scan scanner
for i, tt := range unmarshalTests {
in := []byte(tt.in)
if err := checkValid(in, &scan); err != nil {
- t.Errorf("#%d: checkValid: %v", i, err)
+ if !reflect.DeepEqual(err, tt.err) {
+ t.Errorf("#%d: checkValid: %v", i, err)
+ continue
+ }
+ }
+ if tt.ptr == nil {
continue
}
// v = new(right-type)
@@ -139,6 +190,16 @@ func TestUnmarshalPtrPtr(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)
+ }
+}
+
func noSpace(c int) int {
if isSpace(c) {
return -1
@@ -209,6 +270,8 @@ type All struct {
Interface interface{}
PInterface *interface{}
+
+ unexported int
}
type Small struct {
@@ -234,15 +297,15 @@ var allValue = All{
Foo: "foo",
String: "16",
Map: map[string]Small{
- "17": Small{Tag: "tag17"},
- "18": Small{Tag: "tag18"},
+ "17": {Tag: "tag17"},
+ "18": {Tag: "tag18"},
},
MapP: map[string]*Small{
"19": &Small{Tag: "tag19"},
"20": nil,
},
EmptyMap: map[string]Small{},
- Slice: []Small{Small{Tag: "tag20"}, Small{Tag: "tag21"}},
+ Slice: []Small{{Tag: "tag20"}, {Tag: "tag21"}},
SliceP: []*Small{&Small{Tag: "tag22"}, nil, &Small{Tag: "tag23"}},
EmptySlice: []Small{},
StringSlice: []string{"str24", "str25", "str26"},
diff --git a/src/pkg/json/encode.go b/src/pkg/json/encode.go
index 5d7ce35cb..759b49dbe 100644
--- a/src/pkg/json/encode.go
+++ b/src/pkg/json/encode.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.
+// The json package implements encoding and decoding of JSON objects as
+// defined in RFC 4627.
package json
import (
@@ -11,6 +13,7 @@ import (
"runtime"
"sort"
"strconv"
+ "utf8"
)
// Marshal returns the JSON encoding of v.
@@ -34,6 +37,7 @@ import (
// a member of the object. By default the object's key name is the
// struct field name converted to lower case. If the struct field
// has a tag, that tag will be used as the name instead.
+// Only exported fields will be encoded.
//
// Map values encode as JSON objects.
// The map's key type must be string; the object keys are used directly
@@ -76,6 +80,43 @@ 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.
+// For historical reasons, web browsers don't honor standard HTML
+// escaping within <script> tags, so an alternative JSON encoding must
+// be used.
+func HTMLEscape(dst *bytes.Buffer, src []byte) {
+ // < > & can only appear in string literals,
+ // so just scan the string one byte at a time.
+ start := 0
+ for i, c := range src {
+ if c == '<' || c == '>' || c == '&' {
+ if start < i {
+ dst.Write(src[start:i])
+ }
+ dst.WriteString(`\u00`)
+ dst.WriteByte(hex[c>>4])
+ dst.WriteByte(hex[c&0xF])
+ start = i + 1
+ }
+ }
+ if start < len(src) {
+ dst.Write(src[start:])
+ }
+}
+
// Marshaler is the interface implemented by objects that
// can marshal themselves into valid JSON.
type Marshaler interface {
@@ -90,6 +131,14 @@ func (e *UnsupportedTypeError) String() string {
return "json: unsupported type: " + e.Type.String()
}
+type InvalidUTF8Error struct {
+ S string
+}
+
+func (e *InvalidUTF8Error) String() string {
+ return "json: invalid UTF-8 in string: " + strconv.Quote(e.S)
+}
+
type MarshalerError struct {
Type reflect.Type
Error os.Error
@@ -171,11 +220,17 @@ func (e *encodeState) reflectValue(v reflect.Value) {
e.WriteByte('{')
t := v.Type().(*reflect.StructType)
n := v.NumField()
+ first := true
for i := 0; i < n; i++ {
- if i > 0 {
+ f := t.Field(i)
+ if f.PkgPath != "" {
+ continue
+ }
+ if first {
+ first = false
+ } else {
e.WriteByte(',')
}
- f := t.Field(i)
if f.Tag != "" {
e.string(f.Tag)
} else {
@@ -242,18 +297,36 @@ func (sv stringValues) get(i int) string { return sv[i].(*reflect.StringValue)
func (e *encodeState) string(s string) {
e.WriteByte('"')
- for _, c := range s {
- switch {
- case c < 0x20:
- e.WriteString(`\u00`)
- e.WriteByte(hex[c>>4])
- e.WriteByte(hex[c&0xF])
- case c == '\\' || c == '"':
- e.WriteByte('\\')
- fallthrough
- default:
- e.WriteRune(c)
+ start := 0
+ for i := 0; i < len(s); {
+ if b := s[i]; b < utf8.RuneSelf {
+ if 0x20 <= b && b != '\\' && b != '"' {
+ i++
+ continue
+ }
+ if start < i {
+ e.WriteString(s[start:i])
+ }
+ if b == '\\' || b == '"' {
+ e.WriteByte('\\')
+ e.WriteByte(b)
+ } else {
+ e.WriteString(`\u00`)
+ e.WriteByte(hex[b>>4])
+ e.WriteByte(hex[b&0xF])
+ }
+ i++
+ start = i
+ continue
+ }
+ c, size := utf8.DecodeRuneInString(s[i:])
+ if c == utf8.RuneError && size == 1 {
+ e.error(&InvalidUTF8Error{s})
}
+ i += size
+ }
+ if start < len(s) {
+ e.WriteString(s[start:])
}
e.WriteByte('"')
}
diff --git a/src/pkg/json/scanner.go b/src/pkg/json/scanner.go
index 27c5ffb7a..112c8f9c3 100644
--- a/src/pkg/json/scanner.go
+++ b/src/pkg/json/scanner.go
@@ -155,18 +155,7 @@ func (s *scanner) eof() int {
// pushParseState pushes a new parse state p onto the parse stack.
func (s *scanner) pushParseState(p int) {
- n := len(s.parseState)
- if n >= cap(s.parseState) {
- if n == 0 {
- s.parseState = make([]int, 0, 16)
- } else {
- ps := make([]int, n, 2*n)
- copy(ps, s.parseState)
- s.parseState = ps
- }
- }
- s.parseState = s.parseState[0 : n+1]
- s.parseState[n] = p
+ s.parseState = append(s.parseState, p)
}
// popParseState pops a parse state (already obtained) off the stack
@@ -251,6 +240,8 @@ func stateBeginStringOrEmpty(s *scanner, c int) int {
return scanSkipSpace
}
if c == '}' {
+ n := len(s.parseState)
+ s.parseState[n-1] = parseObjectValue
return stateEndValue(s, c)
}
return stateBeginString(s, c)
@@ -289,10 +280,6 @@ func stateEndValue(s *scanner, c int) int {
s.step = stateBeginValue
return scanObjectKey
}
- if c == '}' {
- s.popParseState()
- return scanEndObject
- }
return s.error(c, "after object key")
case parseObjectValue:
if c == ',' {
diff --git a/src/pkg/json/scanner_test.go b/src/pkg/json/scanner_test.go
index cdc032263..2dc8ff87f 100644
--- a/src/pkg/json/scanner_test.go
+++ b/src/pkg/json/scanner_test.go
@@ -19,14 +19,14 @@ type example struct {
}
var examples = []example{
- example{`1`, `1`},
- example{`{}`, `{}`},
- example{`[]`, `[]`},
- example{`{"":2}`, "{\n\t\"\": 2\n}"},
- example{`[3]`, "[\n\t3\n]"},
- example{`[1,2,3]`, "[\n\t1,\n\t2,\n\t3\n]"},
- example{`{"x":1}`, "{\n\t\"x\": 1\n}"},
- example{ex1, ex1i},
+ {`1`, `1`},
+ {`{}`, `{}`},
+ {`[]`, `[]`},
+ {`{"":2}`, "{\n\t\"\": 2\n}"},
+ {`[3]`, "[\n\t3\n]"},
+ {`[1,2,3]`, "[\n\t1,\n\t2,\n\t3\n]"},
+ {`{"x":1}`, "{\n\t\"x\": 1\n}"},
+ {ex1, ex1i},
}
var ex1 = `[true,false,null,"x",1,1.5,0,-5e+2]`
@@ -138,7 +138,7 @@ func TestNextValueBig(t *testing.T) {
var scan scanner
item, rest, err := nextValue(jsonBig, &scan)
if err != nil {
- t.Fatalf("nextValue: ", err)
+ t.Fatalf("nextValue: %s", err)
}
if len(item) != len(jsonBig) || &item[0] != &jsonBig[0] {
t.Errorf("invalid item: %d %d", len(item), len(jsonBig))
@@ -147,9 +147,9 @@ func TestNextValueBig(t *testing.T) {
t.Errorf("invalid rest: %d", len(rest))
}
- item, rest, err = nextValue(bytes.Add(jsonBig, []byte("HELLO WORLD")), &scan)
+ item, rest, err = nextValue(append(jsonBig, []byte("HELLO WORLD")...), &scan)
if err != nil {
- t.Fatalf("nextValue extra: ", err)
+ t.Fatalf("nextValue extra: %s", err)
}
if len(item) != len(jsonBig) {
t.Errorf("invalid item: %d %d", len(item), len(jsonBig))
diff --git a/src/pkg/json/stream.go b/src/pkg/json/stream.go
index d4fb34660..cb9b16559 100644
--- a/src/pkg/json/stream.go
+++ b/src/pkg/json/stream.go
@@ -5,7 +5,6 @@
package json
import (
- "bytes"
"io"
"os"
)
@@ -177,7 +176,7 @@ func (m *RawMessage) UnmarshalJSON(data []byte) os.Error {
if m == nil {
return os.NewError("json.RawMessage: UnmarshalJSON on nil pointer")
}
- *m = bytes.Add((*m)[0:0], data)
+ *m = append((*m)[0:0], data...)
return nil
}
diff --git a/src/pkg/json/stream_test.go b/src/pkg/json/stream_test.go
index ab90b754e..c83cfe3a9 100644
--- a/src/pkg/json/stream_test.go
+++ b/src/pkg/json/stream_test.go
@@ -71,10 +71,10 @@ func TestDecoder(t *testing.T) {
}
}
if !reflect.DeepEqual(out, streamTest[0:i]) {
- t.Errorf("decoding %d items: mismatch")
+ t.Errorf("decoding %d items: mismatch", i)
for j := range out {
if !reflect.DeepEqual(out[j], streamTest[j]) {
- t.Errorf("#%d: have %v want %v", out[j], streamTest[j])
+ t.Errorf("#%d: have %v want %v", j, out[j], streamTest[j])
}
}
break
diff --git a/src/pkg/log/Makefile b/src/pkg/log/Makefile
index 402be03bc..da72216af 100644
--- a/src/pkg/log/Makefile
+++ b/src/pkg/log/Makefile
@@ -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 ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=log
GOFILES=\
diff --git a/src/pkg/log/log.go b/src/pkg/log/log.go
index 28d6204eb..d34af9e5e 100644
--- a/src/pkg/log/log.go
+++ b/src/pkg/log/log.go
@@ -2,29 +2,28 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Rudimentary logging package. Defines a type, Logger, with simple
-// methods for formatting output to one or two destinations. Also has
-// predefined Loggers accessible through helper functions Stdout[f],
-// Stderr[f], Exit[f], and Crash[f], which are easier to use than creating
-// a Logger manually.
-// Exit exits when written to.
-// Crash causes a crash when written to.
+// Simple logging package. It defines a type, Logger, with methods
+// for formatting output. It also has a predefined 'standard' Logger
+// accessible through helper functions Print[f|ln], Exit[f|ln], and
+// Panic[f|ln], which are easier to use than creating a Logger manually.
+// That logger writes to standard error and prints the date and time
+// of each logged message.
+// The Exit functions call os.Exit(1) after writing the log message.
+// The Panic functions call panic after writing the log message.
package log
import (
+ "bytes"
"fmt"
"io"
"runtime"
"os"
"time"
+ "sync"
)
-// These flags define the properties of the Logger and the output they produce.
+// These flags define which text to prefix to each log entry generated by the Logger.
const (
- // Flags
- Lok = iota
- Lexit // terminate execution when written
- Lcrash // crash (panic) when written
// Bits or'ed together to control what's printed. There is no control over the
// order they appear (the order listed here) or the format they present (as
// described in the comments). A colon appears after these items:
@@ -34,39 +33,36 @@ const (
Lmicroseconds // microsecond resolution: 01:23:23.123123. assumes Ltime.
Llongfile // full file name and line number: /a/b/c/d.go:23
Lshortfile // final file name element and line number: d.go:23. overrides Llongfile
- lAllBits = Ldate | Ltime | Lmicroseconds | Llongfile | Lshortfile
)
-// Logger represents an active logging object.
+// A Logger represents an active logging object that generates lines of
+// output to an io.Writer. Each logging operation makes a single call to
+// the Writer's Write method. A Logger can be used simultaneously from
+// multiple goroutines; it guarantees to serialize access to the Writer.
type Logger struct {
- out0 io.Writer // first destination for output
- out1 io.Writer // second destination for output; may be nil
- prefix string // prefix to write at beginning of each line
- flag int // properties
+ mu sync.Mutex // ensures atomic writes
+ out io.Writer // destination for output
+ prefix string // prefix to write at beginning of each line
+ flag int // properties
}
-// New creates a new Logger. The out0 and out1 variables set the
-// destinations to which log data will be written; out1 may be nil.
+// New creates a new Logger. The out variable sets the
+// destination to which log data will be written.
// The prefix appears at the beginning of each generated log line.
// The flag argument defines the logging properties.
-func New(out0, out1 io.Writer, prefix string, flag int) *Logger {
- return &Logger{out0, out1, prefix, flag}
+func New(out io.Writer, prefix string, flag int) *Logger {
+ return &Logger{out: out, prefix: prefix, flag: flag}
}
-var (
- stdout = New(os.Stdout, nil, "", Lok|Ldate|Ltime)
- stderr = New(os.Stderr, nil, "", Lok|Ldate|Ltime)
- exit = New(os.Stderr, nil, "", Lexit|Ldate|Ltime)
- crash = New(os.Stderr, nil, "", Lcrash|Ldate|Ltime)
-)
-
-var shortnames = make(map[string]string) // cache of short names to avoid allocation.
+var std = New(os.Stderr, "", Ldate|Ltime)
-// Cheap integer to fixed-width decimal ASCII. Use a negative width to avoid zero-padding
-func itoa(i int, wid int) string {
+// Cheap integer to fixed-width decimal ASCII. Give a negative width to avoid zero-padding.
+// Knows the buffer has capacity.
+func itoa(buf *bytes.Buffer, i int, wid int) {
var u uint = uint(i)
if u == 0 && wid <= 1 {
- return "0"
+ buf.WriteByte('0')
+ return
}
// Assemble decimal in reverse order.
@@ -78,38 +74,48 @@ func itoa(i int, wid int) string {
b[bp] = byte(u%10) + '0'
}
- return string(b[bp:])
+ // avoid slicing b to avoid an allocation.
+ for bp < len(b) {
+ buf.WriteByte(b[bp])
+ bp++
+ }
}
-func (l *Logger) formatHeader(ns int64, calldepth int) string {
- h := l.prefix
+func (l *Logger) formatHeader(buf *bytes.Buffer, ns int64, calldepth int) {
+ buf.WriteString(l.prefix)
if l.flag&(Ldate|Ltime|Lmicroseconds) != 0 {
t := time.SecondsToLocalTime(ns / 1e9)
- if l.flag&(Ldate) != 0 {
- h += itoa(int(t.Year), 4) + "/" + itoa(t.Month, 2) + "/" + itoa(t.Day, 2) + " "
+ if l.flag&Ldate != 0 {
+ itoa(buf, int(t.Year), 4)
+ buf.WriteByte('/')
+ itoa(buf, int(t.Month), 2)
+ buf.WriteByte('/')
+ itoa(buf, int(t.Day), 2)
+ buf.WriteByte(' ')
}
if l.flag&(Ltime|Lmicroseconds) != 0 {
- h += itoa(t.Hour, 2) + ":" + itoa(t.Minute, 2) + ":" + itoa(t.Second, 2)
+ itoa(buf, int(t.Hour), 2)
+ buf.WriteByte(':')
+ itoa(buf, int(t.Minute), 2)
+ buf.WriteByte(':')
+ itoa(buf, int(t.Second), 2)
if l.flag&Lmicroseconds != 0 {
- h += "." + itoa(int(ns%1e9)/1e3, 6)
+ buf.WriteByte('.')
+ itoa(buf, int(ns%1e9)/1e3, 6)
}
- h += " "
+ buf.WriteByte(' ')
}
}
if l.flag&(Lshortfile|Llongfile) != 0 {
_, file, line, ok := runtime.Caller(calldepth)
if ok {
if l.flag&Lshortfile != 0 {
- short, ok := shortnames[file]
- if !ok {
- short = file
- for i := len(file) - 1; i > 0; i-- {
- if file[i] == '/' {
- short = file[i+1:]
- break
- }
+ short := file
+ for i := len(file) - 1; i > 0; i-- {
+ if file[i] == '/' {
+ short = file[i+1:]
+ break
}
- shortnames[file] = short
}
file = short
}
@@ -117,65 +123,156 @@ func (l *Logger) formatHeader(ns int64, calldepth int) string {
file = "???"
line = 0
}
- h += file + ":" + itoa(line, -1) + ": "
+ buf.WriteString(file)
+ buf.WriteByte(':')
+ itoa(buf, line, -1)
+ buf.WriteString(": ")
}
- return h
}
-// Output writes the output for a logging event. The string s contains the text to print after
-// the time stamp; calldepth is used to recover the PC. It is provided for generality, although
-// at the moment on all pre-defined paths it will be 2.
+// Output writes the output for a logging event. The string s contains
+// the text to print after the prefix specified by the flags of the
+// Logger. A newline is appended if the last character of s is not
+// already a newline. Calldepth is used to recover the PC and is
+// provided for generality, although at the moment on all pre-defined
+// paths it will be 2.
func (l *Logger) Output(calldepth int, s string) os.Error {
now := time.Nanoseconds() // get this early.
- newline := "\n"
- if len(s) > 0 && s[len(s)-1] == '\n' {
- newline = ""
- }
- s = l.formatHeader(now, calldepth+1) + s + newline
- _, err := io.WriteString(l.out0, s)
- if l.out1 != nil {
- _, err1 := io.WriteString(l.out1, s)
- if err == nil && err1 != nil {
- err = err1
- }
- }
- switch l.flag & ^lAllBits {
- case Lcrash:
- panic("log: fatal error")
- case Lexit:
- os.Exit(1)
+ buf := new(bytes.Buffer)
+ l.formatHeader(buf, now, calldepth+1)
+ buf.WriteString(s)
+ if len(s) > 0 && s[len(s)-1] != '\n' {
+ buf.WriteByte('\n')
}
+ l.mu.Lock()
+ defer l.mu.Unlock()
+ _, err := l.out.Write(buf.Bytes())
return err
}
-// Logf is analogous to Printf() for a Logger.
-func (l *Logger) Logf(format string, v ...interface{}) {
- l.Output(2, fmt.Sprintf(format, v))
+// Printf calls l.Output to print to the logger.
+// Arguments are handled in the manner of fmt.Printf.
+func (l *Logger) Printf(format string, v ...interface{}) {
+ l.Output(2, fmt.Sprintf(format, v...))
+}
+
+// Print calls l.Output to print to the logger.
+// Arguments are handled in the manner of fmt.Print.
+func (l *Logger) Print(v ...interface{}) { l.Output(2, fmt.Sprint(v...)) }
+
+// Println calls l.Output to print to the logger.
+// Arguments are handled in the manner of fmt.Println.
+func (l *Logger) Println(v ...interface{}) { l.Output(2, fmt.Sprintln(v...)) }
+
+// Exit is equivalent to l.Print() followed by a call to os.Exit(1).
+func (l *Logger) Exit(v ...interface{}) {
+ l.Output(2, fmt.Sprint(v...))
+ os.Exit(1)
+}
+
+// Exitf is equivalent to l.Printf() followed by a call to os.Exit(1).
+func (l *Logger) Exitf(format string, v ...interface{}) {
+ l.Output(2, fmt.Sprintf(format, v...))
+ os.Exit(1)
+}
+
+// Exitln is equivalent to l.Println() followed by a call to os.Exit(1).
+func (l *Logger) Exitln(v ...interface{}) {
+ l.Output(2, fmt.Sprintln(v...))
+ os.Exit(1)
+}
+
+// Panic is equivalent to l.Print() followed by a call to panic().
+func (l *Logger) Panic(v ...interface{}) {
+ s := fmt.Sprint(v...)
+ l.Output(2, s)
+ panic(s)
+}
+
+// Panicf is equivalent to l.Printf() followed by a call to panic().
+func (l *Logger) Panicf(format string, v ...interface{}) {
+ s := fmt.Sprintf(format, v...)
+ l.Output(2, s)
+ panic(s)
}
-// Log is analogous to Print() for a Logger.
-func (l *Logger) Log(v ...interface{}) { l.Output(2, fmt.Sprintln(v)) }
+// Panicln is equivalent to l.Println() followed by a call to panic().
+func (l *Logger) Panicln(v ...interface{}) {
+ s := fmt.Sprintln(v...)
+ l.Output(2, s)
+ panic(s)
+}
+
+// SetOutput sets the output destination for the standard logger.
+func SetOutput(w io.Writer) {
+ std.out = w
+}
+
+// SetFlags sets the output flags for the standard logger.
+func SetFlags(flag int) {
+ std.flag = flag
+}
+
+// SetPrefix sets the output prefix for the standard logger.
+func SetPrefix(prefix string) {
+ std.prefix = prefix
+}
+
+// These functions write to the standard logger.
+
+// Print calls Output to print to the standard logger.
+// Arguments are handled in the manner of fmt.Print.
+func Print(v ...interface{}) {
+ std.Output(2, fmt.Sprint(v...))
+}
-// Stdout is a helper function for easy logging to stdout. It is analogous to Print().
-func Stdout(v ...interface{}) { stdout.Output(2, fmt.Sprint(v)) }
+// Printf calls Output to print to the standard logger.
+// Arguments are handled in the manner of fmt.Printf.
+func Printf(format string, v ...interface{}) {
+ std.Output(2, fmt.Sprintf(format, v...))
+}
-// Stderr is a helper function for easy logging to stderr. It is analogous to Fprint(os.Stderr).
-func Stderr(v ...interface{}) { stderr.Output(2, fmt.Sprintln(v)) }
+// Println calls Output to print to the standard logger.
+// Arguments are handled in the manner of fmt.Println.
+func Println(v ...interface{}) {
+ std.Output(2, fmt.Sprintln(v...))
+}
-// Stdoutf is a helper functions for easy formatted logging to stdout. It is analogous to Printf().
-func Stdoutf(format string, v ...interface{}) { stdout.Output(2, fmt.Sprintf(format, v)) }
+// Exit is equivalent to Print() followed by a call to os.Exit(1).
+func Exit(v ...interface{}) {
+ std.Output(2, fmt.Sprint(v...))
+ os.Exit(1)
+}
-// Stderrf is a helper function for easy formatted logging to stderr. It is analogous to Fprintf(os.Stderr).
-func Stderrf(format string, v ...interface{}) { stderr.Output(2, fmt.Sprintf(format, v)) }
+// Exitf is equivalent to Printf() followed by a call to os.Exit(1).
+func Exitf(format string, v ...interface{}) {
+ std.Output(2, fmt.Sprintf(format, v...))
+ os.Exit(1)
+}
-// Exit is equivalent to Stderr() followed by a call to os.Exit(1).
-func Exit(v ...interface{}) { exit.Output(2, fmt.Sprintln(v)) }
+// Exitln is equivalent to Println() followed by a call to os.Exit(1).
+func Exitln(v ...interface{}) {
+ std.Output(2, fmt.Sprintln(v...))
+ os.Exit(1)
+}
-// Exitf is equivalent to Stderrf() followed by a call to os.Exit(1).
-func Exitf(format string, v ...interface{}) { exit.Output(2, fmt.Sprintf(format, v)) }
+// Panic is equivalent to Print() followed by a call to panic().
+func Panic(v ...interface{}) {
+ s := fmt.Sprint(v...)
+ std.Output(2, s)
+ panic(s)
+}
-// Crash is equivalent to Stderr() followed by a call to panic().
-func Crash(v ...interface{}) { crash.Output(2, fmt.Sprintln(v)) }
+// Panicf is equivalent to Printf() followed by a call to panic().
+func Panicf(format string, v ...interface{}) {
+ s := fmt.Sprintf(format, v...)
+ std.Output(2, s)
+ panic(s)
+}
-// Crashf is equivalent to Stderrf() followed by a call to panic().
-func Crashf(format string, v ...interface{}) { crash.Output(2, fmt.Sprintf(format, v)) }
+// Panicln is equivalent to Println() followed by a call to panic().
+func Panicln(v ...interface{}) {
+ s := fmt.Sprintln(v...)
+ std.Output(2, s)
+ panic(s)
+}
diff --git a/src/pkg/log/log_test.go b/src/pkg/log/log_test.go
index eb4b69a2e..f99070afb 100644
--- a/src/pkg/log/log_test.go
+++ b/src/pkg/log/log_test.go
@@ -7,7 +7,7 @@ package log
// These tests are too simple.
import (
- "bufio"
+ "bytes"
"os"
"regexp"
"testing"
@@ -17,7 +17,7 @@ const (
Rdate = `[0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9]`
Rtime = `[0-9][0-9]:[0-9][0-9]:[0-9][0-9]`
Rmicroseconds = `\.[0-9][0-9][0-9][0-9][0-9][0-9]`
- Rline = `(58|60):` // must update if the calls to l.Logf / l.Log below move
+ Rline = `(54|56):` // must update if the calls to l.Printf / l.Print below move
Rlongfile = `.*/[A-Za-z0-9_\-]+\.go:` + Rline
Rshortfile = `[A-Za-z0-9_\-]+\.go:` + Rline
)
@@ -30,39 +30,32 @@ type tester struct {
var tests = []tester{
// individual pieces:
- tester{0, "", ""},
- tester{0, "XXX", "XXX"},
- tester{Lok | Ldate, "", Rdate + " "},
- tester{Lok | Ltime, "", Rtime + " "},
- tester{Lok | Ltime | Lmicroseconds, "", Rtime + Rmicroseconds + " "},
- tester{Lok | Lmicroseconds, "", Rtime + Rmicroseconds + " "}, // microsec implies time
- tester{Lok | Llongfile, "", Rlongfile + " "},
- tester{Lok | Lshortfile, "", Rshortfile + " "},
- tester{Lok | Llongfile | Lshortfile, "", Rshortfile + " "}, // shortfile overrides longfile
+ {0, "", ""},
+ {0, "XXX", "XXX"},
+ {Ldate, "", Rdate + " "},
+ {Ltime, "", Rtime + " "},
+ {Ltime | Lmicroseconds, "", Rtime + Rmicroseconds + " "},
+ {Lmicroseconds, "", Rtime + Rmicroseconds + " "}, // microsec implies time
+ {Llongfile, "", Rlongfile + " "},
+ {Lshortfile, "", Rshortfile + " "},
+ {Llongfile | Lshortfile, "", Rshortfile + " "}, // shortfile overrides longfile
// everything at once:
- tester{Lok | Ldate | Ltime | Lmicroseconds | Llongfile, "XXX", "XXX" + Rdate + " " + Rtime + Rmicroseconds + " " + Rlongfile + " "},
- tester{Lok | Ldate | Ltime | Lmicroseconds | Lshortfile, "XXX", "XXX" + Rdate + " " + Rtime + Rmicroseconds + " " + Rshortfile + " "},
+ {Ldate | Ltime | Lmicroseconds | Llongfile, "XXX", "XXX" + Rdate + " " + Rtime + Rmicroseconds + " " + Rlongfile + " "},
+ {Ldate | Ltime | Lmicroseconds | Lshortfile, "XXX", "XXX" + Rdate + " " + Rtime + Rmicroseconds + " " + Rshortfile + " "},
}
-// Test using Log("hello", 23, "world") or using Logf("hello %d world", 23)
-func testLog(t *testing.T, flag int, prefix string, pattern string, useLogf bool) {
- r, w, err1 := os.Pipe()
- if err1 != nil {
- t.Fatal("pipe", err1)
- }
- defer r.Close()
- defer w.Close()
- buf := bufio.NewReader(r)
- l := New(w, nil, prefix, flag)
- if useLogf {
- l.Logf("hello %d world", 23)
+// Test using Println("hello", 23, "world") or using Printf("hello %d world", 23)
+func testPrint(t *testing.T, flag int, prefix string, pattern string, useFormat bool) {
+ buf := new(bytes.Buffer)
+ SetOutput(buf)
+ SetFlags(flag)
+ SetPrefix(prefix)
+ if useFormat {
+ Printf("hello %d world", 23)
} else {
- l.Log("hello", 23, "world")
- }
- line, err3 := buf.ReadString('\n')
- if err3 != nil {
- t.Fatal("log error", err3)
+ Println("hello", 23, "world")
}
+ line := buf.String()
line = line[0 : len(line)-1]
pattern = "^" + pattern + "hello 23 world$"
matched, err4 := regexp.MatchString(pattern, line)
@@ -72,11 +65,22 @@ func testLog(t *testing.T, flag int, prefix string, pattern string, useLogf bool
if !matched {
t.Errorf("log output should match %q is %q", pattern, line)
}
+ SetOutput(os.Stderr)
}
-func TestAllLog(t *testing.T) {
+func TestAll(t *testing.T) {
for _, testcase := range tests {
- testLog(t, testcase.flag, testcase.prefix, testcase.pattern, false)
- testLog(t, testcase.flag, testcase.prefix, testcase.pattern, true)
+ testPrint(t, testcase.flag, testcase.prefix, testcase.pattern, false)
+ testPrint(t, testcase.flag, testcase.prefix, testcase.pattern, true)
+ }
+}
+
+func TestOutput(t *testing.T) {
+ const testString = "test"
+ var b bytes.Buffer
+ l := New(&b, "", 0)
+ l.Println(testString)
+ if expect := testString + "\n"; b.String() != expect {
+ t.Errorf("log output should match %q is %q", expect, b.String())
}
}
diff --git a/src/pkg/math/Makefile b/src/pkg/math/Makefile
index a2d11e43d..71347b7fa 100644
--- a/src/pkg/math/Makefile
+++ b/src/pkg/math/Makefile
@@ -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 ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=math
@@ -10,6 +10,9 @@ 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=\
@@ -26,6 +29,7 @@ OFILES_386=\
hypot_386.$O\
ldexp_386.$O\
log_386.$O\
+ log10_386.$O\
log1p_386.$O\
modf_386.$O\
remainder_386.$O\
@@ -50,6 +54,7 @@ ALLGOFILES=\
copysign.go\
erf.go\
exp.go\
+ exp_port.go\
exp2.go\
expm1.go\
fabs.go\
@@ -63,11 +68,12 @@ ALLGOFILES=\
j0.go\
j1.go\
jn.go\
- logb.go\
lgamma.go\
ldexp.go\
log.go\
+ log10.go\
log1p.go\
+ logb.go\
modf.go\
nextafter.go\
pow.go\
diff --git a/src/pkg/math/all_test.go b/src/pkg/math/all_test.go
index 18a3f1b31..6033d37e3 100644
--- a/src/pkg/math/all_test.go
+++ b/src/pkg/math/all_test.go
@@ -7,6 +7,7 @@ package math_test
import (
"fmt"
. "math"
+ "runtime"
"testing"
)
@@ -286,16 +287,16 @@ type fi struct {
}
var frexp = []fi{
- fi{6.2237649061045918750e-01, 3},
- fi{9.6735905932226306250e-01, 3},
- fi{-5.5376011438400318000e-01, -1},
- fi{-6.2632545228388436250e-01, 3},
- fi{6.02268356699901081250e-01, 4},
- fi{7.3159430981099115000e-01, 2},
- fi{6.5363542893241332500e-01, 3},
- fi{6.8198497760900255000e-01, 2},
- fi{9.1265404584042750000e-01, 1},
- fi{-5.4287029803597508250e-01, 4},
+ {6.2237649061045918750e-01, 3},
+ {9.6735905932226306250e-01, 3},
+ {-5.5376011438400318000e-01, -1},
+ {-6.2632545228388436250e-01, 3},
+ {6.02268356699901081250e-01, 4},
+ {7.3159430981099115000e-01, 2},
+ {6.5363542893241332500e-01, 3},
+ {6.8198497760900255000e-01, 2},
+ {9.1265404584042750000e-01, 1},
+ {-5.4287029803597508250e-01, 4},
}
var gamma = []float64{
2.3254348370739963835386613898e+01,
@@ -358,16 +359,16 @@ var jM3 = []float64{
-2.3762660886100206491674503e-01,
}
var lgamma = []fi{
- fi{3.146492141244545774319734e+00, 1},
- fi{8.003414490659126375852113e+00, 1},
- fi{1.517575735509779707488106e+00, -1},
- fi{-2.588480028182145853558748e-01, 1},
- fi{1.1989897050205555002007985e+01, 1},
- fi{6.262899811091257519386906e-01, 1},
- fi{3.5287924899091566764846037e+00, 1},
- fi{4.5725644770161182299423372e-01, 1},
- fi{-6.363667087767961257654854e-02, 1},
- fi{-1.077385130910300066425564e+01, -1},
+ {3.146492141244545774319734e+00, 1},
+ {8.003414490659126375852113e+00, 1},
+ {1.517575735509779707488106e+00, -1},
+ {-2.588480028182145853558748e-01, 1},
+ {1.1989897050205555002007985e+01, 1},
+ {6.262899811091257519386906e-01, 1},
+ {3.5287924899091566764846037e+00, 1},
+ {4.5725644770161182299423372e-01, 1},
+ {-6.363667087767961257654854e-02, 1},
+ {-1.077385130910300066425564e+01, -1},
}
var log = []float64{
1.605231462693062999102599e+00,
@@ -382,16 +383,16 @@ var log = []float64{
2.161703872847352815363655e+00,
}
var logb = []float64{
- 3.0000000000000000e+00,
- 3.0000000000000000e+00,
- -1.0000000000000000e+00,
- 3.0000000000000000e+00,
- 4.0000000000000000e+00,
+ 2.0000000000000000e+00,
+ 2.0000000000000000e+00,
+ -2.0000000000000000e+00,
2.0000000000000000e+00,
3.0000000000000000e+00,
+ 1.0000000000000000e+00,
2.0000000000000000e+00,
1.0000000000000000e+00,
- 4.0000000000000000e+00,
+ 0.0000000000000000e+00,
+ 3.0000000000000000e+00,
}
var log10 = []float64{
6.9714316642508290997617083e-01,
@@ -430,16 +431,16 @@ var log2 = []float64{
3.118679457227342224364709e+00,
}
var modf = [][2]float64{
- [2]float64{4.0000000000000000e+00, 9.7901192488367350108546816e-01},
- [2]float64{7.0000000000000000e+00, 7.3887247457810456552351752e-01},
- [2]float64{0.0000000000000000e+00, -2.7688005719200159404635997e-01},
- [2]float64{-5.0000000000000000e+00, -1.060361827107492160848778e-02},
- [2]float64{9.0000000000000000e+00, 6.3629370719841737980004837e-01},
- [2]float64{2.0000000000000000e+00, 9.2637723924396464525443662e-01},
- [2]float64{5.0000000000000000e+00, 2.2908343145930665230025625e-01},
- [2]float64{2.0000000000000000e+00, 7.2793991043601025126008608e-01},
- [2]float64{1.0000000000000000e+00, 8.2530809168085506044576505e-01},
- [2]float64{-8.0000000000000000e+00, -6.8592476857560136238589621e-01},
+ {4.0000000000000000e+00, 9.7901192488367350108546816e-01},
+ {7.0000000000000000e+00, 7.3887247457810456552351752e-01},
+ {0.0000000000000000e+00, -2.7688005719200159404635997e-01},
+ {-5.0000000000000000e+00, -1.060361827107492160848778e-02},
+ {9.0000000000000000e+00, 6.3629370719841737980004837e-01},
+ {2.0000000000000000e+00, 9.2637723924396464525443662e-01},
+ {5.0000000000000000e+00, 2.2908343145930665230025625e-01},
+ {2.0000000000000000e+00, 7.2793991043601025126008608e-01},
+ {1.0000000000000000e+00, 8.2530809168085506044576505e-01},
+ {-8.0000000000000000e+00, -6.8592476857560136238589621e-01},
}
var nextafter = []float64{
4.97901192488367438926388786e+00,
@@ -707,41 +708,41 @@ var atanhSC = []float64{
NaN(),
}
var vfatan2SC = [][2]float64{
- [2]float64{Inf(-1), Inf(-1)},
- [2]float64{Inf(-1), -Pi},
- [2]float64{Inf(-1), 0},
- [2]float64{Inf(-1), +Pi},
- [2]float64{Inf(-1), Inf(1)},
- [2]float64{Inf(-1), NaN()},
- [2]float64{-Pi, Inf(-1)},
- [2]float64{-Pi, 0},
- [2]float64{-Pi, Inf(1)},
- [2]float64{-Pi, NaN()},
- [2]float64{Copysign(0, -1), Inf(-1)},
- [2]float64{Copysign(0, -1), -Pi},
- [2]float64{Copysign(0, -1), Copysign(0, -1)},
- [2]float64{Copysign(0, -1), 0},
- [2]float64{Copysign(0, -1), +Pi},
- [2]float64{Copysign(0, -1), Inf(1)},
- [2]float64{Copysign(0, -1), NaN()},
- [2]float64{0, Inf(-1)},
- [2]float64{0, -Pi},
- [2]float64{0, Copysign(0, -1)},
- [2]float64{0, 0},
- [2]float64{0, +Pi},
- [2]float64{0, Inf(1)},
- [2]float64{0, NaN()},
- [2]float64{+Pi, Inf(-1)},
- [2]float64{+Pi, 0},
- [2]float64{+Pi, Inf(1)},
- [2]float64{+Pi, NaN()},
- [2]float64{Inf(1), Inf(-1)},
- [2]float64{Inf(1), -Pi},
- [2]float64{Inf(1), 0},
- [2]float64{Inf(1), +Pi},
- [2]float64{Inf(1), Inf(1)},
- [2]float64{Inf(1), NaN()},
- [2]float64{NaN(), NaN()},
+ {Inf(-1), Inf(-1)},
+ {Inf(-1), -Pi},
+ {Inf(-1), 0},
+ {Inf(-1), +Pi},
+ {Inf(-1), Inf(1)},
+ {Inf(-1), NaN()},
+ {-Pi, Inf(-1)},
+ {-Pi, 0},
+ {-Pi, Inf(1)},
+ {-Pi, NaN()},
+ {Copysign(0, -1), Inf(-1)},
+ {Copysign(0, -1), -Pi},
+ {Copysign(0, -1), Copysign(0, -1)},
+ {Copysign(0, -1), 0},
+ {Copysign(0, -1), +Pi},
+ {Copysign(0, -1), Inf(1)},
+ {Copysign(0, -1), NaN()},
+ {0, Inf(-1)},
+ {0, -Pi},
+ {0, Copysign(0, -1)},
+ {0, 0},
+ {0, +Pi},
+ {0, Inf(1)},
+ {0, NaN()},
+ {+Pi, Inf(-1)},
+ {+Pi, 0},
+ {+Pi, Inf(1)},
+ {+Pi, NaN()},
+ {Inf(1), Inf(-1)},
+ {Inf(1), -Pi},
+ {Inf(1), 0},
+ {Inf(1), +Pi},
+ {Inf(1), Inf(1)},
+ {Inf(1), NaN()},
+ {NaN(), NaN()},
}
var atan2SC = []float64{
-3 * Pi / 4, // atan2(-Inf, -Inf)
@@ -876,11 +877,15 @@ var erfcSC = []float64{
var vfexpSC = []float64{
Inf(-1),
+ -2000,
+ 2000,
Inf(1),
NaN(),
}
var expSC = []float64{
0,
+ 0,
+ Inf(1),
Inf(1),
NaN(),
}
@@ -916,40 +921,40 @@ var fabsSC = []float64{
}
var vffmodSC = [][2]float64{
- [2]float64{Inf(-1), Inf(-1)},
- [2]float64{Inf(-1), -Pi},
- [2]float64{Inf(-1), 0},
- [2]float64{Inf(-1), Pi},
- [2]float64{Inf(-1), Inf(1)},
- [2]float64{Inf(-1), NaN()},
- [2]float64{-Pi, Inf(-1)},
- [2]float64{-Pi, 0},
- [2]float64{-Pi, Inf(1)},
- [2]float64{-Pi, NaN()},
- [2]float64{Copysign(0, -1), Inf(-1)},
- [2]float64{Copysign(0, -1), 0},
- [2]float64{Copysign(0, -1), Inf(1)},
- [2]float64{Copysign(0, -1), NaN()},
- [2]float64{0, Inf(-1)},
- [2]float64{0, 0},
- [2]float64{0, Inf(1)},
- [2]float64{0, NaN()},
- [2]float64{Pi, Inf(-1)},
- [2]float64{Pi, 0},
- [2]float64{Pi, Inf(1)},
- [2]float64{Pi, NaN()},
- [2]float64{Inf(1), Inf(-1)},
- [2]float64{Inf(1), -Pi},
- [2]float64{Inf(1), 0},
- [2]float64{Inf(1), Pi},
- [2]float64{Inf(1), Inf(1)},
- [2]float64{Inf(1), NaN()},
- [2]float64{NaN(), Inf(-1)},
- [2]float64{NaN(), -Pi},
- [2]float64{NaN(), 0},
- [2]float64{NaN(), Pi},
- [2]float64{NaN(), Inf(1)},
- [2]float64{NaN(), NaN()},
+ {Inf(-1), Inf(-1)},
+ {Inf(-1), -Pi},
+ {Inf(-1), 0},
+ {Inf(-1), Pi},
+ {Inf(-1), Inf(1)},
+ {Inf(-1), NaN()},
+ {-Pi, Inf(-1)},
+ {-Pi, 0},
+ {-Pi, Inf(1)},
+ {-Pi, NaN()},
+ {Copysign(0, -1), Inf(-1)},
+ {Copysign(0, -1), 0},
+ {Copysign(0, -1), Inf(1)},
+ {Copysign(0, -1), NaN()},
+ {0, Inf(-1)},
+ {0, 0},
+ {0, Inf(1)},
+ {0, NaN()},
+ {Pi, Inf(-1)},
+ {Pi, 0},
+ {Pi, Inf(1)},
+ {Pi, NaN()},
+ {Inf(1), Inf(-1)},
+ {Inf(1), -Pi},
+ {Inf(1), 0},
+ {Inf(1), Pi},
+ {Inf(1), Inf(1)},
+ {Inf(1), NaN()},
+ {NaN(), Inf(-1)},
+ {NaN(), -Pi},
+ {NaN(), 0},
+ {NaN(), Pi},
+ {NaN(), Inf(1)},
+ {NaN(), NaN()},
}
var fmodSC = []float64{
NaN(), // fmod(-Inf, -Inf)
@@ -996,11 +1001,11 @@ var vffrexpSC = []float64{
NaN(),
}
var frexpSC = []fi{
- fi{Inf(-1), 0},
- fi{Copysign(0, -1), 0},
- fi{0, 0},
- fi{Inf(1), 0},
- fi{NaN(), 0},
+ {Inf(-1), 0},
+ {Copysign(0, -1), 0},
+ {0, 0},
+ {Inf(1), 0},
+ {NaN(), 0},
}
var vfgammaSC = []float64{
@@ -1021,25 +1026,25 @@ var gammaSC = []float64{
}
var vfhypotSC = [][2]float64{
- [2]float64{Inf(-1), Inf(-1)},
- [2]float64{Inf(-1), 0},
- [2]float64{Inf(-1), Inf(1)},
- [2]float64{Inf(-1), NaN()},
- [2]float64{Copysign(0, -1), Copysign(0, -1)},
- [2]float64{Copysign(0, -1), 0},
- [2]float64{0, Copysign(0, -1)},
- [2]float64{0, 0}, // +0, +0
- [2]float64{0, Inf(-1)},
- [2]float64{0, Inf(1)},
- [2]float64{0, NaN()},
- [2]float64{Inf(1), Inf(-1)},
- [2]float64{Inf(1), 0},
- [2]float64{Inf(1), Inf(1)},
- [2]float64{Inf(1), NaN()},
- [2]float64{NaN(), Inf(-1)},
- [2]float64{NaN(), 0},
- [2]float64{NaN(), Inf(1)},
- [2]float64{NaN(), NaN()},
+ {Inf(-1), Inf(-1)},
+ {Inf(-1), 0},
+ {Inf(-1), Inf(1)},
+ {Inf(-1), NaN()},
+ {Copysign(0, -1), Copysign(0, -1)},
+ {Copysign(0, -1), 0},
+ {0, Copysign(0, -1)},
+ {0, 0}, // +0, +0
+ {0, Inf(-1)},
+ {0, Inf(1)},
+ {0, NaN()},
+ {Inf(1), Inf(-1)},
+ {Inf(1), 0},
+ {Inf(1), Inf(1)},
+ {Inf(1), NaN()},
+ {NaN(), Inf(-1)},
+ {NaN(), 0},
+ {NaN(), Inf(1)},
+ {NaN(), NaN()},
}
var hypotSC = []float64{
Inf(1),
@@ -1117,13 +1122,13 @@ var vflgammaSC = []float64{
NaN(),
}
var lgammaSC = []fi{
- fi{Inf(-1), 1},
- fi{Inf(1), 1},
- fi{Inf(1), 1},
- fi{0, 1},
- fi{0, 1},
- fi{Inf(1), 1},
- fi{NaN(), 1},
+ {Inf(-1), 1},
+ {Inf(1), 1},
+ {Inf(1), 1},
+ {0, 1},
+ {0, 1},
+ {Inf(1), 1},
+ {NaN(), 1},
}
var vflogSC = []float64{
@@ -1183,15 +1188,15 @@ var vfmodfSC = []float64{
NaN(),
}
var modfSC = [][2]float64{
- [2]float64{Inf(-1), NaN()}, // [2]float64{Copysign(0, -1), Inf(-1)},
- [2]float64{Inf(1), NaN()}, // [2]float64{0, Inf(1)},
- [2]float64{NaN(), NaN()},
+ {Inf(-1), NaN()}, // [2]float64{Copysign(0, -1), Inf(-1)},
+ {Inf(1), NaN()}, // [2]float64{0, Inf(1)},
+ {NaN(), NaN()},
}
var vfnextafterSC = [][2]float64{
- [2]float64{0, NaN()},
- [2]float64{NaN(), 0},
- [2]float64{NaN(), NaN()},
+ {0, NaN()},
+ {NaN(), 0},
+ {NaN(), NaN()},
}
var nextafterSC = []float64{
NaN(),
@@ -1200,70 +1205,70 @@ var nextafterSC = []float64{
}
var vfpowSC = [][2]float64{
- [2]float64{Inf(-1), -Pi},
- [2]float64{Inf(-1), -3},
- [2]float64{Inf(-1), Copysign(0, -1)},
- [2]float64{Inf(-1), 0},
- [2]float64{Inf(-1), 1},
- [2]float64{Inf(-1), 3},
- [2]float64{Inf(-1), Pi},
- [2]float64{Inf(-1), NaN()},
-
- [2]float64{-Pi, Inf(-1)},
- [2]float64{-Pi, -Pi},
- [2]float64{-Pi, Copysign(0, -1)},
- [2]float64{-Pi, 0},
- [2]float64{-Pi, 1},
- [2]float64{-Pi, Pi},
- [2]float64{-Pi, Inf(1)},
- [2]float64{-Pi, NaN()},
-
- [2]float64{-1, Inf(-1)},
- [2]float64{-1, Inf(1)},
- [2]float64{-1, NaN()},
- [2]float64{-1 / 2, Inf(-1)},
- [2]float64{-1 / 2, Inf(1)},
- [2]float64{Copysign(0, -1), Inf(-1)},
- [2]float64{Copysign(0, -1), -Pi},
- [2]float64{Copysign(0, -1), -3},
- [2]float64{Copysign(0, -1), 3},
- [2]float64{Copysign(0, -1), Pi},
- [2]float64{Copysign(0, -1), Inf(1)},
-
- [2]float64{0, Inf(-1)},
- [2]float64{0, -Pi},
- [2]float64{0, -3},
- [2]float64{0, Copysign(0, -1)},
- [2]float64{0, 0},
- [2]float64{0, 3},
- [2]float64{0, Pi},
- [2]float64{0, Inf(1)},
- [2]float64{0, NaN()},
-
- [2]float64{1 / 2, Inf(-1)},
- [2]float64{1 / 2, Inf(1)},
- [2]float64{1, Inf(-1)},
- [2]float64{1, Inf(1)},
- [2]float64{1, NaN()},
-
- [2]float64{Pi, Inf(-1)},
- [2]float64{Pi, Copysign(0, -1)},
- [2]float64{Pi, 0},
- [2]float64{Pi, 1},
- [2]float64{Pi, Inf(1)},
- [2]float64{Pi, NaN()},
- [2]float64{Inf(1), -Pi},
- [2]float64{Inf(1), Copysign(0, -1)},
- [2]float64{Inf(1), 0},
- [2]float64{Inf(1), 1},
- [2]float64{Inf(1), Pi},
- [2]float64{Inf(1), NaN()},
- [2]float64{NaN(), -Pi},
- [2]float64{NaN(), Copysign(0, -1)},
- [2]float64{NaN(), 0},
- [2]float64{NaN(), 1},
- [2]float64{NaN(), Pi},
- [2]float64{NaN(), NaN()},
+ {Inf(-1), -Pi},
+ {Inf(-1), -3},
+ {Inf(-1), Copysign(0, -1)},
+ {Inf(-1), 0},
+ {Inf(-1), 1},
+ {Inf(-1), 3},
+ {Inf(-1), Pi},
+ {Inf(-1), NaN()},
+
+ {-Pi, Inf(-1)},
+ {-Pi, -Pi},
+ {-Pi, Copysign(0, -1)},
+ {-Pi, 0},
+ {-Pi, 1},
+ {-Pi, Pi},
+ {-Pi, Inf(1)},
+ {-Pi, NaN()},
+
+ {-1, Inf(-1)},
+ {-1, Inf(1)},
+ {-1, NaN()},
+ {-1 / 2, Inf(-1)},
+ {-1 / 2, Inf(1)},
+ {Copysign(0, -1), Inf(-1)},
+ {Copysign(0, -1), -Pi},
+ {Copysign(0, -1), -3},
+ {Copysign(0, -1), 3},
+ {Copysign(0, -1), Pi},
+ {Copysign(0, -1), Inf(1)},
+
+ {0, Inf(-1)},
+ {0, -Pi},
+ {0, -3},
+ {0, Copysign(0, -1)},
+ {0, 0},
+ {0, 3},
+ {0, Pi},
+ {0, Inf(1)},
+ {0, NaN()},
+
+ {1 / 2, Inf(-1)},
+ {1 / 2, Inf(1)},
+ {1, Inf(-1)},
+ {1, Inf(1)},
+ {1, NaN()},
+
+ {Pi, Inf(-1)},
+ {Pi, Copysign(0, -1)},
+ {Pi, 0},
+ {Pi, 1},
+ {Pi, Inf(1)},
+ {Pi, NaN()},
+ {Inf(1), -Pi},
+ {Inf(1), Copysign(0, -1)},
+ {Inf(1), 0},
+ {Inf(1), 1},
+ {Inf(1), Pi},
+ {Inf(1), NaN()},
+ {NaN(), -Pi},
+ {NaN(), Copysign(0, -1)},
+ {NaN(), 0},
+ {NaN(), 1},
+ {NaN(), Pi},
+ {NaN(), NaN()},
}
var powSC = []float64{
0, // pow(-Inf, -Pi)
@@ -1467,12 +1472,12 @@ func TestAcos(t *testing.T) {
for i := 0; i < len(vf); i++ {
a := vf[i] / 10
if f := Acos(a); !close(acos[i], f) {
- t.Errorf("Acos(%g) = %g, want %g\n", a, f, acos[i])
+ t.Errorf("Acos(%g) = %g, want %g", a, f, acos[i])
}
}
for i := 0; i < len(vfacosSC); i++ {
if f := Acos(vfacosSC[i]); !alike(acosSC[i], f) {
- t.Errorf("Acos(%g) = %g, want %g\n", vfacosSC[i], f, acosSC[i])
+ t.Errorf("Acos(%g) = %g, want %g", vfacosSC[i], f, acosSC[i])
}
}
}
@@ -1481,12 +1486,12 @@ func TestAcosh(t *testing.T) {
for i := 0; i < len(vf); i++ {
a := 1 + Fabs(vf[i])
if f := Acosh(a); !veryclose(acosh[i], f) {
- t.Errorf("Acosh(%g) = %g, want %g\n", a, f, acosh[i])
+ t.Errorf("Acosh(%g) = %g, want %g", a, f, acosh[i])
}
}
for i := 0; i < len(vfacoshSC); i++ {
if f := Acosh(vfacoshSC[i]); !alike(acoshSC[i], f) {
- t.Errorf("Acosh(%g) = %g, want %g\n", vfacoshSC[i], f, acoshSC[i])
+ t.Errorf("Acosh(%g) = %g, want %g", vfacoshSC[i], f, acoshSC[i])
}
}
}
@@ -1495,12 +1500,12 @@ func TestAsin(t *testing.T) {
for i := 0; i < len(vf); i++ {
a := vf[i] / 10
if f := Asin(a); !veryclose(asin[i], f) {
- t.Errorf("Asin(%g) = %g, want %g\n", a, f, asin[i])
+ t.Errorf("Asin(%g) = %g, want %g", a, f, asin[i])
}
}
for i := 0; i < len(vfasinSC); i++ {
if f := Asin(vfasinSC[i]); !alike(asinSC[i], f) {
- t.Errorf("Asin(%g) = %g, want %g\n", vfasinSC[i], f, asinSC[i])
+ t.Errorf("Asin(%g) = %g, want %g", vfasinSC[i], f, asinSC[i])
}
}
}
@@ -1508,12 +1513,12 @@ func TestAsin(t *testing.T) {
func TestAsinh(t *testing.T) {
for i := 0; i < len(vf); i++ {
if f := Asinh(vf[i]); !veryclose(asinh[i], f) {
- t.Errorf("Asinh(%g) = %g, want %g\n", vf[i], f, asinh[i])
+ t.Errorf("Asinh(%g) = %g, want %g", vf[i], f, asinh[i])
}
}
for i := 0; i < len(vfasinhSC); i++ {
if f := Asinh(vfasinhSC[i]); !alike(asinhSC[i], f) {
- t.Errorf("Asinh(%g) = %g, want %g\n", vfasinhSC[i], f, asinhSC[i])
+ t.Errorf("Asinh(%g) = %g, want %g", vfasinhSC[i], f, asinhSC[i])
}
}
}
@@ -1521,12 +1526,12 @@ func TestAsinh(t *testing.T) {
func TestAtan(t *testing.T) {
for i := 0; i < len(vf); i++ {
if f := Atan(vf[i]); !veryclose(atan[i], f) {
- t.Errorf("Atan(%g) = %g, want %g\n", vf[i], f, atan[i])
+ t.Errorf("Atan(%g) = %g, want %g", vf[i], f, atan[i])
}
}
for i := 0; i < len(vfatanSC); i++ {
if f := Atan(vfatanSC[i]); !alike(atanSC[i], f) {
- t.Errorf("Atan(%g) = %g, want %g\n", vfatanSC[i], f, atanSC[i])
+ t.Errorf("Atan(%g) = %g, want %g", vfatanSC[i], f, atanSC[i])
}
}
}
@@ -1535,12 +1540,12 @@ func TestAtanh(t *testing.T) {
for i := 0; i < len(vf); i++ {
a := vf[i] / 10
if f := Atanh(a); !veryclose(atanh[i], f) {
- t.Errorf("Atanh(%g) = %g, want %g\n", a, f, atanh[i])
+ t.Errorf("Atanh(%g) = %g, want %g", a, f, atanh[i])
}
}
for i := 0; i < len(vfatanhSC); i++ {
if f := Atanh(vfatanhSC[i]); !alike(atanhSC[i], f) {
- t.Errorf("Atanh(%g) = %g, want %g\n", vfatanhSC[i], f, atanhSC[i])
+ t.Errorf("Atanh(%g) = %g, want %g", vfatanhSC[i], f, atanhSC[i])
}
}
}
@@ -1548,12 +1553,12 @@ func TestAtanh(t *testing.T) {
func TestAtan2(t *testing.T) {
for i := 0; i < len(vf); i++ {
if f := Atan2(10, vf[i]); !veryclose(atan2[i], f) {
- t.Errorf("Atan2(10, %g) = %g, want %g\n", vf[i], f, atan2[i])
+ t.Errorf("Atan2(10, %g) = %g, want %g", vf[i], f, atan2[i])
}
}
for i := 0; i < len(vfatan2SC); i++ {
if f := Atan2(vfatan2SC[i][0], vfatan2SC[i][1]); !alike(atan2SC[i], f) {
- t.Errorf("Atan2(%g, %g) = %g, want %g\n", vfatan2SC[i][0], vfatan2SC[i][1], f, atan2SC[i])
+ t.Errorf("Atan2(%g, %g) = %g, want %g", vfatan2SC[i][0], vfatan2SC[i][1], f, atan2SC[i])
}
}
}
@@ -1561,12 +1566,12 @@ func TestAtan2(t *testing.T) {
func TestCbrt(t *testing.T) {
for i := 0; i < len(vf); i++ {
if f := Cbrt(vf[i]); !veryclose(cbrt[i], f) {
- t.Errorf("Cbrt(%g) = %g, want %g\n", vf[i], f, cbrt[i])
+ t.Errorf("Cbrt(%g) = %g, want %g", vf[i], f, cbrt[i])
}
}
for i := 0; i < len(vfcbrtSC); i++ {
if f := Cbrt(vfcbrtSC[i]); !alike(cbrtSC[i], f) {
- t.Errorf("Cbrt(%g) = %g, want %g\n", vfcbrtSC[i], f, cbrtSC[i])
+ t.Errorf("Cbrt(%g) = %g, want %g", vfcbrtSC[i], f, cbrtSC[i])
}
}
}
@@ -1574,12 +1579,12 @@ func TestCbrt(t *testing.T) {
func TestCeil(t *testing.T) {
for i := 0; i < len(vf); i++ {
if f := Ceil(vf[i]); ceil[i] != f {
- t.Errorf("Ceil(%g) = %g, want %g\n", vf[i], f, ceil[i])
+ t.Errorf("Ceil(%g) = %g, want %g", vf[i], f, ceil[i])
}
}
for i := 0; i < len(vfceilSC); i++ {
if f := Ceil(vfceilSC[i]); !alike(ceilSC[i], f) {
- t.Errorf("Ceil(%g) = %g, want %g\n", vfceilSC[i], f, ceilSC[i])
+ t.Errorf("Ceil(%g) = %g, want %g", vfceilSC[i], f, ceilSC[i])
}
}
}
@@ -1587,12 +1592,17 @@ func TestCeil(t *testing.T) {
func TestCopysign(t *testing.T) {
for i := 0; i < len(vf); i++ {
if f := Copysign(vf[i], -1); copysign[i] != f {
- t.Errorf("Copysign(%g, -1) = %g, want %g\n", vf[i], f, copysign[i])
+ t.Errorf("Copysign(%g, -1) = %g, want %g", vf[i], f, copysign[i])
+ }
+ }
+ for i := 0; i < len(vf); i++ {
+ if f := Copysign(vf[i], 1); -copysign[i] != f {
+ t.Errorf("Copysign(%g, 1) = %g, want %g", vf[i], f, -copysign[i])
}
}
for i := 0; i < len(vfcopysignSC); i++ {
if f := Copysign(vfcopysignSC[i], -1); !alike(copysignSC[i], f) {
- t.Errorf("Copysign(%g, -1) = %g, want %g\n", vfcopysignSC[i], f, copysignSC[i])
+ t.Errorf("Copysign(%g, -1) = %g, want %g", vfcopysignSC[i], f, copysignSC[i])
}
}
}
@@ -1600,12 +1610,12 @@ 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) {
- t.Errorf("Cos(%g) = %g, want %g\n", vf[i], f, cos[i])
+ t.Errorf("Cos(%g) = %g, want %g", vf[i], f, cos[i])
}
}
for i := 0; i < len(vfcosSC); i++ {
if f := Cos(vfcosSC[i]); !alike(cosSC[i], f) {
- t.Errorf("Cos(%g) = %g, want %g\n", vfcosSC[i], f, cosSC[i])
+ t.Errorf("Cos(%g) = %g, want %g", vfcosSC[i], f, cosSC[i])
}
}
}
@@ -1613,12 +1623,12 @@ func TestCos(t *testing.T) {
func TestCosh(t *testing.T) {
for i := 0; i < len(vf); i++ {
if f := Cosh(vf[i]); !close(cosh[i], f) {
- t.Errorf("Cosh(%g) = %g, want %g\n", vf[i], f, cosh[i])
+ t.Errorf("Cosh(%g) = %g, want %g", vf[i], f, cosh[i])
}
}
for i := 0; i < len(vfcoshSC); i++ {
if f := Cosh(vfcoshSC[i]); !alike(coshSC[i], f) {
- t.Errorf("Cosh(%g) = %g, want %g\n", vfcoshSC[i], f, coshSC[i])
+ t.Errorf("Cosh(%g) = %g, want %g", vfcoshSC[i], f, coshSC[i])
}
}
}
@@ -1627,12 +1637,12 @@ func TestErf(t *testing.T) {
for i := 0; i < len(vf); i++ {
a := vf[i] / 10
if f := Erf(a); !veryclose(erf[i], f) {
- t.Errorf("Erf(%g) = %g, want %g\n", a, f, erf[i])
+ t.Errorf("Erf(%g) = %g, want %g", a, f, erf[i])
}
}
for i := 0; i < len(vferfSC); i++ {
if f := Erf(vferfSC[i]); !alike(erfSC[i], f) {
- t.Errorf("Erf(%g) = %g, want %g\n", vferfSC[i], f, erfSC[i])
+ t.Errorf("Erf(%g) = %g, want %g", vferfSC[i], f, erfSC[i])
}
}
}
@@ -1641,25 +1651,30 @@ func TestErfc(t *testing.T) {
for i := 0; i < len(vf); i++ {
a := vf[i] / 10
if f := Erfc(a); !veryclose(erfc[i], f) {
- t.Errorf("Erfc(%g) = %g, want %g\n", a, f, erfc[i])
+ t.Errorf("Erfc(%g) = %g, want %g", a, f, erfc[i])
}
}
for i := 0; i < len(vferfcSC); i++ {
if f := Erfc(vferfcSC[i]); !alike(erfcSC[i], f) {
- t.Errorf("Erfc(%g) = %g, want %g\n", vferfcSC[i], f, erfcSC[i])
+ t.Errorf("Erfc(%g) = %g, want %g", vferfcSC[i], f, erfcSC[i])
}
}
}
func TestExp(t *testing.T) {
+ testExp(t, Exp, "Exp")
+ testExp(t, ExpGo, "ExpGo")
+}
+
+func testExp(t *testing.T, Exp func(float64) float64, name string) {
for i := 0; i < len(vf); i++ {
if f := Exp(vf[i]); !close(exp[i], f) {
- t.Errorf("Exp(%g) = %g, want %g\n", vf[i], f, exp[i])
+ t.Errorf("%s(%g) = %g, want %g", name, vf[i], f, exp[i])
}
}
for i := 0; i < len(vfexpSC); i++ {
if f := Exp(vfexpSC[i]); !alike(expSC[i], f) {
- t.Errorf("Exp(%g) = %g, want %g\n", vfexpSC[i], f, expSC[i])
+ t.Errorf("%s(%g) = %g, want %g", name, vfexpSC[i], f, expSC[i])
}
}
}
@@ -1668,25 +1683,37 @@ func TestExpm1(t *testing.T) {
for i := 0; i < len(vf); i++ {
a := vf[i] / 100
if f := Expm1(a); !veryclose(expm1[i], f) {
- t.Errorf("Expm1(%g) = %g, want %g\n", a, f, expm1[i])
+ t.Errorf("Expm1(%g) = %g, want %g", a, f, expm1[i])
}
}
for i := 0; i < len(vfexpm1SC); i++ {
if f := Expm1(vfexpm1SC[i]); !alike(expm1SC[i], f) {
- t.Errorf("Expm1(%g) = %g, want %g\n", vfexpm1SC[i], f, expm1SC[i])
+ t.Errorf("Expm1(%g) = %g, want %g", vfexpm1SC[i], f, expm1SC[i])
}
}
}
func TestExp2(t *testing.T) {
+ testExp2(t, Exp2, "Exp2")
+ testExp2(t, Exp2Go, "Exp2Go")
+}
+
+func testExp2(t *testing.T, Exp2 func(float64) float64, name string) {
for i := 0; i < len(vf); i++ {
if f := Exp2(vf[i]); !close(exp2[i], f) {
- t.Errorf("Exp2(%g) = %g, want %g\n", vf[i], f, exp2[i])
+ t.Errorf("%s(%g) = %g, want %g", name, vf[i], f, exp2[i])
}
}
for i := 0; i < len(vfexpSC); i++ {
if f := Exp2(vfexpSC[i]); !alike(expSC[i], f) {
- t.Errorf("Exp2(%g) = %g, want %g\n", vfexpSC[i], f, expSC[i])
+ t.Errorf("%s(%g) = %g, want %g", name, vfexpSC[i], f, expSC[i])
+ }
+ }
+ for n := -1074; n < 1024; n++ {
+ f := Exp2(float64(n))
+ vf := Ldexp(1, n)
+ if f != vf {
+ t.Errorf("%s(%d) = %g, want %g", name, n, f, vf)
}
}
}
@@ -1694,12 +1721,12 @@ func TestExp2(t *testing.T) {
func TestFabs(t *testing.T) {
for i := 0; i < len(vf); i++ {
if f := Fabs(vf[i]); fabs[i] != f {
- t.Errorf("Fabs(%g) = %g, want %g\n", vf[i], f, fabs[i])
+ t.Errorf("Fabs(%g) = %g, want %g", vf[i], f, fabs[i])
}
}
for i := 0; i < len(vffabsSC); i++ {
if f := Fabs(vffabsSC[i]); !alike(fabsSC[i], f) {
- t.Errorf("Fabs(%g) = %g, want %g\n", vffabsSC[i], f, fabsSC[i])
+ t.Errorf("Fabs(%g) = %g, want %g", vffabsSC[i], f, fabsSC[i])
}
}
}
@@ -1707,7 +1734,7 @@ func TestFabs(t *testing.T) {
func TestFdim(t *testing.T) {
for i := 0; i < len(vf); i++ {
if f := Fdim(vf[i], 0); fdim[i] != f {
- t.Errorf("Fdim(%g, %g) = %g, want %g\n", vf[i], 0.0, f, fdim[i])
+ t.Errorf("Fdim(%g, %g) = %g, want %g", vf[i], 0.0, f, fdim[i])
}
}
}
@@ -1715,12 +1742,12 @@ func TestFdim(t *testing.T) {
func TestFloor(t *testing.T) {
for i := 0; i < len(vf); i++ {
if f := Floor(vf[i]); floor[i] != f {
- t.Errorf("Floor(%g) = %g, want %g\n", vf[i], f, floor[i])
+ t.Errorf("Floor(%g) = %g, want %g", vf[i], f, floor[i])
}
}
for i := 0; i < len(vfceilSC); i++ {
if f := Floor(vfceilSC[i]); !alike(ceilSC[i], f) {
- t.Errorf("Floor(%g) = %g, want %g\n", vfceilSC[i], f, ceilSC[i])
+ t.Errorf("Floor(%g) = %g, want %g", vfceilSC[i], f, ceilSC[i])
}
}
}
@@ -1728,7 +1755,7 @@ func TestFloor(t *testing.T) {
func TestFmax(t *testing.T) {
for i := 0; i < len(vf); i++ {
if f := Fmax(vf[i], ceil[i]); ceil[i] != f {
- t.Errorf("Fmax(%g, %g) = %g, want %g\n", vf[i], ceil[i], f, ceil[i])
+ t.Errorf("Fmax(%g, %g) = %g, want %g", vf[i], ceil[i], f, ceil[i])
}
}
}
@@ -1736,7 +1763,7 @@ func TestFmax(t *testing.T) {
func TestFmin(t *testing.T) {
for i := 0; i < len(vf); i++ {
if f := Fmin(vf[i], floor[i]); floor[i] != f {
- t.Errorf("Fmin(%g, %g) = %g, want %g\n", vf[i], floor[i], f, floor[i])
+ t.Errorf("Fmin(%g, %g) = %g, want %g", vf[i], floor[i], f, floor[i])
}
}
}
@@ -1744,12 +1771,12 @@ func TestFmin(t *testing.T) {
func TestFmod(t *testing.T) {
for i := 0; i < len(vf); i++ {
if f := Fmod(10, vf[i]); fmod[i] != f {
- t.Errorf("Fmod(10, %g) = %g, want %g\n", vf[i], f, fmod[i])
+ t.Errorf("Fmod(10, %g) = %g, want %g", vf[i], f, fmod[i])
}
}
for i := 0; i < len(vffmodSC); i++ {
if f := Fmod(vffmodSC[i][0], vffmodSC[i][1]); !alike(fmodSC[i], f) {
- t.Errorf("Fmod(%g, %g) = %g, want %g\n", vffmodSC[i][0], vffmodSC[i][1], f, fmodSC[i])
+ t.Errorf("Fmod(%g, %g) = %g, want %g", vffmodSC[i][0], vffmodSC[i][1], f, fmodSC[i])
}
}
}
@@ -1757,12 +1784,12 @@ func TestFmod(t *testing.T) {
func TestFrexp(t *testing.T) {
for i := 0; i < len(vf); i++ {
if f, j := Frexp(vf[i]); !veryclose(frexp[i].f, f) || frexp[i].i != j {
- t.Errorf("Frexp(%g) = %g, %d, want %g, %d\n", vf[i], f, j, frexp[i].f, frexp[i].i)
+ t.Errorf("Frexp(%g) = %g, %d, want %g, %d", vf[i], f, j, frexp[i].f, frexp[i].i)
}
}
for i := 0; i < len(vffrexpSC); i++ {
if f, j := Frexp(vffrexpSC[i]); !alike(frexpSC[i].f, f) || frexpSC[i].i != j {
- t.Errorf("Frexp(%g) = %g, %d, want %g, %d\n", vffrexpSC[i], f, j, frexpSC[i].f, frexpSC[i].i)
+ t.Errorf("Frexp(%g) = %g, %d, want %g, %d", vffrexpSC[i], f, j, frexpSC[i].f, frexpSC[i].i)
}
}
}
@@ -1770,12 +1797,12 @@ func TestFrexp(t *testing.T) {
func TestGamma(t *testing.T) {
for i := 0; i < len(vf); i++ {
if f := Gamma(vf[i]); !close(gamma[i], f) {
- t.Errorf("Gamma(%g) = %g, want %g\n", vf[i], f, gamma[i])
+ t.Errorf("Gamma(%g) = %g, want %g", vf[i], f, gamma[i])
}
}
for i := 0; i < len(vfgammaSC); i++ {
if f := Gamma(vfgammaSC[i]); !alike(gammaSC[i], f) {
- t.Errorf("Gamma(%g) = %g, want %g\n", vfgammaSC[i], f, gammaSC[i])
+ t.Errorf("Gamma(%g) = %g, want %g", vfgammaSC[i], f, gammaSC[i])
}
}
}
@@ -1784,25 +1811,26 @@ func TestHypot(t *testing.T) {
for i := 0; i < len(vf); i++ {
a := Fabs(1e200 * tanh[i] * Sqrt(2))
if f := Hypot(1e200*tanh[i], 1e200*tanh[i]); !veryclose(a, f) {
- t.Errorf("Hypot(%g, %g) = %g, want %g\n", 1e200*tanh[i], 1e200*tanh[i], f, a)
+ t.Errorf("Hypot(%g, %g) = %g, want %g", 1e200*tanh[i], 1e200*tanh[i], f, a)
}
}
for i := 0; i < len(vfhypotSC); i++ {
if f := Hypot(vfhypotSC[i][0], vfhypotSC[i][1]); !alike(hypotSC[i], f) {
- t.Errorf("Hypot(%g, %g) = %g, want %g\n", vfhypotSC[i][0], vfhypotSC[i][1], f, hypotSC[i])
+ t.Errorf("Hypot(%g, %g) = %g, want %g", vfhypotSC[i][0], vfhypotSC[i][1], f, hypotSC[i])
}
}
}
func TestIlogb(t *testing.T) {
for i := 0; i < len(vf); i++ {
- if e := Ilogb(vf[i]); frexp[i].i != e {
- t.Errorf("Ilogb(%g) = %d, want %d\n", vf[i], e, frexp[i].i)
+ a := frexp[i].i - 1 // adjust because fr in the interval [½, 1)
+ if e := Ilogb(vf[i]); a != e {
+ t.Errorf("Ilogb(%g) = %d, want %d", vf[i], e, a)
}
}
for i := 0; i < len(vflogbSC); i++ {
if e := Ilogb(vflogbSC[i]); ilogbSC[i] != e {
- t.Errorf("Ilogb(%g) = %d, want %d\n", vflogbSC[i], e, ilogbSC[i])
+ t.Errorf("Ilogb(%g) = %d, want %d", vflogbSC[i], e, ilogbSC[i])
}
}
}
@@ -1810,12 +1838,12 @@ func TestIlogb(t *testing.T) {
func TestJ0(t *testing.T) {
for i := 0; i < len(vf); i++ {
if f := J0(vf[i]); !soclose(j0[i], f, 4e-14) {
- t.Errorf("J0(%g) = %g, want %g\n", vf[i], f, j0[i])
+ t.Errorf("J0(%g) = %g, want %g", vf[i], f, j0[i])
}
}
for i := 0; i < len(vfj0SC); i++ {
if f := J0(vfj0SC[i]); !alike(j0SC[i], f) {
- t.Errorf("J0(%g) = %g, want %g\n", vfj0SC[i], f, j0SC[i])
+ t.Errorf("J0(%g) = %g, want %g", vfj0SC[i], f, j0SC[i])
}
}
}
@@ -1823,12 +1851,12 @@ func TestJ0(t *testing.T) {
func TestJ1(t *testing.T) {
for i := 0; i < len(vf); i++ {
if f := J1(vf[i]); !close(j1[i], f) {
- t.Errorf("J1(%g) = %g, want %g\n", vf[i], f, j1[i])
+ t.Errorf("J1(%g) = %g, want %g", vf[i], f, j1[i])
}
}
for i := 0; i < len(vfj0SC); i++ {
if f := J1(vfj0SC[i]); !alike(j1SC[i], f) {
- t.Errorf("J1(%g) = %g, want %g\n", vfj0SC[i], f, j1SC[i])
+ t.Errorf("J1(%g) = %g, want %g", vfj0SC[i], f, j1SC[i])
}
}
}
@@ -1836,18 +1864,18 @@ func TestJ1(t *testing.T) {
func TestJn(t *testing.T) {
for i := 0; i < len(vf); i++ {
if f := Jn(2, vf[i]); !close(j2[i], f) {
- t.Errorf("Jn(2, %g) = %g, want %g\n", vf[i], f, j2[i])
+ t.Errorf("Jn(2, %g) = %g, want %g", vf[i], f, j2[i])
}
if f := Jn(-3, vf[i]); !close(jM3[i], f) {
- t.Errorf("Jn(-3, %g) = %g, want %g\n", vf[i], f, jM3[i])
+ t.Errorf("Jn(-3, %g) = %g, want %g", vf[i], f, jM3[i])
}
}
for i := 0; i < len(vfj0SC); i++ {
if f := Jn(2, vfj0SC[i]); !alike(j2SC[i], f) {
- t.Errorf("Jn(2, %g) = %g, want %g\n", vfj0SC[i], f, j2SC[i])
+ t.Errorf("Jn(2, %g) = %g, want %g", vfj0SC[i], f, j2SC[i])
}
if f := Jn(-3, vfj0SC[i]); !alike(jM3SC[i], f) {
- t.Errorf("Jn(-3, %g) = %g, want %g\n", vfj0SC[i], f, jM3SC[i])
+ t.Errorf("Jn(-3, %g) = %g, want %g", vfj0SC[i], f, jM3SC[i])
}
}
}
@@ -1855,12 +1883,12 @@ func TestJn(t *testing.T) {
func TestLdexp(t *testing.T) {
for i := 0; i < len(vf); i++ {
if f := Ldexp(frexp[i].f, frexp[i].i); !veryclose(vf[i], f) {
- t.Errorf("Ldexp(%g, %d) = %g, want %g\n", frexp[i].f, frexp[i].i, f, vf[i])
+ t.Errorf("Ldexp(%g, %d) = %g, want %g", frexp[i].f, frexp[i].i, f, vf[i])
}
}
for i := 0; i < len(vffrexpSC); i++ {
if f := Ldexp(frexpSC[i].f, frexpSC[i].i); !alike(vffrexpSC[i], f) {
- t.Errorf("Ldexp(%g, %d) = %g, want %g\n", frexpSC[i].f, frexpSC[i].i, f, vffrexpSC[i])
+ t.Errorf("Ldexp(%g, %d) = %g, want %g", frexpSC[i].f, frexpSC[i].i, f, vffrexpSC[i])
}
}
}
@@ -1868,12 +1896,12 @@ func TestLdexp(t *testing.T) {
func TestLgamma(t *testing.T) {
for i := 0; i < len(vf); i++ {
if f, s := Lgamma(vf[i]); !close(lgamma[i].f, f) || lgamma[i].i != s {
- t.Errorf("Lgamma(%g) = %g, %d, want %g, %d\n", vf[i], f, s, lgamma[i].f, lgamma[i].i)
+ t.Errorf("Lgamma(%g) = %g, %d, want %g, %d", vf[i], f, s, lgamma[i].f, lgamma[i].i)
}
}
for i := 0; i < len(vflgammaSC); i++ {
if f, s := Lgamma(vflgammaSC[i]); !alike(lgammaSC[i].f, f) || lgammaSC[i].i != s {
- t.Errorf("Lgamma(%g) = %g, %d, want %g, %d\n", vflgammaSC[i], f, s, lgammaSC[i].f, lgammaSC[i].i)
+ t.Errorf("Lgamma(%g) = %g, %d, want %g, %d", vflgammaSC[i], f, s, lgammaSC[i].f, lgammaSC[i].i)
}
}
}
@@ -1882,15 +1910,15 @@ func TestLog(t *testing.T) {
for i := 0; i < len(vf); i++ {
a := Fabs(vf[i])
if f := Log(a); log[i] != f {
- t.Errorf("Log(%g) = %g, want %g\n", a, f, log[i])
+ t.Errorf("Log(%g) = %g, want %g", a, f, log[i])
}
}
if f := Log(10); f != Ln10 {
- t.Errorf("Log(%g) = %g, want %g\n", 10.0, f, Ln10)
+ t.Errorf("Log(%g) = %g, want %g", 10.0, f, Ln10)
}
for i := 0; i < len(vflogSC); i++ {
if f := Log(vflogSC[i]); !alike(logSC[i], f) {
- t.Errorf("Log(%g) = %g, want %g\n", vflogSC[i], f, logSC[i])
+ t.Errorf("Log(%g) = %g, want %g", vflogSC[i], f, logSC[i])
}
}
}
@@ -1898,12 +1926,12 @@ func TestLog(t *testing.T) {
func TestLogb(t *testing.T) {
for i := 0; i < len(vf); i++ {
if f := Logb(vf[i]); logb[i] != f {
- t.Errorf("Logb(%g) = %g, want %g\n", vf[i], f, logb[i])
+ t.Errorf("Logb(%g) = %g, want %g", vf[i], f, logb[i])
}
}
for i := 0; i < len(vflogbSC); i++ {
if f := Logb(vflogbSC[i]); !alike(logbSC[i], f) {
- t.Errorf("Logb(%g) = %g, want %g\n", vflogbSC[i], f, logbSC[i])
+ t.Errorf("Logb(%g) = %g, want %g", vflogbSC[i], f, logbSC[i])
}
}
}
@@ -1912,15 +1940,15 @@ func TestLog10(t *testing.T) {
for i := 0; i < len(vf); i++ {
a := Fabs(vf[i])
if f := Log10(a); !veryclose(log10[i], f) {
- t.Errorf("Log10(%g) = %g, want %g\n", a, f, log10[i])
+ t.Errorf("Log10(%g) = %g, want %g", a, f, log10[i])
}
}
if f := Log10(E); f != Log10E {
- t.Errorf("Log10(%g) = %g, want %g\n", E, f, Log10E)
+ t.Errorf("Log10(%g) = %g, want %g", E, f, Log10E)
}
for i := 0; i < len(vflogSC); i++ {
if f := Log10(vflogSC[i]); !alike(logSC[i], f) {
- t.Errorf("Log10(%g) = %g, want %g\n", vflogSC[i], f, logSC[i])
+ t.Errorf("Log10(%g) = %g, want %g", vflogSC[i], f, logSC[i])
}
}
}
@@ -1929,16 +1957,16 @@ func TestLog1p(t *testing.T) {
for i := 0; i < len(vf); i++ {
a := vf[i] / 100
if f := Log1p(a); !veryclose(log1p[i], f) {
- t.Errorf("Log1p(%g) = %g, want %g\n", a, f, log1p[i])
+ t.Errorf("Log1p(%g) = %g, want %g", a, f, log1p[i])
}
}
a := float64(9)
if f := Log1p(a); f != Ln10 {
- t.Errorf("Log1p(%g) = %g, want %g\n", a, f, Ln10)
+ t.Errorf("Log1p(%g) = %g, want %g", a, f, Ln10)
}
for i := 0; i < len(vflogSC); i++ {
if f := Log1p(vflog1pSC[i]); !alike(log1pSC[i], f) {
- t.Errorf("Log1p(%g) = %g, want %g\n", vflog1pSC[i], f, log1pSC[i])
+ t.Errorf("Log1p(%g) = %g, want %g", vflog1pSC[i], f, log1pSC[i])
}
}
}
@@ -1947,15 +1975,15 @@ func TestLog2(t *testing.T) {
for i := 0; i < len(vf); i++ {
a := Fabs(vf[i])
if f := Log2(a); !veryclose(log2[i], f) {
- t.Errorf("Log2(%g) = %g, want %g\n", a, f, log2[i])
+ t.Errorf("Log2(%g) = %g, want %g", a, f, log2[i])
}
}
if f := Log2(E); f != Log2E {
- t.Errorf("Log2(%g) = %g, want %g\n", E, f, Log2E)
+ t.Errorf("Log2(%g) = %g, want %g", E, f, Log2E)
}
for i := 0; i < len(vflogSC); i++ {
if f := Log2(vflogSC[i]); !alike(logSC[i], f) {
- t.Errorf("Log2(%g) = %g, want %g\n", vflogSC[i], f, logSC[i])
+ t.Errorf("Log2(%g) = %g, want %g", vflogSC[i], f, logSC[i])
}
}
}
@@ -1963,12 +1991,12 @@ func TestLog2(t *testing.T) {
func TestModf(t *testing.T) {
for i := 0; i < len(vf); i++ {
if f, g := Modf(vf[i]); !veryclose(modf[i][0], f) || !veryclose(modf[i][1], g) {
- t.Errorf("Modf(%g) = %g, %g, want %g, %g\n", vf[i], f, g, modf[i][0], modf[i][1])
+ t.Errorf("Modf(%g) = %g, %g, want %g, %g", vf[i], f, g, modf[i][0], modf[i][1])
}
}
for i := 0; i < len(vfmodfSC); i++ {
if f, g := Modf(vfmodfSC[i]); !alike(modfSC[i][0], f) || !alike(modfSC[i][1], g) {
- t.Errorf("Modf(%g) = %g, %g, want %g, %g\n", vfmodfSC[i], f, g, modfSC[i][0], modfSC[i][1])
+ t.Errorf("Modf(%g) = %g, %g, want %g, %g", vfmodfSC[i], f, g, modfSC[i][0], modfSC[i][1])
}
}
}
@@ -1976,12 +2004,12 @@ func TestModf(t *testing.T) {
func TestNextafter(t *testing.T) {
for i := 0; i < len(vf); i++ {
if f := Nextafter(vf[i], 10); nextafter[i] != f {
- t.Errorf("Nextafter(%g, %g) = %g want %g\n", vf[i], 10.0, f, nextafter[i])
+ t.Errorf("Nextafter(%g, %g) = %g want %g", vf[i], 10.0, f, nextafter[i])
}
}
for i := 0; i < len(vfmodfSC); i++ {
if f := Nextafter(vfnextafterSC[i][0], vfnextafterSC[i][1]); !alike(nextafterSC[i], f) {
- t.Errorf("Nextafter(%g, %g) = %g want %g\n", vfnextafterSC[i][0], vfnextafterSC[i][1], f, nextafterSC[i])
+ t.Errorf("Nextafter(%g, %g) = %g want %g", vfnextafterSC[i][0], vfnextafterSC[i][1], f, nextafterSC[i])
}
}
}
@@ -1989,12 +2017,12 @@ func TestNextafter(t *testing.T) {
func TestPow(t *testing.T) {
for i := 0; i < len(vf); i++ {
if f := Pow(10, vf[i]); !close(pow[i], f) {
- t.Errorf("Pow(10, %g) = %g, want %g\n", vf[i], f, pow[i])
+ t.Errorf("Pow(10, %g) = %g, want %g", vf[i], f, pow[i])
}
}
for i := 0; i < len(vfpowSC); i++ {
if f := Pow(vfpowSC[i][0], vfpowSC[i][1]); !alike(powSC[i], f) {
- t.Errorf("Pow(%g, %g) = %g, want %g\n", vfpowSC[i][0], vfpowSC[i][1], f, powSC[i])
+ t.Errorf("Pow(%g, %g) = %g, want %g", vfpowSC[i][0], vfpowSC[i][1], f, powSC[i])
}
}
}
@@ -2002,12 +2030,12 @@ func TestPow(t *testing.T) {
func TestRemainder(t *testing.T) {
for i := 0; i < len(vf); i++ {
if f := Remainder(10, vf[i]); remainder[i] != f {
- t.Errorf("Remainder(10, %g) = %g, want %g\n", vf[i], f, remainder[i])
+ t.Errorf("Remainder(10, %g) = %g, want %g", vf[i], f, remainder[i])
}
}
for i := 0; i < len(vffmodSC); i++ {
if f := Remainder(vffmodSC[i][0], vffmodSC[i][1]); !alike(fmodSC[i], f) {
- t.Errorf("Remainder(%g, %g) = %g, want %g\n", vffmodSC[i][0], vffmodSC[i][1], f, fmodSC[i])
+ t.Errorf("Remainder(%g, %g) = %g, want %g", vffmodSC[i][0], vffmodSC[i][1], f, fmodSC[i])
}
}
}
@@ -2015,24 +2043,24 @@ func TestRemainder(t *testing.T) {
func TestSignbit(t *testing.T) {
for i := 0; i < len(vf); i++ {
if f := Signbit(vf[i]); signbit[i] != f {
- t.Errorf("Signbit(%g) = %t, want %t\n", vf[i], f, signbit[i])
+ t.Errorf("Signbit(%g) = %t, want %t", vf[i], f, signbit[i])
}
}
for i := 0; i < len(vfsignbitSC); i++ {
if f := Signbit(vfsignbitSC[i]); signbitSC[i] != f {
- t.Errorf("Signbit(%g) = %t, want %t\n", vfsignbitSC[i], f, signbitSC[i])
+ t.Errorf("Signbit(%g) = %t, want %t", vfsignbitSC[i], f, signbitSC[i])
}
}
}
func TestSin(t *testing.T) {
for i := 0; i < len(vf); i++ {
if f := Sin(vf[i]); !close(sin[i], f) {
- t.Errorf("Sin(%g) = %g, want %g\n", vf[i], f, sin[i])
+ t.Errorf("Sin(%g) = %g, want %g", vf[i], f, sin[i])
}
}
for i := 0; i < len(vfsinSC); i++ {
if f := Sin(vfsinSC[i]); !alike(sinSC[i], f) {
- t.Errorf("Sin(%g) = %g, want %g\n", vfsinSC[i], f, sinSC[i])
+ t.Errorf("Sin(%g) = %g, want %g", vfsinSC[i], f, sinSC[i])
}
}
}
@@ -2040,7 +2068,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) {
- t.Errorf("Sincos(%g) = %g, %g want %g, %g\n", vf[i], s, c, sin[i], cos[i])
+ t.Errorf("Sincos(%g) = %g, %g want %g, %g", vf[i], s, c, sin[i], cos[i])
}
}
}
@@ -2048,12 +2076,12 @@ func TestSincos(t *testing.T) {
func TestSinh(t *testing.T) {
for i := 0; i < len(vf); i++ {
if f := Sinh(vf[i]); !close(sinh[i], f) {
- t.Errorf("Sinh(%g) = %g, want %g\n", vf[i], f, sinh[i])
+ t.Errorf("Sinh(%g) = %g, want %g", vf[i], f, sinh[i])
}
}
for i := 0; i < len(vfsinhSC); i++ {
if f := Sinh(vfsinhSC[i]); !alike(sinhSC[i], f) {
- t.Errorf("Sinh(%g) = %g, want %g\n", vfsinhSC[i], f, sinhSC[i])
+ t.Errorf("Sinh(%g) = %g, want %g", vfsinhSC[i], f, sinhSC[i])
}
}
}
@@ -2062,19 +2090,19 @@ func TestSqrt(t *testing.T) {
for i := 0; i < len(vf); i++ {
a := Fabs(vf[i])
if f := SqrtGo(a); sqrt[i] != f {
- t.Errorf("SqrtGo(%g) = %g, want %g\n", a, f, sqrt[i])
+ t.Errorf("SqrtGo(%g) = %g, want %g", a, f, sqrt[i])
}
a = Fabs(vf[i])
if f := Sqrt(a); sqrt[i] != f {
- t.Errorf("Sqrt(%g) = %g, want %g\n", a, f, sqrt[i])
+ t.Errorf("Sqrt(%g) = %g, want %g", a, f, sqrt[i])
}
}
for i := 0; i < len(vfsqrtSC); i++ {
if f := SqrtGo(vfsqrtSC[i]); !alike(sqrtSC[i], f) {
- t.Errorf("SqrtGo(%g) = %g, want %g\n", vfsqrtSC[i], f, sqrtSC[i])
+ t.Errorf("SqrtGo(%g) = %g, want %g", vfsqrtSC[i], f, sqrtSC[i])
}
if f := Sqrt(vfsqrtSC[i]); !alike(sqrtSC[i], f) {
- t.Errorf("Sqrt(%g) = %g, want %g\n", vfsqrtSC[i], f, sqrtSC[i])
+ t.Errorf("Sqrt(%g) = %g, want %g", vfsqrtSC[i], f, sqrtSC[i])
}
}
}
@@ -2082,13 +2110,23 @@ 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) {
- t.Errorf("Tan(%g) = %g, want %g\n", vf[i], f, tan[i])
+ t.Errorf("Tan(%g) = %g, want %g", vf[i], f, tan[i])
}
}
// same special cases as Sin
for i := 0; i < len(vfsinSC); i++ {
if f := Tan(vfsinSC[i]); !alike(sinSC[i], f) {
- t.Errorf("Tan(%g) = %g, want %g\n", vfsinSC[i], f, sinSC[i])
+ 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())
}
}
}
@@ -2096,12 +2134,12 @@ func TestTan(t *testing.T) {
func TestTanh(t *testing.T) {
for i := 0; i < len(vf); i++ {
if f := Tanh(vf[i]); !veryclose(tanh[i], f) {
- t.Errorf("Tanh(%g) = %g, want %g\n", vf[i], f, tanh[i])
+ t.Errorf("Tanh(%g) = %g, want %g", vf[i], f, tanh[i])
}
}
for i := 0; i < len(vftanhSC); i++ {
if f := Tanh(vftanhSC[i]); !alike(tanhSC[i], f) {
- t.Errorf("Tanh(%g) = %g, want %g\n", vftanhSC[i], f, tanhSC[i])
+ t.Errorf("Tanh(%g) = %g, want %g", vftanhSC[i], f, tanhSC[i])
}
}
}
@@ -2109,12 +2147,12 @@ func TestTanh(t *testing.T) {
func TestTrunc(t *testing.T) {
for i := 0; i < len(vf); i++ {
if f := Trunc(vf[i]); trunc[i] != f {
- t.Errorf("Trunc(%g) = %g, want %g\n", vf[i], f, trunc[i])
+ t.Errorf("Trunc(%g) = %g, want %g", vf[i], f, trunc[i])
}
}
for i := 0; i < len(vfceilSC); i++ {
if f := Trunc(vfceilSC[i]); !alike(ceilSC[i], f) {
- t.Errorf("Trunc(%g) = %g, want %g\n", vfceilSC[i], f, ceilSC[i])
+ t.Errorf("Trunc(%g) = %g, want %g", vfceilSC[i], f, ceilSC[i])
}
}
}
@@ -2123,12 +2161,12 @@ func TestY0(t *testing.T) {
for i := 0; i < len(vf); i++ {
a := Fabs(vf[i])
if f := Y0(a); !close(y0[i], f) {
- t.Errorf("Y0(%g) = %g, want %g\n", a, f, y0[i])
+ t.Errorf("Y0(%g) = %g, want %g", a, f, y0[i])
}
}
for i := 0; i < len(vfy0SC); i++ {
if f := Y0(vfy0SC[i]); !alike(y0SC[i], f) {
- t.Errorf("Y0(%g) = %g, want %g\n", vfy0SC[i], f, y0SC[i])
+ t.Errorf("Y0(%g) = %g, want %g", vfy0SC[i], f, y0SC[i])
}
}
}
@@ -2137,12 +2175,12 @@ func TestY1(t *testing.T) {
for i := 0; i < len(vf); i++ {
a := Fabs(vf[i])
if f := Y1(a); !soclose(y1[i], f, 2e-14) {
- t.Errorf("Y1(%g) = %g, want %g\n", a, f, y1[i])
+ t.Errorf("Y1(%g) = %g, want %g", a, f, y1[i])
}
}
for i := 0; i < len(vfy0SC); i++ {
if f := Y1(vfy0SC[i]); !alike(y1SC[i], f) {
- t.Errorf("Y1(%g) = %g, want %g\n", vfy0SC[i], f, y1SC[i])
+ t.Errorf("Y1(%g) = %g, want %g", vfy0SC[i], f, y1SC[i])
}
}
}
@@ -2151,18 +2189,18 @@ func TestYn(t *testing.T) {
for i := 0; i < len(vf); i++ {
a := Fabs(vf[i])
if f := Yn(2, a); !close(y2[i], f) {
- t.Errorf("Yn(2, %g) = %g, want %g\n", a, f, y2[i])
+ t.Errorf("Yn(2, %g) = %g, want %g", a, f, y2[i])
}
if f := Yn(-3, a); !close(yM3[i], f) {
- t.Errorf("Yn(-3, %g) = %g, want %g\n", a, f, yM3[i])
+ t.Errorf("Yn(-3, %g) = %g, want %g", a, f, yM3[i])
}
}
for i := 0; i < len(vfy0SC); i++ {
if f := Yn(2, vfy0SC[i]); !alike(y2SC[i], f) {
- t.Errorf("Yn(2, %g) = %g, want %g\n", vfy0SC[i], f, y2SC[i])
+ t.Errorf("Yn(2, %g) = %g, want %g", vfy0SC[i], f, y2SC[i])
}
if f := Yn(-3, vfy0SC[i]); !alike(yM3SC[i], f) {
- t.Errorf("Yn(-3, %g) = %g, want %g\n", vfy0SC[i], f, yM3SC[i])
+ t.Errorf("Yn(-3, %g) = %g, want %g", vfy0SC[i], f, yM3SC[i])
}
}
}
@@ -2175,7 +2213,7 @@ func TestLargeCos(t *testing.T) {
f1 := Cos(vf[i])
f2 := Cos(vf[i] + large)
if !kindaclose(f1, f2) {
- t.Errorf("Cos(%g) = %g, want %g\n", vf[i]+large, f2, f1)
+ t.Errorf("Cos(%g) = %g, want %g", vf[i]+large, f2, f1)
}
}
}
@@ -2186,7 +2224,7 @@ func TestLargeSin(t *testing.T) {
f1 := Sin(vf[i])
f2 := Sin(vf[i] + large)
if !kindaclose(f1, f2) {
- t.Errorf("Sin(%g) = %g, want %g\n", vf[i]+large, f2, f1)
+ t.Errorf("Sin(%g) = %g, want %g", vf[i]+large, f2, f1)
}
}
}
@@ -2197,7 +2235,7 @@ func TestLargeSincos(t *testing.T) {
f1, g1 := Sincos(vf[i])
f2, g2 := Sincos(vf[i] + large)
if !kindaclose(f1, f2) || !kindaclose(g1, g2) {
- t.Errorf("Sincos(%g) = %g, %g, want %g, %g\n", vf[i]+large, f2, g2, f1, g1)
+ t.Errorf("Sincos(%g) = %g, %g, want %g, %g", vf[i]+large, f2, g2, f1, g1)
}
}
}
@@ -2208,7 +2246,7 @@ func TestLargeTan(t *testing.T) {
f1 := Tan(vf[i])
f2 := Tan(vf[i] + large)
if !kindaclose(f1, f2) {
- t.Errorf("Tan(%g) = %g, want %g\n", vf[i]+large, f2, f1)
+ t.Errorf("Tan(%g) = %g, want %g", vf[i]+large, f2, f1)
}
}
}
@@ -2224,10 +2262,10 @@ type floatTest struct {
}
var floatTests = []floatTest{
- floatTest{float64(MaxFloat64), "MaxFloat64", "1.7976931348623157e+308"},
- floatTest{float64(MinFloat64), "MinFloat64", "5e-324"},
- floatTest{float32(MaxFloat32), "MaxFloat32", "3.4028235e+38"},
- floatTest{float32(MinFloat32), "MinFloat32", "1e-45"},
+ {float64(MaxFloat64), "MaxFloat64", "1.7976931348623157e+308"},
+ {float64(SmallestNonzeroFloat64), "SmallestNonzeroFloat64", "5e-324"},
+ {float32(MaxFloat32), "MaxFloat32", "3.4028235e+38"},
+ {float32(SmallestNonzeroFloat32), "SmallestNonzeroFloat32", "1e-45"},
}
func TestFloatMinMax(t *testing.T) {
@@ -2331,6 +2369,12 @@ func BenchmarkExp(b *testing.B) {
}
}
+func BenchmarkExpGo(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ ExpGo(.5)
+ }
+}
+
func BenchmarkExpm1(b *testing.B) {
for i := 0; i < b.N; i++ {
Expm1(.5)
@@ -2343,6 +2387,12 @@ func BenchmarkExp2(b *testing.B) {
}
}
+func BenchmarkExp2Go(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Exp2Go(.5)
+ }
+}
+
func BenchmarkFabs(b *testing.B) {
for i := 0; i < b.N; i++ {
Fabs(.5)
diff --git a/src/pkg/math/bits.go b/src/pkg/math/bits.go
index d36cd18d7..1a97e7679 100644
--- a/src/pkg/math/bits.go
+++ b/src/pkg/math/bits.go
@@ -10,7 +10,7 @@ const (
uvneginf = 0xFFF0000000000000
mask = 0x7FF
shift = 64 - 11 - 1
- bias = 1022
+ bias = 1023
)
// Inf returns positive infinity if sign >= 0, negative infinity if sign < 0.
diff --git a/src/pkg/math/const.go b/src/pkg/math/const.go
index 6a78d00a0..b53527a4f 100644
--- a/src/pkg/math/const.go
+++ b/src/pkg/math/const.go
@@ -25,13 +25,13 @@ const (
// Floating-point limit values.
// Max is the largest finite value representable by the type.
-// Min is the smallest nonzero 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 */
- MinFloat32 = 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 */
- MinFloat64 = 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.
diff --git a/src/pkg/math/exp.go b/src/pkg/math/exp.go
index 90409c341..c519c2cb6 100644
--- a/src/pkg/math/exp.go
+++ b/src/pkg/math/exp.go
@@ -4,83 +4,6 @@
package math
-
-// The original C code, the long comment, and the constants
-// below are from FreeBSD's /usr/src/lib/msun/src/e_exp.c
-// and came with this notice. The go code is a simplified
-// 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:
@@ -88,54 +11,4 @@ package math
// Exp(NaN) = NaN
// Very large values overflow to 0 or +Inf.
// Very small values underflow to 1.
-func Exp(x float64) float64 {
- const (
- Ln2Hi = 6.93147180369123816490e-01
- Ln2Lo = 1.90821492927058770002e-10
- Log2e = 1.44269504088896338700e+00
- 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 */
-
- 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
- }
-
- // 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
- r := hi - lo
-
- // compute
- 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)
-}
+func Exp(x float64) float64 { return expGo(x) }
diff --git a/src/pkg/math/exp2.go b/src/pkg/math/exp2.go
index 1e67f29eb..1cface9d3 100644
--- a/src/pkg/math/exp2.go
+++ b/src/pkg/math/exp2.go
@@ -7,4 +7,4 @@ 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 Exp(x * Ln2) }
+func Exp2(x float64) float64 { return exp2Go(x) }
diff --git a/src/pkg/math/exp_amd64.s b/src/pkg/math/exp_amd64.s
index 844b5c923..74c9c876a 100644
--- a/src/pkg/math/exp_amd64.s
+++ b/src/pkg/math/exp_amd64.s
@@ -19,20 +19,32 @@
#define LOG2E 1.4426950408889634073599246810018920 // 1/LN2
#define LN2U 0.69314718055966295651160180568695068359375 // upper half LN2
#define LN2L 0.28235290563031577122588448175013436025525412068e-12 // lower half LN2
+#define T0 1.0
+#define T1 0.5
+#define T2 1.6666666666666666667e-1
+#define T3 4.1666666666666666667e-2
+#define T4 8.3333333333333333333e-3
+#define T5 1.3888888888888888889e-3
+#define T6 1.9841269841269841270e-4
+#define T7 2.4801587301587301587e-5
+#define PosInf 0x7FF0000000000000
+#define NegInf 0xFFF0000000000000
// func Exp(x float64) float64
TEXT ·Exp(SB),7,$0
// test bits for not-finite
- MOVQ x+0(FP), AX
- MOVQ $0x7ff0000000000000, BX
- ANDQ BX, AX
- CMPQ BX, AX
- JEQ not_finite
- MOVSD x+0(FP), X0
+ MOVQ x+0(FP), BX
+ MOVQ $~(1<<63), AX // sign bit mask
+ MOVQ BX, DX
+ ANDQ AX, DX
+ MOVQ $PosInf, AX
+ CMPQ AX, DX
+ JLE notFinite
+ MOVQ BX, X0
MOVSD $LOG2E, X1
MULSD X0, X1
- CVTTSD2SQ X1, BX // BX = exponent
- CVTSQ2SD BX, X1
+ CVTSD2SL X1, BX // BX = exponent
+ CVTSL2SD BX, X1
MOVSD $LN2U, X2
MULSD X1, X2
SUBSD X2, X0
@@ -40,31 +52,23 @@ TEXT ·Exp(SB),7,$0
MULSD X1, X2
SUBSD X2, X0
// reduce argument
- MOVSD $0.0625, X1
- MULSD X1, X0
+ MULSD $0.0625, X0
// Taylor series evaluation
- MOVSD $2.4801587301587301587e-5, X1
+ MOVSD $T7, X1
MULSD X0, X1
- MOVSD $1.9841269841269841270e-4, X2
- ADDSD X2, X1
+ ADDSD $T6, X1
MULSD X0, X1
- MOVSD $1.3888888888888888889e-3, X2
- ADDSD X2, X1
+ ADDSD $T5, X1
MULSD X0, X1
- MOVSD $8.3333333333333333333e-3, X2
- ADDSD X2, X1
+ ADDSD $T4, X1
MULSD X0, X1
- MOVSD $4.1666666666666666667e-2, X2
- ADDSD X2, X1
+ ADDSD $T3, X1
MULSD X0, X1
- MOVSD $1.6666666666666666667e-1, X2
- ADDSD X2, X1
+ ADDSD $T2, X1
MULSD X0, X1
- MOVSD $0.5, X2
- ADDSD X2, X1
+ ADDSD $T1, X1
MULSD X0, X1
- MOVSD $1.0, X2
- ADDSD X2, X1
+ ADDSD $T0, X1
MULSD X1, X0
MOVSD $2.0, X1
ADDSD X0, X1
@@ -78,27 +82,31 @@ TEXT ·Exp(SB),7,$0
MOVSD $2.0, X1
ADDSD X0, X1
MULSD X1, X0
- MOVSD $1.0, X1
- ADDSD X1, X0
- // return ldexp(fr, exp)
- MOVQ $0x3ff, AX // bias + 1
- ADDQ AX, BX
+ ADDSD $1.0, X0
+ // return fr * 2**exponent
+ MOVL $0x3FF, AX // bias
+ ADDL AX, BX
+ JLE underflow
+ CMPL BX, $0x7FF
+ JGE overflow
+ MOVL $52, CX
+ SHLQ CX, BX
MOVQ BX, X1
- MOVQ $52, AX // shift
- MOVQ AX, X2
- PSLLQ X2, X1
MULSD X1, X0
MOVSD X0, r+8(FP)
RET
-not_finite:
-// test bits for -Inf
- MOVQ x+0(FP), AX
- MOVQ $0xfff0000000000000, BX
- CMPQ BX, AX
- JNE not_neginf
- XORQ AX, AX
+notFinite:
+ // test bits for -Inf
+ MOVQ $NegInf, AX
+ CMPQ AX, BX
+ JNE notNegInf
+ // -Inf, return 0
+underflow: // return 0
+ MOVQ $0, AX
MOVQ AX, r+8(FP)
RET
-not_neginf:
- MOVQ AX, r+8(FP)
+overflow: // return +Inf
+ MOVQ $PosInf, BX
+notNegInf: // NaN or +Inf, return x
+ MOVQ BX, r+8(FP)
RET
diff --git a/src/pkg/math/exp_port.go b/src/pkg/math/exp_port.go
new file mode 100644
index 000000000..071420c24
--- /dev/null
+++ b/src/pkg/math/exp_port.go
@@ -0,0 +1,192 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+
+// The original C code, the long comment, and the constants
+// below are from FreeBSD's /usr/src/lib/msun/src/e_exp.c
+// and came with this notice. The go code is a simplified
+// version of the original C.
+//
+// ====================================================
+// Copyright (C) 2004 by Sun Microsystems, Inc. All rights reserved.
+//
+// Permission to use, copy, modify, and distribute this
+// software is freely granted, provided that this notice
+// is preserved.
+// ====================================================
+//
+//
+// exp(x)
+// Returns the exponential of x.
+//
+// Method
+// 1. Argument reduction:
+// Reduce x to an r so that |r| <= 0.5*ln2 ~ 0.34658.
+// Given x, find r and integer k such that
+//
+// x = k*ln2 + r, |r| <= 0.5*ln2.
+//
+// Here r will be represented as r = hi-lo for better
+// accuracy.
+//
+// 2. Approximation of exp(r) by a special rational function on
+// the interval [0,0.34658]:
+// Write
+// R(r**2) = r*(exp(r)+1)/(exp(r)-1) = 2 + r*r/6 - r**4/360 + ...
+// We use a special Remes algorithm on [0,0.34658] to generate
+// a polynomial of degree 5 to approximate R. The maximum error
+// of this polynomial approximation is bounded by 2**-59. In
+// other words,
+// R(z) ~ 2.0 + P1*z + P2*z**2 + P3*z**3 + P4*z**4 + P5*z**5
+// (where z=r*r, and the values of P1 to P5 are listed below)
+// and
+// | 5 | -59
+// | 2.0+P1*z+...+P5*z - R(z) | <= 2
+// | |
+// The computation of exp(r) thus becomes
+// 2*r
+// exp(r) = 1 + -------
+// R - r
+// r*R1(r)
+// = 1 + r + ----------- (for better accuracy)
+// 2 - R1(r)
+// where
+// 2 4 10
+// R1(r) = r - (P1*r + P2*r + ... + P5*r ).
+//
+// 3. Scale back to obtain exp(x):
+// From step 1, we have
+// exp(x) = 2**k * exp(r)
+//
+// Special cases:
+// exp(INF) is INF, exp(NaN) is NaN;
+// exp(-INF) is 0, and
+// for finite argument, only exp(0)=1 is exact.
+//
+// Accuracy:
+// according to an error analysis, the error is always less than
+// 1 ulp (unit in the last place).
+//
+// Misc. info.
+// For IEEE double
+// if x > 7.09782712893383973096e+02 then exp(x) overflow
+// if x < -7.45133219101941108420e+02 then exp(x) underflow
+//
+// Constants:
+// The hexadecimal values are the intended ones for the following
+// constants. The decimal values may be used, provided that the
+// compiler will convert from decimal to binary accurately enough
+// to produce the hexadecimal values shown.
+
+// Exp returns e**x, the base-e exponential of x.
+//
+// Special cases are:
+// Exp(+Inf) = +Inf
+// Exp(NaN) = NaN
+// Very large values overflow to 0 or +Inf.
+// Very small values underflow to 1.
+func expGo(x float64) float64 {
+ const (
+ Ln2Hi = 6.93147180369123816490e-01
+ Ln2Lo = 1.90821492927058770002e-10
+ Log2e = 1.44269504088896338700e+00
+
+ Overflow = 7.09782712893383973096e+02
+ Underflow = -7.45133219101941108420e+02
+ NearZero = 1.0 / (1 << 28) // 2**-28
+ )
+
+ // TODO(rsc): Remove manual inlining of IsNaN, IsInf
+ // when compiler does it for us
+ // special cases
+ switch {
+ case x != x || x > MaxFloat64: // IsNaN(x) || IsInf(x, 1):
+ return x
+ case x < -MaxFloat64: // IsInf(x, -1):
+ return 0
+ case x > Overflow:
+ return Inf(1)
+ case x < Underflow:
+ return 0
+ case -NearZero < x && x < NearZero:
+ return 1 + x
+ }
+
+ // reduce; computed as r = hi - lo for extra precision.
+ var k int
+ switch {
+ case x < 0:
+ k = int(Log2e*x - 0.5)
+ case x > 0:
+ k = int(Log2e*x + 0.5)
+ }
+ hi := x - float64(k)*Ln2Hi
+ lo := float64(k) * Ln2Lo
+
+ // compute
+ return exp(hi, lo, k)
+}
+
+// Exp2 returns 2**x, the base-2 exponential of x.
+//
+// Special cases are the same as Exp.
+func exp2Go(x float64) float64 {
+ const (
+ Ln2Hi = 6.93147180369123816490e-01
+ Ln2Lo = 1.90821492927058770002e-10
+
+ Overflow = 1.0239999999999999e+03
+ Underflow = -1.0740e+03
+ )
+
+ // TODO: remove manual inlining of IsNaN and IsInf
+ // when compiler does it for us
+ // special cases
+ switch {
+ case x != x || x > MaxFloat64: // IsNaN(x) || IsInf(x, 1):
+ return x
+ case x < -MaxFloat64: // IsInf(x, -1):
+ return 0
+ case x > Overflow:
+ return Inf(1)
+ case x < Underflow:
+ return 0
+ }
+
+ // argument reduction; x = r×lg(e) + k with |r| ≤ ln(2)/2.
+ // computed as r = hi - lo for extra precision.
+ var k int
+ switch {
+ case x > 0:
+ k = int(x + 0.5)
+ case x < 0:
+ k = int(x - 0.5)
+ }
+ t := x - float64(k)
+ hi := t * Ln2Hi
+ lo := -t * Ln2Lo
+
+ // compute
+ return exp(hi, lo, k)
+}
+
+// exp returns e**r × 2**k where r = hi - lo and |r| ≤ ln(2)/2.
+func exp(hi, lo float64, k int) float64 {
+ const (
+ P1 = 1.66666666666666019037e-01 /* 0x3FC55555; 0x5555553E */
+ P2 = -2.77777777770155933842e-03 /* 0xBF66C16C; 0x16BEBD93 */
+ P3 = 6.61375632143793436117e-05 /* 0x3F11566A; 0xAF25DE2C */
+ P4 = -1.65339022054652515390e-06 /* 0xBEBBBD41; 0xC5D26BF1 */
+ P5 = 4.13813679705723846039e-08 /* 0x3E663769; 0x72BEA4D0 */
+ )
+
+ r := hi - lo
+ t := r * r
+ c := r - t*(P1+t*(P2+t*(P3+t*(P4+t*P5))))
+ y := 1 - ((lo - (r*c)/(2-c)) - hi)
+ // TODO(rsc): make sure Ldexp can handle boundary k
+ return Ldexp(y, k)
+}
diff --git a/src/pkg/math/exp_test.go b/src/pkg/math/exp_test.go
new file mode 100644
index 000000000..7381fd5ad
--- /dev/null
+++ b/src/pkg/math/exp_test.go
@@ -0,0 +1,10 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// Make expGo and exp2Go available for testing.
+
+func ExpGo(x float64) float64 { return expGo(x) }
+func Exp2Go(x float64) float64 { return exp2Go(x) }
diff --git a/src/pkg/math/frexp.go b/src/pkg/math/frexp.go
index b63b508e6..203219c0d 100644
--- a/src/pkg/math/frexp.go
+++ b/src/pkg/math/frexp.go
@@ -19,9 +19,9 @@ func Frexp(f float64) (frac float64, exp int) {
return f, 0
}
x := Float64bits(f)
- exp = int((x>>shift)&mask) - bias
+ exp = int((x>>shift)&mask) - bias + 1
x &^= mask << shift
- x |= bias << shift
+ x |= (-1 + bias) << shift
frac = Float64frombits(x)
return
}
diff --git a/src/pkg/math/hypot_amd64.s b/src/pkg/math/hypot_amd64.s
new file mode 100644
index 000000000..1f691e70e
--- /dev/null
+++ b/src/pkg/math/hypot_amd64.s
@@ -0,0 +1,50 @@
+// Copyright 2010 The Go 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
+
+// func Hypot(x, y float64) float64
+TEXT ·Hypot(SB),7,$0
+ // test bits for special cases
+ MOVQ x+0(FP), BX
+ MOVQ $~(1<<63), AX
+ ANDQ AX, BX // x = |x|
+ MOVQ y+8(FP), CX
+ ANDQ AX, CX // y = |y|
+ MOVQ $PosInf, AX
+ CMPQ AX, BX
+ JLE isInfOrNaN
+ CMPQ AX, CX
+ JLE isInfOrNaN
+ // hypot = max * sqrt(1 + (min/max)**2)
+ MOVQ BX, X0
+ MOVQ CX, X1
+ ORQ CX, BX
+ JEQ isZero
+ MOVAPD X0, X2
+ MAXSD X1, X0
+ MINSD X2, X1
+ DIVSD X0, X1
+ MULSD X1, X1
+ ADDSD $1.0, X1
+ SQRTSD X1, X1
+ MULSD X1, X0
+ MOVSD X0, r+16(FP)
+ RET
+isInfOrNaN:
+ CMPQ AX, BX
+ JEQ isInf
+ CMPQ AX, CX
+ JEQ isInf
+ MOVQ $NaN, AX
+ MOVQ AX, r+16(FP) // return NaN
+ RET
+isInf:
+ MOVQ AX, r+16(FP) // return +Inf
+ RET
+isZero:
+ MOVQ $0, AX
+ MOVQ AX, r+16(FP) // return 0
+ RET
diff --git a/src/pkg/math/log.go b/src/pkg/math/log.go
index 02e767b95..39d94512d 100644
--- a/src/pkg/math/log.go
+++ b/src/pkg/math/log.go
@@ -121,11 +121,3 @@ func Log(x float64) float64 {
hfsq := 0.5 * f * f
return k*Ln2Hi - ((hfsq - (s*(hfsq+R) + k*Ln2Lo)) - f)
}
-
-// Log10 returns the decimal logarithm of x.
-// The special cases are the same as for Log.
-func Log10(x float64) float64 { return Log(x) * (1 / Ln10) }
-
-// Log2 returns the binary logarithm of x.
-// The special cases are the same as for Log.
-func Log2(x float64) float64 { return Log(x) * (1 / Ln2) }
diff --git a/src/pkg/math/log10.go b/src/pkg/math/log10.go
new file mode 100644
index 000000000..6d18baae2
--- /dev/null
+++ b/src/pkg/math/log10.go
@@ -0,0 +1,13 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+// Log10 returns the decimal logarithm of x.
+// The special cases are the same as for Log.
+func Log10(x float64) float64 { return Log(x) * (1 / Ln10) }
+
+// Log2 returns the binary logarithm of x.
+// The special cases are the same as for Log.
+func Log2(x float64) float64 { return Log(x) * (1 / Ln2) }
diff --git a/src/pkg/math/log10_386.s b/src/pkg/math/log10_386.s
new file mode 100644
index 000000000..cc473b424
--- /dev/null
+++ b/src/pkg/math/log10_386.s
@@ -0,0 +1,19 @@
+// Copyright 2010 The Go 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 Log10(x float64) float64
+TEXT ·Log10(SB),7,$0
+ FLDLG2 // F0=log10(2)
+ FMOVD x+0(FP), F0 // F0=x, F1=log10(2)
+ FYL2X // F0=log10(x)=log2(x)*log10(2)
+ FMOVDP F0, r+8(FP)
+ RET
+
+// func Log2(x float64) float64
+TEXT ·Log2(SB),7,$0
+ FLD1 // F0=1
+ FMOVD x+0(FP), F0 // F0=x, F1=1
+ FYL2X // F0=log2(x)
+ FMOVDP F0, r+8(FP)
+ RET
diff --git a/src/pkg/math/log10_decl.go b/src/pkg/math/log10_decl.go
new file mode 100644
index 000000000..5aec94e1c
--- /dev/null
+++ b/src/pkg/math/log10_decl.go
@@ -0,0 +1,8 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package math
+
+func Log10(x float64) float64
+func Log2(x float64) float64
diff --git a/src/pkg/math/log_386.s b/src/pkg/math/log_386.s
index ae5211e22..6cfbc7605 100644
--- a/src/pkg/math/log_386.s
+++ b/src/pkg/math/log_386.s
@@ -9,19 +9,3 @@ TEXT ·Log(SB),7,$0
FYL2X // F0=log(x)=log2(x)*log(2)
FMOVDP F0, r+8(FP)
RET
-
-// func Log10(x float64) float64
-TEXT ·Log10(SB),7,$0
- FLDLG2 // F0=log10(2)
- FMOVD x+0(FP), F0 // F0=x, F1=log10(2)
- FYL2X // F0=log10(x)=log2(x)*log10(2)
- FMOVDP F0, r+8(FP)
- RET
-
-// func Log2(x float64) float64
-TEXT ·Log2(SB),7,$0
- FLD1 // F0=1
- FMOVD x+0(FP), F0 // F0=x, F1=1
- FYL2X // F0=log2(x)
- FMOVDP F0, r+8(FP)
- RET
diff --git a/src/pkg/math/log_amd64.s b/src/pkg/math/log_amd64.s
new file mode 100644
index 000000000..79e35907c
--- /dev/null
+++ b/src/pkg/math/log_amd64.s
@@ -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.
+
+#define HSqrt2 7.07106781186547524401e-01 // sqrt(2)/2
+#define Ln2Hi 6.93147180369123816490e-01 // 0x3fe62e42fee00000
+#define Ln2Lo 1.90821492927058770002e-10 // 0x3dea39ef35793c76
+#define L1 6.666666666666735130e-01 // 0x3FE5555555555593
+#define L2 3.999999999940941908e-01 // 0x3FD999999997FA04
+#define L3 2.857142874366239149e-01 // 0x3FD2492494229359
+#define L4 2.222219843214978396e-01 // 0x3FCC71C51D8E78AF
+#define L5 1.818357216161805012e-01 // 0x3FC7466496CB03DE
+#define L6 1.531383769920937332e-01 // 0x3FC39A09D078C69F
+#define L7 1.479819860511658591e-01 // 0x3FC2F112DF3E5244
+#define NaN 0x7FF0000000000001
+#define NegInf 0xFFF0000000000000
+#define PosInf 0x7FF0000000000000
+
+// func Log(x float64) float64
+TEXT ·Log(SB),7,$0
+ // test bits for special cases
+ MOVQ x+0(FP), BX
+ MOVQ $~(1<<63), AX // sign bit mask
+ ANDQ BX, AX
+ JEQ isZero
+ MOVQ $0, AX
+ CMPQ AX, BX
+ JGT isNegative
+ MOVQ $PosInf, AX
+ CMPQ AX, BX
+ JLE isInfOrNaN
+ // f1, ki := math.Frexp(x); k := float64(ki)
+ MOVQ BX, X0
+ MOVQ $0x000FFFFFFFFFFFFF, AX
+ MOVQ AX, X2
+ ANDPD X0, X2
+ MOVSD $0.5, X0 // 0x3FE0000000000000
+ ORPD X0, X2 // X2= f1
+ SHRQ $52, BX
+ ANDL $0x7FF, BX
+ SUBL $0x3FE, BX
+ CVTSL2SD BX, X1 // x1= k, x2= f1
+ // if f1 < math.Sqrt2/2 { k -= 1; f1 *= 2 }
+ MOVSD $HSqrt2, X0 // x0= 0.7071, x1= k, x2= f1
+ CMPSD X2, X0, 5 // cmpnlt; x0= 0 or ^0, x1= k, x2 = f1
+ MOVSD $1.0, X3 // x0= 0 or ^0, x1= k, x2 = f1, x3= 1
+ ANDPD X0, X3 // x0= 0 or ^0, x1= k, x2 = f1, x3= 0 or 1
+ SUBSD X3, X1 // x0= 0 or ^0, x1= k, x2 = f1, x3= 0 or 1
+ MOVSD $1.0, X0 // x0= 1, x1= k, x2= f1, x3= 0 or 1
+ ADDSD X0, X3 // x0= 1, x1= k, x2= f1, x3= 1 or 2
+ MULSD X3, X2 // x0= 1, x1= k, x2= f1
+ // f := f1 - 1
+ SUBSD X0, X2 // x1= k, x2= f
+ // s := f / (2 + f)
+ MOVSD $2.0, X0
+ ADDSD X2, X0
+ MOVSD X2, X3
+ DIVSD X0, X3 // x1=k, x2= f, x3= s
+ // s2 := s * s
+ MOVSD X3, X4 // x1= k, x2= f, x3= s
+ MULSD X4, X4 // x1= k, x2= f, x3= s, x4= s2
+ // s4 := s2 * s2
+ MOVSD X4, X5 // x1= k, x2= f, x3= s, x4= s2
+ MULSD X5, X5 // x1= k, x2= f, x3= s, x4= s2, x5= s4
+ // t1 := s2 * (L1 + s4*(L3+s4*(L5+s4*L7)))
+ MOVSD $L7, X6
+ MULSD X5, X6
+ ADDSD $L5, X6
+ MULSD X5, X6
+ ADDSD $L3, X6
+ MULSD X5, X6
+ ADDSD $L1, X6
+ MULSD X6, X4 // x1= k, x2= f, x3= s, x4= t1, x5= s4
+ // t2 := s4 * (L2 + s4*(L4+s4*L6))
+ MOVSD $L6, X6
+ MULSD X5, X6
+ ADDSD $L4, X6
+ MULSD X5, X6
+ ADDSD $L2, X6
+ MULSD X6, X5 // x1= k, x2= f, x3= s, x4= t1, x5= t2
+ // R := t1 + t2
+ ADDSD X5, X4 // x1= k, x2= f, x3= s, x4= R
+ // hfsq := 0.5 * f * f
+ MOVSD $0.5, X0
+ MULSD X2, X0
+ MULSD X2, X0 // x0= hfsq, x1= k, x2= f, x3= s, x4= R
+ // return k*Ln2Hi - ((hfsq - (s*(hfsq+R) + k*Ln2Lo)) - f)
+ ADDSD X0, X4 // x0= hfsq, x1= k, x2= f, x3= s, x4= hfsq+R
+ MULSD X4, X3 // x0= hfsq, x1= k, x2= f, x3= s*(hfsq+R)
+ MOVSD $Ln2Lo, X4
+ MULSD X1, X4 // x4= k*Ln2Lo
+ ADDSD X4, X3 // x0= hfsq, x1= k, x2= f, x3= s*(hfsq+R)+k*Ln2Lo
+ SUBSD X3, X0 // x0= hfsq-(s*(hfsq+R)+k*Ln2Lo), x1= k, x2= f
+ SUBSD X2, X0 // x0= (hfsq-(s*(hfsq+R)+k*Ln2Lo))-f, x1= k
+ MULSD $Ln2Hi, X1 // x0= (hfsq-(s*(hfsq+R)+k*Ln2Lo))-f, x1= k*Ln2Hi
+ SUBSD X0, X1 // x1= k*Ln2Hi-((hfsq-(s*(hfsq+R)+k*Ln2Lo))-f)
+ MOVSD X1, r+8(FP)
+ RET
+isInfOrNaN:
+ MOVQ BX, r+8(FP) // +Inf or NaN, return x
+ RET
+isNegative:
+ MOVQ $NaN, AX
+ MOVQ AX, r+8(FP) // return NaN
+ RET
+isZero:
+ MOVQ $NegInf, AX
+ MOVQ AX, r+8(FP) // return -Inf
+ RET
diff --git a/src/pkg/math/log_decl.go b/src/pkg/math/log_decl.go
index 074b0cdb6..deda305dd 100644
--- a/src/pkg/math/log_decl.go
+++ b/src/pkg/math/log_decl.go
@@ -5,5 +5,3 @@
package math
func Log(x float64) float64
-func Log10(x float64) float64
-func Log2(x float64) float64
diff --git a/src/pkg/math/logb.go b/src/pkg/math/logb.go
index acda15d22..9e4651517 100644
--- a/src/pkg/math/logb.go
+++ b/src/pkg/math/logb.go
@@ -4,7 +4,7 @@
package math
-// Logb(x) returns the binary logarithm of non-zero x.
+// Logb(x) returns the binary exponent of non-zero x.
//
// Special cases are:
// Logb(±Inf) = +Inf
@@ -25,7 +25,7 @@ func Logb(x float64) float64 {
return float64(int((Float64bits(x)>>shift)&mask) - bias)
}
-// Ilogb(x) returns the binary logarithm of non-zero x as an integer.
+// Ilogb(x) returns the binary exponent of non-zero x as an integer.
//
// Special cases are:
// Ilogb(±Inf) = MaxInt32
diff --git a/src/pkg/math/modf.go b/src/pkg/math/modf.go
index ae0c7c887..315174b70 100644
--- a/src/pkg/math/modf.go
+++ b/src/pkg/math/modf.go
@@ -23,9 +23,9 @@ func Modf(f float64) (int float64, frac float64) {
x := Float64bits(f)
e := uint(x>>shift)&mask - bias
- // Keep the top 11+e bits, the integer part; clear the rest.
- if e < 64-11 {
- x &^= 1<<(64-11-e) - 1
+ // Keep the top 12+e bits, the integer part; clear the rest.
+ if e < 64-12 {
+ x &^= 1<<(64-12-e) - 1
}
int = Float64frombits(x)
frac = f - int
diff --git a/src/pkg/math/sincos_amd64.s b/src/pkg/math/sincos_amd64.s
new file mode 100644
index 000000000..18c824e51
--- /dev/null
+++ b/src/pkg/math/sincos_amd64.s
@@ -0,0 +1,143 @@
+// Copyright 2010 The Go 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 method is based on a paper by Naoki Shibata: "Efficient evaluation
+// methods of elementary functions suitable for SIMD computation", Proc.
+// of International Supercomputing Conference 2010 (ISC'10), pp. 25 -- 32
+// (May 2010). The paper is available at
+// http://www.springerlink.com/content/340228x165742104/
+//
+// The original code and the constants below are from the author's
+// implementation available at http://freshmeat.net/projects/sleef.
+// The README file says, "The software is in public domain.
+// You can use the software without any obligation."
+//
+// This code is a simplified version of the original. The CMPSD
+// instruction, not generated by the compiler, eliminates jumps in the
+// body of the calculation.
+
+#define PosOne 0x3FF0000000000000
+#define PosInf 0x7FF0000000000000
+#define NaN 0x7FF0000000000001
+#define PI4A 0.7853981554508209228515625 // pi/4 split into three parts
+#define PI4B 0.794662735614792836713604629039764404296875e-8
+#define PI4C 0.306161699786838294306516483068750264552437361480769e-16
+#define M4PI 1.273239544735162542821171882678754627704620361328125 // 4/pi
+#define T0 1.0
+#define T1 -8.33333333333333333333333e-02 // (-1.0/12)
+#define T2 2.77777777777777777777778e-03 // (+1.0/360)
+#define T3 -4.96031746031746031746032e-05 // (-1.0/20160)
+#define T4 5.51146384479717813051146e-07 // (+1.0/1814400)
+
+// func Sincos(d float64) (sin, cos float64)
+TEXT ·Sincos(SB),7,$0
+ // test for special cases
+ MOVQ $~(1<<63), DX // sign bit mask
+ MOVQ x+0(FP), BX
+ ANDQ BX, DX
+ JEQ isZero
+ MOVQ $PosInf, AX
+ CMPQ AX, DX
+ JLE isInfOrNaN
+ // Reduce argument
+ MOVQ BX, X7 // x7= d
+ MOVQ DX, X0 // x0= |d|
+ MOVSD $M4PI, X2
+ MULSD X0, X2
+ CVTTSD2SQ X2, BX // bx= q
+ MOVQ $1, AX
+ ANDQ BX, AX
+ ADDQ BX, AX
+ CVTSQ2SD AX, X2
+ MOVSD $PI4A, X3
+ MULSD X2, X3
+ SUBSD X3, X0
+ MOVSD $PI4B, X3
+ MULSD X2, X3
+ SUBSD X3, X0
+ MOVSD $PI4C, X3
+ MULSD X2, X3
+ SUBSD X3, X0
+ MULSD $0.125, X0 // x0= x, x7= d, bx= q
+ // Evaluate Taylor series
+ MULSD X0, X0
+ MOVSD $T4, X2
+ MULSD X0, X2
+ ADDSD $T3, X2
+ MULSD X0, X2
+ ADDSD $T2, X2
+ MULSD X0, X2
+ ADDSD $T1, X2
+ MULSD X0, X2
+ ADDSD $T0, X2
+ MULSD X2, X0 // x0= x, x7= d, bx= q
+ // Apply double angle formula
+ MOVSD $4.0, X2
+ SUBSD X0, X2
+ MULSD X2, X0
+ MOVSD $4.0, X2
+ SUBSD X0, X2
+ MULSD X2, X0
+ MOVSD $4.0, X2
+ SUBSD X0, X2
+ MULSD X2, X0
+ MULSD $0.5, X0 // x0= x, x7= d, bx= q
+ // sin = sqrt((2 - x) * x)
+ MOVSD $2.0, X2
+ SUBSD X0, X2
+ MULSD X0, X2
+ SQRTSD X2, X2 // x0= x, x2= z, x7= d, bx= q
+ // cos = 1 - x
+ MOVSD $1.0, X1
+ SUBSD X0, X1 // x1= x, x2= z, x7= d, bx= q
+ // if ((q + 1) & 2) != 0 { sin, cos = cos, sin }
+ MOVQ $1, DX
+ ADDQ BX, DX
+ MOVQ $2, AX
+ ANDQ AX, DX
+ MOVQ DX, X0
+ MOVSD $0.0, X3
+ CMPSD X0, X3, 0 // cmpeq; x1= x, x2= z, x3 = y, x7= d, bx= q
+ // sin = (y & z) | (^y & x)
+ MOVAPD X2, X0
+ ANDPD X3, X0 // x0= sin
+ MOVAPD X3, X4
+ ANDNPD X1, X4
+ ORPD X4, X0 // x0= sin, x1= x, x2= z, x3= y, x7= d, bx= q
+ // cos = (y & x) | (^y & z)
+ ANDPD X3, X1 // x1= cos
+ ANDNPD X2, X3
+ ORPD X3, X1 // x0= sin, x1= cos, x7= d, bx= q
+ // if ((q & 4) != 0) != (d < 0) { sin = -sin }
+ MOVQ BX, AX
+ MOVQ $61, CX
+ SHLQ CX, AX
+ MOVQ AX, X3
+ XORPD X7, X3
+ MOVQ $(1<<63), AX
+ MOVQ AX, X2 // x2= -0.0
+ ANDPD X2, X3
+ ORPD X3, X0 // x0= sin, x1= cos, x2= -0.0, bx= q
+ // if ((q + 2) & 4) != 0 { cos = -cos }
+ MOVQ $2, AX
+ ADDQ AX, BX
+ MOVQ $61, CX
+ SHLQ CX, BX
+ MOVQ BX, X3
+ ANDPD X2, X3
+ ORPD X3, X1 // x0= sin, x1= cos
+ // return (sin, cos)
+ MOVSD X0, sin+8(FP)
+ MOVSD X1, cos+16(FP)
+ RET
+isZero: // return (±0.0, 1.0)
+ MOVQ BX, sin+8(FP)
+ MOVQ $PosOne, AX
+ MOVQ AX, cos+16(FP)
+ RET
+isInfOrNaN: // return (NaN, NaN)
+ MOVQ $NaN, AX
+ MOVQ AX, sin+8(FP)
+ MOVQ AX, cos+16(FP)
+ RET
diff --git a/src/pkg/math/sqrt_port.go b/src/pkg/math/sqrt_port.go
index 8d821b559..6f35a383d 100644
--- a/src/pkg/math/sqrt_port.go
+++ b/src/pkg/math/sqrt_port.go
@@ -113,7 +113,7 @@ func sqrtGo(x float64) float64 {
}
exp++
}
- exp -= bias + 1 // unbias exponent
+ exp -= bias // unbias exponent
ix &^= mask << shift
ix |= 1 << shift
if exp&1 == 1 { // odd exp, double x to make it even
@@ -138,6 +138,6 @@ func sqrtGo(x float64) float64 {
if ix != 0 { // remainder, result not exact
q += q & 1 // round according to extra bit
}
- ix = q>>1 + uint64(exp+bias)<<shift // significand + biased exponent
+ ix = q>>1 + uint64(exp-1+bias)<<shift // significand + biased exponent
return Float64frombits(ix)
}
diff --git a/src/pkg/math/tan.go b/src/pkg/math/tan.go
index 842ac6438..a36ebbf44 100644
--- a/src/pkg/math/tan.go
+++ b/src/pkg/math/tan.go
@@ -54,7 +54,7 @@ func Tan(x float64) float64 {
if flag {
if temp == 0 {
- panic(NaN())
+ return NaN()
}
temp = 1 / temp
}
diff --git a/src/pkg/mime/Makefile b/src/pkg/mime/Makefile
index 57fc7db44..901ed6f8e 100644
--- a/src/pkg/mime/Makefile
+++ b/src/pkg/mime/Makefile
@@ -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 ../../Make.$(GOARCH)
+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
new file mode 100644
index 000000000..e60cbb8df
--- /dev/null
+++ b/src/pkg/mime/grammar.go
@@ -0,0 +1,36 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package mime
+
+import (
+ "strings"
+)
+
+// isTSpecial returns true if rune is in 'tspecials' as defined by RFC
+// 1531 and RFC 2045.
+func isTSpecial(rune int) bool {
+ return strings.IndexRune(`()<>@,;:\"/[]?=`, rune) != -1
+}
+
+// IsTokenChar returns true if rune is in 'token' as defined by RFC
+// 1531 and RFC 2045.
+func IsTokenChar(rune int) bool {
+ // token := 1*<any (US-ASCII) CHAR except SPACE, CTLs,
+ // or tspecials>
+ return rune > 0x20 && rune < 0x7f && !isTSpecial(rune)
+}
+
+// IsQText returns true if rune is in 'qtext' as defined by RFC 822.
+func IsQText(rune int) bool {
+ // CHAR = <any ASCII character> ; ( 0-177, 0.-127.)
+ // qtext = <any CHAR excepting <">, ; => may be folded
+ // "\" & CR, and including
+ // linear-white-space>
+ switch rune {
+ case '"', '\\', '\r':
+ return false
+ }
+ return rune < 0x80
+}
diff --git a/src/pkg/mime/mediatype.go b/src/pkg/mime/mediatype.go
new file mode 100644
index 000000000..eb629aa6f
--- /dev/null
+++ b/src/pkg/mime/mediatype.go
@@ -0,0 +1,120 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package mime
+
+import (
+ "bytes"
+ "strings"
+ "unicode"
+)
+
+// ParseMediaType parses a media type value and any optional
+// parameters, per RFC 1531. Media types are the values in
+// Content-Type and Content-Disposition headers (RFC 2183). On
+// success, ParseMediaType returns the media type converted to
+// lowercase and trimmed of white space and a non-nil params. On
+// error, it returns an empty string and a nil params.
+func ParseMediaType(v string) (mediatype string, params map[string]string) {
+ i := strings.Index(v, ";")
+ if i == -1 {
+ i = len(v)
+ }
+ mediatype = strings.TrimSpace(strings.ToLower(v[0:i]))
+ params = make(map[string]string)
+
+ v = v[i:]
+ for len(v) > 0 {
+ v = strings.TrimLeftFunc(v, unicode.IsSpace)
+ if len(v) == 0 {
+ return
+ }
+ key, value, rest := consumeMediaParam(v)
+ if key == "" {
+ // Parse error.
+ return "", nil
+ }
+ params[key] = value
+ v = rest
+ }
+ return
+}
+
+func isNotTokenChar(rune int) bool {
+ return !IsTokenChar(rune)
+}
+
+// consumeToken consumes a token from the beginning of provided
+// string, per RFC 2045 section 5.1 (referenced from 2183), and return
+// the token consumed and the rest of the string. Returns ("", v) on
+// failure to consume at least one character.
+func consumeToken(v string) (token, rest string) {
+ notPos := strings.IndexFunc(v, isNotTokenChar)
+ if notPos == -1 {
+ return v, ""
+ }
+ if notPos == 0 {
+ return "", v
+ }
+ return v[0:notPos], v[notPos:]
+}
+
+// consumeValue consumes a "value" per RFC 2045, where a value is
+// either a 'token' or a 'quoted-string'. On success, consumeValue
+// returns the value consumed (and de-quoted/escaped, if a
+// quoted-string) and the rest of the string. On failure, returns
+// ("", v).
+func consumeValue(v string) (value, rest string) {
+ if !strings.HasPrefix(v, `"`) {
+ return consumeToken(v)
+ }
+
+ // parse a quoted-string
+ rest = v[1:] // consume the leading quote
+ buffer := new(bytes.Buffer)
+ var idx, rune int
+ var nextIsLiteral bool
+ for idx, rune = range rest {
+ switch {
+ case nextIsLiteral:
+ if rune >= 0x80 {
+ return "", v
+ }
+ buffer.WriteRune(rune)
+ nextIsLiteral = false
+ case rune == '"':
+ return buffer.String(), rest[idx+1:]
+ case IsQText(rune):
+ buffer.WriteRune(rune)
+ case rune == '\\':
+ nextIsLiteral = true
+ default:
+ return "", v
+ }
+ }
+ return "", v
+}
+
+func consumeMediaParam(v string) (param, value, rest string) {
+ rest = strings.TrimLeftFunc(v, unicode.IsSpace)
+ if !strings.HasPrefix(rest, ";") {
+ return "", "", v
+ }
+
+ rest = rest[1:] // consume semicolon
+ rest = strings.TrimLeftFunc(rest, unicode.IsSpace)
+ param, rest = consumeToken(rest)
+ if param == "" {
+ return "", "", v
+ }
+ if !strings.HasPrefix(rest, "=") {
+ return "", "", v
+ }
+ rest = rest[1:] // consume equals sign
+ value, rest = consumeValue(rest)
+ if value == "" {
+ return "", "", v
+ }
+ return param, value, rest
+}
diff --git a/src/pkg/mime/mediatype_test.go b/src/pkg/mime/mediatype_test.go
new file mode 100644
index 000000000..4891e899d
--- /dev/null
+++ b/src/pkg/mime/mediatype_test.go
@@ -0,0 +1,117 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package mime
+
+import (
+ "testing"
+)
+
+func TestConsumeToken(t *testing.T) {
+ tests := [...][3]string{
+ {"foo bar", "foo", " bar"},
+ {"bar", "bar", ""},
+ {"", "", ""},
+ {" foo", "", " foo"},
+ }
+ for _, test := range tests {
+ token, rest := consumeToken(test[0])
+ expectedToken := test[1]
+ expectedRest := test[2]
+ if token != expectedToken {
+ t.Errorf("expected to consume token '%s', not '%s' from '%s'",
+ expectedToken, token, test[0])
+ } else if rest != expectedRest {
+ t.Errorf("expected to have left '%s', not '%s' after reading token '%s' from '%s'",
+ expectedRest, rest, token, test[0])
+ }
+ }
+}
+
+func TestConsumeValue(t *testing.T) {
+ tests := [...][3]string{
+ {"foo bar", "foo", " bar"},
+ {"bar", "bar", ""},
+ {" bar ", "", " bar "},
+ {`"My value"end`, "My value", "end"},
+ {`"My value" end`, "My value", " end"},
+ {`"\\" rest`, "\\", " rest"},
+ {`"My \" value"end`, "My \" value", "end"},
+ {`"\" rest`, "", `"\" rest`},
+ }
+ for _, test := range tests {
+ value, rest := consumeValue(test[0])
+ expectedValue := test[1]
+ expectedRest := test[2]
+ if value != expectedValue {
+ t.Errorf("expected to consume value [%s], not [%s] from [%s]",
+ expectedValue, value, test[0])
+ } else if rest != expectedRest {
+ t.Errorf("expected to have left [%s], not [%s] after reading value [%s] from [%s]",
+ expectedRest, rest, value, test[0])
+ }
+ }
+}
+
+func TestConsumeMediaParam(t *testing.T) {
+ tests := [...][4]string{
+ {" ; foo=bar", "foo", "bar", ""},
+ {"; foo=bar", "foo", "bar", ""},
+ {";foo=bar", "foo", "bar", ""},
+ {`;foo="bar"`, "foo", "bar", ""},
+ {`;foo="bar"; `, "foo", "bar", "; "},
+ {`;foo="bar"; foo=baz`, "foo", "bar", "; foo=baz"},
+ {` ; boundary=----CUT;`, "boundary", "----CUT", ";"},
+ {` ; key=value; blah="value";name="foo" `, "key", "value", `; blah="value";name="foo" `},
+ {`; blah="value";name="foo" `, "blah", "value", `;name="foo" `},
+ {`;name="foo" `, "name", "foo", ` `},
+ }
+ for _, test := range tests {
+ param, value, rest := consumeMediaParam(test[0])
+ expectedParam := test[1]
+ expectedValue := test[2]
+ expectedRest := test[3]
+ if param != expectedParam {
+ t.Errorf("expected to consume param [%s], not [%s] from [%s]",
+ expectedParam, param, test[0])
+ } else if value != expectedValue {
+ t.Errorf("expected to consume value [%s], not [%s] from [%s]",
+ expectedValue, value, test[0])
+ } else if rest != expectedRest {
+ t.Errorf("expected to have left [%s], not [%s] after reading [%s/%s] from [%s]",
+ expectedRest, rest, param, value, test[0])
+ }
+ }
+}
+
+func TestParseMediaType(t *testing.T) {
+ tests := [...]string{
+ `form-data; name="foo"`,
+ ` form-data ; name=foo`,
+ `FORM-DATA;name="foo"`,
+ ` FORM-DATA ; name="foo"`,
+ ` FORM-DATA ; name="foo"`,
+ `form-data; key=value; blah="value";name="foo" `,
+ }
+ for _, test := range tests {
+ mt, params := ParseMediaType(test)
+ if mt != "form-data" {
+ t.Errorf("expected type form-data for %s, got [%s]", test, mt)
+ continue
+ }
+ if params["name"] != "foo" {
+ t.Errorf("expected name=foo for %s", test)
+ }
+ }
+}
+
+func TestParseMediaTypeBogus(t *testing.T) {
+ mt, params := ParseMediaType("bogus ;=========")
+ if mt != "" {
+ t.Error("expected empty type")
+ }
+ if params != nil {
+ t.Error("expected nil params")
+ }
+}
diff --git a/src/pkg/mime/multipart/Makefile b/src/pkg/mime/multipart/Makefile
new file mode 100644
index 000000000..5a7b98d03
--- /dev/null
+++ b/src/pkg/mime/multipart/Makefile
@@ -0,0 +1,11 @@
+# Copyright 2010 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../../Make.inc
+
+TARG=mime/multipart
+GOFILES=\
+ multipart.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/mime/multipart/multipart.go b/src/pkg/mime/multipart/multipart.go
new file mode 100644
index 000000000..1d855c74c
--- /dev/null
+++ b/src/pkg/mime/multipart/multipart.go
@@ -0,0 +1,280 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+//
+
+/*
+Package multipart implements MIME multipart parsing, as defined in RFC
+2046.
+
+The implementation is sufficient for HTTP (RFC 2388) and the multipart
+bodies generated by popular browsers.
+*/
+package multipart
+
+import (
+ "bufio"
+ "bytes"
+ "io"
+ "mime"
+ "os"
+ "regexp"
+ "strings"
+)
+
+var headerRegexp *regexp.Regexp = regexp.MustCompile("^([a-zA-Z0-9\\-]+): *([^\r\n]+)")
+
+// Reader is an iterator over parts in a MIME multipart body.
+// Reader's underlying parser consumes its input as needed. Seeking
+// isn't supported.
+type Reader interface {
+ // NextPart returns the next part in the multipart, or (nil,
+ // nil) on EOF. An error is returned if the underlying reader
+ // reports errors, or on truncated or otherwise malformed
+ // input.
+ NextPart() (*Part, os.Error)
+}
+
+// A Part represents a single part in a multipart body.
+type Part struct {
+ // The headers of the body, if any, with the keys canonicalized
+ // in the same fashion that the Go http.Request headers are.
+ // i.e. "foo-bar" changes case to "Foo-Bar"
+ Header map[string]string
+
+ buffer *bytes.Buffer
+ mr *multiReader
+}
+
+// FormName returns the name parameter if p has a Content-Disposition
+// of type "form-data". Otherwise it returns the empty string.
+func (p *Part) FormName() string {
+ // See http://tools.ietf.org/html/rfc2183 section 2 for EBNF
+ // of Content-Disposition value format.
+ v, ok := p.Header["Content-Disposition"]
+ if !ok {
+ return ""
+ }
+ d, params := mime.ParseMediaType(v)
+ if d != "form-data" {
+ return ""
+ }
+ return params["name"]
+}
+
+// NewReader creates a new multipart Reader reading from r using the
+// given MIME boundary.
+func NewReader(reader io.Reader, boundary string) Reader {
+ return &multiReader{
+ boundary: boundary,
+ dashBoundary: "--" + boundary,
+ endLine: "--" + boundary + "--",
+ bufReader: bufio.NewReader(reader),
+ }
+}
+
+// Implementation ....
+
+type devNullWriter bool
+
+func (*devNullWriter) Write(p []byte) (n int, err os.Error) {
+ return len(p), nil
+}
+
+var devNull = devNullWriter(false)
+
+func newPart(mr *multiReader) (bp *Part, err os.Error) {
+ bp = new(Part)
+ bp.Header = make(map[string]string)
+ bp.mr = mr
+ bp.buffer = new(bytes.Buffer)
+ if err = bp.populateHeaders(); err != nil {
+ bp = nil
+ }
+ return
+}
+
+func (bp *Part) populateHeaders() os.Error {
+ for {
+ line, err := bp.mr.bufReader.ReadString('\n')
+ if err != nil {
+ return err
+ }
+ if line == "\n" || line == "\r\n" {
+ return nil
+ }
+ if matches := headerRegexp.FindStringSubmatch(line); len(matches) == 3 {
+ key := matches[1]
+ value := matches[2]
+ // TODO: canonicalize headers ala http.Request.Header?
+ bp.Header[key] = value
+ continue
+ }
+ return os.NewError("Unexpected header line found parsing multipart body")
+ }
+ panic("unreachable")
+}
+
+// Read reads the body of a part, after its headers and before the
+// next part (if any) begins.
+func (bp *Part) Read(p []byte) (n int, err os.Error) {
+ for {
+ if bp.buffer.Len() >= len(p) {
+ // Internal buffer of unconsumed data is large enough for
+ // the read request. No need to parse more at the moment.
+ break
+ }
+ if !bp.mr.ensureBufferedLine() {
+ return 0, io.ErrUnexpectedEOF
+ }
+ if bp.mr.bufferedLineIsBoundary() {
+ // Don't consume this line
+ break
+ }
+
+ // Write all of this line, except the final CRLF
+ s := *bp.mr.bufferedLine
+ if strings.HasSuffix(s, "\r\n") {
+ bp.mr.consumeLine()
+ if !bp.mr.ensureBufferedLine() {
+ return 0, io.ErrUnexpectedEOF
+ }
+ if bp.mr.bufferedLineIsBoundary() {
+ // The final \r\n isn't ours. It logically belongs
+ // to the boundary line which follows.
+ bp.buffer.WriteString(s[0 : len(s)-2])
+ } else {
+ bp.buffer.WriteString(s)
+ }
+ break
+ }
+ if strings.HasSuffix(s, "\n") {
+ bp.buffer.WriteString(s)
+ bp.mr.consumeLine()
+ continue
+ }
+ return 0, os.NewError("multipart parse error during Read; unexpected line: " + s)
+ }
+ return bp.buffer.Read(p)
+}
+
+func (bp *Part) Close() os.Error {
+ io.Copy(&devNull, bp)
+ return nil
+}
+
+type multiReader struct {
+ boundary string
+ dashBoundary string // --boundary
+ endLine string // --boundary--
+
+ bufferedLine *string
+
+ bufReader *bufio.Reader
+ currentPart *Part
+ partsRead int
+}
+
+func (mr *multiReader) eof() bool {
+ return mr.bufferedLine == nil &&
+ !mr.readLine()
+}
+
+func (mr *multiReader) readLine() bool {
+ line, err := mr.bufReader.ReadString('\n')
+ if err != nil {
+ // TODO: care about err being EOF or not?
+ return false
+ }
+ mr.bufferedLine = &line
+ return true
+}
+
+func (mr *multiReader) bufferedLineIsBoundary() bool {
+ return strings.HasPrefix(*mr.bufferedLine, mr.dashBoundary)
+}
+
+func (mr *multiReader) ensureBufferedLine() bool {
+ if mr.bufferedLine == nil {
+ return mr.readLine()
+ }
+ return true
+}
+
+func (mr *multiReader) consumeLine() {
+ mr.bufferedLine = nil
+}
+
+func (mr *multiReader) NextPart() (*Part, os.Error) {
+ if mr.currentPart != nil {
+ mr.currentPart.Close()
+ }
+
+ for {
+ if mr.eof() {
+ return nil, io.ErrUnexpectedEOF
+ }
+
+ if isBoundaryDelimiterLine(*mr.bufferedLine, mr.dashBoundary) {
+ mr.consumeLine()
+ mr.partsRead++
+ bp, err := newPart(mr)
+ if err != nil {
+ return nil, err
+ }
+ mr.currentPart = bp
+ return bp, nil
+ }
+
+ if hasPrefixThenNewline(*mr.bufferedLine, mr.endLine) {
+ mr.consumeLine()
+ // Expected EOF (no error)
+ return nil, nil
+ }
+
+ if mr.partsRead == 0 {
+ // skip line
+ mr.consumeLine()
+ continue
+ }
+
+ return nil, os.NewError("Unexpected line in Next().")
+ }
+ panic("unreachable")
+}
+
+func isBoundaryDelimiterLine(line, dashPrefix string) bool {
+ // http://tools.ietf.org/html/rfc2046#section-5.1
+ // The boundary delimiter line is then defined as a line
+ // consisting entirely of two hyphen characters ("-",
+ // decimal value 45) followed by the boundary parameter
+ // value from the Content-Type header field, optional linear
+ // whitespace, and a terminating CRLF.
+ if !strings.HasPrefix(line, dashPrefix) {
+ return false
+ }
+ if strings.HasSuffix(line, "\r\n") {
+ return onlyHorizontalWhitespace(line[len(dashPrefix) : len(line)-2])
+ }
+ // Violate the spec and also support newlines without the
+ // carriage return...
+ if strings.HasSuffix(line, "\n") {
+ return onlyHorizontalWhitespace(line[len(dashPrefix) : len(line)-1])
+ }
+ return false
+}
+
+func onlyHorizontalWhitespace(s string) bool {
+ for i := 0; i < len(s); i++ {
+ if s[i] != ' ' && s[i] != '\t' {
+ return false
+ }
+ }
+ return true
+}
+
+func hasPrefixThenNewline(s, prefix string) bool {
+ return strings.HasPrefix(s, prefix) &&
+ (len(s) == len(prefix)+1 && strings.HasSuffix(s, "\n") ||
+ len(s) == len(prefix)+2 && strings.HasSuffix(s, "\r\n"))
+}
diff --git a/src/pkg/mime/multipart/multipart_test.go b/src/pkg/mime/multipart/multipart_test.go
new file mode 100644
index 000000000..7e1ed133e
--- /dev/null
+++ b/src/pkg/mime/multipart/multipart_test.go
@@ -0,0 +1,204 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package multipart
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "json"
+ "regexp"
+ "strings"
+ "testing"
+)
+
+func TestHorizontalWhitespace(t *testing.T) {
+ if !onlyHorizontalWhitespace(" \t") {
+ t.Error("expected pass")
+ }
+ if onlyHorizontalWhitespace("foo bar") {
+ t.Error("expected failure")
+ }
+}
+
+func TestBoundaryLine(t *testing.T) {
+ boundary := "myBoundary"
+ prefix := "--" + boundary
+ if !isBoundaryDelimiterLine("--myBoundary\r\n", prefix) {
+ t.Error("expected")
+ }
+ if !isBoundaryDelimiterLine("--myBoundary \r\n", prefix) {
+ t.Error("expected")
+ }
+ if !isBoundaryDelimiterLine("--myBoundary \n", prefix) {
+ t.Error("expected")
+ }
+ if isBoundaryDelimiterLine("--myBoundary bogus \n", prefix) {
+ t.Error("expected fail")
+ }
+ if isBoundaryDelimiterLine("--myBoundary bogus--", prefix) {
+ t.Error("expected fail")
+ }
+}
+
+func escapeString(v string) string {
+ bytes, _ := json.Marshal(v)
+ return string(bytes)
+}
+
+func expectEq(t *testing.T, expected, actual, what string) {
+ if expected == actual {
+ return
+ }
+ t.Errorf("Unexpected value for %s; got %s (len %d) but expected: %s (len %d)",
+ what, escapeString(actual), len(actual), escapeString(expected), len(expected))
+}
+
+func TestFormName(t *testing.T) {
+ p := new(Part)
+ p.Header = make(map[string]string)
+ tests := [...][2]string{
+ {`form-data; name="foo"`, "foo"},
+ {` form-data ; name=foo`, "foo"},
+ {`FORM-DATA;name="foo"`, "foo"},
+ {` FORM-DATA ; name="foo"`, "foo"},
+ {` FORM-DATA ; name="foo"`, "foo"},
+ {` FORM-DATA ; name=foo`, "foo"},
+ {` FORM-DATA ; filename="foo.txt"; name=foo; baz=quux`, "foo"},
+ }
+ for _, test := range tests {
+ p.Header["Content-Disposition"] = test[0]
+ expected := test[1]
+ actual := p.FormName()
+ if actual != expected {
+ t.Errorf("expected \"%s\"; got: \"%s\"", expected, actual)
+ }
+ }
+}
+
+func TestMultipart(t *testing.T) {
+ testBody := `
+This is a multi-part message. This line is ignored.
+--MyBoundary
+Header1: value1
+HEADER2: value2
+foo-bar: baz
+
+My value
+The end.
+--MyBoundary
+Header1: value1b
+HEADER2: value2b
+foo-bar: bazb
+
+Line 1
+Line 2
+Line 3 ends in a newline, but just one.
+
+--MyBoundary
+
+never read data
+--MyBoundary--
+`
+ testBody = regexp.MustCompile("\n").ReplaceAllString(testBody, "\r\n")
+ bodyReader := strings.NewReader(testBody)
+
+ reader := NewReader(bodyReader, "MyBoundary")
+ buf := new(bytes.Buffer)
+
+ // Part1
+ part, err := reader.NextPart()
+ if part == nil || err != nil {
+ t.Error("Expected part1")
+ return
+ }
+ if part.Header["Header1"] != "value1" {
+ t.Error("Expected Header1: value")
+ }
+ if part.Header["foo-bar"] != "baz" {
+ t.Error("Expected foo-bar: baz")
+ }
+ buf.Reset()
+ io.Copy(buf, part)
+ expectEq(t, "My value\r\nThe end.",
+ buf.String(), "Value of first part")
+
+ // Part2
+ part, err = reader.NextPart()
+ if part == nil || err != nil {
+ t.Error("Expected part2")
+ return
+ }
+ if part.Header["foo-bar"] != "bazb" {
+ t.Error("Expected foo-bar: bazb")
+ }
+ buf.Reset()
+ io.Copy(buf, part)
+ expectEq(t, "Line 1\r\nLine 2\r\nLine 3 ends in a newline, but just one.\r\n",
+ buf.String(), "Value of second part")
+
+ // Part3
+ part, err = reader.NextPart()
+ if part == nil || err != nil {
+ t.Error("Expected part3 without errors")
+ return
+ }
+
+ // Non-existent part4
+ part, err = reader.NextPart()
+ if part != nil {
+ t.Error("Didn't expect a third part.")
+ }
+ if err != nil {
+ t.Errorf("Unexpected error getting third part: %v", err)
+ }
+}
+
+func TestVariousTextLineEndings(t *testing.T) {
+ tests := [...]string{
+ "Foo\nBar",
+ "Foo\nBar\n",
+ "Foo\r\nBar",
+ "Foo\r\nBar\r\n",
+ "Foo\rBar",
+ "Foo\rBar\r",
+ "\x00\x01\x02\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10",
+ }
+
+ for testNum, expectedBody := range tests {
+ body := "--BOUNDARY\r\n" +
+ "Content-Disposition: form-data; name=\"value\"\r\n" +
+ "\r\n" +
+ expectedBody +
+ "\r\n--BOUNDARY--\r\n"
+ bodyReader := strings.NewReader(body)
+
+ reader := NewReader(bodyReader, "BOUNDARY")
+ buf := new(bytes.Buffer)
+ part, err := reader.NextPart()
+ if part == nil {
+ t.Errorf("Expected a body part on text %d", testNum)
+ continue
+ }
+ if err != nil {
+ t.Errorf("Unexpected error on text %d: %v", testNum, err)
+ continue
+ }
+ written, err := io.Copy(buf, part)
+ expectEq(t, expectedBody, buf.String(), fmt.Sprintf("test %d", testNum))
+ if err != nil {
+ t.Errorf("Error copying multipart; bytes=%v, error=%v", written, err)
+ }
+
+ part, err = reader.NextPart()
+ if part != nil {
+ t.Errorf("Unexpected part in test %d", testNum)
+ }
+ if err != nil {
+ t.Errorf("Unexpected error in test %d: %v", testNum, err)
+ }
+
+ }
+}
diff --git a/src/pkg/mime/type.go b/src/pkg/mime/type.go
index 3706afc47..a10b780ae 100644
--- a/src/pkg/mime/type.go
+++ b/src/pkg/mime/type.go
@@ -2,21 +2,14 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// The mime package translates file name extensions to MIME types.
-// It consults the local system's mime.types file, which must be installed
-// under one of these names:
-//
-// /etc/mime.types
-// /etc/apache2/mime.types
-// /etc/apache/mime.types
-//
+// The mime package implements parts of the MIME spec.
package mime
import (
"bufio"
- "once"
"os"
"strings"
+ "sync"
)
var typeFiles = []string{
@@ -37,6 +30,8 @@ var mimeTypes = map[string]string{
".xml": "text/xml; charset=utf-8",
}
+var mimeLock sync.RWMutex
+
func loadMimeFile(filename string) {
f, err := os.Open(filename, os.O_RDONLY, 0666)
if err != nil {
@@ -73,10 +68,37 @@ func initMime() {
}
}
+var once sync.Once
+
// TypeByExtension returns the MIME type associated with the file extension ext.
// The extension ext should begin with a leading dot, as in ".html".
// When ext has no associated type, TypeByExtension returns "".
+//
+// The built-in table is small but is is augmented by the local
+// system's mime.types file(s) if available under one or more of these
+// names:
+//
+// /etc/mime.types
+// /etc/apache2/mime.types
+// /etc/apache/mime.types
func TypeByExtension(ext string) string {
once.Do(initMime)
- return mimeTypes[ext]
+ mimeLock.RLock()
+ typename := mimeTypes[ext]
+ mimeLock.RUnlock()
+ return typename
+}
+
+// AddExtensionType sets the MIME type associated with
+// the extension ext to typ. The extension should begin with
+// a leading dot, as in ".html".
+func AddExtensionType(ext, typ string) os.Error {
+ once.Do(initMime)
+ if len(ext) < 1 || ext[0] != '.' {
+ return os.EINVAL
+ }
+ mimeLock.Lock()
+ mimeTypes[ext] = typ
+ mimeLock.Unlock()
+ return nil
}
diff --git a/src/pkg/net/Makefile b/src/pkg/net/Makefile
index 955485a6b..6b6d7c0e3 100644
--- a/src/pkg/net/Makefile
+++ b/src/pkg/net/Makefile
@@ -2,13 +2,11 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=net
GOFILES=\
dial.go\
- dnsclient.go\
- dnsconfig.go\
dnsmsg.go\
fd_$(GOOS).go\
hosts.go\
@@ -18,7 +16,6 @@ GOFILES=\
net.go\
parse.go\
pipe.go\
- port.go\
sock.go\
tcpsock.go\
udpsock.go\
@@ -27,18 +24,26 @@ GOFILES=\
GOFILES_freebsd=\
newpollserver.go\
fd.go\
+ dnsconfig.go\
+ dnsclient.go\
+ port.go\
GOFILES_darwin=\
newpollserver.go\
fd.go\
-
+ dnsconfig.go\
+ dnsclient.go\
+ port.go\
+
GOFILES_linux=\
newpollserver.go\
fd.go\
+ dnsconfig.go\
+ dnsclient.go\
+ port.go\
-GOFILES_nacl=\
- newpollserver.go\
- fd.go\
+GOFILES_windows=\
+ resolv_windows.go\
GOFILES+=$(GOFILES_$(GOOS))
diff --git a/src/pkg/net/dial.go b/src/pkg/net/dial.go
index 4ba11e7fe..9a4c8f688 100644
--- a/src/pkg/net/dial.go
+++ b/src/pkg/net/dial.go
@@ -12,7 +12,7 @@ import "os"
//
// Known networks are "tcp", "tcp4" (IPv4-only), "tcp6" (IPv6-only),
// "udp", "udp4" (IPv4-only), "udp6" (IPv6-only), "ip", "ip4"
-// (IPv4-only) and "ip6" IPv6-only).
+// (IPv4-only), "ip6" (IPv6-only), "unix" and "unixgram".
//
// For IP networks, addresses have the form host:port. If host is
// a literal IPv6 address, it must be enclosed in square brackets.
diff --git a/src/pkg/net/dialgoogle_test.go b/src/pkg/net/dialgoogle_test.go
index 03641817d..47a478a8f 100644
--- a/src/pkg/net/dialgoogle_test.go
+++ b/src/pkg/net/dialgoogle_test.go
@@ -17,7 +17,7 @@ var ipv6 = flag.Bool("ipv6", false, "assume ipv6 tunnel is present")
// fd is already connected to the destination, port 80.
// Run an HTTP request to fetch the appropriate page.
func fetchGoogle(t *testing.T, fd Conn, network, addr string) {
- req := []byte("GET /intl/en/privacy.html HTTP/1.0\r\nHost: www.google.com\r\n\r\n")
+ req := []byte("GET /intl/en/privacy/ HTTP/1.0\r\nHost: www.google.com\r\n\r\n")
n, err := fd.Write(req)
buf := make([]byte, 1000)
diff --git a/src/pkg/net/dict/Makefile b/src/pkg/net/dict/Makefile
new file mode 100644
index 000000000..eaa9e6531
--- /dev/null
+++ b/src/pkg/net/dict/Makefile
@@ -0,0 +1,7 @@
+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
new file mode 100644
index 000000000..42f6553ad
--- /dev/null
+++ b/src/pkg/net/dict/dict.go
@@ -0,0 +1,212 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package dict implements the Dictionary Server Protocol
+// as defined in RFC 2229.
+package dict
+
+import (
+ "container/vector"
+ "net/textproto"
+ "os"
+ "strconv"
+ "strings"
+)
+
+// A Client represents a client connection to a dictionary server.
+type Client struct {
+ text *textproto.Conn
+}
+
+// Dial returns a new client connected to a dictionary server at
+// addr on the given network.
+func Dial(network, addr string) (*Client, os.Error) {
+ text, err := textproto.Dial(network, addr)
+ if err != nil {
+ return nil, err
+ }
+ _, _, err = text.ReadCodeLine(220)
+ if err != nil {
+ text.Close()
+ return nil, err
+ }
+ return &Client{text: text}, nil
+}
+
+// Close closes the connection to the dictionary server.
+func (c *Client) Close() os.Error {
+ return c.text.Close()
+}
+
+// A Dict represents a dictionary available on the server.
+type Dict struct {
+ Name string // short name of dictionary
+ Desc string // long description
+}
+
+// Dicts returns a list of the dictionaries available on the server.
+func (c *Client) Dicts() ([]Dict, os.Error) {
+ id, err := c.text.Cmd("SHOW DB")
+ if err != nil {
+ return nil, err
+ }
+
+ c.text.StartResponse(id)
+ defer c.text.EndResponse(id)
+
+ _, _, err = c.text.ReadCodeLine(110)
+ if err != nil {
+ return nil, err
+ }
+ lines, err := c.text.ReadDotLines()
+ if err != nil {
+ return nil, err
+ }
+ _, _, err = c.text.ReadCodeLine(250)
+
+ dicts := make([]Dict, len(lines))
+ for i := range dicts {
+ d := &dicts[i]
+ a, _ := fields(lines[i])
+ if len(a) < 2 {
+ return nil, textproto.ProtocolError("invalid dictionary: " + lines[i])
+ }
+ d.Name = a[0]
+ d.Desc = a[1]
+ }
+ return dicts, err
+}
+
+// A Defn represents a definition.
+type Defn struct {
+ Dict Dict // Dict where definition was found
+ Word string // Word being defined
+ Text []byte // Definition text, typically multiple lines
+}
+
+// Define requests the definition of the given word.
+// The argument dict names the dictionary to use,
+// the Name field of a Dict returned by Dicts.
+//
+// The special dictionary name "*" means to look in all the
+// server's dictionaries.
+// The special dictionary name "!" means to look in all the
+// server's dictionaries in turn, stopping after finding the word
+// in one of them.
+func (c *Client) Define(dict, word string) ([]*Defn, os.Error) {
+ id, err := c.text.Cmd("DEFINE %s %q", dict, word)
+ if err != nil {
+ return nil, err
+ }
+
+ c.text.StartResponse(id)
+ defer c.text.EndResponse(id)
+
+ _, line, err := c.text.ReadCodeLine(150)
+ if err != nil {
+ return nil, err
+ }
+ a, _ := fields(line)
+ if len(a) < 1 {
+ return nil, textproto.ProtocolError("malformed response: " + line)
+ }
+ n, err := strconv.Atoi(a[0])
+ if err != nil {
+ return nil, textproto.ProtocolError("invalid definition count: " + a[0])
+ }
+ def := make([]*Defn, n)
+ for i := 0; i < n; i++ {
+ _, line, err = c.text.ReadCodeLine(151)
+ if err != nil {
+ return nil, err
+ }
+ a, _ := fields(line)
+ if len(a) < 3 {
+ // skip it, to keep protocol in sync
+ i--
+ n--
+ def = def[0:n]
+ continue
+ }
+ d := &Defn{Word: a[0], Dict: Dict{a[1], a[2]}}
+ d.Text, err = c.text.ReadDotBytes()
+ if err != nil {
+ return nil, err
+ }
+ def[i] = d
+ }
+ _, _, err = c.text.ReadCodeLine(250)
+ return def, err
+}
+
+// Fields returns the fields in s.
+// Fields are space separated unquoted words
+// or quoted with single or double quote.
+func fields(s string) ([]string, os.Error) {
+ var v vector.StringVector
+ i := 0
+ for {
+ for i < len(s) && (s[i] == ' ' || s[i] == '\t') {
+ i++
+ }
+ if i >= len(s) {
+ break
+ }
+ if s[i] == '"' || s[i] == '\'' {
+ q := s[i]
+ // quoted string
+ var j int
+ for j = i + 1; ; j++ {
+ if j >= len(s) {
+ return nil, textproto.ProtocolError("malformed quoted string")
+ }
+ if s[j] == '\\' {
+ j++
+ continue
+ }
+ if s[j] == q {
+ j++
+ break
+ }
+ }
+ v.Push(unquote(s[i+1 : j-1]))
+ i = j
+ } else {
+ // atom
+ var j int
+ for j = i; j < len(s); j++ {
+ if s[j] == ' ' || s[j] == '\t' || s[j] == '\\' || s[j] == '"' || s[j] == '\'' {
+ break
+ }
+ }
+ v.Push(s[i:j])
+ i = j
+ }
+ if i < len(s) {
+ c := s[i]
+ if c != ' ' && c != '\t' {
+ return nil, textproto.ProtocolError("quotes not on word boundaries")
+ }
+ }
+ }
+ return v, nil
+}
+
+func unquote(s string) string {
+ if strings.Index(s, "\\") < 0 {
+ return s
+ }
+ b := []byte(s)
+ w := 0
+ for r := 0; r < len(b); r++ {
+ c := b[r]
+ if c == '\\' {
+ r++
+ c = b[r]
+ }
+ b[w] = c
+ w++
+ }
+ return string(b[0:w])
+}
diff --git a/src/pkg/net/dnsclient.go b/src/pkg/net/dnsclient.go
index ea21117e3..f1cd47bb1 100644
--- a/src/pkg/net/dnsclient.go
+++ b/src/pkg/net/dnsclient.go
@@ -15,9 +15,9 @@
package net
import (
- "once"
"os"
"rand"
+ "sync"
"time"
)
@@ -30,6 +30,9 @@ type DNSError struct {
}
func (e *DNSError) String() string {
+ if e == nil {
+ return "<nil>"
+ }
s := "lookup " + e.Name
if e.Server != "" {
s += " on " + e.Server
@@ -52,7 +55,7 @@ func exchange(cfg *dnsConfig, c Conn, name string, qtype uint16) (*dnsMsg, os.Er
out := new(dnsMsg)
out.id = uint16(rand.Int()) ^ uint16(time.Nanoseconds())
out.question = []dnsQuestion{
- dnsQuestion{name, qtype, dnsClassINET},
+ {name, qtype, dnsClassINET},
}
out.recursion_desired = true
msg, ok := out.Pack()
@@ -189,42 +192,46 @@ var dnserr os.Error
func loadConfig() { cfg, dnserr = dnsReadConfig() }
func isDomainName(s string) bool {
- // Requirements on DNS name:
- // * must not be empty.
- // * must be alphanumeric plus - and .
- // * each of the dot-separated elements must begin
- // and end with a letter or digit.
- // RFC 1035 required the element to begin with a letter,
- // but RFC 3696 says this has been relaxed to allow digits too.
- // still, there must be a letter somewhere in the entire name.
+ // See RFC 1035, RFC 3696.
if len(s) == 0 {
return false
}
+ if len(s) > 255 {
+ return false
+ }
if s[len(s)-1] != '.' { // simplify checking loop: make name end in dot
s += "."
}
last := byte('.')
ok := false // ok once we've seen a letter
+ partlen := 0
for i := 0; i < len(s); i++ {
c := s[i]
switch {
default:
return false
- case 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z':
+ case 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || c == '_':
ok = true
+ partlen++
case '0' <= c && c <= '9':
// fine
+ partlen++
case c == '-':
// byte before dash cannot be dot
if last == '.' {
return false
}
+ partlen++
case c == '.':
// byte before dot cannot be dot, dash
if last == '.' || last == '-' {
return false
}
+ if partlen > 63 || partlen == 0 {
+ return false
+ }
+ partlen = 0
}
last = c
}
@@ -232,11 +239,13 @@ func isDomainName(s string) bool {
return ok
}
+var onceLoadConfig sync.Once
+
func lookup(name string, qtype uint16) (cname string, addrs []dnsRR, err os.Error) {
if !isDomainName(name) {
return name, nil, &DNSError{Error: "invalid domain name", Name: name}
}
- once.Do(loadConfig)
+ onceLoadConfig.Do(loadConfig)
if dnserr != nil || cfg == nil {
err = dnserr
return
@@ -290,7 +299,7 @@ func lookup(name string, qtype uint16) (cname string, addrs []dnsRR, err os.Erro
// It returns the canonical name for the host and an array of that
// host's addresses.
func LookupHost(name string) (cname string, addrs []string, err os.Error) {
- once.Do(loadConfig)
+ onceLoadConfig.Do(loadConfig)
if dnserr != nil || cfg == nil {
err = dnserr
return
@@ -317,9 +326,14 @@ type SRV struct {
Weight uint16
}
-func LookupSRV(name string) (cname string, addrs []*SRV, err os.Error) {
+// LookupSRV tries to resolve an SRV query of the given service,
+// protocol, and domain name, as specified in RFC 2782. In most cases
+// the proto argument can be the same as the corresponding
+// Addr.Network().
+func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err os.Error) {
+ target := "_" + service + "._" + proto + "." + name
var records []dnsRR
- cname, records, err = lookup(name, dnsTypeSRV)
+ cname, records, err = lookup(target, dnsTypeSRV)
if err != nil {
return
}
@@ -330,3 +344,22 @@ func LookupSRV(name string) (cname string, addrs []*SRV, err os.Error) {
}
return
}
+
+type MX struct {
+ Host string
+ Pref uint16
+}
+
+func LookupMX(name string) (entries []*MX, err os.Error) {
+ var records []dnsRR
+ _, records, err = lookup(name, dnsTypeMX)
+ if err != nil {
+ return
+ }
+ entries = make([]*MX, len(records))
+ for i := 0; i < len(records); i++ {
+ r := records[i].(*dnsRR_MX)
+ entries[i] = &MX{r.Mx, r.Pref}
+ }
+ return
+}
diff --git a/src/pkg/net/dnsmsg.go b/src/pkg/net/dnsmsg.go
index 1d1b62eeb..dc195caf8 100644
--- a/src/pkg/net/dnsmsg.go
+++ b/src/pkg/net/dnsmsg.go
@@ -430,10 +430,7 @@ func packStructValue(val *reflect.StructValue, msg []byte, off int) (off1 int, o
}
msg[off] = byte(len(s))
off++
- for i := 0; i < len(s); i++ {
- msg[off+i] = s[i]
- }
- off += len(s)
+ off += copy(msg[off:], s)
}
}
}
diff --git a/src/pkg/net/dnsname_test.go b/src/pkg/net/dnsname_test.go
new file mode 100644
index 000000000..f4089c5db
--- /dev/null
+++ b/src/pkg/net/dnsname_test.go
@@ -0,0 +1,69 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+import (
+ "testing"
+ "runtime"
+)
+
+type testCase struct {
+ name string
+ result bool
+}
+
+var tests = []testCase{
+ // RFC2181, section 11.
+ {"_xmpp-server._tcp.google.com", true},
+ {"_xmpp-server._tcp.google.com", true},
+ {"foo.com", true},
+ {"1foo.com", true},
+ {"26.0.0.73.com", true},
+ {"fo-o.com", true},
+ {"fo1o.com", true},
+ {"foo1.com", true},
+ {"a.b..com", false},
+}
+
+func getTestCases(ch chan<- *testCase) {
+ defer close(ch)
+ var char59 = ""
+ var char63 = ""
+ var char64 = ""
+ for i := 0; i < 59; i++ {
+ char59 += "a"
+ }
+ char63 = char59 + "aaaa"
+ char64 = char63 + "a"
+
+ for _, tc := range tests {
+ ch <- &tc
+ }
+
+ ch <- &testCase{char63 + ".com", true}
+ ch <- &testCase{char64 + ".com", false}
+ // 255 char name is fine:
+ ch <- &testCase{char59 + "." + char63 + "." + char63 + "." +
+ char63 + ".com",
+ true}
+ // 256 char name is bad:
+ ch <- &testCase{char59 + "a." + char63 + "." + char63 + "." +
+ char63 + ".com",
+ false}
+}
+
+func TestDNSNames(t *testing.T) {
+ if runtime.GOOS == "windows" {
+ return
+ }
+ ch := make(chan *testCase)
+ go getTestCases(ch)
+ for tc := range ch {
+ if isDomainName(tc.name) != tc.result {
+ t.Errorf("isDomainName(%v) failed: Should be %v",
+ tc.name, tc.result)
+ }
+ }
+}
diff --git a/src/pkg/net/fd.go b/src/pkg/net/fd.go
index 4673a94e4..5ec91845d 100644
--- a/src/pkg/net/fd.go
+++ b/src/pkg/net/fd.go
@@ -8,7 +8,6 @@ package net
import (
"io"
- "once"
"os"
"sync"
"syscall"
@@ -230,7 +229,7 @@ func (s *pollServer) Run() {
} else {
netfd := s.LookupFD(fd, mode)
if netfd == nil {
- print("pollServer: unexpected wakeup for fd=", netfd, " mode=", string(mode), "\n")
+ print("pollServer: unexpected wakeup for fd=", fd, " mode=", string(mode), "\n")
continue
}
s.WakeFD(netfd, mode)
@@ -258,6 +257,7 @@ func (s *pollServer) WaitWrite(fd *netFD) {
// All the network FDs use a single pollServer.
var pollserver *pollServer
+var onceStartServer sync.Once
func startServer() {
p, err := newPollServer()
@@ -268,7 +268,7 @@ func startServer() {
}
func newFD(fd, family, proto int, net string, laddr, raddr Addr) (f *netFD, err os.Error) {
- once.Do(startServer)
+ onceStartServer.Do(startServer)
if e := syscall.SetNonblock(fd, true); e != 0 {
return nil, &OpError{"setnonblock", net, laddr, os.Errno(e)}
}
@@ -401,6 +401,42 @@ func (fd *netFD) ReadFrom(p []byte) (n int, sa syscall.Sockaddr, err os.Error) {
return
}
+func (fd *netFD) ReadMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err os.Error) {
+ if fd == nil || fd.sysfile == nil {
+ return 0, 0, 0, nil, os.EINVAL
+ }
+ fd.rio.Lock()
+ defer fd.rio.Unlock()
+ fd.incref()
+ defer fd.decref()
+ if fd.rdeadline_delta > 0 {
+ fd.rdeadline = pollserver.Now() + fd.rdeadline_delta
+ } else {
+ fd.rdeadline = 0
+ }
+ var oserr os.Error
+ for {
+ var errno int
+ n, oobn, flags, errno = syscall.Recvmsg(fd.sysfd, p, oob, sa, 0)
+ if errno == syscall.EAGAIN && fd.rdeadline >= 0 {
+ pollserver.WaitRead(fd)
+ continue
+ }
+ if errno != 0 {
+ oserr = os.Errno(errno)
+ }
+ if n == 0 {
+ oserr = os.EOF
+ }
+ break
+ }
+ if oserr != nil {
+ err = &OpError{"read", fd.net, fd.laddr, oserr}
+ return
+ }
+ return
+}
+
func (fd *netFD) Write(p []byte) (n int, err os.Error) {
if fd == nil {
return 0, os.EINVAL
@@ -481,6 +517,41 @@ func (fd *netFD) WriteTo(p []byte, sa syscall.Sockaddr) (n int, err os.Error) {
return
}
+func (fd *netFD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err os.Error) {
+ if fd == nil || fd.sysfile == nil {
+ return 0, 0, os.EINVAL
+ }
+ fd.wio.Lock()
+ defer fd.wio.Unlock()
+ fd.incref()
+ defer fd.decref()
+ if fd.wdeadline_delta > 0 {
+ fd.wdeadline = pollserver.Now() + fd.wdeadline_delta
+ } else {
+ fd.wdeadline = 0
+ }
+ var oserr os.Error
+ for {
+ var errno int
+ errno = syscall.Sendmsg(fd.sysfd, p, oob, sa, 0)
+ if errno == syscall.EAGAIN && fd.wdeadline >= 0 {
+ pollserver.WaitWrite(fd)
+ continue
+ }
+ if errno != 0 {
+ oserr = os.Errno(errno)
+ }
+ break
+ }
+ if oserr == nil {
+ n = len(p)
+ oobn = len(oob)
+ } else {
+ err = &OpError{"write", fd.net, fd.raddr, oserr}
+ }
+ return
+}
+
func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os.Error) {
if fd == nil || fd.sysfile == nil {
return nil, os.EINVAL
@@ -496,6 +567,10 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os.
var s, e int
var sa syscall.Sockaddr
for {
+ if fd.closing {
+ syscall.ForkLock.RUnlock()
+ return nil, os.EINVAL
+ }
s, sa, e = syscall.Accept(fd.sysfd)
if e != syscall.EAGAIN {
break
@@ -517,3 +592,21 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os.
}
return nfd, nil
}
+
+func (fd *netFD) dup() (f *os.File, err os.Error) {
+ ns, e := syscall.Dup(fd.sysfd)
+ if e != 0 {
+ return nil, &OpError{"dup", fd.net, fd.laddr, os.Errno(e)}
+ }
+
+ // We want blocking mode for the new fd, hence the double negative.
+ if e = syscall.SetNonblock(ns, false); e != 0 {
+ return nil, &OpError{"setnonblock", fd.net, fd.laddr, os.Errno(e)}
+ }
+
+ return os.NewFile(ns, fd.sysfile.Name()), nil
+}
+
+func closesocket(s int) (errno int) {
+ return syscall.Close(s)
+}
diff --git a/src/pkg/net/fd_freebsd.go b/src/pkg/net/fd_freebsd.go
index 01a3c8d72..4c5e93424 100644
--- a/src/pkg/net/fd_freebsd.go
+++ b/src/pkg/net/fd_freebsd.go
@@ -44,7 +44,7 @@ func (p *pollster) AddFD(fd int, mode int, repeat bool) os.Error {
}
syscall.SetKevent(ev, fd, kmode, flags)
- n, e := syscall.Kevent(p.kq, &events, nil, nil)
+ n, e := syscall.Kevent(p.kq, events[:], nil, nil)
if e != 0 {
return os.NewSyscallError("kevent", e)
}
@@ -68,7 +68,7 @@ func (p *pollster) DelFD(fd int, mode int) {
ev := &events[0]
// EV_DELETE - delete event from kqueue list
syscall.SetKevent(ev, fd, kmode, syscall.EV_DELETE)
- syscall.Kevent(p.kq, &events, nil, nil)
+ syscall.Kevent(p.kq, events[:], nil, nil)
}
func (p *pollster) WaitFD(nsec int64) (fd int, mode int, err os.Error) {
@@ -80,7 +80,7 @@ func (p *pollster) WaitFD(nsec int64) (fd int, mode int, err os.Error) {
}
*t = syscall.NsecToTimespec(nsec)
}
- nn, e := syscall.Kevent(p.kq, nil, &p.eventbuf, t)
+ nn, e := syscall.Kevent(p.kq, nil, p.eventbuf[:], t)
if e != 0 {
if e == syscall.EINTR {
continue
diff --git a/src/pkg/net/fd_nacl.go b/src/pkg/net/fd_nacl.go
deleted file mode 100644
index d21db8b3a..000000000
--- a/src/pkg/net/fd_nacl.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.
-
-package net
-
-import (
- "os"
- "syscall"
-)
-
-type pollster struct{}
-
-func newpollster() (p *pollster, err os.Error) {
- return nil, os.NewSyscallError("networking", syscall.ENACL)
-}
-
-func (p *pollster) AddFD(fd int, mode int, repeat bool) os.Error {
- _, err := newpollster()
- return err
-}
-
-func (p *pollster) StopWaiting(fd int, bits uint) {
-}
-
-func (p *pollster) DelFD(fd int, mode int) {}
-
-func (p *pollster) WaitFD(nsec int64) (fd int, mode int, err os.Error) {
- _, err = newpollster()
- return
-}
-
-func (p *pollster) Close() os.Error { return nil }
diff --git a/src/pkg/net/fd_windows.go b/src/pkg/net/fd_windows.go
index 90887b0a9..72685d612 100644
--- a/src/pkg/net/fd_windows.go
+++ b/src/pkg/net/fd_windows.go
@@ -5,11 +5,11 @@
package net
import (
- "once"
"os"
"sync"
"syscall"
"unsafe"
+ "runtime"
)
// BUG(brainman): The Windows implementation does not implement SetTimeout.
@@ -29,15 +29,14 @@ type netFD struct {
closing bool
// immutable until Close
- sysfd int
- family int
- proto int
- sysfile *os.File
- cr chan *ioResult
- cw chan *ioResult
- net string
- laddr Addr
- raddr Addr
+ sysfd int
+ family int
+ proto int
+ cr chan *ioResult
+ cw chan *ioResult
+ net string
+ laddr Addr
+ raddr Addr
// owned by client
rdeadline_delta int64
@@ -119,6 +118,7 @@ func (s *pollServer) Run() {
// All the network FDs use a single pollServer.
var pollserver *pollServer
+var onceStartServer sync.Once
func startServer() {
p, err := newPollServer()
@@ -134,7 +134,7 @@ func newFD(fd, family, proto int, net string, laddr, raddr Addr) (f *netFD, err
if initErr != nil {
return nil, initErr
}
- once.Do(startServer)
+ onceStartServer.Do(startServer)
// Associate our socket with pollserver.iocp.
if _, e := syscall.CreateIoCompletionPort(int32(fd), pollserver.iocp, 0, 0); e != 0 {
return nil, &OpError{"CreateIoCompletionPort", net, laddr, os.Errno(e)}
@@ -149,14 +149,7 @@ func newFD(fd, family, proto int, net string, laddr, raddr Addr) (f *netFD, err
laddr: laddr,
raddr: raddr,
}
- var ls, rs string
- if laddr != nil {
- ls = laddr.String()
- }
- if raddr != nil {
- rs = raddr.String()
- }
- f.sysfile = os.NewFile(fd, net+":"+ls+"->"+rs)
+ runtime.SetFinalizer(f, (*netFD).Close)
return f, nil
}
@@ -178,15 +171,16 @@ func (fd *netFD) decref() {
// can handle the extra OS processes. Otherwise we'll need to
// use the pollserver for Close too. Sigh.
syscall.SetNonblock(fd.sysfd, false)
- fd.sysfile.Close()
- fd.sysfile = nil
+ closesocket(fd.sysfd)
fd.sysfd = -1
+ // no need for a finalizer anymore
+ runtime.SetFinalizer(fd, nil)
}
fd.sysmu.Unlock()
}
func (fd *netFD) Close() os.Error {
- if fd == nil || fd.sysfile == nil {
+ if fd == nil || fd.sysfd == -1 {
return os.EINVAL
}
@@ -198,7 +192,11 @@ func (fd *netFD) Close() os.Error {
}
func newWSABuf(p []byte) *syscall.WSABuf {
- return &syscall.WSABuf{uint32(len(p)), (*byte)(unsafe.Pointer(&p[0]))}
+ var p0 *byte
+ if len(p) > 0 {
+ p0 = (*byte)(unsafe.Pointer(&p[0]))
+ }
+ return &syscall.WSABuf{uint32(len(p)), p0}
}
func (fd *netFD) Read(p []byte) (n int, err os.Error) {
@@ -209,7 +207,7 @@ func (fd *netFD) Read(p []byte) (n int, err os.Error) {
defer fd.rio.Unlock()
fd.incref()
defer fd.decref()
- if fd.sysfile == nil {
+ if fd.sysfd == -1 {
return 0, os.EINVAL
}
// Submit receive request.
@@ -232,12 +230,50 @@ func (fd *netFD) Read(p []byte) (n int, err os.Error) {
err = &OpError{"WSARecv", fd.net, fd.laddr, os.Errno(r.errno)}
}
n = int(r.qty)
+ if err == nil && n == 0 {
+ err = os.EOF
+ }
return
}
func (fd *netFD) ReadFrom(p []byte) (n int, sa syscall.Sockaddr, err os.Error) {
- var r syscall.Sockaddr
- return 0, r, nil
+ if fd == nil {
+ return 0, nil, os.EINVAL
+ }
+ if len(p) == 0 {
+ return 0, nil, nil
+ }
+ fd.rio.Lock()
+ defer fd.rio.Unlock()
+ fd.incref()
+ defer fd.decref()
+ if fd.sysfd == -1 {
+ return 0, nil, os.EINVAL
+ }
+ // Submit receive request.
+ var pckt ioPacket
+ pckt.c = fd.cr
+ var done uint32
+ flags := uint32(0)
+ var rsa syscall.RawSockaddrAny
+ l := int32(unsafe.Sizeof(rsa))
+ e := syscall.WSARecvFrom(uint32(fd.sysfd), newWSABuf(p), 1, &done, &flags, &rsa, &l, &pckt.o, nil)
+ switch e {
+ case 0:
+ // IO completed immediately, but we need to get our completion message anyway.
+ case syscall.ERROR_IO_PENDING:
+ // IO started, and we have to wait for it's completion.
+ default:
+ return 0, nil, &OpError{"WSARecvFrom", fd.net, fd.laddr, os.Errno(e)}
+ }
+ // Wait for our request to complete.
+ r := <-pckt.c
+ if r.errno != 0 {
+ err = &OpError{"WSARecvFrom", fd.net, fd.laddr, os.Errno(r.errno)}
+ }
+ n = int(r.qty)
+ sa, _ = rsa.Sockaddr()
+ return
}
func (fd *netFD) Write(p []byte) (n int, err os.Error) {
@@ -248,7 +284,7 @@ func (fd *netFD) Write(p []byte) (n int, err os.Error) {
defer fd.wio.Unlock()
fd.incref()
defer fd.decref()
- if fd.sysfile == nil {
+ if fd.sysfd == -1 {
return 0, os.EINVAL
}
// Submit send request.
@@ -274,11 +310,43 @@ func (fd *netFD) Write(p []byte) (n int, err os.Error) {
}
func (fd *netFD) WriteTo(p []byte, sa syscall.Sockaddr) (n int, err os.Error) {
- return 0, nil
+ if fd == nil {
+ return 0, os.EINVAL
+ }
+ if len(p) == 0 {
+ return 0, nil
+ }
+ fd.wio.Lock()
+ defer fd.wio.Unlock()
+ fd.incref()
+ defer fd.decref()
+ if fd.sysfd == -1 {
+ return 0, os.EINVAL
+ }
+ // Submit send request.
+ var pckt ioPacket
+ pckt.c = fd.cw
+ var done uint32
+ e := syscall.WSASendto(uint32(fd.sysfd), newWSABuf(p), 1, &done, 0, sa, &pckt.o, nil)
+ switch e {
+ case 0:
+ // IO completed immediately, but we need to get our completion message anyway.
+ case syscall.ERROR_IO_PENDING:
+ // IO started, and we have to wait for it's completion.
+ default:
+ return 0, &OpError{"WSASendTo", fd.net, fd.laddr, os.Errno(e)}
+ }
+ // Wait for our request to complete.
+ r := <-pckt.c
+ if r.errno != 0 {
+ err = &OpError{"WSASendTo", fd.net, fd.laddr, os.Errno(r.errno)}
+ }
+ n = int(r.qty)
+ return
}
func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os.Error) {
- if fd == nil || fd.sysfile == nil {
+ if fd == nil || fd.sysfd == -1 {
return nil, os.EINVAL
}
fd.incref()
@@ -296,7 +364,7 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os.
syscall.ForkLock.RUnlock()
// Associate our new socket with IOCP.
- once.Do(startServer)
+ onceStartServer.Do(startServer)
if _, e = syscall.CreateIoCompletionPort(int32(s), pollserver.iocp, 0, 0); e != 0 {
return nil, &OpError{"CreateIoCompletionPort", fd.net, fd.laddr, os.Errno(e)}
}
@@ -313,21 +381,21 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os.
case syscall.ERROR_IO_PENDING:
// IO started, and we have to wait for it's completion.
default:
- syscall.Close(s)
+ closesocket(s)
return nil, &OpError{"AcceptEx", fd.net, fd.laddr, os.Errno(e)}
}
// Wait for peer connection.
r := <-pckt.c
if r.errno != 0 {
- syscall.Close(s)
+ closesocket(s)
return nil, &OpError{"AcceptEx", fd.net, fd.laddr, os.Errno(r.errno)}
}
// Inherit properties of the listening socket.
e = syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_UPDATE_ACCEPT_CONTEXT, fd.sysfd)
if e != 0 {
- syscall.Close(s)
+ closesocket(s)
return nil, &OpError{"Setsockopt", fd.net, fd.laddr, os.Errno(r.errno)}
}
@@ -348,17 +416,14 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os.
laddr: laddr,
raddr: raddr,
}
- var ls, rs string
- if laddr != nil {
- ls = laddr.String()
- }
- if raddr != nil {
- rs = raddr.String()
- }
- f.sysfile = os.NewFile(s, fd.net+":"+ls+"->"+rs)
+ runtime.SetFinalizer(f, (*netFD).Close)
return f, nil
}
+func closesocket(s int) (errno int) {
+ return syscall.Closesocket(int32(s))
+}
+
func init() {
var d syscall.WSAData
e := syscall.WSAStartup(uint32(0x101), &d)
@@ -366,3 +431,16 @@ func init() {
initErr = os.NewSyscallError("WSAStartup", e)
}
}
+
+func (fd *netFD) dup() (f *os.File, err os.Error) {
+ // TODO: Implement this
+ return nil, os.NewSyscallError("dup", syscall.EWINDOWS)
+}
+
+func (fd *netFD) ReadMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err os.Error) {
+ return 0, 0, 0, nil, os.EAFNOSUPPORT
+}
+
+func (fd *netFD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err os.Error) {
+ return 0, 0, os.EAFNOSUPPORT
+}
diff --git a/src/pkg/net/hosts.go b/src/pkg/net/hosts.go
index 006352b17..556d57f11 100644
--- a/src/pkg/net/hosts.go
+++ b/src/pkg/net/hosts.go
@@ -44,7 +44,7 @@ func readHosts() {
}
for i := 1; i < len(f); i++ {
h := f[i]
- hs[h] = appendHost(hs[h], f[0])
+ hs[h] = append(hs[h], f[0])
}
}
// Update the data cache.
@@ -55,18 +55,6 @@ func readHosts() {
}
}
-func appendHost(hosts []string, address string) []string {
- n := len(hosts)
- if n+1 > cap(hosts) { // reallocate
- a := make([]string, n, 2*n+1)
- copy(a, hosts)
- hosts = a
- }
- hosts = hosts[0 : n+1]
- hosts[n] = address
- return hosts
-}
-
// lookupStaticHosts looks up the addresses for the given host from /etc/hosts.
func lookupStaticHost(host string) []string {
hosts.Lock()
diff --git a/src/pkg/net/hosts_test.go b/src/pkg/net/hosts_test.go
index d0ee2a7ac..84cd92e37 100644
--- a/src/pkg/net/hosts_test.go
+++ b/src/pkg/net/hosts_test.go
@@ -15,19 +15,19 @@ type hostTest struct {
var hosttests = []hostTest{
- hostTest{"odin", []IP{
+ {"odin", []IP{
IPv4(127, 0, 0, 2),
IPv4(127, 0, 0, 3),
ParseIP("::2"),
}},
- hostTest{"thor", []IP{
+ {"thor", []IP{
IPv4(127, 1, 1, 1),
}},
- hostTest{"loki", []IP{}},
- hostTest{"ullr", []IP{
+ {"loki", []IP{}},
+ {"ullr", []IP{
IPv4(127, 1, 1, 2),
}},
- hostTest{"ullrhost", []IP{
+ {"ullrhost", []IP{
IPv4(127, 1, 1, 2),
}},
}
diff --git a/src/pkg/net/ip.go b/src/pkg/net/ip.go
index bd0c75de6..e82224a28 100644
--- a/src/pkg/net/ip.go
+++ b/src/pkg/net/ip.go
@@ -222,6 +222,11 @@ func (ip IP) String() string {
e1 = j
}
}
+ // The symbol "::" MUST NOT be used to shorten just one 16 bit 0 field.
+ if e1-e0 <= 2 {
+ e0 = -1
+ e1 = -1
+ }
// Print with possible :: in place of run of zeros
var s string
diff --git a/src/pkg/net/ip_test.go b/src/pkg/net/ip_test.go
index 0ea1d9260..e29c3021d 100644
--- a/src/pkg/net/ip_test.go
+++ b/src/pkg/net/ip_test.go
@@ -29,17 +29,17 @@ type parseIPTest struct {
}
var parseiptests = []parseIPTest{
- parseIPTest{"127.0.1.2", IPv4(127, 0, 1, 2)},
- parseIPTest{"127.0.0.1", IPv4(127, 0, 0, 1)},
- parseIPTest{"127.0.0.256", nil},
- parseIPTest{"abc", nil},
- parseIPTest{"::ffff:127.0.0.1", IPv4(127, 0, 0, 1)},
- parseIPTest{"2001:4860:0:2001::68",
+ {"127.0.1.2", IPv4(127, 0, 1, 2)},
+ {"127.0.0.1", IPv4(127, 0, 0, 1)},
+ {"127.0.0.256", nil},
+ {"abc", nil},
+ {"::ffff:127.0.0.1", IPv4(127, 0, 0, 1)},
+ {"2001:4860:0:2001::68",
IP{0x20, 0x01, 0x48, 0x60, 0, 0, 0x20, 0x01,
0, 0, 0, 0, 0, 0, 0x00, 0x68,
},
},
- parseIPTest{"::ffff:4a7d:1363", IPv4(74, 125, 19, 99)},
+ {"::ffff:4a7d:1363", IPv4(74, 125, 19, 99)},
}
func TestParseIP(t *testing.T) {
@@ -50,3 +50,45 @@ func TestParseIP(t *testing.T) {
}
}
}
+
+type ipStringTest struct {
+ in IP
+ out string
+}
+
+var ipstringtests = []ipStringTest{
+ // cf. RFC 5952 (A Recommendation for IPv6 Address Text Representation)
+ {IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0,
+ 0, 0, 0x1, 0x23, 0, 0x12, 0, 0x1},
+ "2001:db8::123:12:1"},
+ {IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0x1},
+ "2001:db8::1"},
+ {IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0x1,
+ 0, 0, 0, 0x1, 0, 0, 0, 0x1},
+ "2001:db8:0:1:0:1:0:1"},
+ {IP{0x20, 0x1, 0xd, 0xb8, 0, 0x1, 0, 0,
+ 0, 0x1, 0, 0, 0, 0x1, 0, 0},
+ "2001:db8:1:0:1:0:1:0"},
+ {IP{0x20, 0x1, 0, 0, 0, 0, 0, 0,
+ 0, 0x1, 0, 0, 0, 0, 0, 0x1},
+ "2001::1:0:0:1"},
+ {IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0,
+ 0, 0x1, 0, 0, 0, 0, 0, 0},
+ "2001:db8:0:0:1::"},
+ {IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0,
+ 0, 0x1, 0, 0, 0, 0, 0, 0x1},
+ "2001:db8::1:0:0:1"},
+ {IP{0x20, 0x1, 0xD, 0xB8, 0, 0, 0, 0,
+ 0, 0xA, 0, 0xB, 0, 0xC, 0, 0xD},
+ "2001:db8::a:b:c:d"},
+}
+
+func TestIPString(t *testing.T) {
+ for i := 0; i < len(ipstringtests); i++ {
+ tt := ipstringtests[i]
+ if out := tt.in.String(); out != tt.out {
+ t.Errorf("IP.String(%v) = %#q, want %#q", tt.in, out, tt.out)
+ }
+ }
+}
diff --git a/src/pkg/net/iprawsock.go b/src/pkg/net/iprawsock.go
index bd8f8080a..241be1509 100644
--- a/src/pkg/net/iprawsock.go
+++ b/src/pkg/net/iprawsock.go
@@ -7,11 +7,13 @@
package net
import (
- "once"
"os"
+ "sync"
"syscall"
)
+var onceReadProtocols sync.Once
+
func sockaddrToIP(sa syscall.Sockaddr) Addr {
switch sa := sa.(type) {
case *syscall.SockaddrInet4:
@@ -30,7 +32,12 @@ type IPAddr struct {
// Network returns the address's network name, "ip".
func (a *IPAddr) Network() string { return "ip" }
-func (a *IPAddr) String() string { return a.IP.String() }
+func (a *IPAddr) String() string {
+ if a == nil {
+ return "<nil>"
+ }
+ return a.IP.String()
+}
func (a *IPAddr) family() int {
if a == nil || len(a.IP) <= 4 {
@@ -279,9 +286,9 @@ func readProtocols() {
}
func netProtoSplit(netProto string) (net string, proto int, err os.Error) {
- once.Do(readProtocols)
+ onceReadProtocols.Do(readProtocols)
i := last(netProto, ':')
- if i+1 >= len(netProto) { // no colon
+ if i < 0 { // no colon
return "", 0, os.ErrorString("no IP protocol specified")
}
net = netProto[0:i]
diff --git a/src/pkg/net/ipsock.go b/src/pkg/net/ipsock.go
index 9477420d6..4ba6a55b9 100644
--- a/src/pkg/net/ipsock.go
+++ b/src/pkg/net/ipsock.go
@@ -24,7 +24,7 @@ func kernelSupportsIPv6() bool {
}
fd, e := syscall.Socket(syscall.AF_INET6, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
if fd >= 0 {
- syscall.Close(fd)
+ closesocket(fd)
}
return e == 0
}
@@ -68,12 +68,12 @@ func internetSocket(net string, laddr, raddr sockaddr, socktype, proto int, mode
var la, ra syscall.Sockaddr
if laddr != nil {
- if la, oserr = laddr.sockaddr(family); err != nil {
+ if la, oserr = laddr.sockaddr(family); oserr != nil {
goto Error
}
}
if raddr != nil {
- if ra, oserr = raddr.sockaddr(family); err != nil {
+ if ra, oserr = raddr.sockaddr(family); oserr != nil {
goto Error
}
}
diff --git a/src/pkg/net/net.go b/src/pkg/net/net.go
index 047447870..c0c1c3b8a 100644
--- a/src/pkg/net/net.go
+++ b/src/pkg/net/net.go
@@ -129,6 +129,9 @@ type OpError struct {
}
func (e *OpError) String() string {
+ if e == nil {
+ return "<nil>"
+ }
s := e.Op
if e.Net != "" {
s += " " + e.Net
@@ -164,6 +167,9 @@ type AddrError struct {
}
func (e *AddrError) String() string {
+ if e == nil {
+ return "<nil>"
+ }
s := e.Error
if e.Addr != "" {
s += " " + e.Addr
diff --git a/src/pkg/net/net_test.go b/src/pkg/net/net_test.go
index 72f7303ea..b303254c6 100644
--- a/src/pkg/net/net_test.go
+++ b/src/pkg/net/net_test.go
@@ -20,35 +20,35 @@ type DialErrorTest struct {
}
var dialErrorTests = []DialErrorTest{
- DialErrorTest{
+ {
"datakit", "", "mh/astro/r70",
"dial datakit mh/astro/r70: unknown network datakit",
},
- DialErrorTest{
+ {
"tcp", "", "127.0.0.1:☺",
"dial tcp 127.0.0.1:☺: unknown port tcp/☺",
},
- DialErrorTest{
+ {
"tcp", "", "no-such-name.google.com.:80",
"dial tcp no-such-name.google.com.:80: lookup no-such-name.google.com.( on .*)?: no (.*)",
},
- DialErrorTest{
+ {
"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 (.*)",
},
- DialErrorTest{
+ {
"tcp", "", "no-such-name:80",
`dial tcp no-such-name:80: lookup no-such-name\.(.*\.)?( on .*)?: no (.*)`,
},
- DialErrorTest{
+ {
"tcp", "", "mh/astro/r70:http",
"dial tcp mh/astro/r70:http: lookup mh/astro/r70: invalid domain name",
},
- DialErrorTest{
+ {
"unix", "", "/etc/file-not-found",
"dial unix /etc/file-not-found: no such file or directory",
},
- DialErrorTest{
+ {
"unix", "", "/etc/",
"dial unix /etc/: (permission denied|socket operation on non-socket|connection refused)",
},
diff --git a/src/pkg/net/parse_test.go b/src/pkg/net/parse_test.go
index f53df3b68..2b7784eee 100644
--- a/src/pkg/net/parse_test.go
+++ b/src/pkg/net/parse_test.go
@@ -8,9 +8,14 @@ import (
"bufio"
"os"
"testing"
+ "runtime"
)
func TestReadLine(t *testing.T) {
+ // /etc/services file does not exist on windows.
+ if runtime.GOOS == "windows" {
+ return
+ }
filename := "/etc/services" // a nice big file
fd, err := os.Open(filename, os.O_RDONLY, 0)
diff --git a/src/pkg/net/port.go b/src/pkg/net/port.go
index 5f182d0d1..cd18d2b42 100644
--- a/src/pkg/net/port.go
+++ b/src/pkg/net/port.go
@@ -7,12 +7,13 @@
package net
import (
- "once"
"os"
+ "sync"
)
var services map[string]map[string]int
var servicesError os.Error
+var onceReadServices sync.Once
func readServices() {
services = make(map[string]map[string]int)
@@ -49,7 +50,7 @@ func readServices() {
// LookupPort looks up the port for the given network and service.
func LookupPort(network, service string) (port int, err os.Error) {
- once.Do(readServices)
+ onceReadServices.Do(readServices)
switch network {
case "tcp4", "tcp6":
diff --git a/src/pkg/net/port_test.go b/src/pkg/net/port_test.go
index 50aab5aba..1b7eaf231 100644
--- a/src/pkg/net/port_test.go
+++ b/src/pkg/net/port_test.go
@@ -16,33 +16,32 @@ type portTest struct {
}
var porttests = []portTest{
- portTest{"tcp", "echo", 7, true},
- portTest{"tcp", "discard", 9, true},
- portTest{"tcp", "systat", 11, true},
- portTest{"tcp", "daytime", 13, true},
- portTest{"tcp", "chargen", 19, true},
- portTest{"tcp", "ftp-data", 20, true},
- portTest{"tcp", "ftp", 21, true},
- portTest{"tcp", "ssh", 22, true},
- portTest{"tcp", "telnet", 23, true},
- portTest{"tcp", "smtp", 25, true},
- portTest{"tcp", "time", 37, true},
- portTest{"tcp", "domain", 53, true},
- portTest{"tcp", "gopher", 70, true},
- portTest{"tcp", "finger", 79, true},
- portTest{"tcp", "http", 80, true},
+ {"tcp", "echo", 7, true},
+ {"tcp", "discard", 9, true},
+ {"tcp", "systat", 11, true},
+ {"tcp", "daytime", 13, true},
+ {"tcp", "chargen", 19, true},
+ {"tcp", "ftp-data", 20, true},
+ {"tcp", "ftp", 21, true},
+ {"tcp", "telnet", 23, true},
+ {"tcp", "smtp", 25, true},
+ {"tcp", "time", 37, true},
+ {"tcp", "domain", 53, true},
+ {"tcp", "gopher", 70, true},
+ {"tcp", "finger", 79, true},
+ {"tcp", "http", 80, true},
- portTest{"udp", "echo", 7, true},
- portTest{"udp", "tftp", 69, true},
- portTest{"udp", "bootpc", 68, true},
- portTest{"udp", "bootps", 67, true},
- portTest{"udp", "domain", 53, true},
- portTest{"udp", "ntp", 123, true},
- portTest{"udp", "snmp", 161, true},
- portTest{"udp", "syslog", 514, true},
+ {"udp", "echo", 7, true},
+ {"udp", "tftp", 69, true},
+ {"udp", "bootpc", 68, true},
+ {"udp", "bootps", 67, true},
+ {"udp", "domain", 53, true},
+ {"udp", "ntp", 123, true},
+ {"udp", "snmp", 161, true},
+ {"udp", "syslog", 514, true},
- portTest{"--badnet--", "zzz", 0, false},
- portTest{"tcp", "--badport--", 0, false},
+ {"--badnet--", "zzz", 0, false},
+ {"tcp", "--badport--", 0, false},
}
func TestLookupPort(t *testing.T) {
diff --git a/src/pkg/net/resolv_windows.go b/src/pkg/net/resolv_windows.go
new file mode 100644
index 000000000..d5292b8be
--- /dev/null
+++ b/src/pkg/net/resolv_windows.go
@@ -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.
+
+package net
+
+import (
+ "syscall"
+ "unsafe"
+ "os"
+ "sync"
+)
+
+var hostentLock sync.Mutex
+var serventLock sync.Mutex
+
+func LookupHost(name string) (cname string, addrs []string, err os.Error) {
+ hostentLock.Lock()
+ defer hostentLock.Unlock()
+ h, e := syscall.GetHostByName(name)
+ if e != 0 {
+ return "", nil, os.NewSyscallError("GetHostByName", e)
+ }
+ cname = name
+ switch h.AddrType {
+ case syscall.AF_INET:
+ i := 0
+ addrs = make([]string, 100) // plenty of room to grow
+ for p := (*[100](*[4]byte))(unsafe.Pointer(h.AddrList)); i < cap(addrs) && p[i] != nil; i++ {
+ addrs[i] = IPv4(p[i][0], p[i][1], p[i][2], p[i][3]).String()
+ }
+ addrs = addrs[0:i]
+ default: // TODO(vcc): Implement non IPv4 address lookups.
+ return "", nil, os.NewSyscallError("LookupHost", syscall.EWINDOWS)
+ }
+ return cname, addrs, nil
+}
+
+type SRV struct {
+ Target string
+ Port uint16
+ Priority uint16
+ Weight uint16
+}
+
+func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err os.Error) {
+ var r *syscall.DNSRecord
+ target := "_" + service + "._" + proto + "." + name
+ e := syscall.DnsQuery(target, syscall.DNS_TYPE_SRV, 0, nil, &r, nil)
+ if int(e) != 0 {
+ return "", nil, os.NewSyscallError("LookupSRV", int(e))
+ }
+ defer syscall.DnsRecordListFree(r, 1)
+ addrs = make([]*SRV, 100)
+ i := 0
+ for p := r; p != nil && p.Type == syscall.DNS_TYPE_SRV; p = p.Next {
+ v := (*syscall.DNSSRVData)(unsafe.Pointer(&p.Data[0]))
+ addrs[i] = &SRV{syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Target))[:]), v.Port, v.Priority, v.Weight}
+ i++
+ }
+ addrs = addrs[0:i]
+ return name, addrs, nil
+}
+
+func LookupPort(network, service string) (port int, err os.Error) {
+ switch network {
+ case "tcp4", "tcp6":
+ network = "tcp"
+ case "udp4", "udp6":
+ network = "udp"
+ }
+ serventLock.Lock()
+ defer serventLock.Unlock()
+ s, e := syscall.GetServByName(service, network)
+ if e != 0 {
+ return 0, os.NewSyscallError("GetServByName", e)
+ }
+ return int(syscall.Ntohs(s.Port)), nil
+}
+
+func isDomainName(s string) bool {
+ panic("unimplemented")
+}
diff --git a/src/pkg/net/server_test.go b/src/pkg/net/server_test.go
index 0d077fe95..46bedaa5b 100644
--- a/src/pkg/net/server_test.go
+++ b/src/pkg/net/server_test.go
@@ -11,6 +11,7 @@ import (
"strings"
"syscall"
"testing"
+ "runtime"
)
// Do not test empty datagrams by default.
@@ -108,6 +109,10 @@ func TestTCPServer(t *testing.T) {
}
func TestUnixServer(t *testing.T) {
+ // "unix" sockets are not supported on windows.
+ if runtime.GOOS == "windows" {
+ return
+ }
os.Remove("/tmp/gotest.net")
doTest(t, "unix", "/tmp/gotest.net", "/tmp/gotest.net")
os.Remove("/tmp/gotest.net")
@@ -177,6 +182,10 @@ func TestUDPServer(t *testing.T) {
}
func TestUnixDatagramServer(t *testing.T) {
+ // "unix" sockets are not supported on windows.
+ if runtime.GOOS == "windows" {
+ return
+ }
for _, isEmpty := range []bool{false} {
os.Remove("/tmp/gotest1.net")
os.Remove("/tmp/gotest1.net.local")
diff --git a/src/pkg/net/sock.go b/src/pkg/net/sock.go
index fbdb69583..8ad3548ad 100644
--- a/src/pkg/net/sock.go
+++ b/src/pkg/net/sock.go
@@ -38,10 +38,16 @@ func socket(net string, f, p, t int, la, ra syscall.Sockaddr, toAddr func(syscal
// Allow broadcast.
syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1)
+ if f == syscall.AF_INET6 {
+ // using ip, tcp, udp, etc.
+ // allow both protocols even if the OS default is otherwise.
+ syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, 0)
+ }
+
if la != nil {
e = syscall.Bind(s, la)
if e != 0 {
- syscall.Close(s)
+ closesocket(s)
return nil, os.Errno(e)
}
}
@@ -49,7 +55,7 @@ func socket(net string, f, p, t int, la, ra syscall.Sockaddr, toAddr func(syscal
if ra != nil {
e = syscall.Connect(s, ra)
if e != 0 {
- syscall.Close(s)
+ closesocket(s)
return nil, os.Errno(e)
}
}
@@ -61,7 +67,7 @@ func socket(net string, f, p, t int, la, ra syscall.Sockaddr, toAddr func(syscal
fd, err = newFD(s, f, p, net, laddr, raddr)
if err != nil {
- syscall.Close(s)
+ closesocket(s)
return nil, err
}
@@ -129,6 +135,12 @@ func setKeepAlive(fd *netFD, keepalive bool) os.Error {
return setsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_KEEPALIVE, boolint(keepalive))
}
+func setNoDelay(fd *netFD, noDelay bool) os.Error {
+ fd.incref()
+ defer fd.decref()
+ return setsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.TCP_NODELAY, boolint(noDelay))
+}
+
func setLinger(fd *netFD, sec int) os.Error {
var l syscall.Linger
if sec >= 0 {
diff --git a/src/pkg/net/srv_test.go b/src/pkg/net/srv_test.go
new file mode 100644
index 000000000..4dd6089cd
--- /dev/null
+++ b/src/pkg/net/srv_test.go
@@ -0,0 +1,22 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// TODO It would be nice to use a mock DNS server, to eliminate
+// external dependencies.
+
+package net
+
+import (
+ "testing"
+)
+
+func TestGoogleSRV(t *testing.T) {
+ _, addrs, err := LookupSRV("xmpp-server", "tcp", "google.com")
+ if err != nil {
+ t.Errorf("failed: %s", err)
+ }
+ if len(addrs) == 0 {
+ t.Errorf("no results")
+ }
+}
diff --git a/src/pkg/net/tcpsock.go b/src/pkg/net/tcpsock.go
index d40035291..a4bca11bb 100644
--- a/src/pkg/net/tcpsock.go
+++ b/src/pkg/net/tcpsock.go
@@ -30,7 +30,12 @@ type TCPAddr struct {
// Network returns the address's network name, "tcp".
func (a *TCPAddr) Network() string { return "tcp" }
-func (a *TCPAddr) String() string { return joinHostPort(a.IP.String(), itoa(a.Port)) }
+func (a *TCPAddr) String() string {
+ if a == nil {
+ return "<nil>"
+ }
+ return joinHostPort(a.IP.String(), itoa(a.Port))
+}
func (a *TCPAddr) family() int {
if a == nil || len(a.IP) <= 4 {
@@ -73,7 +78,7 @@ type TCPConn struct {
func newTCPConn(fd *netFD) *TCPConn {
c := &TCPConn{fd}
- setsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.TCP_NODELAY, 1)
+ c.SetNoDelay(true)
return c
}
@@ -192,6 +197,22 @@ func (c *TCPConn) SetKeepAlive(keepalive bool) os.Error {
return setKeepAlive(c.fd, keepalive)
}
+// SetNoDelay controls whether the operating system should delay
+// packet transmission in hopes of sending fewer packets
+// (Nagle's algorithm). The default is true (no delay), meaning
+// that data is sent as soon as possible after a Write.
+func (c *TCPConn) SetNoDelay(noDelay bool) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setNoDelay(c.fd, noDelay)
+}
+
+// File returns a copy of the underlying os.File, set to blocking mode.
+// It is the caller's responsibility to close f when finished.
+// Closing c does not affect f, and closing f does not affect c.
+func (c *TCPConn) File() (f *os.File, err os.Error) { return c.fd.dup() }
+
// DialTCP is like Dial but can only connect to TCP networks
// and returns a TCPConn structure.
func DialTCP(net string, laddr, raddr *TCPAddr) (c *TCPConn, err os.Error) {
@@ -223,7 +244,7 @@ func ListenTCP(net string, laddr *TCPAddr) (l *TCPListener, err os.Error) {
}
errno := syscall.Listen(fd.sysfd, listenBacklog())
if errno != 0 {
- syscall.Close(fd.sysfd)
+ closesocket(fd.sysfd)
return nil, &OpError{"listen", "tcp", laddr, os.Errno(errno)}
}
l = new(TCPListener)
@@ -265,3 +286,8 @@ func (l *TCPListener) Close() os.Error {
// Addr returns the listener's network address, a *TCPAddr.
func (l *TCPListener) Addr() Addr { return l.fd.laddr }
+
+// File returns a copy of the underlying os.File, set to blocking mode.
+// It is the caller's responsibility to close f when finished.
+// Closing c does not affect f, and closing f does not affect c.
+func (l *TCPListener) File() (f *os.File, err os.Error) { return l.fd.dup() }
diff --git a/src/pkg/net/textproto/Makefile b/src/pkg/net/textproto/Makefile
new file mode 100644
index 000000000..7897fa711
--- /dev/null
+++ b/src/pkg/net/textproto/Makefile
@@ -0,0 +1,14 @@
+# Copyright 2010 The Go Authors. 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=\
+ pipeline.go\
+ reader.go\
+ textproto.go\
+ writer.go\
+
+include ../../../Make.pkg
diff --git a/src/pkg/net/textproto/pipeline.go b/src/pkg/net/textproto/pipeline.go
new file mode 100644
index 000000000..8c25884b3
--- /dev/null
+++ b/src/pkg/net/textproto/pipeline.go
@@ -0,0 +1,117 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package textproto
+
+import (
+ "sync"
+)
+
+// A Pipeline manages a pipelined in-order request/response sequence.
+//
+// To use a Pipeline p to manage multiple clients on a connection,
+// each client should run:
+//
+// id := p.Next() // take a number
+//
+// p.StartRequest(id) // wait for turn to send request
+// «send request»
+// p.EndRequest(id) // notify Pipeline that request is sent
+//
+// p.StartResponse(id) // wait for turn to read response
+// «read response»
+// p.EndResponse(id) // notify Pipeline that response is read
+//
+// A pipelined server can use the same calls to ensure that
+// responses computed in parallel are written in the correct order.
+type Pipeline struct {
+ mu sync.Mutex
+ id uint
+ request sequencer
+ response sequencer
+}
+
+// Next returns the next id for a request/response pair.
+func (p *Pipeline) Next() uint {
+ p.mu.Lock()
+ id := p.id
+ p.id++
+ p.mu.Unlock()
+ return id
+}
+
+// StartRequest blocks until it is time to send (or, if this is a server, receive)
+// the request with the given id.
+func (p *Pipeline) StartRequest(id uint) {
+ p.request.Start(id)
+}
+
+// EndRequest notifies p that the request with the given id has been sent
+// (or, if this is a server, received).
+func (p *Pipeline) EndRequest(id uint) {
+ p.request.End(id)
+}
+
+// StartResponse blocks until it is time to receive (or, if this is a server, send)
+// the request with the given id.
+func (p *Pipeline) StartResponse(id uint) {
+ p.response.Start(id)
+}
+
+// EndResponse notifies p that the response with the given id has been received
+// (or, if this is a server, sent).
+func (p *Pipeline) EndResponse(id uint) {
+ p.response.End(id)
+}
+
+// A sequencer schedules a sequence of numbered events that must
+// happen in order, one after the other. The event numbering must start
+// at 0 and increment without skipping. The event number wraps around
+// safely as long as there are not 2^32 simultaneous events pending.
+type sequencer struct {
+ mu sync.Mutex
+ id uint
+ wait map[uint]chan uint
+}
+
+// Start waits until it is time for the event numbered id to begin.
+// That is, except for the first event, it waits until End(id-1) has
+// been called.
+func (s *sequencer) Start(id uint) {
+ s.mu.Lock()
+ if s.id == id {
+ s.mu.Unlock()
+ return
+ }
+ c := make(chan uint)
+ if s.wait == nil {
+ s.wait = make(map[uint]chan uint)
+ }
+ s.wait[id] = c
+ s.mu.Unlock()
+ <-c
+}
+
+// End notifies the sequencer that the event numbered id has completed,
+// allowing it to schedule the event numbered id+1. It is a run-time error
+// to call End with an id that is not the number of the active event.
+func (s *sequencer) End(id uint) {
+ s.mu.Lock()
+ if s.id != id {
+ panic("out of sync")
+ }
+ id++
+ s.id = id
+ if s.wait == nil {
+ s.wait = make(map[uint]chan uint)
+ }
+ c, ok := s.wait[id]
+ if ok {
+ s.wait[id] = nil, false
+ }
+ s.mu.Unlock()
+ if ok {
+ c <- 1
+ }
+}
diff --git a/src/pkg/net/textproto/reader.go b/src/pkg/net/textproto/reader.go
new file mode 100644
index 000000000..c8e34b758
--- /dev/null
+++ b/src/pkg/net/textproto/reader.go
@@ -0,0 +1,492 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package textproto
+
+import (
+ "bufio"
+ "bytes"
+ "container/vector"
+ "io"
+ "io/ioutil"
+ "os"
+ "strconv"
+)
+
+// BUG(rsc): To let callers manage exposure to denial of service
+// attacks, Reader should allow them to set and reset a limit on
+// the number of bytes read from the connection.
+
+// A Reader implements convenience methods for reading requests
+// or responses from a text protocol network connection.
+type Reader struct {
+ R *bufio.Reader
+ dot *dotReader
+}
+
+// NewReader returns a new Reader reading from r.
+func NewReader(r *bufio.Reader) *Reader {
+ return &Reader{R: r}
+}
+
+// ReadLine reads a single line from r,
+// eliding the final \n or \r\n from the returned string.
+func (r *Reader) ReadLine() (string, os.Error) {
+ line, err := r.ReadLineBytes()
+ return string(line), err
+}
+
+// ReadLineBytes is like ReadLine but returns a []byte instead of a string.
+func (r *Reader) ReadLineBytes() ([]byte, os.Error) {
+ r.closeDot()
+ line, err := r.R.ReadBytes('\n')
+ n := len(line)
+ if n > 0 && line[n-1] == '\n' {
+ n--
+ if n > 0 && line[n-1] == '\r' {
+ n--
+ }
+ }
+ return line[0:n], err
+}
+
+// ReadContinuedLine reads a possibly continued line from r,
+// eliding the final trailing ASCII white space.
+// Lines after the first are considered continuations if they
+// begin with a space or tab character. In the returned data,
+// continuation lines are separated from the previous line
+// only by a single space: the newline and leading white space
+// are removed.
+//
+// For example, consider this input:
+//
+// Line 1
+// continued...
+// Line 2
+//
+// The first call to ReadContinuedLine will return "Line 1 continued..."
+// and the second will return "Line 2".
+//
+// A line consisting of only white space is never continued.
+//
+func (r *Reader) ReadContinuedLine() (string, os.Error) {
+ line, err := r.ReadContinuedLineBytes()
+ return string(line), err
+}
+
+// trim returns s with leading and trailing spaces and tabs removed.
+// It does not assume Unicode or UTF-8.
+func trim(s []byte) []byte {
+ i := 0
+ for i < len(s) && (s[i] == ' ' || s[i] == '\t') {
+ i++
+ }
+ n := len(s)
+ for n > i && (s[n-1] == ' ' || s[n-1] == '\t') {
+ n--
+ }
+ return s[i:n]
+}
+
+// ReadContinuedLineBytes is like ReadContinuedLine but
+// returns a []byte instead of a string.
+func (r *Reader) ReadContinuedLineBytes() ([]byte, os.Error) {
+ // Read the first line.
+ line, err := r.ReadLineBytes()
+ if err != nil {
+ return line, err
+ }
+ if len(line) == 0 { // blank line - no continuation
+ return line, nil
+ }
+ line = trim(line)
+
+ // Look for a continuation line.
+ c, err := r.R.ReadByte()
+ if err != nil {
+ // Delay err until we read the byte next time.
+ return line, nil
+ }
+ if c != ' ' && c != '\t' {
+ // Not a continuation.
+ r.R.UnreadByte()
+ return line, nil
+ }
+
+ // Read continuation lines.
+ for {
+ // Consume leading spaces; one already gone.
+ for {
+ c, err = r.R.ReadByte()
+ if err != nil {
+ break
+ }
+ if c != ' ' && c != '\t' {
+ r.R.UnreadByte()
+ break
+ }
+ }
+ var cont []byte
+ cont, err = r.ReadLineBytes()
+ cont = trim(cont)
+ line = append(line, ' ')
+ line = append(line, cont...)
+ if err != nil {
+ break
+ }
+
+ // Check for leading space on next line.
+ if c, err = r.R.ReadByte(); err != nil {
+ break
+ }
+ if c != ' ' && c != '\t' {
+ r.R.UnreadByte()
+ break
+ }
+ }
+
+ // Delay error until next call.
+ if len(line) > 0 {
+ err = nil
+ }
+ return line, err
+}
+
+func (r *Reader) readCodeLine(expectCode int) (code int, continued bool, message string, err os.Error) {
+ line, err := r.ReadLine()
+ if err != nil {
+ return
+ }
+ if len(line) < 4 || line[3] != ' ' && line[3] != '-' {
+ err = ProtocolError("short response: " + line)
+ return
+ }
+ continued = line[3] == '-'
+ code, err = strconv.Atoi(line[0:3])
+ if err != nil || code < 100 {
+ err = ProtocolError("invalid response code: " + line)
+ return
+ }
+ message = line[4:]
+ if 1 <= expectCode && expectCode < 10 && code/100 != expectCode ||
+ 10 <= expectCode && expectCode < 100 && code/10 != expectCode ||
+ 100 <= expectCode && expectCode < 1000 && code != expectCode {
+ err = &Error{code, message}
+ }
+ return
+}
+
+// ReadCodeLine reads a response code line of the form
+// code message
+// where code is a 3-digit status code and the message
+// extends to the rest of the line. An example of such a line is:
+// 220 plan9.bell-labs.com ESMTP
+//
+// If the prefix of the status does not match the digits in expectCode,
+// ReadCodeLine returns with err set to &Error{code, message}.
+// For example, if expectCode is 31, an error will be returned if
+// the status is not in the range [310,319].
+//
+// If the response is multi-line, ReadCodeLine returns an error.
+//
+// An expectCode <= 0 disables the check of the status code.
+//
+func (r *Reader) ReadCodeLine(expectCode int) (code int, message string, err os.Error) {
+ code, continued, message, err := r.readCodeLine(expectCode)
+ if err == nil && continued {
+ err = ProtocolError("unexpected multi-line response: " + message)
+ }
+ return
+}
+
+// ReadResponse reads a multi-line response of the form
+// code-message line 1
+// code-message line 2
+// ...
+// code message line n
+// where code is a 3-digit status code. Each line should have the same code.
+// The response is terminated by a line that uses a space between the code and
+// the message line rather than a dash. Each line in message is separated by
+// a newline (\n).
+//
+// If the prefix of the status does not match the digits in expectCode,
+// ReadResponse returns with err set to &Error{code, message}.
+// For example, if expectCode is 31, an error will be returned if
+// the status is not in the range [310,319].
+//
+// An expectCode <= 0 disables the check of the status code.
+//
+func (r *Reader) ReadResponse(expectCode int) (code int, message string, err os.Error) {
+ code, continued, message, err := r.readCodeLine(expectCode)
+ for err == nil && continued {
+ var code2 int
+ var moreMessage string
+ code2, continued, moreMessage, err = r.readCodeLine(expectCode)
+ if code != code2 {
+ err = ProtocolError("status code mismatch: " + strconv.Itoa(code) + ", " + strconv.Itoa(code2))
+ }
+ message += "\n" + moreMessage
+ }
+ return
+}
+
+// DotReader returns a new Reader that satisfies Reads using the
+// decoded text of a dot-encoded block read from r.
+// The returned Reader is only valid until the next call
+// to a method on r.
+//
+// Dot encoding is a common framing used for data blocks
+// in text protcols like SMTP. The data consists of a sequence
+// of lines, each of which ends in "\r\n". The sequence itself
+// ends at a line containing just a dot: ".\r\n". Lines beginning
+// with a dot are escaped with an additional dot to avoid
+// looking like the end of the sequence.
+//
+// The decoded form returned by the Reader's Read method
+// rewrites the "\r\n" line endings into the simpler "\n",
+// removes leading dot escapes if present, and stops with error os.EOF
+// after consuming (and discarding) the end-of-sequence line.
+func (r *Reader) DotReader() io.Reader {
+ r.closeDot()
+ r.dot = &dotReader{r: r}
+ return r.dot
+}
+
+type dotReader struct {
+ r *Reader
+ state int
+}
+
+// Read satisfies reads by decoding dot-encoded data read from d.r.
+func (d *dotReader) Read(b []byte) (n int, err os.Error) {
+ // Run data through a simple state machine to
+ // elide leading dots, rewrite trailing \r\n into \n,
+ // and detect ending .\r\n line.
+ const (
+ stateBeginLine = iota // beginning of line; initial state; must be zero
+ stateDot // read . at beginning of line
+ stateDotCR // read .\r at beginning of line
+ stateCR // read \r (possibly at end of line)
+ stateData // reading data in middle of line
+ stateEOF // reached .\r\n end marker line
+ )
+ br := d.r.R
+ for n < len(b) && d.state != stateEOF {
+ var c byte
+ c, err = br.ReadByte()
+ if err != nil {
+ if err == os.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ break
+ }
+ switch d.state {
+ case stateBeginLine:
+ if c == '.' {
+ d.state = stateDot
+ continue
+ }
+ if c == '\r' {
+ d.state = stateCR
+ continue
+ }
+ d.state = stateData
+
+ case stateDot:
+ if c == '\r' {
+ d.state = stateDotCR
+ continue
+ }
+ if c == '\n' {
+ d.state = stateEOF
+ continue
+ }
+ d.state = stateData
+
+ case stateDotCR:
+ if c == '\n' {
+ d.state = stateEOF
+ continue
+ }
+ // Not part of .\r\n.
+ // Consume leading dot and emit saved \r.
+ br.UnreadByte()
+ c = '\r'
+ d.state = stateData
+
+ case stateCR:
+ if c == '\n' {
+ d.state = stateBeginLine
+ break
+ }
+ // Not part of \r\n. Emit saved \r
+ br.UnreadByte()
+ c = '\r'
+ d.state = stateData
+
+ case stateData:
+ if c == '\r' {
+ d.state = stateCR
+ continue
+ }
+ if c == '\n' {
+ d.state = stateBeginLine
+ }
+ }
+ b[n] = c
+ n++
+ }
+ if err == nil && d.state == stateEOF {
+ err = os.EOF
+ }
+ if err != nil && d.r.dot == d {
+ d.r.dot = nil
+ }
+ return
+}
+
+// closeDot drains the current DotReader if any,
+// making sure that it reads until the ending dot line.
+func (r *Reader) closeDot() {
+ if r.dot == nil {
+ return
+ }
+ buf := make([]byte, 128)
+ for r.dot != nil {
+ // When Read reaches EOF or an error,
+ // it will set r.dot == nil.
+ r.dot.Read(buf)
+ }
+}
+
+// ReadDotBytes reads a dot-encoding and returns the decoded data.
+//
+// See the documentation for the DotReader method for details about dot-encoding.
+func (r *Reader) ReadDotBytes() ([]byte, os.Error) {
+ return ioutil.ReadAll(r.DotReader())
+}
+
+// ReadDotLines reads a dot-encoding and returns a slice
+// containing the decoded lines, with the final \r\n or \n elided from each.
+//
+// See the documentation for the DotReader method for details about dot-encoding.
+func (r *Reader) ReadDotLines() ([]string, os.Error) {
+ // We could use ReadDotBytes and then Split it,
+ // but reading a line at a time avoids needing a
+ // large contiguous block of memory and is simpler.
+ var v vector.StringVector
+ var err os.Error
+ for {
+ var line string
+ line, err = r.ReadLine()
+ if err != nil {
+ if err == os.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ break
+ }
+
+ // Dot by itself marks end; otherwise cut one dot.
+ if len(line) > 0 && line[0] == '.' {
+ if len(line) == 1 {
+ break
+ }
+ line = line[1:]
+ }
+ v.Push(line)
+ }
+ return v, err
+}
+
+// ReadMIMEHeader reads a MIME-style header from r.
+// The header is a sequence of possibly continued Key: Value lines
+// ending in a blank line.
+// The returned map m maps CanonicalHeaderKey(key) to a
+// sequence of values in the same order encountered in the input.
+//
+// For example, consider this input:
+//
+// My-Key: Value 1
+// Long-Key: Even
+// Longer Value
+// My-Key: Value 2
+//
+// Given that input, ReadMIMEHeader returns the map:
+//
+// map[string][]string{
+// "My-Key": []string{"Value 1", "Value 2"},
+// "Long-Key": []string{"Even Longer Value"},
+// }
+//
+func (r *Reader) ReadMIMEHeader() (map[string][]string, os.Error) {
+ m := make(map[string][]string)
+ for {
+ kv, err := r.ReadContinuedLineBytes()
+ if len(kv) == 0 {
+ return m, err
+ }
+
+ // Key ends at first colon; must not have spaces.
+ i := bytes.IndexByte(kv, ':')
+ if i < 0 || bytes.IndexByte(kv[0:i], ' ') >= 0 {
+ return m, ProtocolError("malformed MIME header line: " + string(kv))
+ }
+ key := CanonicalHeaderKey(string(kv[0:i]))
+
+ // Skip initial spaces in value.
+ i++ // skip colon
+ for i < len(kv) && (kv[i] == ' ' || kv[i] == '\t') {
+ i++
+ }
+ value := string(kv[i:])
+
+ v := vector.StringVector(m[key])
+ v.Push(value)
+ m[key] = v
+
+ if err != nil {
+ return m, err
+ }
+ }
+ panic("unreachable")
+}
+
+// CanonicalHeaderKey returns the canonical format of the
+// MIME header key s. The canonicalization converts the first
+// letter and any letter following a hyphen to upper case;
+// the rest are converted to lowercase. For example, the
+// canonical key for "accept-encoding" is "Accept-Encoding".
+func CanonicalHeaderKey(s string) string {
+ // Quick check for canonical encoding.
+ needUpper := true
+ for i := 0; i < len(s); i++ {
+ c := s[i]
+ if needUpper && 'a' <= c && c <= 'z' {
+ goto MustRewrite
+ }
+ if !needUpper && 'A' <= c && c <= 'Z' {
+ goto MustRewrite
+ }
+ needUpper = c == '-'
+ }
+ return s
+
+MustRewrite:
+ // Canonicalize: first letter upper case
+ // and upper case after each dash.
+ // (Host, User-Agent, If-Modified-Since).
+ // MIME headers are ASCII only, so no Unicode issues.
+ a := []byte(s)
+ upper := true
+ for i, v := range a {
+ if upper && 'a' <= v && v <= 'z' {
+ a[i] = v + 'A' - 'a'
+ }
+ if !upper && 'A' <= v && v <= 'Z' {
+ a[i] = v + 'a' - 'A'
+ }
+ upper = v == '-'
+ }
+ return string(a)
+}
diff --git a/src/pkg/net/textproto/reader_test.go b/src/pkg/net/textproto/reader_test.go
new file mode 100644
index 000000000..2cecbc75f
--- /dev/null
+++ b/src/pkg/net/textproto/reader_test.go
@@ -0,0 +1,140 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package textproto
+
+import (
+ "bufio"
+ "io"
+ "os"
+ "reflect"
+ "strings"
+ "testing"
+)
+
+type canonicalHeaderKeyTest struct {
+ in, out string
+}
+
+var canonicalHeaderKeyTests = []canonicalHeaderKeyTest{
+ {"a-b-c", "A-B-C"},
+ {"a-1-c", "A-1-C"},
+ {"User-Agent", "User-Agent"},
+ {"uSER-aGENT", "User-Agent"},
+ {"user-agent", "User-Agent"},
+ {"USER-AGENT", "User-Agent"},
+}
+
+func TestCanonicalHeaderKey(t *testing.T) {
+ for _, tt := range canonicalHeaderKeyTests {
+ if s := CanonicalHeaderKey(tt.in); s != tt.out {
+ t.Errorf("CanonicalHeaderKey(%q) = %q, want %q", tt.in, s, tt.out)
+ }
+ }
+}
+
+func reader(s string) *Reader {
+ return NewReader(bufio.NewReader(strings.NewReader(s)))
+}
+
+func TestReadLine(t *testing.T) {
+ r := reader("line1\nline2\n")
+ s, err := r.ReadLine()
+ if s != "line1" || err != nil {
+ t.Fatalf("Line 1: %s, %v", s, err)
+ }
+ s, err = r.ReadLine()
+ if s != "line2" || err != nil {
+ t.Fatalf("Line 2: %s, %v", s, err)
+ }
+ s, err = r.ReadLine()
+ if s != "" || err != os.EOF {
+ t.Fatalf("EOF: %s, %v", s, err)
+ }
+}
+
+func TestReadContinuedLine(t *testing.T) {
+ r := reader("line1\nline\n 2\nline3\n")
+ s, err := r.ReadContinuedLine()
+ if s != "line1" || err != nil {
+ t.Fatalf("Line 1: %s, %v", s, err)
+ }
+ s, err = r.ReadContinuedLine()
+ if s != "line 2" || err != nil {
+ t.Fatalf("Line 2: %s, %v", s, err)
+ }
+ s, err = r.ReadContinuedLine()
+ if s != "line3" || err != nil {
+ t.Fatalf("Line 3: %s, %v", s, err)
+ }
+ s, err = r.ReadContinuedLine()
+ if s != "" || err != os.EOF {
+ t.Fatalf("EOF: %s, %v", s, err)
+ }
+}
+
+func TestReadCodeLine(t *testing.T) {
+ r := reader("123 hi\n234 bye\n345 no way\n")
+ code, msg, err := r.ReadCodeLine(0)
+ if code != 123 || msg != "hi" || err != nil {
+ t.Fatalf("Line 1: %d, %s, %v", code, msg, err)
+ }
+ code, msg, err = r.ReadCodeLine(23)
+ if code != 234 || msg != "bye" || err != nil {
+ t.Fatalf("Line 2: %d, %s, %v", code, msg, err)
+ }
+ code, msg, err = r.ReadCodeLine(346)
+ if code != 345 || msg != "no way" || err == nil {
+ t.Fatalf("Line 3: %d, %s, %v", code, msg, err)
+ }
+ if e, ok := err.(*Error); !ok || e.Code != code || e.Msg != msg {
+ t.Fatalf("Line 3: wrong error %v\n", err)
+ }
+ code, msg, err = r.ReadCodeLine(1)
+ if code != 0 || msg != "" || err != os.EOF {
+ t.Fatalf("EOF: %d, %s, %v", code, msg, err)
+ }
+}
+
+func TestReadDotLines(t *testing.T) {
+ r := reader("dotlines\r\n.foo\r\n..bar\n...baz\nquux\r\n\r\n.\r\nanother\n")
+ s, err := r.ReadDotLines()
+ want := []string{"dotlines", "foo", ".bar", "..baz", "quux", ""}
+ if !reflect.DeepEqual(s, want) || err != nil {
+ t.Fatalf("ReadDotLines: %v, %v", s, err)
+ }
+
+ s, err = r.ReadDotLines()
+ want = []string{"another"}
+ if !reflect.DeepEqual(s, want) || err != io.ErrUnexpectedEOF {
+ t.Fatalf("ReadDotLines2: %v, %v", s, err)
+ }
+}
+
+func TestReadDotBytes(t *testing.T) {
+ r := reader("dotlines\r\n.foo\r\n..bar\n...baz\nquux\r\n\r\n.\r\nanot.her\r\n")
+ b, err := r.ReadDotBytes()
+ want := []byte("dotlines\nfoo\n.bar\n..baz\nquux\n\n")
+ if !reflect.DeepEqual(b, want) || err != nil {
+ t.Fatalf("ReadDotBytes: %q, %v", b, err)
+ }
+
+ b, err = r.ReadDotBytes()
+ want = []byte("anot.her\n")
+ if !reflect.DeepEqual(b, want) || err != io.ErrUnexpectedEOF {
+ t.Fatalf("ReadDotBytes2: %q, %v", b, err)
+ }
+}
+
+func TestReadMIMEHeader(t *testing.T) {
+ r := reader("my-key: Value 1 \r\nLong-key: Even \n Longer Value\r\nmy-Key: Value 2\r\n\n")
+ m, err := r.ReadMIMEHeader()
+ want := map[string][]string{
+ "My-Key": {"Value 1", "Value 2"},
+ "Long-Key": {"Even Longer Value"},
+ }
+ if !reflect.DeepEqual(m, want) || err != nil {
+ t.Fatalf("ReadMIMEHeader: %v, %v; want %v", m, err, want)
+ }
+}
diff --git a/src/pkg/net/textproto/textproto.go b/src/pkg/net/textproto/textproto.go
new file mode 100644
index 000000000..f62009c52
--- /dev/null
+++ b/src/pkg/net/textproto/textproto.go
@@ -0,0 +1,122 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The textproto package implements generic support for
+// text-based request/response protocols in the style of
+// HTTP, NNTP, and SMTP.
+//
+// The package provides:
+//
+// Error, which represents a numeric error response from
+// a server.
+//
+// Pipeline, to manage pipelined requests and responses
+// in a client.
+//
+// Reader, to read numeric response code lines,
+// key: value headers, lines wrapped with leading spaces
+// on continuation lines, and whole text blocks ending
+// with a dot on a line by itself.
+//
+// Writer, to write dot-encoded text blocks.
+//
+package textproto
+
+import (
+ "bufio"
+ "fmt"
+ "io"
+ "net"
+ "os"
+)
+
+// An Error represents a numeric error response from a server.
+type Error struct {
+ Code int
+ Msg string
+}
+
+func (e *Error) String() string {
+ return fmt.Sprintf("%03d %s", e.Code, e.Msg)
+}
+
+// A ProtocolError describes a protocol violation such
+// as an invalid response or a hung-up connection.
+type ProtocolError string
+
+func (p ProtocolError) String() string {
+ return string(p)
+}
+
+// A Conn represents a textual network protocol connection.
+// It consists of a Reader and Writer to manage I/O
+// and a Pipeline to sequence concurrent requests on the connection.
+// These embedded types carry methods with them;
+// see the documentation of those types for details.
+type Conn struct {
+ Reader
+ Writer
+ Pipeline
+ conn io.ReadWriteCloser
+}
+
+// NewConn returns a new Conn using conn for I/O.
+func NewConn(conn io.ReadWriteCloser) *Conn {
+ return &Conn{
+ Reader: Reader{R: bufio.NewReader(conn)},
+ Writer: Writer{W: bufio.NewWriter(conn)},
+ conn: conn,
+ }
+}
+
+// Close closes the connection.
+func (c *Conn) Close() os.Error {
+ return c.conn.Close()
+}
+
+// Dial connects to the given address on the given network using net.Dial
+// and then returns a new Conn for the connection.
+func Dial(network, addr string) (*Conn, os.Error) {
+ c, err := net.Dial(network, "", addr)
+ if err != nil {
+ return nil, err
+ }
+ return NewConn(c), nil
+}
+
+// Cmd is a convenience method that sends a command after
+// waiting its turn in the pipeline. The command text is the
+// result of formatting format with args and appending \r\n.
+// Cmd returns the id of the command, for use with StartResponse and EndResponse.
+//
+// For example, a client might run a HELP command that returns a dot-body
+// by using:
+//
+// id, err := c.Cmd("HELP")
+// if err != nil {
+// return nil, err
+// }
+//
+// c.StartResponse(id)
+// defer c.EndResponse(id)
+//
+// if _, _, err = c.ReadCodeLine(110); err != nil {
+// return nil, err
+// }
+// text, err := c.ReadDotAll()
+// if err != nil {
+// return nil, err
+// }
+// return c.ReadCodeLine(250)
+//
+func (c *Conn) Cmd(format string, args ...interface{}) (id uint, err os.Error) {
+ id = c.Next()
+ c.StartRequest(id)
+ err = c.PrintfLine(format, args...)
+ c.EndRequest(id)
+ if err != nil {
+ return 0, err
+ }
+ return id, nil
+}
diff --git a/src/pkg/net/textproto/writer.go b/src/pkg/net/textproto/writer.go
new file mode 100644
index 000000000..4e705f6c3
--- /dev/null
+++ b/src/pkg/net/textproto/writer.go
@@ -0,0 +1,119 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package textproto
+
+import (
+ "bufio"
+ "fmt"
+ "io"
+ "os"
+)
+
+// A Writer implements convenience methods for writing
+// requests or responses to a text protocol network connection.
+type Writer struct {
+ W *bufio.Writer
+ dot *dotWriter
+}
+
+// NewWriter returns a new Writer writing to w.
+func NewWriter(w *bufio.Writer) *Writer {
+ return &Writer{W: w}
+}
+
+var crnl = []byte{'\r', '\n'}
+var dotcrnl = []byte{'.', '\r', '\n'}
+
+// PrintfLine writes the formatted output followed by \r\n.
+func (w *Writer) PrintfLine(format string, args ...interface{}) os.Error {
+ w.closeDot()
+ fmt.Fprintf(w.W, format, args...)
+ w.W.Write(crnl)
+ return w.W.Flush()
+}
+
+// DotWriter returns a writer that can be used to write a dot-encoding to w.
+// It takes care of inserting leading dots when necessary,
+// translating line-ending \n into \r\n, and adding the final .\r\n line
+// when the DotWriter is closed. The caller should close the
+// DotWriter before the next call to a method on w.
+//
+// See the documentation for Reader's DotReader method for details about dot-encoding.
+func (w *Writer) DotWriter() io.WriteCloser {
+ w.closeDot()
+ w.dot = &dotWriter{w: w}
+ return w.dot
+}
+
+func (w *Writer) closeDot() {
+ if w.dot != nil {
+ w.dot.Close() // sets w.dot = nil
+ }
+}
+
+type dotWriter struct {
+ w *Writer
+ state int
+}
+
+const (
+ wstateBeginLine = iota // beginning of line; initial state; must be zero
+ wstateCR // wrote \r (possibly at end of line)
+ wstateData // writing data in middle of line
+)
+
+func (d *dotWriter) Write(b []byte) (n int, err os.Error) {
+ bw := d.w.W
+ for n < len(b) {
+ c := b[n]
+ switch d.state {
+ case wstateBeginLine:
+ d.state = wstateData
+ if c == '.' {
+ // escape leading dot
+ bw.WriteByte('.')
+ }
+ fallthrough
+
+ case wstateData:
+ if c == '\r' {
+ d.state = wstateCR
+ }
+ if c == '\n' {
+ bw.WriteByte('\r')
+ d.state = wstateBeginLine
+ }
+
+ case wstateCR:
+ d.state = wstateData
+ if c == '\n' {
+ d.state = wstateBeginLine
+ }
+ }
+ if err = bw.WriteByte(c); err != nil {
+ break
+ }
+ n++
+ }
+ return
+}
+
+func (d *dotWriter) Close() os.Error {
+ if d.w.dot == d {
+ d.w.dot = nil
+ }
+ bw := d.w.W
+ switch d.state {
+ default:
+ bw.WriteByte('\r')
+ fallthrough
+ case wstateCR:
+ bw.WriteByte('\n')
+ fallthrough
+ case wstateBeginLine:
+ bw.Write(dotcrnl)
+ }
+ return bw.Flush()
+}
diff --git a/src/pkg/net/textproto/writer_test.go b/src/pkg/net/textproto/writer_test.go
new file mode 100644
index 000000000..e03ab5e15
--- /dev/null
+++ b/src/pkg/net/textproto/writer_test.go
@@ -0,0 +1,35 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package textproto
+
+import (
+ "bufio"
+ "bytes"
+ "testing"
+)
+
+func TestPrintfLine(t *testing.T) {
+ var buf bytes.Buffer
+ w := NewWriter(bufio.NewWriter(&buf))
+ err := w.PrintfLine("foo %d", 123)
+ if s := buf.String(); s != "foo 123\r\n" || err != nil {
+ t.Fatalf("s=%q; err=%s", s, err)
+ }
+}
+
+func TestDotWriter(t *testing.T) {
+ var buf bytes.Buffer
+ w := NewWriter(bufio.NewWriter(&buf))
+ d := w.DotWriter()
+ n, err := d.Write([]byte("abc\n.def\n..ghi\n.jkl\n."))
+ if n != 21 || err != nil {
+ t.Fatalf("Write: %d, %s", n, err)
+ }
+ d.Close()
+ want := "abc\r\n..def\r\n...ghi\r\n..jkl\r\n..\r\n.\r\n"
+ if s := buf.String(); s != want {
+ t.Fatalf("wrote %q", s)
+ }
+}
diff --git a/src/pkg/net/timeout_test.go b/src/pkg/net/timeout_test.go
index 3594c0a35..092781685 100644
--- a/src/pkg/net/timeout_test.go
+++ b/src/pkg/net/timeout_test.go
@@ -8,9 +8,14 @@ import (
"os"
"testing"
"time"
+ "runtime"
)
func testTimeout(t *testing.T, network, addr string, readFrom bool) {
+ // Timeouts are not implemented on windows.
+ if runtime.GOOS == "windows" {
+ return
+ }
fd, err := Dial(network, "", addr)
if err != nil {
t.Errorf("dial %s %s failed: %v", network, addr, err)
diff --git a/src/pkg/net/udpsock.go b/src/pkg/net/udpsock.go
index 6ea0f2753..0270954c1 100644
--- a/src/pkg/net/udpsock.go
+++ b/src/pkg/net/udpsock.go
@@ -30,7 +30,12 @@ type UDPAddr struct {
// Network returns the address's network name, "udp".
func (a *UDPAddr) Network() string { return "udp" }
-func (a *UDPAddr) String() string { return joinHostPort(a.IP.String(), itoa(a.Port)) }
+func (a *UDPAddr) String() string {
+ if a == nil {
+ return "<nil>"
+ }
+ return joinHostPort(a.IP.String(), itoa(a.Port))
+}
func (a *UDPAddr) family() int {
if a == nil || len(a.IP) <= 4 {
@@ -269,3 +274,8 @@ func (c *UDPConn) BindToDevice(device string) os.Error {
defer c.fd.decref()
return os.NewSyscallError("setsockopt", syscall.BindToDevice(c.fd.sysfd, device))
}
+
+// File returns a copy of the underlying os.File, set to blocking mode.
+// It is the caller's responsibility to close f when finished.
+// Closing c does not affect f, and closing f does not affect c.
+func (c *UDPConn) File() (f *os.File, err os.Error) { return c.fd.dup() }
diff --git a/src/pkg/net/unixsock.go b/src/pkg/net/unixsock.go
index 93535130a..2521969eb 100644
--- a/src/pkg/net/unixsock.go
+++ b/src/pkg/net/unixsock.go
@@ -277,6 +277,37 @@ func (c *UnixConn) WriteTo(b []byte, addr Addr) (n int, err os.Error) {
return c.WriteToUnix(b, a)
}
+func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAddr, err os.Error) {
+ if !c.ok() {
+ return 0, 0, 0, nil, os.EINVAL
+ }
+ n, oobn, flags, sa, err := c.fd.ReadMsg(b, oob)
+ switch sa := sa.(type) {
+ case *syscall.SockaddrUnix:
+ addr = &UnixAddr{sa.Name, c.fd.proto == syscall.SOCK_DGRAM}
+ }
+ return
+}
+
+func (c *UnixConn) WriteMsgUnix(b, oob []byte, addr *UnixAddr) (n, oobn int, err os.Error) {
+ if !c.ok() {
+ return 0, 0, os.EINVAL
+ }
+ if addr != nil {
+ if addr.Datagram != (c.fd.proto == syscall.SOCK_DGRAM) {
+ return 0, 0, os.EAFNOSUPPORT
+ }
+ sa := &syscall.SockaddrUnix{Name: addr.Name}
+ return c.fd.WriteMsg(b, oob, sa)
+ }
+ return c.fd.WriteMsg(b, oob, nil)
+}
+
+// File returns a copy of the underlying os.File, set to blocking mode.
+// It is the caller's responsibility to close f when finished.
+// Closing c does not affect f, and closing f does not affect c.
+func (c *UnixConn) File() (f *os.File, err os.Error) { return c.fd.dup() }
+
// DialUnix connects to the remote address raddr on the network net,
// which must be "unix" or "unixgram". If laddr is not nil, it is used
// as the local address for the connection.
@@ -311,7 +342,7 @@ func ListenUnix(net string, laddr *UnixAddr) (l *UnixListener, err os.Error) {
}
e1 := syscall.Listen(fd.sysfd, 8) // listenBacklog());
if e1 != 0 {
- syscall.Close(fd.sysfd)
+ closesocket(fd.sysfd)
return nil, &OpError{Op: "listen", Net: "unix", Addr: laddr, Error: os.Errno(e1)}
}
return &UnixListener{fd, laddr.Name}, nil
@@ -369,6 +400,11 @@ func (l *UnixListener) Close() os.Error {
// Addr returns the listener's network address.
func (l *UnixListener) Addr() Addr { return l.fd.laddr }
+// File returns a copy of the underlying os.File, set to blocking mode.
+// It is the caller's responsibility to close f when finished.
+// Closing c does not affect f, and closing f does not affect c.
+func (l *UnixListener) File() (f *os.File, err os.Error) { return l.fd.dup() }
+
// ListenUnixgram listens for incoming Unix datagram packets addressed to the
// local address laddr. The returned connection c's ReadFrom
// and WriteTo methods can be used to receive and send UDP
diff --git a/src/pkg/netchan/Makefile b/src/pkg/netchan/Makefile
index a8a5c6a3c..9b9fdcf59 100644
--- a/src/pkg/netchan/Makefile
+++ b/src/pkg/netchan/Makefile
@@ -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 ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=netchan
GOFILES=\
diff --git a/src/pkg/netchan/common.go b/src/pkg/netchan/common.go
index 624397ef4..bde3087a5 100644
--- a/src/pkg/netchan/common.go
+++ b/src/pkg/netchan/common.go
@@ -10,6 +10,7 @@ import (
"os"
"reflect"
"sync"
+ "time"
)
// The direction of a connection from the client's perspective.
@@ -20,31 +21,65 @@ const (
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
)
// 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 {
- name string
- payloadType int
+ Name string
+ 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. If count is zero, it means unlimited.
+// messages. If count is -1, it means unlimited.
type request struct {
- count int
- dir Dir
+ Count int64
+ Dir Dir
}
// Sent with a header to report an error.
type error struct {
- error string
+ Error string
+}
+
+// Used to unify management of acknowledgements for import and export.
+type unackedCounter interface {
+ unackedCount() int64
+ ack() int64
+ seq() int64
+}
+
+// A channel and its direction.
+type chanDir struct {
+ ch *reflect.ChanValue
+ dir Dir
+}
+
+// clientSet contains the objects and methods needed for tracking
+// clients of an exporter and draining outstanding messages.
+type clientSet struct {
+ mu sync.Mutex // protects access to channel and client maps
+ chans map[string]*chanDir
+ clients map[unackedCounter]bool
}
// Mutex-protected encoder and decoder pair.
@@ -76,13 +111,81 @@ func (ed *encDec) decode(value reflect.Value) os.Error {
// 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
+ hdr.PayloadType = payloadType
err := ed.enc.Encode(hdr)
if err == nil {
- err = ed.enc.Encode(payload)
- } else {
+ 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.chans {
+ if chDir.ch.Len() > 0 {
+ pending = true
+ }
+ }
+ // Any unacknowledged messages?
+ for client := range cs.clients {
+ n := client.unackedCount()
+ if n > 0 { // Check for > rather than != just to be safe.
+ pending = true
+ break
+ }
+ }
+ cs.mu.Unlock()
+ if !pending {
+ break
+ }
+ if timeout > 0 && time.Nanoseconds()-startTime >= timeout {
+ return os.ErrorString("timeout")
+ }
+ time.Sleep(100 * 1e6) // 100 milliseconds
+ }
+ return nil
+}
+
+// See the comment for Exporter.Sync.
+func (cs *clientSet) sync(timeout int64) os.Error {
+ startTime := time.Nanoseconds()
+ // seq remembers the clients and their seqNum at point of entry.
+ seq := make(map[unackedCounter]int64)
+ for client := range cs.clients {
+ seq[client] = client.seq()
+ }
+ for {
+ pending := false
+ cs.mu.Lock()
+ // Any unacknowledged messages? Look only at clients that existed
+ // when we started and are still in this client set.
+ for client := range seq {
+ if _, ok := cs.clients[client]; ok {
+ if client.ack() < seq[client] {
+ pending = true
+ break
+ }
+ }
+ }
+ cs.mu.Unlock()
+ if !pending {
+ break
+ }
+ if timeout > 0 && time.Nanoseconds()-startTime >= timeout {
+ return os.ErrorString("timeout")
+ }
+ time.Sleep(100 * 1e6) // 100 milliseconds
+ }
+ return nil
+}
diff --git a/src/pkg/netchan/export.go b/src/pkg/netchan/export.go
index a16714ba2..9ad388c18 100644
--- a/src/pkg/netchan/export.go
+++ b/src/pkg/netchan/export.go
@@ -19,7 +19,7 @@
*/
package netchan
-// BUG: can't use range clause to receive when using ImportNValues with N non-zero.
+// BUG: can't use range clause to receive when using ImportNValues to limit the count.
import (
"log"
@@ -31,73 +31,69 @@ import (
// Export
-// A channel and its associated information: a direction plus
-// a handy marshaling place for its data.
-type exportChan struct {
- ch *reflect.ChanValue
- dir Dir
+// expLog is a logging convenience function. The first argument must be a string.
+func expLog(args ...interface{}) {
+ args[0] = "netchan export: " + args[0].(string)
+ log.Print(args...)
}
// An Exporter allows a set of channels to be published on a single
// network port. A single machine may have multiple Exporters
// but they must use different ports.
type Exporter struct {
+ *clientSet
listener net.Listener
- chanLock sync.Mutex // protects access to channel map
- chans map[string]*exportChan
}
type expClient struct {
*encDec
- exp *Exporter
+ exp *Exporter
+ mu sync.Mutex // protects remaining fields
+ errored bool // client has been sent an error
+ seqNum int64 // sequences messages sent to client; has value of highest sent
+ ackNum int64 // highest sequence number acknowledged
+ seqLock sync.Mutex // guarantees messages are in sequence, only locked under mu
}
func newClient(exp *Exporter, conn net.Conn) *expClient {
client := new(expClient)
client.exp = exp
client.encDec = newEncDec(conn)
+ client.seqNum = 0
+ client.ackNum = 0
return client
}
-// Wait for incoming connections, start a new runner for each
-func (exp *Exporter) listen() {
- for {
- conn, err := exp.listener.Accept()
- if err != nil {
- log.Stderr("exporter.listen:", err)
- break
- }
- client := newClient(exp, conn)
- go client.run()
- }
-}
-
func (client *expClient) sendError(hdr *header, err string) {
error := &error{err}
- log.Stderr("export:", error.error)
+ 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) getChan(hdr *header, dir Dir) *exportChan {
+func (client *expClient) getChan(hdr *header, dir Dir) *chanDir {
exp := client.exp
- exp.chanLock.Lock()
- ech, ok := exp.chans[hdr.name]
- exp.chanLock.Unlock()
+ exp.mu.Lock()
+ ech, ok := exp.chans[hdr.Name]
+ exp.mu.Unlock()
if !ok {
- client.sendError(hdr, "no such channel: "+hdr.name)
+ client.sendError(hdr, "no such channel: "+hdr.Name)
return nil
}
if ech.dir != dir {
- client.sendError(hdr, "wrong direction for channel: "+hdr.name)
+ client.sendError(hdr, "wrong direction for channel: "+hdr.Name)
return nil
}
return ech
}
-// Manage 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.
+// The function run manages sends and receives for a single client. For each
+// (client Recv) request, this will launch a serveRecv goroutine to deliver
+// the data for that channel, while (client Send) requests are handled as
+// data arrives from the client.
func (client *expClient) run() {
hdr := new(header)
hdrValue := reflect.NewValue(hdr)
@@ -105,40 +101,58 @@ func (client *expClient) run() {
reqValue := reflect.NewValue(req)
error := new(error)
for {
+ *hdr = header{}
if err := client.decode(hdrValue); err != nil {
- log.Stderr("error decoding client header:", err)
- // TODO: tear down connection
- return
+ expLog("error decoding client header:", err)
+ break
}
- switch hdr.payloadType {
+ switch hdr.PayloadType {
case payRequest:
+ *req = request{}
if err := client.decode(reqValue); err != nil {
- log.Stderr("error decoding client request:", err)
- // TODO: tear down connection
- return
+ expLog("error decoding client request:", err)
+ break
}
- switch req.dir {
+ switch req.Dir {
case Recv:
- go client.serveRecv(*hdr, req.count)
+ go client.serveRecv(*hdr, req.Count)
case Send:
// Request to send is clear as a matter of protocol
// but not actually used by the implementation.
// The actual sends will have payload type payData.
// TODO: manage the count?
default:
- error.error = "export request: can't handle channel direction"
- log.Stderr(error.error, req.dir)
+ 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()
+ default:
+ log.Exit("netchan export: unknown payload type", hdr.PayloadType)
}
}
+ client.exp.delClient(client)
}
// Send all the data on a single channel to a client asking for a Recv.
// The header is passed by value to avoid issues of overwriting.
-func (client *expClient) serveRecv(hdr header, count int) {
+func (client *expClient) serveRecv(hdr header, count int64) {
ech := client.getChan(&hdr, Send)
if ech == nil {
return
@@ -146,16 +160,30 @@ func (client *expClient) serveRecv(hdr header, count int) {
for {
val := ech.ch.Recv()
if ech.ch.Closed() {
- client.sendError(&hdr, os.EOF.String())
+ if err := client.encode(&hdr, payClosed, nil); err != nil {
+ expLog("error encoding server closed message:", err)
+ }
break
}
- if err := client.encode(&hdr, payData, val.Interface()); err != nil {
- log.Stderr("error encoding client response:", err)
+ // 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
}
- if count > 0 {
- if count--; count == 0 {
+ // Negative count means run forever.
+ if count >= 0 {
+ if count--; count <= 0 {
break
}
}
@@ -172,11 +200,54 @@ func (client *expClient) serveSend(hdr header) {
// Create a new value for each received item.
val := reflect.MakeZero(ech.ch.Type().(*reflect.ChanType).Elem())
if err := client.decode(val); err != nil {
- log.Stderr("exporter value decode:", err)
+ expLog("value decode:", err)
return
}
ech.ch.Send(val)
- // TODO count
+}
+
+// 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) {
+ ech := client.getChan(&hdr, Recv)
+ if ech == nil {
+ return
+ }
+ ech.ch.Close()
+}
+
+func (client *expClient) unackedCount() int64 {
+ client.mu.Lock()
+ n := client.seqNum - client.ackNum
+ client.mu.Unlock()
+ return n
+}
+
+func (client *expClient) seq() int64 {
+ client.mu.Lock()
+ n := client.seqNum
+ client.mu.Unlock()
+ return n
+}
+
+func (client *expClient) ack() int64 {
+ client.mu.Lock()
+ n := client.seqNum
+ client.mu.Unlock()
+ return n
+}
+
+// Wait for incoming connections, start a new runner for each
+func (exp *Exporter) listen() {
+ for {
+ conn, err := exp.listener.Accept()
+ if err != nil {
+ expLog("listen:", err)
+ break
+ }
+ client := exp.addClient(conn)
+ go client.run()
+ }
}
// NewExporter creates a new Exporter to export channels
@@ -188,12 +259,53 @@ func NewExporter(network, localaddr string) (*Exporter, os.Error) {
}
e := &Exporter{
listener: listener,
- chans: make(map[string]*exportChan),
+ clientSet: &clientSet{
+ chans: make(map[string]*chanDir),
+ clients: make(map[unackedCounter]bool),
+ },
}
go e.listen()
return e, nil
}
+// addClient creates a new expClient and records its existence
+func (exp *Exporter) addClient(conn net.Conn) *expClient {
+ client := newClient(exp, conn)
+ exp.mu.Lock()
+ exp.clients[client] = true
+ exp.mu.Unlock()
+ return client
+}
+
+// delClient forgets the client existed
+func (exp *Exporter) delClient(client *expClient) {
+ exp.mu.Lock()
+ exp.clients[client] = false, false
+ exp.mu.Unlock()
+}
+
+// Drain waits until all messages sent from this exporter/importer, including
+// those not yet sent to any client and possibly including those sent while
+// Drain was executing, have been received by the importer. In short, it
+// waits until all the exporter's messages have been received by a client.
+// If the timeout (measured in nanoseconds) is positive and Drain takes
+// longer than that to complete, an error is returned.
+func (exp *Exporter) Drain(timeout int64) os.Error {
+ // This wrapper function is here so the method's comment will appear in godoc.
+ return exp.clientSet.drain(timeout)
+}
+
+// Sync waits until all clients of the exporter have received the messages
+// that were sent at the time Sync was invoked. Unlike Drain, it does not
+// wait for messages sent while it is running or messages that have not been
+// dispatched to any client. If the timeout (measured in nanoseconds) is
+// positive and Sync takes longer than that to complete, an error is
+// returned.
+func (exp *Exporter) Sync(timeout int64) os.Error {
+ // This wrapper function is here so the method's comment will appear in godoc.
+ return exp.clientSet.sync(timeout)
+}
+
// Addr returns the Exporter's local network address.
func (exp *Exporter) Addr() net.Addr { return exp.listener.Addr() }
@@ -229,12 +341,28 @@ func (exp *Exporter) Export(name string, chT interface{}, dir Dir) os.Error {
if err != nil {
return err
}
- exp.chanLock.Lock()
- defer exp.chanLock.Unlock()
+ exp.mu.Lock()
+ defer exp.mu.Unlock()
_, present := exp.chans[name]
if present {
return os.ErrorString("channel name already being exported:" + name)
}
- exp.chans[name] = &exportChan{ch, dir}
+ exp.chans[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.chans[name]
+ if ok {
+ exp.chans[name] = nil, false
+ }
+ exp.mu.Unlock()
+ if !ok {
+ return os.ErrorString("netchan export: hangup: no such channel: " + name)
+ }
+ chDir.ch.Close()
return nil
}
diff --git a/src/pkg/netchan/import.go b/src/pkg/netchan/import.go
index 244a83c5b..baae367a0 100644
--- a/src/pkg/netchan/import.go
+++ b/src/pkg/netchan/import.go
@@ -14,11 +14,10 @@ import (
// Import
-// A channel and its associated information: a template value and direction,
-// plus a handy marshaling place for its data.
-type importChan struct {
- ch *reflect.ChanValue
- dir Dir
+// 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
@@ -28,7 +27,8 @@ type Importer struct {
*encDec
conn net.Conn
chanLock sync.Mutex // protects access to channel map
- chans map[string]*importChan
+ chans map[string]*chanDir
+ errors chan os.Error
}
// NewImporter creates a new Importer object to import channels
@@ -43,7 +43,8 @@ func NewImporter(network, remoteaddr string) (*Importer, os.Error) {
imp := new(Importer)
imp.encDec = newEncDec(conn)
imp.conn = conn
- imp.chans = make(map[string]*importChan)
+ imp.chans = make(map[string]*chanDir)
+ imp.errors = make(chan os.Error, 10)
go imp.run()
return imp, nil
}
@@ -67,61 +68,92 @@ func (imp *Importer) run() {
// Loop on responses; requests are sent by ImportNValues()
hdr := new(header)
hdrValue := reflect.NewValue(hdr)
+ ackHdr := new(header)
err := new(error)
errValue := reflect.NewValue(err)
for {
+ *hdr = header{}
if e := imp.decode(hdrValue); e != nil {
- log.Stderr("importer header:", e)
+ impLog("header:", e)
imp.shutdown()
return
}
- switch hdr.payloadType {
+ switch hdr.PayloadType {
case payData:
// done lower in loop
case payError:
if e := imp.decode(errValue); e != nil {
- log.Stderr("importer error:", e)
+ impLog("error:", e)
return
}
- if err.error != "" {
- log.Stderr("importer response error:", err.error)
- imp.shutdown()
- return
+ if err.Error != "" {
+ impLog("response error:", err.Error)
+ if sent := imp.errors <- os.ErrorString(err.Error); !sent {
+ imp.shutdown()
+ return
+ }
+ continue // errors are not acknowledged.
}
+ case payClosed:
+ ich := imp.getChan(hdr.Name)
+ if ich != nil {
+ ich.ch.Close()
+ }
+ continue // closes are not acknowledged.
default:
- log.Stderr("unexpected payload type:", hdr.payloadType)
+ impLog("unexpected payload type:", hdr.PayloadType)
return
}
- imp.chanLock.Lock()
- ich, ok := imp.chans[hdr.name]
- imp.chanLock.Unlock()
- if !ok {
- log.Stderr("unknown name in request:", hdr.name)
- return
+ ich := imp.getChan(hdr.Name)
+ if ich == nil {
+ continue
}
if ich.dir != Recv {
- log.Stderr("cannot happen: receive from non-Recv channel")
+ impLog("cannot happen: receive from non-Recv channel")
return
}
+ // Acknowledge receipt
+ ackHdr.Name = hdr.Name
+ ackHdr.SeqNum = hdr.SeqNum
+ imp.encode(ackHdr, payAck, nil)
// Create a new value for each received item.
value := reflect.MakeZero(ich.ch.Type().(*reflect.ChanType).Elem())
if e := imp.decode(value); e != nil {
- log.Stderr("importer value decode:", e)
+ impLog("importer value decode:", e)
return
}
ich.ch.Send(value)
}
}
+func (imp *Importer) getChan(name string) *chanDir {
+ imp.chanLock.Lock()
+ ich := imp.chans[name]
+ imp.chanLock.Unlock()
+ if ich == nil {
+ impLog("unknown name in netchan request:", name)
+ 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 and specified direction.
-// It is equivalent to ImportNValues with a count of 0, meaning unbounded.
+// It is equivalent to ImportNValues with a count of -1, meaning unbounded.
func (imp *Importer) Import(name string, chT interface{}, dir Dir) os.Error {
- return imp.ImportNValues(name, chT, dir, 0)
+ return imp.ImportNValues(name, chT, dir, -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==0 implies an unbounded number of values. The channel to be bound to
+// n==-1 implies an unbounded number of values. 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
@@ -130,7 +162,7 @@ func (imp *Importer) Import(name string, chT interface{}, dir Dir) os.Error {
// imp, err := NewImporter("tcp", "netchanserver.mydomain.com:1234")
// if err != nil { log.Exit(err) }
// ch := make(chan myType)
-// err := imp.ImportNValues("name", ch, Recv, 1)
+// err = imp.ImportNValues("name", ch, Recv, 1)
// if err != nil { log.Exit(err) }
// fmt.Printf("%+v\n", <-ch)
func (imp *Importer) ImportNValues(name string, chT interface{}, dir Dir, n int) os.Error {
@@ -144,24 +176,26 @@ func (imp *Importer) ImportNValues(name string, chT interface{}, dir Dir, n int)
if present {
return os.ErrorString("channel name already being imported:" + name)
}
- imp.chans[name] = &importChan{ch, dir}
+ imp.chans[name] = &chanDir{ch, dir}
// Tell the other side about this channel.
- hdr := new(header)
- hdr.name = name
- hdr.payloadType = payRequest
- req := new(request)
- req.dir = dir
- req.count = n
- if err := imp.encode(hdr, payRequest, req); err != nil {
- log.Stderr("importer request encode:", err)
+ hdr := &header{Name: name}
+ req := &request{Count: int64(n), Dir: dir}
+ if err = imp.encode(hdr, payRequest, req); err != nil {
+ impLog("request encode:", err)
return err
}
if dir == Send {
go func() {
- for i := 0; n == 0 || i < n; i++ {
+ for i := 0; n == -1 || i < n; i++ {
val := ch.Recv()
- if err := imp.encode(hdr, payData, val.Interface()); err != nil {
- log.Stderr("error encoding client response:", err)
+ if ch.Closed() {
+ if err = imp.encode(hdr, payClosed, nil); err != nil {
+ impLog("error encoding client closed message:", err)
+ }
+ return
+ }
+ if err = imp.encode(hdr, payData, val.Interface()); err != nil {
+ impLog("error encoding client send:", err)
return
}
}
@@ -169,3 +203,19 @@ func (imp *Importer) ImportNValues(name string, chT interface{}, dir Dir, n int)
}
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()
+ chDir, ok := imp.chans[name]
+ if ok {
+ imp.chans[name] = nil, false
+ }
+ imp.chanLock.Unlock()
+ if !ok {
+ return os.ErrorString("netchan import: hangup: no such channel: " + name)
+ }
+ chDir.ch.Close()
+ return nil
+}
diff --git a/src/pkg/netchan/netchan_test.go b/src/pkg/netchan/netchan_test.go
index 6b5c67c3c..766c4c474 100644
--- a/src/pkg/netchan/netchan_test.go
+++ b/src/pkg/netchan/netchan_test.go
@@ -4,38 +4,67 @@
package netchan
-import "testing"
+import (
+ "strings"
+ "testing"
+ "time"
+)
const count = 10 // number of items in most tests
const closeCount = 5 // number of items when sender closes early
+const base = 23
+
func exportSend(exp *Exporter, n int, t *testing.T) {
ch := make(chan int)
err := exp.Export("exportedSend", ch, Send)
if err != nil {
t.Fatal("exportSend:", err)
}
- for i := 0; i < n; i++ {
- ch <- 23+i
- }
- close(ch)
+ go func() {
+ for i := 0; i < n; i++ {
+ ch <- base+i
+ }
+ close(ch)
+ }()
}
-func exportReceive(exp *Exporter, t *testing.T) {
+func exportReceive(exp *Exporter, t *testing.T, expDone chan bool) {
ch := make(chan int)
err := exp.Export("exportedRecv", ch, Recv)
+ expDone <- true
if err != nil {
t.Fatal("exportReceive:", err)
}
for i := 0; i < count; i++ {
v := <-ch
- if v != 45+i {
- t.Errorf("export Receive: bad value: expected 4%d; got %d", 45+i, v)
+ if closed(ch) {
+ if i != closeCount {
+ t.Errorf("exportReceive expected close at %d; got one at %d", closeCount, i)
+ }
+ break
+ }
+ if v != base+i {
+ t.Errorf("export Receive: bad value: expected %d+%d=%d; got %d", base, i, base+i, v)
}
}
}
-func importReceive(imp *Importer, t *testing.T) {
+func importSend(imp *Importer, n int, t *testing.T) {
+ ch := make(chan int)
+ err := imp.ImportNValues("exportedRecv", ch, Send, count)
+ if err != nil {
+ t.Fatal("importSend:", err)
+ }
+ go func() {
+ for i := 0; i < n; i++ {
+ ch <- base+i
+ }
+ close(ch)
+ }()
+}
+
+func importReceive(imp *Importer, t *testing.T, done chan bool) {
ch := make(chan int)
err := imp.ImportNValues("exportedSend", ch, Recv, count)
if err != nil {
@@ -45,28 +74,33 @@ func importReceive(imp *Importer, t *testing.T) {
v := <-ch
if closed(ch) {
if i != closeCount {
- t.Errorf("expected close at %d; got one at %d\n", closeCount, i)
+ t.Errorf("importReceive expected close at %d; got one at %d", closeCount, i)
}
break
}
if v != 23+i {
- t.Errorf("importReceive: bad value: expected %d; got %+d", 23+i, v)
+ t.Errorf("importReceive: bad value: expected %d+%d=%d; got %+d", base, i, base+i, v)
}
}
+ if done != nil {
+ done <- true
+ }
}
-func importSend(imp *Importer, t *testing.T) {
- ch := make(chan int)
- err := imp.ImportNValues("exportedRecv", ch, Send, count)
+func TestExportSendImportReceive(t *testing.T) {
+ exp, err := NewExporter("tcp", "127.0.0.1:0")
if err != nil {
- t.Fatal("importSend:", err)
+ t.Fatal("new exporter:", err)
}
- for i := 0; i < count; i++ {
- ch <- 45+i
+ imp, err := NewImporter("tcp", exp.Addr().String())
+ if err != nil {
+ t.Fatal("new importer:", err)
}
+ exportSend(exp, count, t)
+ importReceive(imp, t, nil)
}
-func TestExportSendImportReceive(t *testing.T) {
+func TestExportReceiveImportSend(t *testing.T) {
exp, err := NewExporter("tcp", "127.0.0.1:0")
if err != nil {
t.Fatal("new exporter:", err)
@@ -75,11 +109,18 @@ func TestExportSendImportReceive(t *testing.T) {
if err != nil {
t.Fatal("new importer:", err)
}
- go exportSend(exp, count, t)
- importReceive(imp, t)
+ expDone := make(chan bool)
+ done := make(chan bool)
+ go func() {
+ exportReceive(exp, t, expDone)
+ done <- true
+ }()
+ <-expDone
+ importSend(imp, count, t)
+ <-done
}
-func TestExportReceiveImportSend(t *testing.T) {
+func TestClosingExportSendImportReceive(t *testing.T) {
exp, err := NewExporter("tcp", "127.0.0.1:0")
if err != nil {
t.Fatal("new exporter:", err)
@@ -88,11 +129,92 @@ func TestExportReceiveImportSend(t *testing.T) {
if err != nil {
t.Fatal("new importer:", err)
}
- go importSend(imp, t)
- exportReceive(exp, t)
+ exportSend(exp, closeCount, t)
+ importReceive(imp, t, nil)
}
-func TestClosingExportSendImportReceive(t *testing.T) {
+func TestClosingImportSendExportReceive(t *testing.T) {
+ exp, err := NewExporter("tcp", "127.0.0.1:0")
+ if err != nil {
+ t.Fatal("new exporter:", err)
+ }
+ imp, err := NewImporter("tcp", exp.Addr().String())
+ if err != nil {
+ t.Fatal("new importer:", err)
+ }
+ expDone := make(chan bool)
+ done := make(chan bool)
+ go func() {
+ exportReceive(exp, t, expDone)
+ done <- true
+ }()
+ <-expDone
+ importSend(imp, closeCount, t)
+ <-done
+}
+
+func TestErrorForIllegalChannel(t *testing.T) {
+ exp, err := NewExporter("tcp", "127.0.0.1:0")
+ if err != nil {
+ t.Fatal("new exporter:", err)
+ }
+ imp, err := NewImporter("tcp", exp.Addr().String())
+ if err != nil {
+ t.Fatal("new importer:", err)
+ }
+ // Now export a channel.
+ ch := make(chan int, 1)
+ err = exp.Export("aChannel", ch, Send)
+ if err != nil {
+ t.Fatal("export:", err)
+ }
+ ch <- 1234
+ close(ch)
+ // Now try to import a different channel.
+ ch = make(chan int)
+ err = imp.Import("notAChannel", ch, Recv)
+ if err != nil {
+ t.Fatal("import:", err)
+ }
+ // Expect an error now. Start a timeout.
+ timeout := make(chan bool, 1) // buffered so closure will not hang around.
+ go func() {
+ time.Sleep(10e9) // very long, to give even really slow machines a chance.
+ timeout <- true
+ }()
+ select {
+ case err = <-imp.Errors():
+ if strings.Index(err.String(), "no such channel") < 0 {
+ t.Error("wrong error for nonexistent channel:", err)
+ }
+ case <-timeout:
+ t.Error("import of nonexistent channel did not receive an error")
+ }
+}
+
+// Not a great test but it does at least invoke Drain.
+func TestExportDrain(t *testing.T) {
+ exp, err := NewExporter("tcp", "127.0.0.1:0")
+ if err != nil {
+ t.Fatal("new exporter:", err)
+ }
+ imp, err := NewImporter("tcp", exp.Addr().String())
+ if err != nil {
+ t.Fatal("new importer:", err)
+ }
+ done := make(chan bool)
+ go func() {
+ exportSend(exp, closeCount, t)
+ done <- true
+ }()
+ <-done
+ go importReceive(imp, t, done)
+ exp.Drain(0)
+ <-done
+}
+
+// Not a great test but it does at least invoke Sync.
+func TestExportSync(t *testing.T) {
exp, err := NewExporter("tcp", "127.0.0.1:0")
if err != nil {
t.Fatal("new exporter:", err)
@@ -101,6 +223,161 @@ func TestClosingExportSendImportReceive(t *testing.T) {
if err != nil {
t.Fatal("new importer:", err)
}
- go exportSend(exp, closeCount, t)
- importReceive(imp, t)
+ done := make(chan bool)
+ exportSend(exp, closeCount, t)
+ go importReceive(imp, t, done)
+ exp.Sync(0)
+ <-done
+}
+
+// Test hanging up the send side of an export.
+// TODO: test hanging up the receive side of an export.
+func TestExportHangup(t *testing.T) {
+ exp, err := NewExporter("tcp", "127.0.0.1:0")
+ if err != nil {
+ t.Fatal("new exporter:", err)
+ }
+ imp, err := NewImporter("tcp", exp.Addr().String())
+ if err != nil {
+ t.Fatal("new importer:", err)
+ }
+ ech := make(chan int)
+ err = exp.Export("exportedSend", ech, Send)
+ if err != nil {
+ t.Fatal("export:", err)
+ }
+ // Prepare to receive two values. We'll actually deliver only one.
+ ich := make(chan int)
+ err = imp.ImportNValues("exportedSend", ich, Recv, 2)
+ if err != nil {
+ t.Fatal("import exportedSend:", err)
+ }
+ // Send one value, receive it.
+ const Value = 1234
+ ech <- Value
+ v := <-ich
+ if v != Value {
+ t.Fatal("expected", Value, "got", v)
+ }
+ // Now hang up the channel. Importer should see it close.
+ exp.Hangup("exportedSend")
+ v = <-ich
+ if !closed(ich) {
+ t.Fatal("expected channel to be closed; got value", v)
+ }
+}
+
+// Test hanging up the send side of an import.
+// TODO: test hanging up the receive side of an import.
+func TestImportHangup(t *testing.T) {
+ exp, err := NewExporter("tcp", "127.0.0.1:0")
+ if err != nil {
+ t.Fatal("new exporter:", err)
+ }
+ imp, err := NewImporter("tcp", exp.Addr().String())
+ if err != nil {
+ t.Fatal("new importer:", err)
+ }
+ ech := make(chan int)
+ err = exp.Export("exportedRecv", ech, Recv)
+ if err != nil {
+ t.Fatal("export:", err)
+ }
+ // Prepare to Send two values. We'll actually deliver only one.
+ ich := make(chan int)
+ err = imp.ImportNValues("exportedRecv", ich, Send, 2)
+ if err != nil {
+ t.Fatal("import exportedRecv:", err)
+ }
+ // Send one value, receive it.
+ const Value = 1234
+ ich <- Value
+ v := <-ech
+ if v != Value {
+ t.Fatal("expected", Value, "got", v)
+ }
+ // Now hang up the channel. Exporter should see it close.
+ imp.Hangup("exportedRecv")
+ v = <-ech
+ if !closed(ech) {
+ t.Fatal("expected channel to be closed; got value", v)
+ }
+}
+
+// This test cross-connects a pair of exporter/importer pairs.
+type value struct {
+ i int
+ source string
+}
+
+func TestCrossConnect(t *testing.T) {
+ e1, err := NewExporter("tcp", "127.0.0.1:0")
+ if err != nil {
+ t.Fatal("new exporter:", err)
+ }
+ i1, err := NewImporter("tcp", e1.Addr().String())
+ if err != nil {
+ t.Fatal("new importer:", err)
+ }
+
+ e2, err := NewExporter("tcp", "127.0.0.1:0")
+ if err != nil {
+ t.Fatal("new exporter:", err)
+ }
+ i2, err := NewImporter("tcp", e2.Addr().String())
+ if err != nil {
+ t.Fatal("new importer:", err)
+ }
+
+ go 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)
+ }
+
+ 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)
+ if err != nil {
+ t.Fatal("import of exportedReceive:", err)
+ }
+
+ r := make(chan value)
+ err = i1.Import("exportedSend", r, Recv)
+ 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++
+ }
+ }
}
diff --git a/src/pkg/nntp/nntp.go b/src/pkg/nntp/nntp.go
deleted file mode 100644
index e78b036f5..000000000
--- a/src/pkg/nntp/nntp.go
+++ /dev/null
@@ -1,709 +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.
-
-// The nntp package implements a client for the news protocol NNTP,
-// as defined in RFC 3977.
-package nntp
-
-import (
- "bufio"
- "bytes"
- "container/vector"
- "fmt"
- "http"
- "io"
- "io/ioutil"
- "os"
- "net"
- "sort"
- "strconv"
- "strings"
- "time"
-)
-
-// timeFormatNew is the NNTP time format string for NEWNEWS / NEWGROUPS
-const timeFormatNew = "20060102 150405"
-
-// timeFormatDate is the NNTP time format string for responses to the DATE command
-const timeFormatDate = "20060102150405"
-
-// An Error represents an error response from an NNTP server.
-type Error struct {
- Code uint
- Msg string
-}
-
-// A ProtocolError represents responses from an NNTP server
-// that seem incorrect for NNTP.
-type ProtocolError string
-
-// A Conn represents a connection to an NNTP server. The connection with
-// an NNTP server is stateful; it keeps track of what group you have
-// selected, if any, and (if you have a group selected) which article is
-// current, next, or previous.
-//
-// Some methods that return information about a specific message take
-// either a message-id, which is global across all NNTP servers, groups,
-// and messages, or a message-number, which is an integer number that is
-// local to the NNTP session and currently selected group.
-//
-// For all methods that return an io.Reader (or an *Article, which contains
-// an io.Reader), that io.Reader is only valid until the next call to a
-// method of Conn.
-type Conn struct {
- conn io.WriteCloser
- r *bufio.Reader
- br *bodyReader
- close bool
-}
-
-// A Group gives information about a single news group on the server.
-type Group struct {
- Name string
- // High and low message-numbers
- High, Low int
- // Status indicates if general posting is allowed --
- // typical values are "y", "n", or "m".
- Status string
-}
-
-// An Article represents an NNTP article.
-type Article struct {
- Header map[string][]string
- Body io.Reader
-}
-
-// A bodyReader satisfies reads by reading from the connection
-// until it finds a line containing just .
-type bodyReader struct {
- c *Conn
- eof bool
- buf *bytes.Buffer
-}
-
-var dotnl = []byte(".\n")
-var dotdot = []byte("..")
-
-func (r *bodyReader) Read(p []byte) (n int, err os.Error) {
- if r.eof {
- return 0, os.EOF
- }
- if r.buf == nil {
- r.buf = &bytes.Buffer{}
- }
- if r.buf.Len() == 0 {
- b, err := r.c.r.ReadBytes('\n')
- if err != nil {
- return 0, err
- }
- // canonicalize newlines
- if b[len(b)-2] == '\r' { // crlf->lf
- b = b[0 : len(b)-1]
- b[len(b)-1] = '\n'
- }
- // stop on .
- if bytes.Equal(b, dotnl) {
- r.eof = true
- return 0, os.EOF
- }
- // unescape leading ..
- if bytes.HasPrefix(b, dotdot) {
- b = b[1:]
- }
- r.buf.Write(b)
- }
- n, _ = r.buf.Read(p)
- return
-}
-
-func (r *bodyReader) discard() os.Error {
- _, err := ioutil.ReadAll(r)
- return err
-}
-
-// articleReader satisfies reads by dumping out an article's headers
-// and body.
-type articleReader struct {
- a *Article
- headerdone bool
- headerbuf *bytes.Buffer
-}
-
-func (r *articleReader) Read(p []byte) (n int, err os.Error) {
- if r.headerbuf == nil {
- buf := new(bytes.Buffer)
- for k, fv := range r.a.Header {
- for _, v := range fv {
- fmt.Fprintf(buf, "%s: %s\n", k, v)
- }
- }
- if r.a.Body != nil {
- fmt.Fprintf(buf, "\n")
- }
- r.headerbuf = buf
- }
- if !r.headerdone {
- n, err = r.headerbuf.Read(p)
- if err == os.EOF {
- err = nil
- r.headerdone = true
- }
- if n > 0 {
- return
- }
- }
- if r.a.Body != nil {
- n, err = r.a.Body.Read(p)
- if err == os.EOF {
- r.a.Body = nil
- }
- return
- }
- return 0, os.EOF
-}
-
-func (a *Article) String() string {
- id, ok := a.Header["Message-Id"]
- if !ok {
- return "[NNTP article]"
- }
- return fmt.Sprintf("[NNTP article %s]", id[0])
-}
-
-func (a *Article) WriteTo(w io.Writer) (int64, os.Error) {
- return io.Copy(w, &articleReader{a: a})
-}
-
-func (p ProtocolError) String() string {
- return string(p)
-}
-
-func (e Error) String() string {
- return fmt.Sprintf("%03d %s", e.Code, e.Msg)
-}
-
-func maybeId(cmd, id string) string {
- if len(id) > 0 {
- return cmd + " " + id
- }
- return cmd
-}
-
-// Dial connects to an NNTP server.
-// The network and addr are passed to net.Dial to
-// make the connection.
-//
-// Example:
-// conn, err := nntp.Dial("tcp", "my.news:nntp")
-//
-func Dial(network, addr string) (*Conn, os.Error) {
- res := new(Conn)
- c, err := net.Dial(network, "", addr)
- if err != nil {
- return nil, err
- }
-
- res.conn = c
- if res.r, err = bufio.NewReaderSize(c, 4096); err != nil {
- return nil, err
- }
-
- _, err = res.r.ReadString('\n')
- if err != nil {
- return nil, err
- }
-
- return res, nil
-}
-
-func (c *Conn) body() io.Reader {
- c.br = &bodyReader{c: c}
- return c.br
-}
-
-// readStrings reads a list of strings from the NNTP connection,
-// stopping at a line containing only a . (Convenience method for
-// LIST, etc.)
-func (c *Conn) readStrings() ([]string, os.Error) {
- var sv vector.StringVector
- for {
- line, err := c.r.ReadString('\n')
- if err != nil {
- return nil, err
- }
- if strings.HasSuffix(line, "\r\n") {
- line = line[0 : len(line)-2]
- } else if strings.HasSuffix(line, "\n") {
- line = line[0 : len(line)-1]
- }
- if line == "." {
- break
- }
- sv.Push(line)
- }
- return []string(sv), nil
-}
-
-// Authenticate logs in to the NNTP server.
-// It only sends the password if the server requires one.
-func (c *Conn) Authenticate(username, password string) os.Error {
- code, _, err := c.cmd(2, "AUTHINFO USER %s", username)
- if code/100 == 3 {
- _, _, err = c.cmd(2, "AUTHINFO PASS %s", password)
- }
- return err
-}
-
-// cmd executes an NNTP command:
-// It sends the command given by the format and arguments, and then
-// reads the response line. If expectCode > 0, the status code on the
-// response line must match it. 1 digit expectCodes only check the first
-// digit of the status code, etc.
-func (c *Conn) cmd(expectCode uint, format string, args ...interface{}) (code uint, line string, err os.Error) {
- if c.close {
- return 0, "", ProtocolError("connection closed")
- }
- if c.br != nil {
- if err := c.br.discard(); err != nil {
- return 0, "", err
- }
- c.br = nil
- }
- if _, err := fmt.Fprintf(c.conn, format+"\r\n", args); err != nil {
- return 0, "", err
- }
- line, err = c.r.ReadString('\n')
- if err != nil {
- return 0, "", err
- }
- line = strings.TrimSpace(line)
- if len(line) < 4 || line[3] != ' ' {
- return 0, "", ProtocolError("short response: " + line)
- }
- code, err = strconv.Atoui(line[0:3])
- if err != nil {
- return 0, "", ProtocolError("invalid response code: " + line)
- }
- line = line[4:]
- if 1 <= expectCode && expectCode < 10 && code/100 != expectCode ||
- 10 <= expectCode && expectCode < 100 && code/10 != expectCode ||
- 100 <= expectCode && expectCode < 1000 && code != expectCode {
- err = Error{code, line}
- }
- return
-}
-
-// ModeReader switches the NNTP server to "reader" mode, if it
-// is a mode-switching server.
-func (c *Conn) ModeReader() os.Error {
- _, _, err := c.cmd(20, "MODE READER")
- return err
-}
-
-// NewGroups returns a list of groups added since the given time.
-func (c *Conn) NewGroups(since *time.Time) ([]Group, os.Error) {
- if _, _, err := c.cmd(231, "NEWGROUPS %s GMT", since.Format(timeFormatNew)); err != nil {
- return nil, err
- }
- return c.readGroups()
-}
-
-func (c *Conn) readGroups() ([]Group, os.Error) {
- lines, err := c.readStrings()
- if err != nil {
- return nil, err
- }
- return parseGroups(lines)
-}
-
-// NewNews returns a list of the IDs of articles posted
-// to the given group since the given time.
-func (c *Conn) NewNews(group string, since *time.Time) ([]string, os.Error) {
- if _, _, err := c.cmd(230, "NEWNEWS %s %s GMT", group, since.Format(timeFormatNew)); err != nil {
- return nil, err
- }
-
- id, err := c.readStrings()
- if err != nil {
- return nil, err
- }
-
- sort.SortStrings(id)
- w := 0
- for r, s := range id {
- if r == 0 || id[r-1] != s {
- id[w] = s
- w++
- }
- }
- id = id[0:w]
-
- return id, nil
-}
-
-// parseGroups is used to parse a list of group states.
-func parseGroups(lines []string) ([]Group, os.Error) {
- var res vector.Vector
- for _, line := range lines {
- ss := strings.Split(strings.TrimSpace(line), " ", 4)
- if len(ss) < 4 {
- return nil, ProtocolError("short group info line: " + line)
- }
- high, err := strconv.Atoi(ss[1])
- if err != nil {
- return nil, ProtocolError("bad number in line: " + line)
- }
- low, err := strconv.Atoi(ss[2])
- if err != nil {
- return nil, ProtocolError("bad number in line: " + line)
- }
- res.Push(&Group{ss[0], high, low, ss[3]})
- }
- realres := make([]Group, res.Len())
- i := 0
- for v := range res.Iter() {
- realres[i] = *v.(*Group)
- i++
- }
- return realres, nil
-}
-
-// Capabilities returns a list of features this server performs.
-// Not all servers support capabilities.
-func (c *Conn) Capabilities() ([]string, os.Error) {
- if _, _, err := c.cmd(101, "CAPABILITIES"); err != nil {
- return nil, err
- }
- return c.readStrings()
-}
-
-// Date returns the current time on the server.
-// Typically the time is later passed to NewGroups or NewNews.
-func (c *Conn) Date() (*time.Time, os.Error) {
- _, line, err := c.cmd(111, "DATE")
- if err != nil {
- return nil, err
- }
- t, err := time.Parse(timeFormatDate, line)
- if err != nil {
- return nil, ProtocolError("invalid time: " + line)
- }
- return t, nil
-}
-
-// List returns a list of groups present on the server.
-// Valid forms are:
-//
-// List() - return active groups
-// List(keyword) - return different kinds of information about groups
-// List(keyword, pattern) - filter groups against a glob-like pattern called a wildmat
-//
-func (c *Conn) List(a ...string) ([]string, os.Error) {
- if len(a) > 2 {
- return nil, ProtocolError("List only takes up to 2 arguments")
- }
- cmd := "LIST"
- if len(a) > 0 {
- cmd += " " + a[0]
- if len(a) > 1 {
- cmd += " " + a[1]
- }
- }
- if _, _, err := c.cmd(215, cmd); err != nil {
- return nil, err
- }
- return c.readStrings()
-}
-
-// Group changes the current group.
-func (c *Conn) Group(group string) (number, low, high int, err os.Error) {
- _, line, err := c.cmd(211, "GROUP %s", group)
- if err != nil {
- return
- }
-
- ss := strings.Split(line, " ", 4) // intentional -- we ignore optional message
- if len(ss) < 3 {
- err = ProtocolError("bad group response: " + line)
- return
- }
-
- var n [3]int
- for i, _ := range n {
- c, err := strconv.Atoi(ss[i])
- if err != nil {
- err = ProtocolError("bad group response: " + line)
- return
- }
- n[i] = c
- }
- number, low, high = n[0], n[1], n[2]
- return
-}
-
-// Help returns the server's help text.
-func (c *Conn) Help() (io.Reader, os.Error) {
- if _, _, err := c.cmd(100, "HELP"); err != nil {
- return nil, err
- }
- return c.body(), nil
-}
-
-// nextLastStat performs the work for NEXT, LAST, and STAT.
-func (c *Conn) nextLastStat(cmd, id string) (string, string, os.Error) {
- _, line, err := c.cmd(223, maybeId(cmd, id))
- if err != nil {
- return "", "", err
- }
- ss := strings.Split(line, " ", 3) // optional comment ignored
- if len(ss) < 2 {
- return "", "", ProtocolError("Bad response to " + cmd + ": " + line)
- }
- return ss[0], ss[1], nil
-}
-
-// Stat looks up the message with the given id and returns its
-// message number in the current group, and vice versa.
-// The returned message number can be "0" if the current group
-// isn't one of the groups the message was posted to.
-func (c *Conn) Stat(id string) (number, msgid string, err os.Error) {
- return c.nextLastStat("STAT", id)
-}
-
-// Last selects the previous article, returning its message number and id.
-func (c *Conn) Last() (number, msgid string, err os.Error) {
- return c.nextLastStat("LAST", "")
-}
-
-// Next selects the next article, returning its message number and id.
-func (c *Conn) Next() (number, msgid string, err os.Error) {
- return c.nextLastStat("NEXT", "")
-}
-
-// ArticleText returns the article named by id as an io.Reader.
-// The article is in plain text format, not NNTP wire format.
-func (c *Conn) ArticleText(id string) (io.Reader, os.Error) {
- if _, _, err := c.cmd(220, maybeId("ARTICLE", id)); err != nil {
- return nil, err
- }
- return c.body(), nil
-}
-
-// Article returns the article named by id as an *Article.
-func (c *Conn) Article(id string) (*Article, os.Error) {
- if _, _, err := c.cmd(220, maybeId("ARTICLE", id)); err != nil {
- return nil, err
- }
- r := bufio.NewReader(c.body())
- res, err := c.readHeader(r)
- if err != nil {
- return nil, err
- }
- res.Body = r
- return res, nil
-}
-
-// HeadText returns the header for the article named by id as an io.Reader.
-// The article is in plain text format, not NNTP wire format.
-func (c *Conn) HeadText(id string) (io.Reader, os.Error) {
- if _, _, err := c.cmd(221, maybeId("HEAD", id)); err != nil {
- return nil, err
- }
- return c.body(), nil
-}
-
-// Head returns the header for the article named by id as an *Article.
-// The Body field in the Article is nil.
-func (c *Conn) Head(id string) (*Article, os.Error) {
- if _, _, err := c.cmd(221, maybeId("HEAD", id)); err != nil {
- return nil, err
- }
- return c.readHeader(bufio.NewReader(c.body()))
-}
-
-// Body returns the body for the article named by id as an io.Reader.
-func (c *Conn) Body(id string) (io.Reader, os.Error) {
- if _, _, err := c.cmd(222, maybeId("BODY", id)); err != nil {
- return nil, err
- }
- return c.body(), nil
-}
-
-// RawPost reads a text-formatted article from r and posts it to the server.
-func (c *Conn) RawPost(r io.Reader) os.Error {
- if _, _, err := c.cmd(3, "POST"); err != nil {
- return err
- }
- br := bufio.NewReader(r)
- eof := false
- for {
- line, err := br.ReadString('\n')
- if err == os.EOF {
- eof = true
- } else if err != nil {
- return err
- }
- if eof && len(line) == 0 {
- break
- }
- if strings.HasSuffix(line, "\n") {
- line = line[0 : len(line)-1]
- }
- var prefix string
- if strings.HasPrefix(line, ".") {
- prefix = "."
- }
- _, err = fmt.Fprintf(c.conn, "%s%s\r\n", prefix, line)
- if err != nil {
- return err
- }
- if eof {
- break
- }
- }
-
- if _, _, err := c.cmd(240, "."); err != nil {
- return err
- }
- return nil
-}
-
-// Post posts an article to the server.
-func (c *Conn) Post(a *Article) os.Error {
- return c.RawPost(&articleReader{a: a})
-}
-
-// Quit sends the QUIT command and closes the connection to the server.
-func (c *Conn) Quit() os.Error {
- _, _, err := c.cmd(0, "QUIT")
- c.conn.Close()
- c.close = true
- return err
-}
-
-// Functions after this point are mostly copy-pasted from http
-// (though with some modifications). They should be factored out to
-// a common library.
-
-// 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
- }
- return nil, err
- }
-
- // 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
-}
-
-var colon = []byte{':'}
-
-// Read a key/value pair from b.
-// A key/value has the form Key: Value\r\n
-// and the Value can continue on multiple lines if each continuation line
-// starts with a space/tab.
-func readKeyValue(b *bufio.Reader) (key, value string, err os.Error) {
- line, e := readLineBytes(b)
- if e == io.ErrUnexpectedEOF {
- return "", "", nil
- } else if e != nil {
- return "", "", e
- }
- if len(line) == 0 {
- return "", "", nil
- }
-
- // Scan first line for colon.
- i := bytes.Index(line, colon)
- if i < 0 {
- goto Malformed
- }
-
- key = string(line[0:i])
- if strings.Index(key, " ") >= 0 {
- // Key field has space - no good.
- goto Malformed
- }
-
- // Skip initial space before value.
- for i++; i < len(line); i++ {
- if line[i] != ' ' && line[i] != '\t' {
- break
- }
- }
- value = string(line[i:])
-
- // Look for extension lines, which must begin with space.
- for {
- c, e := b.ReadByte()
- if c != ' ' && c != '\t' {
- if e != os.EOF {
- b.UnreadByte()
- }
- break
- }
-
- // Eat leading space.
- for c == ' ' || c == '\t' {
- if c, e = b.ReadByte(); e != nil {
- if e == os.EOF {
- e = io.ErrUnexpectedEOF
- }
- return "", "", e
- }
- }
- b.UnreadByte()
-
- // Read the rest of the line and add to value.
- if line, e = readLineBytes(b); e != nil {
- return "", "", e
- }
- value += " " + string(line)
- }
- return key, value, nil
-
-Malformed:
- return "", "", ProtocolError("malformed header line: " + string(line))
-}
-
-// Internal. Parses headers in NNTP articles. Most of this is stolen from the http package,
-// and it should probably be split out into a generic RFC822 header-parsing package.
-func (c *Conn) readHeader(r *bufio.Reader) (res *Article, err os.Error) {
- res = new(Article)
- res.Header = make(map[string][]string)
- for {
- var key, value string
- if key, value, err = readKeyValue(r); err != nil {
- return nil, err
- }
- if key == "" {
- break
- }
- key = http.CanonicalHeaderKey(key)
- // RFC 3977 says nothing about duplicate keys' values being equivalent to
- // a single key joined with commas, so we keep all values seperate.
- oldvalue, present := res.Header[key]
- if present {
- sv := vector.StringVector(oldvalue)
- sv.Push(value)
- res.Header[key] = []string(sv)
- } else {
- res.Header[key] = []string{value}
- }
- }
- return res, nil
-}
diff --git a/src/pkg/nntp/nntp_test.go b/src/pkg/nntp/nntp_test.go
deleted file mode 100644
index bca185722..000000000
--- a/src/pkg/nntp/nntp_test.go
+++ /dev/null
@@ -1,241 +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 nntp
-
-import (
- "bufio"
- "bytes"
- "fmt"
- "io"
- "io/ioutil"
- "os"
- "strings"
- "testing"
- "time"
-)
-
-func TestSanityChecks(t *testing.T) {
- if _, err := Dial("", ""); err == nil {
- t.Fatal("Dial should require at least a destination address.")
- }
-}
-
-type faker struct {
- io.Writer
-}
-
-func (f faker) Close() os.Error {
- return nil
-}
-
-func TestBasic(t *testing.T) {
- basicServer = strings.Join(strings.Split(basicServer, "\n", -1), "\r\n")
- basicClient = strings.Join(strings.Split(basicClient, "\n", -1), "\r\n")
-
- var cmdbuf bytes.Buffer
- var fake faker
- fake.Writer = &cmdbuf
-
- conn := &Conn{conn: fake, r: bufio.NewReader(strings.NewReader(basicServer))}
-
- // Test some global commands that don't take arguments
- if _, err := conn.Capabilities(); err != nil {
- t.Fatal("should be able to request CAPABILITIES after connecting: " + err.String())
- }
-
- _, err := conn.Date()
- if err != nil {
- t.Fatal("should be able to send DATE: " + err.String())
- }
-
- /*
- Test broken until time.Parse adds this format.
- cdate := time.UTC()
- if sdate.Year != cdate.Year || sdate.Month != cdate.Month || sdate.Day != cdate.Day {
- t.Fatal("DATE seems off, probably erroneous: " + sdate.String())
- }
- */
-
- // Test LIST (implicit ACTIVE)
- if _, err = conn.List(); err != nil {
- t.Fatal("LIST should work: " + err.String())
- }
-
- tt := new(time.Time)
- tt.Year = 2010
- tt.Month = 3
- tt.Day = 1
-
- const grp = "gmane.comp.lang.go.general"
- _, l, h, err := conn.Group(grp)
- if err != nil {
- t.Fatal("Group shouldn't error: " + err.String())
- }
-
- // test STAT, NEXT, and LAST
- if _, _, err = conn.Stat(""); err != nil {
- t.Fatal("should be able to STAT after selecting a group: " + err.String())
- }
- if _, _, err = conn.Next(); err != nil {
- t.Fatal("should be able to NEXT after selecting a group: " + err.String())
- }
- if _, _, err = conn.Last(); err != nil {
- t.Fatal("should be able to LAST after a NEXT selecting a group: " + err.String())
- }
-
- // Can we grab articles?
- a, err := conn.Article(fmt.Sprintf("%d", l))
- if err != nil {
- t.Fatal("should be able to fetch the low article: " + err.String())
- }
- body, err := ioutil.ReadAll(a.Body)
- if err != nil {
- t.Fatal("error reading reader: " + err.String())
- }
-
- // Test that the article body doesn't get mangled.
- expectedbody := `Blah, blah.
-.A single leading .
-Fin.
-`
- if !bytes.Equal([]byte(expectedbody), body) {
- t.Fatalf("article body read incorrectly; got:\n%s\nExpected:\n%s", body, expectedbody)
- }
-
- // Test articleReader
- expectedart := `Message-Id: <b@c.d>
-
-Body.
-`
- a, err = conn.Article(fmt.Sprintf("%d", l+1))
- if err != nil {
- t.Fatal("shouldn't error reading article low+1: " + err.String())
- }
- var abuf bytes.Buffer
- _, err = a.WriteTo(&abuf)
- if err != nil {
- t.Fatal("shouldn't error writing out article: " + err.String())
- }
- actualart := abuf.String()
- if actualart != expectedart {
- t.Fatalf("articleReader broke; got:\n%s\nExpected\n%s", actualart, expectedart)
- }
-
- // Just headers?
- if _, err = conn.Head(fmt.Sprintf("%d", h)); err != nil {
- t.Fatal("should be able to fetch the high article: " + err.String())
- }
-
- // Without an id?
- if _, err = conn.Head(""); err != nil {
- t.Fatal("should be able to fetch the selected article without specifying an id: " + err.String())
- }
-
- // How about bad articles? Do they error?
- if _, err = conn.Head(fmt.Sprintf("%d", l-1)); err == nil {
- t.Fatal("shouldn't be able to fetch articles lower than low")
- }
- if _, err = conn.Head(fmt.Sprintf("%d", h+1)); err == nil {
- t.Fatal("shouldn't be able to fetch articles higher than high")
- }
-
- // Just the body?
- r, err := conn.Body(fmt.Sprintf("%d", l))
- if err != nil {
- t.Fatal("should be able to fetch the low article body\n" + err.String())
- }
- if _, err = ioutil.ReadAll(r); err != nil {
- t.Fatal("error reading reader: " + err.String())
- }
-
- if _, err = conn.NewNews(grp, tt); err != nil {
- t.Fatal("newnews should work: " + err.String())
- }
-
-
- // NewGroups
- if _, err = conn.NewGroups(tt); err != nil {
- t.Fatal("newgroups shouldn't error " + err.String())
- }
-
- if err = conn.Quit(); err != nil {
- t.Fatal("Quit shouldn't error: " + err.String())
- }
-
- actualcmds := cmdbuf.String()
- if basicClient != actualcmds {
- t.Fatalf("Got:\n%s\nExpected\n%s", actualcmds, basicClient)
- }
-}
-
-var basicServer = `101 Capability list:
-VERSION 2
-.
-111 20100329034158
-215 Blah blah
-foo 7 3 y
-bar 000008 02 m
-.
-211 100 1 100 gmane.comp.lang.go.general
-223 1 <a@b.c> status
-223 2 <b@c.d> Article retrieved
-223 1 <a@b.c> Article retrieved
-220 1 <a@b.c> article
-Path: fake!not-for-mail
-From: Someone
-Newsgroups: gmane.comp.lang.go.general
-Subject: [go-nuts] What about base members?
-Message-ID: <a@b.c>
-
-Blah, blah.
-..A single leading .
-Fin.
-.
-220 2 <b@c.d> article
-Message-ID: <b@c.d>
-
-Body.
-.
-221 100 <c@d.e> head
-Path: fake!not-for-mail
-Message-ID: <c@d.e>
-.
-221 100 <c@d.e> head
-Path: fake!not-for-mail
-Message-ID: <c@d.e>
-.
-423 Bad article number
-423 Bad article number
-222 1 <a@b.c> body
-Blah, blah.
-..A single leading .
-Fin.
-.
-230 list of new articles by message-id follows
-<d@e.c>
-.
-231 New newsgroups follow
-.
-205 Bye!
-`
-
-var basicClient = `CAPABILITIES
-DATE
-LIST
-GROUP gmane.comp.lang.go.general
-STAT
-NEXT
-LAST
-ARTICLE 1
-ARTICLE 2
-HEAD 100
-HEAD
-HEAD 0
-HEAD 101
-BODY 1
-NEWNEWS gmane.comp.lang.go.general 20100301 000000 GMT
-NEWGROUPS 20100301 000000 GMT
-QUIT
-`
diff --git a/src/pkg/once/once.go b/src/pkg/once/once.go
deleted file mode 100644
index 43949ee19..000000000
--- a/src/pkg/once/once.go
+++ /dev/null
@@ -1,59 +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 package provides a single function, Do, to run a function
-// exactly once, usually used as part of initialization.
-package once
-
-import "sync"
-
-type job struct {
- done bool
- sync.Mutex // should probably be sync.Notification or some such
-}
-
-var jobs = make(map[func()]*job)
-var joblock sync.Mutex
-
-// Do is the the only exported piece of the package.
-// For one-time initialization that is not done during init,
-// wrap the initialization in a niladic function f() and call
-// Do(f)
-// If multiple processes call Do(f) simultaneously
-// with the same f argument, only one will call f, and the
-// others will block until f finishes running.
-//
-// Since a func() expression typically evaluates to a differerent
-// function value each time it is evaluated, it is incorrect to
-// pass such values to Do. For example,
-// func f(x int) {
-// Do(func() { fmt.Println(x) })
-// }
-// behaves the same as
-// func f(x int) {
-// fmt.Println(x)
-// }
-// because the func() expression in the first creates a new
-// func each time f runs, and each of those funcs is run once.
-func Do(f func()) {
- joblock.Lock()
- j := jobs[f]
- if j == nil {
- // run it
- j = new(job)
- j.Lock()
- jobs[f] = j
- joblock.Unlock()
- f()
- j.done = true
- j.Unlock()
- } else {
- // wait for it
- joblock.Unlock()
- if j.done != true {
- j.Lock()
- j.Unlock()
- }
- }
-}
diff --git a/src/pkg/once/once_test.go b/src/pkg/once/once_test.go
deleted file mode 100644
index e7aaec312..000000000
--- a/src/pkg/once/once_test.go
+++ /dev/null
@@ -1,30 +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 once_test
-
-import (
- "once"
- "testing"
-)
-
-var ncall int
-
-func call() { ncall++ }
-
-func TestDo(t *testing.T) {
- ncall = 0
- once.Do(call)
- if ncall != 1 {
- t.Fatalf("once.Do(call) didn't call(): ncall=%d", ncall)
- }
- once.Do(call)
- if ncall != 1 {
- t.Fatalf("second once.Do(call) did call(): ncall=%d", ncall)
- }
- once.Do(call)
- if ncall != 1 {
- t.Fatalf("third once.Do(call) did call(): ncall=%d", ncall)
- }
-}
diff --git a/src/pkg/os/Makefile b/src/pkg/os/Makefile
index 45954bbeb..f6caf084c 100644
--- a/src/pkg/os/Makefile
+++ b/src/pkg/os/Makefile
@@ -2,13 +2,13 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=os
GOFILES=\
dir_$(GOOS).go\
- env.go\
error.go\
+ env.go\
exec.go\
file.go\
getwd.go\
@@ -33,11 +33,6 @@ GOFILES_linux=\
file_unix.go\
sys_linux.go\
-GOFILES_nacl=\
- env_unix.go\
- file_unix.go\
- sys_nacl.go\
-
GOFILES_windows=\
env_windows.go\
file_windows.go\
diff --git a/src/pkg/os/dir_darwin.go b/src/pkg/os/dir_darwin.go
index 7917daec6..861bcef27 100644
--- a/src/pkg/os/dir_darwin.go
+++ b/src/pkg/os/dir_darwin.go
@@ -58,21 +58,13 @@ func (file *File) Readdirnames(count int) (names []string, err Error) {
if dirent.Ino == 0 { // File absent in directory.
continue
}
- bytes := (*[len(dirent.Name)]byte)(unsafe.Pointer(&dirent.Name[0]))
+ bytes := (*[10000]byte)(unsafe.Pointer(&dirent.Name[0]))
var name = string(bytes[0:dirent.Namlen])
if name == "." || name == ".." { // Useless names
continue
}
count--
- if len(names) == cap(names) {
- nnames := make([]string, len(names), 2*len(names))
- for i := 0; i < len(names); i++ {
- nnames[i] = names[i]
- }
- names = nnames
- }
- names = names[0 : len(names)+1]
- names[len(names)-1] = name
+ names = append(names, name)
}
}
return names, nil
diff --git a/src/pkg/os/dir_freebsd.go b/src/pkg/os/dir_freebsd.go
index 7a0290ac6..2ebe368a6 100644
--- a/src/pkg/os/dir_freebsd.go
+++ b/src/pkg/os/dir_freebsd.go
@@ -53,21 +53,13 @@ func (file *File) Readdirnames(count int) (names []string, err Error) {
if dirent.Fileno == 0 { // File absent in directory.
continue
}
- bytes := (*[len(dirent.Name)]byte)(unsafe.Pointer(&dirent.Name[0]))
+ bytes := (*[10000]byte)(unsafe.Pointer(&dirent.Name[0]))
var name = string(bytes[0:dirent.Namlen])
if name == "." || name == ".." { // Useless names
continue
}
count--
- if len(names) == cap(names) {
- nnames := make([]string, len(names), 2*len(names))
- for i := 0; i < len(names); i++ {
- nnames[i] = names[i]
- }
- names = nnames
- }
- names = names[0 : len(names)+1]
- names[len(names)-1] = name
+ names = append(names, name)
}
}
return names, nil
diff --git a/src/pkg/os/dir_linux.go b/src/pkg/os/dir_linux.go
index 84f87007e..09aad6367 100644
--- a/src/pkg/os/dir_linux.go
+++ b/src/pkg/os/dir_linux.go
@@ -56,21 +56,13 @@ func (file *File) Readdirnames(count int) (names []string, err Error) {
if dirent.Ino == 0 { // File absent in directory.
continue
}
- bytes := (*[len(dirent.Name)]byte)(unsafe.Pointer(&dirent.Name[0]))
+ bytes := (*[10000]byte)(unsafe.Pointer(&dirent.Name[0]))
var name = string(bytes[0:clen(bytes[0:])])
if name == "." || name == ".." { // Useless names
continue
}
count--
- if len(names) == cap(names) {
- nnames := make([]string, len(names), 2*len(names))
- for i := 0; i < len(names); i++ {
- nnames[i] = names[i]
- }
- names = nnames
- }
- names = names[0 : len(names)+1]
- names[len(names)-1] = name
+ names = append(names, name)
}
}
return names, nil
diff --git a/src/pkg/os/dir_nacl.go b/src/pkg/os/dir_nacl.go
deleted file mode 100644
index e693794f0..000000000
--- a/src/pkg/os/dir_nacl.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 os
-
-import (
- "syscall"
- "unsafe"
-)
-
-const (
- blockSize = 4096 // TODO(r): use statfs
-)
-
-func clen(n []byte) int {
- for i := 0; i < len(n); i++ {
- if n[i] == 0 {
- return i
- }
- }
- return len(n)
-}
-
-func (file *File) Readdirnames(count int) (names []string, err Error) {
- // If this file has no dirinfo, create one.
- if file.dirinfo == nil {
- file.dirinfo = new(dirInfo)
- // The buffer must be at least a block long.
- // TODO(r): use fstatfs to find fs block size.
- file.dirinfo.buf = make([]byte, blockSize)
- }
- d := file.dirinfo
- size := count
- if size < 0 {
- size = 100
- }
- names = make([]string, 0, size) // Empty with room to grow.
- for count != 0 {
- // Refill the buffer if necessary
- if d.bufp >= d.nbuf {
- var errno int
- d.nbuf, errno = syscall.Getdents(file.fd, d.buf)
- if errno != 0 {
- return names, NewSyscallError("getdents", errno)
- }
- if d.nbuf <= 0 {
- break // EOF
- }
- d.bufp = 0
- }
- // Drain the buffer
- for count != 0 && d.bufp < d.nbuf {
- dirent := (*syscall.Dirent)(unsafe.Pointer(&d.buf[d.bufp]))
- d.bufp += int(dirent.Reclen)
- if dirent.Ino == 0 { // File absent in directory.
- continue
- }
- bytes := (*[len(dirent.Name)]byte)(unsafe.Pointer(&dirent.Name[0]))
- var name = string(bytes[0:clen(bytes)])
- if name == "." || name == ".." { // Useless names
- continue
- }
- count--
- if len(names) == cap(names) {
- nnames := make([]string, len(names), 2*len(names))
- for i := 0; i < len(names); i++ {
- nnames[i] = names[i]
- }
- names = nnames
- }
- names = names[0 : len(names)+1]
- names[len(names)-1] = name
- }
- }
- return names, nil
-}
diff --git a/src/pkg/os/env.go b/src/pkg/os/env.go
index bdd2ac293..3a6d79dd0 100644
--- a/src/pkg/os/env.go
+++ b/src/pkg/os/env.go
@@ -1,86 +1,73 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2010 The Go 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.
+// General environment variables.
package os
-import (
- "once"
-)
-
-// ENOENV is the Error indicating that an environment variable does not exist.
-var ENOENV = NewError("no such environment variable")
-
-var env map[string]string
-
-
-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
- }
+// Expand replaces ${var} or $var in the string based on the mapping function.
+// Invocations of undefined variables are replaced with the empty string.
+func Expand(s string, mapping func(string) string) string {
+ buf := make([]byte, 0, 2*len(s))
+ // ${} is all ASCII, so bytes are fine for this operation.
+ i := 0
+ for j := 0; j < len(s); j++ {
+ if s[j] == '$' && j+1 < len(s) {
+ buf = append(buf, []byte(s[i:j])...)
+ name, w := getShellName(s[j+1:])
+ buf = append(buf, []byte(mapping(name))...)
+ j += w
+ i = j + 1
}
}
+ return string(buf) + s[i:]
}
-// Getenverror retrieves the value of the environment variable named by the key.
-// It returns the value and an error, if any.
-func Getenverror(key string) (value string, err Error) {
- once.Do(copyenv)
-
- if len(key) == 0 {
- return "", EINVAL
- }
- v, ok := env[key]
- if !ok {
- return "", ENOENV
- }
- return v, nil
-}
-
-// Getenv retrieves the value of the environment variable named by the key.
-// It returns the value, which will be empty if the variable is not present.
-func Getenv(key string) string {
- v, _ := Getenverror(key)
- return v
+// ShellExpand replaces ${var} or $var in the string according to the values
+// of the operating system's environment variables. References to undefined
+// variables are replaced by the empty string.
+func ShellExpand(s string) string {
+ return Expand(s, Getenv)
}
-// 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
+// isSpellSpecialVar reports whether the character identifies a special
+// shell variable such as $*.
+func isShellSpecialVar(c uint8) bool {
+ switch c {
+ case '*', '#', '$', '@', '!', '?', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
+ return true
}
- env[key] = value
- return nil
+ return false
}
-// Clearenv deletes all environment variables.
-func Clearenv() {
- once.Do(copyenv) // prevent copyenv in Getenv/Setenv
- env = make(map[string]string)
+// isAlphaNum reports whether the byte is an ASCII letter, number, or underscore
+func isAlphaNum(c uint8) bool {
+ return c == '_' || '0' <= c && c <= '9' || 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z'
}
-// Environ returns an array of strings representing the environment,
-// in the form "key=value".
-func Environ() []string {
- once.Do(copyenv)
- a := make([]string, len(env))
- i := 0
- for k, v := range env {
- // check i < len(a) for safety,
- // in case env is changing underfoot.
- if i < len(a) {
- a[i] = k + "=" + v
- i++
+// getName returns the name that begins the string and the number of bytes
+// consumed to extract it. If the name is enclosed in {}, it's part of a ${}
+// expansion and two more bytes are needed than the length of the name.
+func getShellName(s string) (string, int) {
+ switch {
+ case s[0] == '{':
+ if len(s) > 2 && isShellSpecialVar(s[1]) && s[2] == '}' {
+ return s[1:2], 3
+ }
+ // Scan to closing brace
+ for i := 1; i < len(s); i++ {
+ if s[i] == '}' {
+ return s[1:i], i + 1
+ }
}
+ return "", 1 // Bad syntax; just eat the brace.
+ case isShellSpecialVar(s[0]):
+ return s[0:1], 1
+ }
+ // Scan alphanumerics.
+ var i int
+ for i = 0; i < len(s) && isAlphaNum(s[i]); i++ {
}
- return a[0:i]
+ return s[:i], i
}
diff --git a/src/pkg/os/env_test.go b/src/pkg/os/env_test.go
new file mode 100644
index 000000000..04ff39072
--- /dev/null
+++ b/src/pkg/os/env_test.go
@@ -0,0 +1,59 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os_test
+
+import (
+ . "os"
+ "testing"
+)
+
+// testGetenv gives us a controlled set of variables for testing Expand.
+func testGetenv(s string) string {
+ switch s {
+ case "*":
+ return "all the args"
+ case "#":
+ return "NARGS"
+ case "$":
+ return "PID"
+ case "1":
+ return "ARGUMENT1"
+ case "HOME":
+ return "/usr/gopher"
+ case "H":
+ return "(Value of H)"
+ case "home_1":
+ return "/usr/foo"
+ case "_":
+ return "underscore"
+ }
+ return ""
+}
+
+var expandTests = []struct {
+ in, out string
+}{
+ {"", ""},
+ {"$*", "all the args"},
+ {"$$", "PID"},
+ {"${*}", "all the args"},
+ {"$1", "ARGUMENT1"},
+ {"${1}", "ARGUMENT1"},
+ {"now is the time", "now is the time"},
+ {"$HOME", "/usr/gopher"},
+ {"$home_1", "/usr/foo"},
+ {"${HOME}", "/usr/gopher"},
+ {"${H}OME", "(Value of H)OME"},
+ {"A$$$#$1$H$home_1*B", "APIDNARGSARGUMENT1(Value of H)/usr/foo*B"},
+}
+
+func TestExpand(t *testing.T) {
+ for _, test := range expandTests {
+ result := Expand(test.in, testGetenv)
+ if result != test.out {
+ t.Errorf("Expand(%q)=%q; expected %q", test.in, result, test.out)
+ }
+ }
+}
diff --git a/src/pkg/os/env_unix.go b/src/pkg/os/env_unix.go
index 0c13bda0e..e7e1c3b90 100755..100644
--- a/src/pkg/os/env_unix.go
+++ b/src/pkg/os/env_unix.go
@@ -6,10 +6,87 @@
package os
+import (
+ "sync"
+)
+
+// ENOENV is the Error indicating that an environment variable does not exist.
+var ENOENV = NewError("no such environment variable")
+
+var env map[string]string
+var once sync.Once
+
+
+func copyenv() {
+ env = make(map[string]string)
+ for _, s := range Envs {
+ for j := 0; j < len(s); j++ {
+ if s[j] == '=' {
+ env[s[0:j]] = s[j+1:]
+ break
+ }
+ }
+ }
+}
+
+// Getenverror retrieves the value of the environment variable named by the key.
+// It returns the value and an error, if any.
+func Getenverror(key string) (value string, err Error) {
+ once.Do(copyenv)
+
+ if len(key) == 0 {
+ return "", EINVAL
+ }
+ v, ok := env[key]
+ if !ok {
+ return "", ENOENV
+ }
+ return v, nil
+}
+
+// Getenv retrieves the value of the environment variable named by the key.
+// It returns the value, which will be empty if the variable is not present.
+func Getenv(key string) string {
+ v, _ := Getenverror(key)
+ return v
+}
+
+// Setenv sets the value of the environment variable named by the key.
+// It returns an Error, if any.
+func Setenv(key, value string) Error {
+ once.Do(copyenv)
+
+ if len(key) == 0 {
+ return EINVAL
+ }
+ env[key] = value
+ return nil
+}
+
+// Clearenv deletes all environment variables.
+func Clearenv() {
+ once.Do(copyenv) // prevent copyenv in Getenv/Setenv
+ env = make(map[string]string)
+}
+
+// Environ returns an array of strings representing the environment,
+// in the form "key=value".
+func Environ() []string {
+ once.Do(copyenv)
+ a := make([]string, len(env))
+ i := 0
+ for k, v := range env {
+ // check i < len(a) for safety,
+ // in case env is changing underfoot.
+ if i < len(a) {
+ a[i] = k + "=" + v
+ i++
+ }
+ }
+ return a[0:i]
+}
+
// TempDir returns the default directory to use for temporary files.
-// On Unix-like systems, it uses the environment variable $TMPDIR
-// or, if that is empty, /tmp.
-// On Windows systems, it uses the Windows GetTempPath API.
func TempDir() string {
dir := Getenv("TMPDIR")
if dir == "" {
diff --git a/src/pkg/os/env_windows.go b/src/pkg/os/env_windows.go
index 7d5b007c9..d2b159dfb 100755..100644
--- a/src/pkg/os/env_windows.go
+++ b/src/pkg/os/env_windows.go
@@ -9,8 +9,92 @@ package os
import (
"syscall"
"utf16"
+ "unsafe"
)
+// ENOENV is the Error indicating that an environment variable does not exist.
+var ENOENV = NewError("no such environment variable")
+
+// Getenverror retrieves the value of the environment variable named by the key.
+// It returns the value and an error, if any.
+func Getenverror(key string) (value string, err Error) {
+ b := make([]uint16, 100)
+ n, e := syscall.GetEnvironmentVariable(syscall.StringToUTF16Ptr(key), &b[0], uint32(len(b)))
+ if n == 0 && e == syscall.ERROR_ENVVAR_NOT_FOUND {
+ return "", ENOENV
+ }
+ if n > uint32(len(b)) {
+ b = make([]uint16, n)
+ n, e = syscall.GetEnvironmentVariable(syscall.StringToUTF16Ptr(key), &b[0], uint32(len(b)))
+ if n > uint32(len(b)) {
+ n = 0
+ }
+ }
+ if n == 0 {
+ return "", NewSyscallError("GetEnvironmentVariable", e)
+ }
+ return string(utf16.Decode(b[0:n])), nil
+}
+
+// Getenv retrieves the value of the environment variable named by the key.
+// It returns the value, which will be empty if the variable is not present.
+func Getenv(key string) string {
+ v, _ := Getenverror(key)
+ return v
+}
+
+// Setenv sets the value of the environment variable named by the key.
+// It returns an Error, if any.
+func Setenv(key, value string) Error {
+ var v *uint16
+ if len(value) > 0 {
+ v = syscall.StringToUTF16Ptr(value)
+ }
+ ok, e := syscall.SetEnvironmentVariable(syscall.StringToUTF16Ptr(key), v)
+ if !ok {
+ return NewSyscallError("SetEnvironmentVariable", e)
+ }
+ return nil
+}
+
+// Clearenv deletes all environment variables.
+func Clearenv() {
+ for _, s := range Environ() {
+ // Environment variables can begin with =
+ // so start looking for the separator = at j=1.
+ // http://blogs.msdn.com/b/oldnewthing/archive/2010/05/06/10008132.aspx
+ for j := 1; j < len(s); j++ {
+ if s[j] == '=' {
+ Setenv(s[0:j], "")
+ break
+ }
+ }
+ }
+}
+
+// Environ returns an array of strings representing the environment,
+// in the form "key=value".
+func Environ() []string {
+ s, e := syscall.GetEnvironmentStrings()
+ if e != 0 {
+ return nil
+ }
+ defer syscall.FreeEnvironmentStrings(s)
+ r := make([]string, 0, 50) // Empty with room to grow.
+ for from, i, p := 0, 0, (*[1 << 24]uint16)(unsafe.Pointer(s)); true; i++ {
+ if p[i] == 0 {
+ // empty string marks the end
+ if i <= from {
+ break
+ }
+ r = append(r, string(utf16.Decode(p[from:i])))
+ from = i + 1
+ }
+ }
+ return r
+}
+
+// TempDir returns the default directory to use for temporary files.
func TempDir() string {
const pathSep = '\\'
dirw := make([]uint16, syscall.MAX_PATH)
@@ -27,3 +111,17 @@ func TempDir() string {
}
return string(utf16.Decode(dirw[0:n]))
}
+
+func init() {
+ var argc int32
+ cmd := syscall.GetCommandLine()
+ argv, e := syscall.CommandLineToArgv(cmd, &argc)
+ if e != 0 {
+ return
+ }
+ defer syscall.LocalFree(uint32(uintptr(unsafe.Pointer(argv))))
+ Args = make([]string, argc)
+ for i, v := range (*argv)[:argc] {
+ Args[i] = string(syscall.UTF16ToString((*v)[:]))
+ }
+}
diff --git a/src/pkg/os/exec.go b/src/pkg/os/exec.go
index d55acbaa7..501ebc270 100644
--- a/src/pkg/os/exec.go
+++ b/src/pkg/os/exec.go
@@ -8,14 +8,17 @@ import (
"syscall"
)
-// ForkExec forks the current process and invokes Exec with the file, arguments,
-// and environment specified by argv0, argv, and envv. It returns the process
+// ForkExec forks the current process and invokes Exec with the program, arguments,
+// and environment specified by name, argv, and envv. It returns the process
// id of the forked process and an Error, if any. The fd array specifies the
// file descriptors to be set up in the new process: fd[0] will be Unix file
// descriptor 0 (standard input), fd[1] descriptor 1, and so on. A nil entry
// will cause the child to have no open file descriptor with that index.
// If dir is not empty, the child chdirs into the directory before execing the program.
-func ForkExec(argv0 string, argv []string, envv []string, dir string, fd []*File) (pid int, err Error) {
+func ForkExec(name string, argv []string, envv []string, dir string, fd []*File) (pid int, err Error) {
+ if envv == nil {
+ envv = Environ()
+ }
// Create array of integer (system) fds.
intfd := make([]int, len(fd))
for i, f := range fd {
@@ -26,24 +29,24 @@ func ForkExec(argv0 string, argv []string, envv []string, dir string, fd []*File
}
}
- p, e := syscall.ForkExec(argv0, argv, envv, dir, intfd)
+ p, e := syscall.ForkExec(name, argv, envv, dir, intfd)
if e != 0 {
- return 0, &PathError{"fork/exec", argv0, Errno(e)}
+ return 0, &PathError{"fork/exec", name, Errno(e)}
}
return p, nil
}
-// Exec replaces the current process with an execution of the program
-// named by argv0, with arguments argv and environment envv.
+// 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(argv0 string, argv []string, envv []string) Error {
+func Exec(name string, argv []string, envv []string) Error {
if envv == nil {
envv = Environ()
}
- e := syscall.Exec(argv0, argv, envv)
+ e := syscall.Exec(name, argv, envv)
if e != 0 {
- return &PathError{"exec", argv0, Errno(e)}
+ return &PathError{"exec", name, Errno(e)}
}
return nil
}
diff --git a/src/pkg/os/file.go b/src/pkg/os/file.go
index be2a30693..3f73f1dff 100644
--- a/src/pkg/os/file.go
+++ b/src/pkg/os/file.go
@@ -46,19 +46,19 @@ var (
// Flags to Open wrapping those of the underlying system. Not all flags
// may be implemented on a given system.
const (
- O_RDONLY = syscall.O_RDONLY // open the file read-only.
- O_WRONLY = syscall.O_WRONLY // open the file write-only.
- O_RDWR = syscall.O_RDWR // open the file read-write.
- O_APPEND = syscall.O_APPEND // open the file append-only.
- O_ASYNC = syscall.O_ASYNC // generate a signal when I/O is available.
- O_CREAT = syscall.O_CREAT // create a new file if none exists.
- O_EXCL = syscall.O_EXCL // used with O_CREAT, file must not exist
- O_NOCTTY = syscall.O_NOCTTY // do not make file the controlling tty.
- O_NONBLOCK = syscall.O_NONBLOCK // open in non-blocking mode.
- O_NDELAY = O_NONBLOCK // synonym for O_NONBLOCK
- O_SYNC = syscall.O_SYNC // open for synchronous I/O.
- O_TRUNC = syscall.O_TRUNC // if possible, truncate file when opened.
- O_CREATE = O_CREAT // create a new file if none exists.
+ O_RDONLY int = syscall.O_RDONLY // open the file read-only.
+ O_WRONLY int = syscall.O_WRONLY // open the file write-only.
+ O_RDWR int = syscall.O_RDWR // open the file read-write.
+ O_APPEND int = syscall.O_APPEND // append data to the file when writing.
+ O_ASYNC int = syscall.O_ASYNC // generate a signal when I/O is available.
+ O_CREAT int = syscall.O_CREAT // create a new file if none exists.
+ O_EXCL int = syscall.O_EXCL // used with O_CREAT, file must not exist
+ O_NOCTTY int = syscall.O_NOCTTY // do not make file the controlling tty.
+ O_NONBLOCK int = syscall.O_NONBLOCK // open in non-blocking mode.
+ O_NDELAY int = O_NONBLOCK // synonym for O_NONBLOCK
+ O_SYNC int = syscall.O_SYNC // open for synchronous I/O.
+ O_TRUNC int = syscall.O_TRUNC // if possible, truncate file when opened.
+ O_CREATE int = O_CREAT // create a new file if none exists.
)
type eofError int
@@ -208,7 +208,7 @@ func Pipe() (r *File, w *File, err Error) {
// Mkdir creates a new directory with the specified name and permission bits.
// It returns an error, if any.
-func Mkdir(name string, perm int) Error {
+func Mkdir(name string, perm uint32) Error {
e := syscall.Mkdir(name, perm)
if e != 0 {
return &PathError{"mkdir", name, Errno(e)}
@@ -358,7 +358,7 @@ func Rename(oldname, newname string) Error {
// 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 int) Error {
+func Chmod(name string, mode uint32) Error {
if e := syscall.Chmod(name, mode); e != 0 {
return &PathError{"chmod", name, Errno(e)}
}
@@ -366,7 +366,7 @@ func Chmod(name string, mode int) Error {
}
// Chmod changes the mode of the file to mode.
-func (f *File) Chmod(mode int) Error {
+func (f *File) Chmod(mode uint32) Error {
if e := syscall.Fchmod(f.fd, mode); e != 0 {
return &PathError{"chmod", f.name, Errno(e)}
}
@@ -408,6 +408,19 @@ func (f *File) Truncate(size int64) Error {
return nil
}
+// Sync commits the current contents of the file to stable storage.
+// Typically, this means flushing the file system's in-memory copy
+// of recently written data to disk.
+func (file *File) Sync() (err Error) {
+ if file == nil {
+ return EINVAL
+ }
+ if e := syscall.Fsync(file.fd); e != 0 {
+ return NewSyscallError("fsync", e)
+ }
+ return nil
+}
+
// Chtimes changes the access and modification times of the named
// file, similar to the Unix utime() or utimes() functions.
//
diff --git a/src/pkg/os/file_unix.go b/src/pkg/os/file_unix.go
index 6cf266140..df5894459 100644
--- a/src/pkg/os/file_unix.go
+++ b/src/pkg/os/file_unix.go
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// The os package provides a platform-independent interface to operating
-// system functionality. The design is Unix-like.
package os
import (
@@ -18,10 +16,14 @@ type dirInfo struct {
bufp int // location of next record in buf.
}
+// DevNull is the name of the operating system's ``null device.''
+// On Unix-like systems, it is "/dev/null"; on Windows, "NUL".
+const DevNull = "/dev/null"
+
// Open opens the named file with specified flag (O_RDONLY etc.) and perm, (0666 etc.)
// if applicable. If successful, methods on the returned File can be used for I/O.
// It returns the File and an Error, if any.
-func Open(name string, flag int, perm int) (file *File, err Error) {
+func Open(name string, flag int, perm uint32) (file *File, err Error) {
r, e := syscall.Open(name, flag|syscall.O_CLOEXEC, perm)
if e != 0 {
return nil, &PathError{"open", name, Errno(e)}
@@ -66,7 +68,7 @@ func (file *File) Stat() (fi *FileInfo, err Error) {
// Readdir reads the contents of the directory associated with file and
// returns an array of up to count FileInfo structures, as would be returned
-// by Stat, in directory order. Subsequent calls on the same file will yield
+// by Lstat, in directory order. Subsequent calls on the same file will yield
// further FileInfos.
// A negative count means to read until EOF.
// Readdir returns the array and an Error, if any.
diff --git a/src/pkg/os/file_windows.go b/src/pkg/os/file_windows.go
index 4f7acbb08..bf710bb67 100644
--- a/src/pkg/os/file_windows.go
+++ b/src/pkg/os/file_windows.go
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// The os package provides a platform-independent interface to operating
-// system functionality. The design is Unix-like.
package os
import (
@@ -17,9 +15,11 @@ type dirInfo struct {
usefirststat bool
}
+const DevNull = "NUL"
+
func (file *File) isdir() bool { return file != nil && file.dirinfo != nil }
-func openFile(name string, flag int, perm int) (file *File, err Error) {
+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)}
@@ -49,16 +49,29 @@ func openDir(name string) (file *File, err Error) {
// Open opens the named file with specified flag (O_RDONLY etc.) and perm, (0666 etc.)
// if applicable. If successful, methods on the returned File can be used for I/O.
// It returns the File and an Error, if any.
-func Open(name string, flag int, perm int) (file *File, err Error) {
+func Open(name string, flag int, perm uint32) (file *File, err Error) {
// 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 r, nil
}
r, e = openFile(name, flag, perm)
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
}
@@ -108,11 +121,17 @@ func (file *File) Stat() (fi *FileInfo, err Error) {
// Readdir reads the contents of the directory associated with file and
// returns an array of up to count FileInfo structures, as would be returned
-// by Stat, in directory order. Subsequent calls on the same file will yield
+// by Lstat, in directory order. Subsequent calls on the same file will yield
// further FileInfos.
// A negative count means to read until EOF.
// Readdir returns the array and an Error, if any.
func (file *File) Readdir(count int) (fi []FileInfo, err Error) {
+ if file == nil || file.fd < 0 {
+ return nil, EINVAL
+ }
+ if !file.isdir() {
+ return nil, &PathError{"Readdir", file.name, ENOTDIR}
+ }
di := file.dirinfo
size := count
if size < 0 {
@@ -138,15 +157,7 @@ func (file *File) Readdir(count int) (fi []FileInfo, err Error) {
continue
}
count--
- if len(fi) == cap(fi) {
- nfi := make([]FileInfo, len(fi), 2*len(fi))
- for i := 0; i < len(fi); i++ {
- nfi[i] = fi[i]
- }
- fi = nfi
- }
- fi = fi[0 : len(fi)+1]
- fi[len(fi)-1] = f
+ fi = append(fi, f)
}
return fi, nil
}
diff --git a/src/pkg/os/inotify/Makefile b/src/pkg/os/inotify/Makefile
new file mode 100644
index 000000000..90e18da57
--- /dev/null
+++ b/src/pkg/os/inotify/Makefile
@@ -0,0 +1,14 @@
+# Copyright 2010 The Go Authors. 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
new file mode 100644
index 000000000..1e74c7fbc
--- /dev/null
+++ b/src/pkg/os/inotify/inotify_linux.go
@@ -0,0 +1,291 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+This package implements a wrapper for the Linux inotify system.
+
+Example:
+ watcher, err := inotify.NewWatcher()
+ if err != nil {
+ log.Exit(err)
+ }
+ err = watcher.Watch("/tmp")
+ if err != nil {
+ log.Exit(err)
+ }
+ for {
+ select {
+ case ev := <-watcher.Event:
+ log.Println("event:", ev)
+ case err := <-watcher.Error:
+ log.Println("error:", err)
+ }
+ }
+
+*/
+package inotify
+
+import (
+ "fmt"
+ "os"
+ "strings"
+ "syscall"
+ "unsafe"
+)
+
+
+type Event struct {
+ Mask uint32 // Mask of events
+ Cookie uint32 // Unique cookie associating related events (for rename(2))
+ Name string // File name (optional)
+}
+
+type watch struct {
+ wd uint32 // Watch descriptor (as returned by the inotify_add_watch() syscall)
+ flags uint32 // inotify flags of this watch (see inotify(7) for the list of valid flags)
+}
+
+type Watcher struct {
+ fd int // File descriptor (as returned by the inotify_init() syscall)
+ watches map[string]*watch // Map of inotify watches (key: path)
+ paths map[int]string // Map of watched paths (key: watch descriptor)
+ Error chan os.Error // Errors are sent on this channel
+ Event chan *Event // Events are returned on this channel
+ done chan bool // Channel for sending a "quit message" to the reader goroutine
+ isClosed bool // Set to true when Close() is first called
+}
+
+
+// NewWatcher creates and returns a new inotify instance using inotify_init(2)
+func NewWatcher() (*Watcher, os.Error) {
+ fd, errno := syscall.InotifyInit()
+ if fd == -1 {
+ return nil, os.NewSyscallError("inotify_init", errno)
+ }
+ w := &Watcher{
+ fd: fd,
+ watches: make(map[string]*watch),
+ paths: make(map[int]string),
+ Event: make(chan *Event),
+ Error: make(chan os.Error),
+ done: make(chan bool, 1),
+ }
+
+ go w.readEvents()
+ return w, nil
+}
+
+
+// Close closes an inotify watcher instance
+// It sends a message to the reader goroutine to quit and removes all watches
+// associated with the inotify instance
+func (w *Watcher) Close() os.Error {
+ if w.isClosed {
+ return nil
+ }
+ w.isClosed = true
+
+ // Send "quit" message to the reader goroutine
+ w.done <- true
+ for path := range w.watches {
+ w.RemoveWatch(path)
+ }
+
+ return nil
+}
+
+// AddWatch adds path to the watched file set.
+// The flags are interpreted as described in inotify_add_watch(2).
+func (w *Watcher) AddWatch(path string, flags uint32) os.Error {
+ if w.isClosed {
+ return os.NewError("inotify instance already closed")
+ }
+
+ watchEntry, found := w.watches[path]
+ if found {
+ watchEntry.flags |= flags
+ flags |= syscall.IN_MASK_ADD
+ }
+ wd, errno := syscall.InotifyAddWatch(w.fd, path, flags)
+ if wd == -1 {
+ return os.NewSyscallError("inotify_add_watch", errno)
+ }
+
+ if !found {
+ w.watches[path] = &watch{wd: uint32(wd), flags: flags}
+ w.paths[wd] = path
+ }
+ return nil
+}
+
+
+// Watch adds path to the watched file set, watching all events.
+func (w *Watcher) Watch(path string) os.Error {
+ return w.AddWatch(path, IN_ALL_EVENTS)
+}
+
+
+// RemoveWatch removes path from the watched file set.
+func (w *Watcher) RemoveWatch(path string) os.Error {
+ watch, ok := w.watches[path]
+ if !ok {
+ return os.NewError(fmt.Sprintf("can't remove non-existent inotify watch for: %s", path))
+ }
+ success, errno := syscall.InotifyRmWatch(w.fd, watch.wd)
+ if success == -1 {
+ return os.NewSyscallError("inotify_rm_watch", errno)
+ }
+ w.watches[path] = nil, false
+ return nil
+}
+
+
+// readEvents reads from the inotify file descriptor, converts the
+// received events into Event objects and sends them via the Event channel
+func (w *Watcher) readEvents() {
+ var (
+ buf [syscall.SizeofInotifyEvent * 4096]byte // Buffer for a maximum of 4096 raw events
+ n int // Number of bytes read with read()
+ errno int // Syscall errno
+ )
+
+ for {
+ n, errno = syscall.Read(w.fd, buf[0:])
+ // See if there is a message on the "done" channel
+ _, done := <-w.done
+
+ // If EOF or a "done" message is received
+ if n == 0 || done {
+ errno := syscall.Close(w.fd)
+ if errno == -1 {
+ w.Error <- os.NewSyscallError("close", errno)
+ }
+ close(w.Event)
+ close(w.Error)
+ return
+ }
+ if n < 0 {
+ w.Error <- os.NewSyscallError("read", errno)
+ continue
+ }
+ if n < syscall.SizeofInotifyEvent {
+ w.Error <- os.NewError("inotify: short read in readEvents()")
+ continue
+ }
+
+ var offset uint32 = 0
+ // We don't know how many events we just read into the buffer
+ // While the offset points to at least one whole event...
+ for offset <= uint32(n-syscall.SizeofInotifyEvent) {
+ // Point "raw" to the event in the buffer
+ raw := (*syscall.InotifyEvent)(unsafe.Pointer(&buf[offset]))
+ event := new(Event)
+ event.Mask = uint32(raw.Mask)
+ event.Cookie = uint32(raw.Cookie)
+ nameLen := uint32(raw.Len)
+ // If the event happened to the watched directory or the watched file, the kernel
+ // doesn't append the filename to the event, but we would like to always fill the
+ // the "Name" field with a valid filename. We retrieve the path of the watch from
+ // the "paths" map.
+ event.Name = w.paths[int(raw.Wd)]
+ if nameLen > 0 {
+ // Point "bytes" at the first byte of the filename
+ bytes := (*[syscall.PathMax]byte)(unsafe.Pointer(&buf[offset+syscall.SizeofInotifyEvent]))
+ // The filename is padded with NUL bytes. TrimRight() gets rid of those.
+ event.Name += "/" + strings.TrimRight(string(bytes[0:nameLen]), "\000")
+ }
+ // Send the event on the events channel
+ w.Event <- event
+
+ // Move to the next event in the buffer
+ offset += syscall.SizeofInotifyEvent + nameLen
+ }
+ }
+}
+
+
+// String formats the event e in the form
+// "filename: 0xEventMask = IN_ACCESS|IN_ATTRIB_|..."
+func (e *Event) String() string {
+ var events string = ""
+
+ m := e.Mask
+ for _, b := range eventBits {
+ if m&b.Value != 0 {
+ m &^= b.Value
+ events += "|" + b.Name
+ }
+ }
+
+ if m != 0 {
+ events += fmt.Sprintf("|%#x", m)
+ }
+ if len(events) > 0 {
+ events = " == " + events[1:]
+ }
+
+ return fmt.Sprintf("%q: %#x%s", e.Name, e.Mask, events)
+}
+
+const (
+ // Options for inotify_init() are not exported
+ // IN_CLOEXEC uint32 = syscall.IN_CLOEXEC
+ // IN_NONBLOCK uint32 = syscall.IN_NONBLOCK
+
+ // Options for AddWatch
+ IN_DONT_FOLLOW uint32 = syscall.IN_DONT_FOLLOW
+ IN_ONESHOT uint32 = syscall.IN_ONESHOT
+ IN_ONLYDIR uint32 = syscall.IN_ONLYDIR
+
+ // The "IN_MASK_ADD" option is not exported, as AddWatch
+ // adds it automatically, if there is already a watch for the given path
+ // IN_MASK_ADD uint32 = syscall.IN_MASK_ADD
+
+ // Events
+ IN_ACCESS uint32 = syscall.IN_ACCESS
+ IN_ALL_EVENTS uint32 = syscall.IN_ALL_EVENTS
+ IN_ATTRIB uint32 = syscall.IN_ATTRIB
+ IN_CLOSE uint32 = syscall.IN_CLOSE
+ IN_CLOSE_NOWRITE uint32 = syscall.IN_CLOSE_NOWRITE
+ IN_CLOSE_WRITE uint32 = syscall.IN_CLOSE_WRITE
+ IN_CREATE uint32 = syscall.IN_CREATE
+ IN_DELETE uint32 = syscall.IN_DELETE
+ IN_DELETE_SELF uint32 = syscall.IN_DELETE_SELF
+ IN_MODIFY uint32 = syscall.IN_MODIFY
+ IN_MOVE uint32 = syscall.IN_MOVE
+ IN_MOVED_FROM uint32 = syscall.IN_MOVED_FROM
+ IN_MOVED_TO uint32 = syscall.IN_MOVED_TO
+ IN_MOVE_SELF uint32 = syscall.IN_MOVE_SELF
+ IN_OPEN uint32 = syscall.IN_OPEN
+
+ // Special events
+ IN_ISDIR uint32 = syscall.IN_ISDIR
+ IN_IGNORED uint32 = syscall.IN_IGNORED
+ IN_Q_OVERFLOW uint32 = syscall.IN_Q_OVERFLOW
+ IN_UNMOUNT uint32 = syscall.IN_UNMOUNT
+)
+
+var eventBits = []struct {
+ Value uint32
+ Name string
+}{
+ {IN_ACCESS, "IN_ACCESS"},
+ {IN_ATTRIB, "IN_ATTRIB"},
+ {IN_CLOSE, "IN_CLOSE"},
+ {IN_CLOSE_NOWRITE, "IN_CLOSE_NOWRITE"},
+ {IN_CLOSE_WRITE, "IN_CLOSE_WRITE"},
+ {IN_CREATE, "IN_CREATE"},
+ {IN_DELETE, "IN_DELETE"},
+ {IN_DELETE_SELF, "IN_DELETE_SELF"},
+ {IN_MODIFY, "IN_MODIFY"},
+ {IN_MOVE, "IN_MOVE"},
+ {IN_MOVED_FROM, "IN_MOVED_FROM"},
+ {IN_MOVED_TO, "IN_MOVED_TO"},
+ {IN_MOVE_SELF, "IN_MOVE_SELF"},
+ {IN_OPEN, "IN_OPEN"},
+ {IN_ISDIR, "IN_ISDIR"},
+ {IN_IGNORED, "IN_IGNORED"},
+ {IN_Q_OVERFLOW, "IN_Q_OVERFLOW"},
+ {IN_UNMOUNT, "IN_UNMOUNT"},
+}
diff --git a/src/pkg/os/inotify/inotify_linux_test.go b/src/pkg/os/inotify/inotify_linux_test.go
new file mode 100644
index 000000000..332edcb64
--- /dev/null
+++ b/src/pkg/os/inotify/inotify_linux_test.go
@@ -0,0 +1,99 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package inotify
+
+import (
+ "os"
+ "time"
+ "testing"
+)
+
+func TestInotifyEvents(t *testing.T) {
+ // Create an inotify watcher instance and initialize it
+ watcher, err := NewWatcher()
+ if err != nil {
+ t.Fatalf("NewWatcher() failed: %s", err)
+ }
+
+ // Add a watch for "_obj"
+ err = watcher.Watch("_obj")
+ if err != nil {
+ t.Fatalf("Watcher.Watch() failed: %s", err)
+ }
+
+ // Receive errors on the error channel on a separate goroutine
+ go func() {
+ for err := range watcher.Error {
+ t.Fatalf("error received: %s", err)
+ }
+ }()
+
+ const testFile string = "_obj/TestInotifyEvents.testfile"
+
+ // Receive events on the event channel on a separate goroutine
+ eventstream := watcher.Event
+ var eventsReceived = 0
+ go func() {
+ for event := range eventstream {
+ // Only count relevant events
+ if event.Name == testFile {
+ eventsReceived++
+ t.Logf("event received: %s", event)
+ } else {
+ t.Logf("unexpected event received: %s", event)
+ }
+ }
+ }()
+
+ // Create a file
+ // This should add at least one event to the inotify event queue
+ _, err = os.Open(testFile, os.O_WRONLY|os.O_CREAT, 0666)
+ if err != nil {
+ t.Fatalf("creating test file failed: %s", err)
+ }
+
+ // We expect this event to be received almost immediately, but let's wait 1 s to be sure
+ time.Sleep(1000e6) // 1000 ms
+ if eventsReceived == 0 {
+ t.Fatal("inotify event hasn't been received after 1 second")
+ }
+
+ // Try closing the inotify instance
+ t.Log("calling Close()")
+ watcher.Close()
+ t.Log("waiting for the event channel to become closed...")
+ var i = 0
+ for !closed(eventstream) {
+ if i >= 20 {
+ t.Fatal("event stream was not closed after 1 second, as expected")
+ }
+ t.Log("waiting for 50 ms...")
+ time.Sleep(50e6) // 50 ms
+ i++
+ }
+ t.Log("event channel closed")
+}
+
+
+func TestInotifyClose(t *testing.T) {
+ watcher, _ := NewWatcher()
+ watcher.Close()
+
+ done := false
+ go func() {
+ watcher.Close()
+ done = true
+ }()
+
+ time.Sleep(50e6) // 50 ms
+ if !done {
+ t.Fatal("double Close() test failed: second Close() call didn't return")
+ }
+
+ err := watcher.Watch("_obj")
+ if err == nil {
+ t.Fatal("expected error on Watch() after Close(), got nil")
+ }
+}
diff --git a/src/pkg/os/os_test.go b/src/pkg/os/os_test.go
index 6827c3f60..49b58c83c 100644
--- a/src/pkg/os/os_test.go
+++ b/src/pkg/os/os_test.go
@@ -11,13 +11,14 @@ import (
"io/ioutil"
. "os"
"strings"
+ "syscall"
"testing"
)
var dot = []string{
"dir_darwin.go",
"dir_linux.go",
- "env.go",
+ "env_unix.go",
"error.go",
"file.go",
"os_test.go",
@@ -27,12 +28,36 @@ var dot = []string{
"stat_linux.go",
}
-var etc = []string{
- "group",
- "hosts",
- "passwd",
+type sysDir struct {
+ name string
+ files []string
}
+var sysdir = func() (sd *sysDir) {
+ switch syscall.OS {
+ case "windows":
+ sd = &sysDir{
+ Getenv("SystemRoot") + "\\system32\\drivers\\etc",
+ []string{
+ "hosts",
+ "networks",
+ "protocol",
+ "services",
+ },
+ }
+ default:
+ sd = &sysDir{
+ "/etc",
+ []string{
+ "group",
+ "hosts",
+ "passwd",
+ },
+ }
+ }
+ return
+}()
+
func size(name string, t *testing.T) int64 {
file, err := Open(name, O_RDONLY, 0)
defer file.Close()
@@ -54,22 +79,52 @@ func size(name string, t *testing.T) int64 {
return int64(len)
}
+func equal(name1, name2 string) (r bool) {
+ switch syscall.OS {
+ case "windows":
+ r = strings.ToLower(name1) == strings.ToLower(name2)
+ default:
+ r = name1 == name2
+ }
+ return
+}
+
+func newFile(testName string, t *testing.T) (f *File) {
+ // Use a local file system, not NFS.
+ // On Unix, override $TMPDIR in case the user
+ // has it set to an NFS-mounted directory.
+ dir := ""
+ if syscall.OS != "windows" {
+ dir = "/tmp"
+ }
+ f, err := ioutil.TempFile(dir, "_Go_"+testName)
+ if err != nil {
+ t.Fatalf("open %s: %s", testName, err)
+ }
+ return
+}
+
+var sfdir = sysdir.name
+var sfname = sysdir.files[0]
+
func TestStat(t *testing.T) {
- dir, err := Stat("/etc/passwd")
+ path := sfdir + "/" + sfname
+ dir, err := Stat(path)
if err != nil {
t.Fatal("stat failed:", err)
}
- if dir.Name != "passwd" {
- t.Error("name should be passwd; is", dir.Name)
+ if !equal(sfname, dir.Name) {
+ t.Error("name should be ", sfname, "; is", dir.Name)
}
- filesize := size("/etc/passwd", t)
+ filesize := size(path, t)
if dir.Size != filesize {
t.Error("size should be", filesize, "; is", dir.Size)
}
}
func TestFstat(t *testing.T) {
- file, err1 := Open("/etc/passwd", O_RDONLY, 0)
+ path := sfdir + "/" + sfname
+ file, err1 := Open(path, O_RDONLY, 0)
defer file.Close()
if err1 != nil {
t.Fatal("open failed:", err1)
@@ -78,24 +133,25 @@ func TestFstat(t *testing.T) {
if err2 != nil {
t.Fatal("fstat failed:", err2)
}
- if dir.Name != "passwd" {
- t.Error("name should be passwd; is", dir.Name)
+ if !equal(sfname, dir.Name) {
+ t.Error("name should be ", sfname, "; is", dir.Name)
}
- filesize := size("/etc/passwd", t)
+ filesize := size(path, t)
if dir.Size != filesize {
t.Error("size should be", filesize, "; is", dir.Size)
}
}
func TestLstat(t *testing.T) {
- dir, err := Lstat("/etc/passwd")
+ path := sfdir + "/" + sfname
+ dir, err := Lstat(path)
if err != nil {
t.Fatal("lstat failed:", err)
}
- if dir.Name != "passwd" {
- t.Error("name should be passwd; is", dir.Name)
+ if !equal(sfname, dir.Name) {
+ t.Error("name should be ", sfname, "; is", dir.Name)
}
- filesize := size("/etc/passwd", t)
+ filesize := size(path, t)
if dir.Size != filesize {
t.Error("size should be", filesize, "; is", dir.Size)
}
@@ -109,7 +165,7 @@ func testReaddirnames(dir string, contents []string, t *testing.T) {
}
s, err2 := file.Readdirnames(-1)
if err2 != nil {
- t.Fatalf("readdirnames %q failed: %v", err2)
+ t.Fatalf("readdirnames %q failed: %v", dir, err2)
}
for _, m := range contents {
found := false
@@ -117,7 +173,7 @@ func testReaddirnames(dir string, contents []string, t *testing.T) {
if n == "." || n == ".." {
t.Errorf("got %s in directory", n)
}
- if m == n {
+ if equal(m, n) {
if found {
t.Error("present twice:", m)
}
@@ -143,7 +199,7 @@ func testReaddir(dir string, contents []string, t *testing.T) {
for _, m := range contents {
found := false
for _, n := range s {
- if m == n.Name {
+ if equal(m, n.Name) {
if found {
t.Error("present twice:", m)
}
@@ -158,12 +214,12 @@ func testReaddir(dir string, contents []string, t *testing.T) {
func TestReaddirnames(t *testing.T) {
testReaddirnames(".", dot, t)
- testReaddirnames("/etc", etc, t)
+ testReaddirnames(sysdir.name, sysdir.files, t)
}
func TestReaddir(t *testing.T) {
testReaddir(".", dot, t)
- testReaddir("/etc", etc, t)
+ testReaddir(sysdir.name, sysdir.files, t)
}
// Read the directory one entry at a time.
@@ -187,7 +243,11 @@ func smallReaddirnames(file *File, length int, t *testing.T) []string {
// Check that reading a directory one entry at a time gives the same result
// as reading it all at once.
func TestReaddirnamesOneAtATime(t *testing.T) {
- dir := "/usr/bin" // big directory that doesn't change often.
+ // big directory that doesn't change often.
+ dir := "/usr/bin"
+ if syscall.OS == "windows" {
+ dir = Getenv("SystemRoot") + "\\system32"
+ }
file, err := Open(dir, O_RDONLY, 0)
defer file.Close()
if err != nil {
@@ -204,12 +264,16 @@ func TestReaddirnamesOneAtATime(t *testing.T) {
small := smallReaddirnames(file1, len(all)+100, t) // +100 in case we screw up
for i, n := range all {
if small[i] != n {
- t.Errorf("small read %q %q mismatch: %v", small[i], n)
+ t.Errorf("small read %q mismatch: %v", small[i], n)
}
}
}
func TestHardLink(t *testing.T) {
+ // Hardlinks are not supported under windows.
+ if syscall.OS == "windows" {
+ return
+ }
from, to := "hardlinktestfrom", "hardlinktestto"
Remove(from) // Just in case.
file, err := Open(to, O_CREAT|O_WRONLY, 0666)
@@ -239,6 +303,10 @@ func TestHardLink(t *testing.T) {
}
func TestSymLink(t *testing.T) {
+ // Symlinks are not supported under windows.
+ if syscall.OS == "windows" {
+ return
+ }
from, to := "symlinktestfrom", "symlinktestto"
Remove(from) // Just in case.
file, err := Open(to, O_CREAT|O_WRONLY, 0666)
@@ -280,7 +348,7 @@ func TestSymLink(t *testing.T) {
t.Fatalf("stat %q failed: %v", from, err)
}
if !fromstat.FollowedSymlink {
- t.Fatalf("stat %q did not follow symlink")
+ t.Fatalf("stat %q did not follow symlink", from)
}
s, err := Readlink(from)
if err != nil {
@@ -297,6 +365,10 @@ func TestSymLink(t *testing.T) {
}
func TestLongSymlink(t *testing.T) {
+ // Symlinks are not supported under windows.
+ if syscall.OS == "windows" {
+ return
+ }
s := "0123456789abcdef"
// Long, but not too long: a common limit is 255.
s = s + s + s + s + s + s + s + s + s + s + s + s + s + s + s
@@ -338,11 +410,24 @@ func TestRename(t *testing.T) {
}
func TestForkExec(t *testing.T) {
+ var cmd, adir, expect string
+ var args []string
r, w, err := Pipe()
if err != nil {
t.Fatalf("Pipe: %v", err)
}
- pid, err := ForkExec("/bin/pwd", []string{"pwd"}, nil, "/", []*File{nil, w, Stderr})
+ if syscall.OS == "windows" {
+ cmd = Getenv("COMSPEC")
+ args = []string{Getenv("COMSPEC"), "/c cd"}
+ adir = Getenv("SystemRoot")
+ expect = Getenv("SystemRoot") + "\r\n"
+ } else {
+ cmd = "/bin/pwd"
+ args = []string{"pwd"}
+ adir = "/"
+ expect = "/\n"
+ }
+ pid, err := ForkExec(cmd, args, nil, adir, []*File{nil, w, Stderr})
if err != nil {
t.Fatalf("ForkExec: %v", err)
}
@@ -351,9 +436,9 @@ func TestForkExec(t *testing.T) {
var b bytes.Buffer
io.Copy(&b, r)
output := b.String()
- expect := "/\n"
if output != expect {
- t.Errorf("exec /bin/pwd returned %q wanted %q", output, expect)
+ args[0] = cmd
+ t.Errorf("exec %q returned %q wanted %q", strings.Join(args, " "), output, expect)
}
Wait(pid, 0)
}
@@ -369,25 +454,23 @@ func checkMode(t *testing.T, path string, mode uint32) {
}
func TestChmod(t *testing.T) {
- MkdirAll("_obj", 0777)
- const Path = "_obj/_TestChmod_"
- fd, err := Open(Path, O_WRONLY|O_CREAT, 0666)
- if err != nil {
- t.Fatalf("create %s: %s", Path, err)
+ // Chmod is not supported under windows.
+ if syscall.OS == "windows" {
+ return
}
+ f := newFile("TestChmod", t)
+ defer Remove(f.Name())
+ defer f.Close()
- if err = Chmod(Path, 0456); err != nil {
- t.Fatalf("chmod %s 0456: %s", Path, err)
+ if err := Chmod(f.Name(), 0456); err != nil {
+ t.Fatalf("chmod %s 0456: %s", f.Name(), err)
}
- checkMode(t, Path, 0456)
+ checkMode(t, f.Name(), 0456)
- if err = fd.Chmod(0123); err != nil {
- t.Fatalf("fchmod %s 0123: %s", Path, err)
+ if err := f.Chmod(0123); err != nil {
+ t.Fatalf("chmod %s 0123: %s", f.Name(), err)
}
- checkMode(t, Path, 0123)
-
- fd.Close()
- Remove(Path)
+ checkMode(t, f.Name(), 0123)
}
func checkUidGid(t *testing.T, path string, uid, gid int) {
@@ -404,31 +487,30 @@ func checkUidGid(t *testing.T, path string, uid, gid int) {
}
func TestChown(t *testing.T) {
- // Use /tmp, not _obj, to make sure we're on a local file system,
+ // Chown is not supported under windows.
+ if syscall.OS == "windows" {
+ return
+ }
+ // Use TempDir() to make sure we're on a local file system,
// so that the group ids returned by Getgroups will be allowed
- // on the file. If _obj is on NFS, the Getgroups groups are
+ // on the file. On NFS, the Getgroups groups are
// basically useless.
-
- const Path = "/tmp/_TestChown_"
- fd, err := Open(Path, O_WRONLY|O_CREAT, 0666)
+ f := newFile("TestChown", t)
+ defer Remove(f.Name())
+ defer f.Close()
+ dir, err := f.Stat()
if err != nil {
- t.Fatalf("create %s: %s", Path, err)
+ t.Fatalf("stat %s: %s", f.Name(), err)
}
- dir, err := fd.Stat()
- if err != nil {
- t.Fatalf("fstat %s: %s", Path, err)
- }
- defer fd.Close()
- defer Remove(Path)
// 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(Path, -1, gid); err != nil {
- t.Fatalf("chown %s -1 %d: %s", Path, gid, err)
+ if err = Chown(f.Name(), -1, gid); err != nil {
+ t.Fatalf("chown %s -1 %d: %s", f.Name(), gid, err)
}
- checkUidGid(t, Path, dir.Uid, gid)
+ checkUidGid(t, f.Name(), dir.Uid, gid)
// Then try all the auxiliary groups.
groups, err := Getgroups()
@@ -437,77 +519,74 @@ func TestChown(t *testing.T) {
}
t.Log("groups: ", groups)
for _, g := range groups {
- if err = Chown(Path, -1, g); err != nil {
- t.Fatalf("chown %s -1 %d: %s", Path, g, err)
+ if err = Chown(f.Name(), -1, g); err != nil {
+ t.Fatalf("chown %s -1 %d: %s", f.Name(), g, err)
}
- checkUidGid(t, Path, dir.Uid, g)
+ checkUidGid(t, f.Name(), dir.Uid, g)
// change back to gid to test fd.Chown
- if err = fd.Chown(-1, gid); err != nil {
- t.Fatalf("fchown %s -1 %d: %s", Path, gid, err)
+ if err = f.Chown(-1, gid); err != nil {
+ t.Fatalf("fchown %s -1 %d: %s", f.Name(), gid, err)
}
- checkUidGid(t, Path, dir.Uid, gid)
+ checkUidGid(t, f.Name(), dir.Uid, gid)
}
}
-func checkSize(t *testing.T, path string, size int64) {
- dir, err := Stat(path)
+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", path, size, err)
+ 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", path, dir.Size, size)
+ t.Errorf("Stat %q: size %d want %d", f.Name(), dir.Size, size)
}
}
func TestTruncate(t *testing.T) {
- MkdirAll("_obj", 0777)
- const Path = "_obj/_TestTruncate_"
- fd, err := Open(Path, O_WRONLY|O_CREAT, 0666)
- if err != nil {
- t.Fatalf("create %s: %s", Path, err)
- }
-
- checkSize(t, Path, 0)
- fd.Write([]byte("hello, world\n"))
- checkSize(t, Path, 13)
- fd.Truncate(10)
- checkSize(t, Path, 10)
- fd.Truncate(1024)
- checkSize(t, Path, 1024)
- fd.Truncate(0)
- checkSize(t, Path, 0)
- fd.Write([]byte("surprise!"))
- checkSize(t, Path, 13+9) // wrote at offset past where hello, world was.
- fd.Close()
- Remove(Path)
-}
-
+ f := newFile("TestTruncate", t)
+ defer Remove(f.Name())
+ defer f.Close()
+
+ checkSize(t, f, 0)
+ f.Write([]byte("hello, world\n"))
+ checkSize(t, f, 13)
+ f.Truncate(10)
+ checkSize(t, f, 10)
+ f.Truncate(1024)
+ checkSize(t, f, 1024)
+ f.Truncate(0)
+ checkSize(t, f, 0)
+ f.Write([]byte("surprise!"))
+ checkSize(t, f, 13+9) // wrote at offset past where hello, world was.
+}
+
+// Use TempDir() to make sure we're on a local file system,
+// so that timings are not distorted by latency and caching.
+// On NFS, timings can be off due to caching of meta-data on
+// NFS servers (Issue 848).
func TestChtimes(t *testing.T) {
- MkdirAll("_obj", 0777)
- const Path = "_obj/_TestChtimes_"
- fd, err := Open(Path, O_WRONLY|O_CREAT, 0666)
- if err != nil {
- t.Fatalf("create %s: %s", Path, err)
- }
- fd.Write([]byte("hello, world\n"))
- fd.Close()
+ f := newFile("TestChtimes", t)
+ defer Remove(f.Name())
+ defer f.Close()
- preStat, err := Stat(Path)
+ f.Write([]byte("hello, world\n"))
+ f.Close()
+
+ preStat, err := Stat(f.Name())
if err != nil {
- t.Fatalf("Stat %s: %s", Path, err)
+ t.Fatalf("Stat %s: %s", f.Name(), err)
}
// Move access and modification time back a second
const OneSecond = 1e9 // in nanoseconds
- err = Chtimes(Path, preStat.Atime_ns-OneSecond, preStat.Mtime_ns-OneSecond)
+ err = Chtimes(f.Name(), preStat.Atime_ns-OneSecond, preStat.Mtime_ns-OneSecond)
if err != nil {
- t.Fatalf("Chtimes %s: %s", Path, err)
+ t.Fatalf("Chtimes %s: %s", f.Name(), err)
}
- postStat, err := Stat(Path)
+ postStat, err := Stat(f.Name())
if err != nil {
- t.Fatalf("second Stat %s: %s", Path, err)
+ t.Fatalf("second Stat %s: %s", f.Name(), err)
}
if postStat.Atime_ns >= preStat.Atime_ns {
@@ -521,11 +600,13 @@ func TestChtimes(t *testing.T) {
preStat.Mtime_ns,
postStat.Mtime_ns)
}
-
- Remove(Path)
}
func TestChdirAndGetwd(t *testing.T) {
+ // TODO(brainman): file.Chdir() is not implemented on windows.
+ if syscall.OS == "windows" {
+ return
+ }
fd, err := Open(".", O_RDONLY, 0)
if err != nil {
t.Fatalf("Open .: %s", err)
@@ -586,10 +667,9 @@ func TestTime(t *testing.T) {
}
func TestSeek(t *testing.T) {
- f, err := Open("_obj/seektest", O_CREAT|O_RDWR|O_TRUNC, 0666)
- if err != nil {
- t.Fatalf("open _obj/seektest: %s", err)
- }
+ f := newFile("TestSeek", t)
+ defer Remove(f.Name())
+ defer f.Close()
const data = "hello, world\n"
io.WriteString(f, data)
@@ -600,14 +680,14 @@ func TestSeek(t *testing.T) {
out int64
}
var tests = []test{
- test{0, 1, int64(len(data))},
- test{0, 0, 0},
- test{5, 0, 5},
- test{0, 2, int64(len(data))},
- test{0, 0, 0},
- test{-1, 2, int64(len(data)) - 1},
- test{1 << 33, 0, 1 << 33},
- test{1 << 33, 2, 1<<33 + int64(len(data))},
+ {0, 1, int64(len(data))},
+ {0, 0, 0},
+ {5, 0, 5},
+ {0, 2, int64(len(data))},
+ {0, 0, 0},
+ {-1, 2, int64(len(data)) - 1},
+ {1 << 33, 0, 1 << 33},
+ {1 << 33, 2, 1<<33 + int64(len(data))},
}
for i, tt := range tests {
off, err := f.Seek(tt.in, tt.whence)
@@ -620,30 +700,29 @@ func TestSeek(t *testing.T) {
t.Errorf("#%d: Seek(%v, %v) = %v, %v want %v, nil", i, tt.in, tt.whence, off, err, tt.out)
}
}
- f.Close()
}
type openErrorTest struct {
path string
mode int
- error string
+ error Error
}
var openErrorTests = []openErrorTest{
- openErrorTest{
- "/etc/no-such-file",
+ {
+ sfdir + "/no-such-file",
O_RDONLY,
- "open /etc/no-such-file: no such file or directory",
+ ENOENT,
},
- openErrorTest{
- "/etc",
+ {
+ sfdir,
O_WRONLY,
- "open /etc: is a directory",
+ EISDIR,
},
- openErrorTest{
- "/etc/passwd/group",
+ {
+ sfdir + "/" + sfname + "/no-such-file",
O_WRONLY,
- "open /etc/passwd/group: not a directory",
+ ENOTDIR,
},
}
@@ -655,8 +734,12 @@ func TestOpenError(t *testing.T) {
f.Close()
continue
}
- if s := err.String(); s != tt.error {
- t.Errorf("Open(%q, %d) = _, %q; want %q", tt.path, tt.mode, s, tt.error)
+ perr, ok := err.(*PathError)
+ if !ok {
+ t.Errorf("Open(%q, %d) returns error of %T type; want *os.PathError", tt.path, tt.mode, err)
+ }
+ if perr.Error != tt.error {
+ t.Errorf("Open(%q, %d) = _, %q; want %q", tt.path, tt.mode, perr.Error.String(), tt.error.String())
}
}
}
@@ -689,6 +772,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.
+ if syscall.OS == "windows" {
+ return
+ }
// Check internal Hostname() against the output of /bin/hostname.
// Allow that the internal Hostname returns a Fully Qualified Domain Name
// and the /bin/hostname only returns the first component
@@ -706,10 +793,10 @@ func TestHostname(t *testing.T) {
}
func TestReadAt(t *testing.T) {
- f, err := Open("_obj/readtest", O_CREAT|O_RDWR|O_TRUNC, 0666)
- if err != nil {
- t.Fatalf("open _obj/readtest: %s", err)
- }
+ f := newFile("TestReadAt", t)
+ defer Remove(f.Name())
+ defer f.Close()
+
const data = "hello, world\n"
io.WriteString(f, data)
@@ -724,10 +811,10 @@ func TestReadAt(t *testing.T) {
}
func TestWriteAt(t *testing.T) {
- f, err := Open("_obj/writetest", O_CREAT|O_RDWR|O_TRUNC, 0666)
- if err != nil {
- t.Fatalf("open _obj/writetest: %s", err)
- }
+ f := newFile("TestWriteAt", t)
+ defer Remove(f.Name())
+ defer f.Close()
+
const data = "hello, world\n"
io.WriteString(f, data)
@@ -736,11 +823,64 @@ func TestWriteAt(t *testing.T) {
t.Fatalf("WriteAt 7: %d, %v", n, err)
}
- b, err := ioutil.ReadFile("_obj/writetest")
+ b, err := ioutil.ReadFile(f.Name())
if err != nil {
- t.Fatalf("ReadFile _obj/writetest: %v", err)
+ t.Fatalf("ReadFile %s: %v", f.Name(), err)
}
if string(b) != "hello, WORLD\n" {
t.Fatalf("after write: have %q want %q", string(b), "hello, WORLD\n")
}
}
+
+func writeFile(t *testing.T, fname string, flag int, text string) string {
+ f, err := Open(fname, flag, 0666)
+ if err != nil {
+ t.Fatalf("Open: %v", err)
+ }
+ n, err := io.WriteString(f, text)
+ if err != nil {
+ t.Fatalf("WriteString: %d, %v", n, err)
+ }
+ f.Close()
+ data, err := ioutil.ReadFile(fname)
+ if err != nil {
+ t.Fatalf("ReadFile: %v", err)
+ }
+ return string(data)
+}
+
+func TestAppend(t *testing.T) {
+ const f = "append.txt"
+ defer Remove(f)
+ s := writeFile(t, f, O_CREAT|O_TRUNC|O_RDWR, "new")
+ if s != "new" {
+ t.Fatalf("writeFile: have %q want %q", s, "new")
+ }
+ s = writeFile(t, f, O_APPEND|O_RDWR, "|append")
+ if s != "new|append" {
+ t.Fatalf("writeFile: have %q want %q", s, "new|append")
+ }
+}
+
+func TestStatDirWithTrailingSlash(t *testing.T) {
+ // Create new dir, in _test so it will get
+ // cleaned up by make if not by us.
+ path := "_test/_TestStatDirWithSlash_"
+ err := MkdirAll(path, 0777)
+ if err != nil {
+ t.Fatalf("MkdirAll %q: %s", path, err)
+ }
+ defer RemoveAll(path)
+
+ // Stat of path should succeed.
+ _, err = Stat(path)
+ if err != nil {
+ t.Fatal("stat failed:", err)
+ }
+
+ // Stat of path+"/" should succeed too.
+ _, err = Stat(path + "/")
+ if err != nil {
+ t.Fatal("stat failed:", err)
+ }
+}
diff --git a/src/pkg/os/path.go b/src/pkg/os/path.go
index 36f497a1a..b762971d9 100644
--- a/src/pkg/os/path.go
+++ b/src/pkg/os/path.go
@@ -12,9 +12,9 @@ package os
// directories that MkdirAll creates.
// If path is already a directory, MkdirAll does nothing
// and returns nil.
-func MkdirAll(path string, perm int) Error {
+func MkdirAll(path string, perm uint32) Error {
// If path exists, stop with success or error.
- dir, err := Lstat(path)
+ dir, err := Stat(path)
if err == nil {
if dir.IsDirectory() {
return nil
@@ -84,7 +84,6 @@ func RemoveAll(path string) Error {
if err != nil {
return err
}
- defer fd.Close()
// Remove contents & return first error.
err = nil
@@ -105,6 +104,9 @@ func RemoveAll(path string) Error {
}
}
+ // Close directory, because windows won't remove opened directory.
+ fd.Close()
+
// Remove directory.
err1 := Remove(path)
if err == nil {
diff --git a/src/pkg/os/path_test.go b/src/pkg/os/path_test.go
index fcd4bac54..799e3ec2f 100644
--- a/src/pkg/os/path_test.go
+++ b/src/pkg/os/path_test.go
@@ -7,16 +7,19 @@ package os_test
import (
. "os"
"testing"
+ "runtime"
+ "syscall"
)
func TestMkdirAll(t *testing.T) {
- // Create new dir, in _obj so it will get
+ // Create new dir, in _test so it will get
// cleaned up by make if not by us.
- path := "_obj/_TestMkdirAll_/dir/./dir2"
+ path := "_test/_TestMkdirAll_/dir/./dir2"
err := MkdirAll(path, 0777)
if err != nil {
t.Fatalf("MkdirAll %q: %s", path, err)
}
+ defer RemoveAll("_test/_TestMkdirAll_")
// Already exists, should succeed.
err = MkdirAll(path, 0777)
@@ -34,7 +37,7 @@ func TestMkdirAll(t *testing.T) {
// Can't make directory named after file.
err = MkdirAll(fpath, 0777)
if err == nil {
- t.Fatalf("MkdirAll %q: no error")
+ t.Fatalf("MkdirAll %q: no error", fpath)
}
perr, ok := err.(*PathError)
if !ok {
@@ -48,7 +51,7 @@ func TestMkdirAll(t *testing.T) {
ffpath := fpath + "/subdir"
err = MkdirAll(ffpath, 0777)
if err == nil {
- t.Fatalf("MkdirAll %q: no error")
+ t.Fatalf("MkdirAll %q: no error", ffpath)
}
perr, ok = err.(*PathError)
if !ok {
@@ -57,13 +60,11 @@ func TestMkdirAll(t *testing.T) {
if perr.Path != fpath {
t.Fatalf("MkdirAll %q returned wrong error path: %q not %q", ffpath, perr.Path, fpath)
}
-
- RemoveAll("_obj/_TestMkdirAll_")
}
func TestRemoveAll(t *testing.T) {
// Work directory.
- path := "_obj/_TestRemoveAll_"
+ path := "_test/_TestRemoveAll_"
fpath := path + "/file"
dpath := path + "/dir"
@@ -104,7 +105,16 @@ func TestRemoveAll(t *testing.T) {
t.Fatalf("Lstat %q succeeded after RemoveAll (second)", path)
}
- if Getuid() != 0 { // Test fails as root
+ // Determine if we should run the following test.
+ testit := true
+ if syscall.OS == "windows" {
+ // Chmod is not supported under windows.
+ testit = false
+ } else {
+ // Test fails as root.
+ testit = Getuid() != 0
+ }
+ if testit {
// Make directory with file and subdirectory and trigger error.
if err = MkdirAll(dpath, 0777); err != nil {
t.Fatalf("MkdirAll %q: %s", dpath, err)
@@ -120,23 +130,17 @@ func TestRemoveAll(t *testing.T) {
if err = Chmod(dpath, 0); err != nil {
t.Fatalf("Chmod %q 0: %s", dpath, err)
}
- if err = RemoveAll(path); err == nil {
- _, err := Lstat(path)
- if err == nil {
- t.Errorf("Can lstat %q after supposed RemoveAll", path)
- }
- t.Fatalf("RemoveAll %q succeeded with chmod 0 subdirectory", path, err)
- }
- perr, ok := err.(*PathError)
- if !ok {
- t.Fatalf("RemoveAll %q returned %T not *PathError", path, err)
- }
- if perr.Path != dpath {
- t.Fatalf("RemoveAll %q failed at %q not %q", path, perr.Path, dpath)
- }
- if err = Chmod(dpath, 0777); err != nil {
- t.Fatalf("Chmod %q 0777: %s", dpath, err)
- }
+
+ // No error checking here: either RemoveAll
+ // will or won't be able to remove dpath;
+ // either way we want to see if it removes fpath
+ // and path/zzz. Reasons why RemoveAll might
+ // succeed in removing dpath as well include:
+ // * running as root
+ // * running on a file system without permissions (FAT)
+ RemoveAll(path)
+ Chmod(dpath, 0777)
+
for _, s := range []string{fpath, path + "/zzz"} {
if _, err := Lstat(s); err == nil {
t.Fatalf("Lstat %q succeeded after partial RemoveAll", s)
@@ -150,3 +154,28 @@ func TestRemoveAll(t *testing.T) {
t.Fatalf("Lstat %q succeeded after RemoveAll (final)", path)
}
}
+
+func TestMkdirAllWithSymlink(t *testing.T) {
+ if runtime.GOOS == "windows" {
+ t.Log("Skipping test: symlinks don't exist under Windows")
+ return
+ }
+
+ err := Mkdir("_test/dir", 0755)
+ if err != nil {
+ t.Fatal(`Mkdir "_test/dir":`, err)
+ }
+ defer RemoveAll("_test/dir")
+
+ err = Symlink("dir", "_test/link")
+ if err != nil {
+ t.Fatal(`Symlink "dir", "_test/link":`, err)
+ }
+ defer RemoveAll("_test/link")
+
+ path := "_test/link/foo"
+ err = MkdirAll(path, 0755)
+ if err != nil {
+ t.Errorf("MkdirAll %q: %s", path, err)
+ }
+}
diff --git a/src/pkg/os/signal/Makefile b/src/pkg/os/signal/Makefile
index 5a245464a..013b91a85 100644
--- a/src/pkg/os/signal/Makefile
+++ b/src/pkg/os/signal/Makefile
@@ -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 ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=os/signal
GOFILES=\
diff --git a/src/pkg/os/stat_nacl.go b/src/pkg/os/stat_nacl.go
deleted file mode 100644
index a44d0b0b6..000000000
--- a/src/pkg/os/stat_nacl.go
+++ /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.
-
-package os
-
-import "syscall"
-
-func isSymlink(stat *syscall.Stat_t) bool {
- return stat.Mode&syscall.S_IFMT == syscall.S_IFLNK
-}
-
-func fileInfoFromStat(name string, fi *FileInfo, lstat, stat *syscall.Stat_t) *FileInfo {
- fi.Dev = uint64(stat.Dev)
- fi.Ino = uint64(stat.Ino)
- fi.Nlink = uint64(stat.Nlink)
- fi.Mode = stat.Mode
- fi.Uid = int(stat.Uid)
- fi.Gid = int(stat.Gid)
- fi.Rdev = uint64(stat.Rdev)
- fi.Size = int64(stat.Size)
- fi.Blksize = int64(stat.Blksize)
- fi.Blocks = int64(stat.Blocks)
- fi.Atime_ns = int64(stat.Atime) * 1e9
- fi.Mtime_ns = int64(stat.Mtime) * 1e9
- fi.Ctime_ns = int64(stat.Ctime) * 1e9
- for i := len(name) - 1; i >= 0; i-- {
- if name[i] == '/' {
- name = name[i+1:]
- break
- }
- }
- fi.Name = name
- if isSymlink(lstat) && !isSymlink(stat) {
- fi.FollowedSymlink = true
- }
- return fi
-}
diff --git a/src/pkg/os/stat_windows.go b/src/pkg/os/stat_windows.go
index d7ff6faf4..11088436a 100644
--- a/src/pkg/os/stat_windows.go
+++ b/src/pkg/os/stat_windows.go
@@ -26,12 +26,12 @@ func fileInfoFromByHandleInfo(fi *FileInfo, name string, d *syscall.ByHandleFile
func setFileInfo(fi *FileInfo, name string, fa, sizehi, sizelo uint32, ctime, atime, wtime syscall.Filetime) *FileInfo {
fi.Mode = 0
- if fa == syscall.FILE_ATTRIBUTE_DIRECTORY {
+ if fa&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 {
fi.Mode = fi.Mode | syscall.S_IFDIR
} else {
fi.Mode = fi.Mode | syscall.S_IFREG
}
- if fa == syscall.FILE_ATTRIBUTE_READONLY {
+ if fa&syscall.FILE_ATTRIBUTE_READONLY != 0 {
fi.Mode = fi.Mode | 0444
} else {
fi.Mode = fi.Mode | 0666
@@ -39,8 +39,8 @@ func setFileInfo(fi *FileInfo, name string, fa, sizehi, sizelo uint32, ctime, at
fi.Size = int64(sizehi)<<32 + int64(sizelo)
fi.Name = name
fi.FollowedSymlink = false
- fi.Atime_ns = atime.Microseconds() * 1000
- fi.Mtime_ns = wtime.Microseconds() * 1000
- fi.Ctime_ns = ctime.Microseconds() * 1000
+ fi.Atime_ns = atime.Nanoseconds()
+ fi.Mtime_ns = wtime.Nanoseconds()
+ fi.Ctime_ns = ctime.Nanoseconds()
return fi
}
diff --git a/src/pkg/os/sys_nacl.go b/src/pkg/os/sys_nacl.go
deleted file mode 100644
index dfcccb3e8..000000000
--- a/src/pkg/os/sys_nacl.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 os
-
-func Hostname() (name string, err Error) { return "nacl", nil }
diff --git a/src/pkg/os/types.go b/src/pkg/os/types.go
index 0e76e90be..79f6e9d49 100644
--- a/src/pkg/os/types.go
+++ b/src/pkg/os/types.go
@@ -53,4 +53,4 @@ func (f *FileInfo) IsSymlink() bool { return (f.Mode & syscall.S_IFMT) == syscal
func (f *FileInfo) IsSocket() bool { return (f.Mode & syscall.S_IFMT) == syscall.S_IFSOCK }
// Permission returns the file permission bits.
-func (f *FileInfo) Permission() int { return int(f.Mode & 0777) }
+func (f *FileInfo) Permission() uint32 { return f.Mode & 0777 }
diff --git a/src/pkg/patch/Makefile b/src/pkg/patch/Makefile
index 1666345c6..32db7bdc8 100644
--- a/src/pkg/patch/Makefile
+++ b/src/pkg/patch/Makefile
@@ -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 ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=patch
GOFILES=\
diff --git a/src/pkg/patch/patch_test.go b/src/pkg/patch/patch_test.go
index afc0ea71c..0a4aef7ea 100644
--- a/src/pkg/patch/patch_test.go
+++ b/src/pkg/patch/patch_test.go
@@ -37,7 +37,7 @@ func TestFileApply(t *testing.T) {
}
var tests = []Test{
- Test{
+ {
"hello, world\n",
"goodbye, world\n",
"Index: a\n" +
@@ -47,7 +47,7 @@ var tests = []Test{
"-hello, world\n" +
"+goodbye, world\n",
},
- Test{
+ {
"hello, world\n",
"goodbye, world\n",
"Index: a\n" +
@@ -58,7 +58,7 @@ var tests = []Test{
"-hello, world\n" +
"+goodbye, world\n",
},
- Test{
+ {
"hello, world\n",
"goodbye, world\n",
"diff a/a b/b\n" +
@@ -68,7 +68,7 @@ var tests = []Test{
"-hello, world\n" +
"+goodbye, world\n",
},
- Test{
+ {
"hello, world",
"goodbye, world\n",
"diff --git a/a b/b\n" +
@@ -79,7 +79,7 @@ var tests = []Test{
"\\ No newline at end of file\n" +
"+goodbye, world\n",
},
- Test{
+ {
"hello, world\n",
"goodbye, world",
"Index: a\n" +
@@ -90,7 +90,7 @@ var tests = []Test{
"+goodbye, world\n" +
"\\ No newline at end of file\n",
},
- Test{
+ {
"hello, world",
"goodbye, world",
"Index: a\n" +
@@ -102,7 +102,7 @@ var tests = []Test{
"+goodbye, world\n" +
"\\ No newline at end of file\n",
},
- Test{
+ {
"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" +
@@ -128,7 +128,7 @@ var tests = []Test{
"-n\n" +
"+N\n",
},
- Test{
+ {
"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" +
@@ -167,7 +167,7 @@ var tests = []Test{
"-y\n" +
"-z\n",
},
- Test{
+ {
"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" +
@@ -205,7 +205,7 @@ var tests = []Test{
"+y\n" +
"+z\n",
},
- Test{
+ {
"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" +
@@ -240,7 +240,7 @@ var tests = []Test{
"-y\n" +
"-z\n",
},
- Test{
+ {
"",
"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" +
@@ -275,7 +275,7 @@ var tests = []Test{
"+y\n" +
"+z\n",
},
- Test{
+ {
"\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" +
@@ -331,7 +331,7 @@ var tests = []Test{
"Gy(*Pb;D3Ms\n" +
"\n",
},
- Test{
+ {
"\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" +
@@ -379,7 +379,7 @@ var tests = []Test{
"G1edVN^?m&S\n" +
"\n",
},
- Test{
+ {
"",
"",
"Index: hello\n" +
diff --git a/src/pkg/path/Makefile b/src/pkg/path/Makefile
index 9372cdf37..4371913e8 100644
--- a/src/pkg/path/Makefile
+++ b/src/pkg/path/Makefile
@@ -2,11 +2,25 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=path
GOFILES=\
match.go\
path.go\
+GOFILES_freebsd=\
+ path_unix.go
+
+GOFILES_darwin=\
+ path_unix.go
+
+GOFILES_linux=\
+ path_unix.go
+
+GOFILES_windows=\
+ path_windows.go
+
+GOFILES+=$(GOFILES_$(GOOS))
+
include ../../Make.pkg
diff --git a/src/pkg/path/match.go b/src/pkg/path/match.go
index e3cf08cae..dd3422c42 100644
--- a/src/pkg/path/match.go
+++ b/src/pkg/path/match.go
@@ -2,6 +2,7 @@ package path
import (
"os"
+ "sort"
"strings"
"utf8"
)
@@ -202,3 +203,76 @@ func getEsc(chunk string) (r int, nchunk string, err os.Error) {
}
return
}
+
+// Glob returns the names of all files matching pattern or nil
+// if there is no matching file. The syntax of patterns is the same
+// as in Match. The pattern may describe hierarchical names such as
+// /usr/*/bin/ed.
+//
+func Glob(pattern string) (matches []string) {
+ if !hasMeta(pattern) {
+ if _, err := os.Stat(pattern); err == nil {
+ return []string{pattern}
+ }
+ return nil
+ }
+
+ dir, file := Split(pattern)
+ switch dir {
+ case "":
+ dir = "."
+ case "/":
+ // nothing
+ default:
+ dir = dir[0 : len(dir)-1] // chop off trailing '/'
+ }
+
+ if hasMeta(dir) {
+ for _, d := range Glob(dir) {
+ matches = glob(d, file, matches)
+ }
+ } else {
+ return glob(dir, file, nil)
+ }
+ return matches
+}
+
+// glob searches for files matching pattern in the directory dir
+// and appends them to matches.
+func glob(dir, pattern string, matches []string) []string {
+ fi, err := os.Stat(dir)
+ if err != nil {
+ return nil
+ }
+ if !fi.IsDirectory() {
+ return matches
+ }
+ d, err := os.Open(dir, os.O_RDONLY, 0666)
+ if err != nil {
+ return nil
+ }
+ defer d.Close()
+
+ names, err := d.Readdirnames(-1)
+ if err != nil {
+ return nil
+ }
+ sort.SortStrings(names)
+
+ for _, n := range names {
+ matched, err := Match(pattern, n)
+ if err != nil {
+ return matches
+ }
+ if matched {
+ matches = append(matches, Join(dir, n))
+ }
+ }
+ return matches
+}
+
+// hasMeta returns true if path contains any of the magic characters
+// recognized by Match.
+func hasMeta(path string) bool {
+ return strings.IndexAny(path, "*?[") != -1
+}
diff --git a/src/pkg/path/match_test.go b/src/pkg/path/match_test.go
index c02384f92..a1bf508e3 100644
--- a/src/pkg/path/match_test.go
+++ b/src/pkg/path/match_test.go
@@ -16,62 +16,90 @@ type MatchTest struct {
}
var matchTests = []MatchTest{
- MatchTest{"abc", "abc", true, nil},
- MatchTest{"*", "abc", true, nil},
- MatchTest{"*c", "abc", true, nil},
- MatchTest{"a*", "a", true, nil},
- MatchTest{"a*", "abc", true, nil},
- MatchTest{"a*", "ab/c", false, nil},
- MatchTest{"a*/b", "abc/b", true, nil},
- MatchTest{"a*/b", "a/c/b", false, nil},
- MatchTest{"a*b*c*d*e*/f", "axbxcxdxe/f", true, nil},
- MatchTest{"a*b*c*d*e*/f", "axbxcxdxexxx/f", true, nil},
- MatchTest{"a*b*c*d*e*/f", "axbxcxdxe/xxx/f", false, nil},
- MatchTest{"a*b*c*d*e*/f", "axbxcxdxexxx/fff", false, nil},
- MatchTest{"a*b?c*x", "abxbbxdbxebxczzx", true, nil},
- MatchTest{"a*b?c*x", "abxbbxdbxebxczzy", false, nil},
- MatchTest{"ab[c]", "abc", true, nil},
- MatchTest{"ab[b-d]", "abc", true, nil},
- MatchTest{"ab[e-g]", "abc", false, nil},
- MatchTest{"ab[^c]", "abc", false, nil},
- MatchTest{"ab[^b-d]", "abc", false, nil},
- MatchTest{"ab[^e-g]", "abc", true, nil},
- MatchTest{"a\\*b", "a*b", true, nil},
- MatchTest{"a\\*b", "ab", false, nil},
- MatchTest{"a?b", "a☺b", true, nil},
- MatchTest{"a[^a]b", "a☺b", true, nil},
- MatchTest{"a???b", "a☺b", false, nil},
- MatchTest{"a[^a][^a][^a]b", "a☺b", false, nil},
- MatchTest{"[a-ζ]*", "α", true, nil},
- MatchTest{"*[a-ζ]", "A", false, nil},
- MatchTest{"a?b", "a/b", false, nil},
- MatchTest{"a*b", "a/b", false, nil},
- MatchTest{"[\\]a]", "]", true, nil},
- MatchTest{"[\\-]", "-", true, nil},
- MatchTest{"[x\\-]", "x", true, nil},
- MatchTest{"[x\\-]", "-", true, nil},
- MatchTest{"[x\\-]", "z", false, nil},
- MatchTest{"[\\-x]", "x", true, nil},
- MatchTest{"[\\-x]", "-", true, nil},
- MatchTest{"[\\-x]", "a", false, nil},
- MatchTest{"[]a]", "]", false, ErrBadPattern},
- MatchTest{"[-]", "-", false, ErrBadPattern},
- MatchTest{"[x-]", "x", false, ErrBadPattern},
- MatchTest{"[x-]", "-", false, ErrBadPattern},
- MatchTest{"[x-]", "z", false, ErrBadPattern},
- MatchTest{"[-x]", "x", false, ErrBadPattern},
- MatchTest{"[-x]", "-", false, ErrBadPattern},
- MatchTest{"[-x]", "a", false, ErrBadPattern},
- MatchTest{"\\", "a", false, ErrBadPattern},
- MatchTest{"[a-b-c]", "a", false, ErrBadPattern},
- MatchTest{"*x", "xxx", true, nil},
+ {"abc", "abc", true, nil},
+ {"*", "abc", true, nil},
+ {"*c", "abc", true, nil},
+ {"a*", "a", true, nil},
+ {"a*", "abc", true, nil},
+ {"a*", "ab/c", false, nil},
+ {"a*/b", "abc/b", true, nil},
+ {"a*/b", "a/c/b", false, nil},
+ {"a*b*c*d*e*/f", "axbxcxdxe/f", true, nil},
+ {"a*b*c*d*e*/f", "axbxcxdxexxx/f", true, nil},
+ {"a*b*c*d*e*/f", "axbxcxdxe/xxx/f", false, nil},
+ {"a*b*c*d*e*/f", "axbxcxdxexxx/fff", false, nil},
+ {"a*b?c*x", "abxbbxdbxebxczzx", true, nil},
+ {"a*b?c*x", "abxbbxdbxebxczzy", false, nil},
+ {"ab[c]", "abc", true, nil},
+ {"ab[b-d]", "abc", true, nil},
+ {"ab[e-g]", "abc", false, nil},
+ {"ab[^c]", "abc", false, nil},
+ {"ab[^b-d]", "abc", false, nil},
+ {"ab[^e-g]", "abc", true, nil},
+ {"a\\*b", "a*b", true, nil},
+ {"a\\*b", "ab", false, nil},
+ {"a?b", "a☺b", true, nil},
+ {"a[^a]b", "a☺b", true, nil},
+ {"a???b", "a☺b", false, nil},
+ {"a[^a][^a][^a]b", "a☺b", false, nil},
+ {"[a-ζ]*", "α", true, nil},
+ {"*[a-ζ]", "A", false, nil},
+ {"a?b", "a/b", false, nil},
+ {"a*b", "a/b", false, nil},
+ {"[\\]a]", "]", true, nil},
+ {"[\\-]", "-", true, nil},
+ {"[x\\-]", "x", true, nil},
+ {"[x\\-]", "-", true, nil},
+ {"[x\\-]", "z", false, nil},
+ {"[\\-x]", "x", true, nil},
+ {"[\\-x]", "-", true, nil},
+ {"[\\-x]", "a", false, nil},
+ {"[]a]", "]", false, ErrBadPattern},
+ {"[-]", "-", false, ErrBadPattern},
+ {"[x-]", "x", false, ErrBadPattern},
+ {"[x-]", "-", false, ErrBadPattern},
+ {"[x-]", "z", false, ErrBadPattern},
+ {"[-x]", "x", false, ErrBadPattern},
+ {"[-x]", "-", false, ErrBadPattern},
+ {"[-x]", "a", false, ErrBadPattern},
+ {"\\", "a", false, ErrBadPattern},
+ {"[a-b-c]", "a", false, ErrBadPattern},
+ {"*x", "xxx", true, nil},
}
func TestMatch(t *testing.T) {
for _, tt := range matchTests {
ok, err := Match(tt.pattern, tt.s)
if ok != tt.match || err != tt.err {
- t.Errorf("Match(%#q, %#q) = %v, %v want %v, nil\n", tt.pattern, tt.s, ok, err, tt.match)
+ t.Errorf("Match(%#q, %#q) = %v, %v want %v, nil", tt.pattern, tt.s, ok, err, tt.match)
+ }
+ }
+}
+
+// contains returns true if vector contains the string s.
+func contains(vector []string, s string) bool {
+ for _, elem := range vector {
+ if elem == s {
+ return true
+ }
+ }
+ return false
+}
+
+var globTests = []struct {
+ pattern, result string
+}{
+ {"match.go", "match.go"},
+ {"mat?h.go", "match.go"},
+ {"*", "match.go"},
+ {"../*/match.go", "../path/match.go"},
+}
+
+func TestGlob(t *testing.T) {
+ for _, tt := range globTests {
+ matches := Glob(tt.pattern)
+ if !contains(matches, tt.result) {
+ t.Errorf("Glob(%#q) = %#v want %v", tt.pattern, matches, tt.result)
}
}
}
diff --git a/src/pkg/path/path.go b/src/pkg/path/path.go
index 9c1d09374..61eea8858 100644
--- a/src/pkg/path/path.go
+++ b/src/pkg/path/path.go
@@ -102,17 +102,13 @@ func Clean(path string) string {
return string(buf[0:w])
}
-// Split splits path immediately following the final slash,
+// Split splits path immediately following the final path separator,
// separating it into a directory and file name component.
-// If there is no slash in path, DirFile returns an empty dir and
+// If there is no separator in path, Split returns an empty dir and
// file set to path.
func Split(path string) (dir, file string) {
- for i := len(path) - 1; i >= 0; i-- {
- if path[i] == '/' {
- return path[0 : i+1], path[i+1:]
- }
- }
- return "", path
+ i := strings.LastIndexAny(path, PathSeps)
+ return path[:i+1], path[i+1:]
}
// Join joins any number of path elements into a single path, adding a
@@ -140,7 +136,7 @@ func Ext(path string) string {
}
// Visitor methods are invoked for corresponding file tree entries
-// visited by Walk. The parameter path is the full path of d relative
+// 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
@@ -208,3 +204,9 @@ func Base(name string) string {
}
return name
}
+
+// IsAbs returns true if the path is absolute.
+func IsAbs(path string) bool {
+ // TODO: Add Windows support
+ return strings.HasPrefix(path, "/")
+}
diff --git a/src/pkg/path/path_test.go b/src/pkg/path/path_test.go
index 6915b48bb..6b4be07a9 100644
--- a/src/pkg/path/path_test.go
+++ b/src/pkg/path/path_test.go
@@ -6,6 +6,7 @@ package path
import (
"os"
+ "runtime"
"testing"
)
@@ -15,52 +16,52 @@ type CleanTest struct {
var cleantests = []CleanTest{
// Already clean
- CleanTest{"", "."},
- CleanTest{"abc", "abc"},
- CleanTest{"abc/def", "abc/def"},
- CleanTest{"a/b/c", "a/b/c"},
- CleanTest{".", "."},
- CleanTest{"..", ".."},
- CleanTest{"../..", "../.."},
- CleanTest{"../../abc", "../../abc"},
- CleanTest{"/abc", "/abc"},
- CleanTest{"/", "/"},
+ {"", "."},
+ {"abc", "abc"},
+ {"abc/def", "abc/def"},
+ {"a/b/c", "a/b/c"},
+ {".", "."},
+ {"..", ".."},
+ {"../..", "../.."},
+ {"../../abc", "../../abc"},
+ {"/abc", "/abc"},
+ {"/", "/"},
// Remove trailing slash
- CleanTest{"abc/", "abc"},
- CleanTest{"abc/def/", "abc/def"},
- CleanTest{"a/b/c/", "a/b/c"},
- CleanTest{"./", "."},
- CleanTest{"../", ".."},
- CleanTest{"../../", "../.."},
- CleanTest{"/abc/", "/abc"},
+ {"abc/", "abc"},
+ {"abc/def/", "abc/def"},
+ {"a/b/c/", "a/b/c"},
+ {"./", "."},
+ {"../", ".."},
+ {"../../", "../.."},
+ {"/abc/", "/abc"},
// Remove doubled slash
- CleanTest{"abc//def//ghi", "abc/def/ghi"},
- CleanTest{"//abc", "/abc"},
- CleanTest{"///abc", "/abc"},
- CleanTest{"//abc//", "/abc"},
- CleanTest{"abc//", "abc"},
+ {"abc//def//ghi", "abc/def/ghi"},
+ {"//abc", "/abc"},
+ {"///abc", "/abc"},
+ {"//abc//", "/abc"},
+ {"abc//", "abc"},
// Remove . elements
- CleanTest{"abc/./def", "abc/def"},
- CleanTest{"/./abc/def", "/abc/def"},
- CleanTest{"abc/.", "abc"},
+ {"abc/./def", "abc/def"},
+ {"/./abc/def", "/abc/def"},
+ {"abc/.", "abc"},
// Remove .. elements
- CleanTest{"abc/def/ghi/../jkl", "abc/def/jkl"},
- CleanTest{"abc/def/../ghi/../jkl", "abc/jkl"},
- CleanTest{"abc/def/..", "abc"},
- CleanTest{"abc/def/../..", "."},
- CleanTest{"/abc/def/../..", "/"},
- CleanTest{"abc/def/../../..", ".."},
- CleanTest{"/abc/def/../../..", "/"},
- CleanTest{"abc/def/../../../ghi/jkl/../../../mno", "../../mno"},
+ {"abc/def/ghi/../jkl", "abc/def/jkl"},
+ {"abc/def/../ghi/../jkl", "abc/jkl"},
+ {"abc/def/..", "abc"},
+ {"abc/def/../..", "."},
+ {"/abc/def/../..", "/"},
+ {"abc/def/../../..", ".."},
+ {"/abc/def/../../..", "/"},
+ {"abc/def/../../../ghi/jkl/../../../mno", "../../mno"},
// Combinations
- CleanTest{"abc/./../def", "def"},
- CleanTest{"abc//./../def", "def"},
- CleanTest{"abc/../../././../def", "../../def"},
+ {"abc/./../def", "def"},
+ {"abc//./../def", "def"},
+ {"abc/../../././../def", "../../def"},
}
func TestClean(t *testing.T) {
@@ -76,14 +77,25 @@ type SplitTest struct {
}
var splittests = []SplitTest{
- SplitTest{"a/b", "a/", "b"},
- SplitTest{"a/b/", "a/b/", ""},
- SplitTest{"a/", "a/", ""},
- SplitTest{"a", "", "a"},
- SplitTest{"/", "/", ""},
+ {"a/b", "a/", "b"},
+ {"a/b/", "a/b/", ""},
+ {"a/", "a/", ""},
+ {"a", "", "a"},
+ {"/", "/", ""},
+}
+
+var winsplittests = []SplitTest{
+ {`C:\Windows\System32`, `C:\Windows\`, `System32`},
+ {`C:\Windows\`, `C:\Windows\`, ``},
+ {`C:\Windows`, `C:\`, `Windows`},
+ {`C:Windows`, `C:`, `Windows`},
+ {`\\?\c:\`, `\\?\c:\`, ``},
}
func TestSplit(t *testing.T) {
+ if runtime.GOOS == "windows" {
+ splittests = append(splittests, winsplittests...)
+ }
for _, test := range splittests {
if d, f := Split(test.path); d != test.dir || f != test.file {
t.Errorf("Split(%q) = %q, %q, want %q, %q", test.path, d, f, test.dir, test.file)
@@ -98,27 +110,27 @@ type JoinTest struct {
var jointests = []JoinTest{
// zero parameters
- JoinTest{[]string{}, ""},
+ {[]string{}, ""},
// one parameter
- JoinTest{[]string{""}, ""},
- JoinTest{[]string{"a"}, "a"},
+ {[]string{""}, ""},
+ {[]string{"a"}, "a"},
// two parameters
- JoinTest{[]string{"a", "b"}, "a/b"},
- JoinTest{[]string{"a", ""}, "a"},
- JoinTest{[]string{"", "b"}, "b"},
- JoinTest{[]string{"/", "a"}, "/a"},
- JoinTest{[]string{"/", ""}, "/"},
- JoinTest{[]string{"a/", "b"}, "a/b"},
- JoinTest{[]string{"a/", ""}, "a"},
- JoinTest{[]string{"", ""}, ""},
+ {[]string{"a", "b"}, "a/b"},
+ {[]string{"a", ""}, "a"},
+ {[]string{"", "b"}, "b"},
+ {[]string{"/", "a"}, "/a"},
+ {[]string{"/", ""}, "/"},
+ {[]string{"a/", "b"}, "a/b"},
+ {[]string{"a/", ""}, "a"},
+ {[]string{"", ""}, ""},
}
// join takes a []string and passes it to Join.
func join(elem []string, args ...string) string {
args = elem
- return Join(args)
+ return Join(args...)
}
func TestJoin(t *testing.T) {
@@ -134,11 +146,11 @@ type ExtTest struct {
}
var exttests = []ExtTest{
- ExtTest{"path.go", ".go"},
- ExtTest{"path.pb.go", ".go"},
- ExtTest{"a.dir/b", ""},
- ExtTest{"a.dir/b.go", ".go"},
- ExtTest{"a.dir/", ""},
+ {"path.go", ".go"},
+ {"path.pb.go", ".go"},
+ {"a.dir/b", ""},
+ {"a.dir/b.go", ".go"},
+ {"a.dir/", ""},
}
func TestExt(t *testing.T) {
@@ -245,7 +257,7 @@ func TestWalk(t *testing.T) {
errors := make(chan os.Error, 64)
Walk(tree.name, v, errors)
if err, ok := <-errors; ok {
- t.Errorf("no error expected, found: s", err)
+ t.Errorf("no error expected, found: %s", err)
}
checkMarks(t)
@@ -287,17 +299,17 @@ func TestWalk(t *testing.T) {
var basetests = []CleanTest{
// Already clean
- CleanTest{"", "."},
- CleanTest{".", "."},
- CleanTest{"/.", "."},
- CleanTest{"/", "/"},
- CleanTest{"////", "/"},
- CleanTest{"x/", "x"},
- CleanTest{"abc", "abc"},
- CleanTest{"abc/def", "def"},
- CleanTest{"a/b/.x", ".x"},
- CleanTest{"a/b/c.", "c."},
- CleanTest{"a/b/c.x", "c.x"},
+ {"", "."},
+ {".", "."},
+ {"/.", "."},
+ {"/", "/"},
+ {"////", "/"},
+ {"x/", "x"},
+ {"abc", "abc"},
+ {"abc/def", "def"},
+ {"a/b/.x", ".x"},
+ {"a/b/c.", "c."},
+ {"a/b/c.x", "c.x"},
}
func TestBase(t *testing.T) {
@@ -307,3 +319,27 @@ func TestBase(t *testing.T) {
}
}
}
+
+type IsAbsTest struct {
+ path string
+ isAbs bool
+}
+
+var isAbsTests = []IsAbsTest{
+ {"", false},
+ {"/", true},
+ {"/usr/bin/gcc", true},
+ {"..", false},
+ {"/a/../bb", true},
+ {".", false},
+ {"./", false},
+ {"lala", false},
+}
+
+func TestIsAbs(t *testing.T) {
+ for _, test := range isAbsTests {
+ if r := IsAbs(test.path); r != test.isAbs {
+ t.Errorf("IsAbs(%q) = %v, want %v", test.path, r, test.isAbs)
+ }
+ }
+}
diff --git a/src/pkg/path/path_unix.go b/src/pkg/path/path_unix.go
new file mode 100644
index 000000000..7e8c5eb8b
--- /dev/null
+++ b/src/pkg/path/path_unix.go
@@ -0,0 +1,11 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package path
+
+const (
+ DirSeps = `/` // directory separators
+ VolumeSeps = `` // volume separators
+ PathSeps = DirSeps + VolumeSeps // all path separators
+)
diff --git a/src/pkg/path/path_windows.go b/src/pkg/path/path_windows.go
new file mode 100644
index 000000000..966eb49fb
--- /dev/null
+++ b/src/pkg/path/path_windows.go
@@ -0,0 +1,11 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package path
+
+const (
+ DirSeps = `\/` // directory separators
+ VolumeSeps = `:` // volume separators
+ PathSeps = DirSeps + VolumeSeps // all path separators
+)
diff --git a/src/pkg/rand/Makefile b/src/pkg/rand/Makefile
index bf3bd87d6..ec3b34180 100644
--- a/src/pkg/rand/Makefile
+++ b/src/pkg/rand/Makefile
@@ -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 ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=rand
GOFILES=\
diff --git a/src/pkg/rand/rand_test.go b/src/pkg/rand/rand_test.go
index 7ce3894db..b9bf43208 100644
--- a/src/pkg/rand/rand_test.go
+++ b/src/pkg/rand/rand_test.go
@@ -290,26 +290,26 @@ func compareFloat32Slices(s1, s2 []float32) int {
func TestNormTables(t *testing.T) {
testKn, testWn, testFn := initNorm()
if i := compareUint32Slices(kn[0:], testKn); i >= 0 {
- t.Errorf("kn disagrees at index %v; %v != %v\n", i, kn[i], testKn[i])
+ t.Errorf("kn disagrees at index %v; %v != %v", i, kn[i], testKn[i])
}
if i := compareFloat32Slices(wn[0:], testWn); i >= 0 {
- t.Errorf("wn disagrees at index %v; %v != %v\n", i, wn[i], testWn[i])
+ t.Errorf("wn disagrees at index %v; %v != %v", i, wn[i], testWn[i])
}
if i := compareFloat32Slices(fn[0:], testFn); i >= 0 {
- t.Errorf("fn disagrees at index %v; %v != %v\n", i, fn[i], testFn[i])
+ t.Errorf("fn disagrees at index %v; %v != %v", i, fn[i], testFn[i])
}
}
func TestExpTables(t *testing.T) {
testKe, testWe, testFe := initExp()
if i := compareUint32Slices(ke[0:], testKe); i >= 0 {
- t.Errorf("ke disagrees at index %v; %v != %v\n", i, ke[i], testKe[i])
+ t.Errorf("ke disagrees at index %v; %v != %v", i, ke[i], testKe[i])
}
if i := compareFloat32Slices(we[0:], testWe); i >= 0 {
- t.Errorf("we disagrees at index %v; %v != %v\n", i, we[i], testWe[i])
+ t.Errorf("we disagrees at index %v; %v != %v", i, we[i], testWe[i])
}
if i := compareFloat32Slices(fe[0:], testFe); i >= 0 {
- t.Errorf("fe disagrees at index %v; %v != %v\n", i, fe[i], testFe[i])
+ t.Errorf("fe disagrees at index %v; %v != %v", i, fe[i], testFe[i])
}
}
diff --git a/src/pkg/reflect/Makefile b/src/pkg/reflect/Makefile
index b72d3873f..b946449a3 100644
--- a/src/pkg/reflect/Makefile
+++ b/src/pkg/reflect/Makefile
@@ -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 ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=reflect
GOFILES=\
diff --git a/src/pkg/reflect/all_test.go b/src/pkg/reflect/all_test.go
index e2c57dadb..7d34e5ca3 100644
--- a/src/pkg/reflect/all_test.go
+++ b/src/pkg/reflect/all_test.go
@@ -38,27 +38,27 @@ func assert(t *testing.T, s, want string) {
func typestring(i interface{}) string { return Typeof(i).String() }
var typeTests = []pair{
- pair{struct{ x int }{}, "int"},
- pair{struct{ x int8 }{}, "int8"},
- pair{struct{ x int16 }{}, "int16"},
- pair{struct{ x int32 }{}, "int32"},
- pair{struct{ x int64 }{}, "int64"},
- pair{struct{ x uint }{}, "uint"},
- pair{struct{ x uint8 }{}, "uint8"},
- pair{struct{ x uint16 }{}, "uint16"},
- pair{struct{ x uint32 }{}, "uint32"},
- pair{struct{ x uint64 }{}, "uint64"},
- pair{struct{ x float }{}, "float"},
- pair{struct{ x float32 }{}, "float32"},
- pair{struct{ x float64 }{}, "float64"},
- pair{struct{ x int8 }{}, "int8"},
- pair{struct{ x (**int8) }{}, "**int8"},
- pair{struct{ x (**integer) }{}, "**reflect_test.integer"},
- pair{struct{ x ([32]int32) }{}, "[32]int32"},
- pair{struct{ x ([]int8) }{}, "[]int8"},
- pair{struct{ x (map[string]int32) }{}, "map[string] int32"},
- pair{struct{ x (chan<- string) }{}, "chan<- string"},
- pair{struct {
+ {struct{ x int }{}, "int"},
+ {struct{ x int8 }{}, "int8"},
+ {struct{ x int16 }{}, "int16"},
+ {struct{ x int32 }{}, "int32"},
+ {struct{ x int64 }{}, "int64"},
+ {struct{ x uint }{}, "uint"},
+ {struct{ x uint8 }{}, "uint8"},
+ {struct{ x uint16 }{}, "uint16"},
+ {struct{ x uint32 }{}, "uint32"},
+ {struct{ x uint64 }{}, "uint64"},
+ {struct{ x float }{}, "float"},
+ {struct{ x float32 }{}, "float32"},
+ {struct{ x float64 }{}, "float64"},
+ {struct{ x int8 }{}, "int8"},
+ {struct{ x (**int8) }{}, "**int8"},
+ {struct{ x (**integer) }{}, "**reflect_test.integer"},
+ {struct{ x ([32]int32) }{}, "[32]int32"},
+ {struct{ x ([]int8) }{}, "[]int8"},
+ {struct{ x (map[string]int32) }{}, "map[string] int32"},
+ {struct{ x (chan<- string) }{}, "chan<- string"},
+ {struct {
x struct {
c chan *int32
d float32
@@ -66,15 +66,15 @@ var typeTests = []pair{
}{},
"struct { c chan *int32; d float32 }",
},
- pair{struct{ x (func(a int8, b int32)) }{}, "func(int8, int32)"},
- pair{struct {
+ {struct{ x (func(a int8, b int32)) }{}, "func(int8, int32)"},
+ {struct {
x struct {
c func(chan *integer, *int8)
}
}{},
"struct { c func(chan *reflect_test.integer, *int8) }",
},
- pair{struct {
+ {struct {
x struct {
a int8
b int32
@@ -82,7 +82,7 @@ var typeTests = []pair{
}{},
"struct { a int8; b int32 }",
},
- pair{struct {
+ {struct {
x struct {
a int8
b int8
@@ -91,7 +91,7 @@ var typeTests = []pair{
}{},
"struct { a int8; b int8; c int32 }",
},
- pair{struct {
+ {struct {
x struct {
a int8
b int8
@@ -101,7 +101,7 @@ var typeTests = []pair{
}{},
"struct { a int8; b int8; c int8; d int32 }",
},
- pair{struct {
+ {struct {
x struct {
a int8
b int8
@@ -112,7 +112,7 @@ var typeTests = []pair{
}{},
"struct { a int8; b int8; c int8; d int8; e int32 }",
},
- pair{struct {
+ {struct {
x struct {
a int8
b int8
@@ -124,28 +124,28 @@ var typeTests = []pair{
}{},
"struct { a int8; b int8; c int8; d int8; e int8; f int32 }",
},
- pair{struct {
+ {struct {
x struct {
a int8 "hi there"
}
}{},
`struct { a int8 "hi there" }`,
},
- pair{struct {
+ {struct {
x struct {
a int8 "hi \x00there\t\n\"\\"
}
}{},
`struct { a int8 "hi \x00there\t\n\"\\" }`,
},
- pair{struct {
+ {struct {
x struct {
f func(args ...int)
}
}{},
"struct { f func(...int) }",
},
- pair{struct {
+ {struct {
x (interface {
a(func(func(int) int) func(func(int)) int)
b()
@@ -156,47 +156,45 @@ var typeTests = []pair{
}
var valueTests = []pair{
- pair{(int8)(0), "8"},
- pair{(int16)(0), "16"},
- pair{(int32)(0), "32"},
- pair{(int64)(0), "64"},
- pair{(uint8)(0), "8"},
- pair{(uint16)(0), "16"},
- pair{(uint32)(0), "32"},
- pair{(uint64)(0), "64"},
- pair{(float32)(0), "256.25"},
- pair{(float64)(0), "512.125"},
- pair{(string)(""), "stringy cheese"},
- pair{(bool)(false), "true"},
- pair{(*int8)(nil), "*int8(0)"},
- pair{(**int8)(nil), "**int8(0)"},
- pair{([5]int32){}, "[5]int32{0, 0, 0, 0, 0}"},
- pair{(**integer)(nil), "**reflect_test.integer(0)"},
- pair{(map[string]int32)(nil), "map[string] int32{<can't iterate on maps>}"},
- pair{(chan<- string)(nil), "chan<- string"},
- pair{(struct {
+ {(int8)(0), "8"},
+ {(int16)(0), "16"},
+ {(int32)(0), "32"},
+ {(int64)(0), "64"},
+ {(uint8)(0), "8"},
+ {(uint16)(0), "16"},
+ {(uint32)(0), "32"},
+ {(uint64)(0), "64"},
+ {(float32)(0), "256.25"},
+ {(float64)(0), "512.125"},
+ {(string)(""), "stringy cheese"},
+ {(bool)(false), "true"},
+ {(*int8)(nil), "*int8(0)"},
+ {(**int8)(nil), "**int8(0)"},
+ {[5]int32{}, "[5]int32{0, 0, 0, 0, 0}"},
+ {(**integer)(nil), "**reflect_test.integer(0)"},
+ {(map[string]int32)(nil), "map[string] int32{<can't iterate on maps>}"},
+ {(chan<- string)(nil), "chan<- string"},
+ {struct {
c chan *int32
d float32
- }){},
+ }{},
"struct { c chan *int32; d float32 }{chan *int32, 0}",
},
- pair{(func(a int8, b int32))(nil), "func(int8, int32)(0)"},
- pair{(struct {
- c func(chan *integer, *int8)
- }){},
+ {(func(a int8, b int32))(nil), "func(int8, int32)(0)"},
+ {struct{ c func(chan *integer, *int8) }{},
"struct { c func(chan *reflect_test.integer, *int8) }{func(chan *reflect_test.integer, *int8)(0)}",
},
- pair{(struct {
+ {struct {
a int8
b int32
- }){},
+ }{},
"struct { a int8; b int32 }{0, 0}",
},
- pair{(struct {
+ {struct {
a int8
b int8
c int32
- }){},
+ }{},
"struct { a int8; b int8; c int32 }{0, 0, 0}",
},
}
@@ -338,16 +336,16 @@ func TestSetValue(t *testing.T) {
var _i = 7
var valueToStringTests = []pair{
- pair{123, "123"},
- pair{123.5, "123.5"},
- pair{byte(123), "123"},
- pair{"abc", "abc"},
- pair{T{123, 456.75, "hello", &_i}, "reflect_test.T{123, 456.75, hello, *int(&7)}"},
- pair{new(chan *T), "*chan *reflect_test.T(&chan *reflect_test.T)"},
- pair{[10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "[10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}"},
- pair{&[10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "*[10]int(&[10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10})"},
- pair{[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}"},
- pair{&[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "*[]int(&[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10})"},
+ {123, "123"},
+ {123.5, "123.5"},
+ {byte(123), "123"},
+ {"abc", "abc"},
+ {T{123, 456.75, "hello", &_i}, "reflect_test.T{123, 456.75, hello, *int(&7)}"},
+ {new(chan *T), "*chan *reflect_test.T(&chan *reflect_test.T)"},
+ {[10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "[10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}"},
+ {&[10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "*[10]int(&[10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10})"},
+ {[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}"},
+ {&[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "*[]int(&[]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10})"},
}
func TestValueToString(t *testing.T) {
@@ -386,6 +384,13 @@ func TestPtrPointTo(t *testing.T) {
if *ip != 1234 {
t.Errorf("got %d, want 1234", *ip)
}
+
+ ip = nil
+ vp := NewValue(ip).(*PtrValue)
+ vp.PointTo(vp.Elem())
+ if ip != nil {
+ t.Errorf("got non-nil (%p), want nil", ip)
+ }
}
func TestPtrSetNil(t *testing.T) {
@@ -493,22 +498,67 @@ func TestFunctionValue(t *testing.T) {
assert(t, v.Type().String(), "func()")
}
-func TestCopyArray(t *testing.T) {
+var appendTests = []struct {
+ orig, extra []int
+}{
+ {make([]int, 2, 4), []int{22}},
+ {make([]int, 2, 4), []int{22, 33, 44}},
+}
+
+func TestAppend(t *testing.T) {
+ for i, test := range appendTests {
+ origLen, extraLen := len(test.orig), len(test.extra)
+ want := append(test.orig, test.extra...)
+ // Convert extra from []int to []Value.
+ e0 := make([]Value, len(test.extra))
+ for j, e := range test.extra {
+ e0[j] = NewValue(e)
+ }
+ // Convert extra from []int to *SliceValue.
+ e1 := NewValue(test.extra).(*SliceValue)
+ // Test Append.
+ a0 := NewValue(test.orig).(*SliceValue)
+ have0 := Append(a0, e0...).Interface().([]int)
+ if !DeepEqual(have0, want) {
+ t.Errorf("Append #%d: have %v, want %v", i, have0, want)
+ }
+ // Check that the orig and extra slices were not modified.
+ if len(test.orig) != origLen {
+ t.Errorf("Append #%d origLen: have %v, want %v", i, len(test.orig), origLen)
+ }
+ if len(test.extra) != extraLen {
+ t.Errorf("Append #%d extraLen: have %v, want %v", i, len(test.extra), extraLen)
+ }
+ // Test AppendSlice.
+ a1 := NewValue(test.orig).(*SliceValue)
+ have1 := AppendSlice(a1, e1).Interface().([]int)
+ if !DeepEqual(have1, want) {
+ t.Errorf("AppendSlice #%d: have %v, want %v", i, have1, want)
+ }
+ // Check that the orig and extra slices were not modified.
+ if len(test.orig) != origLen {
+ t.Errorf("AppendSlice #%d origLen: have %v, want %v", i, len(test.orig), origLen)
+ }
+ if len(test.extra) != extraLen {
+ t.Errorf("AppendSlice #%d extraLen: have %v, want %v", i, len(test.extra), extraLen)
+ }
+ }
+}
+
+func TestCopy(t *testing.T) {
a := []int{1, 2, 3, 4, 10, 9, 8, 7}
b := []int{11, 22, 33, 44, 1010, 99, 88, 77, 66, 55, 44}
c := []int{11, 22, 33, 44, 1010, 99, 88, 77, 66, 55, 44}
- va := NewValue(&a)
- vb := NewValue(&b)
for i := 0; i < len(b); i++ {
if b[i] != c[i] {
t.Fatalf("b != c before test")
}
}
- aa := va.(*PtrValue).Elem().(*SliceValue)
- ab := vb.(*PtrValue).Elem().(*SliceValue)
+ aa := NewValue(a).(*SliceValue)
+ ab := NewValue(b).(*SliceValue)
for tocopy := 1; tocopy <= 7; tocopy++ {
aa.SetLen(tocopy)
- ArrayCopy(ab, aa)
+ Copy(ab, aa)
aa.SetLen(8)
for i := 0; i < tocopy; i++ {
if a[i] != b[i] {
@@ -570,42 +620,42 @@ type DeepEqualTest struct {
var deepEqualTests = []DeepEqualTest{
// Equalities
- DeepEqualTest{1, 1, true},
- DeepEqualTest{int32(1), int32(1), true},
- DeepEqualTest{0.5, 0.5, true},
- DeepEqualTest{float32(0.5), float32(0.5), true},
- DeepEqualTest{"hello", "hello", true},
- DeepEqualTest{make([]int, 10), make([]int, 10), true},
- DeepEqualTest{&[3]int{1, 2, 3}, &[3]int{1, 2, 3}, true},
- DeepEqualTest{Basic{1, 0.5}, Basic{1, 0.5}, true},
- DeepEqualTest{os.Error(nil), os.Error(nil), true},
- DeepEqualTest{map[int]string{1: "one", 2: "two"}, map[int]string{2: "two", 1: "one"}, true},
+ {1, 1, true},
+ {int32(1), int32(1), true},
+ {0.5, 0.5, true},
+ {float32(0.5), float32(0.5), true},
+ {"hello", "hello", true},
+ {make([]int, 10), make([]int, 10), true},
+ {&[3]int{1, 2, 3}, &[3]int{1, 2, 3}, true},
+ {Basic{1, 0.5}, Basic{1, 0.5}, true},
+ {os.Error(nil), os.Error(nil), true},
+ {map[int]string{1: "one", 2: "two"}, map[int]string{2: "two", 1: "one"}, true},
// Inequalities
- DeepEqualTest{1, 2, false},
- DeepEqualTest{int32(1), int32(2), false},
- DeepEqualTest{0.5, 0.6, false},
- DeepEqualTest{float32(0.5), float32(0.6), false},
- DeepEqualTest{"hello", "hey", false},
- DeepEqualTest{make([]int, 10), make([]int, 11), false},
- DeepEqualTest{&[3]int{1, 2, 3}, &[3]int{1, 2, 4}, false},
- DeepEqualTest{Basic{1, 0.5}, Basic{1, 0.6}, false},
- DeepEqualTest{Basic{1, 0}, Basic{2, 0}, false},
- DeepEqualTest{map[int]string{1: "one", 3: "two"}, map[int]string{2: "two", 1: "one"}, false},
- DeepEqualTest{map[int]string{1: "one", 2: "txo"}, map[int]string{2: "two", 1: "one"}, false},
- DeepEqualTest{map[int]string{1: "one"}, map[int]string{2: "two", 1: "one"}, false},
- DeepEqualTest{map[int]string{2: "two", 1: "one"}, map[int]string{1: "one"}, false},
- DeepEqualTest{nil, 1, false},
- DeepEqualTest{1, nil, false},
+ {1, 2, false},
+ {int32(1), int32(2), false},
+ {0.5, 0.6, false},
+ {float32(0.5), float32(0.6), false},
+ {"hello", "hey", false},
+ {make([]int, 10), make([]int, 11), false},
+ {&[3]int{1, 2, 3}, &[3]int{1, 2, 4}, false},
+ {Basic{1, 0.5}, Basic{1, 0.6}, false},
+ {Basic{1, 0}, Basic{2, 0}, false},
+ {map[int]string{1: "one", 3: "two"}, map[int]string{2: "two", 1: "one"}, false},
+ {map[int]string{1: "one", 2: "txo"}, map[int]string{2: "two", 1: "one"}, false},
+ {map[int]string{1: "one"}, map[int]string{2: "two", 1: "one"}, false},
+ {map[int]string{2: "two", 1: "one"}, map[int]string{1: "one"}, false},
+ {nil, 1, false},
+ {1, nil, false},
// Mismatched types
- DeepEqualTest{1, 1.0, false},
- DeepEqualTest{int32(1), int64(1), false},
- DeepEqualTest{0.5, "hello", false},
- DeepEqualTest{[]int{1, 2, 3}, [3]int{1, 2, 3}, false},
- DeepEqualTest{&[3]interface{}{1, 2, 4}, &[3]interface{}{1, 2, "s"}, false},
- DeepEqualTest{Basic{1, 0.5}, NotBasic{1, 0.5}, false},
- DeepEqualTest{map[uint]string{1: "one", 2: "two"}, map[int]string{2: "two", 1: "one"}, false},
+ {1, 1.0, false},
+ {int32(1), int64(1), false},
+ {0.5, "hello", false},
+ {[]int{1, 2, 3}, [3]int{1, 2, 3}, false},
+ {&[3]interface{}{1, 2, 4}, &[3]interface{}{1, 2, "s"}, false},
+ {Basic{1, 0.5}, NotBasic{1, 0.5}, false},
+ {map[uint]string{1: "one", 2: "two"}, map[int]string{2: "two", 1: "one"}, false},
}
func TestDeepEqual(t *testing.T) {
@@ -868,7 +918,7 @@ func TestMap(t *testing.T) {
// Check that value lookup is correct.
vv := mv.Elem(NewValue(k))
if vi := vv.(*IntValue).Get(); vi != int64(v) {
- t.Errorf("Key %q: have value %d, want %d", vi, v)
+ t.Errorf("Key %q: have value %d, want %d", k, vi, v)
}
// Copy into new map.
@@ -1041,6 +1091,11 @@ func TestMethod(t *testing.T) {
t.Errorf("Type Method returned %d; want 250", i)
}
+ i = Typeof(&p).Method(0).Func.Call([]Value{NewValue(&p), NewValue(10)})[0].(*IntValue).Get()
+ if i != 250 {
+ t.Errorf("Pointer Type Method returned %d; want 250", i)
+ }
+
// Curried method of value.
i = NewValue(p).Method(0).Call([]Value{NewValue(10)})[0].(*IntValue).Get()
if i != 250 {
@@ -1159,26 +1214,26 @@ type S4 struct {
}
var fieldTests = []FTest{
- FTest{struct{}{}, "", nil, 0},
- FTest{struct{}{}, "foo", nil, 0},
- FTest{S0{a: 'a'}, "a", []int{0}, 'a'},
- FTest{S0{}, "d", nil, 0},
- FTest{S1{S0: S0{a: 'a'}}, "a", []int{1, 0}, 'a'},
- FTest{S1{b: 'b'}, "b", []int{0}, 'b'},
- FTest{S1{}, "S0", []int{1}, 0},
- FTest{S1{S0: S0{c: 'c'}}, "c", []int{1, 2}, 'c'},
- FTest{S2{a: 'a'}, "a", []int{0}, 'a'},
- FTest{S2{}, "S1", []int{1}, 0},
- FTest{S2{S1: &S1{b: 'b'}}, "b", []int{1, 0}, 'b'},
- FTest{S2{S1: &S1{S0: S0{c: 'c'}}}, "c", []int{1, 1, 2}, 'c'},
- FTest{S2{}, "d", nil, 0},
- FTest{S3{}, "S1", nil, 0},
- FTest{S3{S2: S2{a: 'a'}}, "a", []int{1, 0}, 'a'},
- FTest{S3{}, "b", nil, 0},
- FTest{S3{d: 'd'}, "d", []int{2}, 0},
- FTest{S3{e: 'e'}, "e", []int{3}, 'e'},
- FTest{S4{a: 'a'}, "a", []int{1}, 'a'},
- FTest{S4{}, "b", nil, 0},
+ {struct{}{}, "", nil, 0},
+ {struct{}{}, "foo", nil, 0},
+ {S0{a: 'a'}, "a", []int{0}, 'a'},
+ {S0{}, "d", nil, 0},
+ {S1{S0: S0{a: 'a'}}, "a", []int{1, 0}, 'a'},
+ {S1{b: 'b'}, "b", []int{0}, 'b'},
+ {S1{}, "S0", []int{1}, 0},
+ {S1{S0: S0{c: 'c'}}, "c", []int{1, 2}, 'c'},
+ {S2{a: 'a'}, "a", []int{0}, 'a'},
+ {S2{}, "S1", []int{1}, 0},
+ {S2{S1: &S1{b: 'b'}}, "b", []int{1, 0}, 'b'},
+ {S2{S1: &S1{S0: S0{c: 'c'}}}, "c", []int{1, 1, 2}, 'c'},
+ {S2{}, "d", nil, 0},
+ {S3{}, "S1", nil, 0},
+ {S3{S2: S2{a: 'a'}}, "a", []int{1, 0}, 'a'},
+ {S3{}, "b", nil, 0},
+ {S3{d: 'd'}, "d", []int{2}, 0},
+ {S3{e: 'e'}, "e", []int{3}, 'e'},
+ {S4{a: 'a'}, "a", []int{1}, 'a'},
+ {S4{}, "b", nil, 0},
}
func TestFieldByIndex(t *testing.T) {
@@ -1282,3 +1337,65 @@ func TestDotDotDot(t *testing.T) {
}
t.Error(s)
}
+
+type inner struct {
+ x int
+}
+
+type outer struct {
+ y int
+ inner
+}
+
+func (*inner) m() {}
+func (*outer) m() {}
+
+func TestNestedMethods(t *testing.T) {
+ typ := Typeof((*outer)(nil))
+ if typ.NumMethod() != 1 || typ.Method(0).Func.Get() != NewValue((*outer).m).(*FuncValue).Get() {
+ t.Errorf("Wrong method table for outer: (m=%p)", (*outer).m)
+ for i := 0; i < typ.NumMethod(); i++ {
+ m := typ.Method(i)
+ t.Errorf("\t%d: %s %#x\n", i, m.Name, m.Func.Get())
+ }
+ }
+}
+
+type innerInt struct {
+ x int
+}
+
+type outerInt struct {
+ y int
+ innerInt
+}
+
+func (i *innerInt) m() int {
+ return i.x
+}
+
+func TestEmbeddedMethods(t *testing.T) {
+ typ := Typeof((*outerInt)(nil))
+ if typ.NumMethod() != 1 || typ.Method(0).Func.Get() != NewValue((*outerInt).m).(*FuncValue).Get() {
+ t.Errorf("Wrong method table for outerInt: (m=%p)", (*outerInt).m)
+ for i := 0; i < typ.NumMethod(); i++ {
+ m := typ.Method(i)
+ t.Errorf("\t%d: %s %#x\n", i, m.Name, m.Func.Get())
+ }
+ }
+
+ i := &innerInt{3}
+ if v := NewValue(i).Method(0).Call(nil)[0].(*IntValue).Get(); v != 3 {
+ t.Errorf("i.m() = %d, want 3", v)
+ }
+
+ o := &outerInt{1, innerInt{2}}
+ if v := NewValue(o).Method(0).Call(nil)[0].(*IntValue).Get(); v != 2 {
+ t.Errorf("i.m() = %d, want 2", v)
+ }
+
+ f := (*outerInt).m
+ if v := f(o); v != 2 {
+ t.Errorf("f(o) = %d, want 2", v)
+ }
+}
diff --git a/src/pkg/reflect/type.go b/src/pkg/reflect/type.go
index d87ccc984..9a7467b32 100644
--- a/src/pkg/reflect/type.go
+++ b/src/pkg/reflect/type.go
@@ -550,7 +550,7 @@ func (t *StructType) fieldByNameFunc(match func(string) bool, mark map[*StructTy
var fi int // field index
n := 0 // number of matching fields at depth fd
L:
- for i, _ := range t.fields {
+ for i := range t.fields {
f := t.Field(i)
d := inf
switch {
diff --git a/src/pkg/reflect/value.go b/src/pkg/reflect/value.go
index 56a5d69d8..e0bcb1a39 100644
--- a/src/pkg/reflect/value.go
+++ b/src/pkg/reflect/value.go
@@ -141,7 +141,7 @@ type FloatValue struct {
// Get returns the underlying int value.
func (v *FloatValue) Get() float64 {
- switch v.typ.(*FloatType).Kind() {
+ switch v.typ.Kind() {
case Float:
return float64(*(*float)(v.addr))
case Float32:
@@ -157,7 +157,7 @@ func (v *FloatValue) Set(x float64) {
if !v.canSet {
panic(cannotSet)
}
- switch v.typ.(*FloatType).Kind() {
+ switch v.typ.Kind() {
default:
panic("reflect: invalid float kind")
case Float:
@@ -190,7 +190,7 @@ type ComplexValue struct {
// Get returns the underlying complex value.
func (v *ComplexValue) Get() complex128 {
- switch v.typ.(*ComplexType).Kind() {
+ switch v.typ.Kind() {
case Complex:
return complex128(*(*complex)(v.addr))
case Complex64:
@@ -206,7 +206,7 @@ func (v *ComplexValue) Set(x complex128) {
if !v.canSet {
panic(cannotSet)
}
- switch v.typ.(*ComplexType).Kind() {
+ switch v.typ.Kind() {
default:
panic("reflect: invalid complex kind")
case Complex:
@@ -228,7 +228,7 @@ type IntValue struct {
// Get returns the underlying int value.
func (v *IntValue) Get() int64 {
- switch v.typ.(*IntType).Kind() {
+ switch v.typ.Kind() {
case Int:
return int64(*(*int)(v.addr))
case Int8:
@@ -248,7 +248,7 @@ func (v *IntValue) Set(x int64) {
if !v.canSet {
panic(cannotSet)
}
- switch v.typ.(*IntType).Kind() {
+ switch v.typ.Kind() {
default:
panic("reflect: invalid int kind")
case Int:
@@ -306,7 +306,7 @@ type UintValue struct {
// Get returns the underlying uuint value.
func (v *UintValue) Get() uint64 {
- switch v.typ.(*UintType).Kind() {
+ switch v.typ.Kind() {
case Uint:
return uint64(*(*uint)(v.addr))
case Uint8:
@@ -328,7 +328,7 @@ func (v *UintValue) Set(x uint64) {
if !v.canSet {
panic(cannotSet)
}
- switch v.typ.(*UintType).Kind() {
+ switch v.typ.Kind() {
default:
panic("reflect: invalid uint kind")
case Uint:
@@ -400,11 +400,57 @@ type ArrayOrSliceValue interface {
addr() addr
}
-// ArrayCopy copies the contents of src into dst until either
+// grow grows the slice s so that it can hold extra more values, allocating
+// more capacity if needed. It also returns the old and new slice lengths.
+func grow(s *SliceValue, extra int) (*SliceValue, int, int) {
+ i0 := s.Len()
+ i1 := i0 + extra
+ if i1 < i0 {
+ panic("append: slice overflow")
+ }
+ m := s.Cap()
+ if i1 <= m {
+ return s.Slice(0, i1), i0, i1
+ }
+ if m == 0 {
+ m = extra
+ } else {
+ for m < i1 {
+ if i0 < 1024 {
+ m += m
+ } else {
+ m += m / 4
+ }
+ }
+ }
+ t := MakeSlice(s.Type().(*SliceType), i1, m)
+ Copy(t, s)
+ return t, i0, i1
+}
+
+// Append appends the values x to a slice s and returns the resulting slice.
+// Each x must have the same type as s' element type.
+func Append(s *SliceValue, x ...Value) *SliceValue {
+ s, i0, i1 := grow(s, len(x))
+ for i, j := i0, 0; i < i1; i, j = i+1, j+1 {
+ s.Elem(i).SetValue(x[j])
+ }
+ return s
+}
+
+// AppendSlice appends a slice t to a slice s and returns the resulting slice.
+// The slices s and t must have the same element type.
+func AppendSlice(s, t *SliceValue) *SliceValue {
+ s, i0, i1 := grow(s, t.Len())
+ Copy(s.Slice(i0, i1), t)
+ return s
+}
+
+// Copy copies the contents of src into dst until either
// dst has been filled or src has been exhausted.
// It returns the number of elements copied.
// The arrays dst and src must have the same element type.
-func ArrayCopy(dst, src ArrayOrSliceValue) int {
+func Copy(dst, src ArrayOrSliceValue) int {
// TODO: This will have to move into the runtime
// once the real gc goes in.
de := dst.Type().(ArrayOrSliceType).Elem()
@@ -439,7 +485,7 @@ func (v *ArrayValue) Set(x *ArrayValue) {
panic(cannotSet)
}
typesMustMatch(v.typ, x.typ)
- ArrayCopy(v, x)
+ Copy(v, x)
}
// Set sets v to the value x.
@@ -730,8 +776,6 @@ type tiny struct {
// Call calls the function fv with input parameters in.
// It returns the function's output parameters as Values.
func (fv *FuncValue) Call(in []Value) []Value {
- var structAlign = Typeof((*tiny)(nil)).(*PtrType).Elem().Size()
-
t := fv.Type().(*FuncType)
nin := len(in)
if fv.first != nil && !fv.isInterface {
@@ -757,7 +801,7 @@ func (fv *FuncValue) Call(in []Value) []Value {
size = (size + a - 1) &^ (a - 1)
size += tv.Size()
}
- size = (size + structAlign - 1) &^ (structAlign - 1)
+ size = (size + ptrSize - 1) &^ (ptrSize - 1)
for i := 0; i < nout; i++ {
tv := t.Out(i)
a := uintptr(tv.Align())
@@ -767,9 +811,9 @@ func (fv *FuncValue) Call(in []Value) []Value {
// size must be > 0 in order for &args[0] to be valid.
// the argument copying is going to round it up to
- // a multiple of 8 anyway, so make it 8 to begin with.
- if size < 8 {
- size = 8
+ // a multiple of ptrSize anyway, so make it ptrSize to begin with.
+ if size < ptrSize {
+ size = ptrSize
}
// round to pointer size
@@ -811,7 +855,7 @@ func (fv *FuncValue) Call(in []Value) []Value {
memmove(addr(ptr+off), v.getAddr(), n)
off += n
}
- off = (off + structAlign - 1) &^ (structAlign - 1)
+ off = (off + ptrSize - 1) &^ (ptrSize - 1)
// Call
call(*(**byte)(fv.addr), (*byte)(addr(ptr)), uint32(size))
@@ -843,11 +887,17 @@ type InterfaceValue struct {
value "interface"
}
-// No Get because v.Interface() is available.
-
// IsNil returns whether v is a nil interface value.
func (v *InterfaceValue) IsNil() bool { return v.Interface() == nil }
+// No single uinptr Get because v.Interface() is available.
+
+// Get returns the two words that represent an interface in the runtime.
+// Those words are useful only when playing unsafe games.
+func (v *InterfaceValue) Get() [2]uintptr {
+ return *(*[2]uintptr)(v.addr)
+}
+
// Elem returns the concrete value stored in the interface value v.
func (v *InterfaceValue) Elem() Value { return NewValue(v.Interface()) }
@@ -1058,7 +1108,12 @@ func (v *PtrValue) SetValue(x Value) {
}
// PointTo changes v to point to x.
+// If x is a nil Value, PointTo sets v to nil.
func (v *PtrValue) PointTo(x Value) {
+ if x == nil {
+ *(**uintptr)(v.addr) = nil
+ return
+ }
if !x.CanSet() {
panic("cannot set x; cannot point to x")
}
diff --git a/src/pkg/regexp/Makefile b/src/pkg/regexp/Makefile
index 9f91c8e7a..9024e66da 100644
--- a/src/pkg/regexp/Makefile
+++ b/src/pkg/regexp/Makefile
@@ -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 ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=regexp
GOFILES=\
diff --git a/src/pkg/regexp/all_test.go b/src/pkg/regexp/all_test.go
index 4bdd6c67e..3b2c489bc 100644
--- a/src/pkg/regexp/all_test.go
+++ b/src/pkg/regexp/all_test.go
@@ -37,80 +37,18 @@ type stringError struct {
}
var bad_re = []stringError{
- stringError{`*`, ErrBareClosure},
- stringError{`(abc`, ErrUnmatchedLpar},
- stringError{`abc)`, ErrUnmatchedRpar},
- stringError{`x[a-z`, ErrUnmatchedLbkt},
- stringError{`abc]`, ErrUnmatchedRbkt},
- stringError{`[z-a]`, ErrBadRange},
- stringError{`abc\`, ErrExtraneousBackslash},
- stringError{`a**`, ErrBadClosure},
- stringError{`a*+`, ErrBadClosure},
- stringError{`a??`, ErrBadClosure},
- stringError{`*`, ErrBareClosure},
- stringError{`\x`, ErrBadBackslash},
-}
-
-type vec []int
-
-type tester struct {
- re string
- text string
- match vec
-}
-
-var matches = []tester{
- tester{`^abcdefg`, "abcdefg", vec{0, 7}},
- tester{`a+`, "baaab", vec{1, 4}},
- tester{"abcd..", "abcdef", vec{0, 6}},
- tester{``, "", vec{0, 0}},
- tester{`a`, "a", vec{0, 1}},
- tester{`x`, "y", vec{}},
- tester{`b`, "abc", vec{1, 2}},
- tester{`.`, "a", vec{0, 1}},
- tester{`.*`, "abcdef", vec{0, 6}},
- tester{`^`, "abcde", vec{0, 0}},
- tester{`$`, "abcde", vec{5, 5}},
- tester{`^abcd$`, "abcd", vec{0, 4}},
- tester{`^bcd'`, "abcdef", vec{}},
- tester{`^abcd$`, "abcde", vec{}},
- tester{`a+`, "baaab", vec{1, 4}},
- tester{`a*`, "baaab", vec{0, 0}},
- tester{`[a-z]+`, "abcd", vec{0, 4}},
- tester{`[^a-z]+`, "ab1234cd", vec{2, 6}},
- tester{`[a\-\]z]+`, "az]-bcz", vec{0, 4}},
- tester{`[^\n]+`, "abcd\n", vec{0, 4}},
- tester{`[日本語]+`, "日本語日本語", vec{0, 18}},
- tester{`日本語+`, "日本語", vec{0, 9}},
- tester{`日本語+`, "日本語語語語", vec{0, 18}},
- tester{`()`, "", vec{0, 0, 0, 0}},
- tester{`(a)`, "a", vec{0, 1, 0, 1}},
- tester{`(.)(.)`, "日a", vec{0, 4, 0, 3, 3, 4}},
- tester{`(.*)`, "", vec{0, 0, 0, 0}},
- tester{`(.*)`, "abcd", vec{0, 4, 0, 4}},
- tester{`(..)(..)`, "abcd", vec{0, 4, 0, 2, 2, 4}},
- tester{`(([^xyz]*)(d))`, "abcd", vec{0, 4, 0, 4, 0, 3, 3, 4}},
- tester{`((a|b|c)*(d))`, "abcd", vec{0, 4, 0, 4, 2, 3, 3, 4}},
- tester{`(((a|b|c)*)(d))`, "abcd", vec{0, 4, 0, 4, 0, 3, 2, 3, 3, 4}},
- tester{`a*(|(b))c*`, "aacc", vec{0, 4, 2, 2, -1, -1}},
- tester{`(.*).*`, "ab", vec{0, 2, 0, 2}},
- tester{`[.]`, ".", vec{0, 1}},
- tester{`/$`, "/abc/", vec{4, 5}},
- tester{`/$`, "/abc", vec{}},
-
- // fixed bugs
- tester{`ab$`, "cab", vec{1, 3}},
- tester{`axxb$`, "axxcb", vec{}},
- tester{`data`, "daXY data", vec{5, 9}},
- tester{`da(.)a$`, "daXY data", vec{5, 9, 7, 8}},
-
- // can backslash-escape any punctuation
- tester{`\!\"\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\{\|\}\~`,
- `!"#$%&'()*+,-./:;<=>?@[\]^_{|}~`, vec{0, 31}},
- tester{`[\!\"\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\{\|\}\~]+`,
- `!"#$%&'()*+,-./:;<=>?@[\]^_{|}~`, vec{0, 31}},
- tester{"\\`", "`", vec{0, 1}},
- tester{"[\\`]+", "`", vec{0, 1}},
+ {`*`, ErrBareClosure},
+ {`(abc`, ErrUnmatchedLpar},
+ {`abc)`, ErrUnmatchedRpar},
+ {`x[a-z`, ErrUnmatchedLbkt},
+ {`abc]`, ErrUnmatchedRbkt},
+ {`[z-a]`, ErrBadRange},
+ {`abc\`, ErrExtraneousBackslash},
+ {`a**`, ErrBadClosure},
+ {`a*+`, ErrBadClosure},
+ {`a??`, ErrBadClosure},
+ {`*`, ErrBareClosure},
+ {`\x`, ErrBadBackslash},
}
func compileTest(t *testing.T, expr string, error os.Error) *Regexp {
@@ -121,66 +59,6 @@ func compileTest(t *testing.T, expr string, error os.Error) *Regexp {
return re
}
-func printVec(t *testing.T, m []int) {
- l := len(m)
- if l == 0 {
- t.Log("\t<no match>")
- } else {
- if m[len(m)-1] == -1 {
- m = m[0 : len(m)-2]
- }
- t.Log("\t", m)
- }
-}
-
-func equal(m1, m2 []int) bool {
- l := len(m1)
- if l != len(m2) {
- return false
- }
- for i := 0; i < l; i++ {
- if m1[i] != m2[i] {
- return false
- }
- }
- return true
-}
-
-func equalStrings(m1, m2 []string) bool {
- l := len(m1)
- if l != len(m2) {
- return false
- }
- for i := 0; i < l; i++ {
- if m1[i] != m2[i] {
- return false
- }
- }
- return true
-}
-
-func executeTest(t *testing.T, expr string, str string, match []int) {
- re := compileTest(t, expr, nil)
- if re == nil {
- return
- }
- m := re.ExecuteString(str)
- if !equal(m, match) {
- t.Errorf("ExecuteString failure on %#q matching %q:", expr, str)
- printVec(t, m)
- t.Log("should be:")
- printVec(t, match)
- }
- // now try bytes
- m = re.Execute([]byte(str))
- if !equal(m, match) {
- t.Errorf("Execute failure on %#q matching %q:", expr, str)
- printVec(t, m)
- t.Log("should be:")
- printVec(t, match)
- }
-}
-
func TestGoodCompile(t *testing.T) {
for i := 0; i < len(good_re); i++ {
compileTest(t, good_re[i], nil)
@@ -193,57 +71,41 @@ func TestBadCompile(t *testing.T) {
}
}
-func TestExecute(t *testing.T) {
- for i := 0; i < len(matches); i++ {
- test := &matches[i]
- executeTest(t, test.re, test.text, test.match)
- }
-}
-
-func matchTest(t *testing.T, expr string, str string, match []int) {
- re := compileTest(t, expr, nil)
+func matchTest(t *testing.T, test *FindTest) {
+ re := compileTest(t, test.pat, nil)
if re == nil {
return
}
- m := re.MatchString(str)
- if m != (len(match) > 0) {
- t.Errorf("MatchString failure on %#q matching %q: %t should be %t", expr, str, m, len(match) > 0)
+ 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(str))
- if m != (len(match) > 0) {
- t.Errorf("Match failure on %#q matching %q: %t should be %t", expr, str, m, len(match) > 0)
+ 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 i := 0; i < len(matches); i++ {
- test := &matches[i]
- matchTest(t, test.re, test.text, test.match)
+ for _, test := range findTests {
+ matchTest(t, &test)
}
}
-func TestMatchStrings(t *testing.T) {
- for i := 0; i < len(matches); i++ {
- test := &matches[i]
- matchTest(t, test.re, test.text, test.match)
- }
-}
-
-func matchFunctionTest(t *testing.T, expr string, str string, match []int) {
- m, err := MatchString(expr, str)
+func matchFunctionTest(t *testing.T, test *FindTest) {
+ m, err := MatchString(test.pat, test.text)
if err == nil {
return
}
- if m != (len(match) > 0) {
- t.Errorf("Match failure on %#q matching %q: %d should be %d", expr, str, m, len(match) > 0)
+ 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 i := 0; i < len(matches); i++ {
- test := &matches[i]
- matchFunctionTest(t, test.re, test.text, test.match)
+ for _, test := range findTests {
+ matchFunctionTest(t, &test)
}
}
@@ -253,64 +115,64 @@ type ReplaceTest struct {
var replaceTests = []ReplaceTest{
// Test empty input and/or replacement, with pattern that matches the empty string.
- ReplaceTest{"", "", "", ""},
- ReplaceTest{"", "x", "", "x"},
- ReplaceTest{"", "", "abc", "abc"},
- ReplaceTest{"", "x", "abc", "xaxbxcx"},
+ {"", "", "", ""},
+ {"", "x", "", "x"},
+ {"", "", "abc", "abc"},
+ {"", "x", "abc", "xaxbxcx"},
// Test empty input and/or replacement, with pattern that does not match the empty string.
- ReplaceTest{"b", "", "", ""},
- ReplaceTest{"b", "x", "", ""},
- ReplaceTest{"b", "", "abc", "ac"},
- ReplaceTest{"b", "x", "abc", "axc"},
- ReplaceTest{"y", "", "", ""},
- ReplaceTest{"y", "x", "", ""},
- ReplaceTest{"y", "", "abc", "abc"},
- ReplaceTest{"y", "x", "abc", "abc"},
+ {"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.
- ReplaceTest{"[a-c]*", "x", "\u65e5", "x\u65e5x"},
- ReplaceTest{"[^\u65e5]", "x", "abc\u65e5def", "xxx\u65e5xxx"},
+ {"[a-c]*", "x", "\u65e5", "x\u65e5x"},
+ {"[^\u65e5]", "x", "abc\u65e5def", "xxx\u65e5xxx"},
// Start and end of a string.
- ReplaceTest{"^[a-c]*", "x", "abcdabc", "xdabc"},
- ReplaceTest{"[a-c]*$", "x", "abcdabc", "abcdx"},
- ReplaceTest{"^[a-c]*$", "x", "abcdabc", "abcdabc"},
- ReplaceTest{"^[a-c]*", "x", "abc", "x"},
- ReplaceTest{"[a-c]*$", "x", "abc", "x"},
- ReplaceTest{"^[a-c]*$", "x", "abc", "x"},
- ReplaceTest{"^[a-c]*", "x", "dabce", "xdabce"},
- ReplaceTest{"[a-c]*$", "x", "dabce", "dabcex"},
- ReplaceTest{"^[a-c]*$", "x", "dabce", "dabce"},
- ReplaceTest{"^[a-c]*", "x", "", "x"},
- ReplaceTest{"[a-c]*$", "x", "", "x"},
- ReplaceTest{"^[a-c]*$", "x", "", "x"},
-
- ReplaceTest{"^[a-c]+", "x", "abcdabc", "xdabc"},
- ReplaceTest{"[a-c]+$", "x", "abcdabc", "abcdx"},
- ReplaceTest{"^[a-c]+$", "x", "abcdabc", "abcdabc"},
- ReplaceTest{"^[a-c]+", "x", "abc", "x"},
- ReplaceTest{"[a-c]+$", "x", "abc", "x"},
- ReplaceTest{"^[a-c]+$", "x", "abc", "x"},
- ReplaceTest{"^[a-c]+", "x", "dabce", "dabce"},
- ReplaceTest{"[a-c]+$", "x", "dabce", "dabce"},
- ReplaceTest{"^[a-c]+$", "x", "dabce", "dabce"},
- ReplaceTest{"^[a-c]+", "x", "", ""},
- ReplaceTest{"[a-c]+$", "x", "", ""},
- ReplaceTest{"^[a-c]+$", "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", "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.
- ReplaceTest{"abc", "def", "abcdefg", "defdefg"},
- ReplaceTest{"bc", "BC", "abcbcdcdedef", "aBCBCdcdedef"},
- ReplaceTest{"abc", "", "abcdabc", "d"},
- ReplaceTest{"x", "xXx", "xxxXxxx", "xXxxXxxXxXxXxxXxxXx"},
- ReplaceTest{"abc", "d", "", ""},
- ReplaceTest{"abc", "d", "abc", "d"},
- ReplaceTest{".+", "x", "abc", "x"},
- ReplaceTest{"[a-c]*", "x", "def", "xdxexfx"},
- ReplaceTest{"[a-c]+", "x", "abcbcdcdedef", "xdxdedef"},
- ReplaceTest{"[a-c]*", "x", "abcbcdcdedef", "xdxdxexdxexfx"},
+ {"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 {
@@ -320,9 +182,9 @@ type ReplaceFuncTest struct {
}
var replaceFuncTests = []ReplaceFuncTest{
- ReplaceFuncTest{"[a-c]", func(s string) string { return "x" + s + "y" }, "defabcdef", "defxayxbyxcydef"},
- ReplaceFuncTest{"[a-c]+", func(s string) string { return "x" + s + "y" }, "defabcdef", "defxabcydef"},
- ReplaceFuncTest{"[a-c]*", func(s string) string { return "x" + s + "y" }, "defabcdef", "xydxyexyfxabcydxyexyfxy"},
+ {"[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) {
@@ -367,18 +229,21 @@ func TestReplaceAllFunc(t *testing.T) {
}
}
-type QuoteMetaTest struct {
- pattern, output string
+type MetaTest struct {
+ pattern, output, literal string
+ isLiteral bool
}
-var quoteMetaTests = []QuoteMetaTest{
- QuoteMetaTest{``, ``},
- QuoteMetaTest{`foo`, `foo`},
- QuoteMetaTest{`!@#$%^&*()_+-=[{]}\|,<.>/?~`, `!@#\$%\^&\*\(\)_\+-=\[{\]}\\\|,<\.>/\?~`},
+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 quoteMetaTests {
+ for _, tc := range metaTests {
// Verify that QuoteMeta returns the expected string.
quoted := QuoteMeta(tc.pattern)
if quoted != tc.output {
@@ -407,96 +272,16 @@ func TestQuoteMeta(t *testing.T) {
}
}
-type matchCase struct {
- matchfunc string
- input string
- n int
- regexp string
- expected []string
-}
-
-var matchCases = []matchCase{
- matchCase{"match", " aa b", 0, "[^ ]+", []string{"aa", "b"}},
- matchCase{"match", " aa b", 0, "[^ ]*", []string{"", "aa", "b"}},
- matchCase{"match", "a b c", 0, "[^ ]*", []string{"a", "b", "c"}},
- matchCase{"match", "a:a: a:", 0, "^.:", []string{"a:"}},
- matchCase{"match", "", 0, "[^ ]*", []string{""}},
- matchCase{"match", "", 0, "", []string{""}},
- matchCase{"match", "a", 0, "", []string{"", ""}},
- matchCase{"match", "ab", 0, "^", []string{""}},
- matchCase{"match", "ab", 0, "$", []string{""}},
- matchCase{"match", "ab", 0, "X*", []string{"", "", ""}},
- matchCase{"match", "aX", 0, "X*", []string{"", "X"}},
- matchCase{"match", "XabX", 0, "X*", []string{"X", "", "X"}},
-
- matchCase{"matchit", "", 0, ".", []string{}},
- matchCase{"matchit", "abc", 2, ".", []string{"a", "b"}},
- matchCase{"matchit", "abc", 0, ".", []string{"a", "b", "c"}},
-}
-
-func printStringSlice(t *testing.T, s []string) {
- t.Logf("%#v", s)
-}
-
-func TestAllMatches(t *testing.T) {
- ch := make(chan matchCase)
- go func() {
- for _, c := range matchCases {
- ch <- c
- stringCase := matchCase{
- "string" + c.matchfunc,
- c.input,
- c.n,
- c.regexp,
- c.expected,
- }
- ch <- stringCase
- }
- close(ch)
- }()
-
- for c := range ch {
- var result []string
- re, _ := Compile(c.regexp)
-
- switch c.matchfunc {
- case "matchit":
- result = make([]string, len(c.input)+1)
- i := 0
- b := []byte(c.input)
- for match := range re.AllMatchesIter(b, c.n) {
- result[i] = string(match)
- i++
- }
- result = result[0:i]
- case "stringmatchit":
- result = make([]string, len(c.input)+1)
- i := 0
- for match := range re.AllMatchesStringIter(c.input, c.n) {
- result[i] = match
- i++
- }
- result = result[0:i]
- case "match":
- result = make([]string, len(c.input)+1)
- b := []byte(c.input)
- i := 0
- for _, match := range re.AllMatches(b, c.n) {
- result[i] = string(match)
- i++
- }
- result = result[0:i]
- case "stringmatch":
- result = re.AllMatchesString(c.input, c.n)
+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 !equalStrings(result, c.expected) {
- t.Errorf("testing '%s'.%s('%s', %d), expected: ",
- c.regexp, c.matchfunc, c.input, c.n)
- printStringSlice(t, c.expected)
- t.Log("got: ")
- printStringSlice(t, result)
- t.Log("\n")
+ if str != tc.literal {
+ t.Errorf("LiteralPrefix(`%s`) = `%s`; want `%s`", tc.pattern, str, tc.literal)
}
}
}
@@ -507,16 +292,16 @@ type numSubexpCase struct {
}
var numSubexpCases = []numSubexpCase{
- numSubexpCase{``, 0},
- numSubexpCase{`.*`, 0},
- numSubexpCase{`abba`, 0},
- numSubexpCase{`ab(b)a`, 1},
- numSubexpCase{`ab(.*)a`, 1},
- numSubexpCase{`(.*)ab(.*)a`, 2},
- numSubexpCase{`(.*)(ab)(.*)a`, 3},
- numSubexpCase{`(.*)((a)b)(.*)a`, 4},
- numSubexpCase{`(.*)(\(ab)(.*)a`, 3},
- numSubexpCase{`(.*)(\(a\)b)(.*)a`, 3},
+ {``, 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) {
@@ -592,3 +377,49 @@ func BenchmarkReplaceAll(b *testing.B) {
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/regexp/find_test.go b/src/pkg/regexp/find_test.go
new file mode 100644
index 000000000..1690711dd
--- /dev/null
+++ b/src/pkg/regexp/find_test.go
@@ -0,0 +1,459 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package regexp
+
+import (
+ "fmt"
+ "testing"
+)
+
+// For each pattern/text pair, what is the expected output of each function?
+// We can derive the textual results from the indexed results, the non-submatch
+// results from the submatched results, the single results from the 'all' results,
+// and the byte results from the string results. Therefore the table includes
+// only the FindAllStringSubmatchIndex result.
+type FindTest struct {
+ pat string
+ text string
+ matches [][]int
+}
+
+func (t FindTest) String() string {
+ return fmt.Sprintf("pat: %#q text: %#q", t.pat, t.text)
+}
+
+var findTests = []FindTest{
+ {``, ``, build(1, 0, 0)},
+ {`^abcdefg`, "abcdefg", build(1, 0, 7)},
+ {`a+`, "baaab", build(1, 1, 4)},
+ {"abcd..", "abcdef", build(1, 0, 6)},
+ {`a`, "a", build(1, 0, 1)},
+ {`x`, "y", nil},
+ {`b`, "abc", build(1, 1, 2)},
+ {`.`, "a", build(1, 0, 1)},
+ {`.*`, "abcdef", build(1, 0, 6)},
+ {`^`, "abcde", build(1, 0, 0)},
+ {`$`, "abcde", build(1, 5, 5)},
+ {`^abcd$`, "abcd", build(1, 0, 4)},
+ {`^bcd'`, "abcdef", nil},
+ {`^abcd$`, "abcde", nil},
+ {`a+`, "baaab", build(1, 1, 4)},
+ {`a*`, "baaab", build(3, 0, 0, 1, 4, 5, 5)},
+ {`[a-z]+`, "abcd", build(1, 0, 4)},
+ {`[^a-z]+`, "ab1234cd", build(1, 2, 6)},
+ {`[a\-\]z]+`, "az]-bcz", build(2, 0, 4, 6, 7)},
+ {`[^\n]+`, "abcd\n", build(1, 0, 4)},
+ {`[日本語]+`, "日本語日本語", build(1, 0, 18)},
+ {`日本語+`, "日本語", build(1, 0, 9)},
+ {`日本語+`, "日本語語語語", build(1, 0, 18)},
+ {`()`, "", build(1, 0, 0, 0, 0)},
+ {`(a)`, "a", build(1, 0, 1, 0, 1)},
+ {`(.)(.)`, "日a", build(1, 0, 4, 0, 3, 3, 4)},
+ {`(.*)`, "", build(1, 0, 0, 0, 0)},
+ {`(.*)`, "abcd", build(1, 0, 4, 0, 4)},
+ {`(..)(..)`, "abcd", build(1, 0, 4, 0, 2, 2, 4)},
+ {`(([^xyz]*)(d))`, "abcd", build(1, 0, 4, 0, 4, 0, 3, 3, 4)},
+ {`((a|b|c)*(d))`, "abcd", build(1, 0, 4, 0, 4, 2, 3, 3, 4)},
+ {`(((a|b|c)*)(d))`, "abcd", build(1, 0, 4, 0, 4, 0, 3, 2, 3, 3, 4)},
+ {`\a\b\f\n\r\t\v`, "\a\b\f\n\r\t\v", build(1, 0, 7)},
+ {`[\a\b\f\n\r\t\v]+`, "\a\b\f\n\r\t\v", build(1, 0, 7)},
+
+ {`a*(|(b))c*`, "aacc", build(1, 0, 4, 2, 2, -1, -1)},
+ {`(.*).*`, "ab", build(1, 0, 2, 0, 2)},
+ {`[.]`, ".", build(1, 0, 1)},
+ {`/$`, "/abc/", build(1, 4, 5)},
+ {`/$`, "/abc", nil},
+
+ // multiple matches
+ {`.`, "abc", build(3, 0, 1, 1, 2, 2, 3)},
+ {`(.)`, "abc", build(3, 0, 1, 0, 1, 1, 2, 1, 2, 2, 3, 2, 3)},
+ {`.(.)`, "abcd", build(2, 0, 2, 1, 2, 2, 4, 3, 4)},
+ {`ab*`, "abbaab", build(3, 0, 3, 3, 4, 4, 6)},
+ {`a(b*)`, "abbaab", build(3, 0, 3, 1, 3, 3, 4, 4, 4, 4, 6, 5, 6)},
+
+ // fixed bugs
+ {`ab$`, "cab", build(1, 1, 3)},
+ {`axxb$`, "axxcb", nil},
+ {`data`, "daXY data", build(1, 5, 9)},
+ {`da(.)a$`, "daXY data", build(1, 5, 9, 7, 8)},
+ {`zx+`, "zzx", build(1, 1, 3)},
+
+ // can backslash-escape any punctuation
+ {`\!\"\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\{\|\}\~`,
+ `!"#$%&'()*+,-./:;<=>?@[\]^_{|}~`, build(1, 0, 31)},
+ {`[\!\"\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\{\|\}\~]+`,
+ `!"#$%&'()*+,-./:;<=>?@[\]^_{|}~`, build(1, 0, 31)},
+ {"\\`", "`", build(1, 0, 1)},
+ {"[\\`]+", "`", build(1, 0, 1)},
+
+ // long set of matches (longer than startSize)
+ {
+ ".",
+ "qwertyuiopasdfghjklzxcvbnm1234567890",
+ build(36, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10,
+ 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20,
+ 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 30,
+ 30, 31, 31, 32, 32, 33, 33, 34, 34, 35, 35, 36),
+ },
+}
+
+// build is a helper to construct a [][]int by extracting n sequences from x.
+// This represents n matches with len(x)/n submatches each.
+func build(n int, x ...int) [][]int {
+ ret := make([][]int, n)
+ runLength := len(x) / n
+ j := 0
+ for i := range ret {
+ ret[i] = make([]int, runLength)
+ copy(ret[i], x[j:])
+ j += runLength
+ if j > len(x) {
+ panic("invalid build entry")
+ }
+ }
+ return ret
+}
+
+// First the simple cases.
+
+func TestFind(t *testing.T) {
+ for _, test := range findTests {
+ re := MustCompile(test.pat)
+ if re.String() != test.pat {
+ t.Errorf("String() = `%s`; should be `%s`", re.String(), test.pat)
+ }
+ result := re.Find([]byte(test.text))
+ switch {
+ case len(test.matches) == 0 && len(result) == 0:
+ // ok
+ case test.matches == nil && result != nil:
+ t.Errorf("expected no match; got one: %s", test)
+ case test.matches != nil && result == nil:
+ t.Errorf("expected match; got none: %s", test)
+ case test.matches != nil && result != nil:
+ expect := test.text[test.matches[0][0]:test.matches[0][1]]
+ if expect != string(result) {
+ t.Errorf("expected %q got %q: %s", expect, result, test)
+ }
+ }
+ }
+}
+
+func TestFindString(t *testing.T) {
+ for _, test := range findTests {
+ result := MustCompile(test.pat).FindString(test.text)
+ switch {
+ case len(test.matches) == 0 && len(result) == 0:
+ // ok
+ case test.matches == nil && result != "":
+ t.Errorf("expected no match; got one: %s", test)
+ case test.matches != nil && result == "":
+ // Tricky because an empty result has two meanings: no match or empty match.
+ if test.matches[0][0] != test.matches[0][1] {
+ t.Errorf("expected match; got none: %s", test)
+ }
+ case test.matches != nil && result != "":
+ expect := test.text[test.matches[0][0]:test.matches[0][1]]
+ if expect != result {
+ t.Errorf("expected %q got %q: %s", expect, result, test)
+ }
+ }
+ }
+}
+
+func testFindIndex(test *FindTest, result []int, t *testing.T) {
+ switch {
+ case len(test.matches) == 0 && len(result) == 0:
+ // ok
+ case test.matches == nil && result != nil:
+ t.Errorf("expected no match; got one: %s", test)
+ case test.matches != nil && result == nil:
+ t.Errorf("expected match; got none: %s", test)
+ case test.matches != nil && result != nil:
+ expect := test.matches[0]
+ if expect[0] != result[0] || expect[1] != result[1] {
+ t.Errorf("expected %v got %v: %s", expect, result, test)
+ }
+ }
+}
+
+func TestFindIndex(t *testing.T) {
+ for _, test := range findTests {
+ testFindIndex(&test, MustCompile(test.pat).FindIndex([]byte(test.text)), t)
+ }
+}
+
+func TestFindStringIndex(t *testing.T) {
+ for _, test := range findTests {
+ testFindIndex(&test, MustCompile(test.pat).FindStringIndex(test.text), t)
+ }
+}
+
+// Now come the simple All cases.
+
+func TestFindAll(t *testing.T) {
+ for _, test := range findTests {
+ result := MustCompile(test.pat).FindAll([]byte(test.text), -1)
+ switch {
+ case test.matches == nil && result == nil:
+ // ok
+ case test.matches == nil && result != nil:
+ t.Errorf("expected no match; got one: %s", test)
+ case test.matches != nil && result == nil:
+ t.Errorf("expected match; got none: %s", test)
+ case test.matches != nil && result != nil:
+ if len(test.matches) != len(result) {
+ t.Errorf("expected %d matches; got %d: %s", len(test.matches), len(result), test)
+ continue
+ }
+ for k, e := range test.matches {
+ expect := test.text[e[0]:e[1]]
+ if expect != string(result[k]) {
+ t.Errorf("match %d: expected %q got %q: %s", k, expect, result[k], test)
+ }
+ }
+ }
+ }
+}
+
+func TestFindAllString(t *testing.T) {
+ for _, test := range findTests {
+ result := MustCompile(test.pat).FindAllString(test.text, -1)
+ switch {
+ case test.matches == nil && result == nil:
+ // ok
+ case test.matches == nil && result != nil:
+ t.Errorf("expected no match; got one: %s", test)
+ case test.matches != nil && result == nil:
+ t.Errorf("expected match; got none: %s", test)
+ case test.matches != nil && result != nil:
+ if len(test.matches) != len(result) {
+ t.Errorf("expected %d matches; got %d: %s", len(test.matches), len(result), test)
+ continue
+ }
+ for k, e := range test.matches {
+ expect := test.text[e[0]:e[1]]
+ if expect != result[k] {
+ t.Errorf("expected %q got %q: %s", expect, result, test)
+ }
+ }
+ }
+ }
+}
+
+func testFindAllIndex(test *FindTest, result [][]int, t *testing.T) {
+ switch {
+ case test.matches == nil && result == nil:
+ // ok
+ case test.matches == nil && result != nil:
+ t.Errorf("expected no match; got one: %s", test)
+ case test.matches != nil && result == nil:
+ t.Errorf("expected match; got none: %s", test)
+ case test.matches != nil && result != nil:
+ if len(test.matches) != len(result) {
+ t.Errorf("expected %d matches; got %d: %s", len(test.matches), len(result), test)
+ return
+ }
+ for k, e := range test.matches {
+ if e[0] != result[k][0] || e[1] != result[k][1] {
+ t.Errorf("match %d: expected %v got %v: %s", k, e, result[k], test)
+ }
+ }
+ }
+}
+
+func TestFindAllIndex(t *testing.T) {
+ for _, test := range findTests {
+ testFindAllIndex(&test, MustCompile(test.pat).FindAllIndex([]byte(test.text), -1), t)
+ }
+}
+
+func TestFindAllStringIndex(t *testing.T) {
+ for _, test := range findTests {
+ testFindAllIndex(&test, MustCompile(test.pat).FindAllStringIndex(test.text, -1), t)
+ }
+}
+
+// Now come the Submatch cases.
+
+func testSubmatchBytes(test *FindTest, n int, submatches []int, result [][]byte, t *testing.T) {
+ if len(submatches) != len(result)*2 {
+ t.Errorf("match %d: expected %d submatches; got %d: %s", n, len(submatches)/2, len(result), test)
+ return
+ }
+ for k := 0; k < len(submatches); k += 2 {
+ if submatches[k] == -1 {
+ if result[k/2] != nil {
+ t.Errorf("match %d: expected nil got %q: %s", n, result, test)
+ }
+ continue
+ }
+ expect := test.text[submatches[k]:submatches[k+1]]
+ if expect != string(result[k/2]) {
+ t.Errorf("match %d: expected %q got %q: %s", n, expect, result, test)
+ return
+ }
+ }
+}
+
+func TestFindSubmatch(t *testing.T) {
+ for _, test := range findTests {
+ result := MustCompile(test.pat).FindSubmatch([]byte(test.text))
+ switch {
+ case test.matches == nil && result == nil:
+ // ok
+ case test.matches == nil && result != nil:
+ t.Errorf("expected no match; got one: %s", test)
+ case test.matches != nil && result == nil:
+ t.Errorf("expected match; got none: %s", test)
+ case test.matches != nil && result != nil:
+ testSubmatchBytes(&test, 0, test.matches[0], result, t)
+ }
+ }
+}
+
+func testSubmatchString(test *FindTest, n int, submatches []int, result []string, t *testing.T) {
+ if len(submatches) != len(result)*2 {
+ t.Errorf("match %d: expected %d submatches; got %d: %s", n, len(submatches)/2, len(result), test)
+ return
+ }
+ for k := 0; k < len(submatches); k += 2 {
+ if submatches[k] == -1 {
+ if result[k/2] != "" {
+ t.Errorf("match %d: expected nil got %q: %s", n, result, test)
+ }
+ continue
+ }
+ expect := test.text[submatches[k]:submatches[k+1]]
+ if expect != result[k/2] {
+ t.Errorf("match %d: expected %q got %q: %s", n, expect, result, test)
+ return
+ }
+ }
+}
+
+func TestFindStringSubmatch(t *testing.T) {
+ for _, test := range findTests {
+ result := MustCompile(test.pat).FindStringSubmatch(test.text)
+ switch {
+ case test.matches == nil && result == nil:
+ // ok
+ case test.matches == nil && result != nil:
+ t.Errorf("expected no match; got one: %s", test)
+ case test.matches != nil && result == nil:
+ t.Errorf("expected match; got none: %s", test)
+ case test.matches != nil && result != nil:
+ testSubmatchString(&test, 0, test.matches[0], result, t)
+ }
+ }
+}
+
+func testSubmatchIndices(test *FindTest, n int, expect, result []int, t *testing.T) {
+ if len(expect) != len(result) {
+ t.Errorf("match %d: expected %d matches; got %d: %s", n, len(expect)/2, len(result)/2, test)
+ return
+ }
+ for k, e := range expect {
+ if e != result[k] {
+ t.Errorf("match %d: submatch error: expected %v got %v: %s", n, expect, result, test)
+ }
+ }
+}
+
+func testFindSubmatchIndex(test *FindTest, result []int, t *testing.T) {
+ switch {
+ case test.matches == nil && result == nil:
+ // ok
+ case test.matches == nil && result != nil:
+ t.Errorf("expected no match; got one: %s", test)
+ case test.matches != nil && result == nil:
+ t.Errorf("expected match; got none: %s", test)
+ case test.matches != nil && result != nil:
+ testSubmatchIndices(test, 0, test.matches[0], result, t)
+ }
+}
+
+func TestFindSubmatchIndex(t *testing.T) {
+ for _, test := range findTests {
+ testFindSubmatchIndex(&test, MustCompile(test.pat).FindSubmatchIndex([]byte(test.text)), t)
+ }
+}
+
+func TestFindStringSubmatchndex(t *testing.T) {
+ for _, test := range findTests {
+ testFindSubmatchIndex(&test, MustCompile(test.pat).FindStringSubmatchIndex(test.text), t)
+ }
+}
+
+// Now come the monster AllSubmatch cases.
+
+func TestFindAllSubmatch(t *testing.T) {
+ for _, test := range findTests {
+ result := MustCompile(test.pat).FindAllSubmatch([]byte(test.text), -1)
+ switch {
+ case test.matches == nil && result == nil:
+ // ok
+ case test.matches == nil && result != nil:
+ t.Errorf("expected no match; got one: %s", test)
+ case test.matches != nil && result == nil:
+ t.Errorf("expected match; got none: %s", test)
+ case len(test.matches) != len(result):
+ t.Errorf("expected %d matches; got %d: %s", len(test.matches), len(result), test)
+ case test.matches != nil && result != nil:
+ for k, match := range test.matches {
+ testSubmatchBytes(&test, k, match, result[k], t)
+ }
+ }
+ }
+}
+
+func TestFindAllStringSubmatch(t *testing.T) {
+ for _, test := range findTests {
+ result := MustCompile(test.pat).FindAllStringSubmatch(test.text, -1)
+ switch {
+ case test.matches == nil && result == nil:
+ // ok
+ case test.matches == nil && result != nil:
+ t.Errorf("expected no match; got one: %s", test)
+ case test.matches != nil && result == nil:
+ t.Errorf("expected match; got none: %s", test)
+ case len(test.matches) != len(result):
+ t.Errorf("expected %d matches; got %d: %s", len(test.matches), len(result), test)
+ case test.matches != nil && result != nil:
+ for k, match := range test.matches {
+ testSubmatchString(&test, k, match, result[k], t)
+ }
+ }
+ }
+}
+
+func testFindAllSubmatchIndex(test *FindTest, result [][]int, t *testing.T) {
+ switch {
+ case test.matches == nil && result == nil:
+ // ok
+ case test.matches == nil && result != nil:
+ t.Errorf("expected no match; got one: %s", test)
+ case test.matches != nil && result == nil:
+ t.Errorf("expected match; got none: %s", test)
+ case len(test.matches) != len(result):
+ t.Errorf("expected %d matches; got %d: %s", len(test.matches), len(result), test)
+ case test.matches != nil && result != nil:
+ for k, match := range test.matches {
+ testSubmatchIndices(test, k, match, result[k], t)
+ }
+ }
+}
+
+func TestFindAllSubmatchIndex(t *testing.T) {
+ for _, test := range findTests {
+ testFindAllSubmatchIndex(&test, MustCompile(test.pat).FindAllSubmatchIndex([]byte(test.text), -1), t)
+ }
+}
+
+func TestFindAllStringSubmatchndex(t *testing.T) {
+ for _, test := range findTests {
+ testFindAllSubmatchIndex(&test, MustCompile(test.pat).FindAllStringSubmatchIndex(test.text, -1), t)
+ }
+}
diff --git a/src/pkg/regexp/regexp.go b/src/pkg/regexp/regexp.go
index 4dd430ea6..2e03b798a 100644
--- a/src/pkg/regexp/regexp.go
+++ b/src/pkg/regexp/regexp.go
@@ -16,14 +16,50 @@
// '$'
// '.'
// character
-// '[' [ '^' ] character-ranges ']'
+// '[' [ '^' ] { character-range } ']'
// '(' regexp ')'
+// character-range:
+// character [ '-' character ]
+//
+// All characters are UTF-8-encoded code points. Backslashes escape special
+// characters, including inside character classes. The standard Go character
+// escapes are also recognized: \a \b \f \n \r \t \v.
+//
+// There are 16 methods of Regexp that match a regular expression and identify
+// the matched text. Their names are matched by this regular expression:
+//
+// Find(All)?(String)?(Submatch)?(Index)?
+//
+// If 'All' is present, the routine matches successive non-overlapping
+// matches of the entire expression. Empty matches abutting a preceding
+// match are ignored. The return value is a slice containing the successive
+// return values of the corresponding non-'All' routine. These routines take
+// an extra integer argument, n; if n >= 0, the function returns at most n
+// matches/submatches.
+//
+// If 'String' is present, the argument is a string; otherwise it is a slice
+// of bytes; return values are adjusted as appropriate.
+//
+// If 'Submatch' is present, the return value is a slice identifying the
+// successive submatches of the expression. Submatches are matches of
+// parenthesized subexpressions within the regular expression, numbered from
+// left to right in order of opening parenthesis. Submatch 0 is the match of
+// the entire expression, submatch 1 the match of the first parenthesized
+// subexpression, and so on.
+//
+// If 'Index' is present, matches and submatches are identified by byte index
+// pairs within the input string: result[2*n:2*n+1] identifies the indexes of
+// the nth submatch. The pair for n==0 identifies the match of the entire
+// expression. If 'Index' is not present, the match is identified by the
+// text of the match/submatch. If an index is negative, it means that
+// subexpression did not match any string in the input.
+//
+// (There are a few other methods that do not match this pattern.)
//
package regexp
import (
"bytes"
- "container/vector"
"io"
"os"
"strings"
@@ -53,121 +89,90 @@ var (
ErrBadBackslash = Error("illegal backslash escape")
)
-// An instruction executed by the NFA
-type instr interface {
- kind() int // the type of this instruction: _CHAR, _ANY, etc.
- next() instr // the instruction to execute after this one
- setNext(i instr)
- index() int
- setIndex(i int)
- print()
-}
+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
+)
-// Fields and methods common to all instructions
-type common struct {
- _next instr
- _index int
+// 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")
+ }
}
-func (c *common) next() instr { return c._next }
-func (c *common) setNext(i instr) { c._next = i }
-func (c *common) index() int { return c._index }
-func (c *common) setIndex(i int) { c._index = i }
-
// Regexp is the representation of a compiled regular expression.
// The public interface is entirely through methods.
type Regexp struct {
expr string // the original expression
prefix string // initial plain text string
prefixBytes []byte // initial plain text bytes
- inst *vector.Vector
- 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
-}
-
-const (
- _START = iota // beginning of program
- _END // end of program: success
- _BOT // '^' beginning of text
- _EOT // '$' end of text
- _CHAR // 'a' regular character
- _CHARCLASS // [a-z] character class
- _ANY // '.' any character including newline
- _NOTNL // [^\n] special case: any character but newline
- _BRA // '(' parenthesized expression
- _EBRA // ')'; end of '(' parenthesized expression
- _ALT // '|' alternation
- _NOP // do nothing; makes it easy to link without patching
-)
-
-// --- START start of program
-type _Start struct {
- common
+ 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
}
-func (start *_Start) kind() int { return _START }
-func (start *_Start) print() { print("start") }
-
-// --- END end of program
-type _End struct {
- common
-}
-
-func (end *_End) kind() int { return _END }
-func (end *_End) print() { print("end") }
-
-// --- BOT beginning of text
-type _Bot struct {
- common
-}
-
-func (bot *_Bot) kind() int { return _BOT }
-func (bot *_Bot) print() { print("bot") }
-
-// --- EOT end of text
-type _Eot struct {
- common
-}
-
-func (eot *_Eot) kind() int { return _EOT }
-func (eot *_Eot) print() { print("eot") }
-
-// --- CHAR a regular character
-type _Char struct {
- common
- char int
-}
-
-func (char *_Char) kind() int { return _CHAR }
-func (char *_Char) print() { print("char ", string(char.char)) }
-
-func newChar(char int) *_Char {
- c := new(_Char)
- c.char = char
- return c
-}
-
-// --- CHARCLASS [a-z]
-
-type _CharClass struct {
- common
+type charClass struct {
negate bool // is character class negated? ([^a-z])
- // vector of int, stored pairwise: [a-z] is (a,z); x is (x,x):
- ranges *vector.IntVector
+ // slice of int, stored pairwise: [a-z] is (a,z); x is (x,x):
+ ranges []int
cmin, cmax int
}
-func (cclass *_CharClass) kind() int { return _CHARCLASS }
-
-func (cclass *_CharClass) print() {
+func (cclass *charClass) print() {
print("charclass")
if cclass.negate {
print(" (negated)")
}
- for i := 0; i < cclass.ranges.Len(); i += 2 {
- l := cclass.ranges.At(i)
- r := cclass.ranges.At(i + 1)
+ 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 {
@@ -176,10 +181,9 @@ func (cclass *_CharClass) print() {
}
}
-func (cclass *_CharClass) addRange(a, b int) {
+func (cclass *charClass) addRange(a, b int) {
// range is a through b inclusive
- cclass.ranges.Push(a)
- cclass.ranges.Push(b)
+ cclass.ranges = append(cclass.ranges, a, b)
if a < cclass.cmin {
cclass.cmin = a
}
@@ -188,11 +192,11 @@ func (cclass *_CharClass) addRange(a, b int) {
}
}
-func (cclass *_CharClass) matches(c int) bool {
+func (cclass *charClass) matches(c int) bool {
if c < cclass.cmin || c > cclass.cmax {
return cclass.negate
}
- ranges := []int(*cclass.ranges)
+ ranges := cclass.ranges
for i := 0; i < len(ranges); i = i + 2 {
if ranges[i] <= c && c <= ranges[i+1] {
return !cclass.negate
@@ -201,68 +205,18 @@ func (cclass *_CharClass) matches(c int) bool {
return cclass.negate
}
-func newCharClass() *_CharClass {
- c := new(_CharClass)
- c.ranges = new(vector.IntVector)
- c.cmin = 0x10FFFF + 1 // MaxRune + 1
- c.cmax = -1
- return c
-}
-
-// --- ANY any character
-type _Any struct {
- common
-}
-
-func (any *_Any) kind() int { return _ANY }
-func (any *_Any) print() { print("any") }
-
-// --- NOTNL any character but newline
-type _NotNl struct {
- common
-}
-
-func (notnl *_NotNl) kind() int { return _NOTNL }
-func (notnl *_NotNl) print() { print("notnl") }
-
-// --- BRA parenthesized expression
-type _Bra struct {
- common
- n int // subexpression number
-}
-
-func (bra *_Bra) kind() int { return _BRA }
-func (bra *_Bra) print() { print("bra", bra.n) }
-
-// --- EBRA end of parenthesized expression
-type _Ebra struct {
- common
- n int // subexpression number
-}
-
-func (ebra *_Ebra) kind() int { return _EBRA }
-func (ebra *_Ebra) print() { print("ebra ", ebra.n) }
-
-// --- ALT alternation
-type _Alt struct {
- common
- left instr // other branch
-}
-
-func (alt *_Alt) kind() int { return _ALT }
-func (alt *_Alt) print() { print("alt(", alt.left.index(), ")") }
-
-// --- NOP no operation
-type _Nop struct {
- common
+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 (nop *_Nop) kind() int { return _NOP }
-func (nop *_Nop) print() { print("nop") }
-
-func (re *Regexp) add(i instr) instr {
- i.setIndex(re.inst.Len())
- re.inst.Push(i)
+func (re *Regexp) add(i *instr) *instr {
+ i.index = len(re.inst)
+ re.inst = append(re.inst, i)
return i
}
@@ -317,8 +271,21 @@ func ispunct(c int) bool {
return false
}
-func (p *parser) charClass() instr {
- cc := newCharClass()
+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) charClass() *instr {
+ i := newCharClass()
+ cc := i.cclass
if p.c() == '^' {
cc.negate = true
p.nextc()
@@ -331,20 +298,20 @@ func (p *parser) charClass() instr {
p.error(ErrBadRange)
}
// Is it [^\n]?
- if cc.negate && cc.ranges.Len() == 2 &&
- cc.ranges.At(0) == '\n' && cc.ranges.At(1) == '\n' {
- nl := new(_NotNl)
+ 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 && cc.ranges.Len() == 2 && cc.ranges.At(0) == cc.ranges.At(1) {
- c := newChar(cc.ranges.At(0))
+ 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(cc)
- return cc
+ p.re.add(i)
+ return i
case '-': // do this before backslash processing
p.error(ErrBadRange)
case '\\':
@@ -352,10 +319,10 @@ func (p *parser) charClass() instr {
switch {
case c == endOfFile:
p.error(ErrExtraneousBackslash)
- case c == 'n':
- c = '\n'
case ispunct(c):
// c is as delivered
+ case escape(c) >= 0:
+ c = int(escaped[escape(c)])
default:
p.error(ErrBadBackslash)
}
@@ -381,7 +348,7 @@ func (p *parser) charClass() instr {
return nil
}
-func (p *parser) term() (start, end instr) {
+func (p *parser) term() (start, end *instr) {
switch c := p.c(); c {
case '|', endOfFile:
return nil, nil
@@ -396,15 +363,15 @@ func (p *parser) term() (start, end instr) {
p.error(ErrUnmatchedRbkt)
case '^':
p.nextc()
- start = p.re.add(new(_Bot))
+ start = p.re.add(&instr{kind: iBOT})
return start, start
case '$':
p.nextc()
- start = p.re.add(new(_Eot))
+ start = p.re.add(&instr{kind: iEOT})
return start, start
case '.':
p.nextc()
- start = p.re.add(new(_Any))
+ start = p.re.add(&instr{kind: iAny})
return start, start
case '[':
p.nextc()
@@ -425,12 +392,10 @@ func (p *parser) term() (start, end instr) {
}
p.nlpar--
p.nextc()
- bra := new(_Bra)
+ bra := &instr{kind: iBra, braNum: 2 * nbra}
p.re.add(bra)
- ebra := new(_Ebra)
+ ebra := &instr{kind: iBra, braNum: 2*nbra + 1}
p.re.add(ebra)
- bra.n = nbra
- ebra.n = nbra
if start == nil {
if end == nil {
p.error(ErrInternal)
@@ -438,33 +403,33 @@ func (p *parser) term() (start, end instr) {
}
start = ebra
} else {
- end.setNext(ebra)
+ end.next = ebra
}
- bra.setNext(start)
+ bra.next = start
return bra, ebra
case '\\':
c = p.nextc()
switch {
case c == endOfFile:
p.error(ErrExtraneousBackslash)
- case c == 'n':
- c = '\n'
case ispunct(c):
// c is as delivered
+ case escape(c) >= 0:
+ c = int(escaped[escape(c)])
default:
p.error(ErrBadBackslash)
}
fallthrough
default:
p.nextc()
- start = newChar(c)
+ start = &instr{kind: iChar, char: c}
p.re.add(start)
return start, start
}
panic("unreachable")
}
-func (p *parser) closure() (start, end instr) {
+func (p *parser) closure() (start, end *instr) {
start, end = p.term()
if start == nil {
return
@@ -472,28 +437,28 @@ func (p *parser) closure() (start, end instr) {
switch p.c() {
case '*':
// (start,end)*:
- alt := new(_Alt)
+ alt := &instr{kind: iAlt}
p.re.add(alt)
- end.setNext(alt) // after end, do 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 := new(_Alt)
+ alt := &instr{kind: iAlt}
p.re.add(alt)
- end.setNext(alt) // after end, do 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 := new(_Alt)
+ alt := &instr{kind: iAlt}
p.re.add(alt)
- nop := new(_Nop)
+ nop := &instr{kind: iNop}
p.re.add(nop)
alt.left = start // alternate branch is start
- alt.setNext(nop) // follow on to nop
- end.setNext(nop) // after end, go to nop
+ 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:
@@ -506,27 +471,27 @@ func (p *parser) closure() (start, end instr) {
return
}
-func (p *parser) concatenation() (start, end instr) {
+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(new(_Nop))
+ 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.setNext(nstart)
+ end.next = nstart
end = nend
}
}
panic("unreachable")
}
-func (p *parser) regexp() (start, end instr) {
+func (p *parser) regexp() (start, end *instr) {
start, end = p.concatenation()
for {
switch p.c() {
@@ -535,49 +500,46 @@ func (p *parser) regexp() (start, end instr) {
case '|':
p.nextc()
nstart, nend := p.concatenation()
- alt := new(_Alt)
+ alt := &instr{kind: iAlt}
p.re.add(alt)
alt.left = start
- alt.setNext(nstart)
- nop := new(_Nop)
+ alt.next = nstart
+ nop := &instr{kind: iNop}
p.re.add(nop)
- end.setNext(nop)
- nend.setNext(nop)
+ end.next = nop
+ nend.next = nop
start, end = alt, nop
}
}
panic("unreachable")
}
-func unNop(i instr) instr {
- for i.kind() == _NOP {
- i = i.next()
+func unNop(i *instr) *instr {
+ for i.kind == iNop {
+ i = i.next
}
return i
}
func (re *Regexp) eliminateNops() {
- for i := 0; i < re.inst.Len(); i++ {
- inst := re.inst.At(i).(instr)
- if inst.kind() == _END {
+ for _, inst := range re.inst {
+ if inst.kind == iEnd {
continue
}
- inst.setNext(unNop(inst.next()))
- if inst.kind() == _ALT {
- alt := inst.(*_Alt)
- alt.left = unNop(alt.left)
+ inst.next = unNop(inst.next)
+ if inst.kind == iAlt {
+ inst.left = unNop(inst.left)
}
}
}
func (re *Regexp) dump() {
print("prefix <", re.prefix, ">\n")
- for i := 0; i < re.inst.Len(); i++ {
- inst := re.inst.At(i).(instr)
- print(inst.index(), ": ")
+ for _, inst := range re.inst {
+ print(inst.index, ": ")
inst.print()
- if inst.kind() != _END {
- print(" -> ", inst.next().index())
+ if inst.kind != iEnd {
+ print(" -> ", inst.next.index)
}
print("\n")
}
@@ -585,12 +547,12 @@ func (re *Regexp) dump() {
func (re *Regexp) doParse() {
p := newParser(re)
- start := new(_Start)
+ start := &instr{kind: iStart}
re.add(start)
s, e := p.regexp()
- start.setNext(s)
+ start.next = s
re.start = start
- e.setNext(re.add(new(_End)))
+ e.next = re.add(&instr{kind: iEnd})
if debug {
re.dump()
@@ -609,36 +571,44 @@ func (re *Regexp) doParse() {
}
}
-// Extract regular text from the beginning of the pattern.
+// 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)
- // First instruction is start; skip that.
- i := re.inst.At(0).(instr).next().index()
+ 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 i < re.inst.Len() {
- inst := re.inst.At(i).(instr)
+ for ; inst.kind != iEnd; inst = inst.next {
// stop if this is not a char
- if inst.kind() != _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 re.inst.At(inst.next().index()).(instr).kind() {
- case _BOT, _EOT, _ALT:
+ switch inst.next.kind {
+ case iBOT, iEOT, iAlt:
break Loop
}
- n := utf8.EncodeRune(inst.(*_Char).char, utf)
- b = bytes.Add(b, utf[0:n])
- i = inst.next().index()
+ n := utf8.EncodeRune(utf, inst.char)
+ b = append(b, utf[0:n]...)
}
// point prefixStart instruction to first non-CHAR after prefix
- re.prefixStart = re.inst.At(i).(instr)
+ re.prefixStart = inst
re.prefixBytes = b
re.prefix = string(b)
}
+// String returns the source text used to compile the regular expression.
+func (re *Regexp) String() string {
+ return re.expr
+}
+
// Compile parses a regular expression and returns, if successful, a Regexp
// object that can be used to match against text.
func Compile(str string) (regexp *Regexp, error os.Error) {
@@ -651,7 +621,7 @@ func Compile(str string) (regexp *Regexp, error os.Error) {
}
}()
regexp.expr = str
- regexp.inst = new(vector.Vector)
+ regexp.inst = make([]*instr, 0, 10)
regexp.doParse()
return
}
@@ -727,60 +697,45 @@ func (a *matchArena) noMatch() *matchVec {
}
type state struct {
- inst instr // next instruction to execute
- prefixed bool // this match began with a fixed prefix
+ inst *instr // next instruction to execute
+ prefixed bool // this match began with a fixed prefix
match *matchVec
}
// Append new state to to-do list. Leftmost-longest wins so avoid
// adding a state that's already active. The matchVec will be inc-ref'ed
// if it is assigned to a state.
-func (a *matchArena) addState(s []state, inst instr, prefixed bool, match *matchVec, pos, end int) []state {
- switch inst.kind() {
- case _BOT:
+func (a *matchArena) addState(s []state, inst *instr, prefixed bool, match *matchVec, pos, end int) []state {
+ switch inst.kind {
+ case iBOT:
if pos == 0 {
- s = a.addState(s, inst.next(), prefixed, match, pos, end)
+ s = a.addState(s, inst.next, prefixed, match, pos, end)
}
return s
- case _EOT:
+ case iEOT:
if pos == end {
- s = a.addState(s, inst.next(), prefixed, match, pos, end)
+ s = a.addState(s, inst.next, prefixed, match, pos, end)
}
return s
- case _BRA:
- n := inst.(*_Bra).n
- match.m[2*n] = pos
- s = a.addState(s, inst.next(), prefixed, match, pos, end)
- return s
- case _EBRA:
- n := inst.(*_Ebra).n
- match.m[2*n+1] = pos
- s = a.addState(s, inst.next(), prefixed, match, pos, end)
+ case iBra:
+ match.m[inst.braNum] = pos
+ s = a.addState(s, inst.next, prefixed, match, pos, end)
return s
}
- index := inst.index()
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.index() == index {
+ if s[i].inst == inst {
return s
}
}
- if l == cap(s) {
- s1 := make([]state, 2*l)[0:l]
- copy(s1, s)
- s = s1
- }
- s = s[0 : l+1]
- s[l].inst = inst
- s[l].prefixed = prefixed
- s[l].match = match
+ s = append(s, state{inst, prefixed, match})
match.ref++
- if inst.kind() == _ALT {
- s = a.addState(s, inst.(*_Alt).left, prefixed, a.copy(match), pos, end)
+ if inst.kind == iAlt {
+ s = a.addState(s, inst.left, prefixed, a.copy(match), pos, end)
// give other branch a copy of this match vector
- s = a.addState(s, inst.next(), prefixed, a.copy(match), pos, end)
+ s = a.addState(s, inst.next, prefixed, a.copy(match), pos, end)
}
return s
}
@@ -789,8 +744,8 @@ func (a *matchArena) addState(s []state, inst instr, prefixed bool, match *match
// If bytes == nil, scan str.
func (re *Regexp) doExecute(str string, bytestr []byte, pos int) []int {
var s [2][]state
- s[0] = make([]state, 10)[0:0]
- s[1] = make([]state, 10)[0:0]
+ s[0] = make([]state, 0, 10)
+ s[1] = make([]state, 0, 10)
in, out := 0, 1
var final state
found := false
@@ -798,34 +753,46 @@ func (re *Regexp) doExecute(str string, bytestr []byte, pos int) []int {
if bytestr != nil {
end = len(bytestr)
}
+ anchored := re.inst[0].next.kind == iBOT
+ if anchored && pos > 0 {
+ return nil
+ }
// fast check for initial plain substring
- prefixed := false // has this iteration begun by skipping a prefix?
if re.prefix != "" {
- var advance int
- if bytestr == nil {
- advance = strings.Index(str[pos:], re.prefix)
+ advance := 0
+ if anchored {
+ if bytestr == nil {
+ if !strings.HasPrefix(str, re.prefix) {
+ return nil
+ }
+ } else {
+ if !bytes.HasPrefix(bytestr, re.prefixBytes) {
+ return nil
+ }
+ }
} else {
- advance = bytes.Index(bytestr[pos:], re.prefixBytes)
+ if bytestr == nil {
+ advance = strings.Index(str[pos:], re.prefix)
+ } else {
+ advance = bytes.Index(bytestr[pos:], re.prefixBytes)
+ }
}
if advance == -1 {
- return []int{}
+ return nil
}
- pos += advance + len(re.prefix)
- prefixed = true
+ pos += advance
}
arena := &matchArena{nil, 2 * (re.nbra + 1)}
- for pos <= end {
- if !found {
+ for startPos := pos; pos <= end; {
+ if !found && (pos == startPos || !anchored) {
// prime the pump if we haven't seen a match yet
match := arena.noMatch()
match.m[0] = pos
- if prefixed {
- s[out] = arena.addState(s[out], re.prefixStart, true, match, pos, end)
- prefixed = false // next iteration should start at beginning of machine.
- } else {
- s[out] = arena.addState(s[out], re.start.next(), false, match, pos, end)
- }
+ s[out] = arena.addState(s[out], re.start.next, false, match, pos, end)
arena.free(match) // if addState saved it, ref was incremented
+ } else if len(s[out]) == 0 {
+ // machine has completed
+ break
}
in, out = out, in // old out state is new in state
// clear out old state
@@ -834,10 +801,6 @@ func (re *Regexp) doExecute(str string, bytestr []byte, pos int) []int {
arena.free(state.match)
}
s[out] = old[0:0] // truncate state vector
- if found && len(s[in]) == 0 {
- // machine has completed
- break
- }
charwidth := 1
c := endOfFile
if pos < end {
@@ -849,29 +812,28 @@ func (re *Regexp) doExecute(str string, bytestr []byte, pos int) []int {
}
pos += charwidth
for _, st := range s[in] {
- switch st.inst.kind() {
- case _BOT:
- case _EOT:
- case _CHAR:
- if c == st.inst.(*_Char).char {
- s[out] = arena.addState(s[out], st.inst.next(), st.prefixed, st.match, pos, end)
+ switch st.inst.kind {
+ case iBOT:
+ case iEOT:
+ case iChar:
+ if c == st.inst.char {
+ s[out] = arena.addState(s[out], st.inst.next, st.prefixed, st.match, pos, end)
}
- case _CHARCLASS:
- if st.inst.(*_CharClass).matches(c) {
- s[out] = arena.addState(s[out], st.inst.next(), st.prefixed, st.match, pos, end)
+ case iCharClass:
+ if st.inst.cclass.matches(c) {
+ s[out] = arena.addState(s[out], st.inst.next, st.prefixed, st.match, pos, end)
}
- case _ANY:
+ case iAny:
if c != endOfFile {
- s[out] = arena.addState(s[out], st.inst.next(), st.prefixed, st.match, pos, end)
+ s[out] = arena.addState(s[out], st.inst.next, st.prefixed, st.match, pos, end)
}
- case _NOTNL:
+ case iNotNL:
if c != endOfFile && c != '\n' {
- s[out] = arena.addState(s[out], st.inst.next(), st.prefixed, st.match, pos, end)
+ s[out] = arena.addState(s[out], st.inst.next, st.prefixed, st.match, pos, end)
}
- case _BRA:
- case _EBRA:
- case _ALT:
- case _END:
+ case iBra:
+ case iAlt:
+ case iEnd:
// choose leftmost longest
if !found || // first
st.match.m[0] < final.match.m[0] || // leftmost
@@ -900,77 +862,33 @@ func (re *Regexp) doExecute(str string, bytestr []byte, pos int) []int {
return final.match.m
}
-
-// ExecuteString matches the Regexp against the string s.
-// The return value is an array of integers, in pairs, identifying the positions of
-// substrings matched by the expression.
-// s[a[0]:a[1]] is the substring matched by the entire expression.
-// s[a[2*i]:a[2*i+1]] for i > 0 is the substring matched by the ith parenthesized subexpression.
-// A negative value means the subexpression did not match any element of the string.
-// An empty array means "no match".
-func (re *Regexp) ExecuteString(s string) (a []int) {
- return re.doExecute(s, nil, 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
}
-
-// Execute matches the Regexp against the byte slice b.
-// The return value is an array of integers, in pairs, identifying the positions of
-// subslices matched by the expression.
-// b[a[0]:a[1]] is the subslice matched by the entire expression.
-// b[a[2*i]:a[2*i+1]] for i > 0 is the subslice matched by the ith parenthesized subexpression.
-// A negative value means the subexpression did not match any element of the slice.
-// An empty array means "no match".
-func (re *Regexp) Execute(b []byte) (a []int) { return re.doExecute("", b, 0) }
-
-
// MatchString returns whether the Regexp matches the string s.
// The return value is a boolean: true for match, false for no match.
func (re *Regexp) MatchString(s string) bool { return len(re.doExecute(s, nil, 0)) > 0 }
-
// Match returns whether the Regexp matches the byte slice b.
// The return value is a boolean: true for match, false for no match.
func (re *Regexp) Match(b []byte) bool { return len(re.doExecute("", b, 0)) > 0 }
-// MatchStrings matches the Regexp against the string s.
-// The return value is an array of strings matched by the expression.
-// a[0] is the substring matched by the entire expression.
-// a[i] for i > 0 is the substring matched by the ith parenthesized subexpression.
-// An empty array means ``no match''.
-func (re *Regexp) MatchStrings(s string) (a []string) {
- r := re.doExecute(s, nil, 0)
- if r == nil {
- return nil
- }
- a = make([]string, len(r)/2)
- for i := 0; i < len(r); i += 2 {
- if r[i] != -1 { // -1 means no match for this subexpression
- a[i/2] = s[r[i]:r[i+1]]
- }
- }
- return
-}
-
-// MatchSlices matches the Regexp against the byte slice b.
-// The return value is an array of subslices matched by the expression.
-// a[0] is the subslice matched by the entire expression.
-// a[i] for i > 0 is the subslice matched by the ith parenthesized subexpression.
-// An empty array means ``no match''.
-func (re *Regexp) MatchSlices(b []byte) (a [][]byte) {
- r := re.doExecute("", b, 0)
- if r == nil {
- return nil
- }
- a = make([][]byte, len(r)/2)
- for i := 0; i < len(r); i += 2 {
- if r[i] != -1 { // -1 means no match for this subexpression
- a[i/2] = b[r[i]:r[i+1]]
- }
- }
- return
-}
-
// MatchString checks whether a textual regular expression
// matches a string. More complicated queries need
// to use Compile and the full Regexp interface.
@@ -1117,7 +1035,7 @@ func QuoteMeta(s string) string {
}
// 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, int)) {
+func (re *Regexp) allMatches(s string, b []byte, n int, deliver func([]int)) {
var end int
if b == nil {
end = len(s)
@@ -1156,78 +1074,270 @@ func (re *Regexp) allMatches(s string, b []byte, n int, deliver func(int, int))
prevMatchEnd = matches[1]
if accept {
- deliver(matches[0], matches[1])
+ deliver(matches)
i++
}
}
}
-// AllMatches slices the byte slice b into substrings that are successive
-// matches of the Regexp within b. If n > 0, the function returns at most n
-// matches. Text that does not match the expression will be skipped. Empty
-// matches abutting a preceding match are ignored. The function returns a slice
-// containing the matching substrings.
-func (re *Regexp) AllMatches(b []byte, n int) [][]byte {
- if n <= 0 {
+// Find returns a slice holding the text of the leftmost match in b of the regular expression.
+// A return value of nil indicates no match.
+func (re *Regexp) Find(b []byte) []byte {
+ a := re.doExecute("", b, 0)
+ if a == nil {
+ return nil
+ }
+ return b[a[0]:a[1]]
+}
+
+// FindIndex returns a two-element slice of integers defining the location of
+// the leftmost match in b of the regular expression. The match itself is at
+// b[loc[0]:loc[1]].
+// A return value of nil indicates no match.
+func (re *Regexp) FindIndex(b []byte) (loc []int) {
+ a := re.doExecute("", b, 0)
+ if a == nil {
+ return nil
+ }
+ return a[0:2]
+}
+
+// FindString returns a string holding the text of the leftmost match in s of the regular
+// expression. If there is no match, the return value is an empty string,
+// but it will also be empty if the regular expression successfully matches
+// an empty string. Use FindStringIndex or FindStringSubmatch if it is
+// necessary to distinguish these cases.
+func (re *Regexp) FindString(s string) string {
+ a := re.doExecute(s, nil, 0)
+ if a == nil {
+ return ""
+ }
+ return s[a[0]:a[1]]
+}
+
+// FindStringIndex returns a two-element slice of integers defining the
+// location of the leftmost match in s of the regular expression. The match
+// itself is at s[loc[0]:loc[1]].
+// A return value of nil indicates no match.
+func (re *Regexp) FindStringIndex(s string) []int {
+ a := re.doExecute(s, nil, 0)
+ if a == nil {
+ return nil
+ }
+ return a[0:2]
+}
+
+// FindSubmatch returns a slice of slices holding the text of the leftmost
+// match of the regular expression in b and the matches, if any, of its
+// subexpressions, as defined by the 'Submatch' descriptions in the package
+// comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindSubmatch(b []byte) [][]byte {
+ a := re.doExecute("", b, 0)
+ if a == nil {
+ return nil
+ }
+ ret := make([][]byte, len(a)/2)
+ for i := range ret {
+ if a[2*i] >= 0 {
+ ret[i] = b[a[2*i]:a[2*i+1]]
+ }
+ }
+ return ret
+}
+
+// FindSubmatchIndex returns a slice holding the index pairs identifying the
+// leftmost match of the regular expression in b and the matches, if any, of
+// its subexpressions, as defined by the 'Submatch' and 'Index' descriptions
+// in the package comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindSubmatchIndex(b []byte) []int {
+ return re.doExecute("", b, 0)
+}
+
+// FindStringSubmatch returns a slice of strings holding the text of the
+// leftmost match of the regular expression in s and the matches, if any, of
+// its subexpressions, as defined by the 'Submatch' description in the
+// package comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindStringSubmatch(s string) []string {
+ a := re.doExecute(s, nil, 0)
+ if a == nil {
+ return nil
+ }
+ ret := make([]string, len(a)/2)
+ for i := range ret {
+ if a[2*i] >= 0 {
+ ret[i] = s[a[2*i]:a[2*i+1]]
+ }
+ }
+ return ret
+}
+
+// FindStringSubmatchIndex returns a slice holding the index pairs
+// identifying the leftmost match of the regular expression in s and the
+// matches, if any, of its subexpressions, as defined by the 'Submatch' and
+// 'Index' descriptions in the package comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindStringSubmatchIndex(s string) []int {
+ return re.doExecute(s, nil, 0)
+}
+
+const startSize = 10 // The size at which to start a slice in the 'All' routines.
+
+// FindAll is the 'All' version of Find; it returns a slice of all successive
+// matches of the expression, as defined by the 'All' description in the
+// package comment.
+// A return value of nil indicates no match.
+func (re *Regexp) FindAll(b []byte, n int) [][]byte {
+ if n < 0 {
n = len(b) + 1
}
- result := make([][]byte, n)
- i := 0
- re.allMatches("", b, n, func(start, end int) {
- result[i] = b[start:end]
- i++
+ result := make([][]byte, 0, startSize)
+ re.allMatches("", b, n, func(match []int) {
+ result = append(result, b[match[0]:match[1]])
})
- return result[0:i]
+ 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
}
-// AllMatchesString slices the string s into substrings that are successive
-// matches of the Regexp within s. If n > 0, the function returns at most n
-// matches. Text that does not match the expression will be skipped. Empty
-// matches abutting a preceding match are ignored. The function returns a slice
-// containing the matching substrings.
-func (re *Regexp) AllMatchesString(s string, n int) []string {
- if n <= 0 {
+// 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, n)
- i := 0
- re.allMatches(s, nil, n, func(start, end int) {
- result[i] = s[start:end]
- i++
+ result := make([]string, 0, startSize)
+ re.allMatches(s, nil, n, func(match []int) {
+ result = append(result, s[match[0]:match[1]])
})
- return result[0:i]
+ if len(result) == 0 {
+ return nil
+ }
+ return result
}
-// AllMatchesIter slices the byte slice b into substrings that are successive
-// matches of the Regexp within b. If n > 0, the function returns at most n
-// matches. Text that does not match the expression will be skipped. Empty
-// matches abutting a preceding match are ignored. The function returns a
-// channel that iterates over the matching substrings.
-func (re *Regexp) AllMatchesIter(b []byte, n int) <-chan []byte {
- if n <= 0 {
+// 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
}
- c := make(chan []byte, 10)
- go func() {
- re.allMatches("", b, n, func(start, end int) { c <- b[start:end] })
- close(c)
- }()
- return c
+ 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
}
-// AllMatchesStringIter slices the string s into substrings that are successive
-// matches of the Regexp within s. If n > 0, the function returns at most n
-// matches. Text that does not match the expression will be skipped. Empty
-// matches abutting a preceding match are ignored. The function returns a
-// channel that iterates over the matching substrings.
-func (re *Regexp) AllMatchesStringIter(s string, n int) <-chan string {
- if n <= 0 {
+// 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
}
- c := make(chan string, 10)
- go func() {
- re.allMatches(s, nil, n, func(start, end int) { c <- s[start:end] })
- close(c)
- }()
- return c
+ 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/rpc/Makefile b/src/pkg/rpc/Makefile
index 4757b3aae..191b10d05 100644
--- a/src/pkg/rpc/Makefile
+++ b/src/pkg/rpc/Makefile
@@ -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 ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=rpc
GOFILES=\
diff --git a/src/pkg/rpc/client.go b/src/pkg/rpc/client.go
index d742d099f..601c49715 100644
--- a/src/pkg/rpc/client.go
+++ b/src/pkg/rpc/client.go
@@ -69,12 +69,12 @@ func (client *Client) send(c *Call) {
// Encode and send the request.
request := new(Request)
client.sending.Lock()
+ defer client.sending.Unlock()
request.Seq = c.seq
request.ServiceMethod = c.ServiceMethod
if err := client.codec.WriteRequest(request, c.Args); err != nil {
panic("rpc: client encode error: " + err.String())
}
- client.sending.Unlock()
}
func (client *Client) input() {
@@ -94,10 +94,12 @@ func (client *Client) input() {
client.pending[seq] = c, false
client.mutex.Unlock()
err = client.codec.ReadResponseBody(c.Reply)
- // Empty strings should turn into nil os.Errors
if response.Error != "" {
c.Error = os.ErrorString(response.Error)
+ } else if err != nil {
+ c.Error = err
} else {
+ // Empty strings should turn into nil os.Errors
c.Error = nil
}
// We don't want to block here. It is the caller's responsibility to make
@@ -113,7 +115,7 @@ func (client *Client) input() {
}
client.mutex.Unlock()
if err != os.EOF || !client.closing {
- log.Stderr("rpc: client protocol error:", err)
+ log.Println("rpc: client protocol error:", err)
}
}
@@ -160,14 +162,21 @@ func (c *gobClientCodec) Close() os.Error {
}
-// DialHTTP connects to an HTTP RPC server at the specified network address.
+// DialHTTP connects to an HTTP RPC server at the specified network address
+// listening on the default HTTP RPC path.
func DialHTTP(network, address string) (*Client, os.Error) {
+ return DialHTTPPath(network, address, DefaultRPCPath)
+}
+
+// DialHTTPPath connects to an HTTP RPC server
+// at the specified network address and path.
+func DialHTTPPath(network, address, path string) (*Client, os.Error) {
var err os.Error
conn, err := net.Dial(network, "", address)
if err != nil {
return nil, err
}
- io.WriteString(conn, "CONNECT "+rpcPath+" HTTP/1.0\n\n")
+ io.WriteString(conn, "CONNECT "+path+" HTTP/1.0\n\n")
// Require successful HTTP response
// before switching to RPC protocol.
@@ -218,7 +227,7 @@ func (client *Client) Go(serviceMethod string, args interface{}, reply interface
// RPCs that will be using that channel. If the channel
// is totally unbuffered, it's best not to run at all.
if cap(done) == 0 {
- log.Crash("rpc: done channel is unbuffered")
+ log.Panic("rpc: done channel is unbuffered")
}
}
c.Done = done
diff --git a/src/pkg/rpc/debug.go b/src/pkg/rpc/debug.go
index 638584f49..44b32e04b 100644
--- a/src/pkg/rpc/debug.go
+++ b/src/pkg/rpc/debug.go
@@ -21,14 +21,14 @@ const debugText = `<html>
<title>Services</title>
{.repeated section @}
<hr>
- Service {name}
+ Service {Name}
<hr>
<table>
<th align=center>Method</th><th align=center>Calls</th>
- {.repeated section meth}
+ {.repeated section Method}
<tr>
- <td align=left font=fixed>{name}({m.argType}, {m.replyType}) os.Error</td>
- <td align=center>{m.numCalls}</td>
+ <td align=left font=fixed>{Name}({Type.ArgType}, {Type.ReplyType}) os.Error</td>
+ <td align=center>{Type.NumCalls}</td>
</tr>
{.end}
</table>
@@ -39,30 +39,34 @@ const debugText = `<html>
var debug = template.MustParse(debugText, nil)
type debugMethod struct {
- m *methodType
- name string
+ Type *methodType
+ Name string
}
type methodArray []debugMethod
type debugService struct {
- s *service
- name string
- meth methodArray
+ Service *service
+ Name string
+ Method methodArray
}
type serviceArray []debugService
func (s serviceArray) Len() int { return len(s) }
-func (s serviceArray) Less(i, j int) bool { return s[i].name < s[j].name }
+func (s serviceArray) Less(i, j int) bool { return s[i].Name < s[j].Name }
func (s serviceArray) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (m methodArray) Len() int { return len(m) }
-func (m methodArray) Less(i, j int) bool { return m[i].name < m[j].name }
+func (m methodArray) Less(i, j int) bool { return m[i].Name < m[j].Name }
func (m methodArray) Swap(i, j int) { m[i], m[j] = m[j], m[i] }
+type debugHTTP struct {
+ *Server
+}
+
// Runs at /debug/rpc
-func debugHTTP(c *http.Conn, req *http.Request) {
+func (server debugHTTP) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// Build a sorted version of the data.
var services = make(serviceArray, len(server.serviceMap))
i := 0
@@ -71,16 +75,16 @@ func debugHTTP(c *http.Conn, req *http.Request) {
services[i] = debugService{service, sname, make(methodArray, len(service.method))}
j := 0
for mname, method := range service.method {
- services[i].meth[j] = debugMethod{method, mname}
+ services[i].Method[j] = debugMethod{method, mname}
j++
}
- sort.Sort(services[i].meth)
+ sort.Sort(services[i].Method)
i++
}
server.Unlock()
sort.Sort(services)
- err := debug.Execute(services, c)
+ err := debug.Execute(services, w)
if err != nil {
- fmt.Fprintln(c, "rpc: error executing template:", err.String())
+ fmt.Fprintln(w, "rpc: error executing template:", err.String())
}
}
diff --git a/src/pkg/rpc/jsonrpc/Makefile b/src/pkg/rpc/jsonrpc/Makefile
index 1a4fd2e92..b9a1ac2f7 100644
--- a/src/pkg/rpc/jsonrpc/Makefile
+++ b/src/pkg/rpc/jsonrpc/Makefile
@@ -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 ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=rpc/jsonrpc
GOFILES=\
diff --git a/src/pkg/rpc/jsonrpc/all_test.go b/src/pkg/rpc/jsonrpc/all_test.go
index e94c594da..764ee7ff3 100644
--- a/src/pkg/rpc/jsonrpc/all_test.go
+++ b/src/pkg/rpc/jsonrpc/all_test.go
@@ -53,7 +53,7 @@ func TestServer(t *testing.T) {
type addResp struct {
Id interface{} "id"
Result Reply "result"
- Error string "error"
+ Error interface{} "error"
}
cli, srv := net.Pipe()
@@ -69,7 +69,7 @@ func TestServer(t *testing.T) {
if err != nil {
t.Fatalf("Decode: %s", err)
}
- if resp.Error != "" {
+ if resp.Error != nil {
t.Fatalf("resp.Error: %s", resp.Error)
}
if resp.Id.(string) != string(i) {
@@ -79,6 +79,15 @@ func TestServer(t *testing.T) {
t.Fatalf("resp: bad result: %d+%d=%d", i, i+1, resp.Result.C)
}
}
+
+ fmt.Fprintf(cli, "{}\n")
+ var resp addResp
+ if err := dec.Decode(&resp); err != nil {
+ t.Fatalf("Decode after empty: %s", err)
+ }
+ if resp.Error == nil {
+ t.Fatalf("Expected error, got nil")
+ }
}
func TestClient(t *testing.T) {
diff --git a/src/pkg/rpc/jsonrpc/client.go b/src/pkg/rpc/jsonrpc/client.go
index ed2b4ed37..dcaa69f9d 100644
--- a/src/pkg/rpc/jsonrpc/client.go
+++ b/src/pkg/rpc/jsonrpc/client.go
@@ -7,6 +7,7 @@
package jsonrpc
import (
+ "fmt"
"io"
"json"
"net"
@@ -61,13 +62,13 @@ func (c *clientCodec) WriteRequest(r *rpc.Request, param interface{}) os.Error {
type clientResponse struct {
Id uint64 "id"
Result *json.RawMessage "result"
- Error string "error"
+ Error interface{} "error"
}
func (r *clientResponse) reset() {
r.Id = 0
r.Result = nil
- r.Error = ""
+ r.Error = nil
}
func (c *clientCodec) ReadResponseHeader(r *rpc.Response) os.Error {
@@ -81,8 +82,18 @@ func (c *clientCodec) ReadResponseHeader(r *rpc.Response) os.Error {
c.pending[c.resp.Id] = "", false
c.mutex.Unlock()
+ r.Error = ""
r.Seq = c.resp.Id
- r.Error = c.resp.Error
+ if c.resp.Error != nil {
+ x, ok := c.resp.Error.(string)
+ if !ok {
+ return fmt.Errorf("invalid error %v", c.resp.Error)
+ }
+ if x == "" {
+ x = "unspecified error"
+ }
+ r.Error = x
+ }
return nil
}
diff --git a/src/pkg/rpc/jsonrpc/server.go b/src/pkg/rpc/jsonrpc/server.go
index 9f3472a39..bf53bda8d 100644
--- a/src/pkg/rpc/jsonrpc/server.go
+++ b/src/pkg/rpc/jsonrpc/server.go
@@ -61,7 +61,7 @@ func (r *serverRequest) reset() {
type serverResponse struct {
Id *json.RawMessage "id"
Result interface{} "result"
- Error string "error"
+ Error interface{} "error"
}
func (c *serverCodec) ReadRequestHeader(r *rpc.Request) os.Error {
@@ -94,6 +94,8 @@ func (c *serverCodec) ReadRequestBody(x interface{}) os.Error {
return json.Unmarshal(*c.req.Params, &params)
}
+var null = json.RawMessage([]byte("null"))
+
func (c *serverCodec) WriteResponse(r *rpc.Response, x interface{}) os.Error {
var resp serverResponse
c.mutex.Lock()
@@ -105,9 +107,17 @@ func (c *serverCodec) WriteResponse(r *rpc.Response, x interface{}) os.Error {
c.pending[r.Seq] = nil, false
c.mutex.Unlock()
+ if b == nil {
+ // Invalid request so no id. Use JSON null.
+ b = &null
+ }
resp.Id = b
resp.Result = x
- resp.Error = r.Error
+ if r.Error == "" {
+ resp.Error = nil
+ } else {
+ resp.Error = r.Error
+ }
return c.enc.Encode(resp)
}
diff --git a/src/pkg/rpc/server.go b/src/pkg/rpc/server.go
index d14f6ded2..5c50bcc3a 100644
--- a/src/pkg/rpc/server.go
+++ b/src/pkg/rpc/server.go
@@ -3,9 +3,9 @@
// license that can be found in the LICENSE file.
/*
- The rpc package provides access to the public methods of an object across a
+ The rpc package provides access to the exported methods of an object across a
network or other I/O connection. A server registers an object, making it visible
- as a service with the name of the type of the object. After registration, public
+ as a service with the name of the type of the object. After registration, exported
methods of the object will be accessible remotely. A server may register multiple
objects (services) of different types but it is an error to register multiple
objects of the same type.
@@ -13,8 +13,8 @@
Only methods that satisfy these criteria will be made available for remote access;
other methods will be ignored:
- - the method receiver and name are publicly visible, that is, begin with an upper case letter.
- - the method has two arguments, both pointers to publicly visible types.
+ - the method receiver and name are exported, that is, begin with an upper case letter.
+ - the method has two arguments, both pointers to exported types.
- the method has return type os.Error.
The method's first argument represents the arguments provided by the caller; the
@@ -123,6 +123,12 @@ import (
"utf8"
)
+const (
+ // Defaults used by HandleHTTP
+ DefaultRPCPath = "/_goRPC_"
+ DefaultDebugPath = "/debug/rpc"
+)
+
// Precompute the reflect type for os.Error. Can't use os.Error directly
// because Typeof takes an empty interface value. This is annoying.
var unusedError *os.Error
@@ -131,8 +137,8 @@ var typeOfOsError = reflect.Typeof(unusedError).(*reflect.PtrType).Elem()
type methodType struct {
sync.Mutex // protects counters
method reflect.Method
- argType *reflect.PtrType
- replyType *reflect.PtrType
+ ArgType *reflect.PtrType
+ ReplyType *reflect.PtrType
numCalls uint
}
@@ -166,23 +172,46 @@ type ClientInfo struct {
RemoteAddr string
}
-type serverType struct {
+// Server represents an RPC Server.
+type Server struct {
sync.Mutex // protects the serviceMap
serviceMap map[string]*service
}
-// This variable is a global whose "public" methods are really private methods
-// called from the global functions of this package: rpc.Register, rpc.ServeConn, etc.
-// For example, rpc.Register() calls server.add().
-var server = &serverType{serviceMap: make(map[string]*service)}
+// NewServer returns a new Server.
+func NewServer() *Server {
+ return &Server{serviceMap: make(map[string]*service)}
+}
-// Is this a publicly visible - upper case - name?
-func isPublic(name string) bool {
+// DefaultServer is the default instance of *Server.
+var DefaultServer = NewServer()
+
+// Is this an exported - upper case - name?
+func isExported(name string) bool {
rune, _ := utf8.DecodeRuneInString(name)
return unicode.IsUpper(rune)
}
-func (server *serverType) register(rcvr interface{}) os.Error {
+// Register publishes in the server the set of methods of the
+// receiver value that satisfy the following conditions:
+// - exported method
+// - two arguments, both pointers to exported structs
+// - one return value, of type os.Error
+// It returns an error if the receiver is not an exported type or has no
+// suitable methods.
+// The client accesses each method using a string of the form "Type.Method",
+// where Type is the receiver's concrete type.
+func (server *Server) Register(rcvr interface{}) os.Error {
+ return server.register(rcvr, "", false)
+}
+
+// RegisterName is like Register but uses the provided name for the type
+// instead of the receiver's concrete type.
+func (server *Server) RegisterName(name string, rcvr interface{}) os.Error {
+ return server.register(rcvr, name, true)
+}
+
+func (server *Server) register(rcvr interface{}, name string, useName bool) os.Error {
server.Lock()
defer server.Unlock()
if server.serviceMap == nil {
@@ -192,12 +221,15 @@ func (server *serverType) register(rcvr interface{}) os.Error {
s.typ = reflect.Typeof(rcvr)
s.rcvr = reflect.NewValue(rcvr)
sname := reflect.Indirect(s.rcvr).Type().Name()
+ if useName {
+ sname = name
+ }
if sname == "" {
log.Exit("rpc: no service name for type", s.typ.String())
}
- if s.typ.PkgPath() != "" && !isPublic(sname) {
- s := "rpc Register: type " + sname + " is not public"
- log.Stderr(s)
+ if s.typ.PkgPath() != "" && !isExported(sname) && !useName {
+ s := "rpc Register: type " + sname + " is not exported"
+ log.Print(s)
return os.ErrorString(s)
}
if _, present := server.serviceMap[sname]; present {
@@ -211,54 +243,54 @@ func (server *serverType) register(rcvr interface{}) os.Error {
method := s.typ.Method(m)
mtype := method.Type
mname := method.Name
- if mtype.PkgPath() != "" && !isPublic(mname) {
+ if mtype.PkgPath() != "" || !isExported(mname) {
continue
}
// Method needs three ins: receiver, *args, *reply.
if mtype.NumIn() != 3 {
- log.Stderr("method", mname, "has wrong number of ins:", mtype.NumIn())
+ log.Println("method", mname, "has wrong number of ins:", mtype.NumIn())
continue
}
argType, ok := mtype.In(1).(*reflect.PtrType)
if !ok {
- log.Stderr(mname, "arg type not a pointer:", mtype.In(1))
+ log.Println(mname, "arg type not a pointer:", mtype.In(1))
continue
}
replyType, ok := mtype.In(2).(*reflect.PtrType)
if !ok {
- log.Stderr(mname, "reply type not a pointer:", mtype.In(2))
+ log.Println(mname, "reply type not a pointer:", mtype.In(2))
continue
}
- if argType.Elem().PkgPath() != "" && !isPublic(argType.Elem().Name()) {
- log.Stderr(mname, "argument type not public:", argType)
+ if argType.Elem().PkgPath() != "" && !isExported(argType.Elem().Name()) {
+ log.Println(mname, "argument type not exported:", argType)
continue
}
- if replyType.Elem().PkgPath() != "" && !isPublic(replyType.Elem().Name()) {
- log.Stderr(mname, "reply type not public:", replyType)
+ if replyType.Elem().PkgPath() != "" && !isExported(replyType.Elem().Name()) {
+ log.Println(mname, "reply type not exported:", replyType)
continue
}
if mtype.NumIn() == 4 {
t := mtype.In(3)
if t != reflect.Typeof((*ClientInfo)(nil)) {
- log.Stderr(mname, "last argument not *ClientInfo")
+ log.Println(mname, "last argument not *ClientInfo")
continue
}
}
// Method needs one out: os.Error.
if mtype.NumOut() != 1 {
- log.Stderr("method", mname, "has wrong number of outs:", mtype.NumOut())
+ log.Println("method", mname, "has wrong number of outs:", mtype.NumOut())
continue
}
if returnType := mtype.Out(0); returnType != typeOfOsError {
- log.Stderr("method", mname, "returns", returnType.String(), "not os.Error")
+ log.Println("method", mname, "returns", returnType.String(), "not os.Error")
continue
}
- s.method[mname] = &methodType{method: method, argType: argType, replyType: replyType}
+ s.method[mname] = &methodType{method: method, ArgType: argType, ReplyType: replyType}
}
if len(s.method) == 0 {
- s := "rpc Register: type " + sname + " has no public methods of suitable type"
- log.Stderr(s)
+ s := "rpc Register: type " + sname + " has no exported methods of suitable type"
+ log.Print(s)
return os.ErrorString(s)
}
server.serviceMap[s.name] = s
@@ -289,11 +321,18 @@ func sendResponse(sending *sync.Mutex, req *Request, reply interface{}, codec Se
sending.Lock()
err := codec.WriteResponse(resp, reply)
if err != nil {
- log.Stderr("rpc: writing response: ", err)
+ log.Println("rpc: writing response:", err)
}
sending.Unlock()
}
+func (m *methodType) NumCalls() (n uint) {
+ m.Lock()
+ n = m.numCalls
+ m.Unlock()
+ return n
+}
+
func (s *service) call(sending *sync.Mutex, mtype *methodType, req *Request, argv, replyv reflect.Value, codec ServerCodec) {
mtype.Lock()
mtype.numCalls++
@@ -335,7 +374,19 @@ func (c *gobServerCodec) Close() os.Error {
return c.rwc.Close()
}
-func (server *serverType) input(codec ServerCodec) {
+
+// ServeConn runs the server on a single connection.
+// ServeConn blocks, serving the connection until the client hangs up.
+// The caller typically invokes ServeConn in a go statement.
+// ServeConn uses the gob wire format (see package gob) on the
+// connection. To use an alternate codec, use ServeCodec.
+func (server *Server) ServeConn(conn io.ReadWriteCloser) {
+ server.ServeCodec(&gobServerCodec{conn, gob.NewDecoder(conn), gob.NewEncoder(conn)})
+}
+
+// ServeCodec is like ServeConn but uses the specified codec to
+// decode requests and encode responses.
+func (server *Server) ServeCodec(codec ServerCodec) {
sending := new(sync.Mutex)
for {
// Grab the request header.
@@ -344,7 +395,7 @@ func (server *serverType) input(codec ServerCodec) {
if err != nil {
if err == os.EOF || err == io.ErrUnexpectedEOF {
if err == io.ErrUnexpectedEOF {
- log.Stderr("rpc: ", err)
+ log.Println("rpc:", err)
}
break
}
@@ -374,11 +425,11 @@ func (server *serverType) input(codec ServerCodec) {
continue
}
// Decode the argument value.
- argv := _new(mtype.argType)
- replyv := _new(mtype.replyType)
+ argv := _new(mtype.ArgType)
+ replyv := _new(mtype.ReplyType)
err = codec.ReadRequestBody(argv.Interface())
if err != nil {
- log.Stderr("rpc: tearing down", serviceMethod[0], "connection:", err)
+ log.Println("rpc: tearing down", serviceMethod[0], "connection:", err)
sendResponse(sending, req, replyv.Interface(), codec, err.String())
break
}
@@ -387,24 +438,27 @@ func (server *serverType) input(codec ServerCodec) {
codec.Close()
}
-func (server *serverType) accept(lis net.Listener) {
+// Accept accepts connections on the listener and serves requests
+// for each incoming connection. Accept blocks; the caller typically
+// invokes it in a go statement.
+func (server *Server) Accept(lis net.Listener) {
for {
conn, err := lis.Accept()
if err != nil {
log.Exit("rpc.Serve: accept:", err.String()) // TODO(r): exit?
}
- go ServeConn(conn)
+ go server.ServeConn(conn)
}
}
-// Register publishes in the server the set of methods of the
-// receiver value that satisfy the following conditions:
-// - public method
-// - two arguments, both pointers to public structs
-// - one return value of type os.Error
-// It returns an error if the receiver is not public or has no
-// suitable methods.
-func Register(rcvr interface{}) os.Error { return server.register(rcvr) }
+// Register publishes the receiver's methods in the DefaultServer.
+func Register(rcvr interface{}) os.Error { return DefaultServer.Register(rcvr) }
+
+// RegisterName is like Register but uses the provided name for the type
+// instead of the receiver's concrete type.
+func RegisterName(name string, rcvr interface{}) os.Error {
+ return DefaultServer.RegisterName(name, rcvr)
+}
// A ServerCodec implements reading of RPC requests and writing of
// RPC responses for the server side of an RPC session.
@@ -420,50 +474,57 @@ type ServerCodec interface {
Close() os.Error
}
-// ServeConn runs the server on a single connection.
+// ServeConn runs the DefaultServer on a single connection.
// ServeConn blocks, serving the connection until the client hangs up.
// The caller typically invokes ServeConn in a go statement.
// ServeConn uses the gob wire format (see package gob) on the
// connection. To use an alternate codec, use ServeCodec.
func ServeConn(conn io.ReadWriteCloser) {
- ServeCodec(&gobServerCodec{conn, gob.NewDecoder(conn), gob.NewEncoder(conn)})
+ DefaultServer.ServeConn(conn)
}
// ServeCodec is like ServeConn but uses the specified codec to
// decode requests and encode responses.
func ServeCodec(codec ServerCodec) {
- server.input(codec)
+ DefaultServer.ServeCodec(codec)
}
// Accept accepts connections on the listener and serves requests
-// for each incoming connection. Accept blocks; the caller typically
-// invokes it in a go statement.
-func Accept(lis net.Listener) { server.accept(lis) }
+// to DefaultServer for each incoming connection.
+// Accept blocks; the caller typically invokes it in a go statement.
+func Accept(lis net.Listener) { DefaultServer.Accept(lis) }
// Can connect to RPC service using HTTP CONNECT to rpcPath.
-var rpcPath string = "/_goRPC_"
-var debugPath string = "/debug/rpc"
var connected = "200 Connected to Go RPC"
-func serveHTTP(c *http.Conn, req *http.Request) {
+// ServeHTTP implements an http.Handler that answers RPC requests.
+func (server *Server) ServeHTTP(w http.ResponseWriter, req *http.Request) {
if req.Method != "CONNECT" {
- c.SetHeader("Content-Type", "text/plain; charset=utf-8")
- c.WriteHeader(http.StatusMethodNotAllowed)
- io.WriteString(c, "405 must CONNECT to "+rpcPath+"\n")
+ w.SetHeader("Content-Type", "text/plain; charset=utf-8")
+ w.WriteHeader(http.StatusMethodNotAllowed)
+ io.WriteString(w, "405 must CONNECT\n")
return
}
- conn, _, err := c.Hijack()
+ conn, _, err := w.Hijack()
if err != nil {
- log.Stderr("rpc hijacking ", c.RemoteAddr, ": ", err.String())
+ log.Print("rpc hijacking ", w.RemoteAddr(), ": ", err.String())
return
}
io.WriteString(conn, "HTTP/1.0 "+connected+"\n\n")
- ServeConn(conn)
+ server.ServeConn(conn)
+}
+
+// HandleHTTP registers an HTTP handler for RPC messages on rpcPath,
+// and a debugging handler on debugPath.
+// It is still necessary to invoke http.Serve(), typically in a go statement.
+func (server *Server) HandleHTTP(rpcPath, debugPath string) {
+ http.Handle(rpcPath, server)
+ http.Handle(debugPath, debugHTTP{server})
}
-// HandleHTTP registers an HTTP handler for RPC messages.
+// HandleHTTP registers an HTTP handler for RPC messages to DefaultServer
+// on DefaultRPCPath and a debugging handler on DefaultDebugPath.
// It is still necessary to invoke http.Serve(), typically in a go statement.
func HandleHTTP() {
- http.Handle(rpcPath, http.HandlerFunc(serveHTTP))
- http.Handle(debugPath, http.HandlerFunc(debugHTTP))
+ DefaultServer.HandleHTTP(DefaultRPCPath, DefaultDebugPath)
}
diff --git a/src/pkg/rpc/server_test.go b/src/pkg/rpc/server_test.go
index e502db4e3..355d51ce4 100644
--- a/src/pkg/rpc/server_test.go
+++ b/src/pkg/rpc/server_test.go
@@ -9,17 +9,23 @@ import (
"http"
"log"
"net"
- "once"
"os"
"strings"
+ "sync"
"testing"
+ "time"
)
-var serverAddr string
-var httpServerAddr string
-
-const second = 1e9
+var (
+ serverAddr, newServerAddr string
+ httpServerAddr string
+ once, newOnce, httpOnce sync.Once
+)
+const (
+ second = 1e9
+ newHttpPath = "/foo"
+)
type Args struct {
A, B int
@@ -63,32 +69,56 @@ func (t *Arith) Error(args *Args, reply *Reply) os.Error {
panic("ERROR")
}
-func startServer() {
- Register(new(Arith))
-
+func listenTCP() (net.Listener, string) {
l, e := net.Listen("tcp", "127.0.0.1:0") // any available address
if e != nil {
log.Exitf("net.Listen tcp :0: %v", e)
}
- serverAddr = l.Addr().String()
- log.Stderr("Test RPC server listening on ", serverAddr)
+ return l, l.Addr().String()
+}
+
+func startServer() {
+ Register(new(Arith))
+
+ var l net.Listener
+ l, serverAddr = listenTCP()
+ log.Println("Test RPC server listening on", serverAddr)
go Accept(l)
HandleHTTP()
- l, e = net.Listen("tcp", "127.0.0.1:0") // any available address
- if e != nil {
- log.Stderrf("net.Listen tcp :0: %v", e)
- os.Exit(1)
- }
+ httpOnce.Do(startHttpServer)
+}
+
+func startNewServer() {
+ s := NewServer()
+ s.Register(new(Arith))
+
+ var l net.Listener
+ l, newServerAddr = listenTCP()
+ log.Println("NewServer test RPC server listening on", newServerAddr)
+ go Accept(l)
+
+ s.HandleHTTP(newHttpPath, "/bar")
+ httpOnce.Do(startHttpServer)
+}
+
+func startHttpServer() {
+ var l net.Listener
+ l, httpServerAddr = listenTCP()
httpServerAddr = l.Addr().String()
- log.Stderr("Test HTTP RPC server listening on ", httpServerAddr)
+ log.Println("Test HTTP RPC server listening on", httpServerAddr)
go http.Serve(l, nil)
}
func TestRPC(t *testing.T) {
once.Do(startServer)
+ testRPC(t, serverAddr)
+ newOnce.Do(startNewServer)
+ testRPC(t, newServerAddr)
+}
- client, err := Dial("tcp", serverAddr)
+func testRPC(t *testing.T, addr string) {
+ client, err := Dial("tcp", addr)
if err != nil {
t.Fatal("dialing", err)
}
@@ -174,8 +204,19 @@ func TestRPC(t *testing.T) {
func TestHTTPRPC(t *testing.T) {
once.Do(startServer)
+ testHTTPRPC(t, "")
+ newOnce.Do(startNewServer)
+ testHTTPRPC(t, newHttpPath)
+}
- client, err := DialHTTP("tcp", httpServerAddr)
+func testHTTPRPC(t *testing.T, path string) {
+ var client *Client
+ var err os.Error
+ if path == "" {
+ client, err = DialHTTP("tcp", httpServerAddr)
+ } else {
+ client, err = DialHTTPPath("tcp", httpServerAddr, path)
+ }
if err != nil {
t.Fatal("dialing", err)
}
@@ -292,3 +333,52 @@ func TestRegistrationError(t *testing.T) {
t.Errorf("expected error registering ReplyNotPublic")
}
}
+
+type WriteFailCodec int
+
+func (WriteFailCodec) WriteRequest(*Request, interface{}) os.Error {
+ // the panic caused by this error used to not unlock a lock.
+ return os.NewError("fail")
+}
+
+func (WriteFailCodec) ReadResponseHeader(*Response) os.Error {
+ time.Sleep(60e9)
+ panic("unreachable")
+}
+
+func (WriteFailCodec) ReadResponseBody(interface{}) os.Error {
+ time.Sleep(60e9)
+ panic("unreachable")
+}
+
+func (WriteFailCodec) Close() os.Error {
+ return nil
+}
+
+func TestSendDeadlock(t *testing.T) {
+ client := NewClientWithCodec(WriteFailCodec(0))
+
+ done := make(chan bool)
+ go func() {
+ testSendDeadlock(client)
+ testSendDeadlock(client)
+ done <- true
+ }()
+ for i := 0; i < 50; i++ {
+ time.Sleep(100 * 1e6)
+ _, ok := <-done
+ if ok {
+ return
+ }
+ }
+ t.Fatal("deadlock")
+}
+
+func testSendDeadlock(client *Client) {
+ defer func() {
+ recover()
+ }()
+ args := &Args{7, 8}
+ reply := new(Reply)
+ client.Call("Arith.Add", args, reply)
+}
diff --git a/src/pkg/runtime/386/asm.s b/src/pkg/runtime/386/asm.s
index 614c026ea..84f5367e5 100644
--- a/src/pkg/runtime/386/asm.s
+++ b/src/pkg/runtime/386/asm.s
@@ -23,21 +23,23 @@ TEXT _rt0_386(SB),7,$0
JMP ok
// set up %gs
- CALL ldt0setup(SB)
+ CALL runtime·ldt0setup(SB)
// store through it, to make sure it works
+ CMPL runtime·isplan9(SB), $1
+ JEQ ok
get_tls(BX)
MOVL $0x123, g(BX)
- MOVL tls0(SB), AX
+ MOVL runtime·tls0(SB), AX
CMPL AX, $0x123
JEQ ok
MOVL AX, 0 // abort
ok:
// set up m and g "registers"
get_tls(BX)
- LEAL g0(SB), CX
+ LEAL runtime·g0(SB), CX
MOVL CX, g(BX)
- LEAL m0(SB), AX
+ LEAL runtime·m0(SB), AX
MOVL AX, m(BX)
// save m->g0 = g0
@@ -47,46 +49,46 @@ ok:
LEAL (-8192+104)(SP), AX // TODO: 104?
MOVL AX, g_stackguard(CX)
MOVL SP, g_stackbase(CX)
- CALL emptyfunc(SB) // fault if stack check is wrong
+ CALL runtime·emptyfunc(SB) // fault if stack check is wrong
// convention is D is always cleared
CLD
- CALL check(SB)
+ CALL runtime·check(SB)
// saved argc, argv
MOVL 120(SP), AX
MOVL AX, 0(SP)
MOVL 124(SP), AX
MOVL AX, 4(SP)
- CALL args(SB)
- CALL osinit(SB)
- CALL schedinit(SB)
+ CALL runtime·args(SB)
+ CALL runtime·osinit(SB)
+ CALL runtime·schedinit(SB)
// create a new goroutine to start program
- PUSHL $mainstart(SB) // entry
+ PUSHL $runtime·mainstart(SB) // entry
PUSHL $0 // arg size
- CALL ·newproc(SB)
+ CALL runtime·newproc(SB)
POPL AX
POPL AX
// start this M
- CALL mstart(SB)
+ CALL runtime·mstart(SB)
INT $3
RET
-TEXT mainstart(SB),7,$0
+TEXT runtime·mainstart(SB),7,$0
CALL main·init(SB)
- CALL initdone(SB)
+ CALL runtime·initdone(SB)
CALL main·main(SB)
PUSHL $0
- CALL exit(SB)
+ CALL runtime·exit(SB)
POPL AX
INT $3
RET
-TEXT breakpoint(SB),7,$0
+TEXT runtime·breakpoint(SB),7,$0
INT $3
RET
@@ -96,7 +98,7 @@ TEXT breakpoint(SB),7,$0
// uintptr gosave(Gobuf*)
// save state in Gobuf; setjmp
-TEXT gosave(SB), 7, $0
+TEXT runtime·gosave(SB), 7, $0
MOVL 4(SP), AX // gobuf
LEAL 4(SP), BX // caller's SP
MOVL BX, gobuf_sp(AX)
@@ -110,7 +112,7 @@ TEXT gosave(SB), 7, $0
// void gogo(Gobuf*, uintptr)
// restore state from Gobuf; longjmp
-TEXT gogo(SB), 7, $0
+TEXT runtime·gogo(SB), 7, $0
MOVL 8(SP), AX // return 2nd arg
MOVL 4(SP), BX // gobuf
MOVL gobuf_g(BX), DX
@@ -124,7 +126,7 @@ TEXT gogo(SB), 7, $0
// void gogocall(Gobuf*, void (*fn)(void))
// restore state from Gobuf but then call fn.
// (call fn, returning to state in Gobuf)
-TEXT gogocall(SB), 7, $0
+TEXT runtime·gogocall(SB), 7, $0
MOVL 8(SP), AX // fn
MOVL 4(SP), BX // gobuf
MOVL gobuf_g(BX), DX
@@ -142,7 +144,7 @@ TEXT gogocall(SB), 7, $0
*/
// Called during function prolog when more stack is needed.
-TEXT ·morestack(SB),7,$0
+TEXT runtime·morestack(SB),7,$0
// Cannot grow scheduler stack (m->g0).
get_tls(CX)
MOVL m(CX), BX
@@ -175,8 +177,10 @@ TEXT ·morestack(SB),7,$0
// Call newstack on m's scheduling stack.
MOVL m_g0(BX), BP
MOVL BP, g(CX)
- MOVL (m_sched+gobuf_sp)(BX), SP
- CALL newstack(SB)
+ MOVL (m_sched+gobuf_sp)(BX), AX
+ MOVL -4(AX), BX // fault if CALL would, before smashing SP
+ MOVL AX, SP
+ CALL runtime·newstack(SB)
MOVL $0, 0x1003 // crash if newstack returns
RET
@@ -218,13 +222,13 @@ TEXT reflect·call(SB), 7, $0
get_tls(CX)
MOVL BP, g(CX)
MOVL (m_sched+gobuf_sp)(BX), SP
- CALL newstack(SB)
+ CALL runtime·newstack(SB)
MOVL $0, 0x1103 // crash if newstack returns
RET
// Return point when leaving stack.
-TEXT ·lessstack(SB), 7, $0
+TEXT runtime·lessstack(SB), 7, $0
// Save return value in m->cret
get_tls(CX)
MOVL m(CX), BX
@@ -234,7 +238,7 @@ TEXT ·lessstack(SB), 7, $0
MOVL m_g0(BX), DX
MOVL DX, g(CX)
MOVL (m_sched+gobuf_sp)(BX), SP
- CALL oldstack(SB)
+ CALL runtime·oldstack(SB)
MOVL $0, 0x1004 // crash if oldstack returns
RET
@@ -246,7 +250,7 @@ TEXT ·lessstack(SB), 7, $0
// return 1;
// }else
// return 0;
-TEXT cas(SB), 7, $0
+TEXT runtime·cas(SB), 7, $0
MOVL 4(SP), BX
MOVL 8(SP), AX
MOVL 12(SP), CX
@@ -265,7 +269,7 @@ TEXT cas(SB), 7, $0
// return 1;
// }else
// return 0;
-TEXT casp(SB), 7, $0
+TEXT runtime·casp(SB), 7, $0
MOVL 4(SP), BX
MOVL 8(SP), AX
MOVL 12(SP), CX
@@ -282,14 +286,14 @@ TEXT casp(SB), 7, $0
// 1. pop the caller
// 2. sub 5 bytes from the callers return
// 3. jmp to the argument
-TEXT jmpdefer(SB), 7, $0
+TEXT runtime·jmpdefer(SB), 7, $0
MOVL 4(SP), AX // fn
MOVL 8(SP), BX // caller sp
LEAL -4(BX), SP // caller sp after CALL
SUBL $5, (SP) // return to CALL again
JMP AX // but first run the deferred function
-TEXT ·memclr(SB),7,$0
+TEXT runtime·memclr(SB),7,$0
MOVL 4(SP), DI // arg 1 addr
MOVL 8(SP), CX // arg 2 count
ADDL $3, CX
@@ -300,42 +304,42 @@ TEXT ·memclr(SB),7,$0
STOSL
RET
-TEXT ·getcallerpc+0(SB),7,$0
+TEXT runtime·getcallerpc(SB),7,$0
MOVL x+0(FP),AX // addr of first arg
MOVL -4(AX),AX // get calling pc
RET
-TEXT ·setcallerpc+0(SB),7,$0
+TEXT runtime·setcallerpc(SB),7,$0
MOVL x+0(FP),AX // addr of first arg
MOVL x+4(FP), BX
MOVL BX, -4(AX) // set calling pc
RET
-TEXT getcallersp(SB), 7, $0
+TEXT runtime·getcallersp(SB), 7, $0
MOVL sp+0(FP), AX
RET
-TEXT ldt0setup(SB),7,$16
+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.
// the entry number is just a hint. setldt will set up GS with what it used.
MOVL $7, 0(SP)
- LEAL tls0(SB), AX
+ LEAL runtime·tls0(SB), AX
MOVL AX, 4(SP)
MOVL $32, 8(SP) // sizeof(tls array)
- CALL setldt(SB)
+ CALL runtime·setldt(SB)
RET
-TEXT emptyfunc(SB),0,$0
+TEXT runtime·emptyfunc(SB),0,$0
RET
-TEXT abort(SB),7,$0
+TEXT runtime·abort(SB),7,$0
INT $0x3
// runcgo(void(*fn)(void*), void *arg)
// Call fn(arg) on the scheduler stack,
// aligned appropriately for the gcc ABI.
-TEXT runcgo(SB),7,$16
+TEXT runtime·runcgo(SB),7,$16
MOVL fn+0(FP), AX
MOVL arg+4(FP), BX
MOVL SP, CX
@@ -370,7 +374,7 @@ TEXT runcgo(SB),7,$16
// runcgocallback(G *g1, void* sp, void (*fn)(void))
// Switch to g1 and sp, call fn, switch back. fn's arguments are on
// the new stack.
-TEXT runcgocallback(SB),7,$32
+TEXT runtime·runcgocallback(SB),7,$32
MOVL g1+0(FP), DX
MOVL sp+4(FP), AX
MOVL fn+8(FP), BX
@@ -399,7 +403,7 @@ TEXT runcgocallback(SB),7,$32
RET
// check that SP is in range [g->stackbase, g->stackguard)
-TEXT stackcheck(SB), 7, $0
+TEXT runtime·stackcheck(SB), 7, $0
get_tls(CX)
MOVL g(CX), AX
CMPL g_stackbase(AX), SP
@@ -410,8 +414,4 @@ TEXT stackcheck(SB), 7, $0
INT $3
RET
-GLOBL m0(SB), $1024
-GLOBL g0(SB), $1024
-GLOBL tls0(SB), $32
-GLOBL initcgo(SB), $4
-
+GLOBL runtime·tls0(SB), $32
diff --git a/src/pkg/runtime/386/closure.c b/src/pkg/runtime/386/closure.c
index 9f639c472..b0d4cc41a 100644
--- a/src/pkg/runtime/386/closure.c
+++ b/src/pkg/runtime/386/closure.c
@@ -9,23 +9,20 @@
// fn func(arg0, arg1, arg2 *ptr, callerpc uintptr, xxx) yyy,
// arg0, arg1, arg2 *ptr) (func(xxx) yyy)
void
-·closure(int32 siz, byte *fn, byte *arg0)
+runtime·closure(int32 siz, byte *fn, byte *arg0)
{
byte *p, *q, **ret;
int32 i, n;
int32 pcrel;
- if(goos != nil && strcmp((uint8*)goos, (uint8*)"nacl") == 0)
- throw("no closures in native client yet");
-
if(siz < 0 || siz%4 != 0)
- throw("bad closure size");
+ runtime·throw("bad closure size");
ret = (byte**)((byte*)&arg0 + siz);
if(siz > 100) {
// TODO(rsc): implement stack growth preamble?
- throw("closure too big");
+ runtime·throw("closure too big");
}
// compute size of new fn.
@@ -43,12 +40,12 @@ void
if(n%4)
n += 4 - n%4;
- p = mal(n);
+ p = runtime·mal(n);
*ret = p;
q = p + n - siz;
if(siz > 0) {
- mcpy(q, (byte*)&arg0, siz);
+ runtime·mcpy(q, (byte*)&arg0, siz);
// SUBL $siz, SP
*p++ = 0x81;
@@ -104,7 +101,5 @@ void
*p++ = 0xc3;
if(p > q)
- throw("bad math in sys.closure");
+ runtime·throw("bad math in sys.closure");
}
-
-
diff --git a/src/pkg/runtime/386/memmove.s b/src/pkg/runtime/386/memmove.s
index 8adb687c5..38a0652b5 100644
--- a/src/pkg/runtime/386/memmove.s
+++ b/src/pkg/runtime/386/memmove.s
@@ -23,8 +23,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
- TEXT memmove(SB), 7, $0
-
+TEXT runtime·memmove(SB), 7, $0
MOVL to+0(FP), DI
MOVL fr+4(FP), SI
MOVL n+8(FP), BX
diff --git a/src/pkg/runtime/386/vlop.s b/src/pkg/runtime/386/vlop.s
index 803276ce2..28f6da82d 100644
--- a/src/pkg/runtime/386/vlop.s
+++ b/src/pkg/runtime/386/vlop.s
@@ -27,7 +27,7 @@
* C runtime for 64-bit divide.
*/
-TEXT _mul64by32(SB), 7, $0
+TEXT _mul64by32(SB), 7, $0
MOVL r+0(FP), CX
MOVL a+4(FP), AX
MULL b+12(FP)
@@ -39,7 +39,7 @@ TEXT _mul64by32(SB), 7, $0
MOVL BX, 4(CX)
RET
-TEXT _div64by32(SB), 7, $0
+TEXT _div64by32(SB), 7, $0
MOVL r+12(FP), CX
MOVL a+0(FP), AX
MOVL a+4(FP), DX
diff --git a/src/pkg/runtime/386/vlrt.c b/src/pkg/runtime/386/vlrt.c
index 10417f596..1631dbe10 100644
--- a/src/pkg/runtime/386/vlrt.c
+++ b/src/pkg/runtime/386/vlrt.c
@@ -59,7 +59,7 @@ struct Vlong
};
};
-void abort(void);
+void runtime·abort(void);
void
_d2v(Vlong *y, double d)
@@ -270,7 +270,7 @@ _divvu(Vlong *q, Vlong n, Vlong d)
}
void
-·uint64div(Vlong n, Vlong d, Vlong q)
+runtime·uint64div(Vlong n, Vlong d, Vlong q)
{
_divvu(&q, n, d);
}
@@ -288,7 +288,7 @@ _modvu(Vlong *r, Vlong n, Vlong d)
}
void
-·uint64mod(Vlong n, Vlong d, Vlong q)
+runtime·uint64mod(Vlong n, Vlong d, Vlong q)
{
_modvu(&q, n, d);
}
@@ -334,7 +334,7 @@ _divv(Vlong *q, Vlong n, Vlong d)
}
void
-·int64div(Vlong n, Vlong d, Vlong q)
+runtime·int64div(Vlong n, Vlong d, Vlong q)
{
_divv(&q, n, d);
}
@@ -368,7 +368,7 @@ _modv(Vlong *r, Vlong n, Vlong d)
}
void
-·int64mod(Vlong n, Vlong d, Vlong q)
+runtime·int64mod(Vlong n, Vlong d, Vlong q)
{
_modv(&q, n, d);
}
@@ -522,7 +522,7 @@ _vasop(Vlong *ret, void *lv, void fn(Vlong*, Vlong, Vlong), int type, Vlong rv)
u.hi = 0;
switch(type) {
default:
- abort();
+ runtime·abort();
break;
case 1: /* schar */
diff --git a/src/pkg/runtime/Makefile b/src/pkg/runtime/Makefile
index 6571d802d..e62dbe393 100644
--- a/src/pkg/runtime/Makefile
+++ b/src/pkg/runtime/Makefile
@@ -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 ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=runtime
@@ -12,21 +12,27 @@ SIZE_amd64=64
SIZE_arm=32
SIZE=$(SIZE_$(GOARCH))
-# Setup CFLAGS. Add -D_64BIT on 64-bit platforms (sorry).
-CFLAGS_64=-D_64BIT
# TODO(kaib): fix register allocation to honor extern register so we
# can enable optimizations again.
CFLAGS_arm=-N
CFLAGS_windows=-D__WINDOWS__
-CFLAGS=-I$(GOOS) -I$(GOARCH) -I$(GOOS)/$(GOARCH) -wF $(CFLAGS_$(SIZE)) $(CFLAGS_$(GOARCH)) $(CFLAGS_$(GOOS))
+CFLAGS=-I$(GOOS) -I$(GOARCH) -I$(GOOS)/$(GOARCH) -wF $(CFLAGS_$(GOARCH)) $(CFLAGS_$(GOOS))
GOFILES=\
debug.go\
error.go\
extern.go\
sig.go\
+ softfloat64.go\
type.go\
version.go\
+ chan_defs.go\
+ hashmap_defs.go\
+ iface_defs.go\
+ malloc_defs.go\
+ mheapmap$(SIZE)_defs.go\
+ runtime_defs.go\
+ $(GOOS)/runtime_defs.go\
GOFILES_tiny=\
tiny/io.go\
@@ -116,52 +122,46 @@ $(pkgdir)/%.h: %.h
clean: clean-local
clean-local:
- rm -f goc2c mkversion version.go */asm.h runtime.acid.*
+ rm -f goc2c mkversion version.go */asm.h runtime.acid.* $$(ls *.goc | sed 's/goc$$/c/')
$(GOARCH)/asm.h: mkasmh.sh runtime.acid.$(GOARCH)
./mkasmh.sh >$@.x
mv -f $@.x $@
goc2c: goc2c.c
- $(QUOTED_GOBIN)/quietgcc -o $@ $<
+ quietgcc -o $@ $<
mkversion: mkversion.c
- $(QUOTED_GOBIN)/quietgcc -o $@ -I "$(GOROOT)/include" $< "$(GOROOT)/lib/lib9.a"
+ quietgcc -o $@ -I "$(GOROOT)/include" $< "$(GOROOT)/lib/lib9.a"
version.go: mkversion
./mkversion >version.go
%.c: %.goc goc2c
- ./goc2c $< > $@.tmp
+ ./goc2c `pwd`/$< > $@.tmp
mv -f $@.tmp $@
%.$O: $(GOARCH)/%.c
- $(QUOTED_GOBIN)/$(CC) $(CFLAGS) $<
+ $(CC) $(CFLAGS) $<
%.$O: $(GOOS)/%.c
- $(QUOTED_GOBIN)/$(CC) $(CFLAGS) $<
+ $(CC) $(CFLAGS) $<
%.$O: $(GOOS)/$(GOARCH)/%.c
- $(QUOTED_GOBIN)/$(CC) $(CFLAGS) $<
+ $(CC) $(CFLAGS) $<
%.$O: $(GOARCH)/%.s $(GOARCH)/asm.h
- $(QUOTED_GOBIN)/$(AS) $<
+ $(AS) $<
%.$O: $(GOOS)/$(GOARCH)/%.s $(GOARCH)/asm.h
- $(QUOTED_GOBIN)/$(AS) $<
+ $(AS) $<
# for discovering offsets inside structs when debugging
runtime.acid.$(GOARCH): runtime.h proc.c
- $(QUOTED_GOBIN)/$(CC) $(CFLAGS) -a proc.c >$@
+ $(CC) $(CFLAGS) -a proc.c >$@
# 386 traceback is really amd64 traceback
ifeq ($(GOARCH),386)
traceback.$O: amd64/traceback.c
- $(QUOTED_GOBIN)/$(CC) $(CFLAGS) $<
-endif
-
-# NaCl closure is special.
-ifeq ($(GOOS),nacl)
-closure.$O: nacl/$(GOARCH)/closure.c
- $(QUOTED_GOBIN)/$(CC) $(CFLAGS) $<
+ $(CC) $(CFLAGS) $<
endif
diff --git a/src/pkg/runtime/amd64/asm.s b/src/pkg/runtime/amd64/asm.s
index 52b0a89bc..235f27206 100644
--- a/src/pkg/runtime/amd64/asm.s
+++ b/src/pkg/runtime/amd64/asm.s
@@ -4,7 +4,7 @@
#include "amd64/asm.h"
-TEXT _rt0_amd64(SB),7,$-8
+TEXT _rt0_amd64(SB),7,$-8
// copy arguments forward on an even stack
MOVQ 0(DI), AX // argc
LEAQ 8(DI), BX // argv
@@ -16,54 +16,72 @@ TEXT _rt0_amd64(SB),7,$-8
// if there is an initcgo, call it.
MOVQ initcgo(SB), AX
TESTQ AX, AX
- JZ 2(PC)
+ JZ needtls
CALL AX
-
- // set the per-goroutine and per-mach registers
- LEAQ m0(SB), m
- LEAQ g0(SB), g
- MOVQ g, m_g0(m) // m has pointer to its g0
+ JMP ok
+
+needtls:
+ LEAQ runtime·tls0(SB), DI
+ CALL runtime·settls(SB)
+
+ // store through it, to make sure it works
+ get_tls(BX)
+ MOVQ $0x123, g(BX)
+ MOVQ runtime·tls0(SB), AX
+ CMPQ AX, $0x123
+ JEQ 2(PC)
+ MOVL AX, 0 // abort
+ok:
+ // set the per-goroutine and per-mach "registers"
+ get_tls(BX)
+ LEAQ runtime·g0(SB), CX
+ MOVQ CX, g(BX)
+ LEAQ runtime·m0(SB), AX
+ MOVQ AX, m(BX)
+
+ // 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(g)
- MOVQ SP, g_stackbase(g)
+ MOVQ AX, g_stackguard(CX)
+ MOVQ SP, g_stackbase(CX)
CLD // convention is D is always left cleared
- CALL check(SB)
+ CALL runtime·check(SB)
MOVL 16(SP), AX // copy argc
MOVL AX, 0(SP)
MOVQ 24(SP), AX // copy argv
MOVQ AX, 8(SP)
- CALL args(SB)
- CALL osinit(SB)
- CALL schedinit(SB)
+ CALL runtime·args(SB)
+ CALL runtime·osinit(SB)
+ CALL runtime·schedinit(SB)
// create a new goroutine to start program
- PUSHQ $mainstart(SB) // entry
+ PUSHQ $runtime·mainstart(SB) // entry
PUSHQ $0 // arg size
- CALL ·newproc(SB)
+ CALL runtime·newproc(SB)
POPQ AX
POPQ AX
// start this M
- CALL mstart(SB)
+ CALL runtime·mstart(SB)
- CALL notok(SB) // never returns
+ CALL runtime·notok(SB) // never returns
RET
-TEXT mainstart(SB),7,$0
+TEXT runtime·mainstart(SB),7,$0
CALL main·init(SB)
- CALL initdone(SB)
+ CALL runtime·initdone(SB)
CALL main·main(SB)
PUSHQ $0
- CALL exit(SB)
+ CALL runtime·exit(SB)
POPQ AX
- CALL notok(SB)
+ CALL runtime·notok(SB)
RET
-TEXT breakpoint(SB),7,$0
+TEXT runtime·breakpoint(SB),7,$0
BYTE $0xcc
RET
@@ -73,23 +91,27 @@ TEXT breakpoint(SB),7,$0
// uintptr gosave(Gobuf*)
// save state in Gobuf; setjmp
-TEXT gosave(SB), 7, $0
+TEXT runtime·gosave(SB), 7, $0
MOVQ 8(SP), AX // gobuf
LEAQ 8(SP), BX // caller's SP
MOVQ BX, gobuf_sp(AX)
MOVQ 0(SP), BX // caller's PC
MOVQ BX, gobuf_pc(AX)
- MOVQ g, gobuf_g(AX)
+ get_tls(CX)
+ MOVQ g(CX), BX
+ MOVQ BX, gobuf_g(AX)
MOVL $0, AX // return 0
RET
// void gogo(Gobuf*, uintptr)
// restore state from Gobuf; longjmp
-TEXT gogo(SB), 7, $0
+TEXT runtime·gogo(SB), 7, $0
MOVQ 16(SP), AX // return 2nd arg
MOVQ 8(SP), BX // gobuf
- MOVQ gobuf_g(BX), g
- MOVQ 0(g), CX // make sure g != nil
+ MOVQ gobuf_g(BX), DX
+ MOVQ 0(DX), CX // make sure g != nil
+ get_tls(CX)
+ MOVQ DX, g(CX)
MOVQ gobuf_sp(BX), SP // restore SP
MOVQ gobuf_pc(BX), BX
JMP BX
@@ -97,11 +119,13 @@ TEXT gogo(SB), 7, $0
// void gogocall(Gobuf*, void (*fn)(void))
// restore state from Gobuf but then call fn.
// (call fn, returning to state in Gobuf)
-TEXT gogocall(SB), 7, $0
+TEXT runtime·gogocall(SB), 7, $0
MOVQ 16(SP), AX // fn
MOVQ 8(SP), BX // gobuf
- MOVQ gobuf_g(BX), g
- MOVQ 0(g), CX // make sure g != nil
+ MOVQ gobuf_g(BX), DX
+ get_tls(CX)
+ MOVQ DX, g(CX)
+ MOVQ 0(DX), CX // make sure g != nil
MOVQ gobuf_sp(BX), SP // restore SP
MOVQ gobuf_pc(BX), BX
PUSHQ BX
@@ -113,24 +137,34 @@ TEXT gogocall(SB), 7, $0
*/
// Called during function prolog when more stack is needed.
-TEXT ·morestack(SB),7,$0
+// Caller has already done get_tls(CX); MOVQ m(CX), BX.
+TEXT runtime·morestack(SB),7,$0
+ // Cannot grow scheduler stack (m->g0).
+ MOVQ m_g0(BX), SI
+ CMPQ g(CX), SI
+ JNE 2(PC)
+ INT $3
+
// Called from f.
// Set m->morebuf to f's caller.
MOVQ 8(SP), AX // f's caller's PC
- MOVQ AX, (m_morebuf+gobuf_pc)(m)
+ MOVQ AX, (m_morebuf+gobuf_pc)(BX)
LEAQ 16(SP), AX // f's caller's SP
- MOVQ AX, (m_morebuf+gobuf_sp)(m)
- MOVQ AX, (m_morefp)(m)
- MOVQ g, (m_morebuf+gobuf_g)(m)
+ MOVQ AX, (m_morebuf+gobuf_sp)(BX)
+ MOVQ AX, (m_morefp)(BX)
+ get_tls(CX)
+ MOVQ g(CX), SI
+ MOVQ SI, (m_morebuf+gobuf_g)(BX)
// Set m->morepc to f's PC.
MOVQ 0(SP), AX
- MOVQ AX, m_morepc(m)
+ MOVQ AX, m_morepc(BX)
// Call newstack on m's scheduling stack.
- MOVQ m_g0(m), g
- MOVQ (m_sched+gobuf_sp)(m), SP
- CALL newstack(SB)
+ MOVQ m_g0(BX), BP
+ MOVQ BP, g(CX)
+ MOVQ (m_sched+gobuf_sp)(BX), SP
+ CALL runtime·newstack(SB)
MOVQ $0, 0x1003 // crash if newstack returns
RET
@@ -140,13 +174,17 @@ TEXT ·morestack(SB),7,$0
//
// func call(fn *byte, arg *byte, argsize uint32).
TEXT reflect·call(SB), 7, $0
+ get_tls(CX)
+ MOVQ m(CX), BX
+
// Save our caller's state as the PC and SP to
// restore when returning from f.
MOVQ 0(SP), AX // our caller's PC
- MOVQ AX, (m_morebuf+gobuf_pc)(m)
+ MOVQ AX, (m_morebuf+gobuf_pc)(BX)
LEAQ 8(SP), AX // our caller's SP
- MOVQ AX, (m_morebuf+gobuf_sp)(m)
- MOVQ g, (m_morebuf+gobuf_g)(m)
+ MOVQ AX, (m_morebuf+gobuf_sp)(BX)
+ MOVQ g(CX), AX
+ MOVQ AX, (m_morebuf+gobuf_g)(BX)
// Set up morestack arguments to call f on a new stack.
// We set f's frame size to 1, as a hint to newstack
@@ -155,94 +193,109 @@ TEXT reflect·call(SB), 7, $0
// the default stack, f's usual stack growth prolog will
// allocate a new segment (and recopy the arguments).
MOVQ 8(SP), AX // fn
- MOVQ 16(SP), BX // arg frame
+ MOVQ 16(SP), DX // arg frame
MOVL 24(SP), CX // arg size
- MOVQ AX, m_morepc(m) // f's PC
- MOVQ BX, m_morefp(m) // argument frame pointer
- MOVL CX, m_moreargs(m) // f's argument size
- MOVL $1, m_moreframe(m) // f's frame size
+ MOVQ AX, m_morepc(BX) // f's PC
+ MOVQ DX, m_morefp(BX) // argument frame pointer
+ MOVL CX, m_moreargs(BX) // f's argument size
+ MOVL $1, m_moreframe(BX) // f's frame size
// Call newstack on m's scheduling stack.
- MOVQ m_g0(m), g
- MOVQ (m_sched+gobuf_sp)(m), SP
- CALL newstack(SB)
+ MOVQ m_g0(BX), BP
+ get_tls(CX)
+ MOVQ BP, g(CX)
+ MOVQ (m_sched+gobuf_sp)(BX), SP
+ CALL runtime·newstack(SB)
MOVQ $0, 0x1103 // crash if newstack returns
RET
// Return point when leaving stack.
-TEXT ·lessstack(SB), 7, $0
+TEXT runtime·lessstack(SB), 7, $0
// Save return value in m->cret
- MOVQ AX, m_cret(m)
+ get_tls(CX)
+ MOVQ m(CX), BX
+ MOVQ AX, m_cret(BX)
// Call oldstack on m's scheduling stack.
- MOVQ m_g0(m), g
- MOVQ (m_sched+gobuf_sp)(m), SP
- CALL oldstack(SB)
+ MOVQ m_g0(BX), DX
+ MOVQ DX, g(CX)
+ MOVQ (m_sched+gobuf_sp)(BX), SP
+ CALL runtime·oldstack(SB)
MOVQ $0, 0x1004 // crash if oldstack returns
RET
// morestack trampolines
-TEXT ·morestack00+0(SB),7,$0
+TEXT runtime·morestack00(SB),7,$0
+ get_tls(CX)
+ MOVQ m(CX), BX
MOVQ $0, AX
- MOVQ AX, m_moreframe(m)
- MOVQ $·morestack+0(SB), AX
+ MOVQ AX, m_moreframe(BX)
+ MOVQ $runtime·morestack(SB), AX
JMP AX
-TEXT ·morestack01+0(SB),7,$0
+TEXT runtime·morestack01(SB),7,$0
+ get_tls(CX)
+ MOVQ m(CX), BX
SHLQ $32, AX
- MOVQ AX, m_moreframe(m)
- MOVQ $·morestack+0(SB), AX
+ MOVQ AX, m_moreframe(BX)
+ MOVQ $runtime·morestack(SB), AX
JMP AX
-TEXT ·morestack10+0(SB),7,$0
+TEXT runtime·morestack10(SB),7,$0
+ get_tls(CX)
+ MOVQ m(CX), BX
MOVLQZX AX, AX
- MOVQ AX, m_moreframe(m)
- MOVQ $·morestack+0(SB), AX
+ MOVQ AX, m_moreframe(BX)
+ MOVQ $runtime·morestack(SB), AX
JMP AX
-TEXT ·morestack11+0(SB),7,$0
- MOVQ AX, m_moreframe(m)
- MOVQ $·morestack+0(SB), AX
+TEXT runtime·morestack11(SB),7,$0
+ get_tls(CX)
+ MOVQ m(CX), BX
+ MOVQ AX, m_moreframe(BX)
+ MOVQ $runtime·morestack(SB), AX
JMP AX
// subcases of morestack01
// with const of 8,16,...48
-TEXT ·morestack8(SB),7,$0
+TEXT runtime·morestack8(SB),7,$0
PUSHQ $1
- MOVQ $·morestackx(SB), AX
+ MOVQ $morestack<>(SB), AX
JMP AX
-TEXT ·morestack16(SB),7,$0
+TEXT runtime·morestack16(SB),7,$0
PUSHQ $2
- MOVQ $·morestackx(SB), AX
+ MOVQ $morestack<>(SB), AX
JMP AX
-TEXT ·morestack24(SB),7,$0
+TEXT runtime·morestack24(SB),7,$0
PUSHQ $3
- MOVQ $·morestackx(SB), AX
+ MOVQ $morestack<>(SB), AX
JMP AX
-TEXT ·morestack32(SB),7,$0
+TEXT runtime·morestack32(SB),7,$0
PUSHQ $4
- MOVQ $·morestackx(SB), AX
+ MOVQ $morestack<>(SB), AX
JMP AX
-TEXT ·morestack40(SB),7,$0
+TEXT runtime·morestack40(SB),7,$0
PUSHQ $5
- MOVQ $·morestackx(SB), AX
+ MOVQ $morestack<>(SB), AX
JMP AX
-TEXT ·morestack48(SB),7,$0
+TEXT runtime·morestack48(SB),7,$0
PUSHQ $6
- MOVQ $·morestackx(SB), AX
+ MOVQ $morestack<>(SB), AX
JMP AX
-TEXT ·morestackx(SB),7,$0
+TEXT morestack<>(SB),7,$0
+ get_tls(CX)
+ MOVQ m(CX), BX
POPQ AX
SHLQ $35, AX
- MOVQ AX, m_moreframe(m)
- MOVQ $·morestack(SB), AX
+ MOVQ AX, m_moreframe(BX)
+ MOVQ $runtime·morestack(SB), AX
JMP AX
// bool cas(int32 *val, int32 old, int32 new)
@@ -252,7 +305,7 @@ TEXT ·morestackx(SB),7,$0
// return 1;
// } else
// return 0;
-TEXT cas(SB), 7, $0
+TEXT runtime·cas(SB), 7, $0
MOVQ 8(SP), BX
MOVL 16(SP), AX
MOVL 20(SP), CX
@@ -269,7 +322,7 @@ TEXT cas(SB), 7, $0
// 1. pop the caller
// 2. sub 5 bytes from the callers return
// 3. jmp to the argument
-TEXT jmpdefer(SB), 7, $0
+TEXT runtime·jmpdefer(SB), 7, $0
MOVQ 8(SP), AX // fn
MOVQ 16(SP), BX // caller sp
LEAQ -8(BX), SP // caller sp after CALL
@@ -279,80 +332,80 @@ TEXT jmpdefer(SB), 7, $0
// runcgo(void(*fn)(void*), void *arg)
// Call fn(arg) on the scheduler stack,
// aligned appropriately for the gcc ABI.
-// Save g and m across the call,
-// since the foreign code might reuse them.
-TEXT runcgo(SB),7,$32
+TEXT runtime·runcgo(SB),7,$32
MOVQ fn+0(FP), R12
MOVQ arg+8(FP), R13
MOVQ SP, CX
// Figure out if we need to switch to m->g0 stack.
- MOVQ m_g0(m), SI
- CMPQ SI, g
+ get_tls(DI)
+ MOVQ m(DI), DX
+ MOVQ m_g0(DX), SI
+ CMPQ g(DI), SI
JEQ 2(PC)
- MOVQ (m_sched+gobuf_sp)(m), SP
+ MOVQ (m_sched+gobuf_sp)(DX), SP
// Now on a scheduling stack (a pthread-created stack).
SUBQ $32, SP
ANDQ $~15, SP // alignment for gcc ABI
- MOVQ g, 24(SP) // save old g, m, SP
- MOVQ m, 16(SP)
+ MOVQ g(DI), BP
+ MOVQ BP, 16(SP)
+ MOVQ SI, g(DI)
MOVQ CX, 8(SP)
-
- // Save g and m values for a potential callback. The callback
- // will start running with on the g0 stack and as such should
- // have g set to m->g0.
- MOVQ m, DI // DI = first argument in AMD64 ABI
- // SI, second argument, set above
- MOVQ libcgo_set_scheduler(SB), BX
- CALL BX
-
MOVQ R13, DI // DI = first argument in AMD64 ABI
CALL R12
- // Restore registers, stack pointer.
- MOVQ 16(SP), m
- MOVQ 24(SP), g
+ // Restore registers, g, stack pointer.
+ get_tls(DI)
+ MOVQ 16(SP), SI
+ MOVQ SI, g(DI)
MOVQ 8(SP), SP
RET
// runcgocallback(G *g1, void* sp, void (*fn)(void))
// Switch to g1 and sp, call fn, switch back. fn's arguments are on
// the new stack.
-TEXT runcgocallback(SB),7,$48
+TEXT runtime·runcgocallback(SB),7,$48
MOVQ g1+0(FP), DX
MOVQ sp+8(FP), AX
MOVQ fp+16(FP), BX
- MOVQ DX, g
-
// We are running on m's scheduler stack. Save current SP
// into m->sched.sp so that a recursive call to runcgo doesn't
// clobber our stack, and also so that we can restore
// the SP when the call finishes. Reusing m->sched.sp
// for this purpose depends on the fact that there is only
// one possible gosave of m->sched.
- MOVQ SP, (m_sched+gobuf_sp)(m)
+ get_tls(CX)
+ MOVQ DX, g(CX)
+ MOVQ m(CX), CX
+ MOVQ SP, (m_sched+gobuf_sp)(CX)
// Set new SP, call fn
MOVQ AX, SP
CALL BX
- // Restore old SP, return
- MOVQ (m_sched+gobuf_sp)(m), SP
+ // Restore old g and SP, return
+ get_tls(CX)
+ MOVQ m(CX), DX
+ MOVQ m_g0(DX), BX
+ MOVQ BX, g(CX)
+ MOVQ (m_sched+gobuf_sp)(DX), SP
RET
// check that SP is in range [g->stackbase, g->stackguard)
-TEXT stackcheck(SB), 7, $0
- CMPQ g_stackbase(g), SP
+TEXT runtime·stackcheck(SB), 7, $0
+ get_tls(CX)
+ MOVQ g(CX), AX
+ CMPQ g_stackbase(AX), SP
JHI 2(PC)
INT $3
- CMPQ SP, g_stackguard(g)
+ CMPQ SP, g_stackguard(AX)
JHI 2(PC)
INT $3
RET
-TEXT ·memclr(SB),7,$0
+TEXT runtime·memclr(SB),7,$0
MOVQ 8(SP), DI // arg 1 addr
MOVL 16(SP), CX // arg 2 count
ADDL $7, CX
@@ -363,20 +416,19 @@ TEXT ·memclr(SB),7,$0
STOSQ
RET
-TEXT ·getcallerpc+0(SB),7,$0
+TEXT runtime·getcallerpc(SB),7,$0
MOVQ x+0(FP),AX // addr of first arg
MOVQ -8(AX),AX // get calling pc
RET
-TEXT ·setcallerpc+0(SB),7,$0
+TEXT runtime·setcallerpc(SB),7,$0
MOVQ x+0(FP),AX // addr of first arg
MOVQ x+8(FP), BX
MOVQ BX, -8(AX) // set calling pc
RET
-TEXT getcallersp(SB),7,$0
+TEXT runtime·getcallersp(SB),7,$0
MOVQ sp+0(FP), AX
RET
-GLOBL initcgo(SB), $8
-GLOBL libcgo_set_scheduler(SB), $8
+GLOBL runtime·tls0(SB), $64
diff --git a/src/pkg/runtime/amd64/closure.c b/src/pkg/runtime/amd64/closure.c
index de2d1695f..5033468d2 100644
--- a/src/pkg/runtime/amd64/closure.c
+++ b/src/pkg/runtime/amd64/closure.c
@@ -9,20 +9,20 @@
// fn func(arg0, arg1, arg2 *ptr, callerpc uintptr, xxx) yyy,
// arg0, arg1, arg2 *ptr) (func(xxx) yyy)
void
-·closure(int32 siz, byte *fn, byte *arg0)
+runtime·closure(int32 siz, byte *fn, byte *arg0)
{
byte *p, *q, **ret;
int32 i, n;
int64 pcrel;
if(siz < 0 || siz%8 != 0)
- throw("bad closure size");
+ runtime·throw("bad closure size");
ret = (byte**)((byte*)&arg0 + siz);
if(siz > 100) {
// TODO(rsc): implement stack growth preamble?
- throw("closure too big");
+ runtime·throw("closure too big");
}
// compute size of new fn.
@@ -40,12 +40,12 @@ void
if(n%8)
n += 8 - n%8;
- p = mal(n);
+ p = runtime·mal(n);
*ret = p;
q = p + n - siz;
if(siz > 0) {
- mcpy(q, (byte*)&arg0, siz);
+ runtime·mcpy(q, (byte*)&arg0, siz);
// SUBQ $siz, SP
*p++ = 0x48;
@@ -117,7 +117,7 @@ void
*p++ = 0xc3;
if(p > q)
- throw("bad math in sys.closure");
+ runtime·throw("bad math in sys.closure");
}
diff --git a/src/pkg/runtime/amd64/memmove.s b/src/pkg/runtime/amd64/memmove.s
index d755580dc..9966b0ba7 100644
--- a/src/pkg/runtime/amd64/memmove.s
+++ b/src/pkg/runtime/amd64/memmove.s
@@ -23,7 +23,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
- TEXT memmove(SB), 7, $0
+TEXT runtime·memmove(SB), 7, $0
MOVQ to+0(FP), DI
MOVQ fr+8(FP), SI
diff --git a/src/pkg/runtime/amd64/traceback.c b/src/pkg/runtime/amd64/traceback.c
index 20e9200e5..3ea80a661 100644
--- a/src/pkg/runtime/amd64/traceback.c
+++ b/src/pkg/runtime/amd64/traceback.c
@@ -6,6 +6,8 @@
#include "malloc.h"
static uintptr isclosureentry(uintptr);
+void runtime·deferproc(void);
+void runtime·newproc(void);
// This code is also used for the 386 tracebacks.
// Use uintptr for an appropriate word-sized integer.
@@ -19,7 +21,7 @@ gentraceback(byte *pc0, byte *sp, G *g, int32 skip, uintptr *pcbuf, int32 m)
{
byte *p;
int32 i, n, iter, nascent;
- uintptr pc, tracepc;
+ uintptr pc, tracepc, *fp;
Stktop *stk;
Func *f;
@@ -33,7 +35,7 @@ gentraceback(byte *pc0, byte *sp, G *g, int32 skip, uintptr *pcbuf, int32 m)
}
nascent = 0;
- if(pc0 == g->sched.pc && sp == g->sched.sp && pc0 == (byte*)goexit) {
+ if(pc0 == g->sched.pc && sp == g->sched.sp && pc0 == (byte*)runtime·goexit) {
// Hasn't started yet. g->sched is set up for goexit
// but goroutine will start at g->entry.
nascent = 1;
@@ -43,7 +45,7 @@ gentraceback(byte *pc0, byte *sp, G *g, int32 skip, uintptr *pcbuf, int32 m)
n = 0;
stk = (Stktop*)g->stackbase;
for(iter = 0; iter < 100 && n < m; iter++) { // iter avoids looping forever
- if(pc == (uintptr)·lessstack) {
+ if(pc == (uintptr)runtime·lessstack) {
// Hit top of stack segment. Unwind to next segment.
pc = (uintptr)stk->gobuf.pc;
sp = stk->gobuf.sp;
@@ -51,13 +53,14 @@ gentraceback(byte *pc0, byte *sp, G *g, int32 skip, uintptr *pcbuf, int32 m)
continue;
}
- if(pc <= 0x1000 || (f = findfunc(pc)) == nil) {
+ if(pc <= 0x1000 || (f = runtime·findfunc(pc)) == nil) {
// Dangerous, but worthwhile: see if this is a closure:
// ADDQ $wwxxyyzz, SP; RET
// [48] 81 c4 zz yy xx ww c3
// The 0x48 byte is only on amd64.
p = (byte*)pc;
- if(mheap.min < p && p+8 < mheap.max && // pointer in allocated memory
+ // We check p < p+8 to avoid wrapping and faulting if we lose track.
+ if(runtime·mheap.min < p && p < p+8 && p+8 < runtime·mheap.max && // pointer in allocated memory
(sizeof(uintptr) != 8 || *p++ == 0x48) && // skip 0x48 byte on amd64
p[0] == 0x81 && p[1] == 0xc4 && p[6] == 0xc3) {
sp += *(uint32*)(p+2);
@@ -82,24 +85,29 @@ gentraceback(byte *pc0, byte *sp, G *g, int32 skip, uintptr *pcbuf, int32 m)
// Print during crash.
// main+0xf /home/rsc/go/src/runtime/x.go:23
// main(0x1, 0x2, 0x3)
- printf("%S", f->name);
+ runtime·printf("%S", f->name);
if(pc > f->entry)
- printf("+%p", (uintptr)(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)
tracepc--;
- printf(" %S:%d\n", f->src, funcline(f, tracepc));
- printf("\t%S(", f->name);
+ runtime·printf(" %S:%d\n", f->src, runtime·funcline(f, tracepc));
+ runtime·printf("\t%S(", f->name);
+ fp = (uintptr*)sp;
+ if(f->frame < sizeof(uintptr))
+ fp++;
+ else
+ fp += f->frame/sizeof(uintptr);
for(i = 0; i < f->args; i++) {
if(i != 0)
- prints(", ");
- ·printhex(((uintptr*)sp)[i]);
+ runtime·prints(", ");
+ runtime·printhex(fp[i]);
if(i >= 4) {
- prints(", ...");
+ runtime·prints(", ...");
break;
}
}
- prints(")\n");
+ runtime·prints(")\n");
n++;
}
@@ -115,24 +123,26 @@ gentraceback(byte *pc0, byte *sp, G *g, int32 skip, uintptr *pcbuf, int32 m)
else
sp += f->frame;
pc = *((uintptr*)sp - 1);
+ if(f->entry == (uintptr)runtime·deferproc || f->entry == (uintptr)runtime·newproc)
+ sp += 2*sizeof(uintptr);
}
return n;
}
void
-traceback(byte *pc0, byte *sp, byte*, G *g)
+runtime·traceback(byte *pc0, byte *sp, byte*, G *g)
{
gentraceback(pc0, sp, g, 0, nil, 100);
}
int32
-callers(int32 skip, uintptr *pcbuf, int32 m)
+runtime·callers(int32 skip, uintptr *pcbuf, int32 m)
{
byte *pc, *sp;
// our caller's pc, sp.
sp = (byte*)&skip;
- pc = ·getcallerpc(&skip);
+ pc = runtime·getcallerpc(&skip);
return gentraceback(pc, sp, g, skip, pcbuf, m);
}
@@ -144,7 +154,7 @@ isclosureentry(uintptr pc)
int32 i, siz;
p = (byte*)pc;
- if(p < mheap.min || p+32 > mheap.max)
+ if(p < runtime·mheap.min || p+32 > runtime·mheap.max)
return 0;
// SUBQ $siz, SP
diff --git a/src/pkg/runtime/arm/asm.s b/src/pkg/runtime/arm/asm.s
index 1144ff2a1..44c47bad1 100644
--- a/src/pkg/runtime/arm/asm.s
+++ b/src/pkg/runtime/arm/asm.s
@@ -6,7 +6,7 @@
// using frame size $-4 means do not save LR on stack.
TEXT _rt0_arm(SB),7,$-4
- MOVW $setR12(SB), R12
+ MOVW $0xcafebabe, R12
// copy arguments forward on an even stack
// use R13 instead of SP to avoid linker rewriting the offsets
@@ -19,8 +19,8 @@ TEXT _rt0_arm(SB),7,$-4
// set up m and g registers
// g is R10, m is R9
- MOVW $g0(SB), g
- MOVW $m0(SB), m
+ MOVW $runtime·g0(SB), g
+ MOVW $runtime·m0(SB), m
// save m->g0 = g0
MOVW g, m_g0(m)
@@ -29,45 +29,47 @@ TEXT _rt0_arm(SB),7,$-4
MOVW $(-8192+104)(R13), R0
MOVW R0, g_stackguard(g) // (w 104b guard)
MOVW R13, g_stackbase(g)
- BL emptyfunc(SB) // fault if stack check is wrong
+ BL runtime·emptyfunc(SB) // fault if stack check is wrong
- BL check(SB)
+ BL runtime·check(SB)
// saved argc, argv
MOVW 120(R13), R0
MOVW R0, 4(R13)
MOVW 124(R13), R1
MOVW R1, 8(R13)
- BL args(SB)
- BL osinit(SB)
- BL schedinit(SB)
+ BL runtime·args(SB)
+ BL runtime·osinit(SB)
+ BL runtime·schedinit(SB)
// create a new goroutine to start program
- MOVW $mainstart(SB), R0
+ MOVW $runtime·mainstart(SB), R0
MOVW.W R0, -4(R13)
MOVW $8, R0
MOVW.W R0, -4(R13)
MOVW $0, R0
MOVW.W R0, -4(R13) // push $0 as guard
- BL ·newproc(SB)
+ BL runtime·newproc(SB)
MOVW $12(R13), R13 // pop args and LR
// start this M
- BL mstart(SB)
+ BL runtime·mstart(SB)
MOVW $1234, R0
MOVW $1000, R1
MOVW R0, (R1) // fail hard
- B _dep_dummy(SB) // Never reached
+ B runtime·_dep_dummy(SB) // Never reached
-TEXT mainstart(SB),7,$4
+TEXT runtime·mainstart(SB),7,$4
BL main·init(SB)
- BL initdone(SB)
+ BL runtime·initdone(SB)
+ EOR R0, R0
+ MOVW R0, 0(R13)
BL main·main(SB)
MOVW $0, R0
MOVW R0, 4(SP)
- BL exit(SB)
+ BL runtime·exit(SB)
MOVW $1234, R0
MOVW $1001, R1
MOVW R0, (R1) // fail hard
@@ -75,7 +77,7 @@ TEXT mainstart(SB),7,$4
// TODO(kaib): remove these once i actually understand how the linker removes symbols
// pull in dummy dependencies
-TEXT _dep_dummy(SB),7,$0
+TEXT runtime·_dep_dummy(SB),7,$0
BL _div(SB)
BL _divu(SB)
BL _mod(SB)
@@ -83,8 +85,8 @@ TEXT _dep_dummy(SB),7,$0
BL _modu(SB)
BL _sfloat(SB)
-TEXT breakpoint(SB),7,$0
- BL abort(SB)
+TEXT runtime·breakpoint(SB),7,$0
+ // no breakpoint yet; let program exit
RET
/*
@@ -93,8 +95,8 @@ TEXT breakpoint(SB),7,$0
// uintptr gosave(Gobuf*)
// save state in Gobuf; setjmp
-TEXT gosave(SB), 7, $-4
- MOVW 0(FP), R0
+TEXT runtime·gosave(SB), 7, $-4
+ MOVW 0(FP), R0 // gobuf
MOVW SP, gobuf_sp(R0)
MOVW LR, gobuf_pc(R0)
MOVW g, gobuf_g(R0)
@@ -103,8 +105,8 @@ TEXT gosave(SB), 7, $-4
// void gogo(Gobuf*, uintptr)
// restore state from Gobuf; longjmp
-TEXT gogo(SB), 7, $-4
- MOVW 0(FP), R1 // gobuf
+TEXT runtime·gogo(SB), 7, $-4
+ MOVW 0(FP), R1 // gobuf
MOVW 4(FP), R0 // return 2nd arg
MOVW gobuf_g(R1), g
MOVW 0(g), R2 // make sure g != nil
@@ -115,11 +117,12 @@ TEXT gogo(SB), 7, $-4
// restore state from Gobuf but then call fn.
// (call fn, returning to state in Gobuf)
// using frame size $-4 means do not save LR on stack.
-TEXT gogocall(SB), 7, $-4
- MOVW 0(FP), R0
+TEXT runtime·gogocall(SB), 7, $-4
+ MOVW 0(FP), R0 // gobuf
MOVW 4(FP), R1 // fn
+ MOVW 8(FP), R2 // fp offset
MOVW gobuf_g(R0), g
- MOVW 0(g), R2 // make sure g != nil
+ MOVW 0(g), R3 // make sure g != nil
MOVW gobuf_sp(R0), SP // restore SP
MOVW gobuf_pc(R0), LR
MOVW R1, PC
@@ -135,12 +138,11 @@ TEXT gogocall(SB), 7, $-4
// NB. we do not save R0 because we've forced 5c to pass all arguments
// on the stack.
// using frame size $-4 means do not save LR on stack.
-TEXT ·morestack(SB),7,$-4
+TEXT runtime·morestack(SB),7,$-4
// Cannot grow scheduler stack (m->g0).
MOVW m_g0(m), R4
CMP g, R4
- BNE 2(PC)
- BL abort(SB)
+ BL.EQ runtime·abort(SB)
// Save in m.
MOVW R1, m_moreframe(m)
@@ -148,9 +150,9 @@ TEXT ·morestack(SB),7,$-4
// Called from f.
// Set m->morebuf to f's caller.
- MOVW R3, (m_morebuf+gobuf_pc)(m) // f's caller's PC
- MOVW SP, (m_morebuf+gobuf_sp)(m) // f's caller's SP
- MOVW SP, m_morefp(m) // f's caller's SP
+ MOVW R3, (m_morebuf+gobuf_pc)(m) // f's caller's PC
+ MOVW SP, (m_morebuf+gobuf_sp)(m) // f's caller's SP
+ MOVW SP, m_morefp(m) // f's caller's SP
MOVW g, (m_morebuf+gobuf_g)(m)
// Set m->morepc to f's PC.
@@ -159,7 +161,7 @@ TEXT ·morestack(SB),7,$-4
// Call newstack on m's scheduling stack.
MOVW m_g0(m), g
MOVW (m_sched+gobuf_sp)(m), SP
- B newstack(SB)
+ B runtime·newstack(SB)
// Called from reflection library. Mimics morestack,
// reuses stack growth code to create a frame
@@ -179,45 +181,48 @@ TEXT reflect·call(SB), 7, $-4
// If it turns out that f needs a larger frame than
// the default stack, f's usual stack growth prolog will
// allocate a new segment (and recopy the arguments).
- MOVW 4(SP), R0 // fn
- MOVW 8(SP), R1 // arg frame
- MOVW 12(SP), R2 // arg size
+ MOVW 4(SP), R0 // fn
+ MOVW 8(SP), R1 // arg frame
+ MOVW 12(SP), R2 // arg size
- MOVW R0, m_morepc(m) // f's PC
- MOVW R1, m_morefp(m) // argument frame pointer
- MOVW R2, m_moreargs(m) // f's argument size
+ SUB $4,R1 // add the saved LR to the frame
+ ADD $4,R2
+
+ MOVW R0, m_morepc(m) // f's PC
+ MOVW R1, m_morefp(m) // argument frame pointer
+ MOVW R2, m_moreargs(m) // f's argument size
MOVW $1, R3
- MOVW R3, m_moreframe(m) // f's frame size
+ MOVW R3, m_moreframe(m) // f's frame size
// Call newstack on m's scheduling stack.
MOVW m_g0(m), g
MOVW (m_sched+gobuf_sp)(m), SP
- B newstack(SB)
+ B runtime·newstack(SB)
// Return point when leaving stack.
// using frame size $-4 means do not save LR on stack.
-TEXT ·lessstack(SB), 7, $-4
+TEXT runtime·lessstack(SB), 7, $-4
// Save return value in m->cret
MOVW R0, m_cret(m)
// Call oldstack on m's scheduling stack.
MOVW m_g0(m), g
MOVW (m_sched+gobuf_sp)(m), SP
- B oldstack(SB)
+ B runtime·oldstack(SB)
// void jmpdefer(fn, sp);
// called from deferreturn.
// 1. grab stored LR for caller
// 2. sub 4 bytes to get back to BL deferreturn
// 3. B to fn
-TEXT jmpdefer(SB), 7, $0
+TEXT runtime·jmpdefer(SB), 7, $0
MOVW 0(SP), LR
MOVW $-4(LR), LR // BL deferreturn
MOVW 4(SP), R0 // fn
MOVW 8(SP), SP
B (R0)
-TEXT ·memclr(SB),7,$20
+TEXT runtime·memclr(SB),7,$20
MOVW 0(FP), R0
MOVW $0, R1 // c = 0
MOVW R1, -16(SP)
@@ -225,21 +230,21 @@ TEXT ·memclr(SB),7,$20
MOVW R1, -12(SP)
MOVW m, -8(SP) // Save m and g
MOVW g, -4(SP)
- BL memset(SB)
+ BL runtime·memset(SB)
MOVW -8(SP), m // Restore m and g, memset clobbers them
MOVW -4(SP), g
RET
-TEXT ·getcallerpc+0(SB),7,$-4
+TEXT runtime·getcallerpc(SB),7,$-4
MOVW 0(SP), R0
RET
-TEXT ·setcallerpc+0(SB),7,$-4
+TEXT runtime·setcallerpc(SB),7,$-4
MOVW x+4(FP), R0
MOVW R0, 0(SP)
RET
-TEXT getcallersp(SB),7,$-4
+TEXT runtime·getcallersp(SB),7,$-4
MOVW 0(FP), R0
MOVW $-4(R0), R0
RET
@@ -248,8 +253,8 @@ TEXT getcallersp(SB),7,$-4
// Just call fn(arg), but first align the stack
// appropriately for the gcc ABI.
// TODO(kaib): figure out the arm-gcc ABI
-TEXT runcgo(SB),7,$16
- BL abort(SB)
+TEXT runtime·runcgo(SB),7,$16
+ BL runtime·abort(SB)
// MOVL fn+0(FP), AX
// MOVL arg+4(FP), BX
// MOVL SP, CX
@@ -260,10 +265,13 @@ TEXT runcgo(SB),7,$16
// MOVL 4(SP), SP
// RET
-TEXT emptyfunc(SB),0,$0
+TEXT runtime·emptyfunc(SB),0,$0
RET
-TEXT abort(SB),7,$-4
+TEXT runtime·abort(SB),7,$-4
MOVW $0, R0
MOVW (R0), R1
+TEXT runtime·runcgocallback(SB),7,$0
+ MOVW $0, R0
+ MOVW (R0), R1
diff --git a/src/pkg/runtime/arm/cas5.s b/src/pkg/runtime/arm/cas5.s
index 8a4c8be12..20bd3c3e2 100644
--- a/src/pkg/runtime/arm/cas5.s
+++ b/src/pkg/runtime/arm/cas5.s
@@ -14,12 +14,12 @@
// }else
// return 0;
-TEXT cas(SB),7,$0
+TEXT runtime·cas(SB),7,$0
MOVW 0(FP), R0 // *val
MOVW 4(FP), R1 // old
MOVW 8(FP), R2 // new
MOVW $1, R3
- MOVW $cas_mutex(SB), R4
+ MOVW $runtime·cas_mutex(SB), R4
l:
SWPW (R4), R3 // acquire mutex
CMP $0, R3
@@ -39,5 +39,5 @@ fail0:
MOVW $0, R0
RET
-DATA cas_mutex(SB)/4, $0
-GLOBL cas_mutex(SB), $4
+DATA runtime·cas_mutex(SB)/4, $0
+GLOBL runtime·cas_mutex(SB), $4
diff --git a/src/pkg/runtime/arm/cas6.s b/src/pkg/runtime/arm/cas6.s
index 63df1396d..43788b28a 100644
--- a/src/pkg/runtime/arm/cas6.s
+++ b/src/pkg/runtime/arm/cas6.s
@@ -10,7 +10,7 @@
// }else
// return 0;
-TEXT cas(SB),7,$0
+TEXT runtime·cas(SB),7,$0
MOVW 0(FP), R1 // *val
MOVW 4(FP), R2 // old
MOVW 8(FP), R3 // new
diff --git a/src/pkg/runtime/arm/closure.c b/src/pkg/runtime/arm/closure.c
index 11a7719c9..3aca3a42d 100644
--- a/src/pkg/runtime/arm/closure.c
+++ b/src/pkg/runtime/arm/closure.c
@@ -47,20 +47,20 @@ extern void cacheflush(byte* start, byte* end);
#pragma textflag 7
void
-·closure(int32 siz, byte *fn, byte *arg0)
+runtime·closure(int32 siz, byte *fn, byte *arg0)
{
byte *p, *q, **ret;
uint32 *pc;
int32 n;
if(siz < 0 || siz%4 != 0)
- throw("bad closure size");
+ runtime·throw("bad closure size");
ret = (byte**)((byte*)&arg0 + siz);
if(siz > 100) {
// TODO(kaib): implement stack growth preamble?
- throw("closure too big");
+ runtime·throw("closure too big");
}
// size of new fn.
@@ -73,7 +73,7 @@ void
// store args aligned after code, so gc can find them.
n += siz;
- p = mal(n);
+ p = runtime·mal(n);
*ret = p;
q = p + n - siz;
@@ -83,7 +83,7 @@ void
*pc++ = 0xe52de000 | (siz + 4);
if(siz > 0) {
- mcpy(q, (byte*)&arg0, siz);
+ runtime·mcpy(q, (byte*)&arg0, siz);
// MOVW $vars(PC), R0
*pc = 0xe28f0000 | (int32)(q - (byte*)pc - 8);
@@ -122,8 +122,8 @@ void
p = (byte*)pc;
if(p > q)
- throw("bad math in sys.closure");
+ runtime·throw("bad math in sys.closure");
- cacheflush(*ret, q+siz);
+ runtime·cacheflush(*ret, q+siz);
}
diff --git a/src/pkg/runtime/arm/memmove.s b/src/pkg/runtime/arm/memmove.s
index 9f7dc1dd2..5c0e57404 100644
--- a/src/pkg/runtime/arm/memmove.s
+++ b/src/pkg/runtime/arm/memmove.s
@@ -31,7 +31,7 @@ TMP = 3 /* N and TMP don't overlap */
TMP1 = 4
// TODO(kaib): This can be done with the existing registers of LR is re-used. Same for memset.
-TEXT memmove(SB), 7, $8
+TEXT runtime·memmove(SB), 7, $8
// save g and m
MOVW R9, 4(R13)
MOVW R10, 8(R13)
diff --git a/src/pkg/runtime/arm/memset.s b/src/pkg/runtime/arm/memset.s
index cce94534c..974b8da7a 100644
--- a/src/pkg/runtime/arm/memset.s
+++ b/src/pkg/runtime/arm/memset.s
@@ -31,7 +31,7 @@ TMP = 3 /* N and TMP don't overlap */
// TODO(kaib): memset clobbers R9 and R10 (m and g). This makes the
// registers unpredictable if (when) memset SIGSEGV's. Fix it by
// moving the R4-R11 register bank.
-TEXT memset(SB), $0
+TEXT runtime·memset(SB), $0
MOVW R0, R(TO)
MOVW data+4(FP), R(4)
MOVW n+8(FP), R(N)
diff --git a/src/pkg/runtime/arm/softfloat.c b/src/pkg/runtime/arm/softfloat.c
index 46ab07c82..f60fab14f 100644
--- a/src/pkg/runtime/arm/softfloat.c
+++ b/src/pkg/runtime/arm/softfloat.c
@@ -2,428 +2,498 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// Software floating point interpretaton of ARM 7500 FP instructions.
+// The interpretation is not bit compatible with the 7500.
+// It uses true little-endian doubles, while the 7500 used mixed-endian.
+
#include "runtime.h"
-void abort(void);
+#define CPSR 14
+#define FLAGS_N (1 << 31)
+#define FLAGS_Z (1 << 30)
+#define FLAGS_C (1 << 29)
+#define FLAGS_V (1 << 28)
+
+void runtime·abort(void);
+
+static uint32 trace = 0;
static void
fabort(void)
{
if (1) {
- printf("Unsupported floating point instruction\n");
- abort();
+ runtime·printf("Unsupported floating point instruction\n");
+ runtime·abort();
}
}
-static uint32 doabort = 0;
-static uint32 trace = 0;
-
-#define DOUBLE_EXPBIAS 1023
-#define SINGLE_EXPBIAS 127
-
-static const int8* opnames[] = {
- // binary
- "adf",
- "muf",
- "suf",
- "rsf",
- "dvf",
- "rdf",
- "pow",
- "rpw",
- "rmf",
- "fml",
- "fdv",
- "frd",
- "pol",
- "UNDEFINED",
- "UNDEFINED",
- "UNDEFINED",
-
- // unary
- "mvf",
- "mnf",
- "abs",
- "rnd",
- "sqt",
- "log",
- "lgn",
- "exp",
- "sin",
- "cos",
- "tan",
- "asn",
- "acs",
- "atn",
- "urd",
- "nrm"
-};
-
-static const int8* fpconst[] = {
- "0.0", "1.0", "2.0", "3.0", "4.0", "5.0", "0.5", "10.0",
-};
-
-static const uint64 fpdconst[] = {
- 0x0000000000000000ll,
- 0x3ff0000000000000ll,
- 0x4000000000000000ll,
- 0x4008000000000000ll,
- 0x4010000000000000ll,
- 0x4014000000000000ll,
- 0x3fe0000000000000ll,
- 0x4024000000000000ll
-};
-
-static const int8* fpprec[] = {
- "s", "d", "e", "?"
-};
-
-static uint32
-precision(uint32 i)
-{
- switch (i&0x00080080) {
- case 0:
- return 0;
- case 0x80:
- return 1;
- default:
- fabort();
- }
- return 0;
-}
-
-static uint64
-frhs(uint32 rhs)
-{
- if (rhs & 0x8) {
- return fpdconst[rhs&0x7];
- } else {
- return m->freg[rhs&0x7];
- }
-}
-
-static int32
-fexp(uint64 f)
+static void
+putf(uint32 reg, uint32 val)
{
- return (int32)((uint32)(f >> 52) & 0x7ff) - DOUBLE_EXPBIAS;
+ m->freglo[reg] = val;
}
-static uint32
-fsign(uint64 f)
+static void
+putd(uint32 reg, uint64 val)
{
- return (uint32)(f >> 63) & 0x1;
+ m->freglo[reg] = (uint32)val;
+ m->freghi[reg] = (uint32)(val>>32);
}
static uint64
-fmantissa(uint64 f)
+getd(uint32 reg)
{
- return f &0x000fffffffffffffll;
+ return (uint64)m->freglo[reg] | ((uint64)m->freghi[reg]<<32);
}
static void
-fprint()
+fprint(void)
{
uint32 i;
- for (i = 0; i < 8; i++) {
- printf("\tf%d:\t%X\n", i, m->freg[i]);
+ for (i = 0; i < 16; i++) {
+ runtime·printf("\tf%d:\t%X %X\n", i, m->freghi[i], m->freglo[i]);
}
}
static uint32
-d2s(uint64 d)
+d2f(uint64 d)
{
- return (d>>32 & 0x80000000) | //sign
- ((uint32)(fexp(d) + SINGLE_EXPBIAS) & 0xff) << 23 | // exponent
- (d >> 29 & 0x7fffff); // mantissa
+ uint32 x;
+
+ runtime·f64to32c(d, &x);
+ return x;
}
static uint64
-s2d(uint32 s)
+f2d(uint32 f)
{
- return (uint64)(s & 0x80000000) << 63 | // sign
- (uint64)((s >> 23 &0xff) + (DOUBLE_EXPBIAS - SINGLE_EXPBIAS)) << 52 | // exponent
- (uint64)(s & 0x7fffff) << 29; // mantissa
+ uint64 x;
+
+ runtime·f32to64c(f, &x);
+ return x;
}
-// cdp, data processing instructions
-static void
-dataprocess(uint32* pc)
+static uint32
+fstatus(bool nan, int32 cmp)
{
- uint32 i, opcode, unary, dest, lhs, rhs, prec;
- uint32 high;
- uint64 fraw0, fraw1, exp, sign;
- uint64 fd, f0, f1;
-
- i = *pc;
-
- // data processing
- opcode = i>>20 & 15;
- unary = i>>15 & 1;
-
- dest = i>>12 & 7;
- lhs = i>>16 & 7;
- rhs = i & 15;
-
- prec = precision(i);
- if (unary) {
- switch (opcode) {
- case 0: // mvf
- m->freg[dest] = frhs(rhs);
- goto ret;
- default:
- goto undef;
- }
- } else {
- switch (opcode) {
- case 1: // muf
- fraw0 = m->freg[lhs];
- fraw1 = frhs(rhs);
- f0 = fraw0>>21 & 0xffffffff | 0x80000000;
- f1 = fraw1>>21 & 0xffffffff | 0x80000000;
- fd = f0*f1;
- high = fd >> 63;
- if (high)
- fd = fd >> 11 & 0x000fffffffffffffll;
- else
- fd = fd >> 10 & 0x000fffffffffffffll;
- exp = (uint64)(fexp(fraw0) + fexp(fraw1) + !!high + DOUBLE_EXPBIAS) & 0x7ff;
- sign = fraw0 >> 63 ^ fraw1 >> 63;
- fd = sign << 63 | exp <<52 | fd;
- m->freg[dest] = fd;
- goto ret;
- default:
- goto undef;
- }
- }
-
-undef:
- doabort = 1;
-
-ret:
- if (trace || doabort) {
- printf(" %p %x\t%s%s\tf%d, ", pc, *pc, opnames[opcode | unary<<4],
- fpprec[prec], dest);
- if (!unary)
- printf("f%d, ", lhs);
- if (rhs & 0x8)
- printf("#%s\n", fpconst[rhs&0x7]);
- else
- printf("f%d\n", rhs&0x7);
- }
- if (doabort)
- fabort();
+ if(nan)
+ return FLAGS_C | FLAGS_V;
+ if(cmp == 0)
+ return FLAGS_Z | FLAGS_C;
+ if(cmp < 0)
+ return FLAGS_N;
+ return FLAGS_C;
}
-#define CPSR 14
-#define FLAGS_N (1 << 31)
-#define FLAGS_Z (1 << 30)
-#define FLAGS_C (1 << 29)
-
-// cmf, compare floating point
-static void
-compare(uint32 *pc, uint32 *regs) {
- uint32 i, flags, lhs, rhs, sign0, sign1;
- uint32 f0, f1, mant0, mant1;
- int32 exp0, exp1;
+// returns number of words that the fp instruction
+// is occupying, 0 if next instruction isn't float.
+static uint32
+stepflt(uint32 *pc, uint32 *regs)
+{
+ uint32 i, regd, regm, regn;
+ uint32 *addr;
+ uint64 uval;
+ int64 sval;
+ bool nan, ok;
+ int32 cmp;
i = *pc;
- flags = 0;
- lhs = i>>16 & 0x7;
- rhs = i & 0xf;
-
- f0 = m->freg[lhs];
- f1 = frhs(rhs);
- if (f0 == f1) {
- flags = FLAGS_Z | FLAGS_C;
- goto ret;
- }
- sign0 = fsign(f0);
- sign1 = fsign(f1);
- if (sign0 == 1 && sign1 == 0) {
- flags = FLAGS_N;
- goto ret;
+ if(trace)
+ runtime·printf("stepflt %p %x\n", pc, i);
+
+ // special cases
+ if((i&0xfffff000) == 0xe59fb000) {
+ // load r11 from pc-relative address.
+ // might be part of a floating point move
+ // (or might not, but no harm in simulating
+ // one instruction too many).
+ addr = (uint32*)((uint8*)pc + (i&0xfff) + 8);
+ regs[11] = addr[0];
+
+ if(trace)
+ runtime·printf("*** cpu R[%d] = *(%p) %x\n",
+ 11, addr, regs[11]);
+ return 1;
}
- if (sign0 == 0 && sign1 == 1) {
- flags = FLAGS_C;
- goto ret;
+ if(i == 0xe08bb00d) {
+ // add sp to 11.
+ // might be part of a large stack offset address
+ // (or might not, but again no harm done).
+ regs[11] += regs[13];
+
+ if(trace)
+ runtime·printf("*** cpu R[%d] += R[%d] %x\n",
+ 11, 13, regs[11]);
+ return 1;
}
+ if(i == 0xeef1fa10) {
+ regs[CPSR] = (regs[CPSR]&0x0fffffff) | m->fflag;
- if (sign0 == 0) {
- exp0 = fexp(f0);
- exp1 = fexp(f1);
- mant0 = fmantissa(f0);
- mant1 = fmantissa(f1);
- } else {
- exp0 = fexp(f1);
- exp1 = fexp(f0);
- mant0 = fmantissa(f1);
- mant1 = fmantissa(f0);
+ if(trace)
+ runtime·printf("*** fpsr R[CPSR] = F[CPSR] %x\n", regs[CPSR]);
+ return 1;
}
+ goto stage1;
- if (exp0 > exp1) {
- flags = FLAGS_C;
- } else if (exp0 < exp1) {
- flags = FLAGS_N;
- } else {
- if (mant0 > mant1)
- flags = FLAGS_C;
- else
- flags = FLAGS_N;
- }
+stage1: // load/store regn is cpureg, regm is 8bit offset
+ regd = i>>12 & 0xf;
+ regn = i>>16 & 0xf;
+ regm = (i & 0xff) << 2; // PLUS or MINUS ??
-ret:
- if (trace) {
- printf(" %p %x\tcmf\tf%d, ", pc, *pc, lhs);
- if (rhs & 0x8)
- printf("#%s\n", fpconst[rhs&0x7]);
- else
- printf("f%d\n", rhs&0x7);
+ switch(i & 0xfff00f00) {
+ default:
+ goto stage2;
+
+ case 0xed900a00: // single load
+ addr = (uint32*)(regs[regn] + regm);
+ m->freglo[regd] = addr[0];
+
+ if(trace)
+ runtime·printf("*** load F[%d] = %x\n",
+ regd, m->freglo[regd]);
+ break;
+
+ case 0xed900b00: // double load
+ addr = (uint32*)(regs[regn] + regm);
+ m->freglo[regd] = addr[0];
+ m->freghi[regd] = addr[1];
+
+ if(trace)
+ runtime·printf("*** load D[%d] = %x-%x\n",
+ regd, m->freghi[regd], m->freglo[regd]);
+ break;
+
+ case 0xed800a00: // single store
+ addr = (uint32*)(regs[regn] + regm);
+ addr[0] = m->freglo[regd];
+
+ if(trace)
+ runtime·printf("*** *(%p) = %x\n",
+ addr, addr[0]);
+ break;
+
+ case 0xed800b00: // double store
+ addr = (uint32*)(regs[regn] + regm);
+ addr[0] = m->freglo[regd];
+ addr[1] = m->freghi[regd];
+
+ if(trace)
+ runtime·printf("*** *(%p) = %x-%x\n",
+ addr, addr[1], addr[0]);
+ break;
}
- regs[CPSR] = regs[CPSR] & 0x0fffffff | flags;
-}
+ return 1;
-// ldf/stf, load/store floating
-static void
-loadstore(uint32 *pc, uint32 *regs)
-{
- uint32 i, isload, coproc, ud, wb, tlen, p, reg, freg, offset;
- uint32 addr;
-
- i = *pc;
- coproc = i>>8&0xf;
- isload = i>>20&1;
- p = i>>24&1;
- ud = i>>23&1;
- tlen = i>>(22 - 1)&1 | i>>15&1;
- wb = i>>21&1;
- reg = i>>16 &0xf;
- freg = i>>12 &0x7;
- offset = (i&0xff) << 2;
-
- if (coproc != 1 || p != 1 || wb != 0 || tlen > 1)
- goto undef;
- if (reg > 13)
- goto undef;
-
- if (ud)
- addr = regs[reg] + offset;
- else
- addr = regs[reg] - offset;
-
- if (isload)
- if (tlen)
- m->freg[freg] = *((uint64*)addr);
- else
- m->freg[freg] = s2d(*((uint32*)addr));
- else
- if (tlen)
- *((uint64*)addr) = m->freg[freg];
- else
- *((uint32*)addr) = d2s(m->freg[freg]);
- goto ret;
-
-undef:
- doabort = 1;
-
-ret:
- if (trace || doabort) {
- if (isload)
- printf(" %p %x\tldf", pc, *pc);
- else
- printf(" %p %x\tstf", pc, *pc);
- printf("%s\t\tf%d, %s%d(r%d)", fpprec[tlen], freg, ud ? "" : "-", offset, reg);
- printf("\t\t// %p", regs[reg] + (ud ? offset : -offset));
- if (coproc != 1 || p != 1 || wb != 0)
- printf(" coproc: %d pre: %d wb %d", coproc, p, wb);
- printf("\n");
- fprint();
+stage2: // regd, regm, regn are 4bit variables
+ regm = i>>0 & 0xf;
+ switch(i & 0xfff00ff0) {
+ default:
+ goto stage3;
+
+ case 0xf3000110: // veor
+ m->freglo[regd] = m->freglo[regm]^m->freglo[regn];
+ m->freghi[regd] = m->freghi[regm]^m->freghi[regn];
+
+ if(trace)
+ runtime·printf("*** veor D[%d] = %x-%x\n",
+ regd, m->freghi[regd], m->freglo[regd]);
+ break;
+
+ case 0xeeb00b00: // D[regd] = const(regn,regm)
+ regn = (regn<<4) | regm;
+ regm = 0x40000000UL;
+ if(regn & 0x80)
+ regm |= 0x80000000UL;
+ if(regn & 0x40)
+ regm ^= 0x7fc00000UL;
+ regm |= (regn & 0x3f) << 16;
+ m->freglo[regd] = 0;
+ m->freghi[regd] = regm;
+
+ if(trace)
+ runtime·printf("*** immed D[%d] = %x-%x\n",
+ regd, m->freghi[regd], m->freglo[regd]);
+ break;
+
+ case 0xeeb00a00: // F[regd] = const(regn,regm)
+ regn = (regn<<4) | regm;
+ regm = 0x40000000UL;
+ if(regn & 0x80)
+ regm |= 0x80000000UL;
+ if(regn & 0x40)
+ regm ^= 0x7e000000UL;
+ regm |= (regn & 0x3f) << 19;
+ m->freglo[regd] = regm;
+
+ if(trace)
+ runtime·printf("*** immed D[%d] = %x\n",
+ regd, m->freglo[regd]);
+ break;
+
+ case 0xee300b00: // D[regd] = D[regn]+D[regm]
+ runtime·fadd64c(getd(regn), getd(regm), &uval);
+ putd(regd, uval);
+
+ if(trace)
+ runtime·printf("*** add D[%d] = D[%d]+D[%d] %x-%x\n",
+ regd, regn, regm, m->freghi[regd], m->freglo[regd]);
+ break;
+
+ case 0xee300a00: // F[regd] = F[regn]+F[regm]
+ runtime·fadd64c(f2d(m->freglo[regn]), f2d(m->freglo[regm]), &uval);
+ m->freglo[regd] = d2f(uval);
+
+ if(trace)
+ runtime·printf("*** add F[%d] = F[%d]+F[%d] %x\n",
+ regd, regn, regm, m->freglo[regd]);
+ break;
+
+ case 0xee300b40: // D[regd] = D[regn]-D[regm]
+ runtime·fsub64c(getd(regn), getd(regm), &uval);
+ putd(regd, uval);
+
+ if(trace)
+ runtime·printf("*** sub D[%d] = D[%d]-D[%d] %x-%x\n",
+ regd, regn, regm, m->freghi[regd], m->freglo[regd]);
+ break;
+
+ case 0xee300a40: // F[regd] = F[regn]-F[regm]
+ runtime·fsub64c(f2d(m->freglo[regn]), f2d(m->freglo[regm]), &uval);
+ m->freglo[regd] = d2f(uval);
+
+ if(trace)
+ runtime·printf("*** sub F[%d] = F[%d]-F[%d] %x\n",
+ regd, regn, regm, m->freglo[regd]);
+ break;
+
+ case 0xee200b00: // D[regd] = D[regn]*D[regm]
+ runtime·fmul64c(getd(regn), getd(regm), &uval);
+ putd(regd, uval);
+
+ if(trace)
+ runtime·printf("*** mul D[%d] = D[%d]*D[%d] %x-%x\n",
+ regd, regn, regm, m->freghi[regd], m->freglo[regd]);
+ break;
+
+ case 0xee200a00: // F[regd] = F[regn]*F[regm]
+ runtime·fmul64c(f2d(m->freglo[regn]), f2d(m->freglo[regm]), &uval);
+ m->freglo[regd] = d2f(uval);
+
+ if(trace)
+ runtime·printf("*** mul F[%d] = F[%d]*F[%d] %x\n",
+ regd, regn, regm, m->freglo[regd]);
+ break;
+
+ case 0xee800b00: // D[regd] = D[regn]/D[regm]
+ runtime·fdiv64c(getd(regn), getd(regm), &uval);
+ putd(regd, uval);
+
+ if(trace)
+ runtime·printf("*** div D[%d] = D[%d]/D[%d] %x-%x\n",
+ regd, regn, regm, m->freghi[regd], m->freglo[regd]);
+ break;
+
+ case 0xee800a00: // F[regd] = F[regn]/F[regm]
+ runtime·fdiv64c(f2d(m->freglo[regn]), f2d(m->freglo[regm]), &uval);
+ m->freglo[regd] = d2f(uval);
+
+ if(trace)
+ runtime·printf("*** div F[%d] = F[%d]/F[%d] %x\n",
+ regd, regn, regm, m->freglo[regd]);
+ break;
+
+ case 0xee000b10: // S[regn] = R[regd] (MOVW) (regm ignored)
+ m->freglo[regn] = regs[regd];
+
+ if(trace)
+ runtime·printf("*** cpy S[%d] = R[%d] %x\n",
+ regn, regd, m->freglo[regn]);
+ break;
+
+ case 0xee100b10: // R[regd] = S[regn] (MOVW) (regm ignored)
+ regs[regd] = m->freglo[regn];
+
+ if(trace)
+ runtime·printf("*** cpy R[%d] = S[%d] %x\n",
+ regd, regn, regs[regd]);
+ break;
}
- if (doabort)
- fabort();
-}
-
-static void
-loadconst(uint32 *pc, uint32 *regs)
-{
- uint32 offset;
- uint32 *addr;
-
- if (*pc & 0xfffff000 != 0xe59fb838 ||
- *(pc+1) != 0xe08bb00c ||
- *(pc+2) & 0xffff8fff != 0xed9b0100)
- goto undef;
-
- offset = *pc & 0xfff;
- addr = (uint32*)((uint8*)pc + offset + 8);
-//printf("DEBUG: addr %p *addr %x final %p\n", addr, *addr, *addr + regs[12]);
- regs[11] = *addr + regs[12];
- loadstore(pc + 2, regs);
- goto ret;
+ return 1;
-undef:
- doabort = 1;
-
-ret:
- if (trace || doabort) {
- printf(" %p coproc const %x %x %x\n", pc, *pc, *(pc+1), *(pc+2));
- }
- if (doabort)
- fabort();
-}
+stage3: // regd, regm are 4bit variables
+ switch(i & 0xffff0ff0) {
+ default:
+ goto done;
+
+ case 0xeeb00a40: // F[regd] = F[regm] (MOVF)
+ m->freglo[regd] = m->freglo[regm];
+
+ if(trace)
+ runtime·printf("*** F[%d] = F[%d] %x\n",
+ regd, regm, m->freglo[regd]);
+ break;
+
+ case 0xeeb00b40: // D[regd] = D[regm] (MOVD)
+ m->freglo[regd] = m->freglo[regm];
+ m->freghi[regd] = m->freghi[regm];
+
+ if(trace)
+ runtime·printf("*** D[%d] = D[%d] %x-%x\n",
+ regd, regm, m->freghi[regd], m->freglo[regd]);
+ break;
+
+ case 0xeeb40bc0: // D[regd] :: D[regm] (CMPD)
+ runtime·fcmp64c(getd(regd), getd(regm), &cmp, &nan);
+ m->fflag = fstatus(nan, cmp);
+
+ if(trace)
+ runtime·printf("*** cmp D[%d]::D[%d] %x\n",
+ regd, regm, m->fflag);
+ break;
+
+ case 0xeeb40ac0: // F[regd] :: F[regm] (CMPF)
+ runtime·fcmp64c(f2d(m->freglo[regd]), f2d(m->freglo[regm]), &cmp, &nan);
+ m->fflag = fstatus(nan, cmp);
+
+ if(trace)
+ runtime·printf("*** cmp F[%d]::F[%d] %x\n",
+ regd, regm, m->fflag);
+ break;
+
+ case 0xeeb70ac0: // D[regd] = F[regm] (MOVFD)
+ putd(regd, f2d(m->freglo[regm]));
+
+ if(trace)
+ runtime·printf("*** f2d D[%d]=F[%d] %x-%x\n",
+ regd, regm, m->freghi[regd], m->freglo[regd]);
+ break;
+
+ case 0xeeb70bc0: // F[regd] = D[regm] (MOVDF)
+ m->freglo[regd] = d2f(getd(regm));
+
+ if(trace)
+ runtime·printf("*** d2f F[%d]=D[%d] %x-%x\n",
+ regd, regm, m->freghi[regd], m->freglo[regd]);
+ break;
+
+ case 0xeebd0ac0: // S[regd] = F[regm] (MOVFW)
+ runtime·f64tointc(f2d(m->freglo[regm]), &sval, &ok);
+ if(!ok || (int32)sval != sval)
+ sval = 0;
+ m->freglo[regd] = sval;
+
+ if(trace)
+ runtime·printf("*** fix S[%d]=F[%d] %x\n",
+ regd, regm, m->freglo[regd]);
+ break;
+
+ case 0xeebc0ac0: // S[regd] = F[regm] (MOVFW.U)
+ runtime·f64tointc(f2d(m->freglo[regm]), &sval, &ok);
+ if(!ok || (uint32)sval != sval)
+ sval = 0;
+ m->freglo[regd] = sval;
+
+ if(trace)
+ runtime·printf("*** fix unsigned S[%d]=F[%d] %x\n",
+ regd, regm, m->freglo[regd]);
+ break;
+
+ case 0xeebd0bc0: // S[regd] = D[regm] (MOVDW)
+ runtime·f64tointc(getd(regm), &sval, &ok);
+ if(!ok || (int32)sval != sval)
+ sval = 0;
+ m->freglo[regd] = sval;
+
+ if(trace)
+ runtime·printf("*** fix S[%d]=D[%d] %x\n",
+ regd, regm, m->freglo[regd]);
+ break;
+
+ case 0xeebc0bc0: // S[regd] = D[regm] (MOVDW.U)
+ runtime·f64tointc(getd(regm), &sval, &ok);
+ if(!ok || (uint32)sval != sval)
+ sval = 0;
+ m->freglo[regd] = sval;
+
+ if(trace)
+ runtime·printf("*** fix unsigned S[%d]=D[%d] %x\n",
+ regd, regm, m->freglo[regd]);
+ break;
+
+ case 0xeeb80ac0: // D[regd] = S[regm] (MOVWF)
+ cmp = m->freglo[regm];
+ if(cmp < 0) {
+ runtime·fintto64c(-cmp, &uval);
+ putf(regd, d2f(uval));
+ m->freglo[regd] ^= 0x80000000;
+ } else {
+ runtime·fintto64c(cmp, &uval);
+ putf(regd, d2f(uval));
+ }
+ if(trace)
+ runtime·printf("*** float D[%d]=S[%d] %x-%x\n",
+ regd, regm, m->freghi[regd], m->freglo[regd]);
+ break;
+
+ case 0xeeb80a40: // D[regd] = S[regm] (MOVWF.U)
+ runtime·fintto64c(m->freglo[regm], &uval);
+ putf(regd, d2f(uval));
+
+ if(trace)
+ runtime·printf("*** float unsigned D[%d]=S[%d] %x-%x\n",
+ regd, regm, m->freghi[regd], m->freglo[regd]);
+ break;
+
+ case 0xeeb80bc0: // D[regd] = S[regm] (MOVWD)
+ cmp = m->freglo[regm];
+ if(cmp < 0) {
+ runtime·fintto64c(-cmp, &uval);
+ putd(regd, uval);
+ m->freghi[regd] ^= 0x80000000;
+ } else {
+ runtime·fintto64c(cmp, &uval);
+ putd(regd, uval);
+ }
-// returns number of words that the fp instruction is occupying, 0 if next instruction isn't float.
-// TODO(kaib): insert sanity checks for coproc 1
-static uint32
-stepflt(uint32 *pc, uint32 *regs)
-{
- uint32 i, c;
+ if(trace)
+ runtime·printf("*** float D[%d]=S[%d] %x-%x\n",
+ regd, regm, m->freghi[regd], m->freglo[regd]);
+ break;
- i = *pc;
- c = i >> 25 & 7;
+ case 0xeeb80b40: // D[regd] = S[regm] (MOVWD.U)
+ runtime·fintto64c(m->freglo[regm], &uval);
+ putd(regd, uval);
- switch(c) {
- case 6: // 110
- loadstore(pc, regs);
- return 1;
- case 7: // 111
- if (i>>24 & 1) return 0; // ignore swi
-
- if (i>>4 & 1) { //data transfer
- if ((i&0x00f0ff00) != 0x0090f100) {
- printf(" %p %x\n", pc, i);
- fabort();
- }
- compare(pc, regs);
- } else {
- dataprocess(pc);
- }
- return 1;
+ if(trace)
+ runtime·printf("*** float unsigned D[%d]=S[%d] %x-%x\n",
+ regd, regm, m->freghi[regd], m->freglo[regd]);
+ break;
}
+ return 1;
- // lookahead for virtual instructions that span multiple arm instructions
- c = ((*pc & 0x0f000000) >> 16) |
- ((*(pc + 1) & 0x0f000000) >> 20) |
- ((*(pc + 2) & 0x0f000000) >> 24);
- if(c == 0x50d) { // 0101 0000 1101
- loadconst(pc, regs);
- return 3;
+done:
+ if((i&0xff000000) == 0xee000000 ||
+ (i&0xff000000) == 0xed000000) {
+ runtime·printf("stepflt %p %x\n", pc, i);
+ fabort();
}
-
return 0;
}
#pragma textflag 7
uint32*
-_sfloat2(uint32 *lr, uint32 r0)
+runtime·_sfloat2(uint32 *lr, uint32 r0)
{
uint32 skip;
- uint32 cpsr;
- while(skip = stepflt(lr, &r0)) {
+ skip = stepflt(lr, &r0);
+ if(skip == 0)
+ fabort(); // not ok to fail first instruction
+
+ lr += skip;
+ while(skip = stepflt(lr, &r0))
lr += skip;
- }
return lr;
}
-
diff --git a/src/pkg/runtime/arm/traceback.c b/src/pkg/runtime/arm/traceback.c
index 0131f21d6..8289fdb28 100644
--- a/src/pkg/runtime/arm/traceback.c
+++ b/src/pkg/runtime/arm/traceback.c
@@ -16,9 +16,9 @@ gentraceback(byte *pc0, byte *sp, byte *lr0, G *g, int32 skip, uintptr *pcbuf, i
lr = (uintptr)lr0;
// If the PC is goexit, it hasn't started yet.
- if(pc == (uintptr)goexit) {
+ if(pc == (uintptr)runtime·goexit) {
pc = (uintptr)g->entry;
- lr = (uintptr)goexit;
+ lr = (uintptr)runtime·goexit;
}
// If the PC is zero, it's likely a nil function call.
@@ -31,7 +31,7 @@ gentraceback(byte *pc0, byte *sp, byte *lr0, G *g, int32 skip, uintptr *pcbuf, i
n = 0;
stk = (Stktop*)g->stackbase;
for(iter = 0; iter < 100 && n < m; iter++) { // iter avoids looping forever
- if(pc == (uintptr)·lessstack) {
+ if(pc == (uintptr)runtime·lessstack) {
// Hit top of stack segment. Unwind to next segment.
pc = (uintptr)stk->gobuf.pc;
sp = stk->gobuf.sp;
@@ -39,7 +39,7 @@ gentraceback(byte *pc0, byte *sp, byte *lr0, G *g, int32 skip, uintptr *pcbuf, i
stk = (Stktop*)stk->stackbase;
continue;
}
- if(pc <= 0x1000 || (f = findfunc(pc-4)) == nil) {
+ if(pc <= 0x1000 || (f = runtime·findfunc(pc-4)) == nil) {
// TODO: Check for closure.
break;
}
@@ -53,24 +53,24 @@ gentraceback(byte *pc0, byte *sp, byte *lr0, G *g, int32 skip, uintptr *pcbuf, i
// Print during crash.
// main+0xf /home/rsc/go/src/runtime/x.go:23
// main(0x1, 0x2, 0x3)
- printf("%S", f->name);
+ runtime·printf("%S", f->name);
if(pc > f->entry)
- printf("+%p", (uintptr)(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)
tracepc -= sizeof(uintptr);
- printf(" %S:%d\n", f->src, funcline(f, tracepc));
- printf("\t%S(", f->name);
+ 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)
- prints(", ");
- ·printhex(((uintptr*)sp)[1+i]);
+ runtime·prints(", ");
+ runtime·printhex(((uintptr*)sp)[1+i]);
if(i >= 4) {
- prints(", ...");
+ runtime·prints(", ...");
break;
}
}
- prints(")\n");
+ runtime·prints(")\n");
n++;
}
@@ -85,19 +85,19 @@ gentraceback(byte *pc0, byte *sp, byte *lr0, G *g, int32 skip, uintptr *pcbuf, i
}
void
-traceback(byte *pc0, byte *sp, byte *lr, G *g)
+runtime·traceback(byte *pc0, byte *sp, byte *lr, G *g)
{
gentraceback(pc0, sp, lr, g, 0, nil, 100);
}
// func caller(n int) (pc uintptr, file string, line int, ok bool)
int32
-callers(int32 skip, uintptr *pcbuf, int32 m)
+runtime·callers(int32 skip, uintptr *pcbuf, int32 m)
{
byte *pc, *sp;
- sp = getcallersp(&skip);
- pc = ·getcallerpc(&skip);
+ sp = runtime·getcallersp(&skip);
+ pc = runtime·getcallerpc(&skip);
return gentraceback(pc, sp, 0, g, skip, pcbuf, m);
}
diff --git a/src/pkg/runtime/arm/vlop.s b/src/pkg/runtime/arm/vlop.s
index c9e7090fc..2c5d7ebe1 100644
--- a/src/pkg/runtime/arm/vlop.s
+++ b/src/pkg/runtime/arm/vlop.s
@@ -30,7 +30,7 @@ arg=0
/* replaced use of R10 by R11 because the former can be the data segment base register */
-TEXT _mulv(SB), $0
+TEXT _mulv(SB), $0
MOVW 0(FP), R0
MOVW 4(FP), R2 /* l0 */
MOVW 8(FP), R11 /* h0 */
@@ -52,7 +52,7 @@ D = 2
CC = 3
TMP = 11
-TEXT save<>(SB), 7, $0
+TEXT save<>(SB), 7, $0
MOVW R(Q), 0(FP)
MOVW R(N), 4(FP)
MOVW R(D), 8(FP)
@@ -62,11 +62,11 @@ TEXT save<>(SB), 7, $0
MOVW 20(FP), R(D) /* denominator */
CMP $0, R(D)
BNE s1
- SWI 0
+ BL runtime·panicdivide(SB)
/* MOVW -1(R(D)), R(TMP) /* divide by zero fault */
s1: RET
-TEXT rest<>(SB), 7, $0
+TEXT rest<>(SB), 7, $0
MOVW 0(FP), R(Q)
MOVW 4(FP), R(N)
MOVW 8(FP), R(D)
@@ -79,7 +79,7 @@ TEXT rest<>(SB), 7, $0
ADD $20, R13
B (R14)
-TEXT div<>(SB), 7, $0
+TEXT div<>(SB), 7, $0
MOVW $32, R(CC)
/*
* skip zeros 8-at-a-time
@@ -114,7 +114,7 @@ loop:
BNE loop
RET
-TEXT _div(SB), 7, $16
+TEXT _div(SB), 7, $16
BL save<>(SB)
CMP $0, R(Q)
BGE d1
@@ -135,7 +135,7 @@ d2:
RSB $0, R(Q), R(TMP)
B out
-TEXT _mod(SB), 7, $16
+TEXT _mod(SB), 7, $16
BL save<>(SB)
CMP $0, R(D)
RSB.LT $0, R(D), R(D)
@@ -150,13 +150,13 @@ m1:
MOVW R(N), R(TMP)
B out
-TEXT _divu(SB), 7, $16
+TEXT _divu(SB), 7, $16
BL save<>(SB)
BL div<>(SB)
MOVW R(Q), R(TMP)
B out
-TEXT _modu(SB), 7, $16
+TEXT _modu(SB), 7, $16
BL save<>(SB)
BL div<>(SB)
MOVW R(N), R(TMP)
@@ -169,7 +169,7 @@ out:
// trampoline for _sfloat2. passes LR as arg0 and
// saves registers R0-R13 and CPSR on the stack. R0-R12 and CPSR flags can
// be changed by _sfloat2.
-TEXT _sfloat(SB), 7, $64 // 4 arg + 14*4 saved regs + cpsr
+TEXT _sfloat(SB), 7, $64 // 4 arg + 14*4 saved regs + cpsr
MOVW R14, 4(R13)
MOVW R0, 8(R13)
MOVW $12(R13), R0
@@ -178,7 +178,7 @@ TEXT _sfloat(SB), 7, $64 // 4 arg + 14*4 saved regs + cpsr
MOVW R1, 60(R13)
WORD $0xe10f1000 // mrs r1, cpsr
MOVW R1, 64(R13)
- BL _sfloat2(SB)
+ BL runtime·_sfloat2(SB)
MOVW R0, 0(R13)
MOVW 64(R13), R1
WORD $0xe128f001 // msr cpsr_f, r1
diff --git a/src/pkg/runtime/arm/vlrt.c b/src/pkg/runtime/arm/vlrt.c
index 76b777a35..50f33710b 100644
--- a/src/pkg/runtime/arm/vlrt.c
+++ b/src/pkg/runtime/arm/vlrt.c
@@ -23,6 +23,9 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+// declared here to avoid include of runtime.h
+void runtime·panicstring(char*);
+
typedef unsigned long ulong;
typedef unsigned int uint;
typedef unsigned short ushort;
@@ -31,6 +34,12 @@ typedef signed char schar;
#define SIGN(n) (1UL<<(n-1))
+void
+runtime·panicdivide(void)
+{
+ runtime·panicstring("integer divide by zero");
+}
+
typedef struct Vlong Vlong;
struct Vlong
{
@@ -47,210 +56,231 @@ struct Vlong
ushort loms;
ushort hils;
ushort hims;
- };
- };
+ };
+ };
};
-void abort(void);
+void runtime·abort(void);
void
_addv(Vlong *r, Vlong a, Vlong b)
{
- ulong lo, hi;
+ ulong lo, hi;
- lo = a.lo + b.lo;
- hi = a.hi + b.hi;
- if(lo < a.lo)
- hi++;
- r->lo = lo;
- r->hi = hi;
+ lo = a.lo + b.lo;
+ hi = a.hi + b.hi;
+ if(lo < a.lo)
+ hi++;
+ r->lo = lo;
+ r->hi = hi;
}
void
_subv(Vlong *r, Vlong a, Vlong b)
{
- ulong lo, hi;
+ ulong lo, hi;
- lo = a.lo - b.lo;
- hi = a.hi - b.hi;
- if(lo > a.lo)
- hi--;
- r->lo = lo;
- r->hi = hi;
+ lo = a.lo - b.lo;
+ hi = a.hi - b.hi;
+ if(lo > a.lo)
+ hi--;
+ r->lo = lo;
+ r->hi = hi;
}
-
void
_d2v(Vlong *y, double d)
{
- union { double d; struct Vlong; } x;
- ulong xhi, xlo, ylo, yhi;
- int sh;
-
- x.d = d;
-
- xhi = (x.hi & 0xfffff) | 0x100000;
- xlo = x.lo;
- sh = 1075 - ((x.hi >> 20) & 0x7ff);
-
- ylo = 0;
- yhi = 0;
- if(sh >= 0) {
- /* v = (hi||lo) >> sh */
- if(sh < 32) {
- if(sh == 0) {
- ylo = xlo;
- yhi = xhi;
- } else {
- ylo = (xlo >> sh) | (xhi << (32-sh));
- yhi = xhi >> sh;
- }
- } else {
- if(sh == 32) {
- ylo = xhi;
- } else
- if(sh < 64) {
- ylo = xhi >> (sh-32);
- }
- }
- } else {
- /* v = (hi||lo) << -sh */
- sh = -sh;
- if(sh <= 10) {
- ylo = xlo << sh;
- yhi = (xhi << sh) | (xlo >> (32-sh));
- } else {
- /* overflow */
- yhi = d; /* causes something awful */
- }
- }
- if(x.hi & SIGN(32)) {
- if(ylo != 0) {
- ylo = -ylo;
- yhi = ~yhi;
- } else
- yhi = -yhi;
- }
-
- y->hi = yhi;
- y->lo = ylo;
+ union { double d; struct Vlong; } x;
+ ulong xhi, xlo, ylo, yhi;
+ int sh;
+
+ x.d = d;
+
+ xhi = (x.hi & 0xfffff) | 0x100000;
+ xlo = x.lo;
+ sh = 1075 - ((x.hi >> 20) & 0x7ff);
+
+ ylo = 0;
+ yhi = 0;
+ if(sh >= 0) {
+ /* v = (hi||lo) >> sh */
+ if(sh < 32) {
+ if(sh == 0) {
+ ylo = xlo;
+ yhi = xhi;
+ } else {
+ ylo = (xlo >> sh) | (xhi << (32-sh));
+ yhi = xhi >> sh;
+ }
+ } else {
+ if(sh == 32) {
+ ylo = xhi;
+ } else
+ if(sh < 64) {
+ ylo = xhi >> (sh-32);
+ }
+ }
+ } else {
+ /* v = (hi||lo) << -sh */
+ sh = -sh;
+ if(sh <= 11) {
+ ylo = xlo << sh;
+ yhi = (xhi << sh) | (xlo >> (32-sh));
+ } else {
+ /* overflow */
+ yhi = d; /* causes something awful */
+ }
+ }
+ if(x.hi & SIGN(32)) {
+ if(ylo != 0) {
+ ylo = -ylo;
+ yhi = ~yhi;
+ } else
+ yhi = -yhi;
+ }
+
+ y->hi = yhi;
+ y->lo = ylo;
}
void
_f2v(Vlong *y, float f)
{
- _d2v(y, f);
+ _d2v(y, f);
+}
+
+void
+runtime·float64toint64(double d, Vlong y)
+{
+ _d2v(&y, d);
}
void
-·float64toint64(double d, Vlong y)
+runtime·float64touint64(double d, Vlong y)
{
_d2v(&y, d);
}
double
+_ul2d(ulong u)
+{
+ // compensate for bug in c
+ if(u & SIGN(32)) {
+ u ^= SIGN(32);
+ return 2147483648. + u;
+ }
+ return u;
+}
+
+double
_v2d(Vlong x)
{
- if(x.hi & SIGN(32)) {
- if(x.lo) {
- x.lo = -x.lo;
- x.hi = ~x.hi;
- } else
- x.hi = -x.hi;
- return -((long)x.hi*4294967296. + x.lo);
- }
- return (long)x.hi*4294967296. + x.lo;
+ if(x.hi & SIGN(32)) {
+ if(x.lo) {
+ x.lo = -x.lo;
+ x.hi = ~x.hi;
+ } else
+ x.hi = -x.hi;
+ return -(_ul2d(x.hi)*4294967296. + _ul2d(x.lo));
+ }
+ return x.hi*4294967296. + _ul2d(x.lo);
}
float
_v2f(Vlong x)
{
- return _v2d(x);
+ return _v2d(x);
}
void
-·int64tofloat64(Vlong y, double d)
+runtime·int64tofloat64(Vlong y, double d)
{
d = _v2d(y);
}
+void
+runtime·uint64tofloat64(Vlong y, double d)
+{
+ d = _ul2d(y.hi)*4294967296. + _ul2d(y.lo);
+}
static void
dodiv(Vlong num, Vlong den, Vlong *q, Vlong *r)
{
- ulong numlo, numhi, denhi, denlo, quohi, quolo, t;
- int i;
-
- numhi = num.hi;
- numlo = num.lo;
- denhi = den.hi;
- denlo = den.lo;
-
- /*
- * get a divide by zero
- */
- if(denlo==0 && denhi==0) {
- numlo = numlo / denlo;
- }
-
- /*
- * set up the divisor and find the number of iterations needed
- */
- if(numhi >= SIGN(32)) {
- quohi = SIGN(32);
- quolo = 0;
- } else {
- quohi = numhi;
- quolo = numlo;
- }
- i = 0;
- while(denhi < quohi || (denhi == quohi && denlo < quolo)) {
- denhi = (denhi<<1) | (denlo>>31);
- denlo <<= 1;
- i++;
- }
-
- quohi = 0;
- quolo = 0;
- for(; i >= 0; i--) {
- quohi = (quohi<<1) | (quolo>>31);
- quolo <<= 1;
- if(numhi > denhi || (numhi == denhi && numlo >= denlo)) {
- t = numlo;
- numlo -= denlo;
- if(numlo > t)
- numhi--;
- numhi -= denhi;
- quolo |= 1;
- }
- denlo = (denlo>>1) | (denhi<<31);
- denhi >>= 1;
- }
-
- if(q) {
- q->lo = quolo;
- q->hi = quohi;
- }
- if(r) {
- r->lo = numlo;
- r->hi = numhi;
- }
+ ulong numlo, numhi, denhi, denlo, quohi, quolo, t;
+ int i;
+
+ numhi = num.hi;
+ numlo = num.lo;
+ denhi = den.hi;
+ denlo = den.lo;
+
+ /*
+ * get a divide by zero
+ */
+ if(denlo==0 && denhi==0) {
+ runtime·panicdivide();
+ }
+
+ /*
+ * set up the divisor and find the number of iterations needed
+ */
+ if(numhi >= SIGN(32)) {
+ quohi = SIGN(32);
+ quolo = 0;
+ } else {
+ quohi = numhi;
+ quolo = numlo;
+ }
+ i = 0;
+ while(denhi < quohi || (denhi == quohi && denlo < quolo)) {
+ denhi = (denhi<<1) | (denlo>>31);
+ denlo <<= 1;
+ i++;
+ }
+
+ quohi = 0;
+ quolo = 0;
+ for(; i >= 0; i--) {
+ quohi = (quohi<<1) | (quolo>>31);
+ quolo <<= 1;
+ if(numhi > denhi || (numhi == denhi && numlo >= denlo)) {
+ t = numlo;
+ numlo -= denlo;
+ if(numlo > t)
+ numhi--;
+ numhi -= denhi;
+ quolo |= 1;
+ }
+ denlo = (denlo>>1) | (denhi<<31);
+ denhi >>= 1;
+ }
+
+ if(q) {
+ q->lo = quolo;
+ q->hi = quohi;
+ }
+ if(r) {
+ r->lo = numlo;
+ r->hi = numhi;
+ }
}
void
_divvu(Vlong *q, Vlong n, Vlong d)
{
- if(n.hi == 0 && d.hi == 0) {
- q->hi = 0;
- q->lo = n.lo / d.lo;
- return;
- }
- dodiv(n, d, q, 0);
+ if(n.hi == 0 && d.hi == 0) {
+ q->hi = 0;
+ q->lo = n.lo / d.lo;
+ return;
+ }
+ dodiv(n, d, q, 0);
}
void
-·uint64div(Vlong n, Vlong d, Vlong q)
+runtime·uint64div(Vlong n, Vlong d, Vlong q)
{
_divvu(&q, n, d);
}
@@ -259,16 +289,16 @@ void
_modvu(Vlong *r, Vlong n, Vlong d)
{
- if(n.hi == 0 && d.hi == 0) {
- r->hi = 0;
- r->lo = n.lo % d.lo;
- return;
- }
- dodiv(n, d, 0, r);
+ if(n.hi == 0 && d.hi == 0) {
+ r->hi = 0;
+ r->lo = n.lo % d.lo;
+ return;
+ }
+ dodiv(n, d, 0, r);
}
void
-·uint64mod(Vlong n, Vlong d, Vlong q)
+runtime·uint64mod(Vlong n, Vlong d, Vlong q)
{
_modvu(&q, n, d);
}
@@ -277,20 +307,20 @@ static void
vneg(Vlong *v)
{
- if(v->lo == 0) {
- v->hi = -v->hi;
- return;
- }
- v->lo = -v->lo;
- v->hi = ~v->hi;
+ if(v->lo == 0) {
+ v->hi = -v->hi;
+ return;
+ }
+ v->lo = -v->lo;
+ v->hi = ~v->hi;
}
void
_divv(Vlong *q, Vlong n, Vlong d)
{
- long nneg, dneg;
+ long nneg, dneg;
- if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+ if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
if((long)n.lo == -0x80000000 && (long)d.lo == -1) {
// special case: 32-bit -0x80000000 / -1 causes wrong sign
q->lo = 0x80000000;
@@ -300,20 +330,20 @@ _divv(Vlong *q, Vlong n, Vlong d)
q->lo = (long)n.lo / (long)d.lo;
q->hi = ((long)q->lo) >> 31;
return;
- }
- nneg = n.hi >> 31;
- if(nneg)
- vneg(&n);
- dneg = d.hi >> 31;
- if(dneg)
- vneg(&d);
- dodiv(n, d, q, 0);
- if(nneg != dneg)
- vneg(q);
+ }
+ nneg = n.hi >> 31;
+ if(nneg)
+ vneg(&n);
+ dneg = d.hi >> 31;
+ if(dneg)
+ vneg(&d);
+ dodiv(n, d, q, 0);
+ if(nneg != dneg)
+ vneg(q);
}
void
-·int64div(Vlong n, Vlong d, Vlong q)
+runtime·int64div(Vlong n, Vlong d, Vlong q)
{
_divv(&q, n, d);
}
@@ -321,26 +351,26 @@ void
void
_modv(Vlong *r, Vlong n, Vlong d)
{
- long nneg, dneg;
+ long nneg, dneg;
- if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
- r->lo = (long)n.lo % (long)d.lo;
- r->hi = ((long)r->lo) >> 31;
- return;
- }
- nneg = n.hi >> 31;
- if(nneg)
- vneg(&n);
- dneg = d.hi >> 31;
- if(dneg)
- vneg(&d);
- dodiv(n, d, 0, r);
- if(nneg)
- vneg(r);
+ if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+ r->lo = (long)n.lo % (long)d.lo;
+ r->hi = ((long)r->lo) >> 31;
+ return;
+ }
+ nneg = n.hi >> 31;
+ if(nneg)
+ vneg(&n);
+ dneg = d.hi >> 31;
+ if(dneg)
+ vneg(&d);
+ dodiv(n, d, 0, r);
+ if(nneg)
+ vneg(r);
}
void
-·int64mod(Vlong n, Vlong d, Vlong q)
+runtime·int64mod(Vlong n, Vlong d, Vlong q)
{
_modv(&q, n, d);
}
@@ -348,439 +378,439 @@ void
void
_rshav(Vlong *r, Vlong a, int b)
{
- long t;
-
- t = a.hi;
- if(b >= 32) {
- r->hi = t>>31;
- if(b >= 64) {
- /* this is illegal re C standard */
- r->lo = t>>31;
- return;
- }
- r->lo = t >> (b-32);
- return;
- }
- if(b <= 0) {
- r->hi = t;
- r->lo = a.lo;
- return;
- }
- r->hi = t >> b;
- r->lo = (t << (32-b)) | (a.lo >> b);
+ long t;
+
+ t = a.hi;
+ if(b >= 32) {
+ r->hi = t>>31;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->lo = t>>31;
+ return;
+ }
+ r->lo = t >> (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->hi = t;
+ r->lo = a.lo;
+ return;
+ }
+ r->hi = t >> b;
+ r->lo = (t << (32-b)) | (a.lo >> b);
}
void
_rshlv(Vlong *r, Vlong a, int b)
{
- ulong t;
-
- t = a.hi;
- if(b >= 32) {
- r->hi = 0;
- if(b >= 64) {
- /* this is illegal re C standard */
- r->lo = 0;
- return;
- }
- r->lo = t >> (b-32);
- return;
- }
- if(b <= 0) {
- r->hi = t;
- r->lo = a.lo;
- return;
- }
- r->hi = t >> b;
- r->lo = (t << (32-b)) | (a.lo >> b);
+ ulong t;
+
+ t = a.hi;
+ if(b >= 32) {
+ r->hi = 0;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->lo = 0;
+ return;
+ }
+ r->lo = t >> (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->hi = t;
+ r->lo = a.lo;
+ return;
+ }
+ r->hi = t >> b;
+ r->lo = (t << (32-b)) | (a.lo >> b);
}
void
_lshv(Vlong *r, Vlong a, int b)
{
- ulong t;
-
- t = a.lo;
- if(b >= 32) {
- r->lo = 0;
- if(b >= 64) {
- /* this is illegal re C standard */
- r->hi = 0;
- return;
- }
- r->hi = t << (b-32);
- return;
- }
- if(b <= 0) {
- r->lo = t;
- r->hi = a.hi;
- return;
- }
- r->lo = t << b;
- r->hi = (t >> (32-b)) | (a.hi << b);
+ ulong t;
+
+ t = a.lo;
+ if(b >= 32) {
+ r->lo = 0;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->hi = 0;
+ return;
+ }
+ r->hi = t << (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->lo = t;
+ r->hi = a.hi;
+ return;
+ }
+ r->lo = t << b;
+ r->hi = (t >> (32-b)) | (a.hi << b);
}
void
_andv(Vlong *r, Vlong a, Vlong b)
{
- r->hi = a.hi & b.hi;
- r->lo = a.lo & b.lo;
+ r->hi = a.hi & b.hi;
+ r->lo = a.lo & b.lo;
}
void
_orv(Vlong *r, Vlong a, Vlong b)
{
- r->hi = a.hi | b.hi;
- r->lo = a.lo | b.lo;
+ r->hi = a.hi | b.hi;
+ r->lo = a.lo | b.lo;
}
void
_xorv(Vlong *r, Vlong a, Vlong b)
{
- r->hi = a.hi ^ b.hi;
- r->lo = a.lo ^ b.lo;
+ r->hi = a.hi ^ b.hi;
+ r->lo = a.lo ^ b.lo;
}
void
_vpp(Vlong *l, Vlong *r)
{
- l->hi = r->hi;
- l->lo = r->lo;
- r->lo++;
- if(r->lo == 0)
- r->hi++;
+ l->hi = r->hi;
+ l->lo = r->lo;
+ r->lo++;
+ if(r->lo == 0)
+ r->hi++;
}
void
_vmm(Vlong *l, Vlong *r)
{
- l->hi = r->hi;
- l->lo = r->lo;
- if(r->lo == 0)
- r->hi--;
- r->lo--;
+ l->hi = r->hi;
+ l->lo = r->lo;
+ if(r->lo == 0)
+ r->hi--;
+ r->lo--;
}
void
_ppv(Vlong *l, Vlong *r)
{
- r->lo++;
- if(r->lo == 0)
- r->hi++;
- l->hi = r->hi;
- l->lo = r->lo;
+ r->lo++;
+ if(r->lo == 0)
+ r->hi++;
+ l->hi = r->hi;
+ l->lo = r->lo;
}
void
_mmv(Vlong *l, Vlong *r)
{
- if(r->lo == 0)
- r->hi--;
- r->lo--;
- l->hi = r->hi;
- l->lo = r->lo;
+ if(r->lo == 0)
+ r->hi--;
+ r->lo--;
+ l->hi = r->hi;
+ l->lo = r->lo;
}
void
_vasop(Vlong *ret, void *lv, void fn(Vlong*, Vlong, Vlong), int type, Vlong rv)
{
- Vlong t, u;
-
- u = *ret;
- switch(type) {
- default:
- abort();
- break;
-
- case 1: /* schar */
- t.lo = *(schar*)lv;
- t.hi = t.lo >> 31;
- fn(&u, t, rv);
- *(schar*)lv = u.lo;
- break;
-
- case 2: /* uchar */
- t.lo = *(uchar*)lv;
- t.hi = 0;
- fn(&u, t, rv);
- *(uchar*)lv = u.lo;
- break;
-
- case 3: /* short */
- t.lo = *(short*)lv;
- t.hi = t.lo >> 31;
- fn(&u, t, rv);
- *(short*)lv = u.lo;
- break;
-
- case 4: /* ushort */
- t.lo = *(ushort*)lv;
- t.hi = 0;
- fn(&u, t, rv);
- *(ushort*)lv = u.lo;
- break;
-
- case 9: /* int */
- t.lo = *(int*)lv;
- t.hi = t.lo >> 31;
- fn(&u, t, rv);
- *(int*)lv = u.lo;
- break;
-
- case 10: /* uint */
- t.lo = *(uint*)lv;
- t.hi = 0;
- fn(&u, t, rv);
- *(uint*)lv = u.lo;
- break;
-
- case 5: /* long */
- t.lo = *(long*)lv;
- t.hi = t.lo >> 31;
- fn(&u, t, rv);
- *(long*)lv = u.lo;
- break;
-
- case 6: /* ulong */
- t.lo = *(ulong*)lv;
- t.hi = 0;
- fn(&u, t, rv);
- *(ulong*)lv = u.lo;
- break;
-
- case 7: /* vlong */
- case 8: /* uvlong */
- fn(&u, *(Vlong*)lv, rv);
- *(Vlong*)lv = u;
- break;
- }
- *ret = u;
+ Vlong t, u;
+
+ u = *ret;
+ switch(type) {
+ default:
+ runtime·abort();
+ break;
+
+ case 1: /* schar */
+ t.lo = *(schar*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(schar*)lv = u.lo;
+ break;
+
+ case 2: /* uchar */
+ t.lo = *(uchar*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(uchar*)lv = u.lo;
+ break;
+
+ case 3: /* short */
+ t.lo = *(short*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(short*)lv = u.lo;
+ break;
+
+ case 4: /* ushort */
+ t.lo = *(ushort*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(ushort*)lv = u.lo;
+ break;
+
+ case 9: /* int */
+ t.lo = *(int*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(int*)lv = u.lo;
+ break;
+
+ case 10: /* uint */
+ t.lo = *(uint*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(uint*)lv = u.lo;
+ break;
+
+ case 5: /* long */
+ t.lo = *(long*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(long*)lv = u.lo;
+ break;
+
+ case 6: /* ulong */
+ t.lo = *(ulong*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(ulong*)lv = u.lo;
+ break;
+
+ case 7: /* vlong */
+ case 8: /* uvlong */
+ fn(&u, *(Vlong*)lv, rv);
+ *(Vlong*)lv = u;
+ break;
+ }
+ *ret = u;
}
void
_p2v(Vlong *ret, void *p)
{
- long t;
+ long t;
- t = (ulong)p;
- ret->lo = t;
- ret->hi = 0;
+ t = (ulong)p;
+ ret->lo = t;
+ ret->hi = 0;
}
void
_sl2v(Vlong *ret, long sl)
{
- long t;
+ long t;
- t = sl;
- ret->lo = t;
- ret->hi = t >> 31;
+ t = sl;
+ ret->lo = t;
+ ret->hi = t >> 31;
}
void
_ul2v(Vlong *ret, ulong ul)
{
- long t;
+ long t;
- t = ul;
- ret->lo = t;
- ret->hi = 0;
+ t = ul;
+ ret->lo = t;
+ ret->hi = 0;
}
void
_si2v(Vlong *ret, int si)
{
- long t;
+ long t;
- t = si;
- ret->lo = t;
- ret->hi = t >> 31;
+ t = si;
+ ret->lo = t;
+ ret->hi = t >> 31;
}
void
_ui2v(Vlong *ret, uint ui)
{
- long t;
+ long t;
- t = ui;
- ret->lo = t;
- ret->hi = 0;
+ t = ui;
+ ret->lo = t;
+ ret->hi = 0;
}
void
_sh2v(Vlong *ret, long sh)
{
- long t;
+ long t;
- t = (sh << 16) >> 16;
- ret->lo = t;
- ret->hi = t >> 31;
+ t = (sh << 16) >> 16;
+ ret->lo = t;
+ ret->hi = t >> 31;
}
void
_uh2v(Vlong *ret, ulong ul)
{
- long t;
+ long t;
- t = ul & 0xffff;
- ret->lo = t;
- ret->hi = 0;
+ t = ul & 0xffff;
+ ret->lo = t;
+ ret->hi = 0;
}
void
_sc2v(Vlong *ret, long uc)
{
- long t;
+ long t;
- t = (uc << 24) >> 24;
- ret->lo = t;
- ret->hi = t >> 31;
+ t = (uc << 24) >> 24;
+ ret->lo = t;
+ ret->hi = t >> 31;
}
void
_uc2v(Vlong *ret, ulong ul)
{
- long t;
+ long t;
- t = ul & 0xff;
- ret->lo = t;
- ret->hi = 0;
+ t = ul & 0xff;
+ ret->lo = t;
+ ret->hi = 0;
}
long
_v2sc(Vlong rv)
{
- long t;
+ long t;
- t = rv.lo & 0xff;
- return (t << 24) >> 24;
+ t = rv.lo & 0xff;
+ return (t << 24) >> 24;
}
long
_v2uc(Vlong rv)
{
- return rv.lo & 0xff;
+ return rv.lo & 0xff;
}
long
_v2sh(Vlong rv)
{
- long t;
+ long t;
- t = rv.lo & 0xffff;
- return (t << 16) >> 16;
+ t = rv.lo & 0xffff;
+ return (t << 16) >> 16;
}
long
_v2uh(Vlong rv)
{
- return rv.lo & 0xffff;
+ return rv.lo & 0xffff;
}
long
_v2sl(Vlong rv)
{
- return rv.lo;
+ return rv.lo;
}
long
_v2ul(Vlong rv)
{
- return rv.lo;
+ return rv.lo;
}
long
_v2si(Vlong rv)
{
- return rv.lo;
+ return rv.lo;
}
long
_v2ui(Vlong rv)
{
- return rv.lo;
+ return rv.lo;
}
int
_testv(Vlong rv)
{
- return rv.lo || rv.hi;
+ return rv.lo || rv.hi;
}
int
_eqv(Vlong lv, Vlong rv)
{
- return lv.lo == rv.lo && lv.hi == rv.hi;
+ return lv.lo == rv.lo && lv.hi == rv.hi;
}
int
_nev(Vlong lv, Vlong rv)
{
- return lv.lo != rv.lo || lv.hi != rv.hi;
+ return lv.lo != rv.lo || lv.hi != rv.hi;
}
int
_ltv(Vlong lv, Vlong rv)
{
- return (long)lv.hi < (long)rv.hi ||
- (lv.hi == rv.hi && lv.lo < rv.lo);
+ return (long)lv.hi < (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo < rv.lo);
}
int
_lev(Vlong lv, Vlong rv)
{
- return (long)lv.hi < (long)rv.hi ||
- (lv.hi == rv.hi && lv.lo <= rv.lo);
+ return (long)lv.hi < (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo <= rv.lo);
}
int
_gtv(Vlong lv, Vlong rv)
{
- return (long)lv.hi > (long)rv.hi ||
- (lv.hi == rv.hi && lv.lo > rv.lo);
+ return (long)lv.hi > (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo > rv.lo);
}
int
_gev(Vlong lv, Vlong rv)
{
- return (long)lv.hi > (long)rv.hi ||
- (lv.hi == rv.hi && lv.lo >= rv.lo);
+ return (long)lv.hi > (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo >= rv.lo);
}
int
_lov(Vlong lv, Vlong rv)
{
- return lv.hi < rv.hi ||
- (lv.hi == rv.hi && lv.lo < rv.lo);
+ return lv.hi < rv.hi ||
+ (lv.hi == rv.hi && lv.lo < rv.lo);
}
int
_lsv(Vlong lv, Vlong rv)
{
- return lv.hi < rv.hi ||
- (lv.hi == rv.hi && lv.lo <= rv.lo);
+ return lv.hi < rv.hi ||
+ (lv.hi == rv.hi && lv.lo <= rv.lo);
}
int
_hiv(Vlong lv, Vlong rv)
{
- return lv.hi > rv.hi ||
- (lv.hi == rv.hi && lv.lo > rv.lo);
+ return lv.hi > rv.hi ||
+ (lv.hi == rv.hi && lv.lo > rv.lo);
}
int
_hsv(Vlong lv, Vlong rv)
{
- return lv.hi > rv.hi ||
- (lv.hi == rv.hi && lv.lo >= rv.lo);
+ return lv.hi > rv.hi ||
+ (lv.hi == rv.hi && lv.lo >= rv.lo);
}
diff --git a/src/libcgo/386.S b/src/pkg/runtime/cgo/386.S
index cca79cdd5..9abab7ebd 100755
--- a/src/libcgo/386.S
+++ b/src/pkg/runtime/cgo/386.S
@@ -5,7 +5,7 @@
/*
* Apple still insists on underscore prefixes for C function names.
*/
-#if defined(__APPLE__) || defined(__MINGW32__)
+#if defined(__APPLE__) || defined(_WIN32)
#define EXT(s) _##s
#else
#define EXT(s) s
@@ -59,3 +59,9 @@ EXT(crosscall2):
popl %ebx
popl %ebp
ret
+
+.globl EXT(__stack_chk_fail_local)
+EXT(__stack_chk_fail_local):
+1:
+ jmp 1b
+
diff --git a/src/pkg/runtime/cgo/Makefile b/src/pkg/runtime/cgo/Makefile
new file mode 100644
index 000000000..55b6967d9
--- /dev/null
+++ b/src/pkg/runtime/cgo/Makefile
@@ -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.
+
+include ../../../Make.inc
+
+ENABLED:=1
+
+ifeq ($(GOARCH),arm)
+ENABLED:=0
+endif
+
+TARG=runtime/cgo
+
+GOFILES=\
+ cgo.go\
+
+ifeq ($(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\
+
+OFILES=\
+ iscgo.$O\
+ callbacks.$O\
+ _cgo_import.$O\
+ $(CGO_OFILES)\
+
+CGO_LDFLAGS=-lpthread
+
+ifeq ($(GOOS),freebsd)
+OFILES+=\
+ freebsd.$O\
+
+endif
+
+endif
+
+include ../../../Make.pkg
+
+ifeq ($(ENABLED),1)
+_cgo_defun.c:
+ echo >$@
+
+_cgo_main.c:
+ echo 'int main() { return 0; }' >$@
+ echo 'void *crosscall2;' >>$@
+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/libcgo/amd64.S b/src/pkg/runtime/cgo/amd64.S
index 92ded0ac2..083c2bc94 100644
--- a/src/libcgo/amd64.S
+++ b/src/pkg/runtime/cgo/amd64.S
@@ -5,14 +5,14 @@
/*
* Apple still insists on underscore prefixes for C function names.
*/
-#if defined(__APPLE__) || defined(__MINGW64__)
+#if defined(__APPLE__) || defined(_WIN32)
#define EXT(s) _##s
#else
#define EXT(s) s
#endif
/*
- * void crosscall_amd64(M *m, G *g, void (*fn)(void))
+ * void crosscall_amd64(void (*fn)(void))
*
* Calling into the 6c tool chain, where all registers are caller save.
* Called from standard x86-64 ABI, where %rbx, %rbp, %r12-%r15
@@ -32,9 +32,7 @@ EXT(crosscall_amd64):
pushq %r14
pushq %r15
- movq %rdi, %r14 /* m */
- movq %rsi, %r15 /* g */
- call *%rdx /* fn */
+ call *%rdi /* fn */
popq %r15
popq %r14
@@ -60,16 +58,10 @@ EXT(crosscall2):
movq %r14, 0x30(%rsp)
movq %r15, 0x38(%rsp)
- movq %rdi, %r12 /* fn */
movq %rsi, 0(%rsp) /* arg */
movq %rdx, 8(%rsp) /* argsize (includes padding) */
- leaq 0x40(%rsp), %rdi
- call EXT(libcgo_get_scheduler)
- movq 0x40(%rsp), %r14 /* m */
- movq 0x48(%rsp), %r15 /* g */
-
- call *%r12
+ call *%rdi /* fn */
movq 0x10(%rsp), %rbx
movq 0x18(%rsp), %rbp
diff --git a/src/libcgo/linux_arm.c b/src/pkg/runtime/cgo/arm.S
index 32d862984..32d862984 100644
--- a/src/libcgo/linux_arm.c
+++ b/src/pkg/runtime/cgo/arm.S
diff --git a/src/pkg/runtime/cgo/callbacks.c b/src/pkg/runtime/cgo/callbacks.c
new file mode 100644
index 000000000..f36fb3fd7
--- /dev/null
+++ b/src/pkg/runtime/cgo/callbacks.c
@@ -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.
+
+#include "../runtime.h"
+#include "../cgocall.h"
+
+// These utility functions are available to be called from code
+// compiled with gcc via crosscall2.
+
+// The declaration of crosscall2 is:
+// void crosscall2(void (*fn)(void *, int), void *, int);
+//
+// We need to export the symbol crosscall2 in order to support
+// callbacks from shared libraries.
+#pragma dynexport crosscall2 crosscall2
+
+// Allocate memory. This allocates the requested number of bytes in
+// memory controlled by the Go runtime. The allocated memory will be
+// zeroed. You are responsible for ensuring that the Go garbage
+// collector can see a pointer to the allocated memory for as long as
+// it is valid, e.g., by storing a pointer in a local variable in your
+// C function, or in memory allocated by the Go runtime. If the only
+// pointers are in a C global variable or in memory allocated via
+// malloc, then the Go garbage collector may collect the memory.
+
+// Call like this in code compiled with gcc:
+// struct { size_t len; void *ret; } a;
+// a.len = /* number of bytes to allocate */;
+// crosscall2(_cgo_allocate, &a, sizeof a);
+// /* Here a.ret is a pointer to the allocated memory. */
+
+static void
+_cgo_allocate_internal(uintptr len, byte *ret)
+{
+ ret = runtime·mal(len);
+ FLUSH(&ret);
+}
+
+#pragma dynexport _cgo_allocate _cgo_allocate
+void
+_cgo_allocate(void *a, int32 n)
+{
+ runtime·cgocallback((void(*)(void))_cgo_allocate_internal, a, n);
+}
+
+// Panic. The argument is converted into a Go string.
+
+// Call like this in code compiled with gcc:
+// struct { const char *p; } a;
+// a.p = /* string to pass to panic */;
+// crosscall2(_cgo_panic, &a, sizeof a);
+// /* The function call will not return. */
+
+extern void ·cgoStringToEface(String, Eface*);
+
+static void
+_cgo_panic_internal(byte *p)
+{
+ String s;
+ Eface err;
+
+ s = runtime·gostring(p);
+ ·cgoStringToEface(s, &err);
+ runtime·panic(err);
+}
+
+#pragma dynexport _cgo_panic _cgo_panic
+void
+_cgo_panic(void *a, int32 n)
+{
+ runtime·cgocallback((void(*)(void))_cgo_panic_internal, a, n);
+}
diff --git a/src/pkg/runtime/cgo/cgo.go b/src/pkg/runtime/cgo/cgo.go
new file mode 100644
index 000000000..5dcced1e4
--- /dev/null
+++ b/src/pkg/runtime/cgo/cgo.go
@@ -0,0 +1,17 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+Package cgo contains runtime support for code generated
+by the cgo tool. See the documentation for the cgo command
+for details on using cgo.
+*/
+package cgo
+
+// Supports _cgo_panic by converting a string constant to an empty
+// interface.
+
+func cgoStringToEface(s string, ret *interface{}) {
+ *ret = s
+}
diff --git a/src/libcgo/darwin_386.c b/src/pkg/runtime/cgo/darwin_386.c
index 28a428309..4fc7eb4e0 100644
--- a/src/libcgo/darwin_386.c
+++ b/src/pkg/runtime/cgo/darwin_386.c
@@ -8,9 +8,6 @@
static void* threadentry(void*);
static pthread_key_t k1, k2;
-/* gccism: arrange for inittls to be called at dynamic load time */
-static void inittls(void) __attribute__((constructor));
-
static void
inittls(void)
{
@@ -75,7 +72,7 @@ inittls(void)
fprintf(stderr, "\twanted 0x108 and 0x109\n");
fprintf(stderr, "\tgot");
for(i=0; i<ntofree; i++)
- fprintf(stderr, " %#x", tofree[i]);
+ fprintf(stderr, " %#lx", tofree[i]);
fprintf(stderr, "\n");
abort();
}
@@ -97,16 +94,19 @@ inittls(void)
asm volatile("movl %%gs:0x468, %0" : "=r"(y));
if(x != 0x12345678 || y != 0x87654321) {
- printf("libcgo: thread-local storage %#x not at %%gs:0x468 - x=%#x y=%#x\n", k1, x, y);
+ printf("libcgo: thread-local storage %#lx not at %%gs:0x468 - x=%#x y=%#x\n", k1, x, y);
abort();
}
}
-void
-initcgo(void)
+static void
+xinitcgo(void)
{
+ inittls();
}
+void (*initcgo)(void) = xinitcgo;
+
void
libcgo_sys_thread_start(ThreadStart *ts)
{
diff --git a/src/pkg/runtime/cgo/darwin_amd64.c b/src/pkg/runtime/cgo/darwin_amd64.c
new file mode 100644
index 000000000..253a1b252
--- /dev/null
+++ b/src/pkg/runtime/cgo/darwin_amd64.c
@@ -0,0 +1,125 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include <pthread.h>
+#include "libcgo.h"
+
+static void* threadentry(void*);
+static pthread_key_t k1, k2;
+
+static void
+inittls(void)
+{
+ uint64 x, y;
+ pthread_key_t tofree[16], k;
+ int i, ntofree;
+ int havek1, havek2;
+
+ /*
+ * Same logic, code as darwin_386.c:/inittls, except that words
+ * are 8 bytes long now, and the thread-local storage starts at 0x60.
+ * So the offsets are
+ * 0x60+8*0x108 = 0x8a0 and 0x60+8*0x109 = 0x8a8.
+ *
+ * The linker and runtime hard-code these constant offsets
+ * from %gs where we expect to find m and g. The code
+ * below verifies that the constants are correct once it has
+ * obtained the keys. Known to ../cmd/6l/obj.c:/8a0
+ * and to ../pkg/runtime/darwin/amd64/sys.s:/8a0
+ *
+ * As disgusting as on the 386; same justification.
+ */
+ havek1 = 0;
+ havek2 = 0;
+ ntofree = 0;
+ while(!havek1 || !havek2) {
+ if(pthread_key_create(&k, nil) < 0) {
+ fprintf(stderr, "libcgo: pthread_key_create failed\n");
+ abort();
+ }
+ if(k == 0x108) {
+ havek1 = 1;
+ k1 = k;
+ continue;
+ }
+ if(k == 0x109) {
+ havek2 = 1;
+ k2 = k;
+ continue;
+ }
+ if(ntofree >= nelem(tofree)) {
+ fprintf(stderr, "libcgo: could not obtain pthread_keys\n");
+ fprintf(stderr, "\twanted 0x108 and 0x109\n");
+ fprintf(stderr, "\tgot");
+ for(i=0; i<ntofree; i++)
+ fprintf(stderr, " %#x", (unsigned)tofree[i]);
+ fprintf(stderr, "\n");
+ abort();
+ }
+ tofree[ntofree++] = k;
+ }
+
+ for(i=0; i<ntofree; i++)
+ pthread_key_delete(tofree[i]);
+
+ /*
+ * We got the keys we wanted. Make sure that we observe
+ * updates to k1 at 0x8a0, to verify that the TLS array
+ * offset from %gs hasn't changed.
+ */
+ pthread_setspecific(k1, (void*)0x123456789abcdef0ULL);
+ asm volatile("movq %%gs:0x8a0, %0" : "=r"(x));
+
+ pthread_setspecific(k2, (void*)0x0fedcba987654321);
+ asm volatile("movq %%gs:0x8a8, %0" : "=r"(y));
+
+ if(x != 0x123456789abcdef0ULL || y != 0x0fedcba987654321) {
+ printf("libcgo: thread-local storage %#x not at %%gs:0x8a0 - x=%#llx y=%#llx\n", (unsigned)k1, x, y);
+ abort();
+ }
+}
+
+void
+xinitcgo(void)
+{
+ inittls();
+}
+
+void (*initcgo) = xinitcgo;
+
+void
+libcgo_sys_thread_start(ThreadStart *ts)
+{
+ pthread_attr_t attr;
+ pthread_t p;
+ size_t size;
+
+ pthread_attr_init(&attr);
+ pthread_attr_getstacksize(&attr, &size);
+ ts->g->stackguard = size;
+ pthread_create(&p, &attr, threadentry, ts);
+}
+
+static void*
+threadentry(void *v)
+{
+ ThreadStart ts;
+
+ ts = *(ThreadStart*)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;
+
+ pthread_setspecific(k1, (void*)ts.g);
+ pthread_setspecific(k2, (void*)ts.m);
+
+ crosscall_amd64(ts.fn);
+ return nil;
+}
diff --git a/src/pkg/runtime/cgo/freebsd.c b/src/pkg/runtime/cgo/freebsd.c
new file mode 100644
index 000000000..dfcfa3a21
--- /dev/null
+++ b/src/pkg/runtime/cgo/freebsd.c
@@ -0,0 +1,13 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Supply environ and __progname, because we don't
+// link against the standard FreeBSD crt0.o and the
+// libc dynamic library needs them.
+
+char *environ[1];
+char *__progname;
+
+#pragma dynexport environ environ
+#pragma dynexport __progname __progname
diff --git a/src/libcgo/freebsd_386.c b/src/pkg/runtime/cgo/freebsd_386.c
index b445b940a..d08e1dee8 100644
--- a/src/libcgo/freebsd_386.c
+++ b/src/pkg/runtime/cgo/freebsd_386.c
@@ -7,18 +7,12 @@
static void* threadentry(void*);
-char *environ[] = { 0 };
-char *__progname;
-
static void
-inittls(void)
+xinitcgo(void)
{
}
-void
-initcgo(void)
-{
-}
+void (*initcgo)(void) = xinitcgo;
void
libcgo_sys_thread_start(ThreadStart *ts)
diff --git a/src/libcgo/linux_amd64.c b/src/pkg/runtime/cgo/freebsd_amd64.c
index fc4a239fb..fe6ce391f 100644
--- a/src/libcgo/linux_amd64.c
+++ b/src/pkg/runtime/cgo/freebsd_amd64.c
@@ -7,11 +7,13 @@
static void* threadentry(void*);
-void
-initcgo(void)
+static void
+xinitcgo(void)
{
}
+void (*initcgo)(void) = xinitcgo;
+
void
libcgo_sys_thread_start(ThreadStart *ts)
{
@@ -41,31 +43,16 @@ threadentry(void *v)
*/
ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096;
- crosscall_amd64(ts.m, ts.g, ts.fn);
+ /*
+ * Set specific keys. On FreeBSD/ELF, the thread local storage
+ * is just before %fs:0. Our dynamic 6.out's reserve 16 bytes
+ * for the two words g and m at %fs:-16 and %fs:-8.
+ */
+ asm volatile (
+ "movq %0, %%fs:-16\n" // MOVL g, -16(FS)
+ "movq %1, %%fs:-8\n" // MOVL m, -8(FS)
+ :: "r"(ts.g), "r"(ts.m)
+ );
+ crosscall_amd64(ts.fn);
return nil;
}
-
-static __thread void *libcgo_m;
-static __thread void *libcgo_g;
-
-void
-libcgo_set_scheduler(void *m, void *g)
-{
- libcgo_m = m;
- libcgo_g = g;
-}
-
-struct get_scheduler_args {
- void *m;
- void *g;
-};
-
-void libcgo_get_scheduler(struct get_scheduler_args *)
- __attribute__ ((visibility("hidden")));
-
-void
-libcgo_get_scheduler(struct get_scheduler_args *p)
-{
- p->m = libcgo_m;
- p->g = libcgo_g;
-}
diff --git a/src/pkg/runtime/cgo/iscgo.c b/src/pkg/runtime/cgo/iscgo.c
new file mode 100644
index 000000000..eb6f5c09d
--- /dev/null
+++ b/src/pkg/runtime/cgo/iscgo.c
@@ -0,0 +1,14 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The runtime package contains an uninitialized definition
+// for runtime·iscgo. Override it to tell the runtime we're here.
+// There are various function pointers that should be set too,
+// but those depend on dynamic linker magic to get initialized
+// correctly, and sometimes they break. This variable is a
+// backup: it depends only on old C style static linking rules.
+
+#include "../runtime.h"
+
+bool runtime·iscgo = 1;
diff --git a/src/libcgo/libcgo.h b/src/pkg/runtime/cgo/libcgo.h
index b4b25accb..91032959c 100644
--- a/src/libcgo/libcgo.h
+++ b/src/pkg/runtime/cgo/libcgo.h
@@ -10,6 +10,7 @@
#define nelem(x) (sizeof(x)/sizeof((x)[0]))
typedef uint32_t uint32;
+typedef uint64_t uint64;
typedef uintptr_t uintptr;
/*
@@ -41,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);
+void (*libcgo_thread_start)(ThreadStart *ts);
/*
* Creates the new operating system thread (OS, arch dependent).
@@ -49,10 +50,9 @@ void libcgo_thread_start(ThreadStart *ts);
void libcgo_sys_thread_start(ThreadStart *ts);
/*
- * Call fn in the 6c world, with m and g
- * set to the given parameters.
+ * Call fn in the 6c world.
*/
-void crosscall_amd64(uintptr m, G *g, void (*fn)(void));
+void crosscall_amd64(void (*fn)(void));
/*
* Call fn in the 8c world.
diff --git a/src/pkg/runtime/cgo/linux_386.c b/src/pkg/runtime/cgo/linux_386.c
new file mode 100644
index 000000000..00322d4b7
--- /dev/null
+++ b/src/pkg/runtime/cgo/linux_386.c
@@ -0,0 +1,68 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include <pthread.h>
+#include <string.h>
+#include "libcgo.h"
+
+static void *threadentry(void*);
+
+static void
+xinitcgo(void)
+{
+}
+
+void (*initcgo) = xinitcgo;
+
+void
+libcgo_sys_thread_start(ThreadStart *ts)
+{
+ pthread_attr_t attr;
+ pthread_t p;
+ size_t size;
+
+ // 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.
+ memset(&attr, 0, sizeof attr);
+ pthread_attr_init(&attr);
+ size = 0;
+ pthread_attr_getstacksize(&attr, &size);
+ ts->g->stackguard = size;
+ pthread_create(&p, &attr, threadentry, ts);
+}
+
+static void*
+threadentry(void *v)
+{
+ ThreadStart ts;
+
+ ts = *(ThreadStart*)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;
+
+ /*
+ * Set specific keys. On Linux/ELF, the thread local storage
+ * is just before %gs:0. Our dynamic 8.out's reserve 8 bytes
+ * for the two words g and m at %gs:-8 and %gs:-4.
+ * Xen requires us to access those words indirect from %gs:0
+ * which points at itself.
+ */
+ asm volatile (
+ "movl %%gs:0, %%eax\n" // MOVL 0(GS), tmp
+ "movl %0, -8(%%eax)\n" // MOVL g, -8(GS)
+ "movl %1, -4(%%eax)\n" // MOVL m, -4(GS)
+ :: "r"(ts.g), "r"(ts.m) : "%eax"
+ );
+
+ crosscall_386(ts.fn);
+ return nil;
+}
diff --git a/src/libcgo/linux_386.c b/src/pkg/runtime/cgo/linux_amd64.c
index 9d02455cc..e77c5ddfe 100644
--- a/src/libcgo/linux_386.c
+++ b/src/pkg/runtime/cgo/linux_amd64.c
@@ -5,13 +5,15 @@
#include <pthread.h>
#include "libcgo.h"
-static void *threadentry(void*);
+static void* threadentry(void*);
void
-initcgo(void)
+xinitcgo(void)
{
}
+void (*initcgo)(void) = xinitcgo;
+
void
libcgo_sys_thread_start(ThreadStart *ts)
{
@@ -43,15 +45,14 @@ threadentry(void *v)
/*
* Set specific keys. On Linux/ELF, the thread local storage
- * is just before %gs:0. Our dynamic 8.out's reserve 8 bytes
- * for the two words g and m at %gs:-8 and %gs:-4.
+ * is just before %fs:0. Our dynamic 6.out's reserve 16 bytes
+ * for the two words g and m at %fs:-16 and %fs:-8.
*/
asm volatile (
- "movl %0, %%gs:-8\n" // MOVL g, -8(GS)
- "movl %1, %%gs:-4\n" // MOVL m, -4(GS)
+ "movq %0, %%fs:-16\n" // MOVL g, -16(FS)
+ "movq %1, %%fs:-8\n" // MOVL m, -8(FS)
:: "r"(ts.g), "r"(ts.m)
);
-
- crosscall_386(ts.fn);
+ crosscall_amd64(ts.fn);
return nil;
}
diff --git a/src/pkg/runtime/cgo/linux_arm.c b/src/pkg/runtime/cgo/linux_arm.c
new file mode 100644
index 000000000..e556c433c
--- /dev/null
+++ b/src/pkg/runtime/cgo/linux_arm.c
@@ -0,0 +1,19 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "libcgo.h"
+
+static void
+xinitcgo(void)
+{
+}
+
+void (*initcgo)(void) = xinitcgo;
+
+void
+libcgo_sys_thread_start(ThreadStart *ts)
+{
+ // unimplemented
+ *(int*)0 = 0;
+}
diff --git a/src/pkg/runtime/cgo/nacl_386.c b/src/pkg/runtime/cgo/nacl_386.c
new file mode 100644
index 000000000..e556c433c
--- /dev/null
+++ b/src/pkg/runtime/cgo/nacl_386.c
@@ -0,0 +1,19 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "libcgo.h"
+
+static void
+xinitcgo(void)
+{
+}
+
+void (*initcgo)(void) = xinitcgo;
+
+void
+libcgo_sys_thread_start(ThreadStart *ts)
+{
+ // unimplemented
+ *(int*)0 = 0;
+}
diff --git a/src/libcgo/util.c b/src/pkg/runtime/cgo/util.c
index c296b493d..0eff19aa6 100644
--- a/src/libcgo/util.c
+++ b/src/pkg/runtime/cgo/util.c
@@ -5,8 +5,8 @@
#include "libcgo.h"
/* Stub for calling malloc from Go */
-void
-_cgo_malloc(void *p)
+static void
+x_cgo_malloc(void *p)
{
struct a {
long long n;
@@ -16,9 +16,11 @@ _cgo_malloc(void *p)
a->ret = malloc(a->n);
}
+void (*_cgo_malloc)(void*) = x_cgo_malloc;
+
/* Stub for calling from Go */
-void
-_cgo_free(void *p)
+static void
+x_cgo_free(void *p)
{
struct a {
void *arg;
@@ -27,9 +29,11 @@ _cgo_free(void *p)
free(a->arg);
}
+void (*_cgo_free)(void*) = x_cgo_free;
+
/* Stub for creating a new thread */
-void
-libcgo_thread_start(ThreadStart *arg)
+static void
+xlibcgo_thread_start(ThreadStart *arg)
{
ThreadStart *ts;
@@ -44,3 +48,4 @@ libcgo_thread_start(ThreadStart *arg)
libcgo_sys_thread_start(ts); /* OS-dependent half */
}
+void (*libcgo_thread_start)(ThreadStart*) = xlibcgo_thread_start;
diff --git a/src/pkg/runtime/cgo/windows_386.c b/src/pkg/runtime/cgo/windows_386.c
new file mode 100755
index 000000000..5f5235bd2
--- /dev/null
+++ b/src/pkg/runtime/cgo/windows_386.c
@@ -0,0 +1,57 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include "libcgo.h"
+
+static void *threadentry(void*);
+
+/* From what I've read 1MB is default for 32-bit Linux.
+ Allocation granularity on Windows is typically 64 KB. */
+#define STACKSIZE (1*1024*1024)
+
+static void
+xinitcgo(void)
+{
+}
+
+void (*initcgo)(void) = xinitcgo;
+
+void
+libcgo_sys_thread_start(ThreadStart *ts)
+{
+ ts->g->stackguard = STACKSIZE;
+ _beginthread(threadentry, STACKSIZE, ts);
+}
+
+static void*
+threadentry(void *v)
+{
+ ThreadStart ts;
+
+ ts = *(ThreadStart*)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;
+
+ /*
+ * Set specific keys in thread local storage.
+ */
+ asm volatile (
+ "MOVL %%fs:0x2c, %%eax\n" // MOVL 0x24(FS), tmp
+ "movl %0, 0(%%eax)\n" // MOVL g, 0(FS)
+ "movl %1, 4(%%eax)\n" // MOVL m, 4(FS)
+ :: "r"(ts.g), "r"(ts.m) : "%eax"
+ );
+
+ crosscall_386(ts.fn);
+ return nil;
+}
diff --git a/src/libcgo/windows_amd64.c b/src/pkg/runtime/cgo/windows_amd64.c
index 56417e178..dafe8cd9d 100755
--- a/src/libcgo/windows_amd64.c
+++ b/src/pkg/runtime/cgo/windows_amd64.c
@@ -12,34 +12,36 @@ static void *threadentry(void*);
Allocation granularity on Windows is typically 64 KB. */
#define STACKSIZE (2*1024*1024)
-void
-initcgo(void)
+static void
+xinitcgo(void)
{
}
+void (*initcgo)(void) = xinitcgo;
+
void
libcgo_sys_thread_start(ThreadStart *ts)
{
- ts->g->stackguard = STACKSIZE;
- _beginthread(threadentry, STACKSIZE, ts);
+ ts->g->stackguard = STACKSIZE;
+ _beginthread(threadentry, STACKSIZE, ts);
}
static void*
threadentry(void *v)
{
- ThreadStart ts;
+ ThreadStart ts;
- ts = *(ThreadStart*)v;
- free(v);
+ ts = *(ThreadStart*)v;
+ free(v);
- ts.g->stackbase = (uintptr)&ts;
+ 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;
+ /*
+ * libcgo_sys_thread_start set stackguard to stack size;
+ * change to actual guard pointer.
+ */
+ ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096;
- crosscall_386(ts.fn);
- return nil;
+ crosscall_386(ts.fn);
+ return nil;
}
diff --git a/src/pkg/runtime/cgocall.c b/src/pkg/runtime/cgocall.c
index f673d1b6e..80ae97e7a 100644
--- a/src/pkg/runtime/cgocall.c
+++ b/src/pkg/runtime/cgocall.c
@@ -7,16 +7,19 @@
void *initcgo; /* filled in by dynamic linker when Cgo is available */
int64 ncgocall;
-void ·entersyscall(void);
-void ·exitsyscall(void);
+void runtime·entersyscall(void);
+void runtime·exitsyscall(void);
void
-cgocall(void (*fn)(void*), void *arg)
+runtime·cgocall(void (*fn)(void*), void *arg)
{
G *oldlock;
- if(initcgo == nil)
- throw("cgocall unavailable");
+ if(!runtime·iscgo)
+ runtime·throw("cgocall unavailable");
+
+ if(fn == 0)
+ runtime·throw("cgocall nil");
ncgocall++;
@@ -34,9 +37,9 @@ cgocall(void (*fn)(void*), void *arg)
* M to run goroutines while we are in the
* foreign code.
*/
- ·entersyscall();
- runcgo(fn, arg);
- ·exitsyscall();
+ runtime·entersyscall();
+ runtime·runcgo(fn, arg);
+ runtime·exitsyscall();
m->lockedg = oldlock;
if(oldlock == nil)
@@ -51,37 +54,38 @@ cgocall(void (*fn)(void*), void *arg)
// arguments back where they came from, and finally returns to the old
// stack.
void
-cgocallback(void (*fn)(void), void *arg, int32 argsize)
+runtime·cgocallback(void (*fn)(void), void *arg, int32 argsize)
{
- Gobuf oldsched;
+ Gobuf oldsched, oldg1sched;
G *g1;
void *sp;
if(g != m->g0)
- throw("bad g in cgocallback");
-
- oldsched = m->sched;
+ runtime·throw("bad g in cgocallback");
g1 = m->curg;
+ oldsched = m->sched;
+ oldg1sched = g1->sched;
- startcgocallback(g1);
+ runtime·startcgocallback(g1);
sp = g1->sched.sp - argsize;
if(sp < g1->stackguard)
- throw("g stack overflow in cgocallback");
- mcpy(sp, arg, argsize);
+ runtime·throw("g stack overflow in cgocallback");
+ runtime·mcpy(sp, arg, argsize);
- runcgocallback(g1, sp, fn);
+ runtime·runcgocallback(g1, sp, fn);
- mcpy(arg, sp, argsize);
+ runtime·mcpy(arg, sp, argsize);
- endcgocallback(g1);
+ runtime·endcgocallback(g1);
m->sched = oldsched;
+ g1->sched = oldg1sched;
}
void
-·Cgocalls(int64 ret)
+runtime·Cgocalls(int64 ret)
{
ret = ncgocall;
FLUSH(&ret);
@@ -91,22 +95,22 @@ void (*_cgo_malloc)(void*);
void (*_cgo_free)(void*);
void*
-cmalloc(uintptr n)
+runtime·cmalloc(uintptr n)
{
- struct a {
+ struct {
uint64 n;
void *ret;
} a;
a.n = n;
a.ret = nil;
- cgocall(_cgo_malloc, &a);
+ runtime·cgocall(_cgo_malloc, &a);
return a.ret;
}
void
-cfree(void *p)
+runtime·cfree(void *p)
{
- cgocall(_cgo_free, p);
+ runtime·cgocall(_cgo_free, p);
}
diff --git a/src/pkg/runtime/cgocall.h b/src/pkg/runtime/cgocall.h
index 9cdb409a3..1ad954eb1 100644
--- a/src/pkg/runtime/cgocall.h
+++ b/src/pkg/runtime/cgocall.h
@@ -6,7 +6,7 @@
* Cgo interface.
*/
-void cgocall(void (*fn)(void*), void*);
-void cgocallback(void (*fn)(void), void*, int32);
-void *cmalloc(uintptr);
-void cfree(void*);
+void runtime·cgocall(void (*fn)(void*), void*);
+void runtime·cgocallback(void (*fn)(void), void*, int32);
+void *runtime·cmalloc(uintptr);
+void runtime·cfree(void*);
diff --git a/src/pkg/runtime/chan.c b/src/pkg/runtime/chan.c
index 08cd75a6e..94ea513e7 100644
--- a/src/pkg/runtime/chan.c
+++ b/src/pkg/runtime/chan.c
@@ -90,24 +90,24 @@ static uint32 fastrand2(void);
static void destroychan(Hchan*);
Hchan*
-makechan(Type *elem, int64 hint)
+runtime·makechan_c(Type *elem, int64 hint)
{
Hchan *c;
int32 i;
if(hint < 0 || (int32)hint != hint || hint > ((uintptr)-1) / elem->size)
- panicstring("makechan: size out of range");
+ runtime·panicstring("makechan: size out of range");
- if(elem->alg >= nelem(algarray)) {
- printf("chan(alg=%d)\n", elem->alg);
- throw("runtime.makechan: unsupported elem type");
+ if(elem->alg >= nelem(runtime·algarray)) {
+ runtime·printf("chan(alg=%d)\n", elem->alg);
+ runtime·throw("runtime.makechan: unsupported elem type");
}
- c = mal(sizeof(*c));
- addfinalizer(c, destroychan, 0);
+ c = runtime·mal(sizeof(*c));
+ runtime·addfinalizer(c, destroychan, 0);
c->elemsize = elem->size;
- c->elemalg = &algarray[elem->alg];
+ c->elemalg = &runtime·algarray[elem->alg];
c->elemalign = elem->align;
if(hint > 0) {
@@ -117,7 +117,7 @@ makechan(Type *elem, int64 hint)
b = nil;
e = nil;
for(i=0; i<hint; i++) {
- d = mal(sizeof(*d) + c->elemsize - sizeof(d->elem));
+ d = runtime·mal(sizeof(*d) + c->elemsize - sizeof(d->elem));
if(e == nil)
e = d;
d->link = b;
@@ -131,7 +131,7 @@ makechan(Type *elem, int64 hint)
}
if(debug)
- printf("makechan: chan=%p; elemsize=%D; elemalg=%d; elemalign=%d; dataqsiz=%d\n",
+ runtime·printf("makechan: chan=%p; elemsize=%D; elemalg=%d; elemalign=%d; dataqsiz=%d\n",
c, (int64)elem->size, elem->alg, elem->align, c->dataqsiz);
return c;
@@ -140,15 +140,15 @@ makechan(Type *elem, int64 hint)
static void
destroychan(Hchan *c)
{
- destroylock(&c->Lock);
+ runtime·destroylock(&c->Lock);
}
// makechan(elem *Type, hint int64) (hchan *chan any);
void
-·makechan(Type *elem, int64 hint, Hchan *ret)
+runtime·makechan(Type *elem, int64 hint, Hchan *ret)
{
- ret = makechan(elem, hint);
+ ret = runtime·makechan_c(elem, hint);
FLUSH(&ret);
}
@@ -158,7 +158,7 @@ incerr(Hchan* c)
c->closed += Eincr;
if(c->closed & Emax) {
// Note that channel locks may still be held at this point.
- throw("too many operations on a closed channel");
+ runtime·throw("too many operations on a closed channel");
}
}
@@ -177,21 +177,24 @@ incerr(Hchan* c)
* the operation; we'll see that it's now closed.
*/
void
-chansend(Hchan *c, byte *ep, bool *pres)
+runtime·chansend(Hchan *c, byte *ep, bool *pres)
{
SudoG *sg;
G* gp;
- if(gcwaiting)
- gosched();
+ if(c == nil)
+ runtime·panicstring("send to nil channel");
+
+ if(runtime·gcwaiting)
+ runtime·gosched();
if(debug) {
- printf("chansend: chan=%p; elem=", c);
+ runtime·printf("chansend: chan=%p; elem=", c);
c->elemalg->print(c->elemsize, ep);
- prints("\n");
+ runtime·prints("\n");
}
- lock(c);
+ runtime·lock(c);
loop:
if(c->closed & Wclosed)
goto closed;
@@ -206,8 +209,8 @@ loop:
gp = sg->g;
gp->param = sg;
- unlock(c);
- ready(gp);
+ runtime·unlock(c);
+ runtime·ready(gp);
if(pres != nil)
*pres = true;
@@ -215,7 +218,7 @@ loop:
}
if(pres != nil) {
- unlock(c);
+ runtime·unlock(c);
*pres = false;
return;
}
@@ -226,15 +229,15 @@ loop:
g->param = nil;
g->status = Gwaiting;
enqueue(&c->sendq, sg);
- unlock(c);
- gosched();
+ runtime·unlock(c);
+ runtime·gosched();
- lock(c);
+ runtime·lock(c);
sg = g->param;
if(sg == nil)
goto loop;
freesg(c, sg);
- unlock(c);
+ runtime·unlock(c);
return;
asynch:
@@ -243,17 +246,17 @@ asynch:
if(c->qcount >= c->dataqsiz) {
if(pres != nil) {
- unlock(c);
+ runtime·unlock(c);
*pres = false;
return;
}
sg = allocsg(c);
g->status = Gwaiting;
enqueue(&c->sendq, sg);
- unlock(c);
- gosched();
+ runtime·unlock(c);
+ runtime·gosched();
- lock(c);
+ runtime·lock(c);
goto asynch;
}
if(ep != nil)
@@ -265,10 +268,10 @@ asynch:
if(sg != nil) {
gp = sg->g;
freesg(c, sg);
- unlock(c);
- ready(gp);
+ runtime·unlock(c);
+ runtime·ready(gp);
} else
- unlock(c);
+ runtime·unlock(c);
if(pres != nil)
*pres = true;
return;
@@ -277,22 +280,25 @@ closed:
incerr(c);
if(pres != nil)
*pres = true;
- unlock(c);
+ runtime·unlock(c);
}
void
-chanrecv(Hchan* c, byte *ep, bool* pres)
+runtime·chanrecv(Hchan* c, byte *ep, bool* pres)
{
SudoG *sg;
G *gp;
- if(gcwaiting)
- gosched();
+ if(c == nil)
+ runtime·panicstring("receive from nil channel");
+
+ if(runtime·gcwaiting)
+ runtime·gosched();
if(debug)
- printf("chanrecv: chan=%p\n", c);
+ runtime·printf("chanrecv: chan=%p\n", c);
- lock(c);
+ runtime·lock(c);
loop:
if(c->dataqsiz > 0)
goto asynch;
@@ -307,8 +313,8 @@ loop:
gp = sg->g;
gp->param = sg;
- unlock(c);
- ready(gp);
+ runtime·unlock(c);
+ runtime·ready(gp);
if(pres != nil)
*pres = true;
@@ -316,7 +322,7 @@ loop:
}
if(pres != nil) {
- unlock(c);
+ runtime·unlock(c);
c->elemalg->copy(c->elemsize, ep, nil);
*pres = false;
return;
@@ -326,10 +332,10 @@ loop:
g->param = nil;
g->status = Gwaiting;
enqueue(&c->recvq, sg);
- unlock(c);
- gosched();
+ runtime·unlock(c);
+ runtime·gosched();
- lock(c);
+ runtime·lock(c);
sg = g->param;
if(sg == nil)
goto loop;
@@ -337,7 +343,7 @@ loop:
c->elemalg->copy(c->elemsize, ep, sg->elem);
c->elemalg->copy(c->elemsize, sg->elem, nil);
freesg(c, sg);
- unlock(c);
+ runtime·unlock(c);
return;
asynch:
@@ -346,7 +352,7 @@ asynch:
goto closed;
if(pres != nil) {
- unlock(c);
+ runtime·unlock(c);
c->elemalg->copy(c->elemsize, ep, nil);
*pres = false;
return;
@@ -354,10 +360,10 @@ asynch:
sg = allocsg(c);
g->status = Gwaiting;
enqueue(&c->recvq, sg);
- unlock(c);
- gosched();
+ runtime·unlock(c);
+ runtime·gosched();
- lock(c);
+ runtime·lock(c);
goto asynch;
}
c->elemalg->copy(c->elemsize, ep, c->recvdataq->elem);
@@ -368,14 +374,14 @@ asynch:
if(sg != nil) {
gp = sg->g;
freesg(c, sg);
- unlock(c);
- ready(gp);
+ runtime·unlock(c);
+ runtime·ready(gp);
if(pres != nil)
*pres = true;
return;
}
- unlock(c);
+ runtime·unlock(c);
if(pres != nil)
*pres = true;
return;
@@ -386,96 +392,102 @@ closed:
incerr(c);
if(pres != nil)
*pres = true;
- unlock(c);
+ runtime·unlock(c);
}
// chansend1(hchan *chan any, elem any);
#pragma textflag 7
void
-·chansend1(Hchan* c, ...)
+runtime·chansend1(Hchan* c, ...)
{
int32 o;
byte *ae;
- o = rnd(sizeof(c), c->elemalign);
+ if(c == nil)
+ runtime·panicstring("send to nil channel");
+
+ o = runtime·rnd(sizeof(c), c->elemalign);
ae = (byte*)&c + o;
- chansend(c, ae, nil);
+ runtime·chansend(c, ae, nil);
}
// chansend2(hchan *chan any, elem any) (pres bool);
#pragma textflag 7
void
-·chansend2(Hchan* c, ...)
+runtime·chansend2(Hchan* c, ...)
{
int32 o;
byte *ae, *ap;
- o = rnd(sizeof(c), c->elemalign);
+ if(c == nil)
+ runtime·panicstring("send to nil channel");
+
+ o = runtime·rnd(sizeof(c), c->elemalign);
ae = (byte*)&c + o;
- o = rnd(o+c->elemsize, Structrnd);
+ o = runtime·rnd(o+c->elemsize, Structrnd);
ap = (byte*)&c + o;
- chansend(c, ae, ap);
+ runtime·chansend(c, ae, ap);
}
// chanrecv1(hchan *chan any) (elem any);
#pragma textflag 7
void
-·chanrecv1(Hchan* c, ...)
+runtime·chanrecv1(Hchan* c, ...)
{
int32 o;
byte *ae;
- o = rnd(sizeof(c), Structrnd);
+ o = runtime·rnd(sizeof(c), Structrnd);
ae = (byte*)&c + o;
- chanrecv(c, ae, nil);
+ runtime·chanrecv(c, ae, nil);
}
// chanrecv2(hchan *chan any) (elem any, pres bool);
#pragma textflag 7
void
-·chanrecv2(Hchan* c, ...)
+runtime·chanrecv2(Hchan* c, ...)
{
int32 o;
byte *ae, *ap;
- o = rnd(sizeof(c), Structrnd);
+ o = runtime·rnd(sizeof(c), Structrnd);
ae = (byte*)&c + o;
- o = rnd(o+c->elemsize, 1);
+ o = runtime·rnd(o+c->elemsize, 1);
ap = (byte*)&c + o;
- chanrecv(c, ae, ap);
+ runtime·chanrecv(c, ae, ap);
}
// newselect(size uint32) (sel *byte);
#pragma textflag 7
void
-·newselect(int32 size, ...)
+runtime·newselect(int32 size, ...)
{
int32 n, o;
Select **selp;
Select *sel;
- o = rnd(sizeof(size), Structrnd);
+ o = runtime·rnd(sizeof(size), Structrnd);
selp = (Select**)((byte*)&size + o);
n = 0;
if(size > 1)
n = size-1;
- sel = mal(sizeof(*sel) + n*sizeof(sel->scase[0]));
+ sel = runtime·mal(sizeof(*sel) + n*sizeof(sel->scase[0]));
sel->tcase = size;
sel->ncase = 0;
*selp = sel;
if(debug)
- printf("newselect s=%p size=%d\n", sel, size);
+ runtime·printf("newselect s=%p size=%d\n", sel, size);
}
// selectsend(sel *byte, hchan *chan any, elem any) (selected bool);
#pragma textflag 7
void
-·selectsend(Select *sel, Hchan *c, ...)
+runtime·selectsend(Select *sel, Hchan *c, ...)
{
int32 i, eo;
Scase *cas;
@@ -487,31 +499,31 @@ void
i = sel->ncase;
if(i >= sel->tcase)
- throw("selectsend: too many cases");
+ runtime·throw("selectsend: too many cases");
sel->ncase = i+1;
- cas = mal(sizeof *cas + c->elemsize - sizeof(cas->u.elem));
+ cas = runtime·mal(sizeof *cas + c->elemsize - sizeof(cas->u.elem));
sel->scase[i] = cas;
- cas->pc = ·getcallerpc(&sel);
+ cas->pc = runtime·getcallerpc(&sel);
cas->chan = c;
- eo = rnd(sizeof(sel), sizeof(c));
- eo = rnd(eo+sizeof(c), c->elemsize);
- cas->so = rnd(eo+c->elemsize, Structrnd);
+ eo = runtime·rnd(sizeof(sel), sizeof(c));
+ eo = runtime·rnd(eo+sizeof(c), c->elemsize);
+ cas->so = runtime·rnd(eo+c->elemsize, Structrnd);
cas->send = 1;
ae = (byte*)&sel + eo;
c->elemalg->copy(c->elemsize, cas->u.elem, ae);
if(debug)
- printf("selectsend s=%p pc=%p chan=%p so=%d send=%d\n",
+ runtime·printf("selectsend s=%p pc=%p chan=%p so=%d send=%d\n",
sel, cas->pc, cas->chan, cas->so, cas->send);
}
// selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool);
#pragma textflag 7
void
-·selectrecv(Select *sel, Hchan *c, ...)
+runtime·selectrecv(Select *sel, Hchan *c, ...)
{
int32 i, eo;
Scase *cas;
@@ -522,21 +534,21 @@ void
i = sel->ncase;
if(i >= sel->tcase)
- throw("selectrecv: too many cases");
+ runtime·throw("selectrecv: too many cases");
sel->ncase = i+1;
- cas = mal(sizeof *cas);
+ cas = runtime·mal(sizeof *cas);
sel->scase[i] = cas;
- cas->pc = ·getcallerpc(&sel);
+ cas->pc = runtime·getcallerpc(&sel);
cas->chan = c;
- eo = rnd(sizeof(sel), sizeof(c));
- eo = rnd(eo+sizeof(c), sizeof(byte*));
- cas->so = rnd(eo+sizeof(byte*), Structrnd);
+ eo = runtime·rnd(sizeof(sel), sizeof(c));
+ eo = runtime·rnd(eo+sizeof(c), sizeof(byte*));
+ cas->so = runtime·rnd(eo+sizeof(byte*), Structrnd);
cas->send = 0;
cas->u.elemp = *(byte**)((byte*)&sel + eo);
if(debug)
- printf("selectrecv s=%p pc=%p chan=%p so=%d send=%d\n",
+ runtime·printf("selectrecv s=%p pc=%p chan=%p so=%d send=%d\n",
sel, cas->pc, cas->chan, cas->so, cas->send);
}
@@ -544,26 +556,26 @@ void
// selectdefaul(sel *byte) (selected bool);
#pragma textflag 7
void
-·selectdefault(Select *sel, ...)
+runtime·selectdefault(Select *sel, ...)
{
int32 i;
Scase *cas;
i = sel->ncase;
if(i >= sel->tcase)
- throw("selectdefault: too many cases");
+ runtime·throw("selectdefault: too many cases");
sel->ncase = i+1;
- cas = mal(sizeof *cas);
+ cas = runtime·mal(sizeof *cas);
sel->scase[i] = cas;
- cas->pc = ·getcallerpc(&sel);
+ cas->pc = runtime·getcallerpc(&sel);
cas->chan = nil;
- cas->so = rnd(sizeof(sel), Structrnd);
+ cas->so = runtime·rnd(sizeof(sel), Structrnd);
cas->send = 2;
cas->u.elemp = nil;
if(debug)
- printf("selectdefault s=%p pc=%p so=%d send=%d\n",
+ runtime·printf("selectdefault s=%p pc=%p so=%d send=%d\n",
sel, cas->pc, cas->so, cas->send);
}
@@ -573,8 +585,8 @@ freesel(Select *sel)
uint32 i;
for(i=0; i<sel->ncase; i++)
- free(sel->scase[i]);
- free(sel);
+ runtime·free(sel->scase[i]);
+ runtime·free(sel);
}
static void
@@ -587,7 +599,7 @@ sellock(Select *sel)
for(i=0; i<sel->ncase; i++) {
if(sel->scase[i]->chan != c) {
c = sel->scase[i]->chan;
- lock(c);
+ runtime·lock(c);
}
}
}
@@ -602,14 +614,20 @@ selunlock(Select *sel)
for(i=sel->ncase; i>0; i--) {
if(sel->scase[i-1]->chan && sel->scase[i-1]->chan != c) {
c = sel->scase[i-1]->chan;
- unlock(c);
+ runtime·unlock(c);
}
}
}
// selectgo(sel *byte);
+//
+// overwrites return pc on stack to signal which case of the select
+// to run, so cannot appear at the top of a split stack.
+// frame has 6 pointers and 4 int32 so 64 bytes max.
+// that's less than StackGuard-StackSmall, so okay.
+#pragma textflag 7
void
-·selectgo(Select *sel)
+runtime·selectgo(Select *sel)
{
uint32 p, o, i, j;
Scase *cas, *dfl;
@@ -618,16 +636,18 @@ void
G *gp;
byte *as;
- if(gcwaiting)
- gosched();
+ if(runtime·gcwaiting)
+ runtime·gosched();
if(debug)
- printf("select: sel=%p\n", sel);
+ runtime·printf("select: sel=%p\n", sel);
if(sel->ncase < 2) {
- if(sel->ncase < 1)
- throw("select: no cases");
- // make special case of one.
+ if(sel->ncase < 1) {
+ g->status = Gwaiting; // forever
+ runtime·gosched();
+ }
+ // TODO: make special case of one.
}
// select a (relative) prime
@@ -636,7 +656,7 @@ void
if(gcd(p, sel->ncase) == 1)
break;
if(i > 1000)
- throw("select: failed to select prime");
+ runtime·throw("select: failed to select prime");
}
// select an initial offset
@@ -716,10 +736,10 @@ loop:
case 0: // recv
if(c->dataqsiz > 0) {
if(c->qcount > 0)
- throw("select: pass 2 async recv");
+ runtime·throw("select: pass 2 async recv");
} else {
if(dequeue(&c->sendq, c))
- throw("select: pass 2 sync recv");
+ runtime·throw("select: pass 2 sync recv");
}
enqueue(&c->recvq, sg);
break;
@@ -727,10 +747,10 @@ loop:
case 1: // send
if(c->dataqsiz > 0) {
if(c->qcount < c->dataqsiz)
- throw("select: pass 2 async send");
+ runtime·throw("select: pass 2 async send");
} else {
if(dequeue(&c->recvq, c))
- throw("select: pass 2 sync send");
+ runtime·throw("select: pass 2 sync send");
c->elemalg->copy(c->elemsize, sg->elem, cas->u.elem);
}
enqueue(&c->sendq, sg);
@@ -745,7 +765,7 @@ loop:
g->param = nil;
g->status = Gwaiting;
selunlock(sel);
- gosched();
+ runtime·gosched();
sellock(sel);
sg = g->param;
@@ -780,7 +800,7 @@ loop:
}
if(debug)
- printf("wait-return: sel=%p c=%p cas=%p send=%d o=%d\n",
+ runtime·printf("wait-return: sel=%p c=%p cas=%p send=%d o=%d\n",
sel, c, cas, cas->send, o);
if(!cas->send) {
@@ -803,7 +823,7 @@ asyncrecv:
if(sg != nil) {
gp = sg->g;
freesg(c, sg);
- ready(gp);
+ runtime·ready(gp);
}
goto retc;
@@ -817,20 +837,20 @@ asyncsend:
if(sg != nil) {
gp = sg->g;
freesg(c, sg);
- ready(gp);
+ runtime·ready(gp);
}
goto retc;
syncrecv:
// can receive from sleeping sender (sg)
if(debug)
- printf("syncrecv: sel=%p c=%p o=%d\n", sel, c, o);
+ runtime·printf("syncrecv: sel=%p c=%p o=%d\n", sel, c, o);
if(cas->u.elemp != nil)
c->elemalg->copy(c->elemsize, cas->u.elemp, sg->elem);
c->elemalg->copy(c->elemsize, sg->elem, nil);
gp = sg->g;
gp->param = sg;
- ready(gp);
+ runtime·ready(gp);
goto retc;
rclose:
@@ -844,13 +864,13 @@ rclose:
syncsend:
// can send to sleeping receiver (sg)
if(debug)
- printf("syncsend: sel=%p c=%p o=%d\n", sel, c, o);
+ runtime·printf("syncsend: sel=%p c=%p o=%d\n", sel, c, o);
if(c->closed & Wclosed)
goto sclose;
c->elemalg->copy(c->elemsize, sg->elem, cas->u.elem);
gp = sg->g;
gp->param = sg;
- ready(gp);
+ runtime·ready(gp);
goto retc;
sclose:
@@ -862,7 +882,7 @@ retc:
selunlock(sel);
// return to pc corresponding to chosen case
- ·setcallerpc(&sel, cas->pc);
+ runtime·setcallerpc(&sel, cas->pc);
as = (byte*)&sel + cas->so;
freesel(sel);
*as = true;
@@ -870,15 +890,15 @@ retc:
// closechan(sel *byte);
void
-·closechan(Hchan *c)
+runtime·closechan(Hchan *c)
{
SudoG *sg;
G* gp;
- if(gcwaiting)
- gosched();
+ if(runtime·gcwaiting)
+ runtime·gosched();
- lock(c);
+ runtime·lock(c);
incerr(c);
c->closed |= Wclosed;
@@ -890,7 +910,7 @@ void
gp = sg->g;
gp->param = nil;
freesg(c, sg);
- ready(gp);
+ runtime·ready(gp);
}
// release all writers
@@ -901,32 +921,32 @@ void
gp = sg->g;
gp->param = nil;
freesg(c, sg);
- ready(gp);
+ runtime·ready(gp);
}
- unlock(c);
+ runtime·unlock(c);
}
void
-chanclose(Hchan *c)
+runtime·chanclose(Hchan *c)
{
- ·closechan(c);
+ runtime·closechan(c);
}
bool
-chanclosed(Hchan *c)
+runtime·chanclosed(Hchan *c)
{
return (c->closed & Rclosed) != 0;
}
int32
-chanlen(Hchan *c)
+runtime·chanlen(Hchan *c)
{
return c->qcount;
}
int32
-chancap(Hchan *c)
+runtime·chancap(Hchan *c)
{
return c->dataqsiz;
}
@@ -934,9 +954,9 @@ chancap(Hchan *c)
// closedchan(sel *byte) bool;
void
-·closedchan(Hchan *c, bool closed)
+runtime·closedchan(Hchan *c, bool closed)
{
- closed = chanclosed(c);
+ closed = runtime·chanclosed(c);
FLUSH(&closed);
}
@@ -952,7 +972,7 @@ loop:
q->first = sgp->link;
// if sgp is stale, ignore it
- if(!cas(&sgp->g->selgen, sgp->selgen, sgp->selgen + 1)) {
+ if(!runtime·cas(&sgp->g->selgen, sgp->selgen, sgp->selgen + 1)) {
//prints("INVALID PSEUDOG POINTER\n");
freesg(c, sgp);
goto loop;
@@ -997,7 +1017,7 @@ allocsg(Hchan *c)
if(sg != nil) {
c->free = sg->link;
} else
- sg = mal(sizeof(*sg) + c->elemsize - sizeof(sg->elem));
+ sg = runtime·mal(sizeof(*sg) + c->elemsize - sizeof(sg->elem));
sg->selgen = g->selgen;
sg->g = g;
sg->offset = 0;
@@ -1011,7 +1031,7 @@ freesg(Hchan *c, SudoG *sg)
{
if(sg != nil) {
if(sg->isfree)
- throw("chan.freesg: already free");
+ runtime·throw("chan.freesg: already free");
sg->isfree = 1;
sg->link = c->free;
c->free = sg;
diff --git a/src/pkg/runtime/chan_defs.go b/src/pkg/runtime/chan_defs.go
new file mode 100644
index 000000000..5cfea6e15
--- /dev/null
+++ b/src/pkg/runtime/chan_defs.go
@@ -0,0 +1,56 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Go definitions of internal structures. Master is chan.c
+
+package runtime
+
+type sudoG struct {
+ g *g_
+ selgen uint32
+ offset int16
+ isfree int8
+ link *sudoG
+ elem [8]byte
+}
+
+type waitQ struct {
+ first *sudoG
+ last *sudoG
+}
+
+type hChan struct {
+ qcount uint32
+ dataqsiz uint32
+ elemsize uint16
+ closed uint16
+ elemalign uint8
+ elemalg *alg
+ senddataq *link
+ recvdataq *link
+ recvq waitQ
+ sendq waitQ
+ free sudoG
+ lock
+}
+
+type link struct {
+ link *link
+ elem [8]byte
+}
+
+type scase struct {
+ chan_ *hChan
+ pc *byte
+ send uint16
+ so uint16
+ elemp *byte // union elem [8]byte
+}
+
+type select_ struct {
+ tcase uint16
+ ncase uint16
+ link *select_
+ scase [1]*scase
+}
diff --git a/src/pkg/runtime/complex.c b/src/pkg/runtime/complex.c
index 2240d9fb8..eeb943940 100644
--- a/src/pkg/runtime/complex.c
+++ b/src/pkg/runtime/complex.c
@@ -7,34 +7,34 @@
typedef struct Complex128 Complex128;
void
-·complex128div(Complex128 n, Complex128 d, Complex128 q)
+runtime·complex128div(Complex128 n, Complex128 d, Complex128 q)
{
int32 ninf, dinf, nnan, dnan;
float64 a, b, ratio, denom;
// Special cases as in C99.
- ninf = isInf(n.real, 0) || isInf(n.imag, 0);
- dinf = isInf(d.real, 0) || isInf(d.imag, 0);
+ ninf = runtime·isInf(n.real, 0) || runtime·isInf(n.imag, 0);
+ dinf = runtime·isInf(d.real, 0) || runtime·isInf(d.imag, 0);
- nnan = !ninf && (isNaN(n.real) || isNaN(n.imag));
- dnan = !dinf && (isNaN(d.real) || isNaN(d.imag));
+ nnan = !ninf && (runtime·isNaN(n.real) || runtime·isNaN(n.imag));
+ dnan = !dinf && (runtime·isNaN(d.real) || runtime·isNaN(d.imag));
if(nnan || dnan) {
- q.real = NaN();
- q.imag = NaN();
+ q.real = runtime·NaN();
+ q.imag = runtime·NaN();
} else if(ninf && !dinf && !dnan) {
- q.real = Inf(0);
- q.imag = Inf(0);
+ q.real = runtime·Inf(0);
+ q.imag = runtime·Inf(0);
} else if(!ninf && !nnan && dinf) {
q.real = 0;
q.imag = 0;
} else if(d.real == 0 && d.imag == 0) {
if(n.real == 0 && n.imag == 0) {
- q.real = NaN();
- q.imag = NaN();
+ q.real = runtime·NaN();
+ q.imag = runtime·NaN();
} else {
- q.real = Inf(0);
- q.imag = Inf(0);
+ q.real = runtime·Inf(0);
+ q.imag = runtime·Inf(0);
}
} else {
// Standard complex arithmetic, factored to avoid unnecessary overflow.
diff --git a/src/pkg/runtime/darwin/386/defs.h b/src/pkg/runtime/darwin/386/defs.h
index 371f650a8..f9d874d85 100644
--- a/src/pkg/runtime/darwin/386/defs.h
+++ b/src/pkg/runtime/darwin/386/defs.h
@@ -10,6 +10,7 @@ enum {
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,
diff --git a/src/pkg/runtime/darwin/386/rt0.s b/src/pkg/runtime/darwin/386/rt0.s
index 5b52e912c..30b497f5e 100644
--- a/src/pkg/runtime/darwin/386/rt0.s
+++ b/src/pkg/runtime/darwin/386/rt0.s
@@ -4,5 +4,5 @@
// Darwin and Linux use the same linkage to main
-TEXT _rt0_386_darwin(SB),7,$0
+TEXT _rt0_386_darwin(SB),7,$0
JMP _rt0_386(SB)
diff --git a/src/pkg/runtime/darwin/386/signal.c b/src/pkg/runtime/darwin/386/signal.c
index f7ee3c448..53a4e2f17 100644
--- a/src/pkg/runtime/darwin/386/signal.c
+++ b/src/pkg/runtime/darwin/386/signal.c
@@ -8,39 +8,38 @@
#include "signals.h"
void
-dumpregs(Regs *r)
+runtime·dumpregs(Regs *r)
{
- printf("eax %x\n", r->eax);
- printf("ebx %x\n", r->ebx);
- printf("ecx %x\n", r->ecx);
- printf("edx %x\n", r->edx);
- printf("edi %x\n", r->edi);
- printf("esi %x\n", r->esi);
- printf("ebp %x\n", r->ebp);
- printf("esp %x\n", r->esp);
- printf("eip %x\n", r->eip);
- printf("eflags %x\n", r->eflags);
- printf("cs %x\n", r->cs);
- printf("fs %x\n", r->fs);
- printf("gs %x\n", r->gs);
+ runtime·printf("eax %x\n", r->eax);
+ runtime·printf("ebx %x\n", r->ebx);
+ runtime·printf("ecx %x\n", r->ecx);
+ runtime·printf("edx %x\n", r->edx);
+ runtime·printf("edi %x\n", r->edi);
+ runtime·printf("esi %x\n", r->esi);
+ runtime·printf("ebp %x\n", r->ebp);
+ runtime·printf("esp %x\n", r->esp);
+ runtime·printf("eip %x\n", r->eip);
+ runtime·printf("eflags %x\n", r->eflags);
+ runtime·printf("cs %x\n", r->cs);
+ runtime·printf("fs %x\n", r->fs);
+ runtime·printf("gs %x\n", r->gs);
}
String
-signame(int32 sig)
+runtime·signame(int32 sig)
{
if(sig < 0 || sig >= NSIG)
- return emptystring;
- return gostringnocopy((byte*)sigtab[sig].name);
+ return runtime·emptystring;
+ return runtime·gostringnocopy((byte*)runtime·sigtab[sig].name);
}
void
-sighandler(int32 sig, Siginfo *info, void *context)
+runtime·sighandler(int32 sig, Siginfo *info, void *context)
{
Ucontext *uc;
Mcontext *mc;
Regs *r;
uintptr *sp;
- void (*fn)(void);
G *gp;
byte *pc;
@@ -48,7 +47,7 @@ sighandler(int32 sig, Siginfo *info, void *context)
mc = uc->uc_mcontext;
r = &mc->ss;
- if((gp = m->curg) != nil && (sigtab[sig].flags & SigPanic)) {
+ if((gp = m->curg) != nil && (runtime·sigtab[sig].flags & SigPanic)) {
// 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).
@@ -68,91 +67,91 @@ sighandler(int32 sig, Siginfo *info, void *context)
gp->sigcode0 = info->si_code;
gp->sigcode1 = (uintptr)info->si_addr;
- // Only push sigpanic if r->eip != 0.
+ // Only push runtime·sigpanic if r->eip != 0.
// If r->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 sigpanic instead.
- // (Otherwise the trace will end at sigpanic and we
+ // 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->eip != 0) {
sp = (uintptr*)r->esp;
*--sp = r->eip;
r->esp = (uintptr)sp;
}
- r->eip = (uintptr)sigpanic;
+ r->eip = (uintptr)runtime·sigpanic;
return;
}
- if(sigtab[sig].flags & SigQueue) {
- if(sigsend(sig) || (sigtab[sig].flags & SigIgnore))
+ if(runtime·sigtab[sig].flags & SigQueue) {
+ if(runtime·sigsend(sig) || (runtime·sigtab[sig].flags & SigIgnore))
return;
- exit(2); // SIGINT, SIGTERM, etc
+ runtime·exit(2); // SIGINT, SIGTERM, etc
}
- if(panicking) // traceback already printed
- exit(2);
- panicking = 1;
+ if(runtime·panicking) // traceback already printed
+ runtime·exit(2);
+ runtime·panicking = 1;
if(sig < 0 || sig >= NSIG){
- printf("Signal %d\n", sig);
+ runtime·printf("Signal %d\n", sig);
}else{
- printf("%s\n", sigtab[sig].name);
+ runtime·printf("%s\n", runtime·sigtab[sig].name);
}
- printf("pc: %x\n", r->eip);
- printf("\n");
+ runtime·printf("pc: %x\n", r->eip);
+ runtime·printf("\n");
- if(gotraceback()){
- traceback((void*)r->eip, (void*)r->esp, 0, m->curg);
- tracebackothers(m->curg);
- dumpregs(r);
+ if(runtime·gotraceback()){
+ runtime·traceback((void*)r->eip, (void*)r->esp, 0, m->curg);
+ runtime·tracebackothers(m->curg);
+ runtime·dumpregs(r);
}
- breakpoint();
- exit(2);
+ runtime·breakpoint();
+ runtime·exit(2);
}
void
-sigignore(int32, Siginfo*, void*)
+runtime·sigignore(int32, Siginfo*, void*)
{
}
void
-signalstack(byte *p, int32 n)
+runtime·signalstack(byte *p, int32 n)
{
StackT st;
st.ss_sp = p;
st.ss_size = n;
st.ss_flags = 0;
- sigaltstack(&st, nil);
+ runtime·sigaltstack(&st, nil);
}
void
-initsig(int32 queue)
+runtime·initsig(int32 queue)
{
int32 i;
static Sigaction sa;
- siginit();
+ runtime·siginit();
sa.sa_flags |= SA_SIGINFO|SA_ONSTACK;
sa.sa_mask = 0xFFFFFFFFU;
- sa.sa_tramp = sigtramp; // sigtramp's job is to call into real handler
+ sa.sa_tramp = runtime·sigtramp; // runtime·sigtramp's job is to call into real handler
for(i = 0; i<NSIG; i++) {
- if(sigtab[i].flags) {
- if((sigtab[i].flags & SigQueue) != queue)
+ if(runtime·sigtab[i].flags) {
+ if((runtime·sigtab[i].flags & SigQueue) != queue)
continue;
- if(sigtab[i].flags & (SigCatch | SigQueue)) {
- sa.__sigaction_u.__sa_sigaction = sighandler;
+ if(runtime·sigtab[i].flags & (SigCatch | SigQueue)) {
+ sa.__sigaction_u.__sa_sigaction = runtime·sighandler;
} else {
- sa.__sigaction_u.__sa_sigaction = sigignore;
+ sa.__sigaction_u.__sa_sigaction = runtime·sigignore;
}
- if(sigtab[i].flags & SigRestart)
+ if(runtime·sigtab[i].flags & SigRestart)
sa.sa_flags |= SA_RESTART;
else
sa.sa_flags &= ~SA_RESTART;
- sigaction(i, &sa, nil);
+ runtime·sigaction(i, &sa, nil);
}
}
}
diff --git a/src/pkg/runtime/darwin/386/sys.s b/src/pkg/runtime/darwin/386/sys.s
index 4e0a0b3fd..79bbfb68b 100644
--- a/src/pkg/runtime/darwin/386/sys.s
+++ b/src/pkg/runtime/darwin/386/sys.s
@@ -8,42 +8,45 @@
#include "386/asm.h"
-TEXT notok(SB),7,$0
+TEXT runtime·notok(SB),7,$0
MOVL $0xf1, 0xf1
RET
// Exit the entire program (like C exit)
-TEXT exit(SB),7,$0
+TEXT runtime·exit(SB),7,$0
MOVL $1, AX
INT $0x80
- CALL notok(SB)
+ CALL runtime·notok(SB)
RET
// Exit this OS thread (like pthread_exit, which eventually
// calls __bsdthread_terminate).
-TEXT exit1(SB),7,$0
+TEXT runtime·exit1(SB),7,$0
MOVL $361, AX
INT $0x80
JAE 2(PC)
- CALL notok(SB)
+ CALL runtime·notok(SB)
RET
-TEXT write(SB),7,$0
+TEXT runtime·write(SB),7,$0
MOVL $4, AX
INT $0x80
- JAE 2(PC)
- CALL notok(SB)
RET
-TEXT ·mmap(SB),7,$0
+TEXT runtime·mmap(SB),7,$0
MOVL $197, AX
INT $0x80
+ RET
+
+TEXT runtime·munmap(SB),7,$0
+ MOVL $73, AX
+ INT $0x80
JAE 2(PC)
- CALL notok(SB)
+ CALL runtime·notok(SB)
RET
// void gettime(int64 *sec, int32 *usec)
-TEXT gettime(SB), 7, $32
+TEXT runtime·gettime(SB), 7, $32
LEAL 12(SP), AX // must be non-nil, unused
MOVL AX, 4(SP)
MOVL $0, 8(SP) // time zone pointer
@@ -58,11 +61,11 @@ TEXT gettime(SB), 7, $32
MOVL DX, (DI)
RET
-TEXT sigaction(SB),7,$0
+TEXT runtime·sigaction(SB),7,$0
MOVL $46, AX
INT $0x80
JAE 2(PC)
- CALL notok(SB)
+ CALL runtime·notok(SB)
RET
// Sigtramp's job is to call the actual signal handler.
@@ -73,7 +76,7 @@ TEXT sigaction(SB),7,$0
// 12(FP) signal number
// 16(FP) siginfo
// 20(FP) context
-TEXT sigtramp(SB),7,$40
+TEXT runtime·sigtramp(SB),7,$40
get_tls(CX)
// save g
@@ -109,19 +112,19 @@ TEXT sigtramp(SB),7,$40
MOVL BX, 8(SP)
MOVL $184, AX // sigreturn(ucontext, infostyle)
INT $0x80
- CALL notok(SB)
+ CALL runtime·notok(SB)
RET
-TEXT sigaltstack(SB),7,$0
+TEXT runtime·sigaltstack(SB),7,$0
MOVL $53, AX
INT $0x80
JAE 2(PC)
- CALL notok(SB)
+ CALL runtime·notok(SB)
RET
// void bsdthread_create(void *stk, M *m, G *g, void (*fn)(void))
// System call args are: func arg stack pthread flags.
-TEXT bsdthread_create(SB),7,$32
+TEXT runtime·bsdthread_create(SB),7,$32
MOVL $360, AX
// 0(SP) is where the caller PC would be; kernel skips it
MOVL func+12(FP), BX
@@ -150,7 +153,7 @@ TEXT bsdthread_create(SB),7,$32
// DI = stack top
// SI = flags (= 0x1000000)
// SP = stack - C_32_STK_ALIGN
-TEXT bsdthread_start(SB),7,$0
+TEXT runtime·bsdthread_start(SB),7,$0
// set up ldt 7+id to point at m->tls.
// m->tls is at m+40. newosproc left
// the m->id in tls[0].
@@ -162,7 +165,7 @@ TEXT bsdthread_start(SB),7,$0
PUSHL $32 // sizeof tls
PUSHL BP // &tls
PUSHL DI // tls #
- CALL setldt(SB)
+ CALL runtime·setldt(SB)
POPL AX
POPL AX
POPL AX
@@ -173,18 +176,18 @@ TEXT bsdthread_start(SB),7,$0
MOVL AX, g(BP)
MOVL DX, m(BP)
MOVL BX, m_procid(DX) // m->procid = thread port (for debuggers)
- CALL stackcheck(SB) // smashes AX
+ CALL runtime·stackcheck(SB) // smashes AX
CALL CX // fn()
- CALL exit1(SB)
+ CALL runtime·exit1(SB)
RET
// void bsdthread_register(void)
// registers callbacks for threadstart (see bsdthread_create above
// and wqthread and pthsize (not used). returns 0 on success.
-TEXT bsdthread_register(SB),7,$40
+TEXT runtime·bsdthread_register(SB),7,$40
MOVL $366, AX
// 0(SP) is where kernel expects caller PC; ignored
- MOVL $bsdthread_start(SB), 4(SP) // threadstart
+ MOVL $runtime·bsdthread_start(SB), 4(SP) // threadstart
MOVL $0, 8(SP) // wqthread, not used by us
MOVL $0, 12(SP) // pthsize, not used by us
MOVL $0, 16(SP) // dummy_value [sic]
@@ -192,7 +195,7 @@ TEXT bsdthread_register(SB),7,$40
MOVL $0, 24(SP) // dispatchqueue_offset
INT $0x80
JAE 2(PC)
- CALL notok(SB)
+ CALL runtime·notok(SB)
RET
// Invoke Mach system call.
@@ -206,57 +209,57 @@ TEXT bsdthread_register(SB),7,$40
// in the high 16 bits that seems to be the
// argument count in bytes but is not always.
// INT $0x80 works fine for those.
-TEXT sysenter(SB),7,$0
+TEXT runtime·sysenter(SB),7,$0
POPL DX
MOVL SP, CX
BYTE $0x0F; BYTE $0x34; // SYSENTER
// returns to DX with SP set to CX
-TEXT mach_msg_trap(SB),7,$0
+TEXT runtime·mach_msg_trap(SB),7,$0
MOVL $-31, AX
- CALL sysenter(SB)
+ CALL runtime·sysenter(SB)
RET
-TEXT mach_reply_port(SB),7,$0
+TEXT runtime·mach_reply_port(SB),7,$0
MOVL $-26, AX
- CALL sysenter(SB)
+ CALL runtime·sysenter(SB)
RET
-TEXT mach_task_self(SB),7,$0
+TEXT runtime·mach_task_self(SB),7,$0
MOVL $-28, AX
- CALL sysenter(SB)
+ CALL runtime·sysenter(SB)
RET
// Mach provides trap versions of the semaphore ops,
// instead of requiring the use of RPC.
// uint32 mach_semaphore_wait(uint32)
-TEXT mach_semaphore_wait(SB),7,$0
+TEXT runtime·mach_semaphore_wait(SB),7,$0
MOVL $-36, AX
- CALL sysenter(SB)
+ CALL runtime·sysenter(SB)
RET
// uint32 mach_semaphore_timedwait(uint32, uint32, uint32)
-TEXT mach_semaphore_timedwait(SB),7,$0
+TEXT runtime·mach_semaphore_timedwait(SB),7,$0
MOVL $-38, AX
- CALL sysenter(SB)
+ CALL runtime·sysenter(SB)
RET
// uint32 mach_semaphore_signal(uint32)
-TEXT mach_semaphore_signal(SB),7,$0
+TEXT runtime·mach_semaphore_signal(SB),7,$0
MOVL $-33, AX
- CALL sysenter(SB)
+ CALL runtime·sysenter(SB)
RET
// uint32 mach_semaphore_signal_all(uint32)
-TEXT mach_semaphore_signal_all(SB),7,$0
+TEXT runtime·mach_semaphore_signal_all(SB),7,$0
MOVL $-34, AX
- CALL sysenter(SB)
+ CALL runtime·sysenter(SB)
RET
// setldt(int entry, int address, int limit)
// entry and limit are ignored.
-TEXT setldt(SB),7,$32
+TEXT runtime·setldt(SB),7,$32
MOVL address+4(FP), BX // aka base
/*
diff --git a/src/pkg/runtime/darwin/amd64/defs.h b/src/pkg/runtime/darwin/amd64/defs.h
index 0b5fde85c..09e595988 100644
--- a/src/pkg/runtime/darwin/amd64/defs.h
+++ b/src/pkg/runtime/darwin/amd64/defs.h
@@ -10,6 +10,7 @@ enum {
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,
diff --git a/src/pkg/runtime/darwin/amd64/rt0.s b/src/pkg/runtime/darwin/amd64/rt0.s
index 1b706365a..4cfab5876 100644
--- a/src/pkg/runtime/darwin/amd64/rt0.s
+++ b/src/pkg/runtime/darwin/amd64/rt0.s
@@ -4,7 +4,7 @@
// Darwin and Linux use the same linkage to main
-TEXT _rt0_amd64_darwin(SB),7,$-8
+TEXT _rt0_amd64_darwin(SB),7,$-8
MOVQ $_rt0_amd64(SB), AX
MOVQ SP, DI
JMP AX
diff --git a/src/pkg/runtime/darwin/amd64/signal.c b/src/pkg/runtime/darwin/amd64/signal.c
index 648ef207c..474a1bd5c 100644
--- a/src/pkg/runtime/darwin/amd64/signal.c
+++ b/src/pkg/runtime/darwin/amd64/signal.c
@@ -8,41 +8,41 @@
#include "signals.h"
void
-dumpregs(Regs *r)
+runtime·dumpregs(Regs *r)
{
- printf("rax %X\n", r->rax);
- printf("rbx %X\n", r->rbx);
- printf("rcx %X\n", r->rcx);
- printf("rdx %X\n", r->rdx);
- printf("rdi %X\n", r->rdi);
- printf("rsi %X\n", r->rsi);
- printf("rbp %X\n", r->rbp);
- printf("rsp %X\n", r->rsp);
- printf("r8 %X\n", r->r8 );
- printf("r9 %X\n", r->r9 );
- printf("r10 %X\n", r->r10);
- printf("r11 %X\n", r->r11);
- printf("r12 %X\n", r->r12);
- printf("r13 %X\n", r->r13);
- printf("r14 %X\n", r->r14);
- printf("r15 %X\n", r->r15);
- printf("rip %X\n", r->rip);
- printf("rflags %X\n", r->rflags);
- printf("cs %X\n", r->cs);
- printf("fs %X\n", r->fs);
- printf("gs %X\n", r->gs);
+ 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->rflags);
+ runtime·printf("cs %X\n", r->cs);
+ runtime·printf("fs %X\n", r->fs);
+ runtime·printf("gs %X\n", r->gs);
}
String
-signame(int32 sig)
+runtime·signame(int32 sig)
{
if(sig < 0 || sig >= NSIG)
- return emptystring;
- return gostringnocopy((byte*)sigtab[sig].name);
+ return runtime·emptystring;
+ return runtime·gostringnocopy((byte*)runtime·sigtab[sig].name);
}
void
-sighandler(int32 sig, Siginfo *info, void *context)
+runtime·sighandler(int32 sig, Siginfo *info, void *context)
{
Ucontext *uc;
Mcontext *mc;
@@ -55,7 +55,7 @@ sighandler(int32 sig, Siginfo *info, void *context)
mc = uc->uc_mcontext;
r = &mc->ss;
- if((gp = m->curg) != nil && (sigtab[sig].flags & SigPanic)) {
+ if((gp = m->curg) != nil && (runtime·sigtab[sig].flags & SigPanic)) {
// 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).
@@ -77,91 +77,91 @@ sighandler(int32 sig, Siginfo *info, void *context)
gp->sigcode0 = info->si_code;
gp->sigcode1 = (uintptr)info->si_addr;
- // Only push sigpanic if r->rip != 0.
+ // 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 sigpanic instead.
- // (Otherwise the trace will end at sigpanic and we
+ // 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)sigpanic;
+ r->rip = (uintptr)runtime·sigpanic;
return;
}
- if(sigtab[sig].flags & SigQueue) {
- if(sigsend(sig) || (sigtab[sig].flags & SigIgnore))
+ if(runtime·sigtab[sig].flags & SigQueue) {
+ if(runtime·sigsend(sig) || (runtime·sigtab[sig].flags & SigIgnore))
return;
- exit(2); // SIGINT, SIGTERM, etc
+ runtime·exit(2); // SIGINT, SIGTERM, etc
}
- if(panicking) // traceback already printed
- exit(2);
- panicking = 1;
+ if(runtime·panicking) // traceback already printed
+ runtime·exit(2);
+ runtime·panicking = 1;
if(sig < 0 || sig >= NSIG){
- printf("Signal %d\n", sig);
+ runtime·printf("Signal %d\n", sig);
}else{
- printf("%s\n", sigtab[sig].name);
+ runtime·printf("%s\n", runtime·sigtab[sig].name);
}
- printf("pc: %X\n", r->rip);
- printf("\n");
+ runtime·printf("pc: %X\n", r->rip);
+ runtime·printf("\n");
- if(gotraceback()){
- traceback((void*)r->rip, (void*)r->rsp, 0, (void*)r->r15);
- tracebackothers((void*)r->r15);
- dumpregs(r);
+ if(runtime·gotraceback()){
+ runtime·traceback((void*)r->rip, (void*)r->rsp, 0, g);
+ runtime·tracebackothers(g);
+ runtime·dumpregs(r);
}
- breakpoint();
- exit(2);
+ runtime·breakpoint();
+ runtime·exit(2);
}
void
-sigignore(int32, Siginfo*, void*)
+runtime·sigignore(int32, Siginfo*, void*)
{
}
void
-signalstack(byte *p, int32 n)
+runtime·signalstack(byte *p, int32 n)
{
StackT st;
st.ss_sp = p;
st.ss_size = n;
st.ss_flags = 0;
- sigaltstack(&st, nil);
+ runtime·sigaltstack(&st, nil);
}
void
-initsig(int32 queue)
+runtime·initsig(int32 queue)
{
int32 i;
static Sigaction sa;
- siginit();
+ runtime·siginit();
sa.sa_flags |= SA_SIGINFO|SA_ONSTACK;
sa.sa_mask = 0xFFFFFFFFU;
- sa.sa_tramp = sigtramp; // sigtramp's job is to call into real handler
+ sa.sa_tramp = runtime·sigtramp; // runtime·sigtramp's job is to call into real handler
for(i = 0; i<NSIG; i++) {
- if(sigtab[i].flags) {
- if((sigtab[i].flags & SigQueue) != queue)
+ if(runtime·sigtab[i].flags) {
+ if((runtime·sigtab[i].flags & SigQueue) != queue)
continue;
- if(sigtab[i].flags & (SigCatch | SigQueue)) {
- sa.__sigaction_u.__sa_sigaction = sighandler;
+ if(runtime·sigtab[i].flags & (SigCatch | SigQueue)) {
+ sa.__sigaction_u.__sa_sigaction = runtime·sighandler;
} else {
- sa.__sigaction_u.__sa_sigaction = sigignore;
+ sa.__sigaction_u.__sa_sigaction = runtime·sigignore;
}
- if(sigtab[i].flags & SigRestart)
+ if(runtime·sigtab[i].flags & SigRestart)
sa.sa_flags |= SA_RESTART;
else
sa.sa_flags &= ~SA_RESTART;
- sigaction(i, &sa, nil);
+ runtime·sigaction(i, &sa, nil);
}
}
}
diff --git a/src/pkg/runtime/darwin/amd64/sys.s b/src/pkg/runtime/darwin/amd64/sys.s
index 1654fa2b0..05dbc7b93 100644
--- a/src/pkg/runtime/darwin/amd64/sys.s
+++ b/src/pkg/runtime/darwin/amd64/sys.s
@@ -7,38 +7,39 @@
// 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.
//
+// The low 24 bits are the system call number.
+// The high 8 bits specify the kind of system call: 1=Mach, 2=BSD, 3=Machine-Dependent.
+//
#include "amd64/asm.h"
// Exit the entire program (like C exit)
-TEXT exit(SB),7,$0
+TEXT runtime·exit(SB),7,$0
MOVL 8(SP), DI // arg 1 exit status
MOVL $(0x2000000+1), AX // syscall entry
SYSCALL
- CALL notok(SB)
+ CALL runtime·notok(SB)
RET
// Exit this OS thread (like pthread_exit, which eventually
// calls __bsdthread_terminate).
-TEXT exit1(SB),7,$0
+TEXT runtime·exit1(SB),7,$0
MOVL 8(SP), DI // arg 1 exit status
MOVL $(0x2000000+361), AX // syscall entry
SYSCALL
- CALL notok(SB)
+ CALL runtime·notok(SB)
RET
-TEXT write(SB),7,$0
+TEXT runtime·write(SB),7,$0
MOVL 8(SP), DI // arg 1 fd
MOVQ 16(SP), SI // arg 2 buf
MOVL 24(SP), DX // arg 3 count
MOVL $(0x2000000+4), AX // syscall entry
SYSCALL
- JCC 2(PC)
- CALL notok(SB)
RET
// void gettime(int64 *sec, int32 *usec)
-TEXT gettime(SB), 7, $32
+TEXT runtime·gettime(SB), 7, $32
MOVQ SP, DI // must be non-nil, unused
MOVQ $0, SI
MOVQ $(0x2000000+116), AX
@@ -49,7 +50,7 @@ TEXT gettime(SB), 7, $32
MOVL DX, (DI)
RET
-TEXT sigaction(SB),7,$0
+TEXT runtime·sigaction(SB),7,$0
MOVL 8(SP), DI // arg 1 sig
MOVQ 16(SP), SI // arg 2 act
MOVQ 24(SP), DX // arg 3 oact
@@ -58,24 +59,40 @@ TEXT sigaction(SB),7,$0
MOVL $(0x2000000+46), AX // syscall entry
SYSCALL
JCC 2(PC)
- CALL notok(SB)
+ CALL runtime·notok(SB)
RET
-TEXT sigtramp(SB),7,$40
- MOVQ m_gsignal(m), g
+TEXT runtime·sigtramp(SB),7,$64
+ get_tls(BX)
+
+ // save g
+ MOVQ g(BX), BP
+ MOVQ BP, 40(SP)
+
+ // g = m->gsignal
+ MOVQ m(BX), BP
+ MOVQ m_gsignal(BP), BP
+ MOVQ BP, g(BX)
+
MOVL DX, 0(SP)
MOVQ CX, 8(SP)
MOVQ R8, 16(SP)
MOVQ R8, 24(SP) // save ucontext
MOVQ SI, 32(SP) // save infostyle
CALL DI
+
+ // restore g
+ get_tls(BX)
+ MOVQ 40(SP), BP
+ MOVQ BP, g(BX)
+
MOVL $(0x2000000+184), AX // sigreturn(ucontext, infostyle)
MOVQ 24(SP), DI // saved ucontext
MOVQ 32(SP), SI // saved infostyle
SYSCALL
INT $3 // not reached
-TEXT ·mmap(SB),7,$0
+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
@@ -84,26 +101,33 @@ TEXT ·mmap(SB),7,$0
MOVL 36(SP), R9 // arg 6 offset
MOVL $(0x2000000+197), AX // syscall entry
SYSCALL
+ RET
+
+TEXT runtime·munmap(SB),7,$0
+ MOVQ 8(SP), DI // arg 1 addr
+ MOVQ 16(SP), SI // arg 2 len
+ MOVL $(0x2000000+73), AX // syscall entry
+ SYSCALL
JCC 2(PC)
- CALL notok(SB)
+ CALL runtime·notok(SB)
RET
-TEXT notok(SB),7,$0
+TEXT runtime·notok(SB),7,$0
MOVL $0xf1, BP
MOVQ BP, (BP)
RET
-TEXT sigaltstack(SB),7,$0
+TEXT runtime·sigaltstack(SB),7,$0
MOVQ new+8(SP), DI
MOVQ old+16(SP), SI
MOVQ $(0x2000000+53), AX
SYSCALL
JCC 2(PC)
- CALL notok(SB)
+ CALL runtime·notok(SB)
RET
// void bsdthread_create(void *stk, M *m, G *g, void (*fn)(void))
-TEXT bsdthread_create(SB),7,$0
+TEXT runtime·bsdthread_create(SB),7,$0
// Set up arguments to bsdthread_create system call.
// The ones in quotes pass through to the thread callback
// uninterpreted, so we can put whatever we want there.
@@ -132,21 +156,36 @@ TEXT bsdthread_create(SB),7,$0
// R8 = stack
// R9 = flags (= 0)
// SP = stack - C_64_REDZONE_LEN (= stack - 128)
-TEXT bsdthread_start(SB),7,$0
+TEXT runtime·bsdthread_start(SB),7,$0
MOVQ R8, SP // empirically, SP is very wrong but R8 is right
- MOVQ CX, m
- MOVQ m_g0(m), g
- CALL stackcheck(SB)
- MOVQ SI, m_procid(m) // thread port is m->procid
+
+ PUSHQ DX
+ PUSHQ CX
+ PUSHQ SI
+
+ // set up thread local storage pointing at m->tls.
+ LEAQ m_tls(CX), DI
+ CALL runtime·settls(SB)
+
+ POPQ SI
+ POPQ CX
+ POPQ DX
+
+ get_tls(BX)
+ MOVQ CX, m(BX)
+ MOVQ SI, m_procid(CX) // thread port is m->procid
+ MOVQ m_g0(CX), AX
+ MOVQ AX, g(BX)
+ CALL runtime·stackcheck(SB) // smashes AX, CX
CALL DX // fn
- CALL exit1(SB)
+ CALL runtime·exit1(SB)
RET
// void bsdthread_register(void)
// registers callbacks for threadstart (see bsdthread_create above
// and wqthread and pthsize (not used). returns 0 on success.
-TEXT bsdthread_register(SB),7,$0
- MOVQ $bsdthread_start(SB), DI // threadstart
+TEXT runtime·bsdthread_register(SB),7,$0
+ MOVQ $runtime·bsdthread_start(SB), DI // threadstart
MOVQ $0, SI // wqthread, not used by us
MOVQ $0, DX // pthsize, not used by us
MOVQ $0, R10 // dummy_value [sic]
@@ -155,13 +194,13 @@ TEXT bsdthread_register(SB),7,$0
MOVQ $(0x2000000+366), AX // bsdthread_register
SYSCALL
JCC 2(PC)
- CALL notok(SB)
+ CALL runtime·notok(SB)
RET
// Mach system calls use 0x1000000 instead of the BSD's 0x2000000.
// uint32 mach_msg_trap(void*, uint32, uint32, uint32, uint32, uint32, uint32)
-TEXT mach_msg_trap(SB),7,$0
+TEXT runtime·mach_msg_trap(SB),7,$0
MOVQ 8(SP), DI
MOVL 16(SP), SI
MOVL 20(SP), DX
@@ -175,17 +214,17 @@ TEXT mach_msg_trap(SB),7,$0
POPQ R11
RET
-TEXT mach_task_self(SB),7,$0
+TEXT runtime·mach_task_self(SB),7,$0
MOVL $(0x1000000+28), AX // task_self_trap
SYSCALL
RET
-TEXT mach_thread_self(SB),7,$0
+TEXT runtime·mach_thread_self(SB),7,$0
MOVL $(0x1000000+27), AX // thread_self_trap
SYSCALL
RET
-TEXT mach_reply_port(SB),7,$0
+TEXT runtime·mach_reply_port(SB),7,$0
MOVL $(0x1000000+26), AX // mach_reply_port
SYSCALL
RET
@@ -194,14 +233,14 @@ TEXT mach_reply_port(SB),7,$0
// instead of requiring the use of RPC.
// uint32 mach_semaphore_wait(uint32)
-TEXT mach_semaphore_wait(SB),7,$0
+TEXT runtime·mach_semaphore_wait(SB),7,$0
MOVL 8(SP), DI
MOVL $(0x1000000+36), AX // semaphore_wait_trap
SYSCALL
RET
// uint32 mach_semaphore_timedwait(uint32, uint32, uint32)
-TEXT mach_semaphore_timedwait(SB),7,$0
+TEXT runtime·mach_semaphore_timedwait(SB),7,$0
MOVL 8(SP), DI
MOVL 12(SP), SI
MOVL 16(SP), DX
@@ -210,15 +249,28 @@ TEXT mach_semaphore_timedwait(SB),7,$0
RET
// uint32 mach_semaphore_signal(uint32)
-TEXT mach_semaphore_signal(SB),7,$0
+TEXT runtime·mach_semaphore_signal(SB),7,$0
MOVL 8(SP), DI
MOVL $(0x1000000+33), AX // semaphore_signal_trap
SYSCALL
RET
// uint32 mach_semaphore_signal_all(uint32)
-TEXT mach_semaphore_signal_all(SB),7,$0
+TEXT runtime·mach_semaphore_signal_all(SB),7,$0
MOVL 8(SP), DI
MOVL $(0x1000000+34), AX // semaphore_signal_all_trap
SYSCALL
RET
+
+// 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
+ * of the constant.
+ */
+ SUBQ $0x8a0, DI
+
+ MOVL $(0x3000000+3), AX // thread_fast_set_cthread_self - machdep call #3
+ SYSCALL
+ RET
diff --git a/src/pkg/runtime/darwin/defs.c b/src/pkg/runtime/darwin/defs.c
index 8735e7857..1a1cdf880 100644
--- a/src/pkg/runtime/darwin/defs.c
+++ b/src/pkg/runtime/darwin/defs.c
@@ -26,6 +26,7 @@ enum {
$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,
diff --git a/src/pkg/runtime/darwin/mem.c b/src/pkg/runtime/darwin/mem.c
index 52e351a7d..7fb2c2807 100644
--- a/src/pkg/runtime/darwin/mem.c
+++ b/src/pkg/runtime/darwin/mem.c
@@ -4,14 +4,21 @@
#include "malloc.h"
void*
-SysAlloc(uintptr n)
+runtime·SysAlloc(uintptr n)
{
+ void *v;
+
mstats.sys += n;
- return runtime_mmap(nil, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, -1, 0);
+ v = runtime·mmap(nil, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, -1, 0);
+ if(v < (void*)4096) {
+ runtime·printf("mmap: errno=%p\n", v);
+ runtime·throw("mmap");
+ }
+ return v;
}
void
-SysUnused(void *v, uintptr n)
+runtime·SysUnused(void *v, uintptr n)
{
USED(v);
USED(n);
@@ -19,10 +26,14 @@ SysUnused(void *v, uintptr n)
}
void
-SysFree(void *v, uintptr n)
+runtime·SysFree(void *v, uintptr n)
{
- USED(v);
- USED(n);
- // TODO(rsc): call munmap
+ mstats.sys -= n;
+ runtime·munmap(v, n);
}
+
+void
+runtime·SysMemInit(void)
+{
+}
diff --git a/src/pkg/runtime/darwin/os.h b/src/pkg/runtime/darwin/os.h
index 51a164c33..35ef4e6d9 100644
--- a/src/pkg/runtime/darwin/os.h
+++ b/src/pkg/runtime/darwin/os.h
@@ -2,24 +2,24 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-int32 bsdthread_create(void*, M*, G*, void(*)(void));
-void bsdthread_register(void);
-int32 mach_msg_trap(MachHeader*, int32, uint32, uint32, uint32, uint32, uint32);
-uint32 mach_reply_port(void);
-void mach_semacquire(uint32);
-uint32 mach_semcreate(void);
-void mach_semdestroy(uint32);
-void mach_semrelease(uint32);
-void mach_semreset(uint32);
-uint32 mach_task_self(void);
-uint32 mach_task_self(void);
-uint32 mach_thread_self(void);
-uint32 mach_thread_self(void);
+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);
+uint32 runtime·mach_semcreate(void);
+void runtime·mach_semdestroy(uint32);
+void runtime·mach_semrelease(uint32);
+void runtime·mach_semreset(uint32);
+uint32 runtime·mach_task_self(void);
+uint32 runtime·mach_task_self(void);
+uint32 runtime·mach_thread_self(void);
+uint32 runtime·mach_thread_self(void);
struct Sigaction;
-void sigaction(uintptr, struct Sigaction*, struct Sigaction*);
+void runtime·sigaction(uintptr, struct Sigaction*, struct Sigaction*);
struct StackT;
-void sigaltstack(struct StackT*, struct StackT*);
-void sigtramp(void);
-void sigpanic(void);
+void runtime·sigaltstack(struct StackT*, struct StackT*);
+void runtime·sigtramp(void);
+void runtime·sigpanic(void);
diff --git a/src/pkg/runtime/darwin/runtime_defs.go b/src/pkg/runtime/darwin/runtime_defs.go
new file mode 100644
index 000000000..cf0b414a9
--- /dev/null
+++ b/src/pkg/runtime/darwin/runtime_defs.go
@@ -0,0 +1,23 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Go definitions of internal structures. Master is runtime.h
+
+package runtime
+
+type lock struct {
+ key uint32
+ sema uint32
+}
+
+type usema struct {
+ u uint32
+ k uint32
+}
+
+
+type note struct {
+ wakeup int32
+ sema usema
+}
diff --git a/src/pkg/runtime/darwin/signals.h b/src/pkg/runtime/darwin/signals.h
index ac9e5d606..035027fad 100644
--- a/src/pkg/runtime/darwin/signals.h
+++ b/src/pkg/runtime/darwin/signals.h
@@ -8,7 +8,7 @@
#define Q SigQueue
#define P SigPanic
-SigTab sigtab[] = {
+SigTab runtime·sigtab[] = {
/* 0 */ 0, "SIGNONE: no trap",
/* 1 */ Q+R, "SIGHUP: terminal line hangup",
/* 2 */ Q+R, "SIGINT: interrupt",
diff --git a/src/pkg/runtime/darwin/thread.c b/src/pkg/runtime/darwin/thread.c
index e51d53019..d69c62412 100644
--- a/src/pkg/runtime/darwin/thread.c
+++ b/src/pkg/runtime/darwin/thread.c
@@ -6,13 +6,13 @@
#include "defs.h"
#include "os.h"
-extern SigTab sigtab[];
+extern SigTab runtime·sigtab[];
static void
unimplemented(int8 *name)
{
- prints(name);
- prints(" not implemented\n");
+ runtime·prints(name);
+ runtime·prints(" not implemented\n");
*(int32*)1231 = 1231;
}
@@ -29,10 +29,10 @@ initsema(uint32 *psema)
if(*psema != 0) // already have one
return;
- sema = mach_semcreate();
- if(!cas(psema, 0, sema)){
+ sema = runtime·mach_semcreate();
+ if(!runtime·cas(psema, 0, sema)){
// Someone else filled it in. Use theirs.
- mach_semdestroy(sema);
+ runtime·mach_semdestroy(sema);
return;
}
}
@@ -52,40 +52,40 @@ initsema(uint32 *psema)
// in Plan 9's user-level locks.
void
-lock(Lock *l)
+runtime·lock(Lock *l)
{
if(m->locks < 0)
- throw("lock count");
+ runtime·throw("lock count");
m->locks++;
- if(xadd(&l->key, 1) > 1) { // someone else has it; wait
+ if(runtime·xadd(&l->key, 1) > 1) { // someone else has it; wait
// Allocate semaphore if needed.
if(l->sema == 0)
initsema(&l->sema);
- mach_semacquire(l->sema);
+ runtime·mach_semacquire(l->sema);
}
}
void
-unlock(Lock *l)
+runtime·unlock(Lock *l)
{
m->locks--;
if(m->locks < 0)
- throw("lock count");
+ runtime·throw("lock count");
- if(xadd(&l->key, -1) > 0) { // someone else is waiting
+ if(runtime·xadd(&l->key, -1) > 0) { // someone else is waiting
// Allocate semaphore if needed.
if(l->sema == 0)
initsema(&l->sema);
- mach_semrelease(l->sema);
+ runtime·mach_semrelease(l->sema);
}
}
void
-destroylock(Lock *l)
+runtime·destroylock(Lock *l)
{
if(l->sema != 0) {
- mach_semdestroy(l->sema);
+ runtime·mach_semdestroy(l->sema);
l->sema = 0;
}
}
@@ -95,79 +95,84 @@ destroylock(Lock *l)
// but when it's time to block, fall back on the kernel semaphore k.
// This is the same algorithm used in Plan 9.
void
-usemacquire(Usema *s)
+runtime·usemacquire(Usema *s)
{
- if((int32)xadd(&s->u, -1) < 0) {
+ if((int32)runtime·xadd(&s->u, -1) < 0) {
if(s->k == 0)
initsema(&s->k);
- mach_semacquire(s->k);
+ runtime·mach_semacquire(s->k);
}
}
void
-usemrelease(Usema *s)
+runtime·usemrelease(Usema *s)
{
- if((int32)xadd(&s->u, 1) <= 0) {
+ if((int32)runtime·xadd(&s->u, 1) <= 0) {
if(s->k == 0)
initsema(&s->k);
- mach_semrelease(s->k);
+ runtime·mach_semrelease(s->k);
}
}
// Event notifications.
void
-noteclear(Note *n)
+runtime·noteclear(Note *n)
{
n->wakeup = 0;
}
void
-notesleep(Note *n)
+runtime·notesleep(Note *n)
{
while(!n->wakeup)
- usemacquire(&n->sema);
+ runtime·usemacquire(&n->sema);
}
void
-notewakeup(Note *n)
+runtime·notewakeup(Note *n)
{
n->wakeup = 1;
- usemrelease(&n->sema);
+ runtime·usemrelease(&n->sema);
}
// BSD interface for threading.
void
-osinit(void)
+runtime·osinit(void)
{
// Register our thread-creation callback (see {amd64,386}/sys.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.
- extern void (*libcgo_thread_start)(void*);
- if(libcgo_thread_start == nil)
- bsdthread_register();
+ if(!runtime·iscgo)
+ runtime·bsdthread_register();
}
void
-newosproc(M *m, G *g, void *stk, void (*fn)(void))
+runtime·goenvs(void)
+{
+ runtime·goenvs_unix();
+}
+
+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){
- printf("newosproc stk=%p m=%p g=%p fn=%p id=%d/%d ostk=%p\n",
+ 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(bsdthread_create(stk, m, g, fn) < 0)
- throw("cannot create new OS thread");
+ if(runtime·bsdthread_create(stk, m, g, fn) < 0)
+ runtime·throw("cannot create new OS thread");
}
// Called to initialize a new m (including the bootstrap m).
void
-minit(void)
+runtime·minit(void)
{
// Initialize signal handling.
- m->gsignal = malg(32*1024); // OS X wants >=8K, Linux >=2K
- signalstack(m->gsignal->stackguard, 32*1024);
+ m->gsignal = runtime·malg(32*1024); // OS X wants >=8K, Linux >=2K
+ runtime·signalstack(m->gsignal->stackguard, 32*1024);
}
// Mach IPC, to get at semaphores
@@ -176,8 +181,8 @@ minit(void)
static void
macherror(int32 r, int8 *fn)
{
- printf("mach error %s: %d\n", fn, r);
- throw("mach error");
+ runtime·printf("mach error %s: %d\n", fn, r);
+ runtime·throw("mach error");
}
enum
@@ -199,7 +204,7 @@ mach_msg(MachHeader *h,
uint32 notify)
{
// TODO: Loop on interrupt.
- return mach_msg_trap(h, op, send_size, rcv_size, rcv_name, timeout, notify);
+ return runtime·mach_msg_trap(h, op, send_size, rcv_size, rcv_name, timeout, notify);
}
// Mach RPC (MIG)
@@ -229,7 +234,7 @@ machcall(MachHeader *h, int32 maxsize, int32 rxsize)
CodeMsg *c;
if((port = m->machport) == 0){
- port = mach_reply_port();
+ port = runtime·mach_reply_port();
m->machport = port;
}
@@ -240,48 +245,48 @@ machcall(MachHeader *h, int32 maxsize, int32 rxsize)
if(DebugMach){
p = (uint32*)h;
- prints("send:\t");
+ runtime·prints("send:\t");
for(i=0; i<h->msgh_size/sizeof(p[0]); i++){
- prints(" ");
- ·printpointer((void*)p[i]);
+ runtime·prints(" ");
+ runtime·printpointer((void*)p[i]);
if(i%8 == 7)
- prints("\n\t");
+ runtime·prints("\n\t");
}
if(i%8)
- prints("\n");
+ runtime·prints("\n");
}
ret = mach_msg(h, MACH_SEND_MSG|MACH_RCV_MSG,
h->msgh_size, maxsize, port, 0, 0);
if(ret != 0){
if(DebugMach){
- prints("mach_msg error ");
- ·printint(ret);
- prints("\n");
+ runtime·prints("mach_msg error ");
+ runtime·printint(ret);
+ runtime·prints("\n");
}
return ret;
}
if(DebugMach){
p = (uint32*)h;
- prints("recv:\t");
+ runtime·prints("recv:\t");
for(i=0; i<h->msgh_size/sizeof(p[0]); i++){
- prints(" ");
- ·printpointer((void*)p[i]);
+ runtime·prints(" ");
+ runtime·printpointer((void*)p[i]);
if(i%8 == 7)
- prints("\n\t");
+ runtime·prints("\n\t");
}
if(i%8)
- prints("\n");
+ runtime·prints("\n");
}
if(h->msgh_id != id+Reply){
if(DebugMach){
- prints("mach_msg reply id mismatch ");
- ·printint(h->msgh_id);
- prints(" != ");
- ·printint(id+Reply);
- prints("\n");
+ runtime·prints("mach_msg reply id mismatch ");
+ runtime·printint(h->msgh_id);
+ runtime·prints(" != ");
+ runtime·printint(id+Reply);
+ runtime·prints("\n");
}
return -303; // MIG_REPLY_MISMATCH
}
@@ -296,20 +301,20 @@ machcall(MachHeader *h, int32 maxsize, int32 rxsize)
if(h->msgh_size == sizeof(CodeMsg)
&& !(h->msgh_bits & MACH_MSGH_BITS_COMPLEX)){
if(DebugMach){
- prints("mig result ");
- ·printint(c->code);
- prints("\n");
+ runtime·prints("mig result ");
+ runtime·printint(c->code);
+ runtime·prints("\n");
}
return c->code;
}
if(h->msgh_size != rxsize){
if(DebugMach){
- prints("mach_msg reply size mismatch ");
- ·printint(h->msgh_size);
- prints(" != ");
- ·printint(rxsize);
- prints("\n");
+ runtime·prints("mach_msg reply size mismatch ");
+ runtime·printint(h->msgh_size);
+ runtime·prints(" != ");
+ runtime·printint(rxsize);
+ runtime·prints("\n");
}
return -307; // MIG_ARRAY_TOO_LARGE
}
@@ -363,7 +368,7 @@ struct Tmach_semdestroyMsg
#pragma pack off
uint32
-mach_semcreate(void)
+runtime·mach_semcreate(void)
{
union {
Tmach_semcreateMsg tx;
@@ -374,7 +379,7 @@ mach_semcreate(void)
m.tx.h.msgh_bits = 0;
m.tx.h.msgh_size = sizeof(m.tx);
- m.tx.h.msgh_remote_port = mach_task_self();
+ m.tx.h.msgh_remote_port = runtime·mach_task_self();
m.tx.h.msgh_id = Tmach_semcreate;
m.tx.ndr = zerondr;
@@ -392,7 +397,7 @@ mach_semcreate(void)
}
void
-mach_semdestroy(uint32 sem)
+runtime·mach_semdestroy(uint32 sem)
{
union {
Tmach_semdestroyMsg tx;
@@ -402,7 +407,7 @@ mach_semdestroy(uint32 sem)
m.tx.h.msgh_bits = MACH_MSGH_BITS_COMPLEX;
m.tx.h.msgh_size = sizeof(m.tx);
- m.tx.h.msgh_remote_port = mach_task_self();
+ m.tx.h.msgh_remote_port = runtime·mach_task_self();
m.tx.h.msgh_id = Tmach_semdestroy;
m.tx.body.msgh_descriptor_count = 1;
m.tx.semaphore.name = sem;
@@ -417,17 +422,17 @@ mach_semdestroy(uint32 sem)
}
// The other calls have simple system call traps in sys.s
-int32 mach_semaphore_wait(uint32 sema);
-int32 mach_semaphore_timedwait(uint32 sema, uint32 sec, uint32 nsec);
-int32 mach_semaphore_signal(uint32 sema);
-int32 mach_semaphore_signal_all(uint32 sema);
+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
-mach_semacquire(uint32 sem)
+runtime·mach_semacquire(uint32 sem)
{
int32 r;
- while((r = mach_semaphore_wait(sem)) != 0) {
+ while((r = runtime·mach_semaphore_wait(sem)) != 0) {
if(r == KERN_ABORTED) // interrupted
continue;
macherror(r, "semaphore_wait");
@@ -435,11 +440,11 @@ mach_semacquire(uint32 sem)
}
void
-mach_semrelease(uint32 sem)
+runtime·mach_semrelease(uint32 sem)
{
int32 r;
- while((r = mach_semaphore_signal(sem)) != 0) {
+ while((r = runtime·mach_semaphore_signal(sem)) != 0) {
if(r == KERN_ABORTED) // interrupted
continue;
macherror(r, "semaphore_signal");
@@ -447,25 +452,27 @@ mach_semrelease(uint32 sem)
}
void
-sigpanic(void)
+runtime·sigpanic(void)
{
switch(g->sig) {
case SIGBUS:
if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000)
- panicstring("invalid memory address or nil pointer dereference");
- break;
+ 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->sigcode1 < 0x1000)
- panicstring("invalid memory address or nil pointer dereference");
- break;
+ 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:
- panicstring("integer divide by zero");
+ runtime·panicstring("integer divide by zero");
case FPE_INTOVF:
- panicstring("integer overflow");
+ runtime·panicstring("integer overflow");
}
- panicstring("floating point error");
+ runtime·panicstring("floating point error");
}
- panicstring(sigtab[g->sig].name);
+ runtime·panicstring(runtime·sigtab[g->sig].name);
}
diff --git a/src/pkg/runtime/debug.go b/src/pkg/runtime/debug.go
index b65cc6693..3ce35cc5b 100644
--- a/src/pkg/runtime/debug.go
+++ b/src/pkg/runtime/debug.go
@@ -4,6 +4,8 @@
package runtime
+import "unsafe"
+
// Breakpoint() executes a breakpoint trap.
func Breakpoint()
@@ -26,6 +28,9 @@ func GOMAXPROCS(n int) int
// Cgocalls returns the number of cgo calls made by the current process.
func Cgocalls() int64
+// Goroutines returns the number of goroutines that currently exist.
+func Goroutines() int32
+
type MemStatsType struct {
// General statistics.
// Not locked during update; approximate.
@@ -36,10 +41,11 @@ type MemStatsType struct {
Mallocs uint64 // number of mallocs
// 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
+ HeapAlloc uint64 // bytes allocated and still in use
+ HeapSys uint64 // bytes obtained from system
+ HeapIdle uint64 // bytes in idle spans
+ HeapInuse uint64 // bytes in non-idle span
+ HeapObjects uint64 // total number of allocated objects
// Low-level fixed-size structure allocator statistics.
// Inuse is bytes used now.
@@ -69,6 +75,15 @@ type MemStatsType struct {
}
}
+var sizeof_C_MStats int // filled in by malloc.goc
+
+func init() {
+ if sizeof_C_MStats != unsafe.Sizeof(MemStats) {
+ println(sizeof_C_MStats, unsafe.Sizeof(MemStats))
+ panic("MStats vs MemStatsType size mismatch")
+ }
+}
+
// MemStats holds statistics about the memory system.
// The statistics are only approximate, as they are not interlocked on update.
var MemStats MemStatsType
diff --git a/src/pkg/runtime/error.go b/src/pkg/runtime/error.go
index 673e77b2c..289d78f49 100644
--- a/src/pkg/runtime/error.go
+++ b/src/pkg/runtime/error.go
@@ -111,6 +111,8 @@ type stringer interface {
String() string
}
+func typestring(interface{}) string
+
// For calling from C.
// Prints an argument passed to panic.
// There's room for arbitrary complexity here, but we keep it
@@ -126,6 +128,6 @@ func printany(i interface{}) {
case string:
print(v)
default:
- print(i)
+ print("(", typestring(i), ") ", i)
}
}
diff --git a/src/pkg/runtime/export_test.go b/src/pkg/runtime/export_test.go
new file mode 100644
index 000000000..58631c7b4
--- /dev/null
+++ b/src/pkg/runtime/export_test.go
@@ -0,0 +1,17 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Export guts for testing.
+
+package runtime
+
+var Fadd64 = fadd64
+var Fsub64 = fsub64
+var Fmul64 = fmul64
+var Fdiv64 = fdiv64
+var F64to32 = f64to32
+var F32to64 = f32to64
+var Fcmp64 = fcmp64
+var Fintto64 = fintto64
+var F64toint = f64toint
diff --git a/src/pkg/runtime/extern.go b/src/pkg/runtime/extern.go
index d3d1dabdf..77c3e8e3a 100644
--- a/src/pkg/runtime/extern.go
+++ b/src/pkg/runtime/extern.go
@@ -35,24 +35,6 @@ func Callers(skip int, pc []uintptr) int
// given program counter address, or else nil.
func FuncForPC(pc uintptr) *Func
-// NOTE(rsc): Func must match struct Func in runtime.h
-
-// Func records information about a function in the program,
-// in particular the mapping from program counters to source
-// line numbers within that function.
-type Func struct {
- name string
- typ string
- src string
- pcln []byte
- entry uintptr
- pc0 uintptr
- ln0 int32
- frame int32
- args int32
- locals int32
-}
-
// Name returns the name of the function.
func (f *Func) Name() string { return f.name }
@@ -66,13 +48,17 @@ func (f *Func) Entry() uintptr { return f.entry }
func (f *Func) FileLine(pc uintptr) (file string, line int) {
// NOTE(rsc): If you edit this function, also edit
// symtab.c:/^funcline.
- const PcQuant = 1
+ var pcQuant uintptr = 1
+ if GOARCH == "arm" {
+ pcQuant = 4
+ }
+ targetpc := pc
p := f.pcln
- pc1 := f.pc0
+ pc = f.pc0
line = int(f.ln0)
file = f.src
- for i := 0; i < len(p) && pc1 <= pc; i++ {
+ for i := 0; i < len(p) && pc <= targetpc; i++ {
switch {
case p[i] == 0:
line += int(p[i+1]<<24) | int(p[i+2]<<16) | int(p[i+3]<<8) | int(p[i+4])
@@ -80,11 +66,11 @@ func (f *Func) FileLine(pc uintptr) (file string, line int) {
case p[i] <= 64:
line += int(p[i])
case p[i] <= 128:
- line += int(p[i] - 64)
+ line -= int(p[i] - 64)
default:
- line += PcQuant * int(p[i]-129)
+ pc += pcQuant * uintptr(p[i]-129)
}
- pc += PcQuant
+ pc += pcQuant
}
return
}
@@ -105,13 +91,13 @@ 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 creates
-// a new goroutine running f(x). Creating the new goroutine makes
-// x reachable again, but now without an associated finalizer.
-// Assuming that SetFinalizer is not called again, the next time
-// the garbage collector sees that x is unreachable, it will free x.
+// with an associated finalizer, it clears the association and runs
+// f(x) in a separate goroutine. This makes x reachable again, but
+// now without an associated finalizer. Assuming that SetFinalizer
+// is not called again, the next time the garbage collector sees
+// that x is unreachable, it will free x.
//
-// SetFinalizer(x, nil) clears any finalizer associated with f.
+// SetFinalizer(x, nil) clears any finalizer associated with x.
//
// The argument x must be a pointer to an object allocated by
// calling new or by taking the address of a composite literal.
@@ -142,7 +128,6 @@ func Semrelease(s *uint32)
// If a finalizer must run for a long time, it should do so by starting
// a new goroutine.
//
-// TODO(rsc): make os.File use SetFinalizer
// TODO(rsc): allow f to have (ignored) return values
//
func SetFinalizer(x, f interface{})
@@ -165,4 +150,14 @@ func GOROOT() string {
// a release tag like "release.2010-03-04".
// A trailing + indicates that the tree had local modifications
// at the time of the build.
-func Version() string { return defaultVersion }
+func Version() string {
+ return theVersion
+}
+
+// GOOS is the Go tree's operating system target:
+// one of darwin, freebsd, linux, and so on.
+const GOOS string = theGoos
+
+// GOARCH is the Go tree's architecture target:
+// 386, amd64, or arm.
+const GOARCH string = theGoarch
diff --git a/src/pkg/runtime/float.c b/src/pkg/runtime/float.c
index 5122f359a..f481519f6 100644
--- a/src/pkg/runtime/float.c
+++ b/src/pkg/runtime/float.c
@@ -9,7 +9,7 @@ static uint64 uvinf = 0x7FF0000000000000ULL;
static uint64 uvneginf = 0xFFF0000000000000ULL;
uint32
-float32tobits(float32 f)
+runtime·float32tobits(float32 f)
{
// The obvious cast-and-pointer code is technically
// not valid, and gcc miscompiles it. Use a union instead.
@@ -22,7 +22,7 @@ float32tobits(float32 f)
}
uint64
-float64tobits(float64 f)
+runtime·float64tobits(float64 f)
{
// The obvious cast-and-pointer code is technically
// not valid, and gcc miscompiles it. Use a union instead.
@@ -35,7 +35,7 @@ float64tobits(float64 f)
}
float64
-float64frombits(uint64 i)
+runtime·float64frombits(uint64 i)
{
// The obvious cast-and-pointer code is technically
// not valid, and gcc miscompiles it. Use a union instead.
@@ -48,7 +48,7 @@ float64frombits(uint64 i)
}
float32
-float32frombits(uint32 i)
+runtime·float32frombits(uint32 i)
{
// The obvious cast-and-pointer code is technically
// not valid, and gcc miscompiles it. Use a union instead.
@@ -61,11 +61,11 @@ float32frombits(uint32 i)
}
bool
-isInf(float64 f, int32 sign)
+runtime·isInf(float64 f, int32 sign)
{
uint64 x;
- x = float64tobits(f);
+ x = runtime·float64tobits(f);
if(sign == 0)
return x == uvinf || x == uvneginf;
if(sign > 0)
@@ -74,27 +74,27 @@ isInf(float64 f, int32 sign)
}
float64
-NaN(void)
+runtime·NaN(void)
{
- return float64frombits(uvnan);
+ return runtime·float64frombits(uvnan);
}
bool
-isNaN(float64 f)
+runtime·isNaN(float64 f)
{
uint64 x;
- x = float64tobits(f);
- return ((uint32)(x>>52) & 0x7FF) == 0x7FF && !isInf(f, 0);
+ x = runtime·float64tobits(f);
+ return ((uint32)(x>>52) & 0x7FF) == 0x7FF && !runtime·isInf(f, 0);
}
float64
-Inf(int32 sign)
+runtime·Inf(int32 sign)
{
if(sign >= 0)
- return float64frombits(uvinf);
+ return runtime·float64frombits(uvinf);
else
- return float64frombits(uvneginf);
+ return runtime·float64frombits(uvneginf);
}
enum
@@ -105,7 +105,7 @@ enum
};
float64
-frexp(float64 d, int32 *ep)
+runtime·frexp(float64 d, int32 *ep)
{
uint64 x;
@@ -113,36 +113,36 @@ frexp(float64 d, int32 *ep)
*ep = 0;
return 0;
}
- x = float64tobits(d);
+ x = runtime·float64tobits(d);
*ep = (int32)((x >> SHIFT) & MASK) - BIAS;
x &= ~((uint64)MASK << SHIFT);
x |= (uint64)BIAS << SHIFT;
- return float64frombits(x);
+ return runtime·float64frombits(x);
}
float64
-ldexp(float64 d, int32 e)
+runtime·ldexp(float64 d, int32 e)
{
uint64 x;
if(d == 0)
return 0;
- x = float64tobits(d);
+ x = runtime·float64tobits(d);
e += (int32)(x >> SHIFT) & MASK;
if(e <= 0)
return 0; /* underflow */
if(e >= MASK){ /* overflow */
if(d < 0)
- return Inf(-1);
- return Inf(1);
+ return runtime·Inf(-1);
+ return runtime·Inf(1);
}
x &= ~((uint64)MASK << SHIFT);
x |= (uint64)e << SHIFT;
- return float64frombits(x);
+ return runtime·float64frombits(x);
}
float64
-modf(float64 d, float64 *ip)
+runtime·modf(float64 d, float64 *ip)
{
float64 dd;
uint64 x;
@@ -150,7 +150,7 @@ modf(float64 d, float64 *ip)
if(d < 1) {
if(d < 0) {
- d = modf(-d, ip);
+ d = runtime·modf(-d, ip);
*ip = -*ip;
return -d;
}
@@ -158,7 +158,7 @@ modf(float64 d, float64 *ip)
return d;
}
- x = float64tobits(d);
+ x = runtime·float64tobits(d);
e = (int32)((x >> SHIFT) & MASK) - BIAS;
/*
@@ -166,7 +166,7 @@ modf(float64 d, float64 *ip)
*/
if(e <= 64-11)
x &= ~(((uint64)1 << (64LL-11LL-e))-1);
- dd = float64frombits(x);
+ dd = runtime·float64frombits(x);
*ip = dd;
return d - dd;
}
diff --git a/src/pkg/runtime/freebsd/386/defs.h b/src/pkg/runtime/freebsd/386/defs.h
index 76c55721f..128be9cc9 100644
--- a/src/pkg/runtime/freebsd/386/defs.h
+++ b/src/pkg/runtime/freebsd/386/defs.h
@@ -10,6 +10,7 @@ enum {
PROT_EXEC = 0x4,
MAP_ANON = 0x1000,
MAP_PRIVATE = 0x2,
+ MAP_FIXED = 0x10,
SA_SIGINFO = 0x40,
SA_RESTART = 0x2,
SA_ONSTACK = 0x1,
diff --git a/src/pkg/runtime/freebsd/386/rt0.s b/src/pkg/runtime/freebsd/386/rt0.s
index 67c5f912c..3ca981b3a 100644
--- a/src/pkg/runtime/freebsd/386/rt0.s
+++ b/src/pkg/runtime/freebsd/386/rt0.s
@@ -4,6 +4,6 @@
// Darwin and Linux use the same linkage to main
-TEXT _rt0_386_freebsd(SB),7,$0
+TEXT _rt0_386_freebsd(SB),7,$0
JMP _rt0_386(SB)
diff --git a/src/pkg/runtime/freebsd/386/signal.c b/src/pkg/runtime/freebsd/386/signal.c
index 4fc6d9e12..52b820df1 100644
--- a/src/pkg/runtime/freebsd/386/signal.c
+++ b/src/pkg/runtime/freebsd/386/signal.c
@@ -7,7 +7,7 @@
#include "signals.h"
#include "os.h"
-extern void sigtramp(void);
+extern void runtime·sigtramp(void);
typedef struct sigaction {
union {
@@ -19,33 +19,33 @@ typedef struct sigaction {
} Sigaction;
void
-dumpregs(Mcontext *r)
+runtime·dumpregs(Mcontext *r)
{
- printf("eax %x\n", r->mc_eax);
- printf("ebx %x\n", r->mc_ebx);
- printf("ecx %x\n", r->mc_ecx);
- printf("edx %x\n", r->mc_edx);
- printf("edi %x\n", r->mc_edi);
- printf("esi %x\n", r->mc_esi);
- printf("ebp %x\n", r->mc_ebp);
- printf("esp %x\n", r->mc_esp);
- printf("eip %x\n", r->mc_eip);
- printf("eflags %x\n", r->mc_eflags);
- printf("cs %x\n", r->mc_cs);
- printf("fs %x\n", r->mc_fs);
- printf("gs %x\n", r->mc_gs);
+ runtime·printf("eax %x\n", r->mc_eax);
+ runtime·printf("ebx %x\n", r->mc_ebx);
+ runtime·printf("ecx %x\n", r->mc_ecx);
+ runtime·printf("edx %x\n", r->mc_edx);
+ runtime·printf("edi %x\n", r->mc_edi);
+ runtime·printf("esi %x\n", r->mc_esi);
+ runtime·printf("ebp %x\n", r->mc_ebp);
+ runtime·printf("esp %x\n", r->mc_esp);
+ runtime·printf("eip %x\n", r->mc_eip);
+ runtime·printf("eflags %x\n", r->mc_eflags);
+ runtime·printf("cs %x\n", r->mc_cs);
+ runtime·printf("fs %x\n", r->mc_fs);
+ runtime·printf("gs %x\n", r->mc_gs);
}
String
-signame(int32 sig)
+runtime·signame(int32 sig)
{
if(sig < 0 || sig >= NSIG)
- return emptystring;
- return gostringnocopy((byte*)sigtab[sig].name);
+ return runtime·emptystring;
+ return runtime·gostringnocopy((byte*)runtime·sigtab[sig].name);
}
void
-sighandler(int32 sig, Siginfo* info, void* context)
+runtime·sighandler(int32 sig, Siginfo* info, void* context)
{
Ucontext *uc;
Mcontext *r;
@@ -55,7 +55,7 @@ sighandler(int32 sig, Siginfo* info, void* context)
uc = context;
r = &uc->uc_mcontext;
- if((gp = m->curg) != nil && (sigtab[sig].flags & SigPanic)) {
+ if((gp = m->curg) != nil && (runtime·sigtab[sig].flags & SigPanic)) {
// Make it look like a call to the signal func.
// Have to pass arguments out of band since
// augmenting the stack frame would break
@@ -64,91 +64,91 @@ sighandler(int32 sig, Siginfo* info, void* context)
gp->sigcode0 = info->si_code;
gp->sigcode1 = (uintptr)info->si_addr;
- // Only push sigpanic if r->mc_eip != 0.
+ // Only push runtime·sigpanic if r->mc_eip != 0.
// If r->mc_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 sigpanic instead.
- // (Otherwise the trace will end at sigpanic and we
+ // 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->mc_eip != 0) {
sp = (uintptr*)r->mc_esp;
*--sp = r->mc_eip;
r->mc_esp = (uintptr)sp;
}
- r->mc_eip = (uintptr)sigpanic;
+ r->mc_eip = (uintptr)runtime·sigpanic;
return;
}
- if(sigtab[sig].flags & SigQueue) {
- if(sigsend(sig) || (sigtab[sig].flags & SigIgnore))
+ if(runtime·sigtab[sig].flags & SigQueue) {
+ if(runtime·sigsend(sig) || (runtime·sigtab[sig].flags & SigIgnore))
return;
- exit(2); // SIGINT, SIGTERM, etc
+ runtime·exit(2); // SIGINT, SIGTERM, etc
}
- if(panicking) // traceback already printed
- exit(2);
- panicking = 1;
+ if(runtime·panicking) // traceback already printed
+ runtime·exit(2);
+ runtime·panicking = 1;
if(sig < 0 || sig >= NSIG)
- printf("Signal %d\n", sig);
+ runtime·printf("Signal %d\n", sig);
else
- printf("%s\n", sigtab[sig].name);
+ runtime·printf("%s\n", runtime·sigtab[sig].name);
- printf("PC=%X\n", r->mc_eip);
- printf("\n");
+ runtime·printf("PC=%X\n", r->mc_eip);
+ runtime·printf("\n");
- if(gotraceback()){
- traceback((void*)r->mc_eip, (void*)r->mc_esp, 0, m->curg);
- tracebackothers(m->curg);
- dumpregs(r);
+ if(runtime·gotraceback()){
+ runtime·traceback((void*)r->mc_eip, (void*)r->mc_esp, 0, m->curg);
+ runtime·tracebackothers(m->curg);
+ runtime·dumpregs(r);
}
- breakpoint();
- exit(2);
+ runtime·breakpoint();
+ runtime·exit(2);
}
void
-sigignore(void)
+runtime·sigignore(void)
{
}
void
-signalstack(byte *p, int32 n)
+runtime·signalstack(byte *p, int32 n)
{
Sigaltstack st;
st.ss_sp = (int8*)p;
st.ss_size = n;
st.ss_flags = 0;
- sigaltstack(&st, nil);
+ runtime·sigaltstack(&st, nil);
}
void
-initsig(int32 queue)
+runtime·initsig(int32 queue)
{
static Sigaction sa;
- siginit();
+ runtime·siginit();
int32 i;
sa.sa_flags |= SA_ONSTACK | SA_SIGINFO;
sa.sa_mask = ~0x0ull;
for(i = 0; i < NSIG; i++) {
- if(sigtab[i].flags) {
- if((sigtab[i].flags & SigQueue) != queue)
+ if(runtime·sigtab[i].flags) {
+ if((runtime·sigtab[i].flags & SigQueue) != queue)
continue;
- if(sigtab[i].flags & (SigCatch | SigQueue))
- sa.__sigaction_u.__sa_sigaction = (void*) sigtramp;
+ if(runtime·sigtab[i].flags & (SigCatch | SigQueue))
+ sa.__sigaction_u.__sa_sigaction = (void*) runtime·sigtramp;
else
- sa.__sigaction_u.__sa_sigaction = (void*) sigignore;
+ sa.__sigaction_u.__sa_sigaction = (void*) runtime·sigignore;
- if(sigtab[i].flags & SigRestart)
+ if(runtime·sigtab[i].flags & SigRestart)
sa.sa_flags |= SA_RESTART;
else
sa.sa_flags &= ~SA_RESTART;
- sigaction(i, &sa, nil);
+ runtime·sigaction(i, &sa, nil);
}
}
}
diff --git a/src/pkg/runtime/freebsd/386/sys.s b/src/pkg/runtime/freebsd/386/sys.s
index a0860db81..7110e6924 100644
--- a/src/pkg/runtime/freebsd/386/sys.s
+++ b/src/pkg/runtime/freebsd/386/sys.s
@@ -8,17 +8,17 @@
#include "386/asm.h"
-TEXT sys_umtx_op(SB),7,$-4
+TEXT runtime·sys_umtx_op(SB),7,$-4
MOVL $454, AX
INT $0x80
RET
-TEXT thr_new(SB),7,$-4
+TEXT runtime·thr_new(SB),7,$-4
MOVL $455, AX
INT $0x80
RET
-TEXT thr_start(SB),7,$0
+TEXT runtime·thr_start(SB),7,$0
MOVL mm+0(FP), AX
MOVL m_g0(AX), BX
LEAL m_tls(AX), BP
@@ -28,7 +28,7 @@ TEXT thr_start(SB),7,$0
PUSHL $32
PUSHL BP
PUSHL DI
- CALL setldt(SB)
+ CALL runtime·setldt(SB)
POPL AX
POPL AX
POPL AX
@@ -37,43 +37,57 @@ TEXT thr_start(SB),7,$0
MOVL BX, g(CX)
MOVL AX, m(CX)
- CALL stackcheck(SB) // smashes AX
- CALL mstart(SB)
+ CALL runtime·stackcheck(SB) // smashes AX
+ CALL runtime·mstart(SB)
MOVL 0, AX // crash (not reached)
// Exit the entire program (like C exit)
-TEXT exit(SB),7,$-4
+TEXT runtime·exit(SB),7,$-4
MOVL $1, AX
INT $0x80
- CALL notok(SB)
+ CALL runtime·notok(SB)
RET
-TEXT exit1(SB),7,$-4
+TEXT runtime·exit1(SB),7,$-4
MOVL $431, AX
INT $0x80
JAE 2(PC)
- CALL notok(SB)
+ CALL runtime·notok(SB)
RET
-TEXT write(SB),7,$-4
+TEXT runtime·write(SB),7,$-4
MOVL $4, AX
INT $0x80
- JAE 2(PC)
- CALL notok(SB)
RET
-TEXT notok(SB),7,$0
+TEXT runtime·notok(SB),7,$0
MOVL $0xf1, 0xf1
RET
-TEXT ·mmap(SB),7,$-4
+TEXT runtime·mmap(SB),7,$32
+ LEAL arg0+0(FP), SI
+ LEAL 4(SP), DI
+ CLD
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVSL
+ MOVL $0, AX // top 64 bits of file offset
+ STOSL
MOVL $477, AX
INT $0x80
+ RET
+
+TEXT runtime·munmap(SB),7,$-4
+ MOVL $73, AX
+ INT $0x80
JAE 2(PC)
- CALL notok(SB)
+ CALL runtime·notok(SB)
RET
-TEXT gettime(SB), 7, $32
+TEXT runtime·gettime(SB), 7, $32
MOVL $116, AX
LEAL 12(SP), BX
MOVL BX, 4(SP)
@@ -90,14 +104,14 @@ TEXT gettime(SB), 7, $32
MOVL BX, (DI)
RET
-TEXT sigaction(SB),7,$-4
+TEXT runtime·sigaction(SB),7,$-4
MOVL $416, AX
INT $0x80
JAE 2(PC)
- CALL notok(SB)
+ CALL runtime·notok(SB)
RET
-TEXT sigtramp(SB),7,$40
+TEXT runtime·sigtramp(SB),7,$40
// g = m->gsignal
get_tls(DX)
MOVL m(DX), BP
@@ -111,7 +125,7 @@ TEXT sigtramp(SB),7,$40
MOVL AX, 0(SP)
MOVL BX, 4(SP)
MOVL CX, 8(SP)
- CALL sighandler(SB)
+ CALL runtime·sighandler(SB)
// g = m->curg
get_tls(DX)
@@ -125,14 +139,14 @@ TEXT sigtramp(SB),7,$40
MOVL AX, 4(SP)
MOVL $417, AX // sigreturn(ucontext)
INT $0x80
- CALL notok(SB)
+ CALL runtime·notok(SB)
RET
-TEXT sigaltstack(SB),7,$0
+TEXT runtime·sigaltstack(SB),7,$0
MOVL $53, AX
INT $0x80
JAE 2(PC)
- CALL notok(SB)
+ CALL runtime·notok(SB)
RET
/*
@@ -152,7 +166,7 @@ int i386_set_ldt(int, const union ldt_entry *, int);
*/
// setldt(int entry, int address, int limit)
-TEXT setldt(SB),7,$32
+TEXT runtime·setldt(SB),7,$32
MOVL address+4(FP), BX // aka base
// see comment in linux/386/sys.s; freebsd is similar
ADDL $0x8, BX
@@ -177,7 +191,7 @@ TEXT setldt(SB),7,$32
MOVL $0xffffffff, 0(SP) // auto-allocate entry and return in AX
MOVL AX, 4(SP)
MOVL $1, 8(SP)
- CALL i386_set_ldt(SB)
+ CALL runtime·i386_set_ldt(SB)
// compute segment selector - (entry*8+7)
SHLL $3, AX
@@ -185,7 +199,7 @@ TEXT setldt(SB),7,$32
MOVW AX, GS
RET
-TEXT i386_set_ldt(SB),7,$16
+TEXT runtime·i386_set_ldt(SB),7,$16
LEAL args+0(FP), AX // 0(FP) == 4(SP) before SP got moved
MOVL $0, 0(SP) // syscall gap
MOVL $1, 4(SP)
@@ -197,4 +211,4 @@ TEXT i386_set_ldt(SB),7,$16
INT $3
RET
-GLOBL tlsoffset(SB),$4
+GLOBL runtime·tlsoffset(SB),$4
diff --git a/src/pkg/runtime/freebsd/amd64/defs.h b/src/pkg/runtime/freebsd/amd64/defs.h
index 18b68b355..2a295a479 100644
--- a/src/pkg/runtime/freebsd/amd64/defs.h
+++ b/src/pkg/runtime/freebsd/amd64/defs.h
@@ -10,6 +10,7 @@ enum {
PROT_EXEC = 0x4,
MAP_ANON = 0x1000,
MAP_PRIVATE = 0x2,
+ MAP_FIXED = 0x10,
SA_SIGINFO = 0x40,
SA_RESTART = 0x2,
SA_ONSTACK = 0x1,
diff --git a/src/pkg/runtime/freebsd/amd64/rt0.s b/src/pkg/runtime/freebsd/amd64/rt0.s
index 7903b7ccc..5d2eeeeff 100644
--- a/src/pkg/runtime/freebsd/amd64/rt0.s
+++ b/src/pkg/runtime/freebsd/amd64/rt0.s
@@ -4,6 +4,6 @@
// Darwin and Linux use the same linkage to main
-TEXT _rt0_amd64_freebsd(SB),7,$-8
+TEXT _rt0_amd64_freebsd(SB),7,$-8
MOVQ $_rt0_amd64(SB), DX
JMP DX
diff --git a/src/pkg/runtime/freebsd/amd64/signal.c b/src/pkg/runtime/freebsd/amd64/signal.c
index 57bfcfb55..c74ddad0b 100644
--- a/src/pkg/runtime/freebsd/amd64/signal.c
+++ b/src/pkg/runtime/freebsd/amd64/signal.c
@@ -7,7 +7,7 @@
#include "signals.h"
#include "os.h"
-extern void sigtramp(void);
+extern void runtime·sigtramp(void);
typedef struct sigaction {
union {
@@ -19,41 +19,41 @@ typedef struct sigaction {
} Sigaction;
void
-dumpregs(Mcontext *r)
+runtime·dumpregs(Mcontext *r)
{
- printf("rax %X\n", r->mc_rax);
- printf("rbx %X\n", r->mc_rbx);
- printf("rcx %X\n", r->mc_rcx);
- printf("rdx %X\n", r->mc_rdx);
- printf("rdi %X\n", r->mc_rdi);
- printf("rsi %X\n", r->mc_rsi);
- printf("rbp %X\n", r->mc_rbp);
- printf("rsp %X\n", r->mc_rsp);
- printf("r8 %X\n", r->mc_r8 );
- printf("r9 %X\n", r->mc_r9 );
- printf("r10 %X\n", r->mc_r10);
- printf("r11 %X\n", r->mc_r11);
- printf("r12 %X\n", r->mc_r12);
- printf("r13 %X\n", r->mc_r13);
- printf("r14 %X\n", r->mc_r14);
- printf("r15 %X\n", r->mc_r15);
- printf("rip %X\n", r->mc_rip);
- printf("rflags %X\n", r->mc_flags);
- printf("cs %X\n", r->mc_cs);
- printf("fs %X\n", r->mc_fs);
- printf("gs %X\n", r->mc_gs);
+ runtime·printf("rax %X\n", r->mc_rax);
+ runtime·printf("rbx %X\n", r->mc_rbx);
+ runtime·printf("rcx %X\n", r->mc_rcx);
+ runtime·printf("rdx %X\n", r->mc_rdx);
+ runtime·printf("rdi %X\n", r->mc_rdi);
+ runtime·printf("rsi %X\n", r->mc_rsi);
+ runtime·printf("rbp %X\n", r->mc_rbp);
+ runtime·printf("rsp %X\n", r->mc_rsp);
+ runtime·printf("r8 %X\n", r->mc_r8 );
+ runtime·printf("r9 %X\n", r->mc_r9 );
+ runtime·printf("r10 %X\n", r->mc_r10);
+ runtime·printf("r11 %X\n", r->mc_r11);
+ runtime·printf("r12 %X\n", r->mc_r12);
+ runtime·printf("r13 %X\n", r->mc_r13);
+ runtime·printf("r14 %X\n", r->mc_r14);
+ runtime·printf("r15 %X\n", r->mc_r15);
+ runtime·printf("rip %X\n", r->mc_rip);
+ runtime·printf("rflags %X\n", r->mc_flags);
+ runtime·printf("cs %X\n", r->mc_cs);
+ runtime·printf("fs %X\n", r->mc_fs);
+ runtime·printf("gs %X\n", r->mc_gs);
}
String
-signame(int32 sig)
+runtime·signame(int32 sig)
{
if(sig < 0 || sig >= NSIG)
- return emptystring;
- return gostringnocopy((byte*)sigtab[sig].name);
+ return runtime·emptystring;
+ return runtime·gostringnocopy((byte*)runtime·sigtab[sig].name);
}
void
-sighandler(int32 sig, Siginfo* info, void* context)
+runtime·sighandler(int32 sig, Siginfo* info, void* context)
{
Ucontext *uc;
Mcontext *r;
@@ -63,7 +63,7 @@ sighandler(int32 sig, Siginfo* info, void* context)
uc = context;
r = &uc->uc_mcontext;
- if((gp = m->curg) != nil && (sigtab[sig].flags & SigPanic)) {
+ if((gp = m->curg) != nil && (runtime·sigtab[sig].flags & SigPanic)) {
// Make it look like a call to the signal func.
// Have to pass arguments out of band since
// augmenting the stack frame would break
@@ -72,91 +72,91 @@ sighandler(int32 sig, Siginfo* info, void* context)
gp->sigcode0 = info->si_code;
gp->sigcode1 = (uintptr)info->si_addr;
- // Only push sigpanic if r->mc_rip != 0.
+ // 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 sigpanic instead.
- // (Otherwise the trace will end at sigpanic and we
+ // 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->mc_rip != 0) {
sp = (uintptr*)r->mc_rsp;
*--sp = r->mc_rip;
r->mc_rsp = (uintptr)sp;
}
- r->mc_rip = (uintptr)sigpanic;
+ r->mc_rip = (uintptr)runtime·sigpanic;
return;
}
- if(sigtab[sig].flags & SigQueue) {
- if(sigsend(sig) || (sigtab[sig].flags & SigIgnore))
+ if(runtime·sigtab[sig].flags & SigQueue) {
+ if(runtime·sigsend(sig) || (runtime·sigtab[sig].flags & SigIgnore))
return;
- exit(2); // SIGINT, SIGTERM, etc
+ runtime·exit(2); // SIGINT, SIGTERM, etc
}
- if(panicking) // traceback already printed
- exit(2);
- panicking = 1;
+ if(runtime·panicking) // traceback already printed
+ runtime·exit(2);
+ runtime·panicking = 1;
if(sig < 0 || sig >= NSIG)
- printf("Signal %d\n", sig);
+ runtime·printf("Signal %d\n", sig);
else
- printf("%s\n", sigtab[sig].name);
+ runtime·printf("%s\n", runtime·sigtab[sig].name);
- printf("PC=%X\n", r->mc_rip);
- printf("\n");
+ runtime·printf("PC=%X\n", r->mc_rip);
+ runtime·printf("\n");
- if(gotraceback()){
- traceback((void*)r->mc_rip, (void*)r->mc_rsp, 0, (void*)r->mc_r15);
- tracebackothers((void*)r->mc_r15);
- dumpregs(r);
+ if(runtime·gotraceback()){
+ runtime·traceback((void*)r->mc_rip, (void*)r->mc_rsp, 0, g);
+ runtime·tracebackothers(g);
+ runtime·dumpregs(r);
}
- breakpoint();
- exit(2);
+ runtime·breakpoint();
+ runtime·exit(2);
}
void
-sigignore(void)
+runtime·sigignore(void)
{
}
void
-signalstack(byte *p, int32 n)
+runtime·signalstack(byte *p, int32 n)
{
Sigaltstack st;
st.ss_sp = (int8*)p;
st.ss_size = n;
st.ss_flags = 0;
- sigaltstack(&st, nil);
+ runtime·sigaltstack(&st, nil);
}
void
-initsig(int32 queue)
+runtime·initsig(int32 queue)
{
static Sigaction sa;
- siginit();
+ runtime·siginit();
int32 i;
sa.sa_flags |= SA_ONSTACK | SA_SIGINFO;
sa.sa_mask = ~0x0ull;
for(i = 0; i < NSIG; i++) {
- if(sigtab[i].flags) {
- if((sigtab[i].flags & SigQueue) != queue)
+ if(runtime·sigtab[i].flags) {
+ if((runtime·sigtab[i].flags & SigQueue) != queue)
continue;
- if(sigtab[i].flags & (SigCatch | SigQueue))
- sa.__sigaction_u.__sa_sigaction = (void*) sigtramp;
+ if(runtime·sigtab[i].flags & (SigCatch | SigQueue))
+ sa.__sigaction_u.__sa_sigaction = (void*) runtime·sigtramp;
else
- sa.__sigaction_u.__sa_sigaction = (void*) sigignore;
+ sa.__sigaction_u.__sa_sigaction = (void*) runtime·sigignore;
- if(sigtab[i].flags & SigRestart)
+ if(runtime·sigtab[i].flags & SigRestart)
sa.sa_flags |= SA_RESTART;
else
sa.sa_flags &= ~SA_RESTART;
- sigaction(i, &sa, nil);
+ runtime·sigaction(i, &sa, nil);
}
}
}
diff --git a/src/pkg/runtime/freebsd/amd64/sys.s b/src/pkg/runtime/freebsd/amd64/sys.s
index 604b763ab..b9cf3832d 100644
--- a/src/pkg/runtime/freebsd/amd64/sys.s
+++ b/src/pkg/runtime/freebsd/amd64/sys.s
@@ -8,7 +8,7 @@
#include "amd64/asm.h"
-TEXT sys_umtx_op(SB),7,$0
+TEXT runtime·sys_umtx_op(SB),7,$0
MOVQ 8(SP), DI
MOVL 16(SP), SI
MOVL 20(SP), DX
@@ -18,47 +18,54 @@ TEXT sys_umtx_op(SB),7,$0
SYSCALL
RET
-TEXT thr_new(SB),7,$0
+TEXT runtime·thr_new(SB),7,$0
MOVQ 8(SP), DI
MOVQ 16(SP), SI
MOVL $455, AX
SYSCALL
RET
-TEXT thr_start(SB),7,$0
- MOVQ DI, m
- MOVQ m_g0(m), g
- CALL stackcheck(SB)
- CALL mstart(SB)
- MOVQ 0, AX // crash (not reached)
+TEXT runtime·thr_start(SB),7,$0
+ MOVQ DI, R13 // m
+
+ // set up FS to point at m->tls
+ LEAQ m_tls(R13), DI
+ CALL runtime·settls(SB) // smashes DI
+ // set up m, g
+ get_tls(CX)
+ MOVQ R13, m(CX)
+ MOVQ m_g0(R13), DI
+ MOVQ DI, g(CX)
+
+ CALL runtime·stackcheck(SB)
+ CALL runtime·mstart(SB)
+ MOVQ 0, AX // crash (not reached)
// Exit the entire program (like C exit)
-TEXT exit(SB),7,$-8
+TEXT runtime·exit(SB),7,$-8
MOVL 8(SP), DI // arg 1 exit status
MOVL $1, AX
SYSCALL
- CALL notok(SB)
+ CALL runtime·notok(SB)
RET
-TEXT exit1(SB),7,$-8
+TEXT runtime·exit1(SB),7,$-8
MOVQ 8(SP), DI // arg 1 exit status
MOVL $431, AX
SYSCALL
- CALL notok(SB)
+ CALL runtime·notok(SB)
RET
-TEXT write(SB),7,$-8
+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 count
MOVL $4, AX
SYSCALL
- JCC 2(PC)
- CALL notok(SB)
RET
-TEXT gettime(SB), 7, $32
+TEXT runtime·gettime(SB), 7, $32
MOVL $116, AX
LEAQ 8(SP), DI
MOVQ $0, SI
@@ -73,25 +80,28 @@ TEXT gettime(SB), 7, $32
MOVL BX, (DI)
RET
-TEXT sigaction(SB),7,$-8
+TEXT runtime·sigaction(SB),7,$-8
MOVL 8(SP), DI // arg 1 sig
MOVQ 16(SP), SI // arg 2 act
MOVQ 24(SP), DX // arg 3 oact
MOVL $416, AX
SYSCALL
JCC 2(PC)
- CALL notok(SB)
+ CALL runtime·notok(SB)
RET
-TEXT sigtramp(SB),7,$24-16
- MOVQ m_gsignal(m), g
+TEXT runtime·sigtramp(SB),7,$24-16
+ get_tls(CX)
+ MOVQ m(CX), AX
+ MOVQ m_gsignal(AX), AX
+ MOVQ AX, g(CX)
MOVQ DI, 0(SP)
MOVQ SI, 8(SP)
MOVQ DX, 16(SP)
- CALL sighandler(SB)
+ CALL runtime·sighandler(SB)
RET
-TEXT ·mmap(SB),7,$0
+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
@@ -100,20 +110,39 @@ TEXT ·mmap(SB),7,$0
MOVL 36(SP), R9 // arg 6 offset
MOVL $477, AX
SYSCALL
+ RET
+
+TEXT runtime·munmap(SB),7,$0
+ MOVQ 8(SP), DI // arg 1 addr
+ MOVQ 16(SP), SI // arg 2 len
+ MOVL $73, AX
+ SYSCALL
JCC 2(PC)
- CALL notok(SB)
+ CALL runtime·notok(SB)
RET
-TEXT notok(SB),7,$-8
+TEXT runtime·notok(SB),7,$-8
MOVL $0xf1, BP
MOVQ BP, (BP)
RET
-TEXT sigaltstack(SB),7,$-8
+TEXT runtime·sigaltstack(SB),7,$-8
MOVQ new+8(SP), DI
MOVQ old+16(SP), SI
MOVQ $53, AX
SYSCALL
JCC 2(PC)
- CALL notok(SB)
+ CALL runtime·notok(SB)
+ RET
+
+// set tls base to DI
+TEXT runtime·settls(SB),7,$8
+ ADDQ $16, DI // adjust for ELF: wants to use -16(FS) and -8(FS) for g and m
+ MOVQ DI, 0(SP)
+ MOVQ SP, SI
+ MOVQ $129, DI // AMD64_SET_FSBASE
+ MOVQ $165, AX // sysarch
+ SYSCALL
+ JCC 2(PC)
+ CALL runtime·notok(SB)
RET
diff --git a/src/pkg/runtime/freebsd/defs.c b/src/pkg/runtime/freebsd/defs.c
index 36e69093e..32a80f475 100644
--- a/src/pkg/runtime/freebsd/defs.c
+++ b/src/pkg/runtime/freebsd/defs.c
@@ -28,6 +28,7 @@ enum {
$MAP_ANON = MAP_ANON,
$MAP_PRIVATE = MAP_PRIVATE,
+ $MAP_FIXED = MAP_FIXED,
$SA_SIGINFO = SA_SIGINFO,
$SA_RESTART = SA_RESTART,
diff --git a/src/pkg/runtime/freebsd/mem.c b/src/pkg/runtime/freebsd/mem.c
index 52e351a7d..7fb2c2807 100644
--- a/src/pkg/runtime/freebsd/mem.c
+++ b/src/pkg/runtime/freebsd/mem.c
@@ -4,14 +4,21 @@
#include "malloc.h"
void*
-SysAlloc(uintptr n)
+runtime·SysAlloc(uintptr n)
{
+ void *v;
+
mstats.sys += n;
- return runtime_mmap(nil, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, -1, 0);
+ v = runtime·mmap(nil, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, -1, 0);
+ if(v < (void*)4096) {
+ runtime·printf("mmap: errno=%p\n", v);
+ runtime·throw("mmap");
+ }
+ return v;
}
void
-SysUnused(void *v, uintptr n)
+runtime·SysUnused(void *v, uintptr n)
{
USED(v);
USED(n);
@@ -19,10 +26,14 @@ SysUnused(void *v, uintptr n)
}
void
-SysFree(void *v, uintptr n)
+runtime·SysFree(void *v, uintptr n)
{
- USED(v);
- USED(n);
- // TODO(rsc): call munmap
+ mstats.sys -= n;
+ runtime·munmap(v, n);
}
+
+void
+runtime·SysMemInit(void)
+{
+}
diff --git a/src/pkg/runtime/freebsd/os.h b/src/pkg/runtime/freebsd/os.h
index 47bf7d56f..455355bc7 100644
--- a/src/pkg/runtime/freebsd/os.h
+++ b/src/pkg/runtime/freebsd/os.h
@@ -1,5 +1,5 @@
-int32 thr_new(ThrParam*, int32);
-void sigpanic(void);
-void sigaltstack(Sigaltstack*, Sigaltstack*);
+int32 runtime·thr_new(ThrParam*, int32);
+void runtime·sigpanic(void);
+void runtime·sigaltstack(Sigaltstack*, Sigaltstack*);
struct sigaction;
-void sigaction(int32, struct sigaction*, struct sigaction*);
+void runtime·sigaction(int32, struct sigaction*, struct sigaction*);
diff --git a/src/pkg/runtime/freebsd/runtime_defs.go b/src/pkg/runtime/freebsd/runtime_defs.go
new file mode 100644
index 000000000..86de13316
--- /dev/null
+++ b/src/pkg/runtime/freebsd/runtime_defs.go
@@ -0,0 +1,14 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// OS-Specific Go definitions of internal structures. Master is runtime.h
+
+package runtime
+
+type lock struct {
+ key uint32
+ sema uint32
+}
+
+type note lock
diff --git a/src/pkg/runtime/freebsd/signals.h b/src/pkg/runtime/freebsd/signals.h
index 0c41daf84..63a84671d 100644
--- a/src/pkg/runtime/freebsd/signals.h
+++ b/src/pkg/runtime/freebsd/signals.h
@@ -8,7 +8,7 @@
#define Q SigQueue
#define P SigPanic
-SigTab sigtab[] = {
+SigTab runtime·sigtab[] = {
/* 0 */ 0, "SIGNONE: no trap",
/* 1 */ Q+R, "SIGHUP: terminal line hangup",
/* 2 */ Q+R, "SIGINT: interrupt",
diff --git a/src/pkg/runtime/freebsd/thread.c b/src/pkg/runtime/freebsd/thread.c
index 334043312..9bd883833 100644
--- a/src/pkg/runtime/freebsd/thread.c
+++ b/src/pkg/runtime/freebsd/thread.c
@@ -5,8 +5,8 @@
#include "defs.h"
#include "os.h"
-extern SigTab sigtab[];
-extern int32 sys_umtx_op(uint32*, int32, uint32, void*, void*);
+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.
@@ -16,11 +16,11 @@ umtx_wait(uint32 *addr, uint32 val)
{
int32 ret;
- ret = sys_umtx_op(addr, UMTX_OP_WAIT, val, nil, nil);
+ ret = runtime·sys_umtx_op(addr, UMTX_OP_WAIT, val, nil, nil);
if(ret >= 0 || ret == -EINTR)
return;
- printf("umtx_wait addr=%p val=%d ret=%d\n", addr, val, ret);
+ runtime·printf("umtx_wait addr=%p val=%d ret=%d\n", addr, val, ret);
*(int32*)0x1005 = 0x1005;
}
@@ -29,11 +29,11 @@ umtx_wake(uint32 *addr)
{
int32 ret;
- ret = sys_umtx_op(addr, UMTX_OP_WAKE, 1, nil, nil);
+ ret = runtime·sys_umtx_op(addr, UMTX_OP_WAKE, 1, nil, nil);
if(ret >= 0)
return;
- printf("umtx_wake addr=%p ret=%d\n", addr, ret);
+ runtime·printf("umtx_wake addr=%p ret=%d\n", addr, ret);
*(int32*)0x1006 = 0x1006;
}
@@ -46,12 +46,12 @@ umtx_lock(Lock *l)
again:
v = l->key;
if((v&1) == 0){
- if(cas(&l->key, v, v|1))
+ if(runtime·cas(&l->key, v, v|1))
return;
goto again;
}
- if(!cas(&l->key, v, v+2))
+ if(!runtime·cas(&l->key, v, v+2))
goto again;
umtx_wait(&l->key, v+2);
@@ -59,8 +59,8 @@ again:
for(;;){
v = l->key;
if(v < 2)
- throw("bad lock key");
- if(cas(&l->key, v, v-2))
+ runtime·throw("bad lock key");
+ if(runtime·cas(&l->key, v, v-2))
break;
}
@@ -75,8 +75,8 @@ umtx_unlock(Lock *l)
again:
v = l->key;
if((v&1) == 0)
- throw("unlock of unlocked lock");
- if(!cas(&l->key, v, v&~1))
+ runtime·throw("unlock of unlocked lock");
+ if(!runtime·cas(&l->key, v, v&~1))
goto again;
if(v&~1)
@@ -84,53 +84,53 @@ again:
}
void
-lock(Lock *l)
+runtime·lock(Lock *l)
{
if(m->locks < 0)
- throw("lock count");
+ runtime·throw("lock count");
m->locks++;
umtx_lock(l);
}
void
-unlock(Lock *l)
+runtime·unlock(Lock *l)
{
m->locks--;
if(m->locks < 0)
- throw("lock count");
+ runtime·throw("lock count");
umtx_unlock(l);
}
void
-destroylock(Lock*)
+runtime·destroylock(Lock*)
{
}
// Event notifications.
void
-noteclear(Note *n)
+runtime·noteclear(Note *n)
{
n->lock.key = 0;
umtx_lock(&n->lock);
}
void
-notesleep(Note *n)
+runtime·notesleep(Note *n)
{
umtx_lock(&n->lock);
umtx_unlock(&n->lock);
}
void
-notewakeup(Note *n)
+runtime·notewakeup(Note *n)
{
umtx_unlock(&n->lock);
}
-void thr_start(void*);
+void runtime·thr_start(void*);
void
-newosproc(M *m, G *g, void *stk, void (*fn)(void))
+runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void))
{
ThrParam param;
@@ -138,13 +138,13 @@ newosproc(M *m, G *g, void *stk, void (*fn)(void))
USED(g); // thr_start assumes g == m->g0
if(0){
- printf("newosproc stk=%p m=%p g=%p fn=%p id=%d/%d ostk=%p\n",
+ 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);
+ runtime·memclr((byte*)&param, sizeof param);
- param.start_func = thr_start;
+ param.start_func = runtime·thr_start;
param.arg = m;
param.stack_base = (int8*)g->stackbase;
param.stack_size = (byte*)stk - (byte*)g->stackbase;
@@ -155,43 +155,51 @@ newosproc(M *m, G *g, void *stk, void (*fn)(void))
m->tls[0] = m->id; // so 386 asm can find it
- thr_new(&param, sizeof param);
+ runtime·thr_new(&param, sizeof param);
}
void
-osinit(void)
+runtime·osinit(void)
{
}
+void
+runtime·goenvs(void)
+{
+ runtime·goenvs_unix();
+}
+
// Called to initialize a new m (including the bootstrap m).
void
-minit(void)
+runtime·minit(void)
{
// Initialize signal handling
- m->gsignal = malg(32*1024);
- signalstack(m->gsignal->stackguard, 32*1024);
+ m->gsignal = runtime·malg(32*1024);
+ runtime·signalstack(m->gsignal->stackguard, 32*1024);
}
void
-sigpanic(void)
+runtime·sigpanic(void)
{
switch(g->sig) {
case SIGBUS:
if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000)
- panicstring("invalid memory address or nil pointer dereference");
- break;
+ 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->sigcode1 < 0x1000)
- panicstring("invalid memory address or nil pointer dereference");
- break;
+ 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:
- panicstring("integer divide by zero");
+ runtime·panicstring("integer divide by zero");
case FPE_INTOVF:
- panicstring("integer overflow");
+ runtime·panicstring("integer overflow");
}
- panicstring("floating point error");
+ runtime·panicstring("floating point error");
}
- panicstring(sigtab[g->sig].name);
+ runtime·panicstring(runtime·sigtab[g->sig].name);
}
diff --git a/src/pkg/runtime/goc2c.c b/src/pkg/runtime/goc2c.c
index a4489213f..826ceff3a 100644
--- a/src/pkg/runtime/goc2c.c
+++ b/src/pkg/runtime/goc2c.c
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-/* Translate a .cgo file into a .c file. A .cgo file is a combination
+/* Translate a .goc file into a .c file. A .goc file is a combination
of a limited form of Go with C. */
/*
@@ -28,7 +28,7 @@ static int gcc;
/* File and line number */
static const char *file;
-static unsigned int lineno;
+static unsigned int lineno = 1;
/* List of names and types. */
struct params {
@@ -669,7 +669,7 @@ process_file(void)
static void
usage(void)
{
- fprintf(stderr, "Usage: cgo2c [--6g | --gc] [file]\n");
+ fprintf(stderr, "Usage: goc2c [--6g | --gc] [file]\n");
exit(1);
}
diff --git a/src/pkg/runtime/hashmap.c b/src/pkg/runtime/hashmap.c
index eb98ab54a..a03202ed6 100644
--- a/src/pkg/runtime/hashmap.c
+++ b/src/pkg/runtime/hashmap.c
@@ -139,7 +139,7 @@ hash_init (struct hash *h,
if(datasize < sizeof (void *))
datasize = sizeof (void *);
- datasize = rnd(datasize, sizeof (void *));
+ datasize = runtime·rnd(datasize, sizeof (void *));
init_sizes (hint, &init_power, &max_power);
h->datasize = datasize;
h->max_power = max_power;
@@ -289,7 +289,7 @@ hash_grow (struct hash *h, struct hash_subtable **pst, int32 flags)
free (old_st);
}
-int32
+static int32
hash_lookup (struct hash *h, void *data, void **pres)
{
int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]);
@@ -330,7 +330,7 @@ hash_lookup (struct hash *h, void *data, void **pres)
return (0);
}
-int32
+static int32
hash_remove (struct hash *h, void *data, void *arg)
{
int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]);
@@ -454,7 +454,7 @@ hash_insert_internal (struct hash_subtable **pst, int32 flags, hash_hash_t hash,
}
}
-int32
+static int32
hash_insert (struct hash *h, void *data, void **pres)
{
int32 rc = hash_insert_internal (&h->st, 0, (*h->data_hash) (h->keysize, data), h, data, pres);
@@ -463,7 +463,7 @@ hash_insert (struct hash *h, void *data, void **pres)
return (rc);
}
-uint32
+static uint32
hash_count (struct hash *h)
{
return (h->count);
@@ -503,7 +503,7 @@ iter_restart (struct hash_iter *it, struct hash_subtable *st, int32 used)
sub->e = e;
}
-void *
+static void *
hash_next (struct hash_iter *it)
{
int32 elemsize = it->elemsize;
@@ -570,7 +570,7 @@ hash_next (struct hash_iter *it)
}
}
-void
+static void
hash_iter_init (struct hash *h, struct hash_iter *it)
{
it->elemsize = h->datasize + offsetof (struct hash_entry, data[0]);
@@ -606,7 +606,7 @@ clean_st (struct hash_subtable *st, int32 *slots, int32 *used)
*used += lused;
}
-void
+static void
hash_destroy (struct hash *h)
{
int32 slots = 0;
@@ -645,7 +645,7 @@ hash_visit_internal (struct hash_subtable *st,
}
}
-void
+static void
hash_visit (struct hash *h, void (*data_visit) (void *arg, int32 level, void *data), void *arg)
{
hash_visit_internal (h->st, 0, 0, data_visit, arg);
@@ -692,31 +692,31 @@ static int32 debug = 0;
// makemap(key, val *Type, hint uint32) (hmap *map[any]any);
Hmap*
-makemap(Type *key, Type *val, int64 hint)
+runtime·makemap_c(Type *key, Type *val, int64 hint)
{
Hmap *h;
int32 keyalg, valalg, keysize, valsize, valsize_in_hash;
void (*data_del)(uint32, void*, void*);
if(hint < 0 || (int32)hint != hint)
- panicstring("makemap: size out of range");
+ runtime·panicstring("makemap: size out of range");
keyalg = key->alg;
valalg = val->alg;
keysize = key->size;
valsize = val->size;
- if(keyalg >= nelem(algarray) || algarray[keyalg].hash == nohash) {
- printf("map(keyalg=%d)\n", keyalg);
- throw("runtime.makemap: unsupported map key type");
+ if(keyalg >= nelem(runtime·algarray) || runtime·algarray[keyalg].hash == runtime·nohash) {
+ runtime·printf("map(keyalg=%d)\n", keyalg);
+ runtime·throw("runtime.makemap: unsupported map key type");
}
- if(valalg >= nelem(algarray)) {
- printf("map(valalg=%d)\n", valalg);
- throw("runtime.makemap: unsupported map value type");
+ if(valalg >= nelem(runtime·algarray)) {
+ runtime·printf("map(valalg=%d)\n", valalg);
+ runtime·throw("runtime.makemap: unsupported map value type");
}
- h = mal(sizeof(*h));
+ h = runtime·mal(sizeof(*h));
valsize_in_hash = valsize;
data_del = donothing;
@@ -730,38 +730,38 @@ makemap(Type *key, Type *val, int64 hint)
// might remove in the future and just assume datavo == keysize.
h->datavo = keysize;
if(valsize_in_hash >= sizeof(void*))
- h->datavo = rnd(keysize, sizeof(void*));
+ h->datavo = runtime·rnd(keysize, sizeof(void*));
hash_init(h, h->datavo+valsize_in_hash,
- algarray[keyalg].hash,
- algarray[keyalg].equal,
+ runtime·algarray[keyalg].hash,
+ runtime·algarray[keyalg].equal,
data_del,
hint);
h->keysize = keysize;
h->valsize = valsize;
- h->keyalg = &algarray[keyalg];
- h->valalg = &algarray[valalg];
+ h->keyalg = &runtime·algarray[keyalg];
+ h->valalg = &runtime·algarray[valalg];
// these calculations are compiler dependent.
// figure out offsets of map call arguments.
// func() (key, val)
- h->ko0 = rnd(sizeof(h), Structrnd);
- h->vo0 = rnd(h->ko0+keysize, val->align);
+ h->ko0 = runtime·rnd(sizeof(h), Structrnd);
+ h->vo0 = runtime·rnd(h->ko0+keysize, val->align);
// func(key) (val[, pres])
- h->ko1 = rnd(sizeof(h), key->align);
- h->vo1 = rnd(h->ko1+keysize, Structrnd);
- h->po1 = rnd(h->vo1+valsize, 1);
+ h->ko1 = runtime·rnd(sizeof(h), key->align);
+ h->vo1 = runtime·rnd(h->ko1+keysize, Structrnd);
+ h->po1 = runtime·rnd(h->vo1+valsize, 1);
// func(key, val[, pres])
- h->ko2 = rnd(sizeof(h), key->align);
- h->vo2 = rnd(h->ko2+keysize, val->align);
- h->po2 = rnd(h->vo2+valsize, 1);
+ h->ko2 = runtime·rnd(sizeof(h), key->align);
+ h->vo2 = runtime·rnd(h->ko2+keysize, val->align);
+ h->po2 = runtime·rnd(h->vo2+valsize, 1);
if(debug) {
- printf("makemap: map=%p; keysize=%d; valsize=%d; keyalg=%d; valalg=%d; offsets=%d,%d; %d,%d,%d; %d,%d,%d\n",
+ 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);
}
@@ -770,19 +770,19 @@ makemap(Type *key, Type *val, int64 hint)
// makemap(key, val *Type, hint int64) (hmap *map[any]any);
void
-·makemap(Type *key, Type *val, int64 hint, Hmap *ret)
+runtime·makemap(Type *key, Type *val, int64 hint, Hmap *ret)
{
- ret = makemap(key, val, hint);
+ ret = runtime·makemap_c(key, val, hint);
FLUSH(&ret);
}
void
-mapaccess(Hmap *h, byte *ak, byte *av, bool *pres)
+runtime·mapaccess(Hmap *h, byte *ak, byte *av, bool *pres)
{
byte *res;
- if(gcwaiting)
- gosched();
+ if(runtime·gcwaiting)
+ runtime·gosched();
res = nil;
if(hash_lookup(h, ak, (void**)&res)) {
@@ -797,7 +797,7 @@ mapaccess(Hmap *h, byte *ak, byte *av, bool *pres)
// mapaccess1(hmap *map[any]any, key any) (val any);
#pragma textflag 7
void
-·mapaccess1(Hmap *h, ...)
+runtime·mapaccess1(Hmap *h, ...)
{
byte *ak, *av;
bool pres;
@@ -805,25 +805,25 @@ void
ak = (byte*)&h + h->ko1;
av = (byte*)&h + h->vo1;
- mapaccess(h, ak, av, &pres);
+ runtime·mapaccess(h, ak, av, &pres);
if(debug) {
- prints("runtime.mapaccess1: map=");
- ·printpointer(h);
- prints("; key=");
+ runtime·prints("runtime.mapaccess1: map=");
+ runtime·printpointer(h);
+ runtime·prints("; key=");
h->keyalg->print(h->keysize, ak);
- prints("; val=");
+ runtime·prints("; val=");
h->valalg->print(h->valsize, av);
- prints("; pres=");
- ·printbool(pres);
- prints("\n");
+ runtime·prints("; pres=");
+ runtime·printbool(pres);
+ runtime·prints("\n");
}
}
// mapaccess2(hmap *map[any]any, key any) (val any, pres bool);
#pragma textflag 7
void
-·mapaccess2(Hmap *h, ...)
+runtime·mapaccess2(Hmap *h, ...)
{
byte *ak, *av, *ap;
@@ -831,29 +831,29 @@ void
av = (byte*)&h + h->vo1;
ap = (byte*)&h + h->po1;
- mapaccess(h, ak, av, ap);
+ runtime·mapaccess(h, ak, av, ap);
if(debug) {
- prints("runtime.mapaccess2: map=");
- ·printpointer(h);
- prints("; key=");
+ runtime·prints("runtime.mapaccess2: map=");
+ runtime·printpointer(h);
+ runtime·prints("; key=");
h->keyalg->print(h->keysize, ak);
- prints("; val=");
+ runtime·prints("; val=");
h->valalg->print(h->valsize, av);
- prints("; pres=");
- ·printbool(*ap);
- prints("\n");
+ runtime·prints("; pres=");
+ runtime·printbool(*ap);
+ runtime·prints("\n");
}
}
void
-mapassign(Hmap *h, byte *ak, byte *av)
+runtime·mapassign(Hmap *h, byte *ak, byte *av)
{
byte *res;
int32 hit;
- if(gcwaiting)
- gosched();
+ if(runtime·gcwaiting)
+ runtime·gosched();
res = nil;
if(av == nil) {
@@ -863,42 +863,42 @@ mapassign(Hmap *h, byte *ak, byte *av)
hit = hash_insert(h, ak, (void**)&res);
if(!hit && h->indirectval)
- *(void**)(res+h->datavo) = mal(h->valsize);
+ *(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);
if(debug) {
- prints("mapassign: map=");
- ·printpointer(h);
- prints("; key=");
+ runtime·prints("mapassign: map=");
+ runtime·printpointer(h);
+ runtime·prints("; key=");
h->keyalg->print(h->keysize, ak);
- prints("; val=");
+ runtime·prints("; val=");
h->valalg->print(h->valsize, av);
- prints("; hit=");
- ·printint(hit);
- prints("; res=");
- ·printpointer(res);
- prints("\n");
+ runtime·prints("; hit=");
+ runtime·printint(hit);
+ runtime·prints("; res=");
+ runtime·printpointer(res);
+ runtime·prints("\n");
}
}
// mapassign1(hmap *map[any]any, key any, val any);
#pragma textflag 7
void
-·mapassign1(Hmap *h, ...)
+runtime·mapassign1(Hmap *h, ...)
{
byte *ak, *av;
ak = (byte*)&h + h->ko2;
av = (byte*)&h + h->vo2;
- mapassign(h, ak, av);
+ runtime·mapassign(h, ak, av);
}
// mapassign2(hmap *map[any]any, key any, val any, pres bool);
#pragma textflag 7
void
-·mapassign2(Hmap *h, ...)
+runtime·mapassign2(Hmap *h, ...)
{
byte *ak, *av, *ap;
@@ -909,86 +909,69 @@ void
if(*ap == false)
av = nil; // delete
- mapassign(h, ak, av);
+ runtime·mapassign(h, ak, av);
if(debug) {
- prints("mapassign2: map=");
- ·printpointer(h);
- prints("; key=");
+ runtime·prints("mapassign2: map=");
+ runtime·printpointer(h);
+ runtime·prints("; key=");
h->keyalg->print(h->keysize, ak);
- prints("\n");
+ runtime·prints("\n");
}
}
-void*
-hash_next_and_deref(struct hash_iter *it)
-{
- void *p;
-
- p = hash_next(it);
- if(it->h->indirectval)
- p = *(void**)p;
- return p;
-}
-
// mapiterinit(hmap *map[any]any, hiter *any);
void
-·mapiterinit(Hmap *h, struct hash_iter *it)
+runtime·mapiterinit(Hmap *h, struct hash_iter *it)
{
if(h == nil) {
it->data = nil;
return;
}
hash_iter_init(h, it);
- it->data = hash_next_and_deref(it);
+ it->data = hash_next(it);
if(debug) {
- prints("runtime.mapiterinit: map=");
- ·printpointer(h);
- prints("; iter=");
- ·printpointer(it);
- prints("; data=");
- ·printpointer(it->data);
- prints("\n");
+ runtime·prints("runtime.mapiterinit: map=");
+ runtime·printpointer(h);
+ runtime·prints("; iter=");
+ runtime·printpointer(it);
+ runtime·prints("; data=");
+ runtime·printpointer(it->data);
+ runtime·prints("\n");
}
}
struct hash_iter*
-mapiterinit(Hmap *h)
+runtime·newmapiterinit(Hmap *h)
{
struct hash_iter *it;
- it = mal(sizeof *it);
- ·mapiterinit(h, it);
+ it = runtime·mal(sizeof *it);
+ runtime·mapiterinit(h, it);
return it;
}
// mapiternext(hiter *any);
void
-·mapiternext(struct hash_iter *it)
+runtime·mapiternext(struct hash_iter *it)
{
- if(gcwaiting)
- gosched();
+ if(runtime·gcwaiting)
+ runtime·gosched();
- it->data = hash_next_and_deref(it);
+ it->data = hash_next(it);
if(debug) {
- prints("runtime.mapiternext: iter=");
- ·printpointer(it);
- prints("; data=");
- ·printpointer(it->data);
- prints("\n");
+ runtime·prints("runtime.mapiternext: iter=");
+ runtime·printpointer(it);
+ runtime·prints("; data=");
+ runtime·printpointer(it->data);
+ runtime·prints("\n");
}
}
-void
-mapiternext(struct hash_iter *it)
-{
- ·mapiternext(it);
-}
-
// mapiter1(hiter *any) (key any);
#pragma textflag 7
void
-·mapiter1(struct hash_iter *it, ...)
+runtime·mapiter1(struct hash_iter *it, ...)
{
Hmap *h;
byte *ak, *res;
@@ -998,21 +981,21 @@ void
res = it->data;
if(res == nil)
- throw("runtime.mapiter1: key:val nil pointer");
+ runtime·throw("runtime.mapiter1: key:val nil pointer");
h->keyalg->copy(h->keysize, ak, res);
if(debug) {
- prints("mapiter2: iter=");
- ·printpointer(it);
- prints("; map=");
- ·printpointer(h);
- prints("\n");
+ runtime·prints("mapiter2: iter=");
+ runtime·printpointer(it);
+ runtime·prints("; map=");
+ runtime·printpointer(h);
+ runtime·prints("\n");
}
}
bool
-mapiterkey(struct hash_iter *it, void *ak)
+runtime·mapiterkey(struct hash_iter *it, void *ak)
{
Hmap *h;
byte *res;
@@ -1028,7 +1011,7 @@ mapiterkey(struct hash_iter *it, void *ak)
// mapiter2(hiter *any) (key any, val any);
#pragma textflag 7
void
-·mapiter2(struct hash_iter *it, ...)
+runtime·mapiter2(struct hash_iter *it, ...)
{
Hmap *h;
byte *ak, *av, *res;
@@ -1039,16 +1022,16 @@ void
res = it->data;
if(res == nil)
- throw("runtime.mapiter2: key:val nil pointer");
+ 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));
if(debug) {
- prints("mapiter2: iter=");
- ·printpointer(it);
- prints("; map=");
- ·printpointer(h);
- prints("\n");
+ runtime·prints("mapiter2: iter=");
+ runtime·printpointer(it);
+ runtime·prints("; map=");
+ runtime·printpointer(h);
+ runtime·prints("\n");
}
}
diff --git a/src/pkg/runtime/hashmap.h b/src/pkg/runtime/hashmap.h
index 906de4764..0737535b5 100644
--- a/src/pkg/runtime/hashmap.h
+++ b/src/pkg/runtime/hashmap.h
@@ -63,11 +63,12 @@
}
*/
-#define malloc mal
-#define offsetof(s,m) (uint32)(&(((s*)0)->m))
-#define memset(a,b,c) ·memclr((byte*)(a), (uint32)(c))
-#define memcpy(a,b,c) mcpy((byte*)(a),(byte*)(b),(uint32)(c))
-#define assert(a) if(!(a)) throw("assert")
+#define malloc runtime·mal
+#define memset(a,b,c) runtime·memclr((byte*)(a), (uint32)(c))
+#define memcpy(a,b,c) runtime·mcpy((byte*)(a),(byte*)(b),(uint32)(c))
+#define assert(a) if(!(a)) runtime·throw("assert")
+#define free(x) runtime·free(x)
+#define memmove(a,b,c) runtime·memmove(a, b, c)
struct hash; /* opaque */
struct hash_subtable; /* opaque */
@@ -114,12 +115,12 @@ struct hash_iter {
/* Lookup *data in *h. If the data is found, return 1 and place a pointer to
the found element in *pres. Otherwise return 0 and place 0 in *pres. */
-int32 hash_lookup (struct hash *h, void *data, void **pres);
+// int32 hash_lookup (struct hash *h, void *data, void **pres);
/* Lookup *data in *h. If the data is found, execute (*data_del) (arg, p)
where p points to the data in the table, then remove it from *h and return
1. Otherwise return 0. */
-int32 hash_remove (struct hash *h, void *data, void *arg);
+// int32 hash_remove (struct hash *h, void *data, void *arg);
/* Lookup *data in *h. If the data is found, return 1, and place a pointer
to the found element in *pres. Otherwise, return 0, allocate a region
@@ -129,10 +130,10 @@ int32 hash_remove (struct hash *h, void *data, void *arg);
If using garbage collection, it is the caller's responsibility to
add references for **pres if HASH_ADDED is returned. */
-int32 hash_insert (struct hash *h, void *data, void **pres);
+// int32 hash_insert (struct hash *h, void *data, void **pres);
/* Return the number of elements in the table. */
-uint32 hash_count (struct hash *h);
+// uint32 hash_count (struct hash *h);
/* The following call is useful only if not using garbage collection on the
table.
@@ -141,18 +142,18 @@ uint32 hash_count (struct hash *h);
If other memory pointed to by user data must be freed, the caller is
responsible for doiing do by iterating over *h first; see
hash_iter_init()/hash_next(). */
-void hash_destroy (struct hash *h);
+// void hash_destroy (struct hash *h);
/*----- iteration -----*/
/* Initialize *it from *h. */
-void hash_iter_init (struct hash *h, struct hash_iter *it);
+// void hash_iter_init (struct hash *h, struct hash_iter *it);
/* Return the next used entry in the table which which *it was initialized. */
-void *hash_next (struct hash_iter *it);
+// void *hash_next (struct hash_iter *it);
/*---- test interface ----*/
/* Call (*data_visit) (arg, level, data) for every data entry in the table,
whether used or not. "level" is the subtable level, 0 means first level. */
/* TESTING ONLY: DO NOT USE THIS ROUTINE IN NORMAL CODE */
-void hash_visit (struct hash *h, void (*data_visit) (void *arg, int32 level, void *data), void *arg);
+// void hash_visit (struct hash *h, void (*data_visit) (void *arg, int32 level, void *data), void *arg);
diff --git a/src/pkg/runtime/hashmap_defs.go b/src/pkg/runtime/hashmap_defs.go
new file mode 100644
index 000000000..57780df87
--- /dev/null
+++ b/src/pkg/runtime/hashmap_defs.go
@@ -0,0 +1,51 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Go definitions of internal structures. Master is hashmap.[c,h]
+
+package runtime
+
+type hash_hash uintptr
+
+type hash_entry struct {
+ hash hash_hash
+ key byte // dwarf.c substitutes the real type
+ val byte // for key and val
+}
+
+type hash_subtable struct {
+ power uint8
+ used uint8
+ datasize uint8
+ max_probes uint8
+ limit_bytes int16
+ end *hash_entry
+ entry hash_entry // TODO: [0]hash_entry
+}
+
+type hash struct {
+ count uint32
+ datasize uint8
+ max_power uint8
+ max_probes uint8
+ indirectval uint8
+ changes int32
+ data_hash func(uint32, uintptr) hash_hash
+ data_eq func(uint32, uintptr, uintptr) uint32
+ data_del func(uint32, uintptr, uintptr)
+ st *hash_subtable
+ keysize uint32
+ valsize uint32
+ datavo uint32
+ ko0 uint32
+ vo0 uint32
+ ko1 uint32
+ vo1 uint32
+ po1 uint32
+ ko2 uint32
+ vo2 uint32
+ po2 uint32
+ keyalg *alg
+ valalg *alg
+}
diff --git a/src/pkg/runtime/iface.c b/src/pkg/runtime/iface.c
index 35a710eca..aa36df68e 100644
--- a/src/pkg/runtime/iface.c
+++ b/src/pkg/runtime/iface.c
@@ -6,16 +6,16 @@
#include "type.h"
#include "malloc.h"
-static void
-printiface(Iface i)
+void
+runtime·printiface(Iface i)
{
- printf("(%p,%p)", i.tab, i.data);
+ runtime·printf("(%p,%p)", i.tab, i.data);
}
-static void
-printeface(Eface e)
+void
+runtime·printeface(Eface e)
{
- printf("(%p,%p)", e.type, e.data);
+ runtime·printf("(%p,%p)", e.type, e.data);
}
/*
@@ -49,7 +49,7 @@ itab(InterfaceType *inter, Type *type, int32 canfail)
Eface err;
if(inter->mhdr.len == 0)
- throw("internal error - misuse of itab");
+ runtime·throw("internal error - misuse of itab");
locked = 0;
@@ -72,7 +72,7 @@ itab(InterfaceType *inter, Type *type, int32 canfail)
// common case will be no lock contention.
for(locked=0; locked<2; locked++) {
if(locked)
- lock(&ifacelock);
+ runtime·lock(&ifacelock);
for(m=hash[h]; m!=nil; m=m->link) {
if(m->inter == inter && m->type == type) {
if(m->bad) {
@@ -89,14 +89,14 @@ itab(InterfaceType *inter, Type *type, int32 canfail)
}
}
if(locked)
- unlock(&ifacelock);
+ runtime·unlock(&ifacelock);
return m;
}
}
}
ni = inter->mhdr.len;
- m = malloc(sizeof(*m) + ni*sizeof m->fun[0]);
+ m = runtime·malloc(sizeof(*m) + ni*sizeof m->fun[0]);
m->inter = inter;
m->type = type;
@@ -117,12 +117,12 @@ search:
if(!canfail) {
throw:
// didn't find method
- ·newTypeAssertionError(nil, type, inter,
+ runtime·newTypeAssertionError(nil, type, inter,
nil, type->string, inter->string,
iname, &err);
if(locked)
- unlock(&ifacelock);
- ·panic(err);
+ runtime·unlock(&ifacelock);
+ runtime·panic(err);
return nil; // not reached
}
m->bad = 1;
@@ -139,7 +139,7 @@ out:
m->link = hash[h];
hash[h] = m;
if(locked)
- unlock(&ifacelock);
+ runtime·unlock(&ifacelock);
if(m->bad)
return nil;
return m;
@@ -155,10 +155,10 @@ copyin(Type *t, void *src, void **dst)
alg = t->alg;
if(wid <= sizeof(*dst))
- algarray[alg].copy(wid, dst, src);
+ runtime·algarray[alg].copy(wid, dst, src);
else {
- p = mal(wid);
- algarray[alg].copy(wid, p, src);
+ p = runtime·mal(wid);
+ runtime·algarray[alg].copy(wid, p, src);
*dst = p;
}
}
@@ -172,15 +172,15 @@ copyout(Type *t, void **src, void *dst)
alg = t->alg;
if(wid <= sizeof(*src))
- algarray[alg].copy(wid, dst, src);
+ runtime·algarray[alg].copy(wid, dst, src);
else
- algarray[alg].copy(wid, dst, *src);
+ runtime·algarray[alg].copy(wid, dst, *src);
}
// func convT2I(typ *byte, typ2 *byte, elem any) (ret any)
#pragma textflag 7
void
-·convT2I(Type *t, InterfaceType *inter, ...)
+runtime·convT2I(Type *t, InterfaceType *inter, ...)
{
byte *elem;
Iface *ret;
@@ -188,7 +188,7 @@ void
elem = (byte*)(&inter+1);
wid = t->size;
- ret = (Iface*)(elem + rnd(wid, Structrnd));
+ ret = (Iface*)(elem + runtime·rnd(wid, Structrnd));
ret->tab = itab(inter, t, 0);
copyin(t, elem, &ret->data);
}
@@ -196,7 +196,7 @@ void
// func convT2E(typ *byte, elem any) (ret any)
#pragma textflag 7
void
-·convT2E(Type *t, ...)
+runtime·convT2E(Type *t, ...)
{
byte *elem;
Eface *ret;
@@ -204,7 +204,7 @@ void
elem = (byte*)(&t+1);
wid = t->size;
- ret = (Eface*)(elem + rnd(wid, Structrnd));
+ ret = (Eface*)(elem + runtime·rnd(wid, Structrnd));
ret->type = t;
copyin(t, elem, &ret->data);
}
@@ -212,7 +212,7 @@ void
// func ifaceI2T(typ *byte, iface any) (ret any)
#pragma textflag 7
void
-·assertI2T(Type *t, Iface i, ...)
+runtime·assertI2T(Type *t, Iface i, ...)
{
Itab *tab;
byte *ret;
@@ -221,16 +221,16 @@ void
ret = (byte*)(&i+1);
tab = i.tab;
if(tab == nil) {
- ·newTypeAssertionError(nil, nil, t,
+ runtime·newTypeAssertionError(nil, nil, t,
nil, nil, t->string,
nil, &err);
- ·panic(err);
+ runtime·panic(err);
}
if(tab->type != t) {
- ·newTypeAssertionError(tab->inter, tab->type, t,
+ runtime·newTypeAssertionError(tab->inter, tab->type, t,
tab->inter->string, tab->type->string, t->string,
nil, &err);
- ·panic(err);
+ runtime·panic(err);
}
copyout(t, &i.data, ret);
}
@@ -238,7 +238,7 @@ void
// func ifaceI2T2(typ *byte, iface any) (ret any, ok bool)
#pragma textflag 7
void
-·assertI2T2(Type *t, Iface i, ...)
+runtime·assertI2T2(Type *t, Iface i, ...)
{
byte *ret;
bool *ok;
@@ -246,11 +246,11 @@ void
ret = (byte*)(&i+1);
wid = t->size;
- ok = (bool*)(ret+rnd(wid, 1));
+ ok = (bool*)(ret+runtime·rnd(wid, 1));
if(i.tab == nil || i.tab->type != t) {
*ok = false;
- ·memclr(ret, wid);
+ runtime·memclr(ret, wid);
return;
}
@@ -261,7 +261,7 @@ void
// func ifaceE2T(typ *byte, iface any) (ret any)
#pragma textflag 7
void
-·assertE2T(Type *t, Eface e, ...)
+runtime·assertE2T(Type *t, Eface e, ...)
{
byte *ret;
Eface err;
@@ -269,16 +269,16 @@ void
ret = (byte*)(&e+1);
if(e.type == nil) {
- ·newTypeAssertionError(nil, nil, t,
+ runtime·newTypeAssertionError(nil, nil, t,
nil, nil, t->string,
nil, &err);
- ·panic(err);
+ runtime·panic(err);
}
if(e.type != t) {
- ·newTypeAssertionError(nil, e.type, t,
+ runtime·newTypeAssertionError(nil, e.type, t,
nil, e.type->string, t->string,
nil, &err);
- ·panic(err);
+ runtime·panic(err);
}
copyout(t, &e.data, ret);
}
@@ -286,7 +286,7 @@ void
// func ifaceE2T2(sigt *byte, iface any) (ret any, ok bool);
#pragma textflag 7
void
-·assertE2T2(Type *t, Eface e, ...)
+runtime·assertE2T2(Type *t, Eface e, ...)
{
byte *ret;
bool *ok;
@@ -294,11 +294,11 @@ void
ret = (byte*)(&e+1);
wid = t->size;
- ok = (bool*)(ret+rnd(wid, 1));
+ ok = (bool*)(ret+runtime·rnd(wid, 1));
if(t != e.type) {
*ok = false;
- ·memclr(ret, wid);
+ runtime·memclr(ret, wid);
return;
}
@@ -309,7 +309,7 @@ void
// func convI2E(elem any) (ret any)
#pragma textflag 7
void
-·convI2E(Iface i, Eface ret)
+runtime·convI2E(Iface i, Eface ret)
{
Itab *tab;
@@ -324,7 +324,7 @@ void
// func ifaceI2E(typ *byte, iface any) (ret any)
#pragma textflag 7
void
-·assertI2E(InterfaceType* inter, Iface i, Eface ret)
+runtime·assertI2E(InterfaceType* inter, Iface i, Eface ret)
{
Itab *tab;
Eface err;
@@ -332,10 +332,10 @@ void
tab = i.tab;
if(tab == nil) {
// explicit conversions require non-nil interface value.
- ·newTypeAssertionError(nil, nil, inter,
+ runtime·newTypeAssertionError(nil, nil, inter,
nil, nil, inter->string,
nil, &err);
- ·panic(err);
+ runtime·panic(err);
}
ret.data = i.data;
ret.type = tab->type;
@@ -345,7 +345,7 @@ void
// func ifaceI2E2(typ *byte, iface any) (ret any, ok bool)
#pragma textflag 7
void
-·assertI2E2(InterfaceType* inter, Iface i, Eface ret, bool ok)
+runtime·assertI2E2(InterfaceType* inter, Iface i, Eface ret, bool ok)
{
Itab *tab;
@@ -366,7 +366,7 @@ void
// func convI2I(typ *byte, elem any) (ret any)
#pragma textflag 7
void
-·convI2I(InterfaceType* inter, Iface i, Iface ret)
+runtime·convI2I(InterfaceType* inter, Iface i, Iface ret)
{
Itab *tab;
@@ -381,7 +381,7 @@ void
}
void
-ifaceI2I(InterfaceType *inter, Iface i, Iface *ret)
+runtime·ifaceI2I(InterfaceType *inter, Iface i, Iface *ret)
{
Itab *tab;
Eface err;
@@ -389,10 +389,10 @@ ifaceI2I(InterfaceType *inter, Iface i, Iface *ret)
tab = i.tab;
if(tab == nil) {
// explicit conversions require non-nil interface value.
- ·newTypeAssertionError(nil, nil, inter,
+ runtime·newTypeAssertionError(nil, nil, inter,
nil, nil, inter->string,
nil, &err);
- ·panic(err);
+ runtime·panic(err);
}
ret->data = i.data;
ret->tab = itab(inter, tab->type, 0);
@@ -401,15 +401,15 @@ ifaceI2I(InterfaceType *inter, Iface i, Iface *ret)
// func ifaceI2I(sigi *byte, iface any) (ret any)
#pragma textflag 7
void
-·assertI2I(InterfaceType* inter, Iface i, Iface ret)
+runtime·assertI2I(InterfaceType* inter, Iface i, Iface ret)
{
- ifaceI2I(inter, i, &ret);
+ runtime·ifaceI2I(inter, i, &ret);
}
// func ifaceI2I2(sigi *byte, iface any) (ret any, ok bool)
#pragma textflag 7
void
-·assertI2I2(InterfaceType *inter, Iface i, Iface ret, bool ok)
+runtime·assertI2I2(InterfaceType *inter, Iface i, Iface ret, bool ok)
{
Itab *tab;
@@ -428,7 +428,7 @@ void
}
void
-ifaceE2I(InterfaceType *inter, Eface e, Iface *ret)
+runtime·ifaceE2I(InterfaceType *inter, Eface e, Iface *ret)
{
Type *t;
Eface err;
@@ -436,10 +436,10 @@ ifaceE2I(InterfaceType *inter, Eface e, Iface *ret)
t = e.type;
if(t == nil) {
// explicit conversions require non-nil interface value.
- ·newTypeAssertionError(nil, nil, inter,
+ runtime·newTypeAssertionError(nil, nil, inter,
nil, nil, inter->string,
nil, &err);
- ·panic(err);
+ runtime·panic(err);
}
ret->data = e.data;
ret->tab = itab(inter, t, 0);
@@ -448,15 +448,15 @@ ifaceE2I(InterfaceType *inter, Eface e, Iface *ret)
// func ifaceE2I(sigi *byte, iface any) (ret any)
#pragma textflag 7
void
-·assertE2I(InterfaceType* inter, Eface e, Iface ret)
+runtime·assertE2I(InterfaceType* inter, Eface e, Iface ret)
{
- ifaceE2I(inter, e, &ret);
+ runtime·ifaceE2I(inter, e, &ret);
}
// ifaceE2I2(sigi *byte, iface any) (ret any, ok bool)
#pragma textflag 7
void
-·assertE2I2(InterfaceType *inter, Eface e, Iface ret, bool ok)
+runtime·assertE2I2(InterfaceType *inter, Eface e, Iface ret, bool ok)
{
if(e.type == nil) {
ok = 0;
@@ -476,7 +476,7 @@ void
// func ifaceE2E(typ *byte, iface any) (ret any)
#pragma textflag 7
void
-·assertE2E(InterfaceType* inter, Eface e, Eface ret)
+runtime·assertE2E(InterfaceType* inter, Eface e, Eface ret)
{
Type *t;
Eface err;
@@ -484,10 +484,10 @@ void
t = e.type;
if(t == nil) {
// explicit conversions require non-nil interface value.
- ·newTypeAssertionError(nil, nil, inter,
+ runtime·newTypeAssertionError(nil, nil, inter,
nil, nil, inter->string,
nil, &err);
- ·panic(err);
+ runtime·panic(err);
}
ret = e;
FLUSH(&ret);
@@ -496,7 +496,7 @@ void
// func ifaceE2E2(iface any) (ret any, ok bool)
#pragma textflag 7
void
-·assertE2E2(InterfaceType* inter, Eface e, Eface ret, bool ok)
+runtime·assertE2E2(InterfaceType* inter, Eface e, Eface ret, bool ok)
{
USED(inter);
ret = e;
@@ -516,19 +516,19 @@ ifacehash1(void *data, Type *t)
alg = t->alg;
wid = t->size;
- if(algarray[alg].hash == nohash) {
+ if(runtime·algarray[alg].hash == runtime·nohash) {
// calling nohash will panic too,
// but we can print a better error.
- ·newErrorString(catstring(gostringnocopy((byte*)"hash of unhashable type "), *t->string), &err);
- ·panic(err);
+ runtime·newErrorString(runtime·catstring(runtime·gostringnocopy((byte*)"hash of unhashable type "), *t->string), &err);
+ runtime·panic(err);
}
if(wid <= sizeof(data))
- return algarray[alg].hash(wid, &data);
- return algarray[alg].hash(wid, data);
+ return runtime·algarray[alg].hash(wid, &data);
+ return runtime·algarray[alg].hash(wid, data);
}
uintptr
-ifacehash(Iface a)
+runtime·ifacehash(Iface a)
{
if(a.tab == nil)
return 0;
@@ -536,7 +536,7 @@ ifacehash(Iface a)
}
uintptr
-efacehash(Eface a)
+runtime·efacehash(Eface a)
{
return ifacehash1(a.data, a.type);
}
@@ -550,20 +550,20 @@ ifaceeq1(void *data1, void *data2, Type *t)
alg = t->alg;
wid = t->size;
- if(algarray[alg].equal == noequal) {
+ if(runtime·algarray[alg].equal == runtime·noequal) {
// calling noequal will panic too,
// but we can print a better error.
- ·newErrorString(catstring(gostringnocopy((byte*)"comparing uncomparable type "), *t->string), &err);
- ·panic(err);
+ runtime·newErrorString(runtime·catstring(runtime·gostringnocopy((byte*)"comparing uncomparable type "), *t->string), &err);
+ runtime·panic(err);
}
if(wid <= sizeof(data1))
- return algarray[alg].equal(wid, &data1, &data2);
- return algarray[alg].equal(wid, data1, data2);
+ return runtime·algarray[alg].equal(wid, &data1, &data2);
+ return runtime·algarray[alg].equal(wid, data1, data2);
}
bool
-ifaceeq(Iface i1, Iface i2)
+runtime·ifaceeq_c(Iface i1, Iface i2)
{
if(i1.tab != i2.tab)
return false;
@@ -573,7 +573,7 @@ ifaceeq(Iface i1, Iface i2)
}
bool
-efaceeq(Eface e1, Eface e2)
+runtime·efaceeq_c(Eface e1, Eface e2)
{
if(e1.type != e2.type)
return false;
@@ -584,23 +584,23 @@ efaceeq(Eface e1, Eface e2)
// ifaceeq(i1 any, i2 any) (ret bool);
void
-·ifaceeq(Iface i1, Iface i2, bool ret)
+runtime·ifaceeq(Iface i1, Iface i2, bool ret)
{
- ret = ifaceeq(i1, i2);
+ ret = runtime·ifaceeq_c(i1, i2);
FLUSH(&ret);
}
// efaceeq(i1 any, i2 any) (ret bool)
void
-·efaceeq(Eface e1, Eface e2, bool ret)
+runtime·efaceeq(Eface e1, Eface e2, bool ret)
{
- ret = efaceeq(e1, e2);
+ ret = runtime·efaceeq_c(e1, e2);
FLUSH(&ret);
}
// ifacethash(i1 any) (ret uint32);
void
-·ifacethash(Iface i1, uint32 ret)
+runtime·ifacethash(Iface i1, uint32 ret)
{
Itab *tab;
@@ -613,7 +613,7 @@ void
// efacethash(e1 any) (ret uint32)
void
-·efacethash(Eface e1, uint32 ret)
+runtime·efacethash(Eface e1, uint32 ret)
{
Type *t;
@@ -625,18 +625,6 @@ void
}
void
-·printiface(Iface i)
-{
- printiface(i);
-}
-
-void
-·printeface(Eface e)
-{
- printeface(e);
-}
-
-void
unsafe·Typeof(Eface e, Eface ret)
{
if(e.type == nil) {
@@ -662,17 +650,17 @@ unsafe·Reflect(Eface e, Eface rettype, void *retaddr)
if(e.type->size <= sizeof(uintptr)) {
// Copy data into x ...
x = 0;
- algarray[e.type->alg].copy(e.type->size, &x, &e.data);
+ 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 = mal(sizeof(uintptr));
+ p = runtime·mal(sizeof(uintptr));
*p = x;
} else {
// Already a pointer, but still make a copy,
// to preserve value semantics for interface data.
- p = mal(e.type->size);
- algarray[e.type->alg].copy(e.type->size, p, e.data);
+ p = runtime·mal(e.type->size);
+ runtime·algarray[e.type->alg].copy(e.type->size, p, e.data);
}
retaddr = p;
}
@@ -692,7 +680,7 @@ unsafe·Unreflect(Eface typ, void *addr, Eface e)
// Interface holds either pointer to data
// or copy of original data.
if(e.type->size <= sizeof(uintptr))
- algarray[e.type->alg].copy(e.type->size, &e.data, addr);
+ 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?
@@ -714,9 +702,9 @@ unsafe·New(Eface typ, void *ret)
t = (Type*)((Eface*)typ.data-1);
if(t->kind&KindNoPointers)
- ret = mallocgc(t->size, RefNoPointers, 1, 1);
+ ret = runtime·mallocgc(t->size, RefNoPointers, 1, 1);
else
- ret = mal(t->size);
+ ret = runtime·mal(t->size);
FLUSH(&ret);
}
@@ -734,8 +722,8 @@ unsafe·NewArray(Eface typ, uint32 n, void *ret)
size = n*t->size;
if(t->kind&KindNoPointers)
- ret = mallocgc(size, RefNoPointers, 1, 1);
+ ret = runtime·mallocgc(size, RefNoPointers, 1, 1);
else
- ret = mal(size);
+ ret = runtime·mal(size);
FLUSH(&ret);
}
diff --git a/src/pkg/runtime/iface_defs.go b/src/pkg/runtime/iface_defs.go
new file mode 100644
index 000000000..69d52ef9a
--- /dev/null
+++ b/src/pkg/runtime/iface_defs.go
@@ -0,0 +1,18 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+/*
+ * Must match iface.c:/Itable and compilers.
+ * NOTE: type.go has an Itable, that is the version of Itab used by the reflection code.
+ */
+type itab struct {
+ Itype *Type
+ Type *Type
+ link *itab
+ bad int32
+ unused int32
+ Fn func() // TODO: [0]func()
+}
diff --git a/src/pkg/runtime/linux/386/defs.h b/src/pkg/runtime/linux/386/defs.h
index ef8ef05d0..c1f58b2a0 100644
--- a/src/pkg/runtime/linux/386/defs.h
+++ b/src/pkg/runtime/linux/386/defs.h
@@ -10,6 +10,7 @@ enum {
PROT_EXEC = 0x4,
MAP_ANON = 0x20,
MAP_PRIVATE = 0x2,
+ MAP_FIXED = 0x10,
SA_RESTART = 0x10000000,
SA_ONSTACK = 0x8000000,
SA_RESTORER = 0x4000000,
diff --git a/src/pkg/runtime/linux/386/rt0.s b/src/pkg/runtime/linux/386/rt0.s
index 4d2345d8c..0f82d6a1c 100644
--- a/src/pkg/runtime/linux/386/rt0.s
+++ b/src/pkg/runtime/linux/386/rt0.s
@@ -4,6 +4,14 @@
// Darwin and Linux use the same linkage to main
-TEXT _rt0_386_linux(SB),7,$0
+TEXT _rt0_386_linux(SB),7,$0
+ // Linux starts 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
+
JMP _rt0_386(SB)
diff --git a/src/pkg/runtime/linux/386/signal.c b/src/pkg/runtime/linux/386/signal.c
index 6bc95d0d7..0dbfcf9ff 100644
--- a/src/pkg/runtime/linux/386/signal.c
+++ b/src/pkg/runtime/linux/386/signal.c
@@ -8,41 +8,41 @@
#include "os.h"
void
-dumpregs(Sigcontext *r)
+runtime·dumpregs(Sigcontext *r)
{
- printf("eax %x\n", r->eax);
- printf("ebx %x\n", r->ebx);
- printf("ecx %x\n", r->ecx);
- printf("edx %x\n", r->edx);
- printf("edi %x\n", r->edi);
- printf("esi %x\n", r->esi);
- printf("ebp %x\n", r->ebp);
- printf("esp %x\n", r->esp);
- printf("eip %x\n", r->eip);
- printf("eflags %x\n", r->eflags);
- printf("cs %x\n", r->cs);
- printf("fs %x\n", r->fs);
- printf("gs %x\n", r->gs);
+ runtime·printf("eax %x\n", r->eax);
+ runtime·printf("ebx %x\n", r->ebx);
+ runtime·printf("ecx %x\n", r->ecx);
+ runtime·printf("edx %x\n", r->edx);
+ runtime·printf("edi %x\n", r->edi);
+ runtime·printf("esi %x\n", r->esi);
+ runtime·printf("ebp %x\n", r->ebp);
+ runtime·printf("esp %x\n", r->esp);
+ runtime·printf("eip %x\n", r->eip);
+ runtime·printf("eflags %x\n", r->eflags);
+ runtime·printf("cs %x\n", r->cs);
+ runtime·printf("fs %x\n", r->fs);
+ runtime·printf("gs %x\n", r->gs);
}
/*
* This assembler routine takes the args from registers, puts them on the stack,
* and calls sighandler().
*/
-extern void sigtramp(void);
-extern void sigignore(void); // just returns
-extern void sigreturn(void); // calls sigreturn
+extern void runtime·sigtramp(void);
+extern void runtime·sigignore(void); // just returns
+extern void runtime·sigreturn(void); // calls runtime·sigreturn
String
-signame(int32 sig)
+runtime·signame(int32 sig)
{
if(sig < 0 || sig >= NSIG)
- return emptystring;
- return gostringnocopy((byte*)sigtab[sig].name);
+ return runtime·emptystring;
+ return runtime·gostringnocopy((byte*)runtime·sigtab[sig].name);
}
void
-sighandler(int32 sig, Siginfo* info, void* context)
+runtime·sighandler(int32 sig, Siginfo* info, void* context)
{
Ucontext *uc;
Sigcontext *r;
@@ -52,7 +52,7 @@ sighandler(int32 sig, Siginfo* info, void* context)
uc = context;
r = &uc->uc_mcontext;
- if((gp = m->curg) != nil && (sigtab[sig].flags & SigPanic)) {
+ if((gp = m->curg) != nil && (runtime·sigtab[sig].flags & SigPanic)) {
// Make it look like a call to the signal func.
// Have to pass arguments out of band since
// augmenting the stack frame would break
@@ -61,84 +61,84 @@ sighandler(int32 sig, Siginfo* info, void* context)
gp->sigcode0 = info->si_code;
gp->sigcode1 = ((uintptr*)info)[3];
- // Only push sigpanic if r->eip != 0.
+ // Only push runtime·sigpanic if r->eip != 0.
// If r->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 sigpanic instead.
- // (Otherwise the trace will end at sigpanic and we
+ // 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->eip != 0) {
sp = (uintptr*)r->esp;
*--sp = r->eip;
r->esp = (uintptr)sp;
}
- r->eip = (uintptr)sigpanic;
+ r->eip = (uintptr)runtime·sigpanic;
return;
}
- if(sigtab[sig].flags & SigQueue) {
- if(sigsend(sig) || (sigtab[sig].flags & SigIgnore))
+ if(runtime·sigtab[sig].flags & SigQueue) {
+ if(runtime·sigsend(sig) || (runtime·sigtab[sig].flags & SigIgnore))
return;
- exit(2); // SIGINT, SIGTERM, etc
+ runtime·exit(2); // SIGINT, SIGTERM, etc
}
- if(panicking) // traceback already printed
- exit(2);
- panicking = 1;
+ if(runtime·panicking) // traceback already printed
+ runtime·exit(2);
+ runtime·panicking = 1;
if(sig < 0 || sig >= NSIG)
- printf("Signal %d\n", sig);
+ runtime·printf("Signal %d\n", sig);
else
- printf("%s\n", sigtab[sig].name);
+ runtime·printf("%s\n", runtime·sigtab[sig].name);
- printf("PC=%X\n", r->eip);
- printf("\n");
+ runtime·printf("PC=%X\n", r->eip);
+ runtime·printf("\n");
- if(gotraceback()){
- traceback((void*)r->eip, (void*)r->esp, 0, m->curg);
- tracebackothers(m->curg);
- dumpregs(r);
+ if(runtime·gotraceback()){
+ runtime·traceback((void*)r->eip, (void*)r->esp, 0, m->curg);
+ runtime·tracebackothers(m->curg);
+ runtime·dumpregs(r);
}
- breakpoint();
- exit(2);
+ runtime·breakpoint();
+ runtime·exit(2);
}
void
-signalstack(byte *p, int32 n)
+runtime·signalstack(byte *p, int32 n)
{
Sigaltstack st;
st.ss_sp = p;
st.ss_size = n;
st.ss_flags = 0;
- sigaltstack(&st, nil);
+ runtime·sigaltstack(&st, nil);
}
void
-initsig(int32 queue)
+runtime·initsig(int32 queue)
{
static Sigaction sa;
- siginit();
+ runtime·siginit();
int32 i;
sa.sa_flags = SA_ONSTACK | SA_SIGINFO | SA_RESTORER;
sa.sa_mask = 0xFFFFFFFFFFFFFFFFULL;
- sa.sa_restorer = (void*)sigreturn;
+ sa.sa_restorer = (void*)runtime·sigreturn;
for(i = 0; i<NSIG; i++) {
- if(sigtab[i].flags) {
- if((sigtab[i].flags & SigQueue) != queue)
+ if(runtime·sigtab[i].flags) {
+ if((runtime·sigtab[i].flags & SigQueue) != queue)
continue;
- if(sigtab[i].flags & (SigCatch | SigQueue))
- sa.k_sa_handler = (void*)sigtramp;
+ if(runtime·sigtab[i].flags & (SigCatch | SigQueue))
+ sa.k_sa_handler = (void*)runtime·sigtramp;
else
- sa.k_sa_handler = (void*)sigignore;
- if(sigtab[i].flags & SigRestart)
+ sa.k_sa_handler = (void*)runtime·sigignore;
+ if(runtime·sigtab[i].flags & SigRestart)
sa.sa_flags |= SA_RESTART;
else
sa.sa_flags &= ~SA_RESTART;
- rt_sigaction(i, &sa, nil, 8);
+ runtime·rt_sigaction(i, &sa, nil, 8);
}
}
}
diff --git a/src/pkg/runtime/linux/386/sys.s b/src/pkg/runtime/linux/386/sys.s
index 57ffc4aa4..a1505b0b0 100644
--- a/src/pkg/runtime/linux/386/sys.s
+++ b/src/pkg/runtime/linux/386/sys.s
@@ -8,21 +8,21 @@
#include "386/asm.h"
-TEXT exit(SB),7,$0
+TEXT runtime·exit(SB),7,$0
MOVL $252, AX // syscall number
MOVL 4(SP), BX
INT $0x80
INT $3 // not reached
RET
-TEXT exit1(SB),7,$0
+TEXT runtime·exit1(SB),7,$0
MOVL $1, AX // exit - exit the current os thread
MOVL 4(SP), BX
INT $0x80
INT $3 // not reached
RET
-TEXT write(SB),7,$0
+TEXT runtime·write(SB),7,$0
MOVL $4, AX // syscall - write
MOVL 4(SP), BX
MOVL 8(SP), CX
@@ -30,7 +30,7 @@ TEXT write(SB),7,$0
INT $0x80
RET
-TEXT gettime(SB), 7, $32
+TEXT runtime·gettime(SB), 7, $32
MOVL $78, AX // syscall - gettimeofday
LEAL 8(SP), BX
MOVL $0, CX
@@ -47,7 +47,7 @@ TEXT gettime(SB), 7, $32
MOVL BX, (DI)
RET
-TEXT rt_sigaction(SB),7,$0
+TEXT runtime·rt_sigaction(SB),7,$0
MOVL $174, AX // syscall - rt_sigaction
MOVL 4(SP), BX
MOVL 8(SP), CX
@@ -56,7 +56,7 @@ TEXT rt_sigaction(SB),7,$0
INT $0x80
RET
-TEXT sigtramp(SB),7,$40
+TEXT runtime·sigtramp(SB),7,$40
get_tls(CX)
// save g
@@ -76,7 +76,7 @@ TEXT sigtramp(SB),7,$40
MOVL context+8(FP), BX
MOVL BX, 8(SP)
- CALL sighandler(SB)
+ CALL runtime·sighandler(SB)
// restore g
get_tls(CX)
@@ -85,16 +85,16 @@ TEXT sigtramp(SB),7,$40
RET
-TEXT sigignore(SB),7,$0
+TEXT runtime·sigignore(SB),7,$0
RET
-TEXT sigreturn(SB),7,$0
+TEXT runtime·sigreturn(SB),7,$0
MOVL $173, AX // rt_sigreturn
INT $0x80
INT $3 // not reached
RET
-TEXT ·mmap(SB),7,$0
+TEXT runtime·mmap(SB),7,$0
MOVL $192, AX // mmap2
MOVL 4(SP), BX
MOVL 8(SP), CX
@@ -110,9 +110,19 @@ TEXT ·mmap(SB),7,$0
INCL AX
RET
+TEXT runtime·munmap(SB),7,$0
+ MOVL $91, AX // munmap
+ MOVL 4(SP), BX
+ MOVL 8(SP), CX
+ INT $0x80
+ CMPL AX, $0xfffff001
+ JLS 2(PC)
+ INT $3
+ RET
+
// int32 futex(int32 *uaddr, int32 op, int32 val,
// struct timespec *timeout, int32 *uaddr2, int32 val2);
-TEXT futex(SB),7,$0
+TEXT runtime·futex(SB),7,$0
MOVL $240, AX // futex
MOVL 4(SP), BX
MOVL 8(SP), CX
@@ -124,7 +134,7 @@ TEXT futex(SB),7,$0
RET
// int32 clone(int32 flags, void *stack, M *m, G *g, void (*fn)(void));
-TEXT clone(SB),7,$0
+TEXT runtime·clone(SB),7,$0
MOVL $120, AX // clone
MOVL flags+4(SP), BX
MOVL stack+8(SP), CX
@@ -161,12 +171,12 @@ TEXT clone(SB),7,$0
// In child on new stack. Reload registers (paranoia).
MOVL 0(SP), BX // m
MOVL 4(SP), DX // g
- MOVL 8(SP), CX // fn
+ MOVL 8(SP), SI // fn
MOVL AX, m_procid(BX) // save tid as m->procid
// set up ldt 7+id to point at m->tls.
- // m->tls is at m+40. newosproc left the id in tls[0].
+ // newosproc left the id in tls[0].
LEAL m_tls(BX), BP
MOVL 0(BP), DI
ADDL $7, DI // m0 is LDT#7. count up.
@@ -175,7 +185,7 @@ TEXT clone(SB),7,$0
PUSHL $32 // sizeof tls
PUSHL BP // &tls
PUSHL DI // tls #
- CALL setldt(SB)
+ CALL runtime·setldt(SB)
POPL AX
POPL AX
POPL AX
@@ -186,21 +196,21 @@ TEXT clone(SB),7,$0
MOVL DX, g(AX)
MOVL BX, m(AX)
- CALL stackcheck(SB) // smashes 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 emptyfunc(SB)
+ CALL runtime·emptyfunc(SB)
POPAL
- CALL CX // fn()
- CALL exit1(SB)
+ CALL SI // fn()
+ CALL runtime·exit1(SB)
MOVL $0x1234, 0x1005
RET
-TEXT sigaltstack(SB),7,$-8
+TEXT runtime·sigaltstack(SB),7,$-8
MOVL $186, AX // sigaltstack
MOVL new+4(SP), BX
MOVL old+8(SP), CX
@@ -233,7 +243,7 @@ TEXT sigaltstack(SB),7,$-8
#define USEABLE 0x40
// setldt(int entry, int address, int limit)
-TEXT setldt(SB),7,$32
+TEXT runtime·setldt(SB),7,$32
MOVL entry+0(FP), BX // entry
MOVL address+4(FP), CX // base address
@@ -247,8 +257,11 @@ TEXT setldt(SB),7,$32
* To accommodate that rewrite, we translate
* the address here and bump the limit to 0xffffffff (no limit)
* so that -8(GS) maps to 0(address).
+ * Also, the final 0(GS) (current 8(CX)) has to point
+ * to itself, to mimic ELF.
*/
ADDL $0x8, CX // address
+ MOVL CX, 0(CX)
// set up user_desc
LEAL 16(SP), AX // struct user_desc
diff --git a/src/pkg/runtime/linux/amd64/defs.h b/src/pkg/runtime/linux/amd64/defs.h
index c08e6b25d..3e3d32f0d 100644
--- a/src/pkg/runtime/linux/amd64/defs.h
+++ b/src/pkg/runtime/linux/amd64/defs.h
@@ -10,6 +10,7 @@ enum {
PROT_EXEC = 0x4,
MAP_ANON = 0x20,
MAP_PRIVATE = 0x2,
+ MAP_FIXED = 0x10,
SA_RESTART = 0x10000000,
SA_ONSTACK = 0x8000000,
SA_RESTORER = 0x4000000,
diff --git a/src/pkg/runtime/linux/amd64/rt0.s b/src/pkg/runtime/linux/amd64/rt0.s
index 2190b4414..dac9ae181 100644
--- a/src/pkg/runtime/linux/amd64/rt0.s
+++ b/src/pkg/runtime/linux/amd64/rt0.s
@@ -4,7 +4,7 @@
// Darwin and Linux use the same linkage to main
-TEXT _rt0_amd64_linux(SB),7,$-8
+TEXT _rt0_amd64_linux(SB),7,$-8
MOVQ $_rt0_amd64(SB), AX
MOVQ SP, DI
JMP AX
diff --git a/src/pkg/runtime/linux/amd64/signal.c b/src/pkg/runtime/linux/amd64/signal.c
index 63c3a2e6e..e78bbda9d 100644
--- a/src/pkg/runtime/linux/amd64/signal.c
+++ b/src/pkg/runtime/linux/amd64/signal.c
@@ -8,49 +8,49 @@
#include "os.h"
void
-dumpregs(Sigcontext *r)
+runtime·dumpregs(Sigcontext *r)
{
- printf("rax %X\n", r->rax);
- printf("rbx %X\n", r->rbx);
- printf("rcx %X\n", r->rcx);
- printf("rdx %X\n", r->rdx);
- printf("rdi %X\n", r->rdi);
- printf("rsi %X\n", r->rsi);
- printf("rbp %X\n", r->rbp);
- printf("rsp %X\n", r->rsp);
- printf("r8 %X\n", r->r8 );
- printf("r9 %X\n", r->r9 );
- printf("r10 %X\n", r->r10);
- printf("r11 %X\n", r->r11);
- printf("r12 %X\n", r->r12);
- printf("r13 %X\n", r->r13);
- printf("r14 %X\n", r->r14);
- printf("r15 %X\n", r->r15);
- printf("rip %X\n", r->rip);
- printf("rflags %X\n", r->eflags);
- printf("cs %X\n", (uint64)r->cs);
- printf("fs %X\n", (uint64)r->fs);
- printf("gs %X\n", (uint64)r->gs);
+ 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->cs);
+ runtime·printf("fs %X\n", (uint64)r->fs);
+ runtime·printf("gs %X\n", (uint64)r->gs);
}
/*
* This assembler routine takes the args from registers, puts them on the stack,
* and calls sighandler().
*/
-extern void sigtramp(void);
-extern void sigignore(void); // just returns
-extern void sigreturn(void); // calls sigreturn
+extern void runtime·sigtramp(void);
+extern void runtime·sigignore(void); // just returns
+extern void runtime·sigreturn(void); // calls runtime·sigreturn
String
-signame(int32 sig)
+runtime·signame(int32 sig)
{
if(sig < 0 || sig >= NSIG)
- return emptystring;
- return gostringnocopy((byte*)sigtab[sig].name);
+ return runtime·emptystring;
+ return runtime·gostringnocopy((byte*)runtime·sigtab[sig].name);
}
void
-sighandler(int32 sig, Siginfo* info, void* context)
+runtime·sighandler(int32 sig, Siginfo* info, void* context)
{
Ucontext *uc;
Mcontext *mc;
@@ -62,7 +62,7 @@ sighandler(int32 sig, Siginfo* info, void* context)
mc = &uc->uc_mcontext;
r = (Sigcontext*)mc; // same layout, more conveient names
- if((gp = m->curg) != nil && (sigtab[sig].flags & SigPanic)) {
+ if((gp = m->curg) != nil && (runtime·sigtab[sig].flags & SigPanic)) {
// Make it look like a call to the signal func.
// Have to pass arguments out of band since
// augmenting the stack frame would break
@@ -71,84 +71,84 @@ sighandler(int32 sig, Siginfo* info, void* context)
gp->sigcode0 = info->si_code;
gp->sigcode1 = ((uintptr*)info)[2];
- // Only push sigpanic if r->rip != 0.
+ // 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 sigpanic instead.
- // (Otherwise the trace will end at sigpanic and we
+ // 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)sigpanic;
+ r->rip = (uintptr)runtime·sigpanic;
return;
}
- if(sigtab[sig].flags & SigQueue) {
- if(sigsend(sig) || (sigtab[sig].flags & SigIgnore))
+ if(runtime·sigtab[sig].flags & SigQueue) {
+ if(runtime·sigsend(sig) || (runtime·sigtab[sig].flags & SigIgnore))
return;
- exit(2); // SIGINT, SIGTERM, etc
+ runtime·exit(2); // SIGINT, SIGTERM, etc
}
- if(panicking) // traceback already printed
- exit(2);
- panicking = 1;
+ if(runtime·panicking) // traceback already printed
+ runtime·exit(2);
+ runtime·panicking = 1;
if(sig < 0 || sig >= NSIG)
- printf("Signal %d\n", sig);
+ runtime·printf("Signal %d\n", sig);
else
- printf("%s\n", sigtab[sig].name);
+ runtime·printf("%s\n", runtime·sigtab[sig].name);
- printf("PC=%X\n", r->rip);
- printf("\n");
+ runtime·printf("PC=%X\n", r->rip);
+ runtime·printf("\n");
- if(gotraceback()){
- traceback((void*)r->rip, (void*)r->rsp, 0, (void*)r->r15);
- tracebackothers((void*)r->r15);
- dumpregs(r);
+ if(runtime·gotraceback()){
+ runtime·traceback((void*)r->rip, (void*)r->rsp, 0, g);
+ runtime·tracebackothers(g);
+ runtime·dumpregs(r);
}
- breakpoint();
- exit(2);
+ runtime·breakpoint();
+ runtime·exit(2);
}
void
-signalstack(byte *p, int32 n)
+runtime·signalstack(byte *p, int32 n)
{
Sigaltstack st;
st.ss_sp = p;
st.ss_size = n;
st.ss_flags = 0;
- sigaltstack(&st, nil);
+ runtime·sigaltstack(&st, nil);
}
void
-initsig(int32 queue)
+runtime·initsig(int32 queue)
{
static Sigaction sa;
- siginit();
+ runtime·siginit();
int32 i;
sa.sa_flags = SA_ONSTACK | SA_SIGINFO | SA_RESTORER;
sa.sa_mask = 0xFFFFFFFFFFFFFFFFULL;
- sa.sa_restorer = (void*)sigreturn;
+ sa.sa_restorer = (void*)runtime·sigreturn;
for(i = 0; i<NSIG; i++) {
- if(sigtab[i].flags) {
- if((sigtab[i].flags & SigQueue) != queue)
+ if(runtime·sigtab[i].flags) {
+ if((runtime·sigtab[i].flags & SigQueue) != queue)
continue;
- if(sigtab[i].flags & (SigCatch | SigQueue))
- sa.sa_handler = (void*)sigtramp;
+ if(runtime·sigtab[i].flags & (SigCatch | SigQueue))
+ sa.sa_handler = (void*)runtime·sigtramp;
else
- sa.sa_handler = (void*)sigignore;
- if(sigtab[i].flags & SigRestart)
+ sa.sa_handler = (void*)runtime·sigignore;
+ if(runtime·sigtab[i].flags & SigRestart)
sa.sa_flags |= SA_RESTART;
else
sa.sa_flags &= ~SA_RESTART;
- rt_sigaction(i, &sa, nil, 8);
+ runtime·rt_sigaction(i, &sa, nil, 8);
}
}
}
diff --git a/src/pkg/runtime/linux/amd64/sys.s b/src/pkg/runtime/linux/amd64/sys.s
index dd0473158..170b659fc 100644
--- a/src/pkg/runtime/linux/amd64/sys.s
+++ b/src/pkg/runtime/linux/amd64/sys.s
@@ -8,19 +8,19 @@
#include "amd64/asm.h"
-TEXT exit(SB),7,$0-8
+TEXT runtime·exit(SB),7,$0-8
MOVL 8(SP), DI
MOVL $231, AX // exitgroup - force all os threads to exit
SYSCALL
RET
-TEXT exit1(SB),7,$0-8
+TEXT runtime·exit1(SB),7,$0-8
MOVL 8(SP), DI
MOVL $60, AX // exit - exit the current os thread
SYSCALL
RET
-TEXT open(SB),7,$0-16
+TEXT runtime·open(SB),7,$0-16
MOVQ 8(SP), DI
MOVL 16(SP), SI
MOVL 20(SP), DX
@@ -28,7 +28,7 @@ TEXT open(SB),7,$0-16
SYSCALL
RET
-TEXT write(SB),7,$0-24
+TEXT runtime·write(SB),7,$0-24
MOVL 8(SP), DI
MOVQ 16(SP), SI
MOVL 24(SP), DX
@@ -36,7 +36,7 @@ TEXT write(SB),7,$0-24
SYSCALL
RET
-TEXT gettime(SB), 7, $32
+TEXT runtime·gettime(SB), 7, $32
LEAQ 8(SP), DI
MOVQ $0, SI
MOVQ $0xffffffffff600000, AX
@@ -51,7 +51,7 @@ TEXT gettime(SB), 7, $32
MOVL BX, (DI)
RET
-TEXT rt_sigaction(SB),7,$0-32
+TEXT runtime·rt_sigaction(SB),7,$0-32
MOVL 8(SP), DI
MOVQ 16(SP), SI
MOVQ 24(SP), DX
@@ -60,23 +60,38 @@ TEXT rt_sigaction(SB),7,$0-32
SYSCALL
RET
-TEXT sigtramp(SB),7,$24-16
- MOVQ m_gsignal(m), g
+TEXT runtime·sigtramp(SB),7,$64
+ get_tls(BX)
+
+ // save g
+ MOVQ g(BX), BP
+ MOVQ BP, 40(SP)
+
+ // g = m->gsignal
+ MOVQ m(BX), BP
+ MOVQ m_gsignal(BP), BP
+ MOVQ BP, g(BX)
+
MOVQ DI, 0(SP)
MOVQ SI, 8(SP)
MOVQ DX, 16(SP)
- CALL sighandler(SB)
+ CALL runtime·sighandler(SB)
+
+ // restore g
+ get_tls(BX)
+ MOVQ 40(SP), BP
+ MOVQ BP, g(BX)
RET
-TEXT sigignore(SB),7,$0
+TEXT runtime·sigignore(SB),7,$0
RET
-TEXT sigreturn(SB),7,$0
+TEXT runtime·sigreturn(SB),7,$0
MOVL $15, AX // rt_sigreturn
SYSCALL
INT $3 // not reached
-TEXT ·mmap(SB),7,$0
+TEXT runtime·mmap(SB),7,$0
MOVQ 8(SP), DI
MOVQ $0, SI
MOVQ 16(SP), SI
@@ -85,7 +100,7 @@ TEXT ·mmap(SB),7,$0
MOVL 32(SP), R8
MOVL 36(SP), R9
- MOVL $9, AX // syscall entry
+ MOVL $9, AX // mmap
SYSCALL
CMPQ AX, $0xfffffffffffff001
JLS 3(PC)
@@ -93,14 +108,24 @@ TEXT ·mmap(SB),7,$0
INCQ AX
RET
-TEXT notok(SB),7,$0
+TEXT runtime·munmap(SB),7,$0
+ MOVQ 8(SP), DI
+ MOVQ 16(SP), SI
+ MOVQ $11, AX // munmap
+ SYSCALL
+ CMPQ AX, $0xfffffffffffff001
+ JLS 2(PC)
+ CALL runtime·notok(SB)
+ RET
+
+TEXT runtime·notok(SB),7,$0
MOVQ $0xf1, BP
MOVQ BP, (BP)
RET
// int64 futex(int32 *uaddr, int32 op, int32 val,
// struct timespec *timeout, int32 *uaddr2, int32 val2);
-TEXT futex(SB),7,$0
+TEXT runtime·futex(SB),7,$0
MOVQ 8(SP), DI
MOVL 16(SP), SI
MOVL 20(SP), DX
@@ -112,7 +137,7 @@ TEXT futex(SB),7,$0
RET
// int64 clone(int32 flags, void *stack, M *m, G *g, void (*fn)(void));
-TEXT clone(SB),7,$0
+TEXT runtime·clone(SB),7,$0
MOVL flags+8(SP), DI
MOVQ stack+16(SP), SI
@@ -129,17 +154,24 @@ TEXT clone(SB),7,$0
CMPQ AX, $0
JEQ 2(PC)
RET
-
- // In child, set up new stack
+
+ // In child, on new stack.
MOVQ SI, SP
- MOVQ R8, m
- MOVQ R9, g
- CALL stackcheck(SB)
-
+
// Initialize m->procid to Linux tid
MOVL $186, AX // gettid
SYSCALL
- MOVQ AX, m_procid(m)
+ 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
@@ -150,12 +182,26 @@ TEXT clone(SB),7,$0
SYSCALL
JMP -3(PC) // keep exiting
-TEXT sigaltstack(SB),7,$-8
+TEXT runtime·sigaltstack(SB),7,$-8
MOVQ new+8(SP), DI
MOVQ old+16(SP), SI
MOVQ $131, AX
SYSCALL
CMPQ AX, $0xfffffffffffff001
JLS 2(PC)
- CALL notok(SB)
+ CALL runtime·notok(SB)
+ RET
+
+// set tls base to DI
+TEXT runtime·settls(SB),7,$32
+ ADDQ $16, DI // ELF wants to use -16(FS), -8(FS)
+
+ MOVQ DI, SI
+ MOVQ $0x1002, DI // ARCH_SET_FS
+ MOVQ $158, AX // arch_prctl
+ SYSCALL
+ CMPQ AX, $0xfffffffffffff001
+ JLS 2(PC)
+ CALL runtime·notok(SB)
RET
+
diff --git a/src/pkg/runtime/linux/arm/defs.h b/src/pkg/runtime/linux/arm/defs.h
index b13985171..ff43d689a 100644
--- a/src/pkg/runtime/linux/arm/defs.h
+++ b/src/pkg/runtime/linux/arm/defs.h
@@ -10,6 +10,7 @@ enum {
PROT_EXEC = 0x4,
MAP_ANON = 0x20,
MAP_PRIVATE = 0x2,
+ MAP_FIXED = 0x10,
SA_RESTART = 0x10000000,
SA_ONSTACK = 0x8000000,
SA_RESTORER = 0x4000000,
@@ -44,19 +45,19 @@ enum {
SIGIO = 0x1d,
SIGPWR = 0x1e,
SIGSYS = 0x1f,
- FPE_INTDIV = 0x30001,
- FPE_INTOVF = 0x30002,
- FPE_FLTDIV = 0x30003,
- FPE_FLTOVF = 0x30004,
- FPE_FLTUND = 0x30005,
- FPE_FLTRES = 0x30006,
- FPE_FLTINV = 0x30007,
- FPE_FLTSUB = 0x30008,
- BUS_ADRALN = 0x30001,
- BUS_ADRERR = 0x30002,
- BUS_OBJERR = 0x30003,
- SEGV_MAPERR = 0x30001,
- SEGV_ACCERR = 0x30002,
+ 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,
};
// Types
diff --git a/src/pkg/runtime/linux/arm/rt0.s b/src/pkg/runtime/linux/arm/rt0.s
index 024547ddd..8838b4891 100644
--- a/src/pkg/runtime/linux/arm/rt0.s
+++ b/src/pkg/runtime/linux/arm/rt0.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
+TEXT _rt0_arm_linux(SB),7,$0
B _rt0_arm(SB)
diff --git a/src/pkg/runtime/linux/arm/signal.c b/src/pkg/runtime/linux/arm/signal.c
index a9dccae4a..c65aff913 100644
--- a/src/pkg/runtime/linux/arm/signal.c
+++ b/src/pkg/runtime/linux/arm/signal.c
@@ -8,49 +8,49 @@
#include "os.h"
void
-dumpregs(Sigcontext *r)
+runtime·dumpregs(Sigcontext *r)
{
- printf("trap %x\n", r->trap_no);
- printf("error %x\n", r->error_code);
- printf("oldmask %x\n", r->oldmask);
- printf("r0 %x\n", r->arm_r0);
- printf("r1 %x\n", r->arm_r1);
- printf("r2 %x\n", r->arm_r2);
- printf("r3 %x\n", r->arm_r3);
- printf("r4 %x\n", r->arm_r4);
- printf("r5 %x\n", r->arm_r5);
- printf("r6 %x\n", r->arm_r6);
- printf("r7 %x\n", r->arm_r7);
- printf("r8 %x\n", r->arm_r8);
- printf("r9 %x\n", r->arm_r9);
- printf("r10 %x\n", r->arm_r10);
- printf("fp %x\n", r->arm_fp);
- printf("ip %x\n", r->arm_ip);
- printf("sp %x\n", r->arm_sp);
- printf("lr %x\n", r->arm_lr);
- printf("pc %x\n", r->arm_pc);
- printf("cpsr %x\n", r->arm_cpsr);
- printf("fault %x\n", r->fault_address);
+ runtime·printf("trap %x\n", r->trap_no);
+ runtime·printf("error %x\n", r->error_code);
+ runtime·printf("oldmask %x\n", r->oldmask);
+ runtime·printf("r0 %x\n", r->arm_r0);
+ runtime·printf("r1 %x\n", r->arm_r1);
+ runtime·printf("r2 %x\n", r->arm_r2);
+ runtime·printf("r3 %x\n", r->arm_r3);
+ runtime·printf("r4 %x\n", r->arm_r4);
+ runtime·printf("r5 %x\n", r->arm_r5);
+ runtime·printf("r6 %x\n", r->arm_r6);
+ runtime·printf("r7 %x\n", r->arm_r7);
+ runtime·printf("r8 %x\n", r->arm_r8);
+ runtime·printf("r9 %x\n", r->arm_r9);
+ runtime·printf("r10 %x\n", r->arm_r10);
+ runtime·printf("fp %x\n", r->arm_fp);
+ runtime·printf("ip %x\n", r->arm_ip);
+ runtime·printf("sp %x\n", r->arm_sp);
+ runtime·printf("lr %x\n", r->arm_lr);
+ runtime·printf("pc %x\n", r->arm_pc);
+ runtime·printf("cpsr %x\n", r->arm_cpsr);
+ runtime·printf("fault %x\n", r->fault_address);
}
/*
* This assembler routine takes the args from registers, puts them on the stack,
* and calls sighandler().
*/
-extern void sigtramp(void);
-extern void sigignore(void); // just returns
-extern void sigreturn(void); // calls sigreturn
+extern void runtime·sigtramp(void);
+extern void runtime·sigignore(void); // just returns
+extern void runtime·sigreturn(void); // calls runtime·sigreturn
String
-signame(int32 sig)
+runtime·signame(int32 sig)
{
if(sig < 0 || sig >= NSIG)
- return emptystring;
- return gostringnocopy((byte*)sigtab[sig].name);
+ return runtime·emptystring;
+ return runtime·gostringnocopy((byte*)runtime·sigtab[sig].name);
}
void
-sighandler(int32 sig, Siginfo *info, void *context)
+runtime·sighandler(int32 sig, Siginfo *info, void *context)
{
Ucontext *uc;
Sigcontext *r;
@@ -59,7 +59,7 @@ sighandler(int32 sig, Siginfo *info, void *context)
uc = context;
r = &uc->uc_mcontext;
- if((gp = m->curg) != nil && (sigtab[sig].flags & SigPanic)) {
+ if((gp = m->curg) != nil && (runtime·sigtab[sig].flags & SigPanic)) {
// Make it look like a call to the signal func.
// Have to pass arguments out of band since
// augmenting the stack frame would break
@@ -75,75 +75,75 @@ sighandler(int32 sig, Siginfo *info, void *context)
// old link register is more useful in the stack trace.
if(r->arm_pc != 0)
r->arm_lr = r->arm_pc;
- r->arm_pc = (uintptr)sigpanic;
+ r->arm_pc = (uintptr)runtime·sigpanic;
return;
}
- if(sigtab[sig].flags & SigQueue) {
- if(sigsend(sig) || (sigtab[sig].flags & SigIgnore))
+ if(runtime·sigtab[sig].flags & SigQueue) {
+ if(runtime·sigsend(sig) || (runtime·sigtab[sig].flags & SigIgnore))
return;
- exit(2); // SIGINT, SIGTERM, etc
+ runtime·exit(2); // SIGINT, SIGTERM, etc
}
- if(panicking) // traceback already printed
- exit(2);
- panicking = 1;
+ if(runtime·panicking) // traceback already printed
+ runtime·exit(2);
+ runtime·panicking = 1;
if(sig < 0 || sig >= NSIG)
- printf("Signal %d\n", sig);
+ runtime·printf("Signal %d\n", sig);
else
- printf("%s\n", sigtab[sig].name);
+ runtime·printf("%s\n", runtime·sigtab[sig].name);
- printf("PC=%x\n", r->arm_pc);
- printf("\n");
+ runtime·printf("PC=%x\n", r->arm_pc);
+ runtime·printf("\n");
- if(gotraceback()){
- traceback((void*)r->arm_pc, (void*)r->arm_sp, (void*)r->arm_lr, m->curg);
- tracebackothers(m->curg);
- printf("\n");
- dumpregs(r);
+ if(runtime·gotraceback()){
+ runtime·traceback((void*)r->arm_pc, (void*)r->arm_sp, (void*)r->arm_lr, m->curg);
+ runtime·tracebackothers(m->curg);
+ runtime·printf("\n");
+ runtime·dumpregs(r);
}
// breakpoint();
- exit(2);
+ runtime·exit(2);
}
void
-signalstack(byte *p, int32 n)
+runtime·signalstack(byte *p, int32 n)
{
Sigaltstack st;
st.ss_sp = p;
st.ss_size = n;
st.ss_flags = 0;
- sigaltstack(&st, nil);
+ runtime·sigaltstack(&st, nil);
}
void
-initsig(int32 queue)
+runtime·initsig(int32 queue)
{
static Sigaction sa;
- siginit();
+ runtime·siginit();
int32 i;
sa.sa_flags = SA_ONSTACK | SA_SIGINFO | SA_RESTORER;
sa.sa_mask.sig[0] = 0xFFFFFFFF;
sa.sa_mask.sig[1] = 0xFFFFFFFF;
- sa.sa_restorer = (void*)sigreturn;
+ sa.sa_restorer = (void*)runtime·sigreturn;
for(i = 0; i<NSIG; i++) {
- if(sigtab[i].flags) {
- if((sigtab[i].flags & SigQueue) != queue)
+ if(runtime·sigtab[i].flags) {
+ if((runtime·sigtab[i].flags & SigQueue) != queue)
continue;
- if(sigtab[i].flags & (SigCatch | SigQueue))
- sa.sa_handler = (void*)sigtramp;
+ if(runtime·sigtab[i].flags & (SigCatch | SigQueue))
+ sa.sa_handler = (void*)runtime·sigtramp;
else
- sa.sa_handler = (void*)sigignore;
- if(sigtab[i].flags & SigRestart)
+ sa.sa_handler = (void*)runtime·sigignore;
+ if(runtime·sigtab[i].flags & SigRestart)
sa.sa_flags |= SA_RESTART;
else
sa.sa_flags &= ~SA_RESTART;
- rt_sigaction(i, &sa, nil, 8);
+ runtime·rt_sigaction(i, &sa, nil, 8);
}
}
}
diff --git a/src/pkg/runtime/linux/arm/sys.s b/src/pkg/runtime/linux/arm/sys.s
index f30aed001..b25cf81aa 100644
--- a/src/pkg/runtime/linux/arm/sys.s
+++ b/src/pkg/runtime/linux/arm/sys.s
@@ -25,11 +25,12 @@
#define SYS_gettid (SYS_BASE + 224)
#define SYS_futex (SYS_BASE + 240)
#define SYS_exit_group (SYS_BASE + 248)
+#define SYS_munmap (SYS_BASE + 91)
#define ARM_BASE (SYS_BASE + 0x0f0000)
#define SYS_ARM_cacheflush (ARM_BASE + 2)
-TEXT write(SB),7,$0
+TEXT runtime·write(SB),7,$0
MOVW 0(FP), R0
MOVW 4(FP), R1
MOVW 8(FP), R2
@@ -37,7 +38,7 @@ TEXT write(SB),7,$0
SWI $0
RET
-TEXT exit(SB),7,$-4
+TEXT runtime·exit(SB),7,$-4
MOVW 0(FP), R0
MOVW $SYS_exit_group, R7
SWI $0
@@ -45,7 +46,7 @@ TEXT exit(SB),7,$-4
MOVW $1002, R1
MOVW R0, (R1) // fail hard
-TEXT exit1(SB),7,$-4
+TEXT runtime·exit1(SB),7,$-4
MOVW 0(FP), R0
MOVW $SYS_exit, R7
SWI $0
@@ -53,7 +54,7 @@ TEXT exit1(SB),7,$-4
MOVW $1003, R1
MOVW R0, (R1) // fail hard
-TEXT ·mmap(SB),7,$0
+TEXT runtime·mmap(SB),7,$0
MOVW 0(FP), R0
MOVW 4(FP), R1
MOVW 8(FP), R2
@@ -64,7 +65,14 @@ TEXT ·mmap(SB),7,$0
SWI $0
RET
-TEXT gettime(SB),7,$32
+TEXT runtime·munmap(SB),7,$0
+ MOVW 0(FP), R0
+ MOVW 4(FP), R1
+ MOVW $SYS_munmap, R7
+ SWI $0
+ RET
+
+TEXT runtime·gettime(SB),7,$32
/* dummy version - return 0,0 */
MOVW $0, R1
MOVW 0(FP), R0
@@ -93,7 +101,7 @@ TEXT gettime(SB),7,$32
// int32 futex(int32 *uaddr, int32 op, int32 val,
// struct timespec *timeout, int32 *uaddr2, int32 val2);
-TEXT futex(SB),7,$0
+TEXT runtime·futex(SB),7,$0
MOVW 4(SP), R0
MOVW 8(SP), R1
MOVW 12(SP), R2
@@ -106,7 +114,7 @@ TEXT futex(SB),7,$0
// int32 clone(int32 flags, void *stack, M *m, G *g, void (*fn)(void));
-TEXT clone(SB),7,$0
+TEXT runtime·clone(SB),7,$0
MOVW flags+0(FP), R0
MOVW stack+4(FP), R1
MOVW $0, R2 // parent tid ptr
@@ -139,7 +147,7 @@ TEXT clone(SB),7,$0
MOVW $1234, R1
CMP R0, R1
BEQ 2(PC)
- B abort(SB)
+ BL runtime·abort(SB)
MOVW 0(R13), m
MOVW 4(R13), g
@@ -148,7 +156,7 @@ TEXT clone(SB),7,$0
MOVW 0(m), R0
MOVW 0(g), R0
- BL emptyfunc(SB) // fault if stack check is wrong
+ BL runtime·emptyfunc(SB) // fault if stack check is wrong
// Initialize m->procid to Linux tid
MOVW $SYS_gettid, R7
@@ -162,7 +170,7 @@ TEXT clone(SB),7,$0
MOVW $0, R0
MOVW R0, 4(R13)
- BL exit1(SB)
+ BL runtime·exit1(SB)
// It shouldn't return
MOVW $1234, R0
@@ -170,7 +178,7 @@ TEXT clone(SB),7,$0
MOVW R0, (R1)
-TEXT cacheflush(SB),7,$0
+TEXT runtime·cacheflush(SB),7,$0
MOVW 0(FP), R0
MOVW 4(FP), R1
MOVW $0, R2
@@ -178,30 +186,25 @@ TEXT cacheflush(SB),7,$0
SWI $0
RET
-TEXT sigaltstack(SB),7,$0
+TEXT runtime·sigaltstack(SB),7,$0
MOVW 0(FP), R0
MOVW 4(FP), R1
MOVW $SYS_sigaltstack, R7
SWI $0
RET
-TEXT sigignore(SB),7,$0
- RET
-
-TEXT sigreturn(SB),7,$0
- MOVW R0, R0
- B abort(SB)
+TEXT runtime·sigignore(SB),7,$0
RET
-TEXT sigtramp(SB),7,$24
+TEXT runtime·sigtramp(SB),7,$24
MOVW m_gsignal(m), g
MOVW R0, 4(R13)
MOVW R1, 8(R13)
MOVW R2, 12(R13)
- BL sighandler(SB)
+ BL runtime·sighandler(SB)
RET
-TEXT rt_sigaction(SB),7,$0
+TEXT runtime·rt_sigaction(SB),7,$0
MOVW 0(FP), R0
MOVW 4(FP), R1
MOVW 8(FP), R2
@@ -210,7 +213,7 @@ TEXT rt_sigaction(SB),7,$0
SWI $0
RET
-TEXT sigreturn(SB),7,$0
+TEXT runtime·sigreturn(SB),7,$0
MOVW $SYS_rt_sigreturn, R7
SWI $0
RET
diff --git a/src/pkg/runtime/linux/defs.c b/src/pkg/runtime/linux/defs.c
index f3bdb61fa..2044fd60c 100644
--- a/src/pkg/runtime/linux/defs.c
+++ b/src/pkg/runtime/linux/defs.c
@@ -27,6 +27,7 @@ enum {
$MAP_ANON = MAP_ANONYMOUS,
$MAP_PRIVATE = MAP_PRIVATE,
+ $MAP_FIXED = MAP_FIXED,
$SA_RESTART = SA_RESTART,
$SA_ONSTACK = SA_ONSTACK,
diff --git a/src/pkg/runtime/linux/defs2.c b/src/pkg/runtime/linux/defs2.c
index 4cfe4a7ed..3c0b110fc 100644
--- a/src/pkg/runtime/linux/defs2.c
+++ b/src/pkg/runtime/linux/defs2.c
@@ -47,6 +47,7 @@ enum {
$MAP_ANON = MAP_ANONYMOUS,
$MAP_PRIVATE = MAP_PRIVATE,
+ $MAP_FIXED = MAP_FIXED,
$SA_RESTART = SA_RESTART,
$SA_ONSTACK = SA_ONSTACK,
diff --git a/src/pkg/runtime/linux/defs_arm.c b/src/pkg/runtime/linux/defs_arm.c
index 2b197272c..a5897d6d0 100644
--- a/src/pkg/runtime/linux/defs_arm.c
+++ b/src/pkg/runtime/linux/defs_arm.c
@@ -31,6 +31,7 @@ enum {
$MAP_ANON = MAP_ANONYMOUS,
$MAP_PRIVATE = MAP_PRIVATE,
+ $MAP_FIXED = MAP_FIXED,
$SA_RESTART = SA_RESTART,
$SA_ONSTACK = SA_ONSTACK,
@@ -67,22 +68,22 @@ enum {
$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,
- $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,
+ $BUS_ADRALN = BUS_ADRALN & 0xFFFF,
+ $BUS_ADRERR = BUS_ADRERR & 0xFFFF,
+ $BUS_OBJERR = BUS_OBJERR & 0xFFFF,
- $SEGV_MAPERR = SEGV_MAPERR,
- $SEGV_ACCERR = SEGV_ACCERR,
+ $SEGV_MAPERR = SEGV_MAPERR & 0xFFFF,
+ $SEGV_ACCERR = SEGV_ACCERR & 0xFFFF,
};
typedef sigset_t $Sigset;
diff --git a/src/pkg/runtime/linux/mem.c b/src/pkg/runtime/linux/mem.c
index 7f837bd45..e750f97ea 100644
--- a/src/pkg/runtime/linux/mem.c
+++ b/src/pkg/runtime/linux/mem.c
@@ -4,26 +4,26 @@
#include "malloc.h"
void*
-SysAlloc(uintptr n)
+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);
+ 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) {
- printf("mmap: access denied\n");
- printf("If you're running SELinux, enable execmem for this process.\n");
- } else {
- printf("mmap: errno=%p\n", p);
+ runtime·printf("mmap: access denied\n");
+ runtime·printf("If you're running SELinux, enable execmem for this process.\n");
+ runtime·exit(2);
}
- exit(2);
+ runtime·printf("mmap: errno=%p\n", p);
+ runtime·throw("mmap");
}
return p;
}
void
-SysUnused(void *v, uintptr n)
+runtime·SysUnused(void *v, uintptr n)
{
USED(v);
USED(n);
@@ -31,10 +31,13 @@ SysUnused(void *v, uintptr n)
}
void
-SysFree(void *v, uintptr n)
+runtime·SysFree(void *v, uintptr n)
{
- USED(v);
- USED(n);
- // TODO(rsc): call munmap
+ mstats.sys -= n;
+ runtime·munmap(v, n);
}
+void
+runtime·SysMemInit(void)
+{
+}
diff --git a/src/pkg/runtime/linux/os.h b/src/pkg/runtime/linux/os.h
index 8ca26b748..772ade7da 100644
--- a/src/pkg/runtime/linux/os.h
+++ b/src/pkg/runtime/linux/os.h
@@ -3,11 +3,11 @@
// license that can be found in the LICENSE file.
// Linux-specific system calls
-int32 futex(uint32*, int32, uint32, Timespec*, uint32*, uint32);
-int32 clone(int32, void*, M*, G*, void(*)(void));
+int32 runtime·futex(uint32*, int32, uint32, Timespec*, uint32*, uint32);
+int32 runtime·clone(int32, void*, M*, G*, void(*)(void));
struct Sigaction;
-void rt_sigaction(uintptr, struct Sigaction*, void*, uintptr);
+void runtime·rt_sigaction(uintptr, struct Sigaction*, void*, uintptr);
-void sigaltstack(Sigaltstack*, Sigaltstack*);
-void sigpanic(void);
+void runtime·sigaltstack(Sigaltstack*, Sigaltstack*);
+void runtime·sigpanic(void);
diff --git a/src/pkg/runtime/linux/runtime_defs.go b/src/pkg/runtime/linux/runtime_defs.go
new file mode 100644
index 000000000..86de13316
--- /dev/null
+++ b/src/pkg/runtime/linux/runtime_defs.go
@@ -0,0 +1,14 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// OS-Specific Go definitions of internal structures. Master is runtime.h
+
+package runtime
+
+type lock struct {
+ key uint32
+ sema uint32
+}
+
+type note lock
diff --git a/src/pkg/runtime/linux/signals.h b/src/pkg/runtime/linux/signals.h
index 788f68240..1fc5f8c87 100644
--- a/src/pkg/runtime/linux/signals.h
+++ b/src/pkg/runtime/linux/signals.h
@@ -8,7 +8,7 @@
#define Q SigQueue
#define P SigPanic
-SigTab sigtab[] = {
+SigTab runtime·sigtab[] = {
/* 0 */ 0, "SIGNONE: no trap",
/* 1 */ Q+R, "SIGHUP: terminal line hangup",
/* 2 */ Q+R, "SIGINT: interrupt",
diff --git a/src/pkg/runtime/linux/thread.c b/src/pkg/runtime/linux/thread.c
index a849125f9..979260ba1 100644
--- a/src/pkg/runtime/linux/thread.c
+++ b/src/pkg/runtime/linux/thread.c
@@ -6,7 +6,7 @@
#include "defs.h"
#include "os.h"
-extern SigTab sigtab[];
+extern SigTab runtime·sigtab[];
// Linux futex.
//
@@ -48,7 +48,7 @@ futexsleep(uint32 *addr, uint32 val)
// as an errno. Libpthread ignores the return value
// here, and so can we: as it says a few lines up,
// spurious wakeups are allowed.
- futex(addr, FUTEX_WAIT, val, &longtime, nil, 0);
+ runtime·futex(addr, FUTEX_WAIT, val, &longtime, nil, 0);
}
// If any procs are sleeping on addr, wake up at least one.
@@ -57,7 +57,7 @@ futexwakeup(uint32 *addr)
{
int64 ret;
- ret = futex(addr, FUTEX_WAKE, 1, nil, nil, 0);
+ ret = runtime·futex(addr, FUTEX_WAKE, 1, nil, nil, 0);
if(ret >= 0)
return;
@@ -66,11 +66,11 @@ futexwakeup(uint32 *addr)
// EAGAIN or EINTR, but if it does, it would be
// safe to loop and call futex again.
- prints("futexwakeup addr=");
- ·printpointer(addr);
- prints(" returned ");
- ·printint(ret);
- prints("\n");
+ runtime·prints("futexwakeup addr=");
+ runtime·printpointer(addr);
+ runtime·prints(" returned ");
+ runtime·printint(ret);
+ runtime·prints("\n");
*(int32*)0x1006 = 0x1006;
}
@@ -83,7 +83,7 @@ futexwakeup(uint32 *addr)
// The uncontended case runs entirely in user space.
// When contention is detected, we defer to the kernel (futex).
//
-// A reminder: compare-and-swap cas(addr, old, new) does
+// A reminder: compare-and-swap runtime·cas(addr, old, new) does
// if(*addr == old) { *addr = new; return 1; }
// else return 0;
// but atomically.
@@ -96,7 +96,7 @@ futexlock(Lock *l)
again:
v = l->key;
if((v&1) == 0){
- if(cas(&l->key, v, v|1)){
+ if(runtime·cas(&l->key, v, v|1)){
// Lock wasn't held; we grabbed it.
return;
}
@@ -104,7 +104,7 @@ again:
}
// Lock was held; try to add ourselves to the waiter count.
- if(!cas(&l->key, v, v+2))
+ if(!runtime·cas(&l->key, v, v+2))
goto again;
// We're accounted for, now sleep in the kernel.
@@ -122,8 +122,8 @@ again:
for(;;){
v = l->key;
if(v < 2)
- throw("bad lock key");
- if(cas(&l->key, v, v-2))
+ runtime·throw("bad lock key");
+ if(runtime·cas(&l->key, v, v-2))
break;
}
@@ -140,8 +140,8 @@ futexunlock(Lock *l)
again:
v = l->key;
if((v&1) == 0)
- throw("unlock of unlocked lock");
- if(!cas(&l->key, v, v&~1))
+ runtime·throw("unlock of unlocked lock");
+ if(!runtime·cas(&l->key, v, v&~1))
goto again;
// If there were waiters, wake one.
@@ -150,25 +150,25 @@ again:
}
void
-lock(Lock *l)
+runtime·lock(Lock *l)
{
if(m->locks < 0)
- throw("lock count");
+ runtime·throw("lock count");
m->locks++;
futexlock(l);
}
void
-unlock(Lock *l)
+runtime·unlock(Lock *l)
{
m->locks--;
if(m->locks < 0)
- throw("lock count");
+ runtime·throw("lock count");
futexunlock(l);
}
void
-destroylock(Lock *l)
+runtime·destroylock(Lock*)
{
}
@@ -186,20 +186,20 @@ destroylock(Lock *l)
// you unlock the lock.
void
-noteclear(Note *n)
+runtime·noteclear(Note *n)
{
n->lock.key = 0; // memset(n, 0, sizeof *n)
futexlock(&n->lock);
}
void
-notewakeup(Note *n)
+runtime·notewakeup(Note *n)
{
futexunlock(&n->lock);
}
void
-notesleep(Note *n)
+runtime·notesleep(Note *n)
{
futexlock(&n->lock);
futexunlock(&n->lock); // Let other sleepers find out too.
@@ -230,7 +230,7 @@ enum
};
void
-newosproc(M *m, G *g, void *stk, void (*fn)(void))
+runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void))
{
int32 ret;
int32 flags;
@@ -248,50 +248,58 @@ newosproc(M *m, G *g, void *stk, void (*fn)(void))
m->tls[0] = m->id; // so 386 asm can find it
if(0){
- printf("newosproc stk=%p m=%p g=%p fn=%p clone=%p id=%d/%d ostk=%p\n",
- stk, m, g, fn, clone, m->id, m->tls[0], &m);
+ runtime·printf("newosproc stk=%p m=%p g=%p fn=%p clone=%p id=%d/%d ostk=%p\n",
+ stk, m, g, fn, runtime·clone, m->id, m->tls[0], &m);
}
- ret = clone(flags, stk, m, g, fn);
+ ret = runtime·clone(flags, stk, m, g, fn);
if(ret < 0)
*(int32*)123 = 123;
}
void
-osinit(void)
+runtime·osinit(void)
{
}
+void
+runtime·goenvs(void)
+{
+ runtime·goenvs_unix();
+}
+
// Called to initialize a new m (including the bootstrap m).
void
-minit(void)
+runtime·minit(void)
{
// Initialize signal handling.
- m->gsignal = malg(32*1024); // OS X wants >=8K, Linux >=2K
- signalstack(m->gsignal->stackguard, 32*1024);
+ m->gsignal = runtime·malg(32*1024); // OS X wants >=8K, Linux >=2K
+ runtime·signalstack(m->gsignal->stackguard, 32*1024);
}
void
-sigpanic(void)
+runtime·sigpanic(void)
{
switch(g->sig) {
case SIGBUS:
if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000)
- panicstring("invalid memory address or nil pointer dereference");
- break;
+ 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->sigcode1 < 0x1000)
- panicstring("invalid memory address or nil pointer dereference");
- break;
+ 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:
- panicstring("integer divide by zero");
+ runtime·panicstring("integer divide by zero");
case FPE_INTOVF:
- panicstring("integer overflow");
+ runtime·panicstring("integer overflow");
}
- panicstring("floating point error");
+ runtime·panicstring("floating point error");
}
- panicstring(sigtab[g->sig].name);
+ runtime·panicstring(runtime·sigtab[g->sig].name);
}
diff --git a/src/pkg/runtime/malloc.goc b/src/pkg/runtime/malloc.goc
index 59aeba739..f5ca9f918 100644
--- a/src/pkg/runtime/malloc.goc
+++ b/src/pkg/runtime/malloc.goc
@@ -12,10 +12,10 @@ package runtime
#include "defs.h"
#include "type.h"
-MHeap mheap;
-MStats mstats;
+MHeap runtime·mheap;
+extern MStats mstats; // defined in extern.go
-extern volatile int32 ·MemProfileRate;
+extern volatile int32 runtime·MemProfileRate;
// Same algorithm from chan.c, but a different
// instance of the static uint32 x.
@@ -36,7 +36,7 @@ fastrand1(void)
// Small objects are allocated from the per-thread cache's free lists.
// Large objects (> 32 kB) are allocated straight from the heap.
void*
-mallocgc(uintptr size, uint32 refflag, int32 dogc, int32 zeroed)
+runtime·mallocgc(uintptr size, uint32 refflag, int32 dogc, int32 zeroed)
{
int32 sizeclass, rate;
MCache *c;
@@ -45,10 +45,10 @@ mallocgc(uintptr size, uint32 refflag, int32 dogc, int32 zeroed)
void *v;
uint32 *ref;
- if(gcwaiting && g != m->g0 && m->locks == 0)
- gosched();
+ if(runtime·gcwaiting && g != m->g0 && m->locks == 0)
+ runtime·gosched();
if(m->mallocing)
- throw("malloc/free - deadlock");
+ runtime·throw("malloc/free - deadlock");
m->mallocing = 1;
if(size == 0)
size = 1;
@@ -56,19 +56,19 @@ mallocgc(uintptr size, uint32 refflag, int32 dogc, int32 zeroed)
mstats.nmalloc++;
if(size <= MaxSmallSize) {
// Allocate from mcache free lists.
- sizeclass = SizeToClass(size);
- size = class_to_size[sizeclass];
+ sizeclass = runtime·SizeToClass(size);
+ size = runtime·class_to_size[sizeclass];
c = m->mcache;
- v = MCache_Alloc(c, sizeclass, size, zeroed);
+ v = runtime·MCache_Alloc(c, sizeclass, size, zeroed);
if(v == nil)
- throw("out of memory");
+ runtime·throw("out of memory");
mstats.alloc += size;
mstats.total_alloc += size;
mstats.by_size[sizeclass].nmalloc++;
- if(!mlookup(v, nil, nil, nil, &ref)) {
- printf("malloc %D; mlookup failed\n", (uint64)size);
- throw("malloc mlookup");
+ if(!runtime·mlookup(v, nil, nil, nil, &ref)) {
+ runtime·printf("malloc %D; runtime·mlookup failed\n", (uint64)size);
+ runtime·throw("malloc runtime·mlookup");
}
*ref = RefNone | refflag;
} else {
@@ -78,9 +78,9 @@ mallocgc(uintptr size, uint32 refflag, int32 dogc, int32 zeroed)
npages = size >> PageShift;
if((size & PageMask) != 0)
npages++;
- s = MHeap_Alloc(&mheap, npages, 0, 1);
+ s = runtime·MHeap_Alloc(&runtime·mheap, npages, 0, 1);
if(s == nil)
- throw("out of memory");
+ runtime·throw("out of memory");
size = npages<<PageShift;
mstats.alloc += size;
mstats.total_alloc += size;
@@ -93,7 +93,7 @@ mallocgc(uintptr size, uint32 refflag, int32 dogc, int32 zeroed)
m->mallocing = 0;
- if(!(refflag & RefNoProfiling) && (rate = ·MemProfileRate) > 0) {
+ if(!(refflag & RefNoProfiling) && (rate = runtime·MemProfileRate) > 0) {
if(size >= rate)
goto profile;
if(m->mcache->next_sample > size)
@@ -105,24 +105,24 @@ mallocgc(uintptr size, uint32 refflag, int32 dogc, int32 zeroed)
m->mcache->next_sample = fastrand1() % (2*rate);
profile:
*ref |= RefProfiled;
- MProf_Malloc(v, size);
+ runtime·MProf_Malloc(v, size);
}
}
if(dogc && mstats.heap_alloc >= mstats.next_gc)
- gc(0);
+ runtime·gc(0);
return v;
}
void*
-malloc(uintptr size)
+runtime·malloc(uintptr size)
{
- return mallocgc(size, 0, 0, 1);
+ return runtime·mallocgc(size, 0, 0, 1);
}
// Free the object whose base pointer is v.
void
-free(void *v)
+runtime·free(void *v)
{
int32 sizeclass, size;
MSpan *s;
@@ -133,12 +133,12 @@ free(void *v)
return;
if(m->mallocing)
- throw("malloc/free - deadlock");
+ runtime·throw("malloc/free - deadlock");
m->mallocing = 1;
- if(!mlookup(v, nil, nil, &s, &ref)) {
- printf("free %p: not an allocated block\n", v);
- throw("free mlookup");
+ if(!runtime·mlookup(v, nil, nil, &s, &ref)) {
+ runtime·printf("free %p: not an allocated block\n", v);
+ runtime·throw("free runtime·mlookup");
}
prof = *ref & RefProfiled;
*ref = RefFree;
@@ -148,34 +148,34 @@ free(void *v)
if(sizeclass == 0) {
// Large object.
if(prof)
- MProf_Free(v, s->npages<<PageShift);
+ runtime·MProf_Free(v, s->npages<<PageShift);
mstats.alloc -= s->npages<<PageShift;
- runtime_memclr(v, s->npages<<PageShift);
- MHeap_Free(&mheap, s, 1);
+ runtime·memclr(v, s->npages<<PageShift);
+ runtime·MHeap_Free(&runtime·mheap, s, 1);
} else {
// Small object.
c = m->mcache;
- size = class_to_size[sizeclass];
+ size = runtime·class_to_size[sizeclass];
if(size > sizeof(uintptr))
((uintptr*)v)[1] = 1; // mark as "needs to be zeroed"
if(prof)
- MProf_Free(v, size);
+ runtime·MProf_Free(v, size);
mstats.alloc -= size;
mstats.by_size[sizeclass].nfree++;
- MCache_Free(c, v, sizeclass, size);
+ runtime·MCache_Free(c, v, sizeclass, size);
}
m->mallocing = 0;
}
int32
-mlookup(void *v, byte **base, uintptr *size, MSpan **sp, uint32 **ref)
+runtime·mlookup(void *v, byte **base, uintptr *size, MSpan **sp, uint32 **ref)
{
uintptr n, nobj, i;
byte *p;
MSpan *s;
mstats.nlookup++;
- s = MHeap_LookupMaybe(&mheap, (uintptr)v>>PageShift);
+ s = runtime·MHeap_LookupMaybe(&runtime·mheap, (uintptr)v>>PageShift);
if(sp)
*sp = s;
if(s == nil) {
@@ -206,7 +206,7 @@ mlookup(void *v, byte **base, uintptr *size, MSpan **sp, uint32 **ref)
return 0;
}
- n = class_to_size[s->sizeclass];
+ n = runtime·class_to_size[s->sizeclass];
i = ((byte*)v - p)/n;
if(base)
*base = p + i*n;
@@ -217,12 +217,12 @@ mlookup(void *v, byte **base, uintptr *size, MSpan **sp, uint32 **ref)
if(0) {
nobj = (s->npages << PageShift) / (n + RefcountOverhead);
if((byte*)s->gcref < p || (byte*)(s->gcref+nobj) > p+(s->npages<<PageShift)) {
- printf("odd span state=%d span=%p base=%p sizeclass=%d n=%D size=%D npages=%D\n",
+ runtime·printf("odd span state=%d span=%p base=%p sizeclass=%d n=%D size=%D npages=%D\n",
s->state, s, p, s->sizeclass, (uint64)nobj, (uint64)n, (uint64)s->npages);
- printf("s->base sizeclass %d v=%p base=%p gcref=%p blocksize=%D nobj=%D size=%D end=%p end=%p\n",
+ runtime·printf("s->base sizeclass %d v=%p base=%p gcref=%p blocksize=%D nobj=%D size=%D end=%p end=%p\n",
s->sizeclass, v, p, s->gcref, (uint64)s->npages<<PageShift,
(uint64)nobj, (uint64)n, s->gcref + nobj, p+(s->npages<<PageShift));
- throw("bad gcref");
+ runtime·throw("bad gcref");
}
}
if(ref)
@@ -232,37 +232,42 @@ mlookup(void *v, byte **base, uintptr *size, MSpan **sp, uint32 **ref)
}
MCache*
-allocmcache(void)
+runtime·allocmcache(void)
{
MCache *c;
- c = FixAlloc_Alloc(&mheap.cachealloc);
- mstats.mcache_inuse = mheap.cachealloc.inuse;
- mstats.mcache_sys = mheap.cachealloc.sys;
+ runtime·lock(&runtime·mheap);
+ c = runtime·FixAlloc_Alloc(&runtime·mheap.cachealloc);
+ mstats.mcache_inuse = runtime·mheap.cachealloc.inuse;
+ mstats.mcache_sys = runtime·mheap.cachealloc.sys;
+ runtime·unlock(&runtime·mheap);
return c;
}
+int32 runtime·sizeof_C_MStats = sizeof(MStats);
+
void
-mallocinit(void)
+runtime·mallocinit(void)
{
- InitSizes();
- MHeap_Init(&mheap, SysAlloc);
- m->mcache = allocmcache();
+ runtime·SysMemInit();
+ runtime·InitSizes();
+ runtime·MHeap_Init(&runtime·mheap, runtime·SysAlloc);
+ m->mcache = runtime·allocmcache();
// See if it works.
- free(malloc(1));
+ runtime·free(runtime·malloc(1));
}
// Runtime stubs.
void*
-mal(uintptr n)
+runtime·mal(uintptr n)
{
- return mallocgc(n, 0, 1, 1);
+ return runtime·mallocgc(n, 0, 1, 1);
}
-func mal(n uint32) (ret *uint8) {
- ret = mal(n);
+func new(n uint32) (ret *uint8) {
+ ret = runtime·mal(n);
}
// Stack allocator uses malloc/free most of the time,
@@ -272,66 +277,66 @@ func mal(n uint32) (ret *uint8) {
// allocator, assuming that inside malloc all the stack
// frames are small, so that all the stack allocations
// will be a single size, the minimum (right now, 5k).
-struct {
+static struct {
Lock;
FixAlloc;
} stacks;
void*
-stackalloc(uint32 n)
+runtime·stackalloc(uint32 n)
{
void *v;
uint32 *ref;
if(m->mallocing || m->gcing) {
- lock(&stacks);
+ runtime·lock(&stacks);
if(stacks.size == 0)
- FixAlloc_Init(&stacks, n, SysAlloc, nil, nil);
+ runtime·FixAlloc_Init(&stacks, n, runtime·SysAlloc, nil, nil);
if(stacks.size != n) {
- printf("stackalloc: in malloc, size=%D want %d", (uint64)stacks.size, n);
- throw("stackalloc");
+ runtime·printf("stackalloc: in malloc, size=%D want %d", (uint64)stacks.size, n);
+ runtime·throw("stackalloc");
}
- v = FixAlloc_Alloc(&stacks);
+ v = runtime·FixAlloc_Alloc(&stacks);
mstats.stacks_inuse = stacks.inuse;
mstats.stacks_sys = stacks.sys;
- unlock(&stacks);
+ runtime·unlock(&stacks);
return v;
}
- v = mallocgc(n, RefNoProfiling, 0, 0);
- if(!mlookup(v, nil, nil, nil, &ref))
- throw("stackalloc mlookup");
+ v = runtime·mallocgc(n, RefNoProfiling, 0, 0);
+ if(!runtime·mlookup(v, nil, nil, nil, &ref))
+ runtime·throw("stackalloc runtime·mlookup");
*ref = RefStack;
return v;
}
void
-stackfree(void *v)
+runtime·stackfree(void *v)
{
if(m->mallocing || m->gcing) {
- lock(&stacks);
- FixAlloc_Free(&stacks, v);
+ runtime·lock(&stacks);
+ runtime·FixAlloc_Free(&stacks, v);
mstats.stacks_inuse = stacks.inuse;
mstats.stacks_sys = stacks.sys;
- unlock(&stacks);
+ runtime·unlock(&stacks);
return;
}
- free(v);
+ runtime·free(v);
}
func Alloc(n uintptr) (p *byte) {
- p = malloc(n);
+ p = runtime·malloc(n);
}
func Free(p *byte) {
- free(p);
+ runtime·free(p);
}
func Lookup(p *byte) (base *byte, size uintptr) {
- mlookup(p, &base, &size, nil, nil);
+ runtime·mlookup(p, &base, &size, nil, nil);
}
func GC() {
- gc(1);
+ runtime·gc(1);
}
func SetFinalizer(obj Eface, finalizer Eface) {
@@ -342,23 +347,23 @@ func SetFinalizer(obj Eface, finalizer Eface) {
Type *t;
if(obj.type == nil) {
- printf("runtime.SetFinalizer: first argument is nil interface\n");
+ runtime·printf("runtime.SetFinalizer: first argument is nil interface\n");
throw:
- throw("runtime.SetFinalizer");
+ runtime·throw("runtime.SetFinalizer");
}
if(obj.type->kind != KindPtr) {
- printf("runtime.SetFinalizer: first argument is %S, not pointer\n", *obj.type->string);
+ runtime·printf("runtime.SetFinalizer: first argument is %S, not pointer\n", *obj.type->string);
goto throw;
}
- if(!mlookup(obj.data, &base, &size, nil, nil) || obj.data != base) {
- printf("runtime.SetFinalizer: pointer not at beginning of allocated block\n");
+ if(!runtime·mlookup(obj.data, &base, &size, nil, nil) || obj.data != base) {
+ runtime·printf("runtime.SetFinalizer: pointer not at beginning of allocated block\n");
goto throw;
}
nret = 0;
if(finalizer.type != nil) {
if(finalizer.type->kind != KindFunc) {
badfunc:
- printf("runtime.SetFinalizer: second argument is %S, not func(%S)\n", *finalizer.type->string, *obj.type->string);
+ runtime·printf("runtime.SetFinalizer: second argument is %S, not func(%S)\n", *finalizer.type->string, *obj.type->string);
goto throw;
}
ft = (FuncType*)finalizer.type;
@@ -373,10 +378,10 @@ func SetFinalizer(obj Eface, finalizer Eface) {
}
nret = (nret + sizeof(void*)-1) & ~(sizeof(void*)-1);
- if(getfinalizer(obj.data, 0)) {
- printf("runtime.SetFinalizer: finalizer already set");
+ if(runtime·getfinalizer(obj.data, 0)) {
+ runtime·printf("runtime.SetFinalizer: finalizer already set");
goto throw;
}
}
- addfinalizer(obj.data, finalizer.data, nret);
+ runtime·addfinalizer(obj.data, finalizer.data, nret);
}
diff --git a/src/pkg/runtime/malloc.h b/src/pkg/runtime/malloc.h
index 473e8a836..0cee6c0dd 100644
--- a/src/pkg/runtime/malloc.h
+++ b/src/pkg/runtime/malloc.h
@@ -135,10 +135,10 @@ struct MLink
// an out-of-memory error has been detected midway through
// an allocation. It is okay if SysFree is a no-op.
-void* SysAlloc(uintptr nbytes);
-void SysFree(void *v, uintptr nbytes);
-void SysUnused(void *v, uintptr nbytes);
-
+void* runtime·SysAlloc(uintptr nbytes);
+void runtime·SysFree(void *v, uintptr nbytes);
+void runtime·SysUnused(void *v, uintptr nbytes);
+void runtime·SysMemInit(void);
// FixAlloc is a simple free-list allocator for fixed size objects.
// Malloc uses a FixAlloc wrapped around SysAlloc to manages its
@@ -161,9 +161,9 @@ struct FixAlloc
uintptr sys; // bytes obtained from system
};
-void FixAlloc_Init(FixAlloc *f, uintptr size, void *(*alloc)(uintptr), void (*first)(void*, byte*), void *arg);
-void* FixAlloc_Alloc(FixAlloc *f);
-void FixAlloc_Free(FixAlloc *f, void *p);
+void runtime·FixAlloc_Init(FixAlloc *f, uintptr size, void *(*alloc)(uintptr), void (*first)(void*, byte*), void *arg);
+void* runtime·FixAlloc_Alloc(FixAlloc *f);
+void runtime·FixAlloc_Free(FixAlloc *f, void *p);
// Statistics.
@@ -183,6 +183,7 @@ struct MStats
uint64 heap_sys; // bytes obtained from system
uint64 heap_idle; // bytes in idle spans
uint64 heap_inuse; // bytes in non-idle spans
+ uint64 heap_objects; // total number of allocated objects
// Statistics about allocation of low-level fixed-size structures.
// Protected by FixAlloc locks.
@@ -212,7 +213,7 @@ struct MStats
} by_size[NumSizeClasses];
};
-#define mstats ·MemStats /* name shared with Go */
+#define mstats runtime·MemStats /* name shared with Go */
extern MStats mstats;
@@ -229,11 +230,11 @@ extern MStats mstats;
// taking a bunch of objects out of the central lists
// and putting them in the thread free list.
-int32 SizeToClass(int32);
-extern int32 class_to_size[NumSizeClasses];
-extern int32 class_to_allocnpages[NumSizeClasses];
-extern int32 class_to_transfercount[NumSizeClasses];
-extern void InitSizes(void);
+int32 runtime·SizeToClass(int32);
+extern int32 runtime·class_to_size[NumSizeClasses];
+extern int32 runtime·class_to_allocnpages[NumSizeClasses];
+extern int32 runtime·class_to_transfercount[NumSizeClasses];
+extern void runtime·InitSizes(void);
// Per-thread (in Go, per-M) cache for small objects.
@@ -251,12 +252,13 @@ struct MCache
MCacheList list[NumSizeClasses];
uint64 size;
int64 local_alloc; // bytes allocated (or freed) since last lock of heap
+ int64 local_objects; // objects allocated (or freed) since last lock of heap
int32 next_sample; // trigger heap sample after allocating this many bytes
};
-void* MCache_Alloc(MCache *c, int32 sizeclass, uintptr size, int32 zeroed);
-void MCache_Free(MCache *c, void *p, int32 sizeclass, uintptr size);
-void MCache_ReleaseAll(MCache *c);
+void* runtime·MCache_Alloc(MCache *c, int32 sizeclass, uintptr size, int32 zeroed);
+void runtime·MCache_Free(MCache *c, void *p, int32 sizeclass, uintptr size);
+void runtime·MCache_ReleaseAll(MCache *c);
// An MSpan is a run of pages.
enum
@@ -283,15 +285,15 @@ struct MSpan
};
};
-void MSpan_Init(MSpan *span, PageID start, uintptr npages);
+void runtime·MSpan_Init(MSpan *span, PageID start, uintptr npages);
// Every MSpan is in one doubly-linked list,
// either one of the MHeap's free lists or one of the
// MCentral's span lists. We use empty MSpan structures as list heads.
-void MSpanList_Init(MSpan *list);
-bool MSpanList_IsEmpty(MSpan *list);
-void MSpanList_Insert(MSpan *list, MSpan *span);
-void MSpanList_Remove(MSpan *span); // from whatever list it is in
+void runtime·MSpanList_Init(MSpan *list);
+bool runtime·MSpanList_IsEmpty(MSpan *list);
+void runtime·MSpanList_Insert(MSpan *list, MSpan *span);
+void runtime·MSpanList_Remove(MSpan *span); // from whatever list it is in
// Central list of free objects of a given size.
@@ -304,9 +306,9 @@ struct MCentral
int32 nfree;
};
-void MCentral_Init(MCentral *c, int32 sizeclass);
-int32 MCentral_AllocList(MCentral *c, int32 n, MLink **first);
-void MCentral_FreeList(MCentral *c, int32 n, MLink *first);
+void runtime·MCentral_Init(MCentral *c, int32 sizeclass);
+int32 runtime·MCentral_AllocList(MCentral *c, int32 n, MLink **first);
+void runtime·MCentral_FreeList(MCentral *c, int32 n, MLink *first);
// Main malloc heap.
// The heap itself is the "free[]" and "large" arrays,
@@ -325,10 +327,6 @@ struct MHeap
byte *min;
byte *max;
- // range of addresses we might see in a Native Client closure
- byte *closure_min;
- byte *closure_max;
-
// central free lists for small size classes.
// the union makes sure that the MCentrals are
// spaced 64 bytes apart, so that each MCentral.Lock
@@ -341,22 +339,22 @@ struct MHeap
FixAlloc spanalloc; // allocator for Span*
FixAlloc cachealloc; // allocator for MCache*
};
-extern MHeap mheap;
+extern MHeap runtime·mheap;
-void MHeap_Init(MHeap *h, void *(*allocator)(uintptr));
-MSpan* MHeap_Alloc(MHeap *h, uintptr npage, int32 sizeclass, int32 acct);
-void MHeap_Free(MHeap *h, MSpan *s, int32 acct);
-MSpan* MHeap_Lookup(MHeap *h, PageID p);
-MSpan* MHeap_LookupMaybe(MHeap *h, PageID p);
-void MGetSizeClassInfo(int32 sizeclass, int32 *size, int32 *npages, int32 *nobj);
+void runtime·MHeap_Init(MHeap *h, void *(*allocator)(uintptr));
+MSpan* runtime·MHeap_Alloc(MHeap *h, uintptr npage, int32 sizeclass, int32 acct);
+void runtime·MHeap_Free(MHeap *h, MSpan *s, int32 acct);
+MSpan* runtime·MHeap_Lookup(MHeap *h, PageID p);
+MSpan* runtime·MHeap_LookupMaybe(MHeap *h, PageID p);
+void runtime·MGetSizeClassInfo(int32 sizeclass, int32 *size, int32 *npages, int32 *nobj);
-void* mallocgc(uintptr size, uint32 flag, int32 dogc, int32 zeroed);
-int32 mlookup(void *v, byte **base, uintptr *size, MSpan **s, uint32 **ref);
-void gc(int32 force);
+void* runtime·mallocgc(uintptr size, uint32 flag, int32 dogc, int32 zeroed);
+int32 runtime·mlookup(void *v, byte **base, uintptr *size, MSpan **s, uint32 **ref);
+void runtime·gc(int32 force);
-void* SysAlloc(uintptr);
-void SysUnused(void*, uintptr);
-void SysFree(void*, uintptr);
+void* runtime·SysAlloc(uintptr);
+void runtime·SysUnused(void*, uintptr);
+void runtime·SysFree(void*, uintptr);
enum
{
@@ -373,8 +371,8 @@ enum
RefFlags = 0xFFFF0000U,
};
-void MProf_Malloc(void*, uintptr);
-void MProf_Free(void*, uintptr);
+void runtime·MProf_Malloc(void*, uintptr);
+void runtime·MProf_Free(void*, uintptr);
// Malloc profiling settings.
// Must match definition in extern.go.
@@ -383,7 +381,7 @@ enum {
MProf_Sample = 1,
MProf_All = 2,
};
-extern int32 malloc_profile;
+extern int32 runtime·malloc_profile;
typedef struct Finalizer Finalizer;
struct Finalizer
@@ -394,4 +392,4 @@ struct Finalizer
int32 nret;
};
-Finalizer* getfinalizer(void*, bool);
+Finalizer* runtime·getfinalizer(void*, bool);
diff --git a/src/pkg/runtime/malloc_defs.go b/src/pkg/runtime/malloc_defs.go
new file mode 100644
index 000000000..bfb96f409
--- /dev/null
+++ b/src/pkg/runtime/malloc_defs.go
@@ -0,0 +1,130 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Go definitions of internal structures. Master is malloc.h
+
+package runtime
+
+import "unsafe"
+
+const (
+ pageShift = 12
+ pageSize = 1 << pageShift
+ pageMask = pageSize - 1
+)
+
+type pageID uintptr
+
+const (
+ numSizeClasses = 67
+ maxSmallSize = 32 << 10
+ fixAllocChunk = 128 << 10
+ maxMCacheListLen = 256
+ maxMCacheSize = 2 << 20
+ maxMHeapList = 1 << 8 // 1 << (20 - pageShift)
+ heapAllocChunk = 1 << 20
+)
+
+type mLink struct {
+ next *mLink
+}
+
+type fixAlloc struct {
+ size uintptr
+ alloc func(uintptr)
+ first func(unsafe.Pointer, *byte)
+ arg unsafe.Pointer
+ list *mLink
+ chunk *byte
+ nchunk uint32
+ inuse uintptr
+ sys uintptr
+}
+
+
+// MStats? used to be in extern.go
+
+type mCacheList struct {
+ list *mLink
+ nlist uint32
+ nlistmin uint32
+}
+
+type mCache struct {
+ list [numSizeClasses]mCacheList
+ size uint64
+ local_alloc int64
+ local_objects int64
+ next_sample int32
+}
+
+type mSpan struct {
+ next *mSpan
+ prev *mSpan
+ allnext *mSpan
+ start pageID
+ npages uintptr
+ freelist *mLink
+ ref uint32
+ sizeclass uint32
+ state uint32
+ // union {
+ gcref *uint32 // sizeclass > 0
+ // gcref0 uint32; // sizeclass == 0
+ // }
+}
+
+type mCentral struct {
+ lock
+ sizeclass int32
+ nonempty mSpan
+ empty mSpan
+ nfree int32
+}
+
+type mHeap struct {
+ lock
+ free [maxMHeapList]mSpan
+ large mSpan
+ allspans *mSpan
+ map_ mHeapMap
+ min *byte
+ max *byte
+ closure_min *byte
+ closure_max *byte
+
+ central [numSizeClasses]struct {
+ pad [64]byte
+ // union: mCentral
+ }
+
+ spanalloc fixAlloc
+ cachealloc fixAlloc
+}
+
+const (
+ refFree = iota
+ refStack
+ refNone
+ refSome
+ refcountOverhead = 4
+ refNoPointers = 0x80000000
+ refHasFinalizer = 0x40000000
+ refProfiled = 0x20000000
+ refNoProfiling = 0x10000000
+ refFlags = 0xFFFF0000
+)
+
+const (
+ mProf_None = iota
+ mProf_Sample
+ mProf_All
+)
+
+type finalizer struct {
+ next *finalizer
+ fn func(unsafe.Pointer)
+ arg unsafe.Pointer
+ nret int32
+}
diff --git a/src/pkg/runtime/mcache.c b/src/pkg/runtime/mcache.c
index 202936f6e..0f41a0ebc 100644
--- a/src/pkg/runtime/mcache.c
+++ b/src/pkg/runtime/mcache.c
@@ -10,7 +10,7 @@
#include "malloc.h"
void*
-MCache_Alloc(MCache *c, int32 sizeclass, uintptr size, int32 zeroed)
+runtime·MCache_Alloc(MCache *c, int32 sizeclass, uintptr size, int32 zeroed)
{
MCacheList *l;
MLink *first, *v;
@@ -20,8 +20,8 @@ MCache_Alloc(MCache *c, int32 sizeclass, uintptr size, int32 zeroed)
l = &c->list[sizeclass];
if(l->list == nil) {
// Replenish using central lists.
- n = MCentral_AllocList(&mheap.central[sizeclass],
- class_to_transfercount[sizeclass], &first);
+ n = runtime·MCentral_AllocList(&runtime·mheap.central[sizeclass],
+ runtime·class_to_transfercount[sizeclass], &first);
l->list = first;
l->nlist = n;
c->size += n*size;
@@ -39,7 +39,7 @@ MCache_Alloc(MCache *c, int32 sizeclass, uintptr size, int32 zeroed)
if(zeroed) {
// block is zeroed iff second word is zero ...
if(size > sizeof(uintptr) && ((uintptr*)v)[1] != 0)
- runtime_memclr((byte*)v, size);
+ runtime·memclr((byte*)v, size);
else {
// ... except for the link pointer
// that we used above; zero that.
@@ -47,6 +47,7 @@ MCache_Alloc(MCache *c, int32 sizeclass, uintptr size, int32 zeroed)
}
}
c->local_alloc += size;
+ c->local_objects++;
return v;
}
@@ -67,14 +68,14 @@ ReleaseN(MCache *c, MCacheList *l, int32 n, int32 sizeclass)
l->nlist -= n;
if(l->nlist < l->nlistmin)
l->nlistmin = l->nlist;
- c->size -= n*class_to_size[sizeclass];
+ c->size -= n*runtime·class_to_size[sizeclass];
// Return them to central free list.
- MCentral_FreeList(&mheap.central[sizeclass], n, first);
+ runtime·MCentral_FreeList(&runtime·mheap.central[sizeclass], n, first);
}
void
-MCache_Free(MCache *c, void *v, int32 sizeclass, uintptr size)
+runtime·MCache_Free(MCache *c, void *v, int32 sizeclass, uintptr size)
{
int32 i, n;
MCacheList *l;
@@ -88,10 +89,11 @@ MCache_Free(MCache *c, void *v, int32 sizeclass, uintptr size)
l->nlist++;
c->size += size;
c->local_alloc -= size;
+ c->local_objects--;
if(l->nlist >= MaxMCacheListLen) {
// Release a chunk back.
- ReleaseN(c, l, class_to_transfercount[sizeclass], sizeclass);
+ ReleaseN(c, l, runtime·class_to_transfercount[sizeclass], sizeclass);
}
if(c->size >= MaxMCacheSize) {
@@ -116,16 +118,11 @@ MCache_Free(MCache *c, void *v, int32 sizeclass, uintptr size)
}
void
-MCache_ReleaseAll(MCache *c)
+runtime·MCache_ReleaseAll(MCache *c)
{
int32 i;
MCacheList *l;
- lock(&mheap);
- mstats.heap_alloc += c->local_alloc;
- c->local_alloc = 0;
- unlock(&mheap);
-
for(i=0; i<NumSizeClasses; i++) {
l = &c->list[i];
ReleaseN(c, l, l->nlist, i);
diff --git a/src/pkg/runtime/mcentral.c b/src/pkg/runtime/mcentral.c
index 1e1784cc6..8855dc663 100644
--- a/src/pkg/runtime/mcentral.c
+++ b/src/pkg/runtime/mcentral.c
@@ -23,11 +23,11 @@ static void MCentral_Free(MCentral *c, void *v);
// Initialize a single central free list.
void
-MCentral_Init(MCentral *c, int32 sizeclass)
+runtime·MCentral_Init(MCentral *c, int32 sizeclass)
{
c->sizeclass = sizeclass;
- MSpanList_Init(&c->nonempty);
- MSpanList_Init(&c->empty);
+ runtime·MSpanList_Init(&c->nonempty);
+ runtime·MSpanList_Init(&c->empty);
}
// Allocate up to n objects from the central free list.
@@ -35,16 +35,16 @@ MCentral_Init(MCentral *c, int32 sizeclass)
// The objects are linked together by their first words.
// On return, *pstart points at the first object and *pend at the last.
int32
-MCentral_AllocList(MCentral *c, int32 n, MLink **pfirst)
+runtime·MCentral_AllocList(MCentral *c, int32 n, MLink **pfirst)
{
MLink *first, *last, *v;
int32 i;
- lock(c);
+ runtime·lock(c);
// Replenish central list if empty.
- if(MSpanList_IsEmpty(&c->nonempty)) {
+ if(runtime·MSpanList_IsEmpty(&c->nonempty)) {
if(!MCentral_Grow(c)) {
- unlock(c);
+ runtime·unlock(c);
*pfirst = nil;
return 0;
}
@@ -61,7 +61,7 @@ MCentral_AllocList(MCentral *c, int32 n, MLink **pfirst)
last->next = nil;
c->nfree -= i;
- unlock(c);
+ runtime·unlock(c);
*pfirst = first;
return i;
}
@@ -73,15 +73,15 @@ MCentral_Alloc(MCentral *c)
MSpan *s;
MLink *v;
- if(MSpanList_IsEmpty(&c->nonempty))
+ if(runtime·MSpanList_IsEmpty(&c->nonempty))
return nil;
s = c->nonempty.next;
s->ref++;
v = s->freelist;
s->freelist = v->next;
if(s->freelist == nil) {
- MSpanList_Remove(s);
- MSpanList_Insert(&c->empty, s);
+ runtime·MSpanList_Remove(s);
+ runtime·MSpanList_Insert(&c->empty, s);
}
return v;
}
@@ -91,7 +91,7 @@ MCentral_Alloc(MCentral *c)
// The objects are linked together by their first words.
// On return, *pstart points at the first object and *pend at the last.
void
-MCentral_FreeList(MCentral *c, int32 n, MLink *start)
+runtime·MCentral_FreeList(MCentral *c, int32 n, MLink *start)
{
MLink *v, *next;
@@ -100,12 +100,12 @@ MCentral_FreeList(MCentral *c, int32 n, MLink *start)
// the transfer cache optimization in the TODO above.
USED(n);
- lock(c);
+ runtime·lock(c);
for(v=start; v; v=next) {
next = v->next;
MCentral_Free(c, v);
}
- unlock(c);
+ runtime·unlock(c);
}
// Helper: free one object back into the central free list.
@@ -119,14 +119,14 @@ MCentral_Free(MCentral *c, void *v)
// Find span for v.
page = (uintptr)v >> PageShift;
- s = MHeap_Lookup(&mheap, page);
+ s = runtime·MHeap_Lookup(&runtime·mheap, page);
if(s == nil || s->ref == 0)
- throw("invalid free");
+ runtime·throw("invalid free");
// Move to nonempty if necessary.
if(s->freelist == nil) {
- MSpanList_Remove(s);
- MSpanList_Insert(&c->nonempty, s);
+ runtime·MSpanList_Remove(s);
+ runtime·MSpanList_Insert(&c->nonempty, s);
}
// Add v back to s's free list.
@@ -137,34 +137,34 @@ MCentral_Free(MCentral *c, void *v)
// If s is completely freed, return it to the heap.
if(--s->ref == 0) {
- size = class_to_size[c->sizeclass];
- MSpanList_Remove(s);
+ size = runtime·class_to_size[c->sizeclass];
+ runtime·MSpanList_Remove(s);
// The second word of each freed block indicates
// whether it needs to be zeroed. The first word
// is the link pointer and must always be cleared.
for(p=s->freelist; p; p=next) {
next = p->next;
if(size > sizeof(uintptr) && ((uintptr*)p)[1] != 0)
- runtime_memclr((byte*)p, size);
+ runtime·memclr((byte*)p, size);
else
p->next = nil;
}
s->freelist = nil;
c->nfree -= (s->npages << PageShift) / size;
- unlock(c);
- MHeap_Free(&mheap, s, 0);
- lock(c);
+ runtime·unlock(c);
+ runtime·MHeap_Free(&runtime·mheap, s, 0);
+ runtime·lock(c);
}
}
void
-MGetSizeClassInfo(int32 sizeclass, int32 *sizep, int32 *npagesp, int32 *nobj)
+runtime·MGetSizeClassInfo(int32 sizeclass, int32 *sizep, int32 *npagesp, int32 *nobj)
{
int32 size;
int32 npages;
- npages = class_to_allocnpages[sizeclass];
- size = class_to_size[sizeclass];
+ npages = runtime·class_to_allocnpages[sizeclass];
+ size = runtime·class_to_size[sizeclass];
*npagesp = npages;
*sizep = size;
*nobj = (npages << PageShift) / (size + RefcountOverhead);
@@ -180,12 +180,12 @@ MCentral_Grow(MCentral *c)
byte *p;
MSpan *s;
- unlock(c);
- MGetSizeClassInfo(c->sizeclass, &size, &npages, &n);
- s = MHeap_Alloc(&mheap, npages, c->sizeclass, 0);
+ runtime·unlock(c);
+ runtime·MGetSizeClassInfo(c->sizeclass, &size, &npages, &n);
+ s = runtime·MHeap_Alloc(&runtime·mheap, npages, c->sizeclass, 0);
if(s == nil) {
// TODO(rsc): Log out of memory
- lock(c);
+ runtime·lock(c);
return false;
}
@@ -201,8 +201,8 @@ MCentral_Grow(MCentral *c)
}
*tailp = nil;
- lock(c);
+ runtime·lock(c);
c->nfree += n;
- MSpanList_Insert(&c->nonempty, s);
+ runtime·MSpanList_Insert(&c->nonempty, s);
return true;
}
diff --git a/src/pkg/runtime/mfinal.c b/src/pkg/runtime/mfinal.c
index 03c1e1044..f73561b3c 100644
--- a/src/pkg/runtime/mfinal.c
+++ b/src/pkg/runtime/mfinal.c
@@ -5,7 +5,7 @@
#include "runtime.h"
#include "malloc.h"
-Lock finlock;
+static Lock finlock;
// Finalizer hash table. Direct hash, linear scan, at most 3/4 full.
// Table size is power of 3 so that hash can be key % max.
@@ -44,7 +44,7 @@ addfintab(Fintab *t, void *k, Finalizer *v)
}
// cannot happen - table is known to be non-full
- throw("finalizer table inconsistent");
+ runtime·throw("finalizer table inconsistent");
ret:
t->key[i] = k;
@@ -77,7 +77,7 @@ lookfintab(Fintab *t, void *k, bool del)
}
// cannot happen - table is known to be non-full
- throw("finalizer table inconsistent");
+ runtime·throw("finalizer table inconsistent");
return nil;
}
@@ -85,7 +85,7 @@ static Fintab fintab;
// add finalizer; caller is responsible for making sure not already in table
void
-addfinalizer(void *p, void (*f)(void*), int32 nret)
+runtime·addfinalizer(void *p, void (*f)(void*), int32 nret)
{
Fintab newtab;
int32 i;
@@ -95,28 +95,28 @@ addfinalizer(void *p, void (*f)(void*), int32 nret)
e = nil;
if(f != nil) {
- e = mal(sizeof *e);
+ e = runtime·mal(sizeof *e);
e->fn = f;
e->nret = nret;
}
- lock(&finlock);
- if(!mlookup(p, &base, nil, nil, &ref) || p != base) {
- unlock(&finlock);
- throw("addfinalizer on invalid pointer");
+ runtime·lock(&finlock);
+ if(!runtime·mlookup(p, &base, nil, nil, &ref) || p != base) {
+ runtime·unlock(&finlock);
+ runtime·throw("addfinalizer on invalid pointer");
}
if(f == nil) {
if(*ref & RefHasFinalizer) {
lookfintab(&fintab, p, 1);
*ref &= ~RefHasFinalizer;
}
- unlock(&finlock);
+ runtime·unlock(&finlock);
return;
}
if(*ref & RefHasFinalizer) {
- unlock(&finlock);
- throw("double finalizer");
+ runtime·unlock(&finlock);
+ runtime·throw("double finalizer");
}
*ref |= RefHasFinalizer;
@@ -124,7 +124,7 @@ addfinalizer(void *p, void (*f)(void*), int32 nret)
// keep table at most 3/4 full:
// allocate new table and rehash.
- runtime_memclr((byte*)&newtab, sizeof newtab);
+ runtime·memclr((byte*)&newtab, sizeof newtab);
newtab.max = fintab.max;
if(newtab.max == 0)
newtab.max = 3*3*3;
@@ -134,8 +134,8 @@ addfinalizer(void *p, void (*f)(void*), int32 nret)
newtab.max *= 3;
}
- newtab.key = mallocgc(newtab.max*sizeof newtab.key[0], RefNoPointers, 0, 1);
- newtab.val = mallocgc(newtab.max*sizeof newtab.val[0], 0, 0, 1);
+ newtab.key = runtime·mallocgc(newtab.max*sizeof newtab.key[0], RefNoPointers, 0, 1);
+ newtab.val = runtime·mallocgc(newtab.max*sizeof newtab.val[0], 0, 0, 1);
for(i=0; i<fintab.max; i++) {
void *k;
@@ -144,39 +144,39 @@ addfinalizer(void *p, void (*f)(void*), int32 nret)
if(k != nil && k != (void*)-1)
addfintab(&newtab, k, fintab.val[i]);
}
- free(fintab.key);
- free(fintab.val);
+ runtime·free(fintab.key);
+ runtime·free(fintab.val);
fintab = newtab;
}
addfintab(&fintab, p, e);
- unlock(&finlock);
+ runtime·unlock(&finlock);
}
// get finalizer; if del, delete finalizer.
// caller is responsible for updating RefHasFinalizer bit.
Finalizer*
-getfinalizer(void *p, bool del)
+runtime·getfinalizer(void *p, bool del)
{
Finalizer *f;
- lock(&finlock);
+ runtime·lock(&finlock);
f = lookfintab(&fintab, p, del);
- unlock(&finlock);
+ runtime·unlock(&finlock);
return f;
}
void
-walkfintab(void (*fn)(void*))
+runtime·walkfintab(void (*fn)(void*))
{
void **key;
void **ekey;
- lock(&finlock);
+ runtime·lock(&finlock);
key = fintab.key;
ekey = key + fintab.max;
for(; key < ekey; key++)
if(*key != nil && *key != ((void*)-1))
fn(*key);
- unlock(&finlock);
+ runtime·unlock(&finlock);
}
diff --git a/src/pkg/runtime/mfixalloc.c b/src/pkg/runtime/mfixalloc.c
index 8347a1539..ab9df3196 100644
--- a/src/pkg/runtime/mfixalloc.c
+++ b/src/pkg/runtime/mfixalloc.c
@@ -12,7 +12,7 @@
// Initialize f to allocate objects of the given size,
// using the allocator to obtain chunks of memory.
void
-FixAlloc_Init(FixAlloc *f, uintptr size, void *(*alloc)(uintptr), void (*first)(void*, byte*), void *arg)
+runtime·FixAlloc_Init(FixAlloc *f, uintptr size, void *(*alloc)(uintptr), void (*first)(void*, byte*), void *arg)
{
f->size = size;
f->alloc = alloc;
@@ -26,7 +26,7 @@ FixAlloc_Init(FixAlloc *f, uintptr size, void *(*alloc)(uintptr), void (*first)(
}
void*
-FixAlloc_Alloc(FixAlloc *f)
+runtime·FixAlloc_Alloc(FixAlloc *f)
{
void *v;
@@ -40,7 +40,7 @@ FixAlloc_Alloc(FixAlloc *f)
f->sys += FixAllocChunk;
f->chunk = f->alloc(FixAllocChunk);
if(f->chunk == nil)
- throw("out of memory (FixAlloc)");
+ runtime·throw("out of memory (FixAlloc)");
f->nchunk = FixAllocChunk;
}
v = f->chunk;
@@ -53,7 +53,7 @@ FixAlloc_Alloc(FixAlloc *f)
}
void
-FixAlloc_Free(FixAlloc *f, void *p)
+runtime·FixAlloc_Free(FixAlloc *f, void *p)
{
f->inuse -= f->size;
*(void**)p = f->list;
diff --git a/src/pkg/runtime/mgc0.c b/src/pkg/runtime/mgc0.c
index 2324eff29..6dcb61091 100644
--- a/src/pkg/runtime/mgc0.c
+++ b/src/pkg/runtime/mgc0.c
@@ -19,6 +19,13 @@ enum {
Debug = 0
};
+typedef struct BlockList BlockList;
+struct BlockList
+{
+ byte *obj;
+ uintptr size;
+};
+
extern byte data[];
extern byte etext[];
extern byte end[];
@@ -26,8 +33,8 @@ extern byte end[];
static G *fing;
static Finalizer *finq;
static int32 fingwait;
+static BlockList *bl, *ebl;
-static void sweepblock(byte*, int64, uint32*, int32);
static void runfinq(void);
enum {
@@ -35,7 +42,7 @@ enum {
};
static void
-scanblock(int32 depth, byte *b, int64 n)
+scanblock(byte *b, int64 n)
{
int32 off;
void *obj;
@@ -43,48 +50,49 @@ scanblock(int32 depth, byte *b, int64 n)
uint32 *refp, ref;
void **vp;
int64 i;
-
- if(Debug > 1)
- printf("%d scanblock %p %D\n", depth, b, n);
- off = (uint32)(uintptr)b & (PtrSize-1);
- if(off) {
- b += PtrSize - off;
- n -= PtrSize - off;
- }
-
- vp = (void**)b;
- n /= PtrSize;
- for(i=0; i<n; i++) {
- obj = vp[i];
- if(obj == nil)
- continue;
- if(mheap.closure_min != nil && mheap.closure_min <= (byte*)obj && (byte*)obj < mheap.closure_max) {
- if((((uintptr)obj) & 63) != 0)
- continue;
-
- // Looks like a Native Client closure.
- // Actual pointer is pointed at by address in first instruction.
- // Embedded pointer starts at byte 2.
- // If it is f4f4f4f4 then that space hasn't been
- // used for a closure yet (f4 is the HLT instruction).
- // See nacl/386/closure.c for more.
- void **pp;
- pp = *(void***)((byte*)obj+2);
- if(pp == (void**)0xf4f4f4f4) // HLT... - not a closure after all
- continue;
- obj = *pp;
+ BlockList *w;
+
+ w = bl;
+ w->obj = b;
+ w->size = n;
+ w++;
+
+ while(w > bl) {
+ w--;
+ b = w->obj;
+ n = w->size;
+
+ if(Debug > 1)
+ runtime·printf("scanblock %p %D\n", b, n);
+ off = (uint32)(uintptr)b & (PtrSize-1);
+ if(off) {
+ b += PtrSize - off;
+ n -= PtrSize - off;
}
- if(mheap.min <= (byte*)obj && (byte*)obj < mheap.max) {
- if(mlookup(obj, &obj, &size, nil, &refp)) {
- ref = *refp;
- switch(ref & ~RefFlags) {
- case RefNone:
- if(Debug > 1)
- printf("%d found at %p: ", depth, &vp[i]);
- *refp = RefSome | (ref & RefFlags);
- if(!(ref & RefNoPointers))
- scanblock(depth+1, obj, size);
- break;
+
+ vp = (void**)b;
+ n /= PtrSize;
+ for(i=0; i<n; i++) {
+ obj = vp[i];
+ if(obj == nil)
+ continue;
+ if(runtime·mheap.min <= (byte*)obj && (byte*)obj < runtime·mheap.max) {
+ if(runtime·mlookup(obj, &obj, &size, nil, &refp)) {
+ ref = *refp;
+ switch(ref & ~RefFlags) {
+ case RefNone:
+ if(Debug > 1)
+ runtime·printf("found at %p: ", &vp[i]);
+ *refp = RefSome | (ref & RefFlags);
+ if(!(ref & RefNoPointers)) {
+ if(w >= ebl)
+ runtime·throw("scanblock: garbage collection stack overflow");
+ w->obj = obj;
+ w->size = size;
+ w++;
+ }
+ break;
+ }
}
}
}
@@ -102,10 +110,10 @@ scanstack(G *gp)
else
sp = gp->sched.sp;
if(Debug > 1)
- printf("scanstack %d %p\n", gp->goid, sp);
+ runtime·printf("scanstack %d %p\n", gp->goid, sp);
stk = (Stktop*)gp->stackbase;
while(stk) {
- scanblock(0, sp, (byte*)stk - sp);
+ scanblock(sp, (byte*)stk - sp);
sp = stk->gobuf.sp;
stk = (Stktop*)stk->stackbase;
}
@@ -119,36 +127,57 @@ markfin(void *v)
size = 0;
refp = nil;
- if(!mlookup(v, &v, &size, nil, &refp) || !(*refp & RefHasFinalizer))
- throw("mark - finalizer inconsistency");
+ if(!runtime·mlookup(v, &v, &size, nil, &refp) || !(*refp & RefHasFinalizer))
+ runtime·throw("mark - finalizer inconsistency");
// do not mark the finalizer block itself. just mark the things it points at.
- scanblock(1, v, size);
+ scanblock(v, size);
}
static void
mark(void)
{
G *gp;
+ uintptr blsize, nobj;
+
+ // Figure out how big an object stack we need.
+ // Get a new one if we need more than we have
+ // or we need significantly less than we have.
+ nobj = mstats.heap_objects;
+ if(nobj > ebl - bl || nobj < (ebl-bl)/4) {
+ if(bl != nil)
+ runtime·SysFree(bl, (byte*)ebl - (byte*)bl);
+
+ // While we're allocated a new object stack,
+ // add 20% headroom and also round up to
+ // the nearest page boundary, since mmap
+ // will anyway.
+ nobj = nobj * 12/10;
+ blsize = nobj * sizeof *bl;
+ blsize = (blsize + 4095) & ~4095;
+ nobj = blsize / sizeof *bl;
+ bl = runtime·SysAlloc(blsize);
+ ebl = bl + nobj;
+ }
// mark data+bss.
- // skip mheap itself, which has no interesting pointers
+ // skip runtime·mheap itself, which has no interesting pointers
// and is mostly zeroed and would not otherwise be paged in.
- scanblock(0, data, (byte*)&mheap - data);
- scanblock(0, (byte*)(&mheap+1), end - (byte*)(&mheap+1));
+ scanblock(data, (byte*)&runtime·mheap - data);
+ scanblock((byte*)(&runtime·mheap+1), end - (byte*)(&runtime·mheap+1));
// mark stacks
- for(gp=allg; gp!=nil; gp=gp->alllink) {
+ for(gp=runtime·allg; gp!=nil; gp=gp->alllink) {
switch(gp->status){
default:
- printf("unexpected G.status %d\n", gp->status);
- throw("mark - bad status");
+ runtime·printf("unexpected G.status %d\n", gp->status);
+ runtime·throw("mark - bad status");
case Gdead:
break;
case Grunning:
case Grecovery:
if(gp != g)
- throw("mark - world not stopped");
+ runtime·throw("mark - world not stopped");
scanstack(gp);
break;
case Grunnable:
@@ -160,7 +189,7 @@ mark(void)
}
// mark things pointed at by objects with finalizers
- walkfintab(markfin);
+ runtime·walkfintab(markfin);
}
// free RefNone, free & queue finalizers for RefNone|RefHasFinalizer, reset RefSome
@@ -181,16 +210,16 @@ sweepspan(MSpan *s)
case RefNone:
// Free large object.
mstats.alloc -= s->npages<<PageShift;
- runtime_memclr(p, s->npages<<PageShift);
+ runtime·memclr(p, s->npages<<PageShift);
if(ref & RefProfiled)
- MProf_Free(p, s->npages<<PageShift);
+ runtime·MProf_Free(p, s->npages<<PageShift);
s->gcref0 = RefFree;
- MHeap_Free(&mheap, s, 1);
+ runtime·MHeap_Free(&runtime·mheap, s, 1);
break;
case RefNone|RefHasFinalizer:
- f = getfinalizer(p, 1);
+ f = runtime·getfinalizer(p, 1);
if(f == nil)
- throw("finalizer inconsistency");
+ runtime·throw("finalizer inconsistency");
f->arg = p;
f->next = finq;
finq = f;
@@ -205,7 +234,7 @@ sweepspan(MSpan *s)
}
// Chunk full of small blocks.
- MGetSizeClassInfo(s->sizeclass, &size, &npages, &n);
+ runtime·MGetSizeClassInfo(s->sizeclass, &size, &npages, &n);
gcrefp = s->gcref;
gcrefep = s->gcref + n;
for(; gcrefp < gcrefep; gcrefp++, p += size) {
@@ -216,19 +245,19 @@ sweepspan(MSpan *s)
case RefNone:
// Free small object.
if(ref & RefProfiled)
- MProf_Free(p, size);
+ runtime·MProf_Free(p, size);
*gcrefp = RefFree;
c = m->mcache;
if(size > sizeof(uintptr))
((uintptr*)p)[1] = 1; // mark as "needs to be zeroed"
mstats.alloc -= size;
mstats.by_size[s->sizeclass].nfree++;
- MCache_Free(c, p, s->sizeclass, size);
+ runtime·MCache_Free(c, p, s->sizeclass, size);
break;
case RefNone|RefHasFinalizer:
- f = getfinalizer(p, 1);
+ f = runtime·getfinalizer(p, 1);
if(f == nil)
- throw("finalizer inconsistency");
+ runtime·throw("finalizer inconsistency");
f->arg = p;
f->next = finq;
finq = f;
@@ -247,7 +276,7 @@ sweep(void)
{
MSpan *s;
- for(s = mheap.allspans; s != nil; s = s->allnext)
+ for(s = runtime·mheap.allspans; s != nil; s = s->allnext)
if(s->state == MSpanInUse)
sweepspan(s);
}
@@ -273,12 +302,27 @@ stealcache(void)
{
M *m;
- for(m=allm; m; m=m->alllink)
- MCache_ReleaseAll(m->mcache);
+ for(m=runtime·allm; m; m=m->alllink)
+ runtime·MCache_ReleaseAll(m->mcache);
+}
+
+static void
+cachestats(void)
+{
+ M *m;
+ MCache *c;
+
+ for(m=runtime·allm; m; m=m->alllink) {
+ c = m->mcache;
+ mstats.heap_alloc += c->local_alloc;
+ c->local_alloc = 0;
+ mstats.heap_objects += c->local_objects;
+ c->local_objects = 0;
+ }
}
void
-gc(int32 force)
+runtime·gc(int32 force)
{
int64 t0, t1;
byte *p;
@@ -292,28 +336,29 @@ gc(int32 force)
// problems, don't bother trying to run gc
// while holding a lock. The next mallocgc
// without a lock will do the gc instead.
- if(!mstats.enablegc || m->locks > 0 || panicking)
+ if(!mstats.enablegc || m->locks > 0 || runtime·panicking)
return;
if(gcpercent == -2) { // first time through
- p = getenv("GOGC");
+ p = runtime·getenv("GOGC");
if(p == nil || p[0] == '\0')
gcpercent = 100;
- else if(strcmp(p, (byte*)"off") == 0)
+ else if(runtime·strcmp(p, (byte*)"off") == 0)
gcpercent = -1;
else
- gcpercent = atoi(p);
+ gcpercent = runtime·atoi(p);
}
if(gcpercent < 0)
return;
- semacquire(&gcsema);
- t0 = nanotime();
+ runtime·semacquire(&gcsema);
+ t0 = runtime·nanotime();
m->gcing = 1;
- stoptheworld();
- if(mheap.Lock.key != 0)
- throw("mheap locked during gc");
+ runtime·stoptheworld();
+ if(runtime·mheap.Lock.key != 0)
+ runtime·throw("runtime·mheap locked during gc");
if(force || mstats.heap_alloc >= mstats.next_gc) {
+ cachestats();
mark();
sweep();
stealcache();
@@ -326,25 +371,25 @@ gc(int32 force)
if(fp != nil) {
// kick off or wake up goroutine to run queued finalizers
if(fing == nil)
- fing = newproc1((byte*)runfinq, nil, 0, 0);
+ fing = runtime·newproc1((byte*)runfinq, nil, 0, 0);
else if(fingwait) {
fingwait = 0;
- ready(fing);
+ runtime·ready(fing);
}
}
m->locks--;
- t1 = nanotime();
+ t1 = runtime·nanotime();
mstats.numgc++;
mstats.pause_ns += t1 - t0;
if(mstats.debuggc)
- printf("pause %D\n", t1-t0);
- semrelease(&gcsema);
- starttheworld();
+ runtime·printf("pause %D\n", t1-t0);
+ runtime·semrelease(&gcsema);
+ runtime·starttheworld();
// give the queued finalizers, if any, a chance to run
if(fp != nil)
- gosched();
+ runtime·gosched();
}
static void
@@ -365,20 +410,20 @@ runfinq(void)
if(f == nil) {
fingwait = 1;
g->status = Gwaiting;
- gosched();
+ runtime·gosched();
continue;
}
for(; f; f=next) {
next = f->next;
- frame = mal(sizeof(uintptr) + f->nret);
+ frame = runtime·mal(sizeof(uintptr) + f->nret);
*(void**)frame = f->arg;
reflect·call((byte*)f->fn, frame, sizeof(uintptr) + f->nret);
- free(frame);
+ runtime·free(frame);
f->fn = nil;
f->arg = nil;
f->next = nil;
- free(f);
+ runtime·free(f);
}
- gc(1); // trigger another gc to clean up the finalized objects, if possible
+ runtime·gc(1); // trigger another gc to clean up the finalized objects, if possible
}
}
diff --git a/src/pkg/runtime/mheap.c b/src/pkg/runtime/mheap.c
index 44817ddd5..4bb7f14e3 100644
--- a/src/pkg/runtime/mheap.c
+++ b/src/pkg/runtime/mheap.c
@@ -35,38 +35,42 @@ RecordSpan(void *vh, byte *p)
// Initialize the heap; fetch memory using alloc.
void
-MHeap_Init(MHeap *h, void *(*alloc)(uintptr))
+runtime·MHeap_Init(MHeap *h, void *(*alloc)(uintptr))
{
uint32 i;
- FixAlloc_Init(&h->spanalloc, sizeof(MSpan), alloc, RecordSpan, h);
- FixAlloc_Init(&h->cachealloc, sizeof(MCache), alloc, nil, nil);
- MHeapMap_Init(&h->map, alloc);
+ runtime·FixAlloc_Init(&h->spanalloc, sizeof(MSpan), alloc, RecordSpan, h);
+ runtime·FixAlloc_Init(&h->cachealloc, sizeof(MCache), alloc, nil, nil);
+ runtime·MHeapMap_Init(&h->map, alloc);
// h->mapcache needs no init
for(i=0; i<nelem(h->free); i++)
- MSpanList_Init(&h->free[i]);
- MSpanList_Init(&h->large);
+ runtime·MSpanList_Init(&h->free[i]);
+ runtime·MSpanList_Init(&h->large);
for(i=0; i<nelem(h->central); i++)
- MCentral_Init(&h->central[i], i);
+ runtime·MCentral_Init(&h->central[i], i);
}
// Allocate a new span of npage pages from the heap
// and record its size class in the HeapMap and HeapMapCache.
MSpan*
-MHeap_Alloc(MHeap *h, uintptr npage, int32 sizeclass, int32 acct)
+runtime·MHeap_Alloc(MHeap *h, uintptr npage, int32 sizeclass, int32 acct)
{
MSpan *s;
- lock(h);
+ runtime·lock(h);
mstats.heap_alloc += m->mcache->local_alloc;
m->mcache->local_alloc = 0;
+ mstats.heap_objects += m->mcache->local_objects;
+ m->mcache->local_objects = 0;
s = MHeap_AllocLocked(h, npage, sizeclass);
if(s != nil) {
mstats.heap_inuse += npage<<PageShift;
- if(acct)
+ if(acct) {
+ mstats.heap_objects++;
mstats.heap_alloc += npage<<PageShift;
+ }
}
- unlock(h);
+ runtime·unlock(h);
return s;
}
@@ -78,7 +82,7 @@ MHeap_AllocLocked(MHeap *h, uintptr npage, int32 sizeclass)
// Try in fixed-size lists up to max.
for(n=npage; n < nelem(h->free); n++) {
- if(!MSpanList_IsEmpty(&h->free[n])) {
+ if(!runtime·MSpanList_IsEmpty(&h->free[n])) {
s = h->free[n].next;
goto HaveSpan;
}
@@ -95,22 +99,22 @@ MHeap_AllocLocked(MHeap *h, uintptr npage, int32 sizeclass)
HaveSpan:
// Mark span in use.
if(s->state != MSpanFree)
- throw("MHeap_AllocLocked - MSpan not free");
+ runtime·throw("MHeap_AllocLocked - MSpan not free");
if(s->npages < npage)
- throw("MHeap_AllocLocked - bad npages");
- MSpanList_Remove(s);
+ runtime·throw("MHeap_AllocLocked - bad npages");
+ runtime·MSpanList_Remove(s);
s->state = MSpanInUse;
if(s->npages > npage) {
// Trim extra and put it back in the heap.
- t = FixAlloc_Alloc(&h->spanalloc);
+ t = runtime·FixAlloc_Alloc(&h->spanalloc);
mstats.mspan_inuse = h->spanalloc.inuse;
mstats.mspan_sys = h->spanalloc.sys;
- MSpan_Init(t, s->start + npage, s->npages - npage);
+ runtime·MSpan_Init(t, s->start + npage, s->npages - npage);
s->npages = npage;
- MHeapMap_Set(&h->map, t->start - 1, s);
- MHeapMap_Set(&h->map, t->start, t);
- MHeapMap_Set(&h->map, t->start + t->npages - 1, t);
+ runtime·MHeapMap_Set(&h->map, t->start - 1, s);
+ runtime·MHeapMap_Set(&h->map, t->start, t);
+ runtime·MHeapMap_Set(&h->map, t->start + t->npages - 1, t);
t->state = MSpanInUse;
MHeap_FreeLocked(h, t);
}
@@ -119,7 +123,7 @@ HaveSpan:
// able to map interior pointer to containing span.
s->sizeclass = sizeclass;
for(n=0; n<npage; n++)
- MHeapMap_Set(&h->map, s->start+n, s);
+ runtime·MHeapMap_Set(&h->map, s->start+n, s);
return s;
}
@@ -161,17 +165,17 @@ MHeap_Grow(MHeap *h, uintptr npage)
// Ask for a big chunk, to reduce the number of mappings
// the operating system needs to track; also amortizes
// the overhead of an operating system mapping.
- // For Native Client, allocate a multiple of 64kB (16 pages).
+ // Allocate a multiple of 64kB (16 pages).
npage = (npage+15)&~15;
ask = npage<<PageShift;
if(ask < HeapAllocChunk)
ask = HeapAllocChunk;
- v = SysAlloc(ask);
+ v = runtime·SysAlloc(ask);
if(v == nil) {
if(ask > (npage<<PageShift)) {
ask = npage<<PageShift;
- v = SysAlloc(ask);
+ v = runtime·SysAlloc(ask);
}
if(v == nil)
return false;
@@ -186,19 +190,19 @@ MHeap_Grow(MHeap *h, uintptr npage)
// NOTE(rsc): In tcmalloc, if we've accumulated enough
// system allocations, the heap map gets entirely allocated
// in 32-bit mode. (In 64-bit mode that's not practical.)
- if(!MHeapMap_Preallocate(&h->map, ((uintptr)v>>PageShift) - 1, (ask>>PageShift) + 2)) {
- SysFree(v, ask);
+ if(!runtime·MHeapMap_Preallocate(&h->map, ((uintptr)v>>PageShift) - 1, (ask>>PageShift) + 2)) {
+ runtime·SysFree(v, ask);
return false;
}
// Create a fake "in use" span and free it, so that the
// right coalescing happens.
- s = FixAlloc_Alloc(&h->spanalloc);
+ s = runtime·FixAlloc_Alloc(&h->spanalloc);
mstats.mspan_inuse = h->spanalloc.inuse;
mstats.mspan_sys = h->spanalloc.sys;
- MSpan_Init(s, (uintptr)v>>PageShift, ask>>PageShift);
- MHeapMap_Set(&h->map, s->start, s);
- MHeapMap_Set(&h->map, s->start + s->npages - 1, s);
+ runtime·MSpan_Init(s, (uintptr)v>>PageShift, ask>>PageShift);
+ runtime·MHeapMap_Set(&h->map, s->start, s);
+ runtime·MHeapMap_Set(&h->map, s->start + s->npages - 1, s);
s->state = MSpanInUse;
MHeap_FreeLocked(h, s);
return true;
@@ -208,9 +212,9 @@ MHeap_Grow(MHeap *h, uintptr npage)
// Page number is guaranteed to be in map
// and is guaranteed to be start or end of span.
MSpan*
-MHeap_Lookup(MHeap *h, PageID p)
+runtime·MHeap_Lookup(MHeap *h, PageID p)
{
- return MHeapMap_Get(&h->map, p);
+ return runtime·MHeapMap_Get(&h->map, p);
}
// Look up the span at the given page number.
@@ -221,11 +225,11 @@ MHeap_Lookup(MHeap *h, PageID p)
// other garbage in their middles, so we have to
// check for that.
MSpan*
-MHeap_LookupMaybe(MHeap *h, PageID p)
+runtime·MHeap_LookupMaybe(MHeap *h, PageID p)
{
MSpan *s;
- s = MHeapMap_GetMaybe(&h->map, p);
+ s = runtime·MHeapMap_GetMaybe(&h->map, p);
if(s == nil || p < s->start || p - s->start >= s->npages)
return nil;
if(s->state != MSpanInUse)
@@ -235,16 +239,20 @@ MHeap_LookupMaybe(MHeap *h, PageID p)
// Free the span back into the heap.
void
-MHeap_Free(MHeap *h, MSpan *s, int32 acct)
+runtime·MHeap_Free(MHeap *h, MSpan *s, int32 acct)
{
- lock(h);
+ runtime·lock(h);
mstats.heap_alloc += m->mcache->local_alloc;
m->mcache->local_alloc = 0;
+ mstats.heap_objects += m->mcache->local_objects;
+ m->mcache->local_objects = 0;
mstats.heap_inuse -= s->npages<<PageShift;
- if(acct)
+ if(acct) {
mstats.heap_alloc -= s->npages<<PageShift;
+ mstats.heap_objects--;
+ }
MHeap_FreeLocked(h, s);
- unlock(h);
+ runtime·unlock(h);
}
static void
@@ -253,45 +261,45 @@ MHeap_FreeLocked(MHeap *h, MSpan *s)
MSpan *t;
if(s->state != MSpanInUse || s->ref != 0) {
- printf("MHeap_FreeLocked - span %p ptr %p state %d ref %d\n", s, s->start<<PageShift, s->state, s->ref);
- throw("MHeap_FreeLocked - invalid free");
+ runtime·printf("MHeap_FreeLocked - span %p ptr %p state %d ref %d\n", s, s->start<<PageShift, s->state, s->ref);
+ runtime·throw("MHeap_FreeLocked - invalid free");
}
s->state = MSpanFree;
- MSpanList_Remove(s);
+ runtime·MSpanList_Remove(s);
// Coalesce with earlier, later spans.
- if((t = MHeapMap_Get(&h->map, s->start - 1)) != nil && t->state != MSpanInUse) {
+ if((t = runtime·MHeapMap_Get(&h->map, s->start - 1)) != nil && t->state != MSpanInUse) {
s->start = t->start;
s->npages += t->npages;
- MHeapMap_Set(&h->map, s->start, s);
- MSpanList_Remove(t);
+ runtime·MHeapMap_Set(&h->map, s->start, s);
+ runtime·MSpanList_Remove(t);
t->state = MSpanDead;
- FixAlloc_Free(&h->spanalloc, t);
+ runtime·FixAlloc_Free(&h->spanalloc, t);
mstats.mspan_inuse = h->spanalloc.inuse;
mstats.mspan_sys = h->spanalloc.sys;
}
- if((t = MHeapMap_Get(&h->map, s->start + s->npages)) != nil && t->state != MSpanInUse) {
+ if((t = runtime·MHeapMap_Get(&h->map, s->start + s->npages)) != nil && t->state != MSpanInUse) {
s->npages += t->npages;
- MHeapMap_Set(&h->map, s->start + s->npages - 1, s);
- MSpanList_Remove(t);
+ runtime·MHeapMap_Set(&h->map, s->start + s->npages - 1, s);
+ runtime·MSpanList_Remove(t);
t->state = MSpanDead;
- FixAlloc_Free(&h->spanalloc, t);
+ runtime·FixAlloc_Free(&h->spanalloc, t);
mstats.mspan_inuse = h->spanalloc.inuse;
mstats.mspan_sys = h->spanalloc.sys;
}
// Insert s into appropriate list.
if(s->npages < nelem(h->free))
- MSpanList_Insert(&h->free[s->npages], s);
+ runtime·MSpanList_Insert(&h->free[s->npages], s);
else
- MSpanList_Insert(&h->large, s);
+ runtime·MSpanList_Insert(&h->large, s);
// TODO(rsc): IncrementalScavenge() to return memory to OS.
}
// Initialize a new span with the given start and npages.
void
-MSpan_Init(MSpan *span, PageID start, uintptr npages)
+runtime·MSpan_Init(MSpan *span, PageID start, uintptr npages)
{
span->next = nil;
span->prev = nil;
@@ -305,7 +313,7 @@ MSpan_Init(MSpan *span, PageID start, uintptr npages)
// Initialize an empty doubly-linked list.
void
-MSpanList_Init(MSpan *list)
+runtime·MSpanList_Init(MSpan *list)
{
list->state = MSpanListHead;
list->next = list;
@@ -313,7 +321,7 @@ MSpanList_Init(MSpan *list)
}
void
-MSpanList_Remove(MSpan *span)
+runtime·MSpanList_Remove(MSpan *span)
{
if(span->prev == nil && span->next == nil)
return;
@@ -324,16 +332,16 @@ MSpanList_Remove(MSpan *span)
}
bool
-MSpanList_IsEmpty(MSpan *list)
+runtime·MSpanList_IsEmpty(MSpan *list)
{
return list->next == list;
}
void
-MSpanList_Insert(MSpan *list, MSpan *span)
+runtime·MSpanList_Insert(MSpan *list, MSpan *span)
{
if(span->next != nil || span->prev != nil)
- throw("MSpanList_Insert");
+ runtime·throw("MSpanList_Insert");
span->next = list->next;
span->prev = list;
span->next->prev = span;
diff --git a/src/pkg/runtime/mheapmap32.c b/src/pkg/runtime/mheapmap32.c
index 4481e11f6..323f8b87a 100644
--- a/src/pkg/runtime/mheapmap32.c
+++ b/src/pkg/runtime/mheapmap32.c
@@ -10,13 +10,13 @@
// 3-level radix tree mapping page ids to Span*.
void
-MHeapMap_Init(MHeapMap *m, void *(*allocator)(uintptr))
+runtime·MHeapMap_Init(MHeapMap *m, void *(*allocator)(uintptr))
{
m->allocator = allocator;
}
MSpan*
-MHeapMap_Get(MHeapMap *m, PageID k)
+runtime·MHeapMap_Get(MHeapMap *m, PageID k)
{
int32 i1, i2;
@@ -25,13 +25,13 @@ MHeapMap_Get(MHeapMap *m, PageID k)
i1 = k & MHeapMap_Level1Mask;
k >>= MHeapMap_Level1Bits;
if(k != 0)
- throw("MHeapMap_Get");
+ runtime·throw("MHeapMap_Get");
return m->p[i1]->s[i2];
}
MSpan*
-MHeapMap_GetMaybe(MHeapMap *m, PageID k)
+runtime·MHeapMap_GetMaybe(MHeapMap *m, PageID k)
{
int32 i1, i2;
MHeapMapNode2 *p2;
@@ -41,7 +41,7 @@ MHeapMap_GetMaybe(MHeapMap *m, PageID k)
i1 = k & MHeapMap_Level1Mask;
k >>= MHeapMap_Level1Bits;
if(k != 0)
- throw("MHeapMap_Get");
+ runtime·throw("MHeapMap_Get");
p2 = m->p[i1];
if(p2 == nil)
@@ -50,7 +50,7 @@ MHeapMap_GetMaybe(MHeapMap *m, PageID k)
}
void
-MHeapMap_Set(MHeapMap *m, PageID k, MSpan *s)
+runtime·MHeapMap_Set(MHeapMap *m, PageID k, MSpan *s)
{
int32 i1, i2;
@@ -59,7 +59,7 @@ MHeapMap_Set(MHeapMap *m, PageID k, MSpan *s)
i1 = k & MHeapMap_Level1Mask;
k >>= MHeapMap_Level1Bits;
if(k != 0)
- throw("MHeapMap_Set");
+ runtime·throw("MHeapMap_Set");
m->p[i1]->s[i2] = s;
}
@@ -67,7 +67,7 @@ MHeapMap_Set(MHeapMap *m, PageID k, MSpan *s)
// Allocate the storage required for entries [k, k+1, ..., k+len-1]
// so that Get and Set calls need not check for nil pointers.
bool
-MHeapMap_Preallocate(MHeapMap *m, PageID k, uintptr len)
+runtime·MHeapMap_Preallocate(MHeapMap *m, PageID k, uintptr len)
{
uintptr end;
int32 i1;
diff --git a/src/pkg/runtime/mheapmap32.h b/src/pkg/runtime/mheapmap32.h
index cb8a830d0..29e619071 100644
--- a/src/pkg/runtime/mheapmap32.h
+++ b/src/pkg/runtime/mheapmap32.h
@@ -32,10 +32,10 @@ struct MHeapMapNode2
MSpan *s[1<<MHeapMap_Level2Bits];
};
-void MHeapMap_Init(MHeapMap *m, void *(*allocator)(uintptr));
-bool MHeapMap_Preallocate(MHeapMap *m, PageID k, uintptr npages);
-MSpan* MHeapMap_Get(MHeapMap *m, PageID k);
-MSpan* MHeapMap_GetMaybe(MHeapMap *m, PageID k);
-void MHeapMap_Set(MHeapMap *m, PageID k, MSpan *v);
+void runtime·MHeapMap_Init(MHeapMap *m, void *(*allocator)(uintptr));
+bool runtime·MHeapMap_Preallocate(MHeapMap *m, PageID k, uintptr npages);
+MSpan* runtime·MHeapMap_Get(MHeapMap *m, PageID k);
+MSpan* runtime·MHeapMap_GetMaybe(MHeapMap *m, PageID k);
+void runtime·MHeapMap_Set(MHeapMap *m, PageID k, MSpan *v);
diff --git a/src/pkg/runtime/mheapmap32_defs.go b/src/pkg/runtime/mheapmap32_defs.go
new file mode 100644
index 000000000..755725b46
--- /dev/null
+++ b/src/pkg/runtime/mheapmap32_defs.go
@@ -0,0 +1,23 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+const (
+ mHeapMap_Level1Bits = 10
+ mHeapMap_Level2Bits = 10
+ mHeapMap_TotalBits = mHeapMap_Level1Bits + mHeapMap_Level2Bits
+
+ mHeapMap_Level1Mask = (1 << mHeapMap_Level1Bits) - 1
+ mHeapMap_Level2Mask = (1 << mHeapMap_Level2Bits) - 1
+)
+
+type mHeapMap struct {
+ allocator func(uintptr)
+ p [1 << mHeapMap_Level1Bits]*mHeapMapNode2
+}
+
+type mHeapMapNode2 struct {
+ s [1 << mHeapMap_Level2Bits]*mSpan
+}
diff --git a/src/pkg/runtime/mheapmap64.c b/src/pkg/runtime/mheapmap64.c
index d5590a2d8..e45ac9413 100644
--- a/src/pkg/runtime/mheapmap64.c
+++ b/src/pkg/runtime/mheapmap64.c
@@ -10,13 +10,13 @@
// 3-level radix tree mapping page ids to Span*.
void
-MHeapMap_Init(MHeapMap *m, void *(*allocator)(uintptr))
+runtime·MHeapMap_Init(MHeapMap *m, void *(*allocator)(uintptr))
{
m->allocator = allocator;
}
MSpan*
-MHeapMap_Get(MHeapMap *m, PageID k)
+runtime·MHeapMap_Get(MHeapMap *m, PageID k)
{
int32 i1, i2, i3;
@@ -27,13 +27,13 @@ MHeapMap_Get(MHeapMap *m, PageID k)
i1 = k & MHeapMap_Level1Mask;
k >>= MHeapMap_Level1Bits;
if(k != 0)
- throw("MHeapMap_Get");
+ runtime·throw("MHeapMap_Get");
return m->p[i1]->p[i2]->s[i3];
}
MSpan*
-MHeapMap_GetMaybe(MHeapMap *m, PageID k)
+runtime·MHeapMap_GetMaybe(MHeapMap *m, PageID k)
{
int32 i1, i2, i3;
MHeapMapNode2 *p2;
@@ -46,7 +46,7 @@ MHeapMap_GetMaybe(MHeapMap *m, PageID k)
i1 = k & MHeapMap_Level1Mask;
k >>= MHeapMap_Level1Bits;
if(k != 0)
- throw("MHeapMap_Get");
+ runtime·throw("MHeapMap_Get");
p2 = m->p[i1];
if(p2 == nil)
@@ -58,7 +58,7 @@ MHeapMap_GetMaybe(MHeapMap *m, PageID k)
}
void
-MHeapMap_Set(MHeapMap *m, PageID k, MSpan *s)
+runtime·MHeapMap_Set(MHeapMap *m, PageID k, MSpan *s)
{
int32 i1, i2, i3;
@@ -69,7 +69,7 @@ MHeapMap_Set(MHeapMap *m, PageID k, MSpan *s)
i1 = k & MHeapMap_Level1Mask;
k >>= MHeapMap_Level1Bits;
if(k != 0)
- throw("MHeapMap_Set");
+ runtime·throw("MHeapMap_Set");
m->p[i1]->p[i2]->s[i3] = s;
}
@@ -77,7 +77,7 @@ MHeapMap_Set(MHeapMap *m, PageID k, MSpan *s)
// Allocate the storage required for entries [k, k+1, ..., k+len-1]
// so that Get and Set calls need not check for nil pointers.
bool
-MHeapMap_Preallocate(MHeapMap *m, PageID k, uintptr len)
+runtime·MHeapMap_Preallocate(MHeapMap *m, PageID k, uintptr len)
{
uintptr end;
int32 i1, i2;
diff --git a/src/pkg/runtime/mheapmap64.h b/src/pkg/runtime/mheapmap64.h
index fefeae65d..a9934d2b1 100644
--- a/src/pkg/runtime/mheapmap64.h
+++ b/src/pkg/runtime/mheapmap64.h
@@ -51,10 +51,10 @@ struct MHeapMapNode3
MSpan *s[1<<MHeapMap_Level3Bits];
};
-void MHeapMap_Init(MHeapMap *m, void *(*allocator)(uintptr));
-bool MHeapMap_Preallocate(MHeapMap *m, PageID k, uintptr npages);
-MSpan* MHeapMap_Get(MHeapMap *m, PageID k);
-MSpan* MHeapMap_GetMaybe(MHeapMap *m, PageID k);
-void MHeapMap_Set(MHeapMap *m, PageID k, MSpan *v);
+void runtime·MHeapMap_Init(MHeapMap *m, void *(*allocator)(uintptr));
+bool runtime·MHeapMap_Preallocate(MHeapMap *m, PageID k, uintptr npages);
+MSpan* runtime·MHeapMap_Get(MHeapMap *m, PageID k);
+MSpan* runtime·MHeapMap_GetMaybe(MHeapMap *m, PageID k);
+void runtime·MHeapMap_Set(MHeapMap *m, PageID k, MSpan *v);
diff --git a/src/pkg/runtime/mheapmap64_defs.go b/src/pkg/runtime/mheapmap64_defs.go
new file mode 100644
index 000000000..d7ba2b420
--- /dev/null
+++ b/src/pkg/runtime/mheapmap64_defs.go
@@ -0,0 +1,31 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+const (
+ mHeapMap_Level1Bits = 18
+ mHeapMap_Level2Bits = 18
+ mHeapMap_Level3Bits = 16
+ mHeapMap_TotalBits = mHeapMap_Level1Bits + mHeapMap_Level2Bits + mHeapMap_Level3Bits
+
+ mHeapMap_Level1Mask = (1 << mHeapMap_Level1Bits) - 1
+ mHeapMap_Level2Mask = (1 << mHeapMap_Level2Bits) - 1
+ mHeapMap_Level3Mask = (1 << mHeapMap_Level3Bits) - 1
+)
+
+type mHeapMap struct {
+ allocator func(uintptr)
+ p [1 << mHeapMap_Level1Bits]*mHeapMapNode2
+}
+
+
+type mHeapMapNode2 struct {
+ p [1 << mHeapMap_Level2Bits]*mHeapMapNode3
+}
+
+
+type mHeapMapNode3 struct {
+ s [1 << mHeapMap_Level3Bits]*mSpan
+}
diff --git a/src/pkg/runtime/mkasmh.sh b/src/pkg/runtime/mkasmh.sh
index aae773cfe..3ed5f74c9 100755
--- a/src/pkg/runtime/mkasmh.sh
+++ b/src/pkg/runtime/mkasmh.sh
@@ -16,14 +16,44 @@ case "$GOARCH" in
# The offsets 0 and 4 are also known to:
# nacl/thread.c:/^newosproc
# ../../cmd/8l/pass.c:/D_GS
- # ../../libcgo/linux_386.c:/^start
- # ../../libcgo/darwin_386.c:/^start
+ # ../../libcgo/linux_386.c:/^threadentry
+ # ../../libcgo/darwin_386.c:/^threadentry
case "$GOOS" in
windows)
echo '#define get_tls(r) MOVL 0x2c(FS), r'
echo '#define g(r) 0(r)'
echo '#define m(r) 4(r)'
;;
+ plan9)
+ echo '#define get_tls(r)'
+ echo '#define g(r) 0xdfffefc0'
+ echo '#define m(r) 0xdfffefc4'
+ ;;
+ linux)
+ # On Linux systems, what we call 0(GS) and 4(GS) for g and m
+ # turn into %gs:-8 and %gs:-4 (using gcc syntax to denote
+ # what the machine sees as opposed to 8l input).
+ # 8l rewrites 0(GS) and 4(GS) into these.
+ #
+ # On Linux Xen, it is not allowed to use %gs:-8 and %gs:-4
+ # directly. Instead, we have to store %gs:0 into a temporary
+ # register and then use -8(%reg) and -4(%reg). This kind
+ # of addressing is correct even when not running Xen.
+ #
+ # 8l can rewrite MOVL 0(GS), CX into the appropriate pair
+ # of mov instructions, using CX as the intermediate register
+ # (safe because CX is about to be written to anyway).
+ # But 8l cannot handle other instructions, like storing into 0(GS),
+ # which is where these macros come into play.
+ # get_tls sets up the temporary and then g and r use it.
+ #
+ # The final wrinkle is that get_tls needs to read from %gs:0,
+ # but in 8l input it's called 8(GS), because 8l is going to
+ # subtract 8 from all the offsets, as described above.
+ echo '#define get_tls(r) MOVL 8(GS), r'
+ echo '#define g(r) -8(r)'
+ echo '#define m(r) -4(r)'
+ ;;
*)
echo '#define get_tls(r)'
echo '#define g(r) 0(GS)'
@@ -32,10 +62,14 @@ case "$GOARCH" in
esac
;;
amd64)
- # These registers are also known to:
- # ../../libcgo/linux_amd64.c:/^start
- echo '#define g R15'
- echo '#define m R14'
+ # The offsets 0 and 8 are known to:
+ # ../../cmd/6l/pass.c:/D_GS
+ # ../../libcgo/linux_amd64.c:/^threadentry
+ # ../../libcgo/darwin_amd64.c:/^threadentry
+ #
+ echo '#define get_tls(r)'
+ echo '#define g(r) 0(GS)'
+ echo '#define m(r) 8(GS)'
;;
arm)
echo '#define g R10'
diff --git a/src/pkg/runtime/mkversion.c b/src/pkg/runtime/mkversion.c
index bf33c0f85..9790d3f09 100644
--- a/src/pkg/runtime/mkversion.c
+++ b/src/pkg/runtime/mkversion.c
@@ -5,11 +5,13 @@ char *template =
"// generated by mkversion.c; do not edit.\n"
"package runtime\n"
"const defaultGoroot = \"%s\"\n"
- "const defaultVersion = \"%s\"\n";
+ "const theVersion = \"%s\"\n"
+ "const theGoarch = \"%s\"\n"
+ "const theGoos = \"%s\"\n";
void
main(void)
{
- print(template, getgoroot(), getgoversion());
+ print(template, getgoroot(), getgoversion(), getgoarch(), getgoos());
exits(0);
}
diff --git a/src/pkg/runtime/mprof.goc b/src/pkg/runtime/mprof.goc
index 61a5132b7..f4581e98d 100644
--- a/src/pkg/runtime/mprof.goc
+++ b/src/pkg/runtime/mprof.goc
@@ -45,7 +45,7 @@ stkbucket(uintptr *stk, int32 nstk)
Bucket *b;
if(buckhash == nil) {
- buckhash = SysAlloc(BuckHashSize*sizeof buckhash[0]);
+ buckhash = runtime·SysAlloc(BuckHashSize*sizeof buckhash[0]);
mstats.buckhash_sys += BuckHashSize*sizeof buckhash[0];
}
@@ -62,12 +62,12 @@ stkbucket(uintptr *stk, int32 nstk)
i = h%BuckHashSize;
for(b = buckhash[i]; b; b=b->next)
if(b->hash == h && b->nstk == nstk &&
- mcmp((byte*)b->stk, (byte*)stk, nstk*sizeof stk[0]) == 0)
+ runtime·mcmp((byte*)b->stk, (byte*)stk, nstk*sizeof stk[0]) == 0)
return b;
- b = mallocgc(sizeof *b + nstk*sizeof stk[0], RefNoProfiling, 0, 1);
+ b = runtime·mallocgc(sizeof *b + nstk*sizeof stk[0], RefNoProfiling, 0, 1);
bucketmem += sizeof *b + nstk*sizeof stk[0];
- memmove(b->stk, stk, nstk*sizeof stk[0]);
+ runtime·memmove(b->stk, stk, nstk*sizeof stk[0]);
b->hash = h;
b->nstk = nstk;
b->next = buckhash[i];
@@ -132,7 +132,7 @@ setaddrbucket(uintptr addr, Bucket *b)
if(ah->addr == (addr>>20))
goto found;
- ah = mallocgc(sizeof *ah, RefNoProfiling, 0, 1);
+ ah = runtime·mallocgc(sizeof *ah, RefNoProfiling, 0, 1);
addrmem += sizeof *ah;
ah->next = addrhash[h];
ah->addr = addr>>20;
@@ -140,7 +140,7 @@ setaddrbucket(uintptr addr, Bucket *b)
found:
if((e = addrfree) == nil) {
- e = mallocgc(64*sizeof *e, RefNoProfiling, 0, 0);
+ e = runtime·mallocgc(64*sizeof *e, RefNoProfiling, 0, 0);
addrmem += 64*sizeof *e;
for(i=0; i+1<64; i++)
e[i].next = &e[i+1];
@@ -185,7 +185,7 @@ found:
// Called by malloc to record a profiled block.
void
-MProf_Malloc(void *p, uintptr size)
+runtime·MProf_Malloc(void *p, uintptr size)
{
int32 nstk;
uintptr stk[32];
@@ -195,19 +195,19 @@ MProf_Malloc(void *p, uintptr size)
return;
m->nomemprof++;
- nstk = callers(1, stk, 32);
- lock(&proflock);
+ nstk = runtime·callers(1, stk, 32);
+ runtime·lock(&proflock);
b = stkbucket(stk, nstk);
b->allocs++;
b->alloc_bytes += size;
setaddrbucket((uintptr)p, b);
- unlock(&proflock);
+ runtime·unlock(&proflock);
m->nomemprof--;
}
// Called when freeing a profiled block.
void
-MProf_Free(void *p, uintptr size)
+runtime·MProf_Free(void *p, uintptr size)
{
Bucket *b;
@@ -215,13 +215,13 @@ MProf_Free(void *p, uintptr size)
return;
m->nomemprof++;
- lock(&proflock);
+ runtime·lock(&proflock);
b = getaddrbucket((uintptr)p);
if(b != nil) {
b->frees++;
b->free_bytes += size;
}
- unlock(&proflock);
+ runtime·unlock(&proflock);
m->nomemprof--;
}
@@ -257,7 +257,7 @@ func MemProfile(p Slice, include_inuse_zero bool) (n int32, ok bool) {
Bucket *b;
Record *r;
- lock(&proflock);
+ runtime·lock(&proflock);
n = 0;
for(b=buckets; b; b=b->allnext)
if(include_inuse_zero || b->alloc_bytes != b->free_bytes)
@@ -270,5 +270,5 @@ func MemProfile(p Slice, include_inuse_zero bool) (n int32, ok bool) {
if(include_inuse_zero || b->alloc_bytes != b->free_bytes)
record(r++, b);
}
- unlock(&proflock);
+ runtime·unlock(&proflock);
}
diff --git a/src/pkg/runtime/msize.c b/src/pkg/runtime/msize.c
index aebc15416..ec85eb373 100644
--- a/src/pkg/runtime/msize.c
+++ b/src/pkg/runtime/msize.c
@@ -28,9 +28,9 @@
#include "runtime.h"
#include "malloc.h"
-int32 class_to_size[NumSizeClasses];
-int32 class_to_allocnpages[NumSizeClasses];
-int32 class_to_transfercount[NumSizeClasses];
+int32 runtime·class_to_size[NumSizeClasses];
+int32 runtime·class_to_allocnpages[NumSizeClasses];
+int32 runtime·class_to_transfercount[NumSizeClasses];
// The SizeToClass lookup is implemented using two arrays,
// one mapping sizes <= 1024 to their class and one mapping
@@ -45,24 +45,24 @@ static int32 size_to_class8[1024/8 + 1];
static int32 size_to_class128[(MaxSmallSize-1024)/128 + 1];
int32
-SizeToClass(int32 size)
+runtime·SizeToClass(int32 size)
{
if(size > MaxSmallSize)
- throw("SizeToClass - invalid size");
+ runtime·throw("SizeToClass - invalid size");
if(size > 1024-8)
return size_to_class128[(size-1024+127) >> 7];
return size_to_class8[(size+7)>>3];
}
void
-InitSizes(void)
+runtime·InitSizes(void)
{
int32 align, sizeclass, size, osize, nextsize, n;
uint32 i;
uintptr allocsize, npages;
- // Initialize the class_to_size table (and choose class sizes in the process).
- class_to_size[0] = 0;
+ // Initialize the runtime·class_to_size table (and choose class sizes in the process).
+ runtime·class_to_size[0] = 0;
sizeclass = 1; // 0 means no class
align = 8;
for(size = align; size <= MaxSmallSize; size += align) {
@@ -75,7 +75,7 @@ InitSizes(void)
align = 16; // required for x86 SSE instructions, if we want to use them
}
if((align&(align-1)) != 0)
- throw("InitSizes - bug");
+ runtime·throw("InitSizes - bug");
// Make the allocnpages big enough that
// the leftover is less than 1/8 of the total,
@@ -92,78 +92,78 @@ InitSizes(void)
// use just this size instead of having two
// different sizes.
if(sizeclass > 1
- && npages == class_to_allocnpages[sizeclass-1]
- && allocsize/osize == allocsize/(class_to_size[sizeclass-1]+RefcountOverhead)) {
- class_to_size[sizeclass-1] = size;
+ && npages == runtime·class_to_allocnpages[sizeclass-1]
+ && allocsize/osize == allocsize/(runtime·class_to_size[sizeclass-1]+RefcountOverhead)) {
+ runtime·class_to_size[sizeclass-1] = size;
continue;
}
- class_to_allocnpages[sizeclass] = npages;
- class_to_size[sizeclass] = size;
+ runtime·class_to_allocnpages[sizeclass] = npages;
+ runtime·class_to_size[sizeclass] = size;
sizeclass++;
}
if(sizeclass != NumSizeClasses) {
- printf("sizeclass=%d NumSizeClasses=%d\n", sizeclass, NumSizeClasses);
- throw("InitSizes - bad NumSizeClasses");
+ runtime·printf("sizeclass=%d NumSizeClasses=%d\n", sizeclass, NumSizeClasses);
+ runtime·throw("InitSizes - bad NumSizeClasses");
}
// Initialize the size_to_class tables.
nextsize = 0;
for (sizeclass = 1; sizeclass < NumSizeClasses; sizeclass++) {
- for(; nextsize < 1024 && nextsize <= class_to_size[sizeclass]; nextsize+=8)
+ for(; nextsize < 1024 && nextsize <= runtime·class_to_size[sizeclass]; nextsize+=8)
size_to_class8[nextsize/8] = sizeclass;
if(nextsize >= 1024)
- for(; nextsize <= class_to_size[sizeclass]; nextsize += 128)
+ for(; nextsize <= runtime·class_to_size[sizeclass]; nextsize += 128)
size_to_class128[(nextsize-1024)/128] = sizeclass;
}
// Double-check SizeToClass.
if(0) {
for(n=0; n < MaxSmallSize; n++) {
- sizeclass = SizeToClass(n);
- if(sizeclass < 1 || sizeclass >= NumSizeClasses || class_to_size[sizeclass] < n) {
- printf("size=%d sizeclass=%d class_to_size=%d\n", n, sizeclass, class_to_size[sizeclass]);
- printf("incorrect SizeToClass");
+ sizeclass = runtime·SizeToClass(n);
+ if(sizeclass < 1 || sizeclass >= NumSizeClasses || runtime·class_to_size[sizeclass] < n) {
+ runtime·printf("size=%d sizeclass=%d runtime·class_to_size=%d\n", n, sizeclass, runtime·class_to_size[sizeclass]);
+ runtime·printf("incorrect SizeToClass");
goto dump;
}
- if(sizeclass > 1 && class_to_size[sizeclass-1] >= n) {
- printf("size=%d sizeclass=%d class_to_size=%d\n", n, sizeclass, class_to_size[sizeclass]);
- printf("SizeToClass too big");
+ if(sizeclass > 1 && runtime·class_to_size[sizeclass-1] >= n) {
+ runtime·printf("size=%d sizeclass=%d runtime·class_to_size=%d\n", n, sizeclass, runtime·class_to_size[sizeclass]);
+ runtime·printf("SizeToClass too big");
goto dump;
}
}
}
// Copy out for statistics table.
- for(i=0; i<nelem(class_to_size); i++)
- mstats.by_size[i].size = class_to_size[i];
+ for(i=0; i<nelem(runtime·class_to_size); i++)
+ mstats.by_size[i].size = runtime·class_to_size[i];
- // Initialize the class_to_transfercount table.
+ // Initialize the runtime·class_to_transfercount table.
for(sizeclass = 1; sizeclass < NumSizeClasses; sizeclass++) {
- n = 64*1024 / class_to_size[sizeclass];
+ n = 64*1024 / runtime·class_to_size[sizeclass];
if(n < 2)
n = 2;
if(n > 32)
n = 32;
- class_to_transfercount[sizeclass] = n;
+ runtime·class_to_transfercount[sizeclass] = n;
}
return;
dump:
if(1){
- printf("NumSizeClasses=%d\n", NumSizeClasses);
- printf("class_to_size:");
+ runtime·printf("NumSizeClasses=%d\n", NumSizeClasses);
+ runtime·printf("runtime·class_to_size:");
for(sizeclass=0; sizeclass<NumSizeClasses; sizeclass++)
- printf(" %d", class_to_size[sizeclass]);
- printf("\n\n");
- printf("size_to_class8:");
+ runtime·printf(" %d", runtime·class_to_size[sizeclass]);
+ runtime·printf("\n\n");
+ runtime·printf("size_to_class8:");
for(i=0; i<nelem(size_to_class8); i++)
- printf(" %d=>%d(%d)\n", i*8, size_to_class8[i], class_to_size[size_to_class8[i]]);
- printf("\n");
- printf("size_to_class128:");
+ runtime·printf(" %d=>%d(%d)\n", i*8, size_to_class8[i], runtime·class_to_size[size_to_class8[i]]);
+ runtime·printf("\n");
+ runtime·printf("size_to_class128:");
for(i=0; i<nelem(size_to_class128); i++)
- printf(" %d=>%d(%d)\n", i*128, size_to_class128[i], class_to_size[size_to_class128[i]]);
- printf("\n");
+ runtime·printf(" %d=>%d(%d)\n", i*128, size_to_class128[i], runtime·class_to_size[size_to_class128[i]]);
+ runtime·printf("\n");
}
- throw("InitSizes failed");
+ runtime·throw("InitSizes failed");
}
diff --git a/src/pkg/runtime/nacl/386/closure.c b/src/pkg/runtime/nacl/386/closure.c
deleted file mode 100644
index 6a27d6ec6..000000000
--- a/src/pkg/runtime/nacl/386/closure.c
+++ /dev/null
@@ -1,247 +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.
-
-/*
- * Closure implementation for Native Client.
- * Native Client imposes some interesting restrictions.
- *
- * First, we can only add new code to the code segment
- * through a special system call, and we have to pick the
- * maximum amount of code we're going to add that way
- * at link time (8l reserves 512 kB for us).
- *
- * Second, once we've added the code we can't ever
- * change it or delete it. If we want to garbage collect
- * the memory and then reuse it for another closure,
- * we have to do so without editing the code.
- *
- * To address both of these, we fill the code segment pieces
- * with very stylized closures. Each has the form given below
- * in the comments on the closasm array, with ** replaced by
- * a pointer to a single word of memory. The garbage collector
- * treats a pointer to such a closure as equivalent to the value
- * held in **. This tiled run of closures is called the closure array.
- *
- * The ptr points at a ClosureData structure, defined below,
- * which gives the function, arguments, and size for the
- * closuretramp function. The ClosureData structure has
- * in it a pointer to a ClosureFreeList structure holding the index
- * of the closure in the closure array (but not a pointer to it).
- * That structure has a finalizer: when the garbage collector
- * notices that the ClosureFreeList structure is not referenced
- * anymore, that means the closure is not referenced, so it
- * can be reused. To do that, the ClosureFreeList entry is put
- * onto an actual free list.
- */
-#include "runtime.h"
-#include "malloc.h"
-
-// NaCl system call to copy data into text segment.
-extern int32 dyncode_copy(void*, void*, int32);
-
-enum{
- // Allocate chunks of 4096 bytes worth of closures:
- // at 64 bytes each, that's 64 closures.
- ClosureChunk = 4096,
- ClosureSize = 64,
-};
-
-typedef struct ClosureFreeList ClosureFreeList;
-struct ClosureFreeList
-{
- ClosureFreeList *next;
- int32 index; // into closure array
-};
-
-// Known to closasm
-typedef struct ClosureData ClosureData;
-struct ClosureData
-{
- ClosureFreeList *free;
- byte *fn;
- int32 siz;
- // then args
-};
-
-// List of the closure data pointer blocks we've allocated
-// and hard-coded in the closure text segments.
-// The list keeps the pointer blocks from getting collected.
-typedef struct ClosureDataList ClosureDataList;
-struct ClosureDataList
-{
- ClosureData **block;
- ClosureDataList *next;
-};
-
-static struct {
- Lock;
- byte *code;
- byte *ecode;
- ClosureFreeList *free;
- ClosureDataList *datalist;
- byte buf[ClosureChunk];
-} clos;
-
-static byte closasm[64] = {
- 0x8b, 0x1d, 0, 0, 0, 0, // MOVL **, BX
- 0x8b, 0x4b, 8, // MOVL 8(BX), CX
- 0x8d, 0x73, 12, // LEAL 12(BX), SI
- 0x29, 0xcc, // SUBL CX, SP
- 0x89, 0xe7, // MOVL SP, DI
- 0xc1, 0xe9, 2, // SHRL $2, CX
- 0xf3, 0xa5, // REP MOVSL
- 0x8b, 0x5b, 4, // MOVL 4(BX), BX
- 0x90, 0x90, 0x90, // NOP...
- 0x83, 0xe3, ~31, // ANDL $~31, BX
- 0xff, 0xd3, // CALL *BX
- // --- 32-byte boundary
- 0x8b, 0x1d, 0, 0, 0, 0, // MOVL **, BX
- 0x03, 0x63, 8, // ADDL 8(BX), SP
- 0x5b, // POPL BX
- 0x83, 0xe3, ~31, // ANDL $~31, BX
- 0xff, 0xe3, // JMP *BX
- 0xf4, // HLT...
- 0xf4, 0xf4, 0xf4, 0xf4,
- 0xf4, 0xf4, 0xf4, 0xf4,
- 0xf4, 0xf4, 0xf4, 0xf4,
- 0xf4, 0xf4, 0xf4, 0xf4,
- // --- 32-byte boundary
-};
-
-// Returns immediate pointer from closure code block.
-// Triple pointer:
-// p is the instruction stream
-// p+2 is the location of the immediate value
-// *(p+2) is the immediate value, a word in the pointer block
-// permanently associated with this closure.
-// **(p+2) is the ClosureData* pointer temporarily associated
-// with this closure.
-//
-#define codeptr(p) *(ClosureData***)((byte*)(p)+2)
-
-void
-finclosure(void *v)
-{
- byte *p;
- ClosureFreeList *f;
-
- f = v;
- p = clos.code + f->index*ClosureSize;
- *codeptr(p) = nil;
-
- lock(&clos);
- f->next = clos.free;
- clos.free = f;
- unlock(&clos);
-}
-
-#pragma textflag 7
-// func closure(siz int32,
-// fn func(arg0, arg1, arg2 *ptr, callerpc uintptr, xxx) yyy,
-// arg0, arg1, arg2 *ptr) (func(xxx) yyy)
-void
-·closure(int32 siz, byte *fn, byte *arg0)
-{
- byte *p, **ret;
- int32 e, i, n, off;
- extern byte data[], etext[];
- ClosureData *d, **block;
- ClosureDataList *l;
- ClosureFreeList *f;
-
- if(siz < 0 || siz%4 != 0)
- throw("bad closure size");
-
- ret = (byte**)((byte*)&arg0 + siz);
-
- if(siz > 100) {
- // TODO(rsc): implement stack growth preamble?
- throw("closure too big");
- }
-
- lock(&clos);
- if(clos.free == nil) {
- // Allocate more closures.
- if(clos.code == nil) {
- // First time: find closure space, between end of text
- // segment and beginning of data.
- clos.code = (byte*)(((uintptr)etext + 65535) & ~65535);
- clos.ecode = clos.code;
- mheap.closure_min = clos.code;
- mheap.closure_max = data;
- }
- if(clos.ecode+ClosureChunk > data) {
- // Last ditch effort: garbage collect and hope.
- unlock(&clos);
- gc(1);
- lock(&clos);
- if(clos.free != nil)
- goto alloc;
- throw("ran out of room for closures in text segment");
- }
-
- n = ClosureChunk/ClosureSize;
-
- // Allocate the pointer block as opaque to the
- // garbage collector. Finalizers will clean up.
- block = mallocgc(n*sizeof block[0], RefNoPointers, 1, 1);
-
- // Pointers into the pointer block are getting added
- // to the text segment; keep a pointer here in the data
- // segment so that the garbage collector doesn't free
- // the block itself.
- l = mal(sizeof *l);
- l->block = block;
- l->next = clos.datalist;
- clos.datalist = l;
-
- p = clos.buf;
- off = (clos.ecode - clos.code)/ClosureSize;
- for(i=0; i<n; i++) {
- f = mal(sizeof *f);
- f->index = off++;
- f->next = clos.free;
- clos.free = f;
-
- // There are two hard-coded immediate values in
- // the assembly that need to be pp+i, one 2 bytes in
- // and one 2 bytes after the 32-byte boundary.
- mcpy(p, closasm, ClosureSize);
- *(ClosureData***)(p+2) = block+i;
- *(ClosureData***)(p+32+2) = block+i;
- p += ClosureSize;
- }
-
- if(p != clos.buf+sizeof clos.buf)
- throw("bad buf math in closure");
-
- e = dyncode_copy(clos.ecode, clos.buf, ClosureChunk);
- if(e != 0) {
- fd = 2;
- printf("dyncode_copy: error %d\n", e);
- throw("dyncode_copy");
- }
- clos.ecode += ClosureChunk;
- }
-
-alloc:
- // Grab a free closure and save the data pointer in its indirect pointer.
- f = clos.free;
- clos.free = f->next;
- f->next = nil;
- p = clos.code + f->index*ClosureSize;
-
- d = mal(sizeof(*d)+siz);
- d->free = f;
- d->fn = fn;
- d->siz = siz;
- mcpy((byte*)(d+1), (byte*)&arg0, siz);
- *codeptr(p) = d;
- addfinalizer(f, finclosure, 0);
- unlock(&clos);
-
- *ret = p;
-}
-
-
diff --git a/src/pkg/runtime/nacl/386/defs.h b/src/pkg/runtime/nacl/386/defs.h
deleted file mode 100644
index 420b6910b..000000000
--- a/src/pkg/runtime/nacl/386/defs.h
+++ /dev/null
@@ -1,17 +0,0 @@
-// godefs -f-m32 -f-I/home/rsc/pub/nacl/native_client/src/third_party/nacl_sdk/linux/sdk/nacl-sdk/nacl/include -f-I/home/rsc/pub/nacl/native_client 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,
-};
-
-// Types
-#pragma pack on
-#pragma pack off
diff --git a/src/pkg/runtime/nacl/386/rt0.s b/src/pkg/runtime/nacl/386/rt0.s
deleted file mode 100644
index d967bafd4..000000000
--- a/src/pkg/runtime/nacl/386/rt0.s
+++ /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.
-
-// Native Client and Linux use the same linkage to main
-
-TEXT _rt0_386_nacl(SB),7,$0
- JMP _rt0_386(SB)
diff --git a/src/pkg/runtime/nacl/386/signal.c b/src/pkg/runtime/nacl/386/signal.c
deleted file mode 100644
index 4dda63fcf..000000000
--- a/src/pkg/runtime/nacl/386/signal.c
+++ /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 "runtime.h"
-#include "defs.h"
-#include "signals.h"
-#include "os.h"
-
-void
-initsig(int32 queue)
-{
-}
-
diff --git a/src/pkg/runtime/nacl/386/sys.s b/src/pkg/runtime/nacl/386/sys.s
deleted file mode 100644
index e855351b9..000000000
--- a/src/pkg/runtime/nacl/386/sys.s
+++ /dev/null
@@ -1,138 +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.
-
-//
-// System calls and other sys.stuff for 386, Linux
-//
-
-#include "386/asm.h"
-
-// http://code.google.com/p/nativeclient/source/browse/trunk/src/native_client/src/trusted/service_runtime/include/bits/nacl_syscalls.h
-#define SYS_exit 30
-#define SYS_mmap 21
-#define SYS_thread_create 80
-#define SYS_thread_exit 81
-#define SYS_tls_init 82
-#define SYS_write 13
-#define SYS_close 11
-#define SYS_mutex_create 70
-#define SYS_mutex_lock 71
-#define SYS_mutex_unlock 73
-#define SYS_gettimeofday 40
-#define SYS_dyncode_copy 104
-
-
-#define SYSCALL(x) $(0x10000+SYS_/**/x * 32)
-
-TEXT exit(SB),7,$4
- MOVL code+0(FP), AX
- MOVL AX, 0(SP)
- CALL SYSCALL(exit)
- INT $3 // not reached
- RET
-
-TEXT exit1(SB),7,$4
- MOVL code+0(FP), AX
- MOVL AX, 0(SP)
- CALL SYSCALL(thread_exit)
- INT $3 // not reached
- RET
-
-TEXT write(SB),7,$0
- JMP SYSCALL(write)
-
-TEXT close(SB),7,$0
- JMP SYSCALL(close)
-
-TEXT mutex_create(SB),7,$0
- JMP SYSCALL(mutex_create)
-
-TEXT mutex_lock(SB),7,$0
- JMP SYSCALL(mutex_lock)
-
-TEXT mutex_unlock(SB),7,$0
- JMP SYSCALL(mutex_unlock)
-
-TEXT thread_create(SB),7,$0
- JMP SYSCALL(thread_create)
-
-TEXT dyncode_copy(SB),7,$0
- JMP SYSCALL(dyncode_copy)
-
-// For Native Client: a simple no-op function.
-// Inserting a call to this no-op is a simple way
-// to trigger an alignment.
-TEXT ·naclnop(SB),7,$0
- RET
-
-TEXT ·mmap(SB),7,$24
- MOVL a1+0(FP), BX
- MOVL a2+4(FP), CX // round up to 64 kB boundary; silences nacl warning
- ADDL $(64*1024-1), CX
- ANDL $~(64*1024-1), CX
- MOVL a3+8(FP), DX
- MOVL a4+12(FP), SI
- MOVL a5+16(FP), DI
- MOVL a6+20(FP), BP
- MOVL BX, 0(SP)
- MOVL CX, 4(SP)
- MOVL DX, 8(SP)
- MOVL SI, 12(SP)
- MOVL DI, 16(SP)
- MOVL BP, 20(SP)
- CALL SYSCALL(mmap)
- CMPL AX, $0xfffff001
- JLS 6(PC)
- MOVL $1, 0(SP)
- MOVL $mmap_failed(SB), 4(SP)
- MOVL $12, 8(SP) // "mmap failed\n"
- CALL SYSCALL(write)
- INT $3
- RET
-
-TEXT gettime(SB),7,$32
- LEAL 8(SP), BX
- MOVL BX, 0(SP)
- MOVL $0, 4(SP)
- CALL SYSCALL(gettimeofday)
-
- MOVL 8(SP), BX // sec
- MOVL sec+0(FP), DI
- MOVL BX, (DI)
- MOVL $0, 4(DI) // zero extend 32 -> 64 bits
-
- MOVL 12(SP), BX // usec
- MOVL usec+4(FP), DI
- MOVL BX, (DI)
- RET
-
-// setldt(int entry, int address, int limit)
-TEXT setldt(SB),7,$32
- // entry is ignored - nacl tells us the
- // segment selector to use and stores it in GS.
- MOVL address+4(FP), BX
- MOVL limit+8(FP), CX
- MOVL BX, 0(SP)
- MOVL CX, 4(SP)
- CALL SYSCALL(tls_init)
- CMPL AX, $0xfffff001
- JLS 6(PC)
- MOVL $1, 0(SP)
- MOVL $tls_init_failed(SB), 4(SP)
- MOVL $16, 8(SP) // "tls_init failed\n"
- CALL SYSCALL(write)
- INT $3
- RET
-
-// There's no good way (yet?) to get stack traces out of a
-// broken NaCl process, so if something goes wrong,
-// print an error string before dying.
-
-DATA mmap_failed(SB)/8, $"mmap fai"
-DATA mmap_failed+8(SB)/4, $"led\n"
-GLOBL mmap_failed(SB), $12
-
-DATA tls_init_failed(SB)/8, $"tls_init"
-DATA tls_init_failed+8(SB)/8, $" failed\n"
-GLOBL tls_init_failed(SB), $16
diff --git a/src/pkg/runtime/nacl/defs.c b/src/pkg/runtime/nacl/defs.c
deleted file mode 100644
index bcaddd74f..000000000
--- a/src/pkg/runtime/nacl/defs.c
+++ /dev/null
@@ -1,27 +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/nacl/native_client/src/third_party/nacl_sdk/linux/sdk/nacl-sdk/nacl/include -f-I/home/rsc/pub/nacl/native_client defs.c >386/defs.h
-*/
-
-#define __native_client__ 1
-
-#define suseconds_t nacl_suseconds_t_1
-#include <sys/types.h>
-#undef suseconds_t
-
-#include <sys/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,
-};
diff --git a/src/pkg/runtime/nacl/mem.c b/src/pkg/runtime/nacl/mem.c
deleted file mode 100644
index 52e351a7d..000000000
--- a/src/pkg/runtime/nacl/mem.c
+++ /dev/null
@@ -1,28 +0,0 @@
-#include "runtime.h"
-#include "defs.h"
-#include "os.h"
-#include "malloc.h"
-
-void*
-SysAlloc(uintptr n)
-{
- mstats.sys += n;
- return runtime_mmap(nil, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, -1, 0);
-}
-
-void
-SysUnused(void *v, uintptr n)
-{
- USED(v);
- USED(n);
- // TODO(rsc): call madvise MADV_DONTNEED
-}
-
-void
-SysFree(void *v, uintptr n)
-{
- USED(v);
- USED(n);
- // TODO(rsc): call munmap
-}
-
diff --git a/src/pkg/runtime/nacl/os.h b/src/pkg/runtime/nacl/os.h
deleted file mode 100644
index eb4af57b2..000000000
--- a/src/pkg/runtime/nacl/os.h
+++ /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.
-
-int32 thread_create(void(*fn)(void), void *stk, void *tls, int32 tlssize);
-void close(int32);
-int32 mutex_create(void);
-int32 mutex_lock(int32);
-int32 mutex_unlock(int32);
diff --git a/src/pkg/runtime/nacl/signals.h b/src/pkg/runtime/nacl/signals.h
deleted file mode 100644
index e69de29bb..000000000
--- a/src/pkg/runtime/nacl/signals.h
+++ /dev/null
diff --git a/src/pkg/runtime/nacl/thread.c b/src/pkg/runtime/nacl/thread.c
deleted file mode 100644
index 392be870f..000000000
--- a/src/pkg/runtime/nacl/thread.c
+++ /dev/null
@@ -1,164 +0,0 @@
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-#include "runtime.h"
-#include "defs.h"
-#include "os.h"
-
-int8 *goos = "nacl";
-
-// Thread-safe allocation of a mutex.
-// (The name sema is left over from the Darwin implementation.
-// Native Client implements semaphores too, but it is just a shim
-// over the host implementation, which on some hosts imposes a very
-// low limit on how many semaphores can be created.)
-//
-// Psema points at a mutex descriptor.
-// It starts out zero, meaning no mutex.
-// 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 = mutex_create();
- if((int32)sema < 0) {
- printf("mutex_create failed\n");
- breakpoint();
- }
- // mutex_create returns a file descriptor;
- // shift it up and add the 1 bit so that can
- // distinguish unintialized from fd 0.
- sema = (sema<<1) | 1;
- if(!cas(psema, 0, sema)){
- // Someone else filled it in. Use theirs.
- close(sema);
- return;
- }
-}
-
-// Lock and unlock.
-// Defer entirely to Native Client.
-// The expense of a call into Native Client is more like
-// a function call than a system call, so as long as the
-// Native Client lock implementation is good, we can't
-// do better ourselves.
-
-static void
-xlock(int32 fd)
-{
- if(mutex_lock(fd) < 0) {
- printf("mutex_lock failed\n");
- breakpoint();
- }
-}
-
-static void
-xunlock(int32 fd)
-{
- if(mutex_unlock(fd) < 0) {
- printf("mutex_lock failed\n");
- breakpoint();
- }
-}
-
-void
-lock(Lock *l)
-{
- if(m->locks < 0)
- throw("lock count");
- m->locks++;
- if(l->sema == 0)
- initsema(&l->sema);
- xlock(l->sema>>1);
-}
-
-void
-unlock(Lock *l)
-{
- m->locks--;
- if(m->locks < 0)
- throw("lock count");
- xunlock(l->sema>>1);
-}
-
-void
-destroylock(Lock*)
-{
-}
-
-// One-time notifications.
-//
-// Since the lock/unlock implementation already
-// takes care of sleeping in the kernel, we just reuse it.
-// (But it's a weird use, so it gets its own interface.)
-//
-// We use a lock to represent the event:
-// unlocked == event has happened.
-// Thus the lock starts out locked, and to wait for the
-// event you try to lock the lock. To signal the event,
-// you unlock the lock.
-//
-// Native Client does not require that the thread acquiring
-// a lock be the thread that releases the lock, so this is safe.
-
-void
-noteclear(Note *n)
-{
- if(n->lock.sema == 0)
- initsema(&n->lock.sema);
- xlock(n->lock.sema>>1);
-}
-
-void
-notewakeup(Note *n)
-{
- if(n->lock.sema == 0) {
- printf("notewakeup without noteclear");
- breakpoint();
- }
- xunlock(n->lock.sema>>1);
-}
-
-void
-notesleep(Note *n)
-{
- if(n->lock.sema == 0) {
- printf("notesleep without noteclear");
- breakpoint();
- }
- xlock(n->lock.sema>>1);
- xunlock(n->lock.sema>>1); // Let other sleepers find out too.
-}
-
-void
-newosproc(M *m, G *g, void *stk, void (*fn)(void))
-{
- void **vstk;
-
- // I wish every OS made thread creation this easy.
- m->tls[0] = (uint32)g;
- m->tls[1] = (uint32)m;
- vstk = stk;
- *--vstk = nil;
- if(thread_create(fn, vstk, m->tls, sizeof m->tls) < 0) {
- printf("thread_create failed\n");
- breakpoint();
- }
-}
-
-void
-osinit(void)
-{
-}
-
-// Called to initialize a new m (including the bootstrap m).
-void
-minit(void)
-{
-}
diff --git a/src/pkg/runtime/plan9/386/defs.h b/src/pkg/runtime/plan9/386/defs.h
new file mode 100644
index 000000000..5df757613
--- /dev/null
+++ b/src/pkg/runtime/plan9/386/defs.h
@@ -0,0 +1 @@
+// nothing to see here
diff --git a/src/pkg/runtime/plan9/386/rt0.s b/src/pkg/runtime/plan9/386/rt0.s
new file mode 100644
index 000000000..b56c8b325
--- /dev/null
+++ b/src/pkg/runtime/plan9/386/rt0.s
@@ -0,0 +1,32 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+TEXT _rt0_386_plan9(SB),7, $0
+ MOVL AX, _tos(SB)
+
+ // move arguments down to make room for
+ // m and g at top of stack, right before Tos.
+ MOVL SP, SI
+ SUBL $8, SP
+ MOVL SP, DI
+
+ MOVL AX, CX
+ SUBL SI, CX
+ CLD
+ REP; MOVSB
+
+ // adjust argv
+ SUBL SI, DI
+ MOVL newargc+0(SP), CX
+ LEAL newargv+4(SP), BP
+argv_fix:
+ ADDL DI, 0(BP)
+ ADDL $4, BP
+ LOOP argv_fix
+
+ JMP _rt0_386(SB)
+
+DATA runtime·isplan9(SB)/4, $1
+GLOBL runtime·isplan9(SB), $4
+GLOBL _tos(SB), $4
diff --git a/src/pkg/runtime/plan9/386/signal.c b/src/pkg/runtime/plan9/386/signal.c
new file mode 100644
index 000000000..6bde09846
--- /dev/null
+++ b/src/pkg/runtime/plan9/386/signal.c
@@ -0,0 +1,16 @@
+// Copyright 2010 The Go Authors. 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"
+
+void
+runtime·gettime(int64*, int32*)
+{
+}
+
+String
+runtime·signame(int32)
+{
+ return runtime·emptystring;
+}
diff --git a/src/pkg/runtime/plan9/386/sys.s b/src/pkg/runtime/plan9/386/sys.s
new file mode 100644
index 000000000..867b8940f
--- /dev/null
+++ b/src/pkg/runtime/plan9/386/sys.s
@@ -0,0 +1,76 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// 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"
+
+// setldt(int entry, int address, int limit)
+TEXT runtime·setldt(SB),7,$0
+ RET
+
+TEXT runtime·write(SB),7,$0
+ MOVL $20, AX
+ INT $64
+ RET
+
+TEXT runtime·exits(SB),7,$0
+ MOVL $8, AX
+ INT $64
+ RET
+
+TEXT runtime·brk_(SB),7,$0
+ MOVL $24, AX
+ INT $64
+ RET
+
+TEXT runtime·plan9_semacquire(SB),7,$0
+ MOVL $37, AX
+ INT $64
+ RET
+
+TEXT runtime·plan9_semrelease(SB),7,$0
+ MOVL $38, AX
+ INT $64
+ RET
+
+TEXT runtime·rfork(SB),7,$0
+ MOVL $19, AX // rfork
+ INT $64
+
+ // In parent, return.
+ CMPL AX, $0
+ JEQ 2(PC)
+ RET
+
+ // In child on old stack.
+ MOVL mm+12(SP), BX // m
+ MOVL gg+16(SP), DX // g
+ MOVL fn+20(SP), SI // fn
+
+ // set SP to be on the new child stack
+ MOVL stack+8(SP), CX
+ MOVL CX, SP
+
+ // Initialize m, g.
+ get_tls(AX)
+ MOVL DX, g(AX)
+ MOVL BX, m(AX)
+
+ // Initialize AX from _tos->pid
+ MOVL 0xdfffeff8, AX
+ MOVL AX, m_procid(BX) // save pid as m->procid
+
+ 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 SI // fn()
+ CALL runtime·exit(SB)
+ RET
diff --git a/src/pkg/runtime/plan9/mem.c b/src/pkg/runtime/plan9/mem.c
new file mode 100644
index 000000000..651e6728e
--- /dev/null
+++ b/src/pkg/runtime/plan9/mem.c
@@ -0,0 +1,49 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "runtime.h"
+#include "malloc.h"
+
+extern byte end[];
+static byte *bloc = { end };
+
+enum
+{
+ Round = 7
+};
+
+void*
+runtime·SysAlloc(uintptr ask)
+{
+ uintptr bl;
+
+ // Plan 9 sbrk from /sys/src/libc/9sys/sbrk.c
+ bl = ((uintptr)bloc + Round) & ~Round;
+ if(runtime·brk_((void*)(bl + ask)) < 0)
+ return (void*)-1;
+ bloc = (byte*)bl + ask;
+ return (void*)bl;
+}
+
+void
+runtime·SysFree(void *v, uintptr n)
+{
+ // from tiny/mem.c
+ // Push pointer back if this is a free
+ // of the most recent SysAlloc.
+ n += (n + Round) & ~Round;
+ if(bloc == (byte*)v+n)
+ bloc -= n;
+}
+
+void
+runtime·SysUnused(void *v, uintptr n)
+{
+ USED(v, n);
+}
+
+void
+runtime·SysMemInit(void)
+{
+}
diff --git a/src/pkg/runtime/plan9/os.h b/src/pkg/runtime/plan9/os.h
new file mode 100644
index 000000000..9444acc98
--- /dev/null
+++ b/src/pkg/runtime/plan9/os.h
@@ -0,0 +1,27 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+extern int32 runtime·write(int32 fd, void* buffer, int32 nbytes);
+extern void runtime·exits(int8* msg);
+extern int32 runtime·brk_(void*);
+
+/* rfork */
+enum
+{
+ RFNAMEG = (1<<0),
+ RFENVG = (1<<1),
+ RFFDG = (1<<2),
+ RFNOTEG = (1<<3),
+ RFPROC = (1<<4),
+ RFMEM = (1<<5),
+ RFNOWAIT = (1<<6),
+ RFCNAMEG = (1<<10),
+ RFCENVG = (1<<11),
+ RFCFDG = (1<<12),
+ RFREND = (1<<13),
+ RFNOMNT = (1<<14)
+};
+extern int32 runtime·rfork(int32 flags, void *stk, M *m, G *g, void (*fn)(void));
+extern int32 runtime·plan9_semacquire(uint32 *addr, int32 block);
+extern int32 runtime·plan9_semrelease(uint32 *addr, int32 count);
diff --git a/src/pkg/runtime/plan9/runtime_defs.go b/src/pkg/runtime/plan9/runtime_defs.go
new file mode 100644
index 000000000..cf0b414a9
--- /dev/null
+++ b/src/pkg/runtime/plan9/runtime_defs.go
@@ -0,0 +1,23 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Go definitions of internal structures. Master is runtime.h
+
+package runtime
+
+type lock struct {
+ key uint32
+ sema uint32
+}
+
+type usema struct {
+ u uint32
+ k uint32
+}
+
+
+type note struct {
+ wakeup int32
+ sema usema
+}
diff --git a/src/pkg/runtime/plan9/signals.h b/src/pkg/runtime/plan9/signals.h
new file mode 100644
index 000000000..5df757613
--- /dev/null
+++ b/src/pkg/runtime/plan9/signals.h
@@ -0,0 +1 @@
+// nothing to see here
diff --git a/src/pkg/runtime/plan9/thread.c b/src/pkg/runtime/plan9/thread.c
new file mode 100644
index 000000000..fa96552a9
--- /dev/null
+++ b/src/pkg/runtime/plan9/thread.c
@@ -0,0 +1,140 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#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)
+{
+}
+
+void
+runtime·exit(int32)
+{
+ runtime·exits(nil);
+}
+
+void
+runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void))
+{
+ USED(m, g, stk, fn);
+
+ m->tls[0] = m->id; // so 386 asm can find it
+ if(0){
+ runtime·printf("newosproc stk=%p m=%p g=%p fn=%p rfork=%p id=%d/%d ostk=%p\n",
+ stk, m, g, fn, runtime·rfork, m->id, m->tls[0], &m);
+ }
+
+ if (runtime·rfork(RFPROC | RFMEM, stk, m, g, fn) < 0 )
+ 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);
+}
+
+
+void
+runtime·destroylock(Lock *l)
+{
+ // nothing
+}
+
+// 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);
+}
+
diff --git a/src/pkg/runtime/pprof/Makefile b/src/pkg/runtime/pprof/Makefile
index daffde79d..8bccc0cc0 100644
--- a/src/pkg/runtime/pprof/Makefile
+++ b/src/pkg/runtime/pprof/Makefile
@@ -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 ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=runtime/pprof
GOFILES=\
diff --git a/src/pkg/runtime/print.c b/src/pkg/runtime/print.c
index aa207e312..3b4bb103d 100644
--- a/src/pkg/runtime/print.c
+++ b/src/pkg/runtime/print.c
@@ -10,31 +10,31 @@
static void vprintf(int8*, byte*);
void
-dump(byte *p, int32 n)
+runtime·dump(byte *p, int32 n)
{
int32 i;
for(i=0; i<n; i++) {
- ·printpointer((byte*)(p[i]>>4));
- ·printpointer((byte*)(p[i]&0xf));
+ runtime·printpointer((byte*)(p[i]>>4));
+ runtime·printpointer((byte*)(p[i]&0xf));
if((i&15) == 15)
- prints("\n");
+ runtime·prints("\n");
else
- prints(" ");
+ runtime·prints(" ");
}
if(n & 15)
- prints("\n");
+ runtime·prints("\n");
}
void
-prints(int8 *s)
+runtime·prints(int8 *s)
{
- write(fd, s, findnull((byte*)s));
+ runtime·write(2, s, runtime·findnull((byte*)s));
}
#pragma textflag 7
void
-printf(int8 *s, ...)
+runtime·printf(int8 *s, ...)
{
byte *arg;
@@ -65,7 +65,7 @@ vprintf(int8 *s, byte *arg)
if(*p != '%')
continue;
if(p > lp)
- write(fd, lp, p-lp);
+ runtime·write(2, lp, p-lp);
p++;
narg = nil;
switch(*p) {
@@ -109,107 +109,104 @@ vprintf(int8 *s, byte *arg)
}
switch(*p) {
case 'a':
- ·printslice(*(Slice*)arg);
+ runtime·printslice(*(Slice*)arg);
break;
case 'd':
- ·printint(*(int32*)arg);
+ runtime·printint(*(int32*)arg);
break;
case 'D':
- ·printint(*(int64*)arg);
+ runtime·printint(*(int64*)arg);
break;
case 'e':
- ·printeface(*(Eface*)arg);
+ runtime·printeface(*(Eface*)arg);
break;
case 'f':
- ·printfloat(*(float64*)arg);
+ runtime·printfloat(*(float64*)arg);
break;
case 'C':
- ·printcomplex(*(Complex128*)arg);
+ runtime·printcomplex(*(Complex128*)arg);
break;
case 'i':
- ·printiface(*(Iface*)arg);
+ runtime·printiface(*(Iface*)arg);
break;
case 'p':
- ·printpointer(*(void**)arg);
+ runtime·printpointer(*(void**)arg);
break;
case 's':
- prints(*(int8**)arg);
+ runtime·prints(*(int8**)arg);
break;
case 'S':
- ·printstring(*(String*)arg);
+ runtime·printstring(*(String*)arg);
break;
case 't':
- ·printbool(*(bool*)arg);
+ runtime·printbool(*(bool*)arg);
break;
case 'U':
- ·printuint(*(uint64*)arg);
+ runtime·printuint(*(uint64*)arg);
break;
case 'x':
- ·printhex(*(uint32*)arg);
+ runtime·printhex(*(uint32*)arg);
break;
case 'X':
- ·printhex(*(uint64*)arg);
+ runtime·printhex(*(uint64*)arg);
break;
- case '!':
- panic(-1);
}
arg = narg;
lp = p+1;
}
if(p > lp)
- write(fd, lp, p-lp);
+ runtime·write(2, lp, p-lp);
// unlock(&debuglock);
}
#pragma textflag 7
void
-·printf(String s, ...)
+runtime·goprintf(String s, ...)
{
// Can assume s has terminating NUL because only
- // the Go compiler generates calls to ·printf, using
+ // the Go compiler generates calls to runtime·goprintf, using
// string constants, and all the string constants have NULs.
vprintf((int8*)s.str, (byte*)(&s+1));
}
void
-·printpc(void *p)
+runtime·printpc(void *p)
{
- prints("PC=");
- ·printhex((uint64)·getcallerpc(p));
+ runtime·prints("PC=");
+ runtime·printhex((uint64)runtime·getcallerpc(p));
}
void
-·printbool(bool v)
+runtime·printbool(bool v)
{
if(v) {
- write(fd, (byte*)"true", 4);
+ runtime·write(2, (byte*)"true", 4);
return;
}
- write(fd, (byte*)"false", 5);
+ runtime·write(2, (byte*)"false", 5);
}
void
-·printfloat(float64 v)
+runtime·printfloat(float64 v)
{
byte buf[20];
int32 e, s, i, n;
float64 h;
- if(isNaN(v)) {
- write(fd, "NaN", 3);
+ if(runtime·isNaN(v)) {
+ runtime·write(2, "NaN", 3);
return;
}
- if(isInf(v, 1)) {
- write(fd, "+Inf", 4);
+ if(runtime·isInf(v, 1)) {
+ runtime·write(2, "+Inf", 4);
return;
}
- if(isInf(v, -1)) {
- write(fd, "-Inf", 4);
+ if(runtime·isInf(v, -1)) {
+ runtime·write(2, "-Inf", 4);
return;
}
-
n = 7; // digits printed
e = 0; // exp
s = 0; // sign
@@ -234,6 +231,7 @@ void
h = 5;
for(i=0; i<n; i++)
h /= 10;
+
v += h;
if(v >= 10) {
e++;
@@ -264,20 +262,20 @@ void
buf[n+4] = (e/100) + '0';
buf[n+5] = (e/10)%10 + '0';
buf[n+6] = (e%10) + '0';
- write(fd, buf, n+7);
+ runtime·write(2, buf, n+7);
}
void
-·printcomplex(Complex128 v)
+runtime·printcomplex(Complex128 v)
{
- write(fd, "(", 1);
- ·printfloat(v.real);
- ·printfloat(v.imag);
- write(fd, "i)", 2);
+ runtime·write(2, "(", 1);
+ runtime·printfloat(v.real);
+ runtime·printfloat(v.imag);
+ runtime·write(2, "i)", 2);
}
void
-·printuint(uint64 v)
+runtime·printuint(uint64 v)
{
byte buf[100];
int32 i;
@@ -288,21 +286,21 @@ void
break;
v = v/10;
}
- write(fd, buf+i, nelem(buf)-i);
+ runtime·write(2, buf+i, nelem(buf)-i);
}
void
-·printint(int64 v)
+runtime·printint(int64 v)
{
if(v < 0) {
- write(fd, "-", 1);
+ runtime·write(2, "-", 1);
v = -v;
}
- ·printuint(v);
+ runtime·printuint(v);
}
void
-·printhex(uint64 v)
+runtime·printhex(uint64 v)
{
static int8 *dig = "0123456789abcdef";
byte buf[100];
@@ -315,36 +313,44 @@ void
buf[--i] = '0';
buf[--i] = 'x';
buf[--i] = '0';
- write(fd, buf+i, nelem(buf)-i);
+ runtime·write(2, buf+i, nelem(buf)-i);
}
void
-·printpointer(void *p)
+runtime·printpointer(void *p)
{
- ·printhex((uint64)p);
+ runtime·printhex((uint64)p);
}
void
-·printstring(String v)
+runtime·printstring(String v)
{
- extern int32 maxstring;
+ extern int32 runtime·maxstring;
- if(v.len > maxstring) {
- write(fd, "[invalid string]", 16);
+ if(v.len > runtime·maxstring) {
+ runtime·write(2, "[invalid string]", 16);
return;
}
if(v.len > 0)
- write(fd, v.str, v.len);
+ runtime·write(2, v.str, v.len);
+}
+
+void
+runtime·printsp(void)
+{
+ runtime·write(2, " ", 1);
}
void
-·printsp(void)
+runtime·printnl(void)
{
- write(fd, " ", 1);
+ runtime·write(2, "\n", 1);
}
void
-·printnl(void)
+runtime·typestring(Eface e, String s)
{
- write(fd, "\n", 1);
+ s = *e.type->string;
+ FLUSH(&s);
}
+
diff --git a/src/pkg/runtime/proc.c b/src/pkg/runtime/proc.c
index 2abb28307..e9a19d950 100644
--- a/src/pkg/runtime/proc.c
+++ b/src/pkg/runtime/proc.c
@@ -3,20 +3,23 @@
// license that can be found in the LICENSE file.
#include "runtime.h"
+#include "arch.h"
#include "defs.h"
#include "malloc.h"
#include "os.h"
+bool runtime·iscgo;
+
static void unwindstack(G*, byte*);
typedef struct Sched Sched;
-M m0;
-G g0; // idle goroutine for m0
+M runtime·m0;
+G runtime·g0; // idle goroutine for m0
static int32 debug = 0;
-int32 gcwaiting;
+int32 runtime·gcwaiting;
// Go scheduler
//
@@ -35,7 +38,7 @@ int32 gcwaiting;
//
// Even a program that can run without deadlock in a single process
// might use more ms if given the chance. For example, the prime
-// sieve will use as many ms as there are primes (up to sched.mmax),
+// sieve will use as many ms as there are primes (up to runtime·sched.mmax),
// allowing different stages of the pipeline to execute in parallel.
// We could revisit this choice, only kicking off new ms for blocking
// system calls, but that would limit the amount of parallel computation
@@ -69,7 +72,7 @@ struct Sched {
int32 waitstop; // after setting this flag
};
-Sched sched;
+Sched runtime·sched;
// Scheduling helpers. Sched must be locked.
static void gput(G*); // put/get on ghead/gtail
@@ -90,7 +93,7 @@ static void scheduler(void);
// call osinit
// call schedinit
// make & queue new G
-// call mstart
+// call runtime·mstart
//
// The new G does:
//
@@ -98,66 +101,67 @@ static void scheduler(void);
// call initdone
// call main·main
void
-schedinit(void)
+runtime·schedinit(void)
{
int32 n;
byte *p;
- allm = m;
+ runtime·allm = m;
m->nomemprof++;
- mallocinit();
- goargs();
+ runtime·mallocinit();
+ runtime·goargs();
+ runtime·goenvs();
// For debugging:
// Allocate internal symbol table representation now,
// so that we don't need to call malloc when we crash.
// findfunc(0);
- sched.gomaxprocs = 1;
- p = getenv("GOMAXPROCS");
- if(p != nil && (n = atoi(p)) != 0)
- sched.gomaxprocs = n;
- sched.mcpumax = sched.gomaxprocs;
- sched.mcount = 1;
- sched.predawn = 1;
+ runtime·sched.gomaxprocs = 1;
+ p = runtime·getenv("GOMAXPROCS");
+ if(p != nil && (n = runtime·atoi(p)) != 0)
+ runtime·sched.gomaxprocs = n;
+ runtime·sched.mcpumax = runtime·sched.gomaxprocs;
+ runtime·sched.mcount = 1;
+ runtime·sched.predawn = 1;
m->nomemprof--;
}
// Called after main·init_function; main·main will be called on return.
void
-initdone(void)
+runtime·initdone(void)
{
// Let's go.
- sched.predawn = 0;
+ runtime·sched.predawn = 0;
mstats.enablegc = 1;
// If main·init_function started other goroutines,
// kick off new ms to handle them, like ready
// would have, had it not been pre-dawn.
- lock(&sched);
+ runtime·lock(&runtime·sched);
matchmg();
- unlock(&sched);
+ runtime·unlock(&runtime·sched);
}
void
-goexit(void)
+runtime·goexit(void)
{
g->status = Gmoribund;
- gosched();
+ runtime·gosched();
}
void
-tracebackothers(G *me)
+runtime·tracebackothers(G *me)
{
G *g;
- for(g = allg; g != nil; g = g->alllink) {
+ for(g = runtime·allg; g != nil; g = g->alllink) {
if(g == me || g->status == Gdead)
continue;
- printf("\ngoroutine %d [%d]:\n", g->goid, g->status);
- traceback(g->sched.pc, g->sched.sp, 0, g);
+ runtime·printf("\ngoroutine %d [%d]:\n", g->goid, g->status);
+ runtime·traceback(g->sched.pc, g->sched.sp, 0, g);
}
}
@@ -168,18 +172,18 @@ gput(G *g)
M *m;
// If g is wired, hand it off directly.
- if(sched.mcpu < sched.mcpumax && (m = g->lockedm) != nil) {
+ if(runtime·sched.mcpu < runtime·sched.mcpumax && (m = g->lockedm) != nil) {
mnextg(m, g);
return;
}
g->schedlink = nil;
- if(sched.ghead == nil)
- sched.ghead = g;
+ if(runtime·sched.ghead == nil)
+ runtime·sched.ghead = g;
else
- sched.gtail->schedlink = g;
- sched.gtail = g;
- sched.gwait++;
+ runtime·sched.gtail->schedlink = g;
+ runtime·sched.gtail = g;
+ runtime·sched.gwait++;
}
// Get from `g' queue. Sched must be locked.
@@ -188,12 +192,12 @@ gget(void)
{
G *g;
- g = sched.ghead;
+ g = runtime·sched.ghead;
if(g){
- sched.ghead = g->schedlink;
- if(sched.ghead == nil)
- sched.gtail = nil;
- sched.gwait--;
+ runtime·sched.ghead = g->schedlink;
+ if(runtime·sched.ghead == nil)
+ runtime·sched.gtail = nil;
+ runtime·sched.gwait--;
}
return g;
}
@@ -202,9 +206,9 @@ gget(void)
static void
mput(M *m)
{
- m->schedlink = sched.mhead;
- sched.mhead = m;
- sched.mwait++;
+ m->schedlink = runtime·sched.mhead;
+ runtime·sched.mhead = m;
+ runtime·sched.mwait++;
}
// Get an `m' to run `g'. Sched must be locked.
@@ -218,20 +222,20 @@ mget(G *g)
return m;
// otherwise use general m pool.
- if((m = sched.mhead) != nil){
- sched.mhead = m->schedlink;
- sched.mwait--;
+ if((m = runtime·sched.mhead) != nil){
+ runtime·sched.mhead = m->schedlink;
+ runtime·sched.mwait--;
}
return m;
}
// Mark g ready to run.
void
-ready(G *g)
+runtime·ready(G *g)
{
- lock(&sched);
+ runtime·lock(&runtime·sched);
readylocked(g);
- unlock(&sched);
+ runtime·unlock(&runtime·sched);
}
// Mark g ready to run. Sched is already locked.
@@ -249,11 +253,11 @@ readylocked(G *g)
// Mark runnable.
if(g->status == Grunnable || g->status == Grunning || g->status == Grecovery)
- throw("bad g->status in ready");
+ runtime·throw("bad g->status in ready");
g->status = Grunnable;
gput(g);
- if(!sched.predawn)
+ if(!runtime·sched.predawn)
matchmg();
}
@@ -276,11 +280,11 @@ newprocreadylocked(G *g)
static void
mnextg(M *m, G *g)
{
- sched.mcpu++;
+ runtime·sched.mcpu++;
m->nextg = g;
if(m->waitnextg) {
m->waitnextg = 0;
- notewakeup(&m->havenextg);
+ runtime·notewakeup(&m->havenextg);
}
}
@@ -293,15 +297,15 @@ nextgandunlock(void)
{
G *gp;
- if(sched.mcpu < 0)
- throw("negative sched.mcpu");
+ if(runtime·sched.mcpu < 0)
+ runtime·throw("negative runtime·sched.mcpu");
// If there is a g waiting as m->nextg,
- // mnextg took care of the sched.mcpu++.
+ // mnextg took care of the runtime·sched.mcpu++.
if(m->nextg != nil) {
gp = m->nextg;
m->nextg = nil;
- unlock(&sched);
+ runtime·unlock(&runtime·sched);
return gp;
}
@@ -309,36 +313,36 @@ nextgandunlock(void)
// We can only run one g, and it's not available.
// Make sure some other cpu is running to handle
// the ordinary run queue.
- if(sched.gwait != 0)
+ if(runtime·sched.gwait != 0)
matchmg();
} else {
// Look for work on global queue.
- while(sched.mcpu < sched.mcpumax && (gp=gget()) != nil) {
+ while(runtime·sched.mcpu < runtime·sched.mcpumax && (gp=gget()) != nil) {
if(gp->lockedm) {
mnextg(gp->lockedm, gp);
continue;
}
- sched.mcpu++; // this m will run gp
- unlock(&sched);
+ runtime·sched.mcpu++; // this m will run gp
+ runtime·unlock(&runtime·sched);
return gp;
}
// Otherwise, wait on global m queue.
mput(m);
}
- if(sched.mcpu == 0 && sched.msyscall == 0)
- throw("all goroutines are asleep - deadlock!");
+ if(runtime·sched.mcpu == 0 && runtime·sched.msyscall == 0)
+ runtime·throw("all goroutines are asleep - deadlock!");
m->nextg = nil;
m->waitnextg = 1;
- noteclear(&m->havenextg);
- if(sched.waitstop && sched.mcpu <= sched.mcpumax) {
- sched.waitstop = 0;
- notewakeup(&sched.stopped);
+ runtime·noteclear(&m->havenextg);
+ if(runtime·sched.waitstop && runtime·sched.mcpu <= runtime·sched.mcpumax) {
+ runtime·sched.waitstop = 0;
+ runtime·notewakeup(&runtime·sched.stopped);
}
- unlock(&sched);
+ runtime·unlock(&runtime·sched);
- notesleep(&m->havenextg);
+ runtime·notesleep(&m->havenextg);
if((gp = m->nextg) == nil)
- throw("bad m->nextg in nextgoroutine");
+ runtime·throw("bad m->nextg in nextgoroutine");
m->nextg = nil;
return gp;
}
@@ -346,46 +350,46 @@ nextgandunlock(void)
// TODO(rsc): Remove. This is only temporary,
// for the mark and sweep collector.
void
-stoptheworld(void)
+runtime·stoptheworld(void)
{
- lock(&sched);
- gcwaiting = 1;
- sched.mcpumax = 1;
- while(sched.mcpu > 1) {
+ runtime·lock(&runtime·sched);
+ runtime·gcwaiting = 1;
+ runtime·sched.mcpumax = 1;
+ while(runtime·sched.mcpu > 1) {
// It would be unsafe for multiple threads to be using
// the stopped note at once, but there is only
// ever one thread doing garbage collection,
// so this is okay.
- noteclear(&sched.stopped);
- sched.waitstop = 1;
- unlock(&sched);
- notesleep(&sched.stopped);
- lock(&sched);
+ runtime·noteclear(&runtime·sched.stopped);
+ runtime·sched.waitstop = 1;
+ runtime·unlock(&runtime·sched);
+ runtime·notesleep(&runtime·sched.stopped);
+ runtime·lock(&runtime·sched);
}
- unlock(&sched);
+ runtime·unlock(&runtime·sched);
}
// TODO(rsc): Remove. This is only temporary,
// for the mark and sweep collector.
void
-starttheworld(void)
+runtime·starttheworld(void)
{
- lock(&sched);
- gcwaiting = 0;
- sched.mcpumax = sched.gomaxprocs;
+ runtime·lock(&runtime·sched);
+ runtime·gcwaiting = 0;
+ runtime·sched.mcpumax = runtime·sched.gomaxprocs;
matchmg();
- unlock(&sched);
+ runtime·unlock(&runtime·sched);
}
// Called to start an M.
void
-mstart(void)
+runtime·mstart(void)
{
if(g != m->g0)
- throw("bad mstart");
+ runtime·throw("bad runtime·mstart");
if(m->mcache == nil)
- m->mcache = allocmcache();
- minit();
+ m->mcache = runtime·allocmcache();
+ runtime·minit();
scheduler();
}
@@ -413,29 +417,36 @@ matchmg(void)
if(m->mallocing || m->gcing)
return;
- while(sched.mcpu < sched.mcpumax && (g = gget()) != nil){
+ while(runtime·sched.mcpu < runtime·sched.mcpumax && (g = gget()) != nil){
M *m;
// Find the m that will run g.
if((m = mget(g)) == nil){
- m = malloc(sizeof(M));
- // Add to allm so garbage collector doesn't free m
+ m = runtime·malloc(sizeof(M));
+ // Add to runtime·allm so garbage collector doesn't free m
// when it is just in a register (R14 on amd64).
- m->alllink = allm;
- allm = m;
- m->id = sched.mcount++;
+ m->alllink = runtime·allm;
+ runtime·allm = m;
+ m->id = runtime·sched.mcount++;
- if(libcgo_thread_start != nil) {
+ 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 = malg(-1);
+ m->g0 = runtime·malg(-1);
ts.m = m;
ts.g = m->g0;
- ts.fn = mstart;
- runcgo(libcgo_thread_start, &ts);
+ ts.fn = runtime·mstart;
+ runtime·runcgo(libcgo_thread_start, &ts);
} else {
- m->g0 = malg(8192);
- newosproc(m, m->g0, m->g0->stackbase, mstart);
+ 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);
@@ -448,8 +459,8 @@ scheduler(void)
{
G* gp;
- lock(&sched);
- if(gosave(&m->sched) != 0){
+ runtime·lock(&runtime·sched);
+ if(runtime·gosave(&m->sched) != 0){
gp = m->curg;
if(gp->status == Grecovery) {
// switched to scheduler to get stack unwound.
@@ -470,31 +481,31 @@ scheduler(void)
// each call to deferproc.
// (the pc we're returning to does pop pop
// before it tests the return value.)
- gp->sched.sp = getcallersp(d->sp - 2*sizeof(uintptr));
+ gp->sched.sp = runtime·getcallersp(d->sp - 2*sizeof(uintptr));
gp->sched.pc = d->pc;
gp->status = Grunning;
- free(d);
- gogo(&gp->sched, 1);
+ runtime·free(d);
+ runtime·gogo(&gp->sched, 1);
}
- // Jumped here via gosave/gogo, so didn't
- // execute lock(&sched) above.
- lock(&sched);
+ // Jumped here via runtime·gosave/gogo, so didn't
+ // execute lock(&runtime·sched) above.
+ runtime·lock(&runtime·sched);
- if(sched.predawn)
- throw("init sleeping");
+ if(runtime·sched.predawn)
+ runtime·throw("init sleeping");
// Just finished running gp.
gp->m = nil;
- sched.mcpu--;
+ runtime·sched.mcpu--;
- if(sched.mcpu < 0)
- throw("sched.mcpu < 0 in scheduler");
+ if(runtime·sched.mcpu < 0)
+ runtime·throw("runtime·sched.mcpu < 0 in scheduler");
switch(gp->status){
case Grunnable:
case Gdead:
// Shouldn't have been running!
- throw("bad gp->status in sched");
+ runtime·throw("bad gp->status in sched");
case Grunning:
gp->status = Grunnable;
gput(gp);
@@ -507,8 +518,8 @@ scheduler(void)
}
unwindstack(gp, nil);
gfput(gp);
- if(--sched.gcount == 0)
- exit(0);
+ if(--runtime·sched.gcount == 0)
+ runtime·exit(0);
break;
}
if(gp->readyonstop){
@@ -517,15 +528,16 @@ scheduler(void)
}
}
- // Find (or wait for) g to run. Unlocks sched.
+ // Find (or wait for) g to run. Unlocks runtime·sched.
gp = nextgandunlock();
gp->readyonstop = 0;
gp->status = Grunning;
m->curg = gp;
gp->m = m;
- if(gp->sched.pc == (byte*)goexit) // kickoff
- gogocall(&gp->sched, (void(*)(void))gp->entry);
- gogo(&gp->sched, 1);
+ if(gp->sched.pc == (byte*)runtime·goexit) { // kickoff
+ runtime·gogocall(&gp->sched, (void(*)(void))gp->entry);
+ }
+ runtime·gogo(&gp->sched, 1);
}
// Enter scheduler. If g->status is Grunning,
@@ -533,42 +545,45 @@ scheduler(void)
// before running g again. If g->status is Gmoribund,
// kills off g.
void
-gosched(void)
+runtime·gosched(void)
{
if(m->locks != 0)
- throw("gosched holding locks");
+ runtime·throw("gosched holding locks");
if(g == m->g0)
- throw("gosched of g0");
- if(gosave(&g->sched) == 0)
- gogo(&m->sched, 1);
+ runtime·throw("gosched of g0");
+ if(runtime·gosave(&g->sched) == 0)
+ runtime·gogo(&m->sched, 1);
}
// The goroutine g is about to enter a system call.
// Record that it's not using the cpu anymore.
// This is called only from the go syscall library and cgocall,
// not from the low-level system calls used by the runtime.
+// Entersyscall cannot split the stack: the runtime·gosave must
+// make g->sched refer to the caller's stack pointer.
+#pragma textflag 7
void
-·entersyscall(void)
+runtime·entersyscall(void)
{
- lock(&sched);
+ runtime·lock(&runtime·sched);
// Leave SP around for gc and traceback.
// Do before notewakeup so that gc
// never sees Gsyscall with wrong stack.
- gosave(&g->sched);
- if(sched.predawn) {
- unlock(&sched);
+ runtime·gosave(&g->sched);
+ if(runtime·sched.predawn) {
+ runtime·unlock(&runtime·sched);
return;
}
g->status = Gsyscall;
- sched.mcpu--;
- sched.msyscall++;
- if(sched.gwait != 0)
+ runtime·sched.mcpu--;
+ runtime·sched.msyscall++;
+ if(runtime·sched.gwait != 0)
matchmg();
- if(sched.waitstop && sched.mcpu <= sched.mcpumax) {
- sched.waitstop = 0;
- notewakeup(&sched.stopped);
+ if(runtime·sched.waitstop && runtime·sched.mcpu <= runtime·sched.mcpumax) {
+ runtime·sched.waitstop = 0;
+ runtime·notewakeup(&runtime·sched.stopped);
}
- unlock(&sched);
+ runtime·unlock(&runtime·sched);
}
// The goroutine g exited its system call.
@@ -576,19 +591,19 @@ void
// This is called only from the go syscall library, not
// from the low-level system calls used by the runtime.
void
-·exitsyscall(void)
+runtime·exitsyscall(void)
{
- lock(&sched);
- if(sched.predawn) {
- unlock(&sched);
+ runtime·lock(&runtime·sched);
+ if(runtime·sched.predawn) {
+ runtime·unlock(&runtime·sched);
return;
}
- sched.msyscall--;
- sched.mcpu++;
+ runtime·sched.msyscall--;
+ runtime·sched.mcpu++;
// Fast path - if there's room for this m, we're done.
- if(sched.mcpu <= sched.mcpumax) {
+ if(runtime·sched.mcpu <= runtime·sched.mcpumax) {
g->status = Grunning;
- unlock(&sched);
+ runtime·unlock(&runtime·sched);
return;
}
// Tell scheduler to put g back on the run queue:
@@ -596,35 +611,68 @@ void
// but keeps the garbage collector from thinking
// that g is running right now, which it's not.
g->readyonstop = 1;
- unlock(&sched);
+ runtime·unlock(&runtime·sched);
// Slow path - all the cpus are taken.
// The scheduler will ready g and put this m to sleep.
// When the scheduler takes g away from m,
- // it will undo the sched.mcpu++ above.
- gosched();
+ // it will undo the runtime·sched.mcpu++ above.
+ runtime·gosched();
+}
+
+// Restore the position of m's scheduler stack if we unwind the stack
+// through a cgo callback.
+static void
+runtime·unwindcgocallback(void **spaddr, void *sp)
+{
+ *spaddr = sp;
}
// Start scheduling g1 again for a cgo callback.
void
-startcgocallback(G* g1)
+runtime·startcgocallback(G* g1)
{
- lock(&sched);
+ Defer *d;
+ uintptr arg;
+
+ runtime·lock(&runtime·sched);
g1->status = Grunning;
- sched.msyscall--;
- sched.mcpu++;
- unlock(&sched);
+ runtime·sched.msyscall--;
+ runtime·sched.mcpu++;
+ runtime·unlock(&runtime·sched);
+
+ // Add an entry to the defer stack which restores the old
+ // position of m's scheduler stack. This is so that if the
+ // code we are calling panics, we won't lose the space on the
+ // scheduler stack. Note that we are locked to this m here.
+ d = runtime·malloc(sizeof(*d) + 2*sizeof(void*) - sizeof(d->args));
+ d->fn = (byte*)runtime·unwindcgocallback;
+ d->siz = 2 * sizeof(uintptr);
+ ((void**)d->args)[0] = &m->sched.sp;
+ ((void**)d->args)[1] = m->sched.sp;
+ d->link = g1->defer;
+ g1->defer = d;
}
// Stop scheduling g1 after a cgo callback.
void
-endcgocallback(G* g1)
+runtime·endcgocallback(G* g1)
{
- lock(&sched);
+ Defer *d;
+
+ runtime·lock(&runtime·sched);
g1->status = Gsyscall;
- sched.mcpu--;
- sched.msyscall++;
- unlock(&sched);
+ runtime·sched.mcpu--;
+ runtime·sched.msyscall++;
+ runtime·unlock(&runtime·sched);
+
+ // Remove the entry on the defer stack added by
+ // startcgocallback.
+ d = g1->defer;
+ if (d == nil || d->fn != (byte*)runtime·unwindcgocallback)
+ runtime·throw("bad defer entry in endcgocallback");
+ g1->defer = d->link;
+ runtime·free(d);
}
/*
@@ -697,7 +745,7 @@ enum
};
void
-oldstack(void)
+runtime·oldstack(void)
{
Stktop *top, old;
uint32 args;
@@ -714,20 +762,20 @@ oldstack(void)
args = old.args;
if(args > 0) {
sp -= args;
- mcpy(top->fp, sp, args);
+ runtime·mcpy(top->fp, sp, args);
}
goid = old.gobuf.g->goid; // fault if g is bad, before gogo
if(old.free)
- stackfree(g1->stackguard - StackGuard);
+ runtime·stackfree(g1->stackguard - StackGuard);
g1->stackbase = old.stackbase;
g1->stackguard = old.stackguard;
- gogo(&old.gobuf, m->cret);
+ runtime·gogo(&old.gobuf, m->cret);
}
void
-newstack(void)
+runtime·newstack(void)
{
int32 frame, args;
Stktop *top;
@@ -740,6 +788,8 @@ newstack(void)
args = m->moreargs;
g1 = m->curg;
+ if(m->morebuf.sp < g1->stackguard - StackGuard)
+ runtime·throw("split stack overflow");
if(frame == 1 && args > 0 && m->morebuf.sp - sizeof(Stktop) - args - 32 > g1->stackguard) {
// special case: called from reflect.call (frame == 1)
@@ -758,12 +808,13 @@ newstack(void)
if(frame < StackBig)
frame = StackBig;
frame += 1024; // room for more functions, Stktop.
- stk = stackalloc(frame);
+ stk = runtime·stackalloc(frame);
top = (Stktop*)(stk+frame-sizeof(*top));
free = true;
}
-//printf("newstack frame=%d args=%d morepc=%p morefp=%p gobuf=%p, %p newstk=%p\n", frame, args, m->morepc, m->morefp, g->sched.pc, g->sched.sp, stk);
+//printf("newstack frame=%d args=%d morepc=%p morefp=%p gobuf=%p, %p newstk=%p\n",
+//frame, args, m->morepc, m->morefp, g->sched.pc, g->sched.sp, stk);
top->stackbase = g1->stackbase;
top->stackguard = g1->stackguard;
@@ -782,32 +833,32 @@ newstack(void)
sp = (byte*)top;
if(args > 0) {
sp -= args;
- mcpy(sp, m->morefp, args);
+ runtime·mcpy(sp, m->morefp, args);
}
// Continue as if lessstack had just called m->morepc
// (the PC that decided to grow the stack).
label.sp = sp;
- label.pc = (byte*)·lessstack;
+ label.pc = (byte*)runtime·lessstack;
label.g = m->curg;
- gogocall(&label, m->morepc);
+ runtime·gogocall(&label, m->morepc);
*(int32*)345 = 123; // never return
}
G*
-malg(int32 stacksize)
+runtime·malg(int32 stacksize)
{
G *g;
byte *stk;
- g = malloc(sizeof(G));
+ g = runtime·malloc(sizeof(G));
if(stacksize >= 0) {
- stk = stackalloc(stacksize + StackGuard);
+ stk = runtime·stackalloc(stacksize + StackGuard);
g->stack0 = stk;
g->stackguard = stk + StackGuard;
g->stackbase = stk + StackGuard + stacksize - sizeof(Stktop);
- runtime_memclr(g->stackbase, sizeof(Stktop));
+ runtime·memclr(g->stackbase, sizeof(Stktop));
}
return g;
}
@@ -823,13 +874,13 @@ malg(int32 stacksize)
*/
#pragma textflag 7
void
-·newproc(int32 siz, byte* fn, ...)
+runtime·newproc(int32 siz, byte* fn, ...)
{
- newproc1(fn, (byte*)(&fn+1), siz, 0);
+ runtime·newproc1(fn, (byte*)(&fn+1), siz, 0);
}
G*
-newproc1(byte *fn, byte *argp, int32 narg, int32 nret)
+runtime·newproc1(byte *fn, byte *argp, int32 narg, int32 nret)
{
byte *sp;
G *newg;
@@ -839,36 +890,36 @@ newproc1(byte *fn, byte *argp, int32 narg, int32 nret)
siz = narg + nret;
siz = (siz+7) & ~7;
if(siz > 1024)
- throw("runtime.newproc: too many args");
+ runtime·throw("runtime.newproc: too many args");
- lock(&sched);
+ runtime·lock(&runtime·sched);
if((newg = gfget()) != nil){
newg->status = Gwaiting;
if(newg->stackguard - StackGuard != newg->stack0)
- throw("invalid stack in newg");
+ runtime·throw("invalid stack in newg");
} else {
- newg = malg(4096);
+ newg = runtime·malg(4096);
newg->status = Gwaiting;
- newg->alllink = allg;
- allg = newg;
+ newg->alllink = runtime·allg;
+ runtime·allg = newg;
}
sp = newg->stackbase;
sp -= siz;
- mcpy(sp, argp, narg);
+ runtime·mcpy(sp, argp, narg);
newg->sched.sp = sp;
- newg->sched.pc = (byte*)goexit;
+ newg->sched.pc = (byte*)runtime·goexit;
newg->sched.g = newg;
newg->entry = fn;
- sched.gcount++;
- goidgen++;
- newg->goid = goidgen;
+ runtime·sched.gcount++;
+ runtime·goidgen++;
+ newg->goid = runtime·goidgen;
newprocreadylocked(newg);
- unlock(&sched);
+ runtime·unlock(&runtime·sched);
return newg;
//printf(" goid=%d\n", newg->goid);
@@ -876,16 +927,16 @@ newproc1(byte *fn, byte *argp, int32 narg, int32 nret)
#pragma textflag 7
uintptr
-·deferproc(int32 siz, byte* fn, ...)
+runtime·deferproc(int32 siz, byte* fn, ...)
{
Defer *d;
- d = malloc(sizeof(*d) + siz - sizeof(d->args));
+ d = runtime·malloc(sizeof(*d) + siz - sizeof(d->args));
d->fn = fn;
d->sp = (byte*)(&fn+1);
d->siz = siz;
- d->pc = ·getcallerpc(&siz);
- mcpy(d->args, d->sp, d->siz);
+ d->pc = runtime·getcallerpc(&siz);
+ runtime·mcpy(d->args, d->sp, d->siz);
d->link = g->defer;
g->defer = d;
@@ -901,7 +952,7 @@ uintptr
#pragma textflag 7
void
-·deferreturn(uintptr arg0)
+runtime·deferreturn(uintptr arg0)
{
Defer *d;
byte *sp, *fn;
@@ -909,14 +960,14 @@ void
d = g->defer;
if(d == nil)
return;
- sp = getcallersp(&arg0);
+ sp = runtime·getcallersp(&arg0);
if(d->sp != sp)
return;
- mcpy(d->sp, d->args, d->siz);
+ runtime·mcpy(d->sp, d->args, d->siz);
g->defer = d->link;
fn = d->fn;
- free(d);
- jmpdefer(fn, sp);
+ runtime·free(d);
+ runtime·jmpdefer(fn, sp);
}
static void
@@ -927,7 +978,7 @@ rundefer(void)
while((d = g->defer) != nil) {
g->defer = d->link;
reflect·call(d->fn, d->args, d->siz);
- free(d);
+ runtime·free(d);
}
}
@@ -941,7 +992,7 @@ unwindstack(G *gp, byte *sp)
// Must be called from a different goroutine, usually m->g0.
if(g == gp)
- throw("unwindstack on self");
+ runtime·throw("unwindstack on self");
while((top = (Stktop*)gp->stackbase) != nil && top->stackbase != nil) {
stk = gp->stackguard - StackGuard;
@@ -949,12 +1000,13 @@ unwindstack(G *gp, byte *sp)
break;
gp->stackbase = top->stackbase;
gp->stackguard = top->stackguard;
- free(stk);
+ if(top->free)
+ runtime·stackfree(stk);
}
if(sp != nil && (sp < gp->stackguard - StackGuard || gp->stackbase < sp)) {
- printf("recover: %p not in [%p, %p]\n", sp, gp->stackguard - StackGuard, gp->stackbase);
- throw("bad unwindstack");
+ runtime·printf("recover: %p not in [%p, %p]\n", sp, gp->stackguard - StackGuard, gp->stackbase);
+ runtime·throw("bad unwindstack");
}
}
@@ -963,22 +1015,22 @@ printpanics(Panic *p)
{
if(p->link) {
printpanics(p->link);
- printf("\t");
+ runtime·printf("\t");
}
- printf("panic: ");
- ·printany(p->arg);
+ runtime·printf("panic: ");
+ runtime·printany(p->arg);
if(p->recovered)
- printf(" [recovered]");
- printf("\n");
+ runtime·printf(" [recovered]");
+ runtime·printf("\n");
}
void
-·panic(Eface e)
+runtime·panic(Eface e)
{
Defer *d;
Panic *p;
- p = mal(sizeof *p);
+ p = runtime·mal(sizeof *p);
p->arg = e;
p->link = g->panic;
p->stackbase = g->stackbase;
@@ -991,35 +1043,37 @@ void
// take defer off list in case of recursive panic
g->defer = d->link;
g->ispanic = true; // rock for newstack, where reflect.call ends up
- reflect·call(d->fn, d->args, d->siz);
+ if(thechar == '5')
+ reflect·call(d->fn, d->args+4, d->siz-4); // reflect.call does not expect LR
+ else
+ reflect·call(d->fn, d->args, d->siz);
if(p->recovered) {
g->panic = p->link;
- free(p);
+ runtime·free(p);
// put recovering defer back on list
// for scheduler to find.
d->link = g->defer;
g->defer = d;
g->status = Grecovery;
- gosched();
- throw("recovery failed"); // gosched should not return
+ runtime·gosched();
+ runtime·throw("recovery failed"); // gosched should not return
}
- free(d);
+ runtime·free(d);
}
// ran out of deferred calls - old-school panic now
- fd = 2;
printpanics(g->panic);
- panic(0);
+ runtime·dopanic(0);
}
#pragma textflag 7 /* no split, or else g->stackguard is not the stack for fp */
void
-·recover(byte *fp, Eface ret)
+runtime·recover(byte *fp, Eface ret)
{
Stktop *top, *oldtop;
Panic *p;
- fp = getcallersp(fp);
+ fp = runtime·getcallersp(fp);
// Must be a panic going on.
if((p = g->panic) == nil || p->recovered)
@@ -1090,9 +1144,9 @@ static void
gfput(G *g)
{
if(g->stackguard - StackGuard != g->stack0)
- throw("invalid stack in gfput");
- g->schedlink = sched.gfree;
- sched.gfree = g;
+ runtime·throw("invalid stack in gfput");
+ g->schedlink = runtime·sched.gfree;
+ runtime·sched.gfree = g;
}
// Get from gfree list. Sched must be locked.
@@ -1101,69 +1155,69 @@ gfget(void)
{
G *g;
- g = sched.gfree;
+ g = runtime·sched.gfree;
if(g)
- sched.gfree = g->schedlink;
+ runtime·sched.gfree = g->schedlink;
return g;
}
void
-·Breakpoint(void)
+runtime·Breakpoint(void)
{
- breakpoint();
+ runtime·breakpoint();
}
void
-·Goexit(void)
+runtime·Goexit(void)
{
rundefer();
- goexit();
+ runtime·goexit();
}
void
-·Gosched(void)
+runtime·Gosched(void)
{
- gosched();
+ runtime·gosched();
}
void
-·LockOSThread(void)
+runtime·LockOSThread(void)
{
- if(sched.predawn)
- throw("cannot wire during init");
+ if(runtime·sched.predawn)
+ runtime·throw("cannot wire during init");
m->lockedg = g;
g->lockedm = m;
}
// delete when scheduler is stronger
int32
-gomaxprocsfunc(int32 n)
+runtime·gomaxprocsfunc(int32 n)
{
int32 ret;
- lock(&sched);
- ret = sched.gomaxprocs;
+ runtime·lock(&runtime·sched);
+ ret = runtime·sched.gomaxprocs;
if (n <= 0)
n = ret;
- sched.gomaxprocs = n;
- sched.mcpumax = n;
+ runtime·sched.gomaxprocs = n;
+ runtime·sched.mcpumax = n;
// handle fewer procs?
- if(sched.mcpu > sched.mcpumax) {
- unlock(&sched);
+ if(runtime·sched.mcpu > runtime·sched.mcpumax) {
+ runtime·unlock(&runtime·sched);
// just give up the cpu.
// we'll only get rescheduled once the
// number has come down.
- gosched();
+ runtime·gosched();
return ret;
}
// handle more procs
matchmg();
- unlock(&sched);
+ runtime·unlock(&runtime·sched);
return ret;
}
void
-·UnlockOSThread(void)
+runtime·UnlockOSThread(void)
{
m->lockedg = nil;
g->lockedm = nil;
@@ -1171,8 +1225,15 @@ void
// for testing of wire, unwire
void
-·mid(uint32 ret)
+runtime·mid(uint32 ret)
{
ret = m->id;
FLUSH(&ret);
}
+
+void
+runtime·Goroutines(int32 ret)
+{
+ ret = runtime·sched.gcount;
+ FLUSH(&ret);
+}
diff --git a/src/pkg/runtime/reflect.goc b/src/pkg/runtime/reflect.goc
index 51222f1c4..a2e3c6ee1 100644
--- a/src/pkg/runtime/reflect.goc
+++ b/src/pkg/runtime/reflect.goc
@@ -24,11 +24,11 @@ gettype(void *typ)
*/
func mapaccess(map *byte, key *byte, val *byte) (pres bool) {
- mapaccess((Hmap*)map, key, val, &pres);
+ runtime·mapaccess((Hmap*)map, key, val, &pres);
}
func mapassign(map *byte, key *byte, val *byte) {
- mapassign((Hmap*)map, key, val);
+ runtime·mapassign((Hmap*)map, key, val);
}
func maplen(map *byte) (len int32) {
@@ -37,22 +37,22 @@ func maplen(map *byte) (len int32) {
}
func mapiterinit(map *byte) (it *byte) {
- it = (byte*)mapiterinit((Hmap*)map);
+ it = (byte*)runtime·newmapiterinit((Hmap*)map);
}
func mapiternext(it *byte) {
- mapiternext((struct hash_iter*)it);
+ runtime·mapiternext((struct hash_iter*)it);
}
func mapiterkey(it *byte, key *byte) (ok bool) {
- ok = mapiterkey((struct hash_iter*)it, key);
+ ok = runtime·mapiterkey((struct hash_iter*)it, key);
}
func makemap(typ *byte) (map *byte) {
MapType *t;
t = (MapType*)gettype(typ);
- map = (byte*)makemap(t->key, t->elem, 0);
+ map = (byte*)runtime·makemap_c(t->key, t->elem, 0);
}
/*
@@ -67,31 +67,31 @@ func makechan(typ *byte, size uint32) (ch *byte) {
// in front of the raw ChanType. the -2 below backs up
// to the interface value header.
t = (ChanType*)gettype(typ);
- ch = (byte*)makechan(t->elem, size);
+ ch = (byte*)runtime·makechan_c(t->elem, size);
}
func chansend(ch *byte, val *byte, pres *bool) {
- chansend((Hchan*)ch, val, pres);
+ runtime·chansend((Hchan*)ch, val, pres);
}
func chanrecv(ch *byte, val *byte, pres *bool) {
- chanrecv((Hchan*)ch, val, pres);
+ runtime·chanrecv((Hchan*)ch, val, pres);
}
func chanclose(ch *byte) {
- chanclose((Hchan*)ch);
+ runtime·chanclose((Hchan*)ch);
}
func chanclosed(ch *byte) (r bool) {
- r = chanclosed((Hchan*)ch);
+ r = runtime·chanclosed((Hchan*)ch);
}
func chanlen(ch *byte) (r int32) {
- r = chanlen((Hchan*)ch);
+ r = runtime·chanlen((Hchan*)ch);
}
func chancap(ch *byte) (r int32) {
- r = chancap((Hchan*)ch);
+ r = runtime·chancap((Hchan*)ch);
}
@@ -114,5 +114,5 @@ func setiface(typ *byte, x *byte, ret *byte) {
((Iface*)ret)->data = nil;
return;
}
- ifaceE2I((InterfaceType*)gettype(typ), *(Eface*)x, (Iface*)ret);
+ runtime·ifaceE2I((InterfaceType*)gettype(typ), *(Eface*)x, (Iface*)ret);
}
diff --git a/src/pkg/runtime/rune.c b/src/pkg/runtime/rune.c
index 598edc6f3..86ee76ddd 100644
--- a/src/pkg/runtime/rune.c
+++ b/src/pkg/runtime/rune.c
@@ -39,8 +39,7 @@ enum
Rune1 = (1<<(Bit1+0*Bitx))-1, /* 0000 0000 0111 1111 */
Rune2 = (1<<(Bit2+1*Bitx))-1, /* 0000 0111 1111 1111 */
Rune3 = (1<<(Bit3+2*Bitx))-1, /* 1111 1111 1111 1111 */
- Rune4 = (1<<(Bit4+3*Bitx))-1,
- /* 0001 1111 1111 1111 1111 1111 */
+ Rune4 = (1<<(Bit4+3*Bitx))-1, /* 0001 1111 1111 1111 1111 1111 */
Maskx = (1<<Bitx)-1, /* 0011 1111 */
Testx = Maskx ^ 0xFF, /* 1100 0000 */
@@ -72,7 +71,7 @@ enum
* reasons, we return 1 instead of 0.
*/
int32
-charntorune(int32 *rune, uint8 *str, int32 length)
+runtime·charntorune(int32 *rune, uint8 *str, int32 length)
{
int32 c, c1, c2, c3, l;
@@ -168,7 +167,7 @@ badlen:
}
int32
-runetochar(byte *str, int32 rune) /* note: in original, arg2 was pointer */
+runtime·runetochar(byte *str, int32 rune) /* note: in original, arg2 was pointer */
{
/* Runes are signed, so convert to unsigned for range check. */
uint32 c;
diff --git a/src/pkg/runtime/runtime-gdb.py b/src/pkg/runtime/runtime-gdb.py
new file mode 100644
index 000000000..a7ca94cdb
--- /dev/null
+++ b/src/pkg/runtime/runtime-gdb.py
@@ -0,0 +1,398 @@
+# Copyright 2010 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+"""GDB Pretty printers and convencience 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
+path to this file based on the path to the runtime package.
+"""
+
+# Known issues:
+# - pretty printing only works for the 'native' strings. E.g. 'type
+# foo string' will make foo a plain struct in the eyes of gdb,
+# circumventing the pretty print triggering.
+# -
+
+import sys, re
+
+print >>sys.stderr, "Loading Go Runtime support."
+
+# allow to manually reload while developing
+goobjfile = gdb.current_objfile() or gdb.objfiles()[0]
+goobjfile.pretty_printers = []
+
+#
+# Pretty Printers
+#
+
+class StringTypePrinter:
+ "Pretty print Go strings."
+
+ pattern = re.compile(r'^struct string$')
+
+ def __init__(self, val):
+ self.val = val
+
+ def display_hint(self):
+ return 'string'
+
+ def to_string(self):
+ return self.val['str']
+
+
+class SliceTypePrinter:
+ "Pretty print slices."
+
+ pattern = re.compile(r'^struct \[\]')
+
+ def __init__(self, val):
+ self.val = val
+
+ def display_hint(self):
+ return 'array'
+
+ def to_string(self):
+ return str(self.val.type)[6:] # skip 'struct '
+
+ def children(self):
+ ptr = self.val["array"]
+ for idx in range(self.val["len"]):
+ yield ('[%d]' % idx, (ptr + idx).dereference())
+
+
+class MapTypePrinter:
+ """Pretty print map[K]V types.
+
+ Map-typed go variables are really pointers. dereference them in gdb
+ to inspect their contents with this pretty printer.
+ """
+
+ pattern = re.compile(r'^struct hash<.*>$')
+
+ def __init__(self, val):
+ self.val = val
+
+ def display_hint(self):
+ return 'map'
+
+ def to_string(self):
+ return str(self.val.type)
+
+ def children(self):
+ stab = self.val['st']
+ i = 0
+ for v in self.traverse_hash(stab):
+ yield ("[%d]" % i, v['key'])
+ yield ("[%d]" % (i + 1), v['val'])
+ i += 2
+
+ def traverse_hash(self, stab):
+ ptr = stab['entry'].address
+ end = stab['end']
+ while ptr < end:
+ v = ptr.dereference()
+ ptr = ptr + 1
+ if v['hash'] == 0: continue
+ if v['hash'] & 63 == 63: # subtable
+ for v in self.traverse_hash(v['key'].cast(self.val['st'].type)):
+ yield v
+ else:
+ yield v
+
+
+class ChanTypePrinter:
+ """Pretty print chan[T] types.
+
+ Chan-typed go variables are really pointers. dereference them in gdb
+ to inspect their contents with this pretty printer.
+ """
+
+ pattern = re.compile(r'^struct hchan<.*>$')
+
+ def __init__(self, val):
+ self.val = val
+
+ def display_hint(self):
+ return 'array'
+
+ def to_string(self):
+ return str(self.val.type)
+
+ def children(self):
+ ptr = self.val['recvdataq']
+ for idx in range(self.val["qcount"]):
+ yield ('[%d]' % idx, ptr['elem'])
+ ptr = ptr['link']
+
+#
+# Register all the *Printer classes above.
+#
+
+def makematcher(klass):
+ def matcher(val):
+ try:
+ if klass.pattern.match(str(val.type)):
+ return klass(val)
+ except:
+ pass
+ return matcher
+
+goobjfile.pretty_printers.extend([makematcher(k) for k in vars().values() if hasattr(k, 'pattern')])
+
+#
+# For reference, this is what we're trying to do:
+# eface: p *(*(struct 'runtime.commonType'*)'main.e'->type_->data)->string
+# iface: p *(*(struct 'runtime.commonType'*)'main.s'->tab->Type->data)->string
+#
+# interface types can't be recognized by their name, instead we check
+# if they have the expected fields. Unfortunately the mapping of
+# fields to python attributes in gdb.py isn't complete: you can't test
+# for presence other than by trapping.
+
+
+def is_iface(val):
+ try:
+ return str(val['tab'].type) == "struct runtime.itab *" \
+ and str(val['data'].type) == "void *"
+ except:
+ pass
+
+def is_eface(val):
+ try:
+ return str(val['type_'].type) == "runtime.Type *" \
+ and str(val['data'].type) == "void *"
+ except:
+ pass
+
+def lookup_type(name):
+ try:
+ return gdb.lookup_type(name)
+ except:
+ pass
+ try:
+ return gdb.lookup_type('struct ' + name)
+ except:
+ pass
+ try:
+ return gdb.lookup_type('struct ' + name[1:]).pointer()
+ except:
+ pass
+
+
+def iface_dtype(obj):
+ "Decode type of the data field of an eface or iface struct."
+
+ if is_iface(obj):
+ go_type_ptr = obj['tab']['Type']
+ elif is_eface(obj):
+ go_type_ptr = obj['type_']
+ else:
+ return
+
+ ct = gdb.lookup_type("struct runtime.commonType").pointer()
+ dynamic_go_type = go_type_ptr['data'].cast(ct).dereference()
+ 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 type_size > uintptr_size:
+ dynamic_gdb_type = dynamic_gdb_type.pointer()
+ return dynamic_gdb_type
+
+
+class IfacePrinter:
+ """Pretty print interface values
+
+ Casts the data field to the appropriate dynamic type."""
+
+ def __init__(self, val):
+ self.val = val
+
+ def display_hint(self):
+ return 'string'
+
+ def to_string(self):
+ try:
+ dtype = iface_dtype(self.val)
+ except:
+ return "<bad dynamic type>"
+ try:
+ return self.val['data'].cast(dtype).dereference()
+ except:
+ pass
+ return self.val['data'].cast(dtype)
+
+
+def ifacematcher(val):
+ if is_iface(val) or is_eface(val):
+ return IfacePrinter(val)
+
+goobjfile.pretty_printers.append(ifacematcher)
+
+#
+# Convenience Functions
+#
+
+class GoLenFunc(gdb.Function):
+ "Length of strings, slices, maps or channels"
+
+ how = ((StringTypePrinter, 'len' ),
+ (SliceTypePrinter, 'len'),
+ (MapTypePrinter, 'count'),
+ (ChanTypePrinter, 'qcount'))
+
+ def __init__(self):
+ super(GoLenFunc, self).__init__("len")
+
+ def invoke(self, obj):
+ typename = str(obj.type)
+ for klass, fld in self.how:
+ if klass.pattern.match(typename):
+ return obj[fld]
+
+class GoCapFunc(gdb.Function):
+ "Capacity of slices or channels"
+
+ how = ((SliceTypePrinter, 'cap'),
+ (ChanTypePrinter, 'dataqsiz'))
+
+ def __init__(self):
+ super(GoCapFunc, self).__init__("cap")
+
+ def invoke(self, obj):
+ typename = str(obj.type)
+ for klass, fld in self.how:
+ if klass.pattern.match(typename):
+ return obj[fld]
+
+class DTypeFunc(gdb.Function):
+ """Cast Interface values to their dynamic type.
+
+ For non-interface types this behaves as the identity operation.
+ """
+
+ def __init__(self):
+ super(DTypeFunc, self).__init__("dtype")
+
+ def invoke(self, obj):
+ try:
+ return obj['data'].cast(iface_dtype(obj))
+ except:
+ pass
+ return obj
+
+#
+# Commands
+#
+
+sts = ( 'idle', 'runnable', 'running', 'syscall', 'waiting', 'moribund', 'dead', 'recovery')
+
+def linked_list(ptr, linkfield):
+ while ptr:
+ yield ptr
+ ptr = ptr[linkfield]
+
+
+class GoroutinesCmd(gdb.Command):
+ "List all goroutines."
+
+ def __init__(self):
+ super(GoroutinesCmd, self).__init__("info goroutines", gdb.COMMAND_STACK, gdb.COMPLETE_NONE)
+
+ def invoke(self, arg, from_tty):
+ # args = gdb.string_to_argv(arg)
+ vp = gdb.lookup_type('void').pointer()
+ for ptr in linked_list(gdb.parse_and_eval("'runtime.allg'"), 'alllink'):
+ if ptr['status'] == 6: # 'gdead'
+ continue
+ m = ptr['m']
+ s = ' '
+ if m:
+ pc = m['sched']['pc'].cast(vp)
+ sp = m['sched']['sp'].cast(vp)
+ s = '*'
+ else:
+ 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
+
+def find_goroutine(goid):
+ vp = gdb.lookup_type('void').pointer()
+ for ptr in linked_list(gdb.parse_and_eval("'runtime.allg'"), 'alllink'):
+ if ptr['status'] == 6: # 'gdead'
+ continue
+ if ptr['goid'] == goid:
+ return [(ptr['m'] or ptr)['sched'][x].cast(vp) for x in 'pc', 'sp']
+ return None, None
+
+
+class GoroutineCmd(gdb.Command):
+ """Execute gdb command in the context of goroutine <goid>.
+
+ Switch PC and SP to the ones in the goroutine's G structure,
+ execute an arbitrary gdb command, and restore PC and SP.
+
+ Usage: (gdb) goroutine <goid> <gdbcmd>
+
+ Note that it is ill-defined to modify state in the context of a goroutine.
+ Restrict yourself to inspecting values.
+ """
+
+ def __init__(self):
+ super(GoroutineCmd, self).__init__("goroutine", gdb.COMMAND_STACK, gdb.COMPLETE_NONE)
+
+ def invoke(self, arg, from_tty):
+ goid, cmd = arg.split(None, 1)
+ pc, sp = find_goroutine(int(goid))
+ if not pc:
+ print "No such goroutine: ", goid
+ return
+ save_frame = gdb.selected_frame()
+ gdb.parse_and_eval('$save_pc = $pc')
+ gdb.parse_and_eval('$save_sp = $sp')
+ gdb.parse_and_eval('$pc = 0x%x' % long(pc))
+ gdb.parse_and_eval('$sp = 0x%x' % long(sp))
+ try:
+ gdb.execute(cmd)
+ finally:
+ gdb.parse_and_eval('$pc = $save_pc')
+ gdb.parse_and_eval('$sp = $save_sp')
+ save_frame.select()
+
+
+class GoIfaceCmd(gdb.Command):
+ "Print Static and dynamic interface types"
+
+ def __init__(self):
+ super(GoIfaceCmd, self).__init__("iface", gdb.COMMAND_DATA, gdb.COMPLETE_SYMBOL)
+
+ def invoke(self, arg, from_tty):
+ for obj in gdb.string_to_argv(arg):
+ try:
+ #TODO fix quoting for qualified variable names
+ obj = gdb.parse_and_eval("%s" % obj)
+ except Exception, e:
+ print "Can't parse ", obj, ": ", e
+ continue
+
+ dtype = iface_dtype(obj)
+ if not dtype:
+ print "Not an interface: ", obj.type
+ continue
+
+ print "%s: %s" % (obj.type, dtype)
+
+# TODO: print interface's methods and dynamic type's func pointers thereof.
+#rsc: "to find the number of entries in the itab's Fn field look at itab.inter->numMethods
+#i am sure i have the names wrong but look at the interface type and its method count"
+# so Itype will start with a commontype which has kind = interface
+
+#
+# Register all convience functions and CLI commands
+#
+for k in vars().values():
+ if hasattr(k, 'invoke'):
+ k()
diff --git a/src/pkg/runtime/runtime.c b/src/pkg/runtime/runtime.c
index 25a6f26bd..9d3efe966 100644
--- a/src/pkg/runtime/runtime.c
+++ b/src/pkg/runtime/runtime.c
@@ -4,87 +4,87 @@
#include "runtime.h"
-int32 panicking = 0;
-int32 maxround = sizeof(uintptr);
-int32 fd = 1;
+enum {
+ maxround = sizeof(uintptr),
+};
+
+int32 runtime·panicking = 0;
int32
-gotraceback(void)
+runtime·gotraceback(void)
{
byte *p;
- p = getenv("GOTRACEBACK");
+ p = runtime·getenv("GOTRACEBACK");
if(p == nil || p[0] == '\0')
return 1; // default is on
- return atoi(p);
+ return runtime·atoi(p);
}
void
-panic(int32 unused)
+runtime·dopanic(int32 unused)
{
- fd = 2;
- if(panicking) {
- printf("double panic\n");
- exit(3);
+ if(runtime·panicking) {
+ runtime·printf("double panic\n");
+ runtime·exit(3);
}
- panicking++;
+ runtime·panicking++;
- printf("\npanic PC=%X\n", (uint64)(uintptr)&unused);
- if(gotraceback()){
- traceback(·getcallerpc(&unused), getcallersp(&unused), 0, g);
- tracebackothers(g);
+ runtime·printf("\npanic PC=%X\n", (uint64)(uintptr)&unused);
+ if(runtime·gotraceback()){
+ runtime·traceback(runtime·getcallerpc(&unused), runtime·getcallersp(&unused), 0, g);
+ runtime·tracebackothers(g);
}
- breakpoint(); // so we can grab it in a debugger
- exit(2);
+ runtime·breakpoint(); // so we can grab it in a debugger
+ runtime·exit(2);
}
void
-·panicindex(void)
+runtime·panicindex(void)
{
- panicstring("index out of range");
+ runtime·panicstring("index out of range");
}
void
-·panicslice(void)
+runtime·panicslice(void)
{
- panicstring("slice bounds out of range");
+ runtime·panicstring("slice bounds out of range");
}
void
-·throwreturn(void)
+runtime·throwreturn(void)
{
// can only happen if compiler is broken
- throw("no return at end of a typed function - compiler is broken");
+ runtime·throw("no return at end of a typed function - compiler is broken");
}
void
-·throwinit(void)
+runtime·throwinit(void)
{
// can only happen with linker skew
- throw("recursive call during initialization - linker skew");
+ runtime·throw("recursive call during initialization - linker skew");
}
void
-throw(int8 *s)
+runtime·throw(int8 *s)
{
- fd = 2;
- printf("throw: %s\n", s);
- panic(-1);
+ runtime·printf("throw: %s\n", s);
+ runtime·dopanic(0);
*(int32*)0 = 0; // not reached
- exit(1); // even more not reached
+ runtime·exit(1); // even more not reached
}
void
-panicstring(int8 *s)
+runtime·panicstring(int8 *s)
{
Eface err;
- ·newErrorString(gostringnocopy((byte*)s), &err);
- ·panic(err);
+ runtime·newErrorString(runtime·gostringnocopy((byte*)s), &err);
+ runtime·panic(err);
}
void
-mcpy(byte *t, byte *f, uint32 n)
+runtime·mcpy(byte *t, byte *f, uint32 n)
{
while(n > 0) {
*t = *f;
@@ -95,7 +95,7 @@ mcpy(byte *t, byte *f, uint32 n)
}
int32
-mcmp(byte *s1, byte *s2, uint32 n)
+runtime·mcmp(byte *s1, byte *s2, uint32 n)
{
uint32 i;
byte c1, c2;
@@ -113,7 +113,7 @@ mcmp(byte *s1, byte *s2, uint32 n)
byte*
-mchr(byte *p, byte c, byte *ep)
+runtime·mchr(byte *p, byte c, byte *ep)
{
for(; p < ep; p++)
if(*p == c)
@@ -122,7 +122,7 @@ mchr(byte *p, byte c, byte *ep)
}
uint32
-rnd(uint32 n, uint32 m)
+runtime·rnd(uint32 n, uint32 m)
{
uint32 r;
@@ -141,54 +141,65 @@ Slice os·Args;
Slice os·Envs;
void
-args(int32 c, uint8 **v)
+runtime·args(int32 c, uint8 **v)
{
argc = c;
argv = v;
}
+int32 runtime·isplan9;
+
void
-goargs(void)
+runtime·goargs(void)
{
- String *gargv;
- String *genvv;
- int32 i, envc;
-
- for(envc=0; argv[argc+1+envc] != 0; envc++)
- ;
-
- gargv = malloc(argc*sizeof gargv[0]);
- genvv = malloc(envc*sizeof genvv[0]);
+ String *s;
+ int32 i;
+
+ // for windows implementation see "os" package
+ if(Windows)
+ return;
+ s = runtime·malloc(argc*sizeof s[0]);
for(i=0; i<argc; i++)
- gargv[i] = gostringnocopy(argv[i]);
- os·Args.array = (byte*)gargv;
+ s[i] = runtime·gostringnocopy(argv[i]);
+ os·Args.array = (byte*)s;
os·Args.len = argc;
os·Args.cap = argc;
+}
- for(i=0; i<envc; i++)
- genvv[i] = gostringnocopy(argv[argc+1+i]);
- os·Envs.array = (byte*)genvv;
- os·Envs.len = envc;
- os·Envs.cap = envc;
+void
+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;
}
// Atomic add and return new value.
uint32
-xadd(uint32 volatile *val, int32 delta)
+runtime·xadd(uint32 volatile *val, int32 delta)
{
uint32 oval, nval;
for(;;){
oval = *val;
nval = oval + delta;
- if(cas(val, oval, nval))
+ if(runtime·cas(val, oval, nval))
return nval;
}
}
byte*
-getenv(int8 *s)
+runtime·getenv(int8 *s)
{
int32 i, j, len;
byte *v, *bs;
@@ -196,7 +207,7 @@ getenv(int8 *s)
int32 envc;
bs = (byte*)s;
- len = findnull(bs);
+ len = runtime·findnull(bs);
envv = (String*)os·Envs.array;
envc = os·Envs.len;
for(i=0; i<envc; i++){
@@ -215,17 +226,17 @@ getenv(int8 *s)
}
void
-·getgoroot(String out)
+runtime·getgoroot(String out)
{
byte *p;
- p = getenv("GOROOT");
- out = gostringnocopy(p);
+ p = runtime·getenv("GOROOT");
+ out = runtime·gostringnocopy(p);
FLUSH(&out);
}
int32
-atoi(byte *p)
+runtime·atoi(byte *p)
{
int32 n;
@@ -236,7 +247,7 @@ atoi(byte *p)
}
void
-check(void)
+runtime·check(void)
{
int8 a;
uint8 b;
@@ -250,35 +261,44 @@ check(void)
float64 j;
void* k;
uint16* l;
-
- if(sizeof(a) != 1) throw("bad a");
- if(sizeof(b) != 1) throw("bad b");
- if(sizeof(c) != 2) throw("bad c");
- if(sizeof(d) != 2) throw("bad d");
- if(sizeof(e) != 4) throw("bad e");
- if(sizeof(f) != 4) throw("bad f");
- if(sizeof(g) != 8) throw("bad g");
- if(sizeof(h) != 8) throw("bad h");
- if(sizeof(i) != 4) throw("bad i");
- if(sizeof(j) != 8) throw("bad j");
- if(sizeof(k) != sizeof(uintptr)) throw("bad k");
- if(sizeof(l) != sizeof(uintptr)) throw("bad l");
-// prints(1"check ok\n");
+ struct x1 {
+ byte x;
+ };
+ struct y1 {
+ struct x1 x1;
+ byte y;
+ };
+
+ if(sizeof(a) != 1) runtime·throw("bad a");
+ if(sizeof(b) != 1) runtime·throw("bad b");
+ if(sizeof(c) != 2) runtime·throw("bad c");
+ if(sizeof(d) != 2) runtime·throw("bad d");
+ if(sizeof(e) != 4) runtime·throw("bad e");
+ if(sizeof(f) != 4) runtime·throw("bad f");
+ if(sizeof(g) != 8) runtime·throw("bad g");
+ if(sizeof(h) != 8) runtime·throw("bad h");
+ if(sizeof(i) != 4) runtime·throw("bad i");
+ if(sizeof(j) != 8) runtime·throw("bad j");
+ if(sizeof(k) != sizeof(uintptr)) runtime·throw("bad k");
+ if(sizeof(l) != sizeof(uintptr)) runtime·throw("bad l");
+ if(sizeof(struct x1) != 1) runtime·throw("bad sizeof x1");
+ if(offsetof(struct y1, y) != 1) runtime·throw("bad offsetof y1.y");
+ if(sizeof(struct y1) != 2) runtime·throw("bad sizeof y1");
uint32 z;
z = 1;
- if(!cas(&z, 1, 2))
- throw("cas1");
+ if(!runtime·cas(&z, 1, 2))
+ runtime·throw("cas1");
if(z != 2)
- throw("cas2");
+ runtime·throw("cas2");
z = 4;
- if(cas(&z, 5, 6))
- throw("cas3");
+ if(runtime·cas(&z, 5, 6))
+ runtime·throw("cas3");
if(z != 4)
- throw("cas4");
+ runtime·throw("cas4");
- initsig(0);
+ runtime·initsig(0);
}
/*
@@ -310,14 +330,19 @@ memhash(uint32 s, void *a)
static uint32
memequal(uint32 s, void *a, void *b)
{
- byte *ba, *bb;
- uint32 i;
+ byte *ba, *bb, *aend;
+ if(a == b)
+ return 1;
ba = a;
bb = b;
- for(i=0; i<s; i++)
- if(ba[i] != bb[i])
+ aend = ba+s;
+ while(ba != aend) {
+ if(*ba != *bb)
return 0;
+ ba++;
+ bb++;
+ }
return 1;
}
@@ -341,7 +366,7 @@ memprint(uint32 s, void *a)
v = *(uint64*)a;
break;
}
- ·printint(v);
+ runtime·printint(v);
}
static void
@@ -361,6 +386,24 @@ memcopy(uint32 s, void *a, void *b)
ba[i] = bb[i];
}
+static uint32
+memwordequal(uint32 s, void *a, void *b)
+{
+ USED(s);
+ return *(uintptr*)(a) == *(uintptr*)(b);
+}
+
+static void
+memwordcopy(uint32 s, void *a, void *b)
+{
+ USED(s);
+ if (b == nil) {
+ *(uintptr*)(a) = 0;
+ return;
+ }
+ *(uintptr*)(a) = *(uintptr*)(b);
+}
+
static uintptr
strhash(uint32 s, String *a)
{
@@ -371,119 +414,118 @@ strhash(uint32 s, String *a)
static uint32
strequal(uint32 s, String *a, String *b)
{
+ int32 alen;
+
USED(s);
- return cmpstring(*a, *b) == 0;
+ 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);
- ·printstring(*a);
+ runtime·printstring(*a);
}
static uintptr
interhash(uint32 s, Iface *a)
{
USED(s);
- return ifacehash(*a);
+ return runtime·ifacehash(*a);
}
static void
interprint(uint32 s, Iface *a)
{
USED(s);
- ·printiface(*a);
+ runtime·printiface(*a);
}
static uint32
interequal(uint32 s, Iface *a, Iface *b)
{
USED(s);
- return ifaceeq(*a, *b);
+ return runtime·ifaceeq_c(*a, *b);
}
static uintptr
nilinterhash(uint32 s, Eface *a)
{
USED(s);
- return efacehash(*a);
+ return runtime·efacehash(*a);
}
static void
nilinterprint(uint32 s, Eface *a)
{
USED(s);
- ·printeface(*a);
+ runtime·printeface(*a);
}
static uint32
nilinterequal(uint32 s, Eface *a, Eface *b)
{
USED(s);
- return efaceeq(*a, *b);
+ return runtime·efaceeq_c(*a, *b);
}
uintptr
-nohash(uint32 s, void *a)
+runtime·nohash(uint32 s, void *a)
{
USED(s);
USED(a);
- panicstring("hash of unhashable type");
+ runtime·panicstring("hash of unhashable type");
return 0;
}
uint32
-noequal(uint32 s, void *a, void *b)
+runtime·noequal(uint32 s, void *a, void *b)
{
USED(s);
USED(a);
USED(b);
- panicstring("comparing uncomparable types");
+ runtime·panicstring("comparing uncomparable types");
return 0;
}
Alg
-algarray[] =
+runtime·algarray[] =
{
[AMEM] { memhash, memequal, memprint, memcopy },
-[ANOEQ] { nohash, noequal, memprint, memcopy },
+[ANOEQ] { runtime·nohash, runtime·noequal, memprint, memcopy },
[ASTRING] { strhash, strequal, strprint, memcopy },
[AINTER] { interhash, interequal, interprint, memcopy },
[ANILINTER] { nilinterhash, nilinterequal, nilinterprint, memcopy },
+[AMEMWORD] { memhash, memwordequal, memprint, memwordcopy },
};
-#pragma textflag 7
-void
-FLUSH(void *v)
-{
- USED(v);
-}
-
int64
-nanotime(void)
+runtime·nanotime(void)
{
int64 sec;
int32 usec;
sec = 0;
usec = 0;
- gettime(&sec, &usec);
+ runtime·gettime(&sec, &usec);
return sec*1000000000 + (int64)usec*1000;
}
void
-·Caller(int32 skip, uintptr retpc, String retfile, int32 retline, bool retbool)
+runtime·Caller(int32 skip, uintptr retpc, String retfile, int32 retline, bool retbool)
{
Func *f;
- if(callers(1+skip, &retpc, 1) == 0 || (f = findfunc(retpc-1)) == nil) {
- retfile = emptystring;
+ if(runtime·callers(1+skip, &retpc, 1) == 0 || (f = runtime·findfunc(retpc-1)) == nil) {
+ retfile = runtime·emptystring;
retline = 0;
retbool = false;
} else {
retfile = f->src;
- retline = funcline(f, retpc-1);
+ retline = runtime·funcline(f, retpc-1);
retbool = true;
}
FLUSH(&retfile);
@@ -492,15 +534,15 @@ void
}
void
-·Callers(int32 skip, Slice pc, int32 retn)
+runtime·Callers(int32 skip, Slice pc, int32 retn)
{
- retn = callers(skip, (uintptr*)pc.array, pc.len);
+ retn = runtime·callers(skip, (uintptr*)pc.array, pc.len);
FLUSH(&retn);
}
void
-·FuncForPC(uintptr pc, void *retf)
+runtime·FuncForPC(uintptr pc, void *retf)
{
- retf = findfunc(pc);
+ retf = runtime·findfunc(pc);
FLUSH(&retf);
}
diff --git a/src/pkg/runtime/runtime.h b/src/pkg/runtime/runtime.h
index a774d96d5..bde62833e 100644
--- a/src/pkg/runtime/runtime.h
+++ b/src/pkg/runtime/runtime.h
@@ -76,7 +76,7 @@ typedef struct Complex128 Complex128;
* segment register.
*
* amd64: allocated downwards from R15
- * x86: allocated upwards from 0(FS)
+ * x86: allocated upwards from 0(GS)
* arm: allocated downwards from R10
*
* every C file linked into a Go program must include runtime.h
@@ -230,11 +230,11 @@ struct M
uint32 machport; // Return address for Mach IPC (OS X)
MCache *mcache;
G* lockedg;
- uint64 freg[8]; // Floating point register storage used by ARM software fp routines
+ 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__
- void* return_address; // saved return address and stack
- void* stack_pointer; // pointer for Windows stdcall
- void* os_stack_pointer;
+ void* gostack; // bookmark to keep track of go stack during stdcall
#endif
};
struct Stktop
@@ -289,6 +289,16 @@ struct Func
int32 locals; // number of 32-bit locals
};
+#ifdef __WINDOWS__
+enum {
+ Windows = 1
+};
+#else
+enum {
+ Windows = 0
+};
+#endif
+
/*
* defined macros
* you need super-goru privilege
@@ -296,6 +306,7 @@ struct Func
*/
#define nelem(x) (sizeof(x)/sizeof((x)[0]))
#define nil ((void*)0)
+#define offsetof(s,m) (uint32)(&(((s*)0)->m))
/*
* known to compiler
@@ -307,6 +318,7 @@ enum
ASTRING,
AINTER,
ANILINTER,
+ AMEMWORD,
Amax
};
@@ -342,110 +354,110 @@ struct Panic
/*
* external data
*/
-extern Alg algarray[Amax];
-extern String emptystring;
-G* allg;
-M* allm;
-int32 goidgen;
-extern int32 gomaxprocs;
-extern int32 panicking;
-extern int32 maxround;
-extern int32 fd; // usually 1; set to 2 when panicking
-extern int32 gcwaiting; // gc is waiting to run
-int8* goos;
+extern Alg runtime·algarray[Amax];
+extern String runtime·emptystring;
+G* runtime·allg;
+M* runtime·allm;
+int32 runtime·goidgen;
+extern int32 runtime·gomaxprocs;
+extern int32 runtime·panicking;
+extern int32 runtime·gcwaiting; // gc is waiting to run
+int8* runtime·goos;
+extern bool runtime·iscgo;
/*
* common functions and data
*/
-int32 strcmp(byte*, byte*);
-int32 findnull(byte*);
-int32 findnullw(uint16*);
-void dump(byte*, int32);
-int32 runetochar(byte*, int32);
-int32 charntorune(int32*, uint8*, int32);
+int32 runtime·strcmp(byte*, byte*);
+int32 runtime·findnull(byte*);
+int32 runtime·findnullw(uint16*);
+void runtime·dump(byte*, int32);
+int32 runtime·runetochar(byte*, int32);
+int32 runtime·charntorune(int32*, uint8*, int32);
/*
* very low level c-called
*/
-void gogo(Gobuf*, uintptr);
-void gogocall(Gobuf*, void(*)(void));
-uintptr gosave(Gobuf*);
-void ·lessstack(void);
-void goargs(void);
-void FLUSH(void*);
-void* getu(void);
-void throw(int8*);
-void panicstring(int8*);
-uint32 rnd(uint32, uint32);
-void prints(int8*);
-void printf(int8*, ...);
-byte* mchr(byte*, byte, byte*);
-void mcpy(byte*, byte*, uint32);
-int32 mcmp(byte*, byte*, uint32);
-void memmove(void*, void*, uint32);
-void* mal(uintptr);
-uint32 cmpstring(String, String);
-String catstring(String, String);
-String gostring(byte*);
-String gostringnocopy(byte*);
-String gostringw(uint16*);
-void initsig(int32);
-int32 gotraceback(void);
-void traceback(uint8 *pc, uint8 *sp, uint8 *lr, G* gp);
-void tracebackothers(G*);
-int32 open(byte*, int32, ...);
-int32 write(int32, void*, int32);
-bool cas(uint32*, uint32, uint32);
-bool casp(void**, void*, void*);
-uint32 xadd(uint32 volatile*, int32);
-void jmpdefer(byte*, void*);
-void exit1(int32);
-void ready(G*);
-byte* getenv(int8*);
-int32 atoi(byte*);
-void newosproc(M *m, G *g, void *stk, void (*fn)(void));
-void signalstack(byte*, int32);
-G* malg(int32);
-void minit(void);
-Func* findfunc(uintptr);
-int32 funcline(Func*, uint64);
-void* stackalloc(uint32);
-void stackfree(void*);
-MCache* allocmcache(void);
-void mallocinit(void);
-bool ifaceeq(Iface, Iface);
-bool efaceeq(Eface, Eface);
-uintptr ifacehash(Iface);
-uintptr efacehash(Eface);
-uintptr nohash(uint32, void*);
-uint32 noequal(uint32, void*, void*);
-void* malloc(uintptr size);
-void free(void *v);
-void addfinalizer(void*, void(*fn)(void*), int32);
-void walkfintab(void (*fn)(void*));
-void runpanic(Panic*);
-void* getcallersp(void*);
-
-void exit(int32);
-void breakpoint(void);
-void gosched(void);
-void goexit(void);
-void runcgo(void (*fn)(void*), void*);
-void runcgocallback(G*, void*, void (*fn)());
-void ·entersyscall(void);
-void ·exitsyscall(void);
-void startcgocallback(G*);
-void endcgocallback(G*);
-G* newproc1(byte*, byte*, int32, int32);
-void siginit(void);
-bool sigsend(int32 sig);
-void gettime(int64*, int32*);
-int32 callers(int32, uintptr*, int32);
-int64 nanotime(void);
-void panic(int32);
-
-#pragma varargck argpos printf 1
-
+#define FLUSH(x) USED(x)
+
+void runtime·gogo(Gobuf*, uintptr);
+void runtime·gogocall(Gobuf*, void(*)(void));
+uintptr runtime·gosave(Gobuf*);
+void runtime·lessstack(void);
+void runtime·goargs(void);
+void runtime·goenvs(void);
+void runtime·goenvs_unix(void);
+void* runtime·getu(void);
+void runtime·throw(int8*);
+void runtime·panicstring(int8*);
+uint32 runtime·rnd(uint32, uint32);
+void runtime·prints(int8*);
+void runtime·printf(int8*, ...);
+byte* runtime·mchr(byte*, byte, byte*);
+void runtime·mcpy(byte*, byte*, uint32);
+int32 runtime·mcmp(byte*, byte*, uint32);
+void runtime·memmove(void*, void*, uint32);
+void* runtime·mal(uintptr);
+String runtime·catstring(String, String);
+String runtime·gostring(byte*);
+String runtime·gostringn(byte*, int32);
+String runtime·gostringnocopy(byte*);
+String runtime·gostringw(uint16*);
+void runtime·initsig(int32);
+int32 runtime·gotraceback(void);
+void runtime·traceback(uint8 *pc, uint8 *sp, uint8 *lr, G* gp);
+void runtime·tracebackothers(G*);
+int32 runtime·write(int32, void*, int32);
+bool runtime·cas(uint32*, uint32, uint32);
+bool runtime·casp(void**, void*, void*);
+uint32 runtime·xadd(uint32 volatile*, int32);
+void runtime·jmpdefer(byte*, void*);
+void runtime·exit1(int32);
+void runtime·ready(G*);
+byte* runtime·getenv(int8*);
+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·minit(void);
+Func* runtime·findfunc(uintptr);
+int32 runtime·funcline(Func*, uint64);
+void* runtime·stackalloc(uint32);
+void runtime·stackfree(void*);
+MCache* runtime·allocmcache(void);
+void runtime·mallocinit(void);
+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*));
+void runtime·runpanic(Panic*);
+void* runtime·getcallersp(void*);
+
+void runtime·exit(int32);
+void runtime·breakpoint(void);
+void runtime·gosched(void);
+void runtime·goexit(void);
+void runtime·runcgo(void (*fn)(void*), void*);
+void runtime·runcgocallback(G*, void*, void (*fn)());
+void runtime·entersyscall(void);
+void runtime·exitsyscall(void);
+void runtime·startcgocallback(G*);
+void runtime·endcgocallback(G*);
+G* runtime·newproc1(byte*, byte*, int32, int32);
+void runtime·siginit(void);
+bool runtime·sigsend(int32 sig);
+void runtime·gettime(int64*, int32*);
+int32 runtime·callers(int32, uintptr*, int32);
+int64 runtime·nanotime(void);
+void runtime·dopanic(int32);
+
+#pragma varargck argpos runtime·printf 1
#pragma varargck type "d" int32
#pragma varargck type "d" uint32
#pragma varargck type "D" int64
@@ -462,8 +474,8 @@ void panic(int32);
// TODO(rsc): Remove. These are only temporary,
// for the mark and sweep collector.
-void stoptheworld(void);
-void starttheworld(void);
+void runtime·stoptheworld(void);
+void runtime·starttheworld(void);
/*
* mutual exclusion locks. in the uncontended case,
@@ -471,9 +483,9 @@ void starttheworld(void);
* but on the contention path they sleep in the kernel.
* a zeroed Lock is unlocked (no need to initialize each lock).
*/
-void lock(Lock*);
-void unlock(Lock*);
-void destroylock(Lock*);
+void runtime·lock(Lock*);
+void runtime·unlock(Lock*);
+void runtime·destroylock(Lock*);
/*
* sleep and wakeup on one-time events.
@@ -484,32 +496,9 @@ void destroylock(Lock*);
* once notewakeup has been called, all the notesleeps
* will return. future notesleeps will return immediately.
*/
-void noteclear(Note*);
-void notesleep(Note*);
-void notewakeup(Note*);
-
-/*
- * Redefine methods for the benefit of gcc, which does not support
- * UTF-8 characters in identifiers.
- */
-#ifndef __GNUC__
-#define runtime_memclr ·memclr
-#define runtime_getcallerpc ·getcallerpc
-#define runtime_mmap ·mmap
-#define runtime_printslice ·printslice
-#define runtime_printbool ·printbool
-#define runtime_printfloat ·printfloat
-#define runtime_printhex ·printhex
-#define runtime_printint ·printint
-#define runtime_printiface ·printiface
-#define runtime_printeface ·printeface
-#define runtime_printpc ·printpc
-#define runtime_printpointer ·printpointer
-#define runtime_printstring ·printstring
-#define runtime_printuint ·printuint
-#define runtime_printcomplex ·printcomplex
-#define runtime_setcallerpc ·setcallerpc
-#endif
+void runtime·noteclear(Note*);
+void runtime·notesleep(Note*);
+void runtime·notewakeup(Note*);
/*
* This is consistent across Linux and BSD.
@@ -521,72 +510,83 @@ void notewakeup(Note*);
/*
* low level go-called
*/
-uint8* runtime_mmap(byte*, uintptr, int32, int32, int32, uint32);
-void runtime_memclr(byte*, uint32);
-void runtime_setcallerpc(void*, void*);
-void* runtime_getcallerpc(void*);
+uint8* runtime·mmap(byte*, uintptr, int32, int32, int32, uint32);
+void runtime·munmap(uint8*, uintptr);
+void runtime·memclr(byte*, uint32);
+void runtime·setcallerpc(void*, void*);
+void* runtime·getcallerpc(void*);
/*
* runtime go-called
*/
-void runtime_printbool(bool);
-void runtime_printfloat(float64);
-void runtime_printint(int64);
-void runtime_printiface(Iface);
-void runtime_printeface(Eface);
-void runtime_printstring(String);
-void runtime_printpc(void*);
-void runtime_printpointer(void*);
-void runtime_printuint(uint64);
-void runtime_printhex(uint64);
-void runtime_printslice(Slice);
-void runtime_printcomplex(Complex128);
+void runtime·printbool(bool);
+void runtime·printfloat(float64);
+void runtime·printint(int64);
+void runtime·printiface(Iface);
+void runtime·printeface(Eface);
+void runtime·printstring(String);
+void runtime·printpc(void*);
+void runtime·printpointer(void*);
+void runtime·printuint(uint64);
+void runtime·printhex(uint64);
+void runtime·printslice(Slice);
+void runtime·printcomplex(Complex128);
void reflect·call(byte*, byte*, uint32);
-void ·panic(Eface);
-void ·panicindex(void);
-void ·panicslice(void);
+void runtime·panic(Eface);
+void runtime·panicindex(void);
+void runtime·panicslice(void);
+
/*
* runtime c-called (but written in Go)
*/
-void ·newError(String, Eface*);
-void ·printany(Eface);
-void ·newTypeAssertionError(Type*, Type*, Type*, String*, String*, String*, String*, Eface*);
-void ·newErrorString(String, Eface*);
+void runtime·newError(String, Eface*);
+void runtime·printany(Eface);
+void runtime·newTypeAssertionError(Type*, Type*, Type*, String*, String*, String*, String*, Eface*);
+void runtime·newErrorString(String, Eface*);
+void runtime·fadd64c(uint64, uint64, uint64*);
+void runtime·fsub64c(uint64, uint64, uint64*);
+void runtime·fmul64c(uint64, uint64, uint64*);
+void runtime·fdiv64c(uint64, uint64, uint64*);
+void runtime·fneg64c(uint64, uint64*);
+void runtime·f32to64c(uint32, uint64*);
+void runtime·f64to32c(uint64, uint32*);
+void runtime·fcmp64c(uint64, uint64, int32*, bool*);
+void runtime·fintto64c(int64, uint64*);
+void runtime·f64tointc(uint64, int64*, bool*);
/*
* wrapped for go users
*/
-float64 Inf(int32 sign);
-float64 NaN(void);
-float32 float32frombits(uint32 i);
-uint32 float32tobits(float32 f);
-float64 float64frombits(uint64 i);
-uint64 float64tobits(float64 f);
-float64 frexp(float64 d, int32 *ep);
-bool isInf(float64 f, int32 sign);
-bool isNaN(float64 f);
-float64 ldexp(float64 d, int32 e);
-float64 modf(float64 d, float64 *ip);
-void semacquire(uint32*);
-void semrelease(uint32*);
-String signame(int32 sig);
-int32 gomaxprocsfunc(int32 n);
-
-
-void mapassign(Hmap*, byte*, byte*);
-void mapaccess(Hmap*, byte*, byte*, bool*);
-struct hash_iter* mapiterinit(Hmap*);
-void mapiternext(struct hash_iter*);
-bool mapiterkey(struct hash_iter*, void*);
-void mapiterkeyvalue(struct hash_iter*, void*, void*);
-Hmap* makemap(Type*, Type*, int64);
-
-Hchan* makechan(Type*, int64);
-void chansend(Hchan*, void*, bool*);
-void chanrecv(Hchan*, void*, bool*);
-void chanclose(Hchan*);
-bool chanclosed(Hchan*);
-int32 chanlen(Hchan*);
-int32 chancap(Hchan*);
-
-void ifaceE2I(struct InterfaceType*, Eface, Iface*);
+float64 runtime·Inf(int32 sign);
+float64 runtime·NaN(void);
+float32 runtime·float32frombits(uint32 i);
+uint32 runtime·float32tobits(float32 f);
+float64 runtime·float64frombits(uint64 i);
+uint64 runtime·float64tobits(float64 f);
+float64 runtime·frexp(float64 d, int32 *ep);
+bool runtime·isInf(float64 f, int32 sign);
+bool runtime·isNaN(float64 f);
+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·mapassign(Hmap*, byte*, byte*);
+void runtime·mapaccess(Hmap*, byte*, byte*, bool*);
+struct hash_iter* runtime·newmapiterinit(Hmap*);
+void runtime·mapiternext(struct hash_iter*);
+bool runtime·mapiterkey(struct hash_iter*, void*);
+void runtime·mapiterkeyvalue(struct hash_iter*, void*, void*);
+Hmap* runtime·makemap_c(Type*, Type*, int64);
+
+Hchan* runtime·makechan_c(Type*, int64);
+void runtime·chansend(Hchan*, void*, bool*);
+void runtime·chanrecv(Hchan*, void*, bool*);
+void runtime·chanclose(Hchan*);
+bool runtime·chanclosed(Hchan*);
+int32 runtime·chanlen(Hchan*);
+int32 runtime·chancap(Hchan*);
+
+void runtime·ifaceE2I(struct InterfaceType*, Eface, Iface*);
diff --git a/src/pkg/runtime/runtime1.goc b/src/pkg/runtime/runtime1.goc
index 548844329..da2d0c572 100644
--- a/src/pkg/runtime/runtime1.goc
+++ b/src/pkg/runtime/runtime1.goc
@@ -6,5 +6,5 @@ package runtime
#include "runtime.h"
func GOMAXPROCS(n int32) (ret int32) {
- ret = gomaxprocsfunc(n);
+ ret = runtime·gomaxprocsfunc(n);
}
diff --git a/src/pkg/runtime/runtime_defs.go b/src/pkg/runtime/runtime_defs.go
new file mode 100644
index 000000000..ba3c3ed75
--- /dev/null
+++ b/src/pkg/runtime/runtime_defs.go
@@ -0,0 +1,200 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Go definitions of internal structures. Master is runtime.h
+
+// TODO(lvd): automate conversion to all the _defs.go files
+
+package runtime
+
+import "unsafe"
+
+const (
+ gidle = iota
+ grunnable
+ grunning
+ gsyscall
+ gwaiting
+ gmoribund
+ gdead
+ grecovery
+)
+
+// const ( Structrnd = sizeof(uintptr) )
+
+type string_ struct {
+ str *byte
+ len int32
+}
+
+type iface struct {
+ tab *itab
+ data unsafe.Pointer
+}
+
+type eface struct {
+ type_ *Type
+ data unsafe.Pointer
+}
+
+type complex64 struct {
+ real float32
+ imag float32
+}
+
+type complex128 struct {
+ real float64
+ imag float64
+}
+
+type slice struct {
+ array *byte
+ len uint32
+ cap uint32
+}
+
+type gobuf struct {
+ sp unsafe.Pointer
+ pc unsafe.Pointer
+ g *g_
+}
+
+type g_ struct {
+ stackguard unsafe.Pointer
+ stackbase unsafe.Pointer
+ defer_ *defer_
+ panic_ *panic_
+ sched gobuf
+ stack0 unsafe.Pointer
+ entry unsafe.Pointer
+ alllink *g_
+ param unsafe.Pointer
+ status int16
+ goid int32
+ selgen uint32
+ schedlink *g_
+ readyonstop bool
+ ispanic bool
+ m *m_
+ lockedm *m_
+ sig int32
+ sigcode0 uintptr
+ sigcode1 uintptr
+}
+
+type m_ struct {
+ g0 *g_
+ morepc unsafe.Pointer
+ morefp unsafe.Pointer
+ morebuf gobuf
+ moreframe uint32
+ moreargs uint32
+ cret uintptr
+ procid uint64
+ gsignal *g_
+ tls [8]uint32
+ sched gobuf
+ curg *g_
+ id int32
+ mallocing int32
+ gcing int32
+ locks int32
+ nomemprof int32
+ waitnextg int32
+ havenextg note
+ nextg *g_
+ alllink *m_
+ schedlink *m_
+ machport uint32
+ mcache *mCache
+ lockedg *g_
+ freg [8]uint64
+ // gostack unsafe.Pointer // __WINDOWS__
+}
+
+type stktop struct {
+ stackguard *uint8
+ stackbase *uint8
+ gobuf gobuf
+ args uint32
+ fp *uint8
+ free bool
+ panic_ bool
+}
+
+type alg struct {
+ hash func(uint32, unsafe.Pointer) uintptr
+ equal func(uint32, unsafe.Pointer, unsafe.Pointer) uint32
+ print func(uint32, unsafe.Pointer)
+ copy func(uint32, unsafe.Pointer, unsafe.Pointer)
+}
+
+type sigtab struct {
+ flags int32
+ name *int8
+}
+
+const (
+ sigCatch = (1 << iota)
+ sigIgnore
+ sigRestart
+ sigQueue
+ sigPanic
+)
+
+type Func struct {
+ name string
+ typ string
+ src string
+ pcln []byte
+ entry uintptr
+ pc0 uintptr
+ ln0 int32
+ frame int32
+ args int32
+ locals int32
+}
+
+const (
+ aMEM = iota
+ aNOEQ
+ aSTRING
+ aINTER
+ aNILINTER
+ aMEMWORD
+ amax
+)
+
+type defer_ struct {
+ siz int32
+ sp unsafe.Pointer
+ pc unsafe.Pointer
+ fn unsafe.Pointer
+ link *defer_
+ args [8]byte // padded to actual size
+}
+
+type panic_ struct {
+ arg eface
+ stackbase unsafe.Pointer
+ link *panic_
+ recovered bool
+}
+
+/*
+ * External data.
+ */
+
+var (
+ algarray [amax]alg
+ emptystring string
+ allg *g_
+ allm *m_
+ goidgen int32
+ gomaxprocs int32
+ panicking int32
+ fd int32
+ gcwaiting int32
+ goos *int8
+)
diff --git a/src/pkg/runtime/sema.goc b/src/pkg/runtime/sema.goc
index 71395ce77..1c77e87a5 100644
--- a/src/pkg/runtime/sema.goc
+++ b/src/pkg/runtime/sema.goc
@@ -39,7 +39,7 @@ semqueue(uint32 *addr, Sema *s)
s->addr = addr;
s->g = nil;
- lock(&semlock);
+ runtime·lock(&semlock);
s->prev = semlast;
s->next = nil;
if(semlast)
@@ -47,13 +47,13 @@ semqueue(uint32 *addr, Sema *s)
else
semfirst = s;
semlast = s;
- unlock(&semlock);
+ runtime·unlock(&semlock);
}
static void
semdequeue(Sema *s)
{
- lock(&semlock);
+ runtime·lock(&semlock);
if(s->next)
s->next->prev = s->prev;
else
@@ -64,7 +64,7 @@ semdequeue(Sema *s)
semfirst = s->next;
s->prev = nil;
s->next = nil;
- unlock(&semlock);
+ runtime·unlock(&semlock);
}
static void
@@ -72,15 +72,15 @@ semwakeup(uint32 *addr)
{
Sema *s;
- lock(&semlock);
+ runtime·lock(&semlock);
for(s=semfirst; s; s=s->next) {
if(s->addr == addr && s->g) {
- ready(s->g);
+ runtime·ready(s->g);
s->g = nil;
break;
}
}
- unlock(&semlock);
+ runtime·unlock(&semlock);
}
// Step 1 of sleep: make ourselves available for wakeup.
@@ -90,16 +90,16 @@ semwakeup(uint32 *addr)
static void
semsleep1(Sema *s)
{
- lock(&semlock);
+ runtime·lock(&semlock);
s->g = g;
- unlock(&semlock);
+ runtime·unlock(&semlock);
}
// Decided not to go through with it: undo step 1.
static void
semsleepundo1(Sema *s)
{
- lock(&semlock);
+ runtime·lock(&semlock);
if(s->g != nil) {
s->g = nil; // back ourselves out
} else {
@@ -111,7 +111,7 @@ semsleepundo1(Sema *s)
*(int32*)0x555 = 555;
g->readyonstop = 0;
}
- unlock(&semlock);
+ runtime·unlock(&semlock);
}
// Step 2: wait for the wakeup.
@@ -120,7 +120,7 @@ semsleep2(Sema *s)
{
USED(s);
g->status = Gwaiting;
- gosched();
+ runtime·gosched();
}
static int32
@@ -129,7 +129,7 @@ cansemacquire(uint32 *addr)
uint32 v;
while((v = *addr) > 0)
- if(cas(addr, v, v-1))
+ if(runtime·cas(addr, v, v-1))
return 1;
return 0;
}
@@ -137,7 +137,7 @@ cansemacquire(uint32 *addr)
// For now has no return value.
// Might return an ok (not interrupted) bool in the future?
void
-semacquire(uint32 *addr)
+runtime·semacquire(uint32 *addr)
{
Sema s;
@@ -164,22 +164,22 @@ semacquire(uint32 *addr)
}
void
-semrelease(uint32 *addr)
+runtime·semrelease(uint32 *addr)
{
uint32 v;
for(;;) {
v = *addr;
- if(cas(addr, v, v+1))
+ if(runtime·cas(addr, v, v+1))
break;
}
semwakeup(addr);
}
func Semacquire(addr *uint32) {
- semacquire(addr);
+ runtime·semacquire(addr);
}
func Semrelease(addr *uint32) {
- semrelease(addr);
+ runtime·semrelease(addr);
}
diff --git a/src/pkg/runtime/sigqueue.goc b/src/pkg/runtime/sigqueue.goc
index 572daab52..504590a54 100644
--- a/src/pkg/runtime/sigqueue.goc
+++ b/src/pkg/runtime/sigqueue.goc
@@ -47,14 +47,14 @@ static struct {
} sig;
void
-siginit(void)
+runtime·siginit(void)
{
- noteclear(&sig);
+ runtime·noteclear(&sig);
}
// Called from sighandler to send a signal back out of the signal handling thread.
bool
-sigsend(int32 s)
+runtime·sigsend(int32 s)
{
uint32 bit, mask;
@@ -65,11 +65,11 @@ sigsend(int32 s)
mask = sig.mask;
if(mask & bit)
break; // signal already in queue
- if(cas(&sig.mask, mask, mask|bit)) {
+ if(runtime·cas(&sig.mask, mask, mask|bit)) {
// Added to queue.
// Only send a wakeup for the first signal in each round.
if(mask == 0)
- notewakeup(&sig);
+ runtime·notewakeup(&sig);
break;
}
}
@@ -78,22 +78,22 @@ sigsend(int32 s)
// Called to receive a bitmask of queued signals.
func Sigrecv() (m uint32) {
- ·entersyscall();
- notesleep(&sig);
- ·exitsyscall();
- noteclear(&sig);
+ runtime·entersyscall();
+ runtime·notesleep(&sig);
+ runtime·exitsyscall();
+ runtime·noteclear(&sig);
for(;;) {
m = sig.mask;
- if(cas(&sig.mask, m, 0))
+ if(runtime·cas(&sig.mask, m, 0))
break;
}
}
func Signame(sig int32) (name String) {
- name = signame(sig);
+ name = runtime·signame(sig);
}
func Siginit() {
- initsig(SigQueue);
+ runtime·initsig(SigQueue);
sig.inuse = true; // enable reception of signals; cannot disable
}
diff --git a/src/pkg/runtime/slice.c b/src/pkg/runtime/slice.c
index 4162b8daa..051075479 100644
--- a/src/pkg/runtime/slice.c
+++ b/src/pkg/runtime/slice.c
@@ -8,60 +8,124 @@
static int32 debug = 0;
+static void makeslice1(SliceType*, int32, int32, Slice*);
+ void runtime·slicecopy(Slice to, Slice fm, uintptr width, int32 ret);
+
// see also unsafe·NewArray
// makeslice(typ *Type, len, cap int64) (ary []any);
void
-·makeslice(SliceType *t, int64 len, int64 cap, Slice ret)
+runtime·makeslice(SliceType *t, int64 len, int64 cap, Slice ret)
{
- uintptr size;
-
if(len < 0 || (int32)len != len)
- panicstring("makeslice: len out of range");
+ runtime·panicstring("makeslice: len out of range");
if(cap < len || (int32)cap != cap || cap > ((uintptr)-1) / t->elem->size)
- panicstring("makeslice: cap out of range");
+ runtime·panicstring("makeslice: cap out of range");
+
+ makeslice1(t, len, cap, &ret);
+
+ if(debug) {
+ runtime·printf("makeslice(%S, %D, %D); ret=",
+ *t->string, len, cap);
+ runtime·printslice(ret);
+ }
+}
+
+static void
+makeslice1(SliceType *t, int32 len, int32 cap, Slice *ret)
+{
+ uintptr size;
size = cap*t->elem->size;
- ret.len = len;
- ret.cap = cap;
+ ret->len = len;
+ ret->cap = cap;
if((t->elem->kind&KindNoPointers))
- ret.array = mallocgc(size, RefNoPointers, 1, 1);
+ ret->array = runtime·mallocgc(size, RefNoPointers, 1, 1);
else
- ret.array = mal(size);
+ ret->array = runtime·mal(size);
+}
- FLUSH(&ret);
+static void appendslice1(SliceType*, Slice, Slice, Slice*);
- if(debug) {
- printf("makeslice(%S, %D, %D); ret=",
- *t->string, len, cap);
- ·printslice(ret);
+// append(type *Type, n int, old []T, ...,) []T
+#pragma textflag 7
+void
+runtime·append(SliceType *t, int32 n, Slice old, ...)
+{
+ Slice sl;
+ Slice *ret;
+
+ sl.len = n;
+ sl.array = (byte*)(&old+1);
+ ret = (Slice*)(sl.array + ((t->elem->size*n+sizeof(uintptr)-1) & ~(sizeof(uintptr)-1)));
+ appendslice1(t, old, sl, ret);
+}
+
+// appendslice(type *Type, x, y, []T) []T
+void
+runtime·appendslice(SliceType *t, Slice x, Slice y, Slice ret)
+{
+ appendslice1(t, x, y, &ret);
+}
+
+static void
+appendslice1(SliceType *t, Slice x, Slice y, Slice *ret)
+{
+ Slice newx;
+ int32 m;
+ uintptr w;
+
+ if(x.len+y.len < x.len)
+ runtime·throw("append: slice overflow");
+
+ w = t->elem->size;
+ if(x.len+y.len > x.cap) {
+ m = x.cap;
+ if(m == 0)
+ m = y.len;
+ else {
+ do {
+ if(x.len < 1024)
+ m += m;
+ else
+ m += m/4;
+ } while(m < x.len+y.len);
+ }
+ makeslice1(t, x.len, m, &newx);
+ runtime·memmove(newx.array, x.array, x.len*w);
+ x = newx;
}
+ runtime·memmove(x.array+x.len*w, y.array, y.len*w);
+ x.len += y.len;
+ *ret = x;
}
-// sliceslice(old []any, lb int, hb int, width int) (ary []any);
+
+
+// sliceslice(old []any, lb uint64, hb uint64, width uint64) (ary []any);
void
-·sliceslice(Slice old, uint32 lb, uint32 hb, uint32 width, Slice ret)
+runtime·sliceslice(Slice old, uint64 lb, uint64 hb, uint64 width, Slice ret)
{
if(hb > old.cap || lb > hb) {
if(debug) {
- prints("runtime.sliceslice: old=");
- ·printslice(old);
- prints("; lb=");
- ·printint(lb);
- prints("; hb=");
- ·printint(hb);
- prints("; width=");
- ·printint(width);
- prints("\n");
-
- prints("oldarray: nel=");
- ·printint(old.len);
- prints("; cap=");
- ·printint(old.cap);
- prints("\n");
+ runtime·prints("runtime.sliceslice: old=");
+ runtime·printslice(old);
+ runtime·prints("; lb=");
+ runtime·printint(lb);
+ runtime·prints("; hb=");
+ runtime·printint(hb);
+ runtime·prints("; width=");
+ runtime·printint(width);
+ runtime·prints("\n");
+
+ runtime·prints("oldarray: nel=");
+ runtime·printint(old.len);
+ runtime·prints("; cap=");
+ runtime·printint(old.cap);
+ runtime·prints("\n");
}
- ·panicslice();
+ runtime·panicslice();
}
// new array is inside old array
@@ -72,41 +136,41 @@ void
FLUSH(&ret);
if(debug) {
- prints("runtime.sliceslice: old=");
- ·printslice(old);
- prints("; lb=");
- ·printint(lb);
- prints("; hb=");
- ·printint(hb);
- prints("; width=");
- ·printint(width);
- prints("; ret=");
- ·printslice(ret);
- prints("\n");
+ runtime·prints("runtime.sliceslice: old=");
+ runtime·printslice(old);
+ runtime·prints("; lb=");
+ runtime·printint(lb);
+ runtime·prints("; hb=");
+ runtime·printint(hb);
+ runtime·prints("; width=");
+ runtime·printint(width);
+ runtime·prints("; ret=");
+ runtime·printslice(ret);
+ runtime·prints("\n");
}
}
-// sliceslice1(old []any, lb int, width int) (ary []any);
+// sliceslice1(old []any, lb uint64, width uint64) (ary []any);
void
-·sliceslice1(Slice old, uint32 lb, uint32 width, Slice ret)
+runtime·sliceslice1(Slice old, uint64 lb, uint64 width, Slice ret)
{
if(lb > old.len) {
if(debug) {
- prints("runtime.sliceslice: old=");
- ·printslice(old);
- prints("; lb=");
- ·printint(lb);
- prints("; width=");
- ·printint(width);
- prints("\n");
-
- prints("oldarray: nel=");
- ·printint(old.len);
- prints("; cap=");
- ·printint(old.cap);
- prints("\n");
+ runtime·prints("runtime.sliceslice: old=");
+ runtime·printslice(old);
+ runtime·prints("; lb=");
+ runtime·printint(lb);
+ runtime·prints("; width=");
+ runtime·printint(width);
+ runtime·prints("\n");
+
+ runtime·prints("oldarray: nel=");
+ runtime·printint(old.len);
+ runtime·prints("; cap=");
+ runtime·printint(old.cap);
+ runtime·prints("\n");
}
- ·panicslice();
+ runtime·panicslice();
}
// new array is inside old array
@@ -117,21 +181,21 @@ void
FLUSH(&ret);
if(debug) {
- prints("runtime.sliceslice: old=");
- ·printslice(old);
- prints("; lb=");
- ·printint(lb);
- prints("; width=");
- ·printint(width);
- prints("; ret=");
- ·printslice(ret);
- prints("\n");
+ runtime·prints("runtime.sliceslice: old=");
+ runtime·printslice(old);
+ runtime·prints("; lb=");
+ runtime·printint(lb);
+ runtime·prints("; width=");
+ runtime·printint(width);
+ runtime·prints("; ret=");
+ runtime·printslice(ret);
+ runtime·prints("\n");
}
}
-// slicearray(old *any, nel int, lb int, hb int, width int) (ary []any);
+// slicearray(old *any, nel uint64, lb uint64, hb uint64, width uint64) (ary []any);
void
-·slicearray(byte* old, uint32 nel, uint32 lb, uint32 hb, uint32 width, Slice ret)
+runtime·slicearray(byte* old, uint64 nel, uint64 lb, uint64 hb, uint64 width, Slice ret)
{
if(nel > 0 && old == nil) {
// crash if old == nil.
@@ -143,19 +207,19 @@ void
if(hb > nel || lb > hb) {
if(debug) {
- prints("runtime.slicearray: old=");
- ·printpointer(old);
- prints("; nel=");
- ·printint(nel);
- prints("; lb=");
- ·printint(lb);
- prints("; hb=");
- ·printint(hb);
- prints("; width=");
- ·printint(width);
- prints("\n");
+ runtime·prints("runtime.slicearray: old=");
+ runtime·printpointer(old);
+ runtime·prints("; nel=");
+ runtime·printint(nel);
+ runtime·prints("; lb=");
+ runtime·printint(lb);
+ runtime·prints("; hb=");
+ runtime·printint(hb);
+ runtime·prints("; width=");
+ runtime·printint(width);
+ runtime·prints("\n");
}
- ·panicslice();
+ runtime·panicslice();
}
// new array is inside old array
@@ -166,25 +230,25 @@ void
FLUSH(&ret);
if(debug) {
- prints("runtime.slicearray: old=");
- ·printpointer(old);
- prints("; nel=");
- ·printint(nel);
- prints("; lb=");
- ·printint(lb);
- prints("; hb=");
- ·printint(hb);
- prints("; width=");
- ·printint(width);
- prints("; ret=");
- ·printslice(ret);
- prints("\n");
+ runtime·prints("runtime.slicearray: old=");
+ runtime·printpointer(old);
+ runtime·prints("; nel=");
+ runtime·printint(nel);
+ runtime·prints("; lb=");
+ runtime·printint(lb);
+ runtime·prints("; hb=");
+ runtime·printint(hb);
+ runtime·prints("; width=");
+ runtime·printint(width);
+ runtime·prints("; ret=");
+ runtime·printslice(ret);
+ runtime·prints("\n");
}
}
// slicecopy(to any, fr any, wid uint32) int
void
-·slicecopy(Slice to, Slice fm, uintptr width, int32 ret)
+runtime·slicecopy(Slice to, Slice fm, uintptr width, int32 ret)
{
if(fm.len == 0 || to.len == 0 || width == 0) {
ret = 0;
@@ -198,32 +262,50 @@ void
if(ret == 1 && width == 1) { // common case worth about 2x to do here
*to.array = *fm.array; // known to be a byte pointer
} else {
- memmove(to.array, fm.array, ret*width);
+ runtime·memmove(to.array, fm.array, ret*width);
}
out:
FLUSH(&ret);
if(debug) {
- prints("main·copy: to=");
- ·printslice(to);
- prints("; fm=");
- ·printslice(fm);
- prints("; width=");
- ·printint(width);
- prints("; ret=");
- ·printint(ret);
- prints("\n");
+ runtime·prints("main·copy: to=");
+ runtime·printslice(to);
+ runtime·prints("; fm=");
+ runtime·printslice(fm);
+ runtime·prints("; width=");
+ runtime·printint(width);
+ runtime·prints("; ret=");
+ runtime·printint(ret);
+ runtime·prints("\n");
+ }
+}
+
+void
+runtime·slicestringcopy(Slice to, String fm, int32 ret)
+{
+ if(fm.len == 0 || to.len == 0) {
+ ret = 0;
+ goto out;
}
+
+ ret = fm.len;
+ if(to.len < ret)
+ ret = to.len;
+
+ runtime·memmove(to.array, fm.str, ret);
+
+out:
+ FLUSH(&ret);
}
void
-·printslice(Slice a)
+runtime·printslice(Slice a)
{
- prints("[");
- ·printint(a.len);
- prints("/");
- ·printint(a.cap);
- prints("]");
- ·printpointer(a.array);
+ runtime·prints("[");
+ runtime·printint(a.len);
+ runtime·prints("/");
+ runtime·printint(a.cap);
+ runtime·prints("]");
+ runtime·printpointer(a.array);
}
diff --git a/src/pkg/runtime/softfloat64.go b/src/pkg/runtime/softfloat64.go
new file mode 100644
index 000000000..d9bbe5def
--- /dev/null
+++ b/src/pkg/runtime/softfloat64.go
@@ -0,0 +1,498 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Software IEEE754 64-bit floating point.
+// Only referred to (and thus linked in) by arm port
+// and by gotest in this directory.
+
+package runtime
+
+const (
+ mantbits64 uint = 52
+ expbits64 uint = 11
+ bias64 = -1<<(expbits64-1) + 1
+
+ nan64 uint64 = (1<<expbits64-1)<<mantbits64 + 1
+ inf64 uint64 = (1<<expbits64 - 1) << mantbits64
+ neg64 uint64 = 1 << (expbits64 + mantbits64)
+
+ mantbits32 uint = 23
+ expbits32 uint = 8
+ bias32 = -1<<(expbits32-1) + 1
+
+ nan32 uint32 = (1<<expbits32-1)<<mantbits32 + 1
+ inf32 uint32 = (1<<expbits32 - 1) << mantbits32
+ neg32 uint32 = 1 << (expbits32 + mantbits32)
+)
+
+func funpack64(f uint64) (sign, mant uint64, exp int, inf, nan bool) {
+ sign = f & (1 << (mantbits64 + expbits64))
+ mant = f & (1<<mantbits64 - 1)
+ exp = int(f>>mantbits64) & (1<<expbits64 - 1)
+
+ switch exp {
+ case 1<<expbits64 - 1:
+ if mant != 0 {
+ nan = true
+ return
+ }
+ inf = true
+ return
+
+ case 0:
+ // denormalized
+ if mant != 0 {
+ exp += bias64 + 1
+ for mant < 1<<mantbits64 {
+ mant <<= 1
+ exp--
+ }
+ }
+
+ default:
+ // add implicit top bit
+ mant |= 1 << mantbits64
+ exp += bias64
+ }
+ return
+}
+
+func funpack32(f uint32) (sign, mant uint32, exp int, inf, nan bool) {
+ sign = f & (1 << (mantbits32 + expbits32))
+ mant = f & (1<<mantbits32 - 1)
+ exp = int(f>>mantbits32) & (1<<expbits32 - 1)
+
+ switch exp {
+ case 1<<expbits32 - 1:
+ if mant != 0 {
+ nan = true
+ return
+ }
+ inf = true
+ return
+
+ case 0:
+ // denormalized
+ if mant != 0 {
+ exp += bias32 + 1
+ for mant < 1<<mantbits32 {
+ mant <<= 1
+ exp--
+ }
+ }
+
+ default:
+ // add implicit top bit
+ mant |= 1 << mantbits32
+ exp += bias32
+ }
+ return
+}
+
+func fpack64(sign, mant uint64, exp int, trunc uint64) uint64 {
+ mant0, exp0, trunc0 := mant, exp, trunc
+ if mant == 0 {
+ return sign
+ }
+ for mant < 1<<mantbits64 {
+ mant <<= 1
+ exp--
+ }
+ for mant >= 4<<mantbits64 {
+ trunc |= mant & 1
+ mant >>= 1
+ exp++
+ }
+ if mant >= 2<<mantbits64 {
+ if mant&1 != 0 && (trunc != 0 || mant&2 != 0) {
+ mant++
+ if mant >= 4<<mantbits64 {
+ mant >>= 1
+ exp++
+ }
+ }
+ mant >>= 1
+ exp++
+ }
+ if exp >= 1<<expbits64-1+bias64 {
+ return sign ^ inf64
+ }
+ if exp < bias64+1 {
+ if exp < bias64-int(mantbits64) {
+ return sign | 0
+ }
+ // repeat expecting denormal
+ mant, exp, trunc = mant0, exp0, trunc0
+ for exp < bias64 {
+ trunc |= mant & 1
+ mant >>= 1
+ exp++
+ }
+ if mant&1 != 0 && (trunc != 0 || mant&2 != 0) {
+ mant++
+ }
+ mant >>= 1
+ exp++
+ if mant < 1<<mantbits64 {
+ return sign | mant
+ }
+ }
+ return sign | uint64(exp-bias64)<<mantbits64 | mant&(1<<mantbits64-1)
+}
+
+func fpack32(sign, mant uint32, exp int, trunc uint32) uint32 {
+ mant0, exp0, trunc0 := mant, exp, trunc
+ if mant == 0 {
+ return sign
+ }
+ for mant < 1<<mantbits32 {
+ mant <<= 1
+ exp--
+ }
+ for mant >= 4<<mantbits32 {
+ trunc |= mant & 1
+ mant >>= 1
+ exp++
+ }
+ if mant >= 2<<mantbits32 {
+ if mant&1 != 0 && (trunc != 0 || mant&2 != 0) {
+ mant++
+ if mant >= 4<<mantbits32 {
+ mant >>= 1
+ exp++
+ }
+ }
+ mant >>= 1
+ exp++
+ }
+ if exp >= 1<<expbits32-1+bias32 {
+ return sign ^ inf32
+ }
+ if exp < bias32+1 {
+ if exp < bias32-int(mantbits32) {
+ return sign | 0
+ }
+ // repeat expecting denormal
+ mant, exp, trunc = mant0, exp0, trunc0
+ for exp < bias32 {
+ trunc |= mant & 1
+ mant >>= 1
+ exp++
+ }
+ if mant&1 != 0 && (trunc != 0 || mant&2 != 0) {
+ mant++
+ }
+ mant >>= 1
+ exp++
+ if mant < 1<<mantbits32 {
+ return sign | mant
+ }
+ }
+ return sign | uint32(exp-bias32)<<mantbits32 | mant&(1<<mantbits32-1)
+}
+
+func fadd64(f, g uint64) uint64 {
+ fs, fm, fe, fi, fn := funpack64(f)
+ gs, gm, ge, gi, gn := funpack64(g)
+
+ // Special cases.
+ switch {
+ case fn || gn: // NaN + x or x + NaN = NaN
+ return nan64
+
+ case fi && gi && fs != gs: // +Inf + -Inf or -Inf + +Inf = NaN
+ return nan64
+
+ case fi: // ±Inf + g = ±Inf
+ return f
+
+ case gi: // f + ±Inf = ±Inf
+ return g
+
+ case fm == 0 && gm == 0 && fs != 0 && gs != 0: // -0 + -0 = -0
+ return f
+
+ case fm == 0: // 0 + g = g but 0 + -0 = +0
+ if gm == 0 {
+ g ^= gs
+ }
+ return g
+
+ case gm == 0: // f + 0 = f
+ return f
+
+ }
+
+ if fe < ge || fe == ge && fm < gm {
+ f, g, fs, fm, fe, gs, gm, ge = g, f, gs, gm, ge, fs, fm, fe
+ }
+
+ shift := uint(fe - ge)
+ fm <<= 2
+ gm <<= 2
+ trunc := gm & (1<<shift - 1)
+ gm >>= shift
+ if fs == gs {
+ fm += gm
+ } else {
+ fm -= gm
+ if trunc != 0 {
+ fm--
+ }
+ }
+ if fm == 0 {
+ fs = 0
+ }
+ return fpack64(fs, fm, fe-2, trunc)
+}
+
+func fsub64(f, g uint64) uint64 {
+ return fadd64(f, fneg64(g))
+}
+
+func fneg64(f uint64) uint64 {
+ return f ^ (1 << (mantbits64 + expbits64))
+}
+
+func fmul64(f, g uint64) uint64 {
+ fs, fm, fe, fi, fn := funpack64(f)
+ gs, gm, ge, gi, gn := funpack64(g)
+
+ // Special cases.
+ switch {
+ case fn || gn: // NaN * g or f * NaN = NaN
+ return nan64
+
+ case fi && gi: // Inf * Inf = Inf (with sign adjusted)
+ return f ^ gs
+
+ case fi && gm == 0, fm == 0 && gi: // 0 * Inf = Inf * 0 = NaN
+ return nan64
+
+ case fm == 0: // 0 * x = 0 (with sign adjusted)
+ return f ^ gs
+
+ case gm == 0: // x * 0 = 0 (with sign adjusted)
+ return g ^ fs
+ }
+
+ // 53-bit * 53-bit = 107- or 108-bit
+ lo, hi := mullu(fm, gm)
+ shift := mantbits64 - 1
+ trunc := lo & (1<<shift - 1)
+ mant := hi<<(64-shift) | lo>>shift
+ return fpack64(fs^gs, mant, fe+ge-1, trunc)
+}
+
+func fdiv64(f, g uint64) uint64 {
+ fs, fm, fe, fi, fn := funpack64(f)
+ gs, gm, ge, gi, gn := funpack64(g)
+
+ // Special cases.
+ switch {
+ case fn || gn: // NaN / g = f / NaN = NaN
+ return nan64
+
+ case fi && gi: // ±Inf / ±Inf = NaN
+ return nan64
+
+ case !fi && !gi && fm == 0 && gm == 0: // 0 / 0 = NaN
+ return nan64
+
+ case fi, !gi && gm == 0: // Inf / g = f / 0 = Inf
+ return fs ^ gs ^ inf64
+
+ case gi, fm == 0: // f / Inf = 0 / g = Inf
+ return fs ^ gs ^ 0
+ }
+ _, _, _, _ = fi, fn, gi, gn
+
+ // 53-bit<<54 / 53-bit = 53- or 54-bit.
+ shift := mantbits64 + 2
+ q, r := divlu(fm>>(64-shift), fm<<shift, gm)
+ return fpack64(fs^gs, q, fe-ge-2, r)
+}
+
+func f64to32(f uint64) uint32 {
+ fs, fm, fe, fi, fn := funpack64(f)
+ if fn {
+ return nan32
+ }
+ fs32 := uint32(fs >> 32)
+ if fi {
+ return fs32 ^ inf32
+ }
+ const d = mantbits64 - mantbits32 - 1
+ return fpack32(fs32, uint32(fm>>d), fe-1, uint32(fm&(1<<d-1)))
+}
+
+func f32to64(f uint32) uint64 {
+ const d = mantbits64 - mantbits32
+ fs, fm, fe, fi, fn := funpack32(f)
+ if fn {
+ return nan64
+ }
+ fs64 := uint64(fs) << 32
+ if fi {
+ return fs64 ^ inf64
+ }
+ return fpack64(fs64, uint64(fm)<<d, fe, 0)
+}
+
+func fcmp64(f, g uint64) (cmp int, isnan bool) {
+ fs, fm, _, fi, fn := funpack64(f)
+ gs, gm, _, gi, gn := funpack64(g)
+
+ switch {
+ case fn, gn: // flag NaN
+ return 0, true
+
+ case !fi && !gi && fm == 0 && gm == 0: // ±0 == ±0
+ return 0, false
+
+ case fs > gs: // f < 0, g > 0
+ return -1, false
+
+ case fs < gs: // f > 0, g < 0
+ return +1, false
+
+ // Same sign, not NaN.
+ // Can compare encodings directly now.
+ // Reverse for sign.
+ case fs == 0 && f < g, fs != 0 && f > g:
+ return -1, false
+
+ case fs == 0 && f > g, fs != 0 && f < g:
+ return +1, false
+ }
+
+ // f == g
+ return 0, false
+}
+
+func f64toint(f uint64) (val int64, ok bool) {
+ fs, fm, fe, fi, fn := funpack64(f)
+
+ switch {
+ case fi, fn: // NaN
+ return 0, false
+
+ case fe < -1: // f < 0.5
+ return 0, false
+
+ case fe > 63: // f >= 2^63
+ if fs != 0 && fm == 0 { // f == -2^63
+ return -1 << 63, true
+ }
+ if fs != 0 {
+ return 0, false
+ }
+ return 0, false
+ }
+
+ for fe > int(mantbits64) {
+ fe--
+ fm <<= 1
+ }
+ for fe < int(mantbits64) {
+ fe++
+ fm >>= 1
+ }
+ val = int64(fm)
+ if fs != 0 {
+ val = -val
+ }
+ return val, true
+}
+
+func fintto64(val int64) (f uint64) {
+ fs := uint64(val) & (1 << 63)
+ mant := uint64(val)
+ if fs != 0 {
+ mant = -mant
+ }
+ return fpack64(fs, mant, int(mantbits64), 0)
+}
+
+// 64x64 -> 128 multiply.
+// adapted from hacker's delight.
+func mullu(u, v uint64) (lo, hi uint64) {
+ const (
+ s = 32
+ mask = 1<<s - 1
+ )
+ u0 := u & mask
+ u1 := u >> s
+ v0 := v & mask
+ v1 := v >> s
+ w0 := u0 * v0
+ t := u1*v0 + w0>>s
+ w1 := t & mask
+ w2 := t >> s
+ w1 += u0 * v1
+ return u * v, u1*v1 + w2 + w1>>s
+}
+
+// 128/64 -> 64 quotient, 64 remainder.
+// adapted from hacker's delight
+func divlu(u1, u0, v uint64) (q, r uint64) {
+ const b = 1 << 32
+
+ if u1 >= v {
+ return 1<<64 - 1, 1<<64 - 1
+ }
+
+ // s = nlz(v); v <<= s
+ s := uint(0)
+ for v&(1<<63) == 0 {
+ s++
+ v <<= 1
+ }
+
+ vn1 := v >> 32
+ vn0 := v & (1<<32 - 1)
+ un32 := u1<<s | u0>>(64-s)
+ un10 := u0 << s
+ un1 := un10 >> 32
+ un0 := un10 & (1<<32 - 1)
+ q1 := un32 / vn1
+ rhat := un32 - q1*vn1
+
+again1:
+ if q1 >= b || q1*vn0 > b*rhat+un1 {
+ q1--
+ rhat += vn1
+ if rhat < b {
+ goto again1
+ }
+ }
+
+ un21 := un32*b + un1 - q1*v
+ q0 := un21 / vn1
+ rhat = un21 - q0*vn1
+
+again2:
+ if q0 >= b || q0*vn0 > b*rhat+un0 {
+ q0--
+ rhat += vn1
+ if rhat < b {
+ goto again2
+ }
+ }
+
+ return q1*b + q0, (un21*b + un0 - q0*v) >> s
+}
+
+// callable from C
+
+func fadd64c(f, g uint64, ret *uint64) { *ret = fadd64(f, g) }
+func fsub64c(f, g uint64, ret *uint64) { *ret = fsub64(f, g) }
+func fmul64c(f, g uint64, ret *uint64) { *ret = fmul64(f, g) }
+func fdiv64c(f, g uint64, ret *uint64) { *ret = fdiv64(f, g) }
+func fneg64c(f uint64, ret *uint64) { *ret = fneg64(f) }
+func f32to64c(f uint32, ret *uint64) { *ret = f32to64(f) }
+func f64to32c(f uint64, ret *uint32) { *ret = f64to32(f) }
+func fcmp64c(f, g uint64, ret *int, retnan *bool) { *ret, *retnan = fcmp64(f, g) }
+func fintto64c(val int64, ret *uint64) { *ret = fintto64(val) }
+func f64tointc(f uint64, ret *int64, retok *bool) { *ret, *retok = f64toint(f) }
diff --git a/src/pkg/runtime/softfloat64_test.go b/src/pkg/runtime/softfloat64_test.go
new file mode 100644
index 000000000..fb7f3d3c0
--- /dev/null
+++ b/src/pkg/runtime/softfloat64_test.go
@@ -0,0 +1,198 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime_test
+
+import (
+ "math"
+ "rand"
+ . "runtime"
+ "testing"
+)
+
+// turn uint64 op into float64 op
+func fop(f func(x, y uint64) uint64) func(x, y float64) float64 {
+ return func(x, y float64) float64 {
+ bx := math.Float64bits(x)
+ by := math.Float64bits(y)
+ return math.Float64frombits(f(bx, by))
+ }
+}
+
+func add(x, y float64) float64 { return x + y }
+func sub(x, y float64) float64 { return x - y }
+func mul(x, y float64) float64 { return x * y }
+func div(x, y float64) float64 { return x / y }
+
+func TestFloat64(t *testing.T) {
+ base := []float64{
+ 0,
+ math.Copysign(0, -1),
+ -1,
+ 1,
+ math.NaN(),
+ math.Inf(+1),
+ math.Inf(-1),
+ 0.1,
+ 1.5,
+ 1.9999999999999998, // all 1s mantissa
+ 1.3333333333333333, // 1.010101010101...
+ 1.1428571428571428, // 1.001001001001...
+ 1.112536929253601e-308, // first normal
+ 2,
+ 4,
+ 8,
+ 16,
+ 32,
+ 64,
+ 128,
+ 256,
+ 3,
+ 12,
+ 1234,
+ 123456,
+ -0.1,
+ -1.5,
+ -1.9999999999999998,
+ -1.3333333333333333,
+ -1.1428571428571428,
+ -2,
+ -3,
+ 1e-200,
+ 1e-300,
+ 1e-310,
+ 5e-324,
+ 1e-105,
+ 1e-305,
+ 1e+200,
+ 1e+306,
+ 1e+307,
+ 1e+308,
+ }
+ all := make([]float64, 200)
+ copy(all, base)
+ for i := len(base); i < len(all); i++ {
+ all[i] = rand.NormFloat64()
+ }
+
+ test(t, "+", add, fop(Fadd64), all)
+ test(t, "-", sub, fop(Fsub64), all)
+ if GOARCH != "386" { // 386 is not precise!
+ test(t, "*", mul, fop(Fmul64), all)
+ test(t, "/", div, fop(Fdiv64), all)
+ }
+}
+
+// 64 -hw-> 32 -hw-> 64
+func trunc32(f float64) float64 {
+ return float64(float32(f))
+}
+
+// 64 -sw->32 -hw-> 64
+func to32sw(f float64) float64 {
+ return float64(math.Float32frombits(F64to32(math.Float64bits(f))))
+}
+
+// 64 -hw->32 -sw-> 64
+func to64sw(f float64) float64 {
+ return math.Float64frombits(F32to64(math.Float32bits(float32(f))))
+}
+
+// float64 -hw-> int64 -hw-> float64
+func hwint64(f float64) float64 {
+ return float64(int64(f))
+}
+
+// float64 -hw-> int32 -hw-> float64
+func hwint32(f float64) float64 {
+ return float64(int32(f))
+}
+
+// float64 -sw-> int64 -hw-> float64
+func toint64sw(f float64) float64 {
+ i, ok := F64toint(math.Float64bits(f))
+ if !ok {
+ // There's no right answer for out of range.
+ // Match the hardware to pass the test.
+ i = int64(f)
+ }
+ return float64(i)
+}
+
+// float64 -hw-> int64 -sw-> float64
+func fromint64sw(f float64) float64 {
+ return math.Float64frombits(Fintto64(int64(f)))
+}
+
+var nerr int
+
+func err(t *testing.T, format string, args ...interface{}) {
+ t.Errorf(format, args...)
+
+ // cut errors off after a while.
+ // otherwise we spend all our time
+ // allocating memory to hold the
+ // formatted output.
+ if nerr++; nerr >= 10 {
+ t.Fatal("too many errors")
+ }
+}
+
+func test(t *testing.T, op string, hw, sw func(float64, float64) float64, all []float64) {
+ for _, f := range all {
+ for _, g := range all {
+ h := hw(f, g)
+ s := sw(f, g)
+ if !same(h, s) {
+ err(t, "%g %s %g = sw %g, hw %g\n", f, op, g, s, h)
+ }
+ testu(t, "to32", trunc32, to32sw, h)
+ testu(t, "to64", trunc32, to64sw, h)
+ testu(t, "toint64", hwint64, toint64sw, h)
+ testu(t, "fromint64", hwint64, fromint64sw, h)
+ testcmp(t, f, h)
+ testcmp(t, h, f)
+ testcmp(t, g, h)
+ testcmp(t, h, g)
+ }
+ }
+}
+
+func testu(t *testing.T, op string, hw, sw func(float64) float64, v float64) {
+ h := hw(v)
+ s := sw(v)
+ if !same(h, s) {
+ err(t, "%s %g = sw %g, hw %g\n", op, v, s, h)
+ }
+}
+
+func hwcmp(f, g float64) (cmp int, isnan bool) {
+ switch {
+ case f < g:
+ return -1, false
+ case f > g:
+ return +1, false
+ case f == g:
+ return 0, false
+ }
+ return 0, true // must be NaN
+}
+
+func testcmp(t *testing.T, f, g float64) {
+ hcmp, hisnan := hwcmp(f, g)
+ scmp, sisnan := Fcmp64(math.Float64bits(f), math.Float64bits(g))
+ if hcmp != scmp || hisnan != sisnan {
+ err(t, "cmp(%g, %g) = sw %v, %v, hw %v, %v\n", f, g, scmp, sisnan, hcmp, hisnan)
+ }
+}
+
+func same(f, g float64) bool {
+ if math.IsNaN(f) && math.IsNaN(g) {
+ return true
+ }
+ if math.Copysign(1, f) != math.Copysign(1, g) {
+ return false
+ }
+ return f == g
+}
diff --git a/src/pkg/runtime/string.goc b/src/pkg/runtime/string.goc
index 1a4847322..916559eb2 100644
--- a/src/pkg/runtime/string.goc
+++ b/src/pkg/runtime/string.goc
@@ -6,10 +6,10 @@ package runtime
#include "runtime.h"
#include "malloc.h"
-String emptystring;
+String runtime·emptystring;
int32
-findnull(byte *s)
+runtime·findnull(byte *s)
{
int32 l;
@@ -21,7 +21,7 @@ findnull(byte *s)
}
int32
-findnullw(uint16 *s)
+runtime·findnullw(uint16 *s)
{
int32 l;
@@ -32,46 +32,56 @@ findnullw(uint16 *s)
return l;
}
-int32 maxstring = 256;
+int32 runtime·maxstring = 256;
String
-gostringsize(int32 l)
+runtime·gostringsize(int32 l)
{
String s;
if(l == 0)
- return emptystring;
- s.str = mal(l+1); // leave room for NUL for C runtime (e.g., callers of getenv)
+ return runtime·emptystring;
+ s.str = runtime·mal(l+1); // leave room for NUL for C runtime (e.g., callers of getenv)
s.len = l;
- if(l > maxstring)
- maxstring = l;
+ if(l > runtime·maxstring)
+ runtime·maxstring = l;
return s;
}
String
-gostring(byte *str)
+runtime·gostring(byte *str)
{
int32 l;
String s;
- l = findnull(str);
- s = gostringsize(l);
- mcpy(s.str, str, l);
+ l = runtime·findnull(str);
+ s = runtime·gostringsize(l);
+ runtime·mcpy(s.str, str, l);
return s;
}
String
-gostringnocopy(byte *str)
+runtime·gostringn(byte *str, int32 l)
+{
+ String s;
+
+ s = runtime·gostringsize(l);
+ runtime·mcpy(s.str, str, l);
+ return s;
+}
+
+String
+runtime·gostringnocopy(byte *str)
{
String s;
s.str = str;
- s.len = findnull(str);
+ s.len = runtime·findnull(str);
return s;
}
String
-gostringw(uint16 *str)
+runtime·gostringw(uint16 *str)
{
int32 n, i;
byte buf[8];
@@ -79,17 +89,17 @@ gostringw(uint16 *str)
n = 0;
for(i=0; str[i]; i++)
- n += runetochar(buf, str[i]);
- s = gostringsize(n+4);
+ n += runtime·runetochar(buf, str[i]);
+ s = runtime·gostringsize(n+4);
n = 0;
for(i=0; str[i]; i++)
- n += runetochar(s.str+n, str[i]);
+ n += runtime·runetochar(s.str+n, str[i]);
s.len = n;
return s;
}
String
-catstring(String s1, String s2)
+runtime·catstring(String s1, String s2)
{
String s3;
@@ -98,18 +108,42 @@ catstring(String s1, String s2)
if(s2.len == 0)
return s1;
- s3 = gostringsize(s1.len + s2.len);
- mcpy(s3.str, s1.str, s1.len);
- mcpy(s3.str+s1.len, s2.str, s2.len);
+ s3 = runtime·gostringsize(s1.len + s2.len);
+ runtime·mcpy(s3.str, s1.str, s1.len);
+ runtime·mcpy(s3.str+s1.len, s2.str, s2.len);
return s3;
}
+static String
+concatstring(int32 n, String *s)
+{
+ int32 i, l;
+ String out;
+
+ l = 0;
+ for(i=0; i<n; i++) {
+ if(l + s[i].len < l)
+ runtime·throw("string concatenation too long");
+ l += s[i].len;
+ }
+
+ out = runtime·gostringsize(l);
+ l = 0;
+ for(i=0; i<n; i++) {
+ runtime·mcpy(out.str+l, s[i].str, s[i].len);
+ l += s[i].len;
+ }
+ return out;
+}
-func catstring(s1 String, s2 String) (s3 String) {
- s3 = catstring(s1, s2);
+#pragma textflag 7
+// s1 is the first of n strings.
+// the output string follows.
+func concatstring(n int32, s1 String) {
+ (&s1)[n] = concatstring(n, &s1);
}
-uint32
+static int32
cmpstring(String s1, String s2)
{
uint32 i, l;
@@ -138,7 +172,7 @@ func cmpstring(s1 String, s2 String) (v int32) {
}
int32
-strcmp(byte *s1, byte *s2)
+runtime·strcmp(byte *s1, byte *s2)
{
uint32 i;
byte c1, c2;
@@ -160,57 +194,41 @@ func slicestring(si String, lindex int32, hindex int32) (so String) {
if(lindex < 0 || lindex > si.len ||
hindex < lindex || hindex > si.len) {
- ·panicslice();
+ runtime·panicslice();
}
l = hindex-lindex;
so.str = si.str + lindex;
so.len = l;
-
-// alternate to create a new string
-// so = gostringsize(l);
-// mcpy(so.str, si.str+lindex, l);
}
func slicestring1(si String, lindex int32) (so String) {
int32 l;
if(lindex < 0 || lindex > si.len) {
- ·panicslice();
+ runtime·panicslice();
}
l = si.len-lindex;
so.str = si.str + lindex;
so.len = l;
-
-// alternate to create a new string
-// so = gostringsize(l);
-// mcpy(so.str, si.str+lindex, l);
-}
-
-func indexstring(s String, i int32) (b byte) {
- if(i < 0 || i >= s.len) {
- ·panicindex();
- }
-
- b = s.str[i];
}
func intstring(v int64) (s String) {
- s = gostringsize(8);
- s.len = runetochar(s.str, v);
+ s = runtime·gostringsize(8);
+ s.len = runtime·runetochar(s.str, v);
}
func slicebytetostring(b Slice) (s String) {
- s = gostringsize(b.len);
- mcpy(s.str, b.array, s.len);
+ s = runtime·gostringsize(b.len);
+ runtime·mcpy(s.str, b.array, s.len);
}
func stringtoslicebyte(s String) (b Slice) {
- b.array = mallocgc(s.len, RefNoPointers, 1, 1);
+ b.array = runtime·mallocgc(s.len, RefNoPointers, 1, 1);
b.len = s.len;
b.cap = s.len;
- mcpy(b.array, s.str, s.len);
+ runtime·mcpy(b.array, s.str, s.len);
}
func sliceinttostring(b Slice) (s String) {
@@ -221,16 +239,16 @@ func sliceinttostring(b Slice) (s String) {
a = (int32*)b.array;
siz1 = 0;
for(i=0; i<b.len; i++) {
- siz1 += runetochar(dum, a[i]);
+ siz1 += runtime·runetochar(dum, a[i]);
}
- s = gostringsize(siz1+4);
+ s = runtime·gostringsize(siz1+4);
siz2 = 0;
for(i=0; i<b.len; i++) {
// check for race
if(siz2 >= siz1)
break;
- siz2 += runetochar(s.str+siz2, a[i]);
+ siz2 += runtime·runetochar(s.str+siz2, a[i]);
}
s.len = siz2;
}
@@ -246,17 +264,17 @@ func stringtosliceint(s String) (b Slice) {
ep = s.str+s.len;
n = 0;
while(p < ep) {
- p += charntorune(&dum, p, ep-p);
+ p += runtime·charntorune(&dum, p, ep-p);
n++;
}
- b.array = mallocgc(n*sizeof(r[0]), RefNoPointers, 1, 1);
+ b.array = runtime·mallocgc(n*sizeof(r[0]), RefNoPointers, 1, 1);
b.len = n;
b.cap = n;
p = s.str;
r = (int32*)b.array;
while(p < ep)
- p += charntorune(r++, p, ep-p);
+ p += runtime·charntorune(r++, p, ep-p);
}
enum
@@ -280,7 +298,7 @@ func stringiter(s String, k int32) (retk int32) {
}
// multi-char rune
- retk = k + charntorune(&l, s.str+k, s.len-k);
+ retk = k + runtime·charntorune(&l, s.str+k, s.len-k);
out:
}
@@ -300,7 +318,7 @@ func stringiter2(s String, k int32) (retk int32, retv int32) {
}
// multi-char rune
- retk = k + charntorune(&retv, s.str+k, s.len-k);
+ retk = k + runtime·charntorune(&retv, s.str+k, s.len-k);
out:
}
diff --git a/src/pkg/runtime/symtab.c b/src/pkg/runtime/symtab.c
index 5a35f635b..b2cccd3cf 100644
--- a/src/pkg/runtime/symtab.c
+++ b/src/pkg/runtime/symtab.c
@@ -17,7 +17,7 @@
#include "os.h"
#include "arch.h"
-extern int32 symdat[];
+extern byte pclntab[], epclntab[], symtab[], esymtab[];
typedef struct Sym Sym;
struct Sym
@@ -32,25 +32,16 @@ struct Sym
static void
walksymtab(void (*fn)(Sym*))
{
- int32 *v;
byte *p, *ep, *q;
Sym s;
- if(symdat == nil)
- return;
-
-#ifdef __WINDOWS__
- v = get_symdat_addr();
- p = (byte*)v+8;
-#else
- v = symdat;
- p = (byte*)(symdat+2);
-#endif
- ep = p + v[0];
+ p = symtab;
+ ep = esymtab;
while(p < ep) {
if(p + 7 > ep)
break;
s.value = ((uint32)p[0]<<24) | ((uint32)p[1]<<16) | ((uint32)p[2]<<8) | ((uint32)p[3]);
+
if(!(p[4]&0x80))
break;
s.symtype = p[4] & ~0x80;
@@ -69,7 +60,7 @@ walksymtab(void (*fn)(Sym*))
}
p = q+2;
}else{
- q = mchr(p, '\0', ep);
+ q = runtime·mchr(p, '\0', ep);
if(q == nil)
break;
p = q+1;
@@ -99,14 +90,14 @@ dofunc(Sym *sym)
case 'T':
case 'l':
case 'L':
- if(strcmp(sym->name, (byte*)"etext") == 0)
+ if(runtime·strcmp(sym->name, (byte*)"etext") == 0)
break;
if(func == nil) {
nfunc++;
break;
}
f = &func[nfunc++];
- f->name = gostringnocopy(sym->name);
+ f->name = runtime·gostringnocopy(sym->name);
f->entry = sym->value;
if(sym->symtype == 'L' || sym->symtype == 'l')
f->frame = -sizeof(uintptr);
@@ -127,8 +118,13 @@ dofunc(Sym *sym)
break;
case 'f':
if(fname == nil) {
- if(sym->value >= nfname)
+ if(sym->value >= nfname) {
+ if(sym->value >= 0x10000) {
+ runtime·printf("invalid symbol file index %p\n", sym->value);
+ runtime·throw("mangled symbol table");
+ }
nfname = sym->value+1;
+ }
break;
}
fname[sym->value] = sym->name;
@@ -158,12 +154,12 @@ makepath(byte *buf, int32 nbuf, byte *path)
if(n >= nfname)
break;
q = fname[n];
- len = findnull(q);
+ len = runtime·findnull(q);
if(p+1+len >= ep)
break;
if(p > buf && p[-1] != '/')
*p++ = '/';
- mcpy(p, q, len+1);
+ runtime·mcpy(p, q, len+1);
p += len;
}
}
@@ -189,7 +185,7 @@ dosrcline(Sym *sym)
switch(sym->symtype) {
case 't':
case 'T':
- if(strcmp(sym->name, (byte*)"etext") == 0)
+ if(runtime·strcmp(sym->name, (byte*)"etext") == 0)
break;
f = &func[nfunc++];
// find source file
@@ -208,7 +204,7 @@ dosrcline(Sym *sym)
nfile = 0;
if(nfile == nelem(files))
return;
- files[nfile].srcstring = gostring(srcbuf);
+ files[nfile].srcstring = runtime·gostring(srcbuf);
files[nfile].aline = 0;
files[nfile++].delta = 0;
} else {
@@ -219,7 +215,7 @@ dosrcline(Sym *sym)
incstart = sym->value;
if(nhist == 0 && nfile < nelem(files)) {
// new top-level file
- files[nfile].srcstring = gostring(srcbuf);
+ files[nfile].srcstring = runtime·gostring(srcbuf);
files[nfile].aline = sym->value;
// this is "line 0"
files[nfile++].delta = sym->value - 1;
@@ -240,9 +236,11 @@ splitpcln(void)
uintptr pc;
byte *p, *ep;
Func *f, *ef;
- int32 *v;
int32 pcquant;
+ if(pclntab == epclntab || nfunc == 0)
+ return;
+
switch(thechar) {
case '5':
pcquant = 4;
@@ -252,19 +250,9 @@ splitpcln(void)
break;
}
- if(symdat == nil)
- return;
-
// pc/ln table bounds
-#ifdef __WINDOWS__
- v = get_symdat_addr();
- p = (byte*)v+8;
-#else
- v = symdat;
- p = (byte*)(symdat+2);
-#endif
- p += v[0];
- ep = p+v[1];
+ p = pclntab;
+ ep = epclntab;
f = func;
ef = func + nfunc;
@@ -305,7 +293,7 @@ splitpcln(void)
// (Source file is f->src.)
// NOTE(rsc): If you edit this function, also edit extern.go:/FileLine
int32
-funcline(Func *f, uint64 targetpc)
+runtime·funcline(Func *f, uint64 targetpc)
{
byte *p, *ep;
uintptr pc;
@@ -360,9 +348,9 @@ buildfuncs(void)
walksymtab(dofunc);
// initialize tables
- func = mal((nfunc+1)*sizeof func[0]);
+ func = runtime·mal((nfunc+1)*sizeof func[0]);
func[nfunc].entry = (uint64)etext;
- fname = mal(nfname*sizeof fname[0]);
+ fname = runtime·mal(nfname*sizeof fname[0]);
nfunc = 0;
walksymtab(dofunc);
@@ -376,15 +364,15 @@ buildfuncs(void)
}
Func*
-findfunc(uintptr addr)
+runtime·findfunc(uintptr addr)
{
Func *f;
int32 nf, n;
- lock(&funclock);
+ runtime·lock(&funclock);
if(func == nil)
buildfuncs();
- unlock(&funclock);
+ runtime·unlock(&funclock);
if(nfunc == 0)
return nil;
@@ -410,6 +398,6 @@ findfunc(uintptr addr)
// that the address was in the table bounds.
// this can only happen if the table isn't sorted
// by address or if the binary search above is buggy.
- prints("findfunc unreachable\n");
+ runtime·prints("findfunc unreachable\n");
return nil;
}
diff --git a/src/pkg/runtime/tiny/386/rt0.s b/src/pkg/runtime/tiny/386/rt0.s
index ff7aae7ac..524ac7664 100644
--- a/src/pkg/runtime/tiny/386/rt0.s
+++ b/src/pkg/runtime/tiny/386/rt0.s
@@ -11,18 +11,18 @@ TEXT _rt0_386_tiny(SB), 7, $0
MOVL AX, SP
// Set up memory hardware.
- CALL msetup(SB)
+ CALL runtime·msetup(SB)
// _rt0_386 expects to find argc, argv, envv on stack.
// Set up argv=["kernel"] and envv=[].
SUBL $64, SP
MOVL $1, 0(SP)
- MOVL $kernel(SB), 4(SP)
+ MOVL $runtime·kernel(SB), 4(SP)
MOVL $0, 8(SP)
MOVL $0, 12(SP)
JMP _rt0_386(SB)
-DATA kernel+0(SB)/7, $"kernel\z"
-GLOBL kernel(SB), $7
+DATA runtime·kernel(SB)/7, $"kernel\z"
+GLOBL runtime·kernel(SB), $7
diff --git a/src/pkg/runtime/tiny/386/signal.c b/src/pkg/runtime/tiny/386/signal.c
index de06ba8db..88e634e9d 100644
--- a/src/pkg/runtime/tiny/386/signal.c
+++ b/src/pkg/runtime/tiny/386/signal.c
@@ -4,16 +4,16 @@
#include "runtime.h"
-extern void ·write(int32 fd, void *v, int32 len, int32 cap); // slice, spelled out
+extern void runtime·write(int32 fd, void *v, int32 len, int32 cap); // slice, spelled out
int32
-write(int32 fd, void *v, int32 len)
+runtime·write(int32 fd, void *v, int32 len)
{
- ·write(fd, v, len, len);
+ runtime·write(fd, v, len, len);
return len;
}
void
-gettime(int64*, int32*)
+runtime·gettime(int64*, int32*)
{
}
diff --git a/src/pkg/runtime/tiny/386/sys.s b/src/pkg/runtime/tiny/386/sys.s
index c51a5ec3e..851171476 100644
--- a/src/pkg/runtime/tiny/386/sys.s
+++ b/src/pkg/runtime/tiny/386/sys.s
@@ -17,8 +17,8 @@
// Called to set up memory hardware.
// Already running in 32-bit mode thanks to boot block,
// but we need to install our new GDT that we can modify.
-TEXT msetup(SB), 7, $0
- MOVL gdtptr(SB), GDTR
+TEXT runtime·msetup(SB), 7, $0
+ MOVL runtime·gdtptr(SB), GDTR
MOVL $(1*8+0), AX
MOVW AX, DS
MOVW AX, ES
@@ -29,14 +29,14 @@ TEXT msetup(SB), 7, $0
// long jmp to cs:mret
BYTE $0xEA
- LONG $mret(SB)
+ LONG $runtime·mret(SB)
WORD $(2*8+0)
-TEXT mret(SB), 7, $0
+TEXT runtime·mret(SB), 7, $0
RET
// GDT memory
-TEXT gdt(SB), 7, $0
+TEXT runtime·gdt(SB), 7, $0
// null segment
LONG $0
LONG $0
@@ -54,14 +54,14 @@ TEXT gdt(SB), 7, $0
LONG $0
// GDT pseudo-descriptor
-TEXT gdtptr(SB), 7, $0
+TEXT runtime·gdtptr(SB), 7, $0
WORD $(4*8)
- LONG $gdt(SB)
+ LONG $runtime·gdt(SB)
// Called to establish the per-thread segment.
// Write to gdt[3] and reload the gdt register.
// setldt(int entry, int address, int limit)
-TEXT setldt(SB),7,$32
+TEXT runtime·setldt(SB),7,$32
MOVL address+4(FP), BX // aka base
MOVL limit+8(FP), CX
@@ -83,7 +83,7 @@ TEXT setldt(SB),7,$32
MOVB CX, 6(AX)
MOVB $0xF2, 5(AX) // r/w data descriptor, dpl=3, present
- MOVL gdtptr(SB), GDTR
+ MOVL runtime·gdtptr(SB), GDTR
// Compute segment selector - (entry*8+0)
MOVL $(3*8+0), AX
diff --git a/src/pkg/runtime/tiny/README b/src/pkg/runtime/tiny/README
index bbe00f3ea..cf001d1e6 100755
--- a/src/pkg/runtime/tiny/README
+++ b/src/pkg/runtime/tiny/README
@@ -6,8 +6,7 @@ for 386 and arm.
386
It is very primitive but can run go/test/sieve.go, the concurrent
-prime sieve, on a uniprocessor. It has only been tested using the
-Bochs emulator.
+prime sieve, on a uniprocessor.
To run, first build the tools by running all.bash with GOARCH=386
and GOOS set to your normal GOOS (linux, darwin). Then:
@@ -22,14 +21,41 @@ and GOOS set to your normal GOOS (linux, darwin). Then:
8l -a sieve.8 >sieve.asm # can consult sieve.asm for debugging
dd if=/dev/zero of=disk count=10000
cat bootblock 8.out | dd of=disk conv=notrunc
- bochs
Use the built-in print(text string) function to print to the
console.
+
+BOCHS
+
You may have to tweak the .bochsrc depending on your system,
and you may need to install the Bochs emulator.
+ $ cp dot-bochsrc .bochsrc
+ $ $EDITOR .bochsrc # tweak it if required
+ $ bochs
+
+
+ORACLE xVM VIRTUALBOX
+
+Install VirtualBox. Then:
+
+ Build 'disk' (described above under '386').
+
+ $ VBoxManage convertfromraw disk go-tiny.vdi
+ $ VirtualBox
+ create a new VM; as disk use the go-tiny.vdi image.
+ start the vm.
+
+
+QEMU / KVM
+
+This should work the same for qemu and kvm (really: qemu-kvm).
+
+ Build 'disk' (described above under '386').
+
+ $ qemu -hda disk
+
ARM
diff --git a/src/pkg/runtime/tiny/mem.c b/src/pkg/runtime/tiny/mem.c
index a66a4a731..7abecfba0 100644
--- a/src/pkg/runtime/tiny/mem.c
+++ b/src/pkg/runtime/tiny/mem.c
@@ -8,34 +8,43 @@
// Assume there's an arbitrary amount of memory starting at "end".
// Sizing PC memory is beyond the scope of this demo.
+static byte *allocp;
+
void*
-SysAlloc(uintptr ask)
+runtime·SysAlloc(uintptr ask)
{
- static byte *p;
extern byte end[];
byte *q;
- if(p == nil) {
- p = end;
- p += 7 & -(uintptr)p;
+ if(allocp == nil) {
+ allocp = end;
+ allocp += 7 & -(uintptr)allocp;
}
ask += 7 & -ask;
- q = p;
- p += ask;
- ·memclr(q, ask);
+ q = allocp;
+ allocp += ask;
+ runtime·memclr(q, ask);
return q;
}
void
-SysFree(void *v, uintptr n)
+runtime·SysFree(void *v, uintptr n)
{
- USED(v, n);
+ // Push pointer back if this is a free
+ // of the most recent SysAlloc.
+ n += 7 & -n;
+ if(allocp == (byte*)v+n)
+ allocp -= n;
}
void
-SysUnused(void *v, uintptr n)
+runtime·SysUnused(void *v, uintptr n)
{
USED(v, n);
}
+void
+runtime·SysMemInit(void)
+{
+}
diff --git a/src/pkg/runtime/tiny/runtime_defs.go b/src/pkg/runtime/tiny/runtime_defs.go
new file mode 100644
index 000000000..86de13316
--- /dev/null
+++ b/src/pkg/runtime/tiny/runtime_defs.go
@@ -0,0 +1,14 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// OS-Specific Go definitions of internal structures. Master is runtime.h
+
+package runtime
+
+type lock struct {
+ key uint32
+ sema uint32
+}
+
+type note lock
diff --git a/src/pkg/runtime/tiny/thread.c b/src/pkg/runtime/tiny/thread.c
index e4b58256f..0572ecb77 100644
--- a/src/pkg/runtime/tiny/thread.c
+++ b/src/pkg/runtime/tiny/thread.c
@@ -7,22 +7,28 @@
int8 *goos = "tiny";
void
-minit(void)
+runtime·minit(void)
{
}
void
-osinit(void)
+runtime·osinit(void)
{
}
void
-initsig(int32 queue)
+runtime·goenvs(void)
{
+ runtime·goenvs_unix();
}
void
-exit(int32)
+runtime·initsig(int32 queue)
+{
+}
+
+void
+runtime·exit(int32)
{
for(;;);
}
@@ -31,50 +37,56 @@ exit(int32)
// so no need for real concurrency or atomicity
void
-newosproc(M *m, G *g, void *stk, void (*fn)(void))
+runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void))
{
USED(m, g, stk, fn);
- throw("newosproc");
+ runtime·throw("newosproc");
}
void
-lock(Lock *l)
+runtime·lock(Lock *l)
{
if(m->locks < 0)
- throw("lock count");
+ runtime·throw("lock count");
m->locks++;
if(l->key != 0)
- throw("deadlock");
+ runtime·throw("deadlock");
l->key = 1;
}
void
-unlock(Lock *l)
+runtime·unlock(Lock *l)
{
m->locks--;
if(m->locks < 0)
- throw("lock count");
+ runtime·throw("lock count");
if(l->key != 1)
- throw("unlock of unlocked lock");
+ runtime·throw("unlock of unlocked lock");
l->key = 0;
}
+void
+runtime·destroylock(Lock *l)
+{
+ // nothing
+}
+
void
-noteclear(Note *n)
+runtime·noteclear(Note *n)
{
n->lock.key = 0;
}
void
-notewakeup(Note *n)
+runtime·notewakeup(Note *n)
{
n->lock.key = 1;
}
void
-notesleep(Note *n)
+runtime·notesleep(Note *n)
{
if(n->lock.key != 1)
- throw("notesleep");
+ runtime·throw("notesleep");
}
diff --git a/src/pkg/runtime/type.go b/src/pkg/runtime/type.go
index 5efbfaf83..d92fe5f2a 100644
--- a/src/pkg/runtime/type.go
+++ b/src/pkg/runtime/type.go
@@ -9,6 +9,7 @@
* data structures and must be kept in sync with this file:
*
* ../../cmd/gc/reflect.c
+ * ../../cmd/ld/dwarf.c
* ../reflect/type.go
* type.h
*/
@@ -53,6 +54,9 @@ const (
kindFloat
kindFloat32
kindFloat64
+ kindComplex
+ kindComplex64
+ kindComplex128
kindArray
kindChan
kindFunc
@@ -191,6 +195,8 @@ type StructType struct {
/*
* 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
diff --git a/src/pkg/runtime/windows/386/rt0.s b/src/pkg/runtime/windows/386/rt0.s
index 4e6850416..e379830fb 100644
--- a/src/pkg/runtime/windows/386/rt0.s
+++ b/src/pkg/runtime/windows/386/rt0.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_386_windows(SB),7,$0
+TEXT _rt0_386_windows(SB),7,$0
JMP _rt0_386(SB)
diff --git a/src/pkg/runtime/windows/386/signal.c b/src/pkg/runtime/windows/386/signal.c
index 278bb7fc4..2ae79e5b5 100644
--- a/src/pkg/runtime/windows/386/signal.c
+++ b/src/pkg/runtime/windows/386/signal.c
@@ -5,6 +5,13 @@
#include "runtime.h"
void
-initsig(int32 queue)
+runtime·initsig(int32)
{
}
+
+String
+runtime·signame(int32)
+{
+ return runtime·emptystring;
+}
+
diff --git a/src/pkg/runtime/windows/386/sys.s b/src/pkg/runtime/windows/386/sys.s
index e36ef53e0..7f99b34de 100644
--- a/src/pkg/runtime/windows/386/sys.s
+++ b/src/pkg/runtime/windows/386/sys.s
@@ -4,105 +4,112 @@
#include "386/asm.h"
-TEXT get_kernel_module(SB),7,$0
- MOVL 0x30(FS), AX // get PEB
- MOVL 0x0c(AX), AX // get PEB_LDR_DATA
- MOVL 0x1c(AX), AX // get init order module list
- MOVL (AX), AX // get next entry (kernel module)
- MOVL 0x08(AX), AX // get base of module
- RET
-
-// void *stdcall_raw(void *fn, ...);
-// Call fn with stdcall calling convention.
-// fn parameters are on stack.
-TEXT stdcall_raw(SB),7,$0
- get_tls(CX)
- MOVL m(CX), CX
- POPL m_return_address(CX) // save return address
- POPL AX // first arg is function pointer
- MOVL SP, m_stack_pointer(CX) // save stack pointer
- CALL AX
- get_tls(CX)
- MOVL m(CX), CX
- MOVL m_stack_pointer(CX), SP
- PUSHL AX
- PUSHL m_return_address(CX)
- RET
+// void *stdcall_raw(void *fn, int32 count, uintptr *args)
+TEXT runtime·stdcall_raw(SB),7,$4
+ // Copy arguments from stack.
+ MOVL fn+0(FP), AX
+ MOVL count+4(FP), CX // words
+ MOVL args+8(FP), BP
-// void syscall(StdcallParams *p);
-// Call p.fn syscall + GetLastError on os stack.
-TEXT syscall(SB),7,$16
- MOVL p+0(FP), AX
- MOVL SP, CX
-
- // Figure out if we need to switch to m->g0 stack.
+ // Switch to m->g0 if needed.
get_tls(DI)
MOVL m(DI), DX
+ MOVL g(DI), SI
+ MOVL SI, 0(SP) // save g
+ MOVL SP, m_gostack(DX) // save SP
MOVL m_g0(DX), SI
CMPL g(DI), SI
- JEQ 2(PC)
+ JEQ 3(PC)
MOVL (m_sched+gobuf_sp)(DX), SP
-
- // Now on a scheduling stack (an os stack).
- MOVL g(DI), BP
- MOVL BP, 8(SP)
MOVL SI, g(DI)
- MOVL CX, 4(SP)
- MOVL AX, 0(SP)
- CALL call_syscall(SB)
-
- // Back; switch to original g and stack, re-establish
- // "DF is clear" invariant.
+
+ // Copy args to new stack.
+ SUBL $(10*4), SP // padding
+ MOVL CX, BX
+ SALL $2, BX
+ SUBL BX, SP // room for args
+ MOVL SP, DI
+ MOVL BP, SI
CLD
+ REP; MOVSL
+
+ // Call stdcall function.
+ CALL AX
+
+ // Restore original SP, g.
get_tls(DI)
- MOVL 8(SP), SI
+ MOVL m(DI), DX
+ MOVL m_gostack(DX), SP // restore SP
+ MOVL 0(SP), SI // restore g
MOVL SI, g(DI)
- MOVL 4(SP), SP
- RET
-TEXT threadstart(SB),7,$0
- MOVL 4(SP), AX // threadstart param
- MOVL 0(AX), BX // newosproc arg stack
- MOVL 0(BX), CX // m
- MOVL 4(BX), DX // g
+ // Someday the convention will be D is always cleared.
+ CLD
+
+ RET
+
+// void tstart(M *newm);
+TEXT runtime·tstart(SB),7,$0
+ MOVL newm+4(SP), CX // m
+ MOVL m_g0(CX), DX // g
+
+ MOVL SP, DI // remember stack
- // set up tls
+ // Layout new m scheduler stack on os stack.
+ MOVL SP, AX
+ SUBL $256, AX // just some space for ourselves
+ MOVL AX, g_stackbase(DX)
+ SUBL $8192, AX // stack size
+ MOVL AX, g_stackguard(DX)
+
+ // Set up tls.
LEAL m_tls(CX), SI
MOVL SI, 0x2c(FS)
MOVL CX, m(SI)
MOVL DX, g(SI)
- MOVL SP, m_os_stack_pointer(CX)
-
- PUSHL 8(BX) // stk
- PUSHL 12(BX) // fn
- PUSHL 4(AX) // event_handle
-
- // signal that we're done with thread args
- MOVL SetEvent(SB), BX
- CALL BX // SetEvent(event_handle)
- POPL BX // fn
- POPL SP // stk
-
- CALL stackcheck(SB) // clobbers AX,CX
- CALL BX // fn()
-
- // cleanup stack before returning as we are stdcall
- get_tls(CX)
- MOVL m(CX), CX
- MOVL m_os_stack_pointer(CX), SP
- POPL AX // return address
- MOVL AX, (SP)
- XORL AX, AX
+
+ // Use scheduler stack now.
+ MOVL g_stackbase(DX), SP
+
+ // Someday the convention will be D is always cleared.
+ CLD
+
+ PUSHL DI // original stack
+
+ CALL runtime·stackcheck(SB) // clobbers AX,CX
+
+ CALL runtime·mstart(SB)
+
+ POPL DI // original stack
+ MOVL DI, SP
+
+ RET
+
+// uint32 tstart_stdcall(M *newm);
+TEXT runtime·tstart_stdcall(SB),7,$0
+ MOVL newm+4(SP), BX
+
+ PUSHL BX
+ CALL runtime·tstart(SB)
+ POPL BX
+
+ // Adjust stack for stdcall to return properly.
+ MOVL (SP), AX // save return address
+ ADDL $4, SP // remove single parameter
+ MOVL AX, (SP) // restore return address
+
+ XORL AX, AX // return 0 == success
+
RET
// setldt(int entry, int address, int limit)
-TEXT setldt(SB),7,$0
+TEXT runtime·setldt(SB),7,$0
MOVL address+4(FP), CX
MOVL CX, 0x2c(FS)
RET
// for now, return 0,0. only used for internal performance monitoring.
-TEXT gettime(SB),7,$0
+TEXT runtime·gettime(SB),7,$0
MOVL sec+0(FP), DI
MOVL $0, (DI)
MOVL $0, 4(DI) // zero extend 32 -> 64 bits
diff --git a/src/pkg/runtime/windows/mem.c b/src/pkg/runtime/windows/mem.c
index 982344fa0..ba89887ea 100644
--- a/src/pkg/runtime/windows/mem.c
+++ b/src/pkg/runtime/windows/mem.c
@@ -7,23 +7,58 @@
#include "defs.h"
#include "malloc.h"
+enum {
+ MEM_COMMIT = 0x1000,
+ MEM_RESERVE = 0x2000,
+ MEM_RELEASE = 0x8000,
+
+ PAGE_EXECUTE_READWRITE = 0x40,
+};
+
+static void
+abort(int8 *name)
+{
+ uintptr errno;
+
+ errno = (uintptr)runtime·stdcall(runtime·GetLastError, 0);
+ runtime·printf("%s failed with errno=%d\n", name, errno);
+ runtime·throw(name);
+}
+
+#pragma dynimport runtime·VirtualAlloc VirtualAlloc "kernel32.dll"
+#pragma dynimport runtime·VirtualFree VirtualFree "kernel32.dll"
+extern void *runtime·VirtualAlloc;
+extern void *runtime·VirtualFree;
+
void*
-SysAlloc(uintptr n)
+runtime·SysAlloc(uintptr n)
{
- return stdcall(VirtualAlloc, 4, nil, n, 0x3000, 0x40);
+ void *v;
+
+ v = runtime·stdcall(runtime·VirtualAlloc, 4, nil, n, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
+ if(v == 0)
+ abort("VirtualAlloc");
+ return v;
}
void
-SysUnused(void *v, uintptr n)
+runtime·SysUnused(void *v, uintptr n)
{
USED(v);
USED(n);
}
void
-SysFree(void *v, uintptr n)
+runtime·SysFree(void *v, uintptr n)
{
- USED(v);
- USED(n);
+ uintptr r;
+
+ r = (uintptr)runtime·stdcall(runtime·VirtualFree, 3, v, 0, MEM_RELEASE);
+ if(r == 0)
+ abort("VirtualFree");
}
+void
+runtime·SysMemInit(void)
+{
+}
diff --git a/src/pkg/runtime/windows/os.h b/src/pkg/runtime/windows/os.h
index 931f4991c..77d0d32a0 100644
--- a/src/pkg/runtime/windows/os.h
+++ b/src/pkg/runtime/windows/os.h
@@ -2,28 +2,21 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// The following function allows one to dynamically
-// resolve DLL function names.
-// The arguments are strings.
-void *get_proc_addr(void *library, void *name);
-
-extern void *VirtualAlloc;
-extern void *LoadLibraryEx;
-extern void *GetProcAddress;
-extern void *GetLastError;
-
-#define goargs windows_goargs
-void windows_goargs(void);
+extern void *runtime·LoadLibraryEx;
+extern void *runtime·GetProcAddress;
+extern void *runtime·GetLastError;
// Get start address of symbol data in memory.
-void *get_symdat_addr(void);
-
-// Call a Windows function with stdcall conventions.
-void *stdcall_raw(void *fn, ...);
+void *runtime·get_symdat_addr(void);
// Call a Windows function with stdcall conventions,
// and switch to os stack during the call.
-void *stdcall(void *fn, int32 count, ...);
+void *runtime·stdcall_raw(void *fn, int32 count, uintptr *args);
+void *runtime·stdcall(void *fn, int32 count, ...);
+
+// Function to be called by windows CreateTread
+// to start new os thread.
+uint32 runtime·tstart_stdcall(M *newm);
// Call stdcall Windows function StdcallParams.fn
// with params StdcallParams.args,
@@ -34,9 +27,10 @@ typedef struct StdcallParams StdcallParams;
struct StdcallParams
{
void *fn;
- uintptr args[9];
+ uintptr args[12];
+ int32 n;
uintptr r;
uintptr err;
};
-void call_syscall(void *args);
-void syscall(StdcallParams *p);
+
+void runtime·syscall(StdcallParams *p);
diff --git a/src/pkg/runtime/windows/runtime_defs.go b/src/pkg/runtime/windows/runtime_defs.go
new file mode 100644
index 000000000..34a9b3259
--- /dev/null
+++ b/src/pkg/runtime/windows/runtime_defs.go
@@ -0,0 +1,22 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Go definitions of internal structures. Master is runtime.h
+
+package runtime
+
+import "unsafe"
+
+const (
+ Windows = 1
+)
+
+// const ( Structrnd = sizeof(uintptr) )
+
+type lock struct {
+ key uint32
+ event unsafe.Pointer
+}
+
+type note lock
diff --git a/src/pkg/runtime/windows/syscall.goc b/src/pkg/runtime/windows/syscall.goc
index 362217e6b..d3057c540 100644
--- a/src/pkg/runtime/windows/syscall.goc
+++ b/src/pkg/runtime/windows/syscall.goc
@@ -8,24 +8,22 @@ package syscall
func loadlibraryex(filename uintptr) (handle uint32) {
StdcallParams p;
- p.fn = (void*)LoadLibraryEx;
+ p.fn = (void*)runtime·LoadLibraryEx;
p.args[0] = filename;
p.args[1] = 0;
p.args[2] = 0;
- ·entersyscall();
- syscall(&p);
- ·exitsyscall();
+ p.n = 3;
+ runtime·syscall(&p);
handle = p.r;
}
func getprocaddress(handle uint32, procname uintptr) (proc uintptr) {
StdcallParams p;
- p.fn = (void*)GetProcAddress;
+ p.fn = (void*)runtime·GetProcAddress;
p.args[0] = handle;
p.args[1] = procname;
- ·entersyscall();
- syscall(&p);
- ·exitsyscall();
+ p.n = 2;
+ runtime·syscall(&p);
proc = p.r;
}
@@ -35,9 +33,8 @@ func Syscall(trap uintptr, a1 uintptr, a2 uintptr, a3 uintptr) (r1 uintptr, r2 u
p.args[0] = a1;
p.args[1] = a2;
p.args[2] = a3;
- ·entersyscall();
- syscall(&p);
- ·exitsyscall();
+ p.n = 3;
+ runtime·syscall(&p);
r1 = p.r;
r2 = 0;
err = p.err;
@@ -52,9 +49,8 @@ func Syscall6(trap uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 u
p.args[3] = a4;
p.args[4] = a5;
p.args[5] = a6;
- ·entersyscall();
- syscall(&p);
- ·exitsyscall();
+ p.n = 6;
+ runtime·syscall(&p);
r1 = p.r;
r2 = 0;
err = p.err;
@@ -72,9 +68,30 @@ func Syscall9(trap uintptr, a1 uintptr, a2 uintptr, a3 uintptr, a4 uintptr, a5 u
p.args[6] = a7;
p.args[7] = a8;
p.args[8] = a9;
- ·entersyscall();
- syscall(&p);
- ·exitsyscall();
+ p.n = 9;
+ runtime·syscall(&p);
+ r1 = p.r;
+ r2 = 0;
+ lasterr = p.err;
+}
+
+func Syscall12(trap 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, lasterr uintptr) {
+ StdcallParams p;
+ p.fn = (void*)trap;
+ p.args[0] = a1;
+ p.args[1] = a2;
+ p.args[2] = a3;
+ p.args[3] = a4;
+ p.args[4] = a5;
+ p.args[5] = a6;
+ p.args[6] = a7;
+ p.args[7] = a8;
+ p.args[8] = a9;
+ p.args[9] = a10;
+ p.args[10] = a11;
+ p.args[11] = a12;
+ p.n = 12;
+ runtime·syscall(&p);
r1 = p.r;
r2 = 0;
lasterr = p.err;
@@ -86,7 +103,8 @@ func RawSyscall(trap uintptr, a1 uintptr, a2 uintptr, a3 uintptr) (r1 uintptr, r
p.args[0] = a1;
p.args[1] = a2;
p.args[2] = a3;
- syscall(&p);
+ p.n = 3;
+ runtime·syscall(&p);
r1 = p.r;
r2 = 0;
err = p.err;
diff --git a/src/pkg/runtime/windows/thread.c b/src/pkg/runtime/windows/thread.c
index c65f665b1..9b5181337 100644
--- a/src/pkg/runtime/windows/thread.c
+++ b/src/pkg/runtime/windows/thread.c
@@ -5,130 +5,84 @@
#include "runtime.h"
#include "os.h"
-extern void *get_kernel_module(void);
+#pragma dynimport runtime·LoadLibraryEx LoadLibraryExA "kernel32.dll"
+#pragma dynimport runtime·GetProcAddress GetProcAddress "kernel32.dll"
+#pragma dynimport runtime·CloseHandle CloseHandle "kernel32.dll"
+#pragma dynimport runtime·ExitProcess ExitProcess "kernel32.dll"
+#pragma dynimport runtime·GetStdHandle GetStdHandle "kernel32.dll"
+#pragma dynimport runtime·SetEvent SetEvent "kernel32.dll"
+#pragma dynimport runtime·WriteFile WriteFile "kernel32.dll"
+#pragma dynimport runtime·GetLastError GetLastError "kernel32.dll"
+#pragma dynimport runtime·SetLastError SetLastError "kernel32.dll"
// Also referenced by external packages
-void *CloseHandle;
-void *ExitProcess;
-void *GetStdHandle;
-void *SetEvent;
-void *WriteFile;
-void *VirtualAlloc;
-void *LoadLibraryEx;
-void *GetProcAddress;
-void *GetLastError;
-
-static void *CreateEvent;
-static void *CreateThread;
-static void *GetModuleHandle;
-static void *WaitForSingleObject;
-
-static void*
-get_proc_addr2(byte *base, byte *name)
-{
- byte *pe_header, *exports;
- uint32 entries, *addr, *names, i;
- uint16 *ordinals;
-
- pe_header = base+*(uint32*)(base+0x3c);
- exports = base+*(uint32*)(pe_header+0x78);
- entries = *(uint32*)(exports+0x18);
- addr = (uint32*)(base+*(uint32*)(exports+0x1c));
- names = (uint32*)(base+*(uint32*)(exports+0x20));
- ordinals = (uint16*)(base+*(uint32*)(exports+0x24));
- for(i=0; i<entries; i++) {
- byte *s = base+names[i];
- if(!strcmp(name, s))
- break;
- }
- if(i == entries)
- return 0;
- return base+addr[ordinals[i]];
-}
+extern void *runtime·CloseHandle;
+extern void *runtime·ExitProcess;
+extern void *runtime·GetStdHandle;
+extern void *runtime·SetEvent;
+extern void *runtime·WriteFile;
+extern void *runtime·LoadLibraryEx;
+extern void *runtime·GetProcAddress;
+extern void *runtime·GetLastError;
+extern void *runtime·SetLastError;
+
+#pragma dynimport runtime·CreateEvent CreateEventA "kernel32.dll"
+#pragma dynimport runtime·CreateThread CreateThread "kernel32.dll"
+#pragma dynimport runtime·WaitForSingleObject WaitForSingleObject "kernel32.dll"
+
+extern void *runtime·CreateEvent;
+extern void *runtime·CreateThread;
+extern void *runtime·WaitForSingleObject;
void
-osinit(void)
+runtime·osinit(void)
{
- void *base;
-
- base = get_kernel_module();
- GetProcAddress = get_proc_addr2(base, (byte*)"GetProcAddress");
- LoadLibraryEx = get_proc_addr2(base, (byte*)"LoadLibraryExA");
- CloseHandle = get_proc_addr("kernel32.dll", "CloseHandle");
- CreateEvent = get_proc_addr("kernel32.dll", "CreateEventA");
- CreateThread = get_proc_addr("kernel32.dll", "CreateThread");
- ExitProcess = get_proc_addr("kernel32.dll", "ExitProcess");
- GetModuleHandle = get_proc_addr("kernel32.dll", "GetModuleHandleA");
- GetStdHandle = get_proc_addr("kernel32.dll", "GetStdHandle");
- SetEvent = get_proc_addr("kernel32.dll", "SetEvent");
- VirtualAlloc = get_proc_addr("kernel32.dll", "VirtualAlloc");
- WaitForSingleObject = get_proc_addr("kernel32.dll", "WaitForSingleObject");
- WriteFile = get_proc_addr("kernel32.dll", "WriteFile");
- GetLastError = get_proc_addr("kernel32.dll", "GetLastError");
}
-// The arguments are strings.
-void*
-get_proc_addr(void *library, void *name)
-{
- void *base;
+#pragma dynimport runtime·GetEnvironmentStringsW GetEnvironmentStringsW "kernel32.dll"
+#pragma dynimport runtime·FreeEnvironmentStringsW FreeEnvironmentStringsW "kernel32.dll"
- base = stdcall_raw(LoadLibraryEx, library, 0, 0);
- return stdcall_raw(GetProcAddress, base, name);
-}
+extern void *runtime·GetEnvironmentStringsW;
+extern void *runtime·FreeEnvironmentStringsW;
void
-windows_goargs(void)
+runtime·goenvs(void)
{
- extern Slice os·Args;
extern Slice os·Envs;
- void *gcl, *clta, *ges;
- uint16 *cmd, *env, **argv;
- String *gargv;
- String *genvv;
- int32 i, argc, envc;
- uint16 *envp;
-
- gcl = get_proc_addr("kernel32.dll", "GetCommandLineW");
- clta = get_proc_addr("shell32.dll", "CommandLineToArgvW");
- ges = get_proc_addr("kernel32.dll", "GetEnvironmentStringsW");
-
- cmd = stdcall(gcl, 0);
- env = stdcall(ges, 0);
- argv = stdcall(clta, 2, cmd, &argc);
-
- envc = 0;
- for(envp=env; *envp; envc++)
- envp += findnullw(envp)+1;
-
- gargv = malloc(argc*sizeof gargv[0]);
- genvv = malloc(envc*sizeof genvv[0]);
-
- for(i=0; i<argc; i++)
- gargv[i] = gostringw(argv[i]);
- os·Args.array = (byte*)gargv;
- os·Args.len = argc;
- os·Args.cap = argc;
-
- envp = env;
- for(i=0; i<envc; i++) {
- genvv[i] = gostringw(envp);
- envp += findnullw(envp)+1;
+ 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*)genvv;
- os·Envs.len = envc;
- os·Envs.cap = envc;
+ os·Envs.array = (byte*)s;
+ os·Envs.len = n;
+ os·Envs.cap = n;
+
+ runtime·stdcall(runtime·FreeEnvironmentStringsW, 1, env);
}
void
-exit(int32 code)
+runtime·exit(int32 code)
{
- stdcall(ExitProcess, 1, code);
+ runtime·stdcall(runtime·ExitProcess, 1, code);
}
int32
-write(int32 fd, void *buf, int32 n)
+runtime·write(int32 fd, void *buf, int32 n)
{
void *handle;
uint32 written;
@@ -136,46 +90,28 @@ write(int32 fd, void *buf, int32 n)
written = 0;
switch(fd) {
case 1:
- handle = stdcall(GetStdHandle, 1, -11);
+ handle = runtime·stdcall(runtime·GetStdHandle, 1, -11);
break;
case 2:
- handle = stdcall(GetStdHandle, 1, -12);
+ handle = runtime·stdcall(runtime·GetStdHandle, 1, -12);
break;
default:
return -1;
}
- stdcall(WriteFile, 5, handle, buf, n, &written, 0);
+ runtime·stdcall(runtime·WriteFile, 5, handle, buf, n, &written, 0);
return written;
}
-void*
-get_symdat_addr(void)
-{
- byte *mod, *p;
- uint32 peh, add;
- uint16 oph;
-
- mod = stdcall(GetModuleHandle, 1, 0);
- peh = *(uint32*)(mod+0x3c);
- p = mod+peh+4;
- oph = *(uint16*)(p+0x10);
- p += 0x14+oph;
- while(strcmp(p, (byte*)".symdat"))
- p += 40;
- add = *(uint32*)(p+0x0c);
- return mod+add;
-}
-
// Thread-safe allocation of an event.
static void
initevent(void **pevent)
{
void *event;
- event = stdcall(CreateEvent, 4, 0, 0, 0, 0);
- if(!casp(pevent, 0, event)) {
+ event = runtime·stdcall(runtime·CreateEvent, 4, 0, 0, 0, 0);
+ if(!runtime·casp(pevent, 0, event)) {
// Someone else filled it in. Use theirs.
- stdcall(CloseHandle, 1, event);
+ runtime·stdcall(runtime·CloseHandle, 1, event);
}
}
@@ -186,106 +122,96 @@ eventlock(Lock *l)
if(l->event == 0)
initevent(&l->event);
- if(xadd(&l->key, 1) > 1) // someone else has it; wait
- stdcall(WaitForSingleObject, 2, l->event, -1);
+ if(runtime·xadd(&l->key, 1) > 1) // someone else has it; wait
+ runtime·stdcall(runtime·WaitForSingleObject, 2, l->event, -1);
}
static void
eventunlock(Lock *l)
{
- if(xadd(&l->key, -1) > 0) // someone else is waiting
- stdcall(SetEvent, 1, l->event);
+ if(runtime·xadd(&l->key, -1) > 0) // someone else is waiting
+ runtime·stdcall(runtime·SetEvent, 1, l->event);
}
void
-lock(Lock *l)
+runtime·lock(Lock *l)
{
if(m->locks < 0)
- throw("lock count");
+ runtime·throw("lock count");
m->locks++;
eventlock(l);
}
void
-unlock(Lock *l)
+runtime·unlock(Lock *l)
{
m->locks--;
if(m->locks < 0)
- throw("lock count");
+ runtime·throw("lock count");
eventunlock(l);
}
void
-destroylock(Lock *l)
+runtime·destroylock(Lock *l)
{
if(l->event != 0)
- stdcall(CloseHandle, 1, l->event);
+ runtime·stdcall(runtime·CloseHandle, 1, l->event);
}
void
-noteclear(Note *n)
+runtime·noteclear(Note *n)
{
eventlock(&n->lock);
}
void
-notewakeup(Note *n)
+runtime·notewakeup(Note *n)
{
eventunlock(&n->lock);
}
void
-notesleep(Note *n)
+runtime·notesleep(Note *n)
{
eventlock(&n->lock);
eventunlock(&n->lock); // Let other sleepers find out too.
}
void
-newosproc(M *m, G *g, void *stk, void (*fn)(void))
+runtime·newosproc(M *m, G *g, void *stk, void (*fn)(void))
{
- struct {
- void *args;
- void *event_handle;
- } param = { &m };
- extern uint32 threadstart(void *p);
-
- USED(g, stk, fn);
- param.event_handle = stdcall(CreateEvent, 4, 0, 0, 0, 0);
- stdcall(CreateThread, 6, 0, 0, threadstart, &param, 0, 0);
- stdcall(WaitForSingleObject, 2, param.event_handle, -1);
- stdcall(CloseHandle, 1, param.event_handle);
+ USED(stk);
+ USED(g); // assuming g = m->g0
+ USED(fn); // assuming fn = mstart
+
+ runtime·stdcall(runtime·CreateThread, 6, 0, 0, runtime·tstart_stdcall, m, 0, 0);
}
// Called to initialize a new m (including the bootstrap m).
void
-minit(void)
+runtime·minit(void)
{
}
// Calling stdcall on os stack.
#pragma textflag 7
void *
-stdcall(void *fn, int32 count, ...)
+runtime·stdcall(void *fn, int32 count, ...)
{
- uintptr *a;
- StdcallParams p;
-
- p.fn = fn;
- a = (uintptr*)(&count + 1);
- while(count > 0) {
- count--;
- p.args[count] = a[count];
- }
- syscall(&p);
- return (void*)(p.r);
+ return runtime·stdcall_raw(fn, count, (uintptr*)(&count + 1));
}
void
-call_syscall(void *args)
-{
- StdcallParams *p = (StdcallParams*)args;
- p->r = (uintptr)stdcall_raw((void*)p->fn, p->args[0], p->args[1], p->args[2], p->args[3], p->args[4], p->args[5], p->args[6], p->args[7], p->args[8]);
- p->err = (uintptr)stdcall_raw(GetLastError);
- return;
+runtime·syscall(StdcallParams *p)
+{
+ uintptr a;
+
+ runtime·entersyscall();
+ // TODO(brainman): Move calls to SetLastError and GetLastError
+ // to stdcall_raw to speed up syscall.
+ a = 0;
+ runtime·stdcall_raw(runtime·SetLastError, 1, &a);
+ p->r = (uintptr)runtime·stdcall_raw((void*)p->fn, p->n, p->args);
+ p->err = (uintptr)runtime·stdcall_raw(runtime·GetLastError, 0, &a);
+ runtime·exitsyscall();
}
diff --git a/src/pkg/scanner/Makefile b/src/pkg/scanner/Makefile
index 8ac16d681..db4752513 100644
--- a/src/pkg/scanner/Makefile
+++ b/src/pkg/scanner/Makefile
@@ -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 ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=scanner
GOFILES=\
diff --git a/src/pkg/scanner/scanner.go b/src/pkg/scanner/scanner.go
index f60a4eed2..11aa9f43f 100644
--- a/src/pkg/scanner/scanner.go
+++ b/src/pkg/scanner/scanner.go
@@ -2,15 +2,15 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// A general-purpose scanner for UTF-8 encoded text. Takes an io.Reader
-// providing the source which then can be tokenized through repeated
-// calls to the Scan function. For compatibility with existing tools,
-// the NUL character is not allowed (implementation restriction).
+// A scanner and tokenizer for UTF-8-encoded text. Takes an io.Reader
+// providing the source, which then can be tokenized through repeated calls
+// to the Scan function. For compatibility with existing tools, the NUL
+// character is not allowed (implementation restriction).
//
-// By default, a Scanner skips white space and comments and
-// recognizes literals as defined by the Go language spec.
-// It may be customized to recognize only a subset of those
-// literals and to recognize different white space characters.
+// By default, a Scanner skips white space and Go comments and recognizes all
+// literals as defined by the Go language specification. It may be
+// customized to recognize only a subset of those literals and to recognize
+// different white space characters.
//
// Basic usage pattern:
//
@@ -158,7 +158,7 @@ type Scanner struct {
ErrorCount int
// The Mode field controls which tokens are recognized. For instance,
- // to recognize Ints, set the (1<<-Int) bit in Mode. The field may be
+ // to recognize Ints, set the ScanInts bit in Mode. The field may be
// changed at any time.
Mode uint
@@ -236,8 +236,10 @@ func (s *Scanner) next() int {
if s.srcEnd == 0 {
return EOF
}
- s.error(err.String())
- break
+ if err != os.EOF {
+ s.error(err.String())
+ break
+ }
}
}
// at least one byte
diff --git a/src/pkg/scanner/scanner_test.go b/src/pkg/scanner/scanner_test.go
index 563ceea0c..506f434fe 100644
--- a/src/pkg/scanner/scanner_test.go
+++ b/src/pkg/scanner/scanner_test.go
@@ -23,10 +23,7 @@ type StringReader struct {
func (r *StringReader) Read(p []byte) (n int, err os.Error) {
if r.step < len(r.data) {
s := r.data[r.step]
- for i := 0; i < len(s); i++ {
- p[i] = s[i]
- }
- n = len(s)
+ n = copy(p, s)
r.step++
} else {
err = os.EOF
@@ -53,14 +50,14 @@ func readRuneSegments(t *testing.T, segments []string) {
var segmentList = [][]string{
- []string{},
- []string{""},
- []string{"日", "本語"},
- []string{"\u65e5", "\u672c", "\u8a9e"},
- []string{"\U000065e5", " ", "\U0000672c", "\U00008a9e"},
- []string{"\xe6", "\x97\xa5\xe6", "\x9c\xac\xe8\xaa\x9e"},
- []string{"Hello", ", ", "World", "!"},
- []string{"Hello", ", ", "", "World", "!"},
+ {},
+ {""},
+ {"日", "本語"},
+ {"\u65e5", "\u672c", "\u8a9e"},
+ {"\U000065e5", " ", "\U0000672c", "\U00008a9e"},
+ {"\xe6", "\x97\xa5\xe6", "\x9c\xac\xe8\xaa\x9e"},
+ {"Hello", ", ", "World", "!"},
+ {"Hello", ", ", "", "World", "!"},
}
@@ -79,161 +76,161 @@ type token struct {
var f100 = "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
var tokenList = []token{
- token{Comment, "// line comments\n"},
- token{Comment, "//\n"},
- token{Comment, "////\n"},
- token{Comment, "// comment\n"},
- token{Comment, "// /* comment */\n"},
- token{Comment, "// // comment //\n"},
- token{Comment, "//" + f100 + "\n"},
-
- token{Comment, "// general comments\n"},
- token{Comment, "/**/"},
- token{Comment, "/***/"},
- token{Comment, "/* comment */"},
- token{Comment, "/* // comment */"},
- token{Comment, "/* /* comment */"},
- token{Comment, "/*\n comment\n*/"},
- token{Comment, "/*" + f100 + "*/"},
-
- token{Comment, "// identifiers\n"},
- token{Ident, "a"},
- token{Ident, "a0"},
- token{Ident, "foobar"},
- token{Ident, "abc123"},
- token{Ident, "LGTM"},
- token{Ident, "_"},
- token{Ident, "_abc123"},
- token{Ident, "abc123_"},
- token{Ident, "_abc_123_"},
- token{Ident, "_äöü"},
- token{Ident, "_本"},
+ {Comment, "// line comments\n"},
+ {Comment, "//\n"},
+ {Comment, "////\n"},
+ {Comment, "// comment\n"},
+ {Comment, "// /* comment */\n"},
+ {Comment, "// // comment //\n"},
+ {Comment, "//" + f100 + "\n"},
+
+ {Comment, "// general comments\n"},
+ {Comment, "/**/"},
+ {Comment, "/***/"},
+ {Comment, "/* comment */"},
+ {Comment, "/* // comment */"},
+ {Comment, "/* /* comment */"},
+ {Comment, "/*\n comment\n*/"},
+ {Comment, "/*" + f100 + "*/"},
+
+ {Comment, "// identifiers\n"},
+ {Ident, "a"},
+ {Ident, "a0"},
+ {Ident, "foobar"},
+ {Ident, "abc123"},
+ {Ident, "LGTM"},
+ {Ident, "_"},
+ {Ident, "_abc123"},
+ {Ident, "abc123_"},
+ {Ident, "_abc_123_"},
+ {Ident, "_äöü"},
+ {Ident, "_本"},
// TODO for unknown reasons these fail when checking the literals
/*
token{Ident, "äöü"},
token{Ident, "本"},
*/
- token{Ident, "a۰۱۸"},
- token{Ident, "foo६४"},
- token{Ident, "bar9876"},
- token{Ident, f100},
-
- token{Comment, "// decimal ints\n"},
- token{Int, "0"},
- token{Int, "1"},
- token{Int, "9"},
- token{Int, "42"},
- token{Int, "1234567890"},
-
- token{Comment, "// octal ints\n"},
- token{Int, "00"},
- token{Int, "01"},
- token{Int, "07"},
- token{Int, "042"},
- token{Int, "01234567"},
-
- token{Comment, "// hexadecimal ints\n"},
- token{Int, "0x0"},
- token{Int, "0x1"},
- token{Int, "0xf"},
- token{Int, "0x42"},
- token{Int, "0x123456789abcDEF"},
- token{Int, "0x" + f100},
- token{Int, "0X0"},
- token{Int, "0X1"},
- token{Int, "0XF"},
- token{Int, "0X42"},
- token{Int, "0X123456789abcDEF"},
- token{Int, "0X" + f100},
-
- token{Comment, "// floats\n"},
- token{Float, "0."},
- token{Float, "1."},
- token{Float, "42."},
- token{Float, "01234567890."},
- token{Float, ".0"},
- token{Float, ".1"},
- token{Float, ".42"},
- token{Float, ".0123456789"},
- token{Float, "0.0"},
- token{Float, "1.0"},
- token{Float, "42.0"},
- token{Float, "01234567890.0"},
- token{Float, "0e0"},
- token{Float, "1e0"},
- token{Float, "42e0"},
- token{Float, "01234567890e0"},
- token{Float, "0E0"},
- token{Float, "1E0"},
- token{Float, "42E0"},
- token{Float, "01234567890E0"},
- token{Float, "0e+10"},
- token{Float, "1e-10"},
- token{Float, "42e+10"},
- token{Float, "01234567890e-10"},
- token{Float, "0E+10"},
- token{Float, "1E-10"},
- token{Float, "42E+10"},
- token{Float, "01234567890E-10"},
-
- token{Comment, "// chars\n"},
- token{Char, `' '`},
- token{Char, `'a'`},
- token{Char, `'本'`},
- token{Char, `'\a'`},
- token{Char, `'\b'`},
- token{Char, `'\f'`},
- token{Char, `'\n'`},
- token{Char, `'\r'`},
- token{Char, `'\t'`},
- token{Char, `'\v'`},
- token{Char, `'\''`},
- token{Char, `'\000'`},
- token{Char, `'\777'`},
- token{Char, `'\x00'`},
- token{Char, `'\xff'`},
- token{Char, `'\u0000'`},
- token{Char, `'\ufA16'`},
- token{Char, `'\U00000000'`},
- token{Char, `'\U0000ffAB'`},
-
- token{Comment, "// strings\n"},
- token{String, `" "`},
- token{String, `"a"`},
- token{String, `"本"`},
- token{String, `"\a"`},
- token{String, `"\b"`},
- token{String, `"\f"`},
- token{String, `"\n"`},
- token{String, `"\r"`},
- token{String, `"\t"`},
- token{String, `"\v"`},
- token{String, `"\""`},
- token{String, `"\000"`},
- token{String, `"\777"`},
- token{String, `"\x00"`},
- token{String, `"\xff"`},
- token{String, `"\u0000"`},
- token{String, `"\ufA16"`},
- token{String, `"\U00000000"`},
- token{String, `"\U0000ffAB"`},
- token{String, `"` + f100 + `"`},
-
- token{Comment, "// raw strings\n"},
- token{String, "``"},
- token{String, "`\\`"},
- token{String, "`" + "\n\n/* foobar */\n\n" + "`"},
- token{String, "`" + f100 + "`"},
-
- token{Comment, "// individual characters\n"},
+ {Ident, "a۰۱۸"},
+ {Ident, "foo६४"},
+ {Ident, "bar9876"},
+ {Ident, f100},
+
+ {Comment, "// decimal ints\n"},
+ {Int, "0"},
+ {Int, "1"},
+ {Int, "9"},
+ {Int, "42"},
+ {Int, "1234567890"},
+
+ {Comment, "// octal ints\n"},
+ {Int, "00"},
+ {Int, "01"},
+ {Int, "07"},
+ {Int, "042"},
+ {Int, "01234567"},
+
+ {Comment, "// hexadecimal ints\n"},
+ {Int, "0x0"},
+ {Int, "0x1"},
+ {Int, "0xf"},
+ {Int, "0x42"},
+ {Int, "0x123456789abcDEF"},
+ {Int, "0x" + f100},
+ {Int, "0X0"},
+ {Int, "0X1"},
+ {Int, "0XF"},
+ {Int, "0X42"},
+ {Int, "0X123456789abcDEF"},
+ {Int, "0X" + f100},
+
+ {Comment, "// floats\n"},
+ {Float, "0."},
+ {Float, "1."},
+ {Float, "42."},
+ {Float, "01234567890."},
+ {Float, ".0"},
+ {Float, ".1"},
+ {Float, ".42"},
+ {Float, ".0123456789"},
+ {Float, "0.0"},
+ {Float, "1.0"},
+ {Float, "42.0"},
+ {Float, "01234567890.0"},
+ {Float, "0e0"},
+ {Float, "1e0"},
+ {Float, "42e0"},
+ {Float, "01234567890e0"},
+ {Float, "0E0"},
+ {Float, "1E0"},
+ {Float, "42E0"},
+ {Float, "01234567890E0"},
+ {Float, "0e+10"},
+ {Float, "1e-10"},
+ {Float, "42e+10"},
+ {Float, "01234567890e-10"},
+ {Float, "0E+10"},
+ {Float, "1E-10"},
+ {Float, "42E+10"},
+ {Float, "01234567890E-10"},
+
+ {Comment, "// chars\n"},
+ {Char, `' '`},
+ {Char, `'a'`},
+ {Char, `'本'`},
+ {Char, `'\a'`},
+ {Char, `'\b'`},
+ {Char, `'\f'`},
+ {Char, `'\n'`},
+ {Char, `'\r'`},
+ {Char, `'\t'`},
+ {Char, `'\v'`},
+ {Char, `'\''`},
+ {Char, `'\000'`},
+ {Char, `'\777'`},
+ {Char, `'\x00'`},
+ {Char, `'\xff'`},
+ {Char, `'\u0000'`},
+ {Char, `'\ufA16'`},
+ {Char, `'\U00000000'`},
+ {Char, `'\U0000ffAB'`},
+
+ {Comment, "// strings\n"},
+ {String, `" "`},
+ {String, `"a"`},
+ {String, `"本"`},
+ {String, `"\a"`},
+ {String, `"\b"`},
+ {String, `"\f"`},
+ {String, `"\n"`},
+ {String, `"\r"`},
+ {String, `"\t"`},
+ {String, `"\v"`},
+ {String, `"\""`},
+ {String, `"\000"`},
+ {String, `"\777"`},
+ {String, `"\x00"`},
+ {String, `"\xff"`},
+ {String, `"\u0000"`},
+ {String, `"\ufA16"`},
+ {String, `"\U00000000"`},
+ {String, `"\U0000ffAB"`},
+ {String, `"` + f100 + `"`},
+
+ {Comment, "// raw strings\n"},
+ {String, "``"},
+ {String, "`\\`"},
+ {String, "`" + "\n\n/* foobar */\n\n" + "`"},
+ {String, "`" + f100 + "`"},
+
+ {Comment, "// individual characters\n"},
// NUL character is not allowed
- token{'\x01', "\x01"},
- token{' ' - 1, string(' ' - 1)},
- token{'+', "+"},
- token{'/', "/"},
- token{'.', "."},
- token{'~', "~"},
- token{'(', "("},
+ {'\x01', "\x01"},
+ {' ' - 1, string(' ' - 1)},
+ {'+', "+"},
+ {'/', "/"},
+ {'.', "."},
+ {'~', "~"},
+ {'(', "("},
}
diff --git a/src/pkg/smtp/Makefile b/src/pkg/smtp/Makefile
new file mode 100644
index 000000000..0e7d8d5f7
--- /dev/null
+++ b/src/pkg/smtp/Makefile
@@ -0,0 +1,12 @@
+# Copyright 2010 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include ../../Make.inc
+
+TARG=smtp
+GOFILES=\
+ auth.go\
+ smtp.go\
+
+include ../../Make.pkg
diff --git a/src/pkg/smtp/auth.go b/src/pkg/smtp/auth.go
new file mode 100644
index 000000000..dd27f8e93
--- /dev/null
+++ b/src/pkg/smtp/auth.go
@@ -0,0 +1,69 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package smtp
+
+import (
+ "os"
+)
+
+// Auth is implemented by an SMTP authentication mechanism.
+type Auth interface {
+ // Start begins an authentication with a server.
+ // It returns the name of the authentication protocol
+ // and optionally data to include in the initial AUTH message
+ // sent to the server. It can return proto == "" to indicate
+ // that the authentication should be skipped.
+ // If it returns a non-nil os.Error, the SMTP client aborts
+ // the authentication attempt and closes the connection.
+ Start(server *ServerInfo) (proto string, toServer []byte, err os.Error)
+
+ // Next continues the authentication. The server has just sent
+ // the fromServer data. If more is true, the server expects a
+ // response, which Next should return as toServer; otherwise
+ // Next should return toServer == nil.
+ // If Next returns a non-nil os.Error, the SMTP client aborts
+ // the authentication attempt and closes the connection.
+ Next(fromServer []byte, more bool) (toServer []byte, err os.Error)
+}
+
+// ServerInfo records information about an SMTP server.
+type ServerInfo struct {
+ Name string // SMTP server name
+ TLS bool // using TLS, with valid certificate for Name
+ Auth []string // advertised authentication mechanisms
+}
+
+type plainAuth struct {
+ identity, username, password string
+ host string
+}
+
+// PlainAuth returns an Auth that implements the PLAIN authentication
+// mechanism as defined in RFC 4616.
+// The returned Auth uses the given username and password to authenticate
+// on TLS connections to host and act as identity. Usually identity will be
+// left blank to act as username.
+func PlainAuth(identity, username, password, host string) Auth {
+ return &plainAuth{identity, username, password, host}
+}
+
+func (a *plainAuth) Start(server *ServerInfo) (string, []byte, os.Error) {
+ if !server.TLS {
+ return "", nil, os.NewError("unencrypted connection")
+ }
+ if server.Name != a.host {
+ return "", nil, os.NewError("wrong host name")
+ }
+ resp := []byte(a.identity + "\x00" + a.username + "\x00" + a.password)
+ return "PLAIN", resp, nil
+}
+
+func (a *plainAuth) Next(fromServer []byte, more bool) ([]byte, os.Error) {
+ if more {
+ // We've already sent everything.
+ return nil, os.NewError("unexpected server challenge")
+ }
+ return nil, nil
+}
diff --git a/src/pkg/smtp/smtp.go b/src/pkg/smtp/smtp.go
new file mode 100644
index 000000000..2f6d2f31a
--- /dev/null
+++ b/src/pkg/smtp/smtp.go
@@ -0,0 +1,295 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package smtp implements the Simple Mail Transfer Protocol as defined in RFC 5321.
+// It also implements the following extensions:
+// 8BITMIME RFC 1652
+// AUTH RFC 2554
+// STARTTLS RFC 3207
+// Additional extensions may be handled by clients.
+package smtp
+
+import (
+ "crypto/tls"
+ "encoding/base64"
+ "io"
+ "os"
+ "net"
+ "net/textproto"
+ "strings"
+)
+
+// A Client represents a client connection to an SMTP server.
+type Client struct {
+ // Text is the textproto.Conn used by the Client. It is exported to allow for
+ // clients to add extensions.
+ Text *textproto.Conn
+ // keep a reference to the connection so it can be used to create a TLS
+ // connection later
+ conn net.Conn
+ // whether the Client is using TLS
+ tls bool
+ serverName string
+ // map of supported extensions
+ ext map[string]string
+ // supported auth mechanisms
+ auth []string
+}
+
+// Dial returns a new Client connected to an SMTP server at addr.
+func Dial(addr string) (*Client, os.Error) {
+ conn, err := net.Dial("tcp", "", addr)
+ if err != nil {
+ return nil, err
+ }
+ host := addr[:strings.Index(addr, ":")]
+ return NewClient(conn, host)
+}
+
+// NewClient returns a new Client using an existing connection and host as a
+// server name to be used when authenticating.
+func NewClient(conn net.Conn, host string) (*Client, os.Error) {
+ text := textproto.NewConn(conn)
+ _, msg, err := text.ReadResponse(220)
+ if err != nil {
+ text.Close()
+ return nil, err
+ }
+ c := &Client{Text: text, conn: conn, serverName: host}
+ if strings.Contains(msg, "ESMTP") {
+ err = c.ehlo()
+ } else {
+ err = c.helo()
+ }
+ return c, err
+}
+
+// cmd is a convenience function that sends a command and returns the response
+func (c *Client) cmd(expectCode int, format string, args ...interface{}) (int, string, os.Error) {
+ id, err := c.Text.Cmd(format, args...)
+ if err != nil {
+ return 0, "", err
+ }
+ c.Text.StartResponse(id)
+ defer c.Text.EndResponse(id)
+ code, msg, err := c.Text.ReadResponse(expectCode)
+ return code, msg, err
+}
+
+// helo sends the HELO greeting to the server. It should be used only when the
+// server does not support ehlo.
+func (c *Client) helo() os.Error {
+ c.ext = nil
+ _, _, err := c.cmd(250, "HELO localhost")
+ return err
+}
+
+// ehlo sends the EHLO (extended hello) greeting to the server. It
+// should be the preferred greeting for servers that support it.
+func (c *Client) ehlo() os.Error {
+ _, msg, err := c.cmd(250, "EHLO localhost")
+ if err != nil {
+ return err
+ }
+ ext := make(map[string]string)
+ extList := strings.Split(msg, "\n", -1)
+ if len(extList) > 1 {
+ extList = extList[1:]
+ for _, line := range extList {
+ args := strings.Split(line, " ", 2)
+ if len(args) > 1 {
+ ext[args[0]] = args[1]
+ } else {
+ ext[args[0]] = ""
+ }
+ }
+ }
+ if mechs, ok := ext["AUTH"]; ok {
+ c.auth = strings.Split(mechs, " ", -1)
+ }
+ c.ext = ext
+ return err
+}
+
+// StartTLS sends the STARTTLS command and encrypts all further communication.
+// Only servers that advertise the STARTTLS extension support this function.
+func (c *Client) StartTLS(config *tls.Config) os.Error {
+ _, _, err := c.cmd(220, "STARTTLS")
+ if err != nil {
+ return err
+ }
+ c.conn = tls.Client(c.conn, config)
+ c.Text = textproto.NewConn(c.conn)
+ c.tls = true
+ return c.ehlo()
+}
+
+// Verify checks the validity of an email address on the server.
+// If Verify returns nil, the address is valid. A non-nil return
+// does not necessarily indicate an invalid address. Many servers
+// will not verify addresses for security reasons.
+func (c *Client) Verify(addr string) os.Error {
+ _, _, err := c.cmd(250, "VRFY %s", addr)
+ return err
+}
+
+// Auth authenticates a client using the provided authentication mechanism.
+// A failed authentication closes the connection.
+// Only servers that advertise the AUTH extension support this function.
+func (c *Client) Auth(a Auth) os.Error {
+ encoding := base64.StdEncoding
+ mech, resp, err := a.Start(&ServerInfo{c.serverName, c.tls, c.auth})
+ if err != nil {
+ c.Quit()
+ return err
+ }
+ resp64 := make([]byte, encoding.EncodedLen(len(resp)))
+ encoding.Encode(resp64, resp)
+ code, msg64, err := c.cmd(0, "AUTH %s %s", mech, resp64)
+ for err == nil {
+ var msg []byte
+ switch code {
+ case 334:
+ msg = make([]byte, encoding.DecodedLen(len(msg64)))
+ _, err = encoding.Decode(msg, []byte(msg64))
+ case 235:
+ // the last message isn't base64 because it isn't a challenge
+ msg = []byte(msg64)
+ default:
+ err = &textproto.Error{code, msg64}
+ }
+ resp, err = a.Next(msg, code == 334)
+ if err != nil {
+ // abort the AUTH
+ c.cmd(501, "*")
+ c.Quit()
+ break
+ }
+ if resp == nil {
+ break
+ }
+ resp64 = make([]byte, encoding.EncodedLen(len(resp)))
+ encoding.Encode(resp64, resp)
+ code, msg64, err = c.cmd(0, string(resp64))
+ }
+ return err
+}
+
+// Mail issues a MAIL command to the server using the provided email address.
+// If the server supports the 8BITMIME extension, Mail adds the BODY=8BITMIME
+// parameter.
+// This initiates a mail transaction and is followed by one or more Rcpt calls.
+func (c *Client) Mail(from string) os.Error {
+ cmdStr := "MAIL FROM:<%s>"
+ if c.ext != nil {
+ if _, ok := c.ext["8BITMIME"]; ok {
+ cmdStr += " BODY=8BITMIME"
+ }
+ }
+ _, _, err := c.cmd(250, cmdStr, from)
+ return err
+}
+
+// Rcpt issues a RCPT command to the server using the provided email address.
+// A call to Rcpt must be preceded by a call to Mail and may be followed by
+// a Data call or another Rcpt call.
+func (c *Client) Rcpt(to string) os.Error {
+ _, _, err := c.cmd(25, "RCPT TO:<%s>", to)
+ return err
+}
+
+type dataCloser struct {
+ c *Client
+ io.WriteCloser
+}
+
+func (d *dataCloser) Close() os.Error {
+ d.WriteCloser.Close()
+ _, _, err := d.c.Text.ReadResponse(250)
+ return err
+}
+
+// Data issues a DATA command to the server and returns a writer that
+// can be used to write the data. The caller should close the writer
+// before calling any more methods on c.
+// A call to Data must be preceded by one or more calls to Rcpt.
+func (c *Client) Data() (io.WriteCloser, os.Error) {
+ _, _, err := c.cmd(354, "DATA")
+ if err != nil {
+ return nil, err
+ }
+ return &dataCloser{c, c.Text.DotWriter()}, nil
+}
+
+// SendMail connects to the server at addr, switches to TLS if possible,
+// authenticates with mechanism a if possible, and then sends an email from
+// address from, to addresses to, with message msg.
+func SendMail(addr string, a Auth, from string, to []string, msg []byte) os.Error {
+ c, err := Dial(addr)
+ if err != nil {
+ return err
+ }
+ if ok, _ := c.Extension("STARTTLS"); ok {
+ if err = c.StartTLS(nil); err != nil {
+ return err
+ }
+ }
+ if a != nil && c.ext != nil {
+ if _, ok := c.ext["AUTH"]; ok {
+ if err = c.Auth(a); err != nil {
+ return err
+ }
+ }
+ }
+ if err = c.Mail(from); err != nil {
+ return err
+ }
+ for _, addr := range to {
+ if err = c.Rcpt(addr); err != nil {
+ return err
+ }
+ }
+ w, err := c.Data()
+ if err != nil {
+ return err
+ }
+ _, err = w.Write(msg)
+ if err != nil {
+ return err
+ }
+ err = w.Close()
+ if err != nil {
+ return err
+ }
+ return c.Quit()
+}
+
+// Extension reports whether an extension is support by the server.
+// The extension name is case-insensitive. If the extension is supported,
+// Extension also returns a string that contains any parameters the
+// server specifies for the extension.
+func (c *Client) Extension(ext string) (bool, string) {
+ if c.ext == nil {
+ return false, ""
+ }
+ ext = strings.ToUpper(ext)
+ param, ok := c.ext[ext]
+ return ok, param
+}
+
+// Reset sends the RSET command to the server, aborting the current mail
+// transaction.
+func (c *Client) Reset() os.Error {
+ _, _, err := c.cmd(250, "RSET")
+ return err
+}
+
+// Quit sends the QUIT command and closes the connection to the server.
+func (c *Client) Quit() os.Error {
+ _, _, err := c.cmd(221, "QUIT")
+ if err != nil {
+ return err
+ }
+ return c.Text.Close()
+}
diff --git a/src/pkg/smtp/smtp_test.go b/src/pkg/smtp/smtp_test.go
new file mode 100644
index 000000000..49363adf0
--- /dev/null
+++ b/src/pkg/smtp/smtp_test.go
@@ -0,0 +1,182 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package smtp
+
+import (
+ "bufio"
+ "bytes"
+ "io"
+ "net/textproto"
+ "os"
+ "strings"
+ "testing"
+)
+
+type authTest struct {
+ auth Auth
+ challenges []string
+ name string
+ responses []string
+}
+
+var authTests = []authTest{
+ {PlainAuth("", "user", "pass", "testserver"), []string{}, "PLAIN", []string{"\x00user\x00pass"}},
+ {PlainAuth("foo", "bar", "baz", "testserver"), []string{}, "PLAIN", []string{"foo\x00bar\x00baz"}},
+}
+
+func TestAuth(t *testing.T) {
+testLoop:
+ for i, test := range authTests {
+ name, resp, err := test.auth.Start(&ServerInfo{"testserver", true, nil})
+ if name != test.name {
+ t.Errorf("#%d got name %s, expected %s", i, name, test.name)
+ }
+ if !bytes.Equal(resp, []byte(test.responses[0])) {
+ t.Errorf("#%d got response %s, expected %s", i, resp, test.responses[0])
+ }
+ if err != nil {
+ t.Errorf("#%d error: %s", i, err.String())
+ }
+ for j := range test.challenges {
+ challenge := []byte(test.challenges[j])
+ expected := []byte(test.responses[j+1])
+ resp, err := test.auth.Next(challenge, true)
+ if err != nil {
+ t.Errorf("#%d error: %s", i, err.String())
+ continue testLoop
+ }
+ if !bytes.Equal(resp, expected) {
+ t.Errorf("#%d got %s, expected %s", i, resp, expected)
+ continue testLoop
+ }
+ }
+ }
+}
+
+type faker struct {
+ io.ReadWriter
+}
+
+func (f faker) Close() os.Error {
+ return nil
+}
+
+func TestBasic(t *testing.T) {
+ basicServer = strings.Join(strings.Split(basicServer, "\n", -1), "\r\n")
+ basicClient = strings.Join(strings.Split(basicClient, "\n", -1), "\r\n")
+
+ var cmdbuf bytes.Buffer
+ bcmdbuf := bufio.NewWriter(&cmdbuf)
+ var fake faker
+ fake.ReadWriter = bufio.NewReadWriter(bufio.NewReader(strings.NewReader(basicServer)), bcmdbuf)
+ c := &Client{Text: textproto.NewConn(fake)}
+
+ if err := c.helo(); err != nil {
+ t.Fatalf("HELO failed: %s", err.String())
+ }
+ if err := c.ehlo(); err == nil {
+ t.Fatalf("Expected first EHLO to fail")
+ }
+ if err := c.ehlo(); err != nil {
+ t.Fatalf("Second EHLO failed: %s", err.String())
+ }
+
+ if ok, args := c.Extension("aUtH"); !ok || args != "LOGIN PLAIN" {
+ t.Fatalf("Expected AUTH supported")
+ }
+ if ok, _ := c.Extension("DSN"); ok {
+ t.Fatalf("Shouldn't support DSN")
+ }
+
+ if err := c.Mail("user@gmail.com"); err == nil {
+ t.Fatalf("MAIL should require authentication")
+ }
+
+ if err := c.Verify("user1@gmail.com"); err == nil {
+ t.Fatalf("First VRFY: expected no verification")
+ }
+ if err := c.Verify("user2@gmail.com"); err != nil {
+ t.Fatalf("Second VRFY: expected verification, got %s", err)
+ }
+
+ // fake TLS so authentication won't complain
+ c.tls = true
+ c.serverName = "smtp.google.com"
+ if err := c.Auth(PlainAuth("", "user", "pass", "smtp.google.com")); err != nil {
+ t.Fatalf("AUTH failed: %s", err.String())
+ }
+
+ if err := c.Mail("user@gmail.com"); err != nil {
+ t.Fatalf("MAIL failed: %s", err.String())
+ }
+ if err := c.Rcpt("golang-nuts@googlegroups.com"); err != nil {
+ t.Fatalf("RCPT failed: %s", err.String())
+ }
+ msg := `From: user@gmail.com
+To: golang-nuts@googlegroups.com
+Subject: Hooray for Go
+
+Line 1
+.Leading dot line .
+Goodbye.`
+ w, err := c.Data()
+ if err != nil {
+ t.Fatalf("DATA failed: %s", err.String())
+ }
+ if _, err := w.Write([]byte(msg)); err != nil {
+ t.Fatalf("Data write failed: %s", err.String())
+ }
+ if err := w.Close(); err != nil {
+ t.Fatalf("Bad data response: %s", err.String())
+ }
+
+ if err := c.Quit(); err != nil {
+ t.Fatalf("QUIT failed: %s", err.String())
+ }
+
+ bcmdbuf.Flush()
+ actualcmds := cmdbuf.String()
+ if basicClient != actualcmds {
+ t.Fatalf("Got:\n%s\nExpected:\n%s", actualcmds, basicClient)
+ }
+}
+
+var basicServer = `250 mx.google.com at your service
+502 Unrecognized command.
+250-mx.google.com at your service
+250-SIZE 35651584
+250-AUTH LOGIN PLAIN
+250 8BITMIME
+530 Authentication required
+252 Send some mail, I'll try my best
+250 User is valid
+235 Accepted
+250 Sender OK
+250 Receiver OK
+354 Go ahead
+250 Data OK
+221 OK
+`
+
+var basicClient = `HELO localhost
+EHLO localhost
+EHLO localhost
+MAIL FROM:<user@gmail.com> BODY=8BITMIME
+VRFY user1@gmail.com
+VRFY user2@gmail.com
+AUTH PLAIN AHVzZXIAcGFzcw==
+MAIL FROM:<user@gmail.com> BODY=8BITMIME
+RCPT TO:<golang-nuts@googlegroups.com>
+DATA
+From: user@gmail.com
+To: golang-nuts@googlegroups.com
+Subject: Hooray for Go
+
+Line 1
+..Leading dot line .
+Goodbye.
+.
+QUIT
+`
diff --git a/src/pkg/sort/Makefile b/src/pkg/sort/Makefile
index 57c9f8f47..9deaabfec 100644
--- a/src/pkg/sort/Makefile
+++ b/src/pkg/sort/Makefile
@@ -2,10 +2,11 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=sort
GOFILES=\
+ search.go\
sort.go\
include ../../Make.pkg
diff --git a/src/pkg/sort/search.go b/src/pkg/sort/search.go
new file mode 100644
index 000000000..b3ddd2dfa
--- /dev/null
+++ b/src/pkg/sort/search.go
@@ -0,0 +1,110 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file implements binary search.
+
+package sort
+
+// Search uses binary search to find and return the smallest index i
+// in [0, n) at which f(i) is true, assuming that on the range [0, n),
+// f(i) == true implies f(i+1) == true. That is, Search requires that
+// f is false for some (possibly empty) prefix of the input range [0, n)
+// and then true for the (possibly empty) remainder; Search returns
+// the first true index. If there is no such index, Search returns n.
+// Search calls f(i) only for i in the range [0, n).
+//
+// A common use of Search is to find the index i for a value x in
+// a sorted, indexable data structure like an array or slice.
+// In this case, the argument f, typically a closure, captures the value
+// to be searched for, and how the data structure is indexed and
+// ordered.
+//
+// For instance, given a slice data sorted in ascending order,
+// the call Search(len(data), func(i int) bool { return data[i] >= 23 })
+// returns the smallest index i such that data[i] >= 23. If the caller
+// wants to find whether 23 is in the slice, it must test data[i] == 23
+// separately.
+//
+// Searching data sorted in descending order would use the <=
+// operator instead of the >= operator.
+//
+// To complete the example above, the following code tries to find the value
+// x in an integer slice data sorted in ascending order:
+//
+// x := 23
+// i := sort.Search(len(data), func(i int) bool { return data[i] >= x })
+// if i < len(data) && data[i] == x {
+// // x is present at data[i]
+// } else {
+// // x is not present in data,
+// // but i is the index where it would be inserted.
+// }
+//
+// As a more whimsical example, this program guesses your number:
+//
+// func GuessingGame() {
+// var s string
+// fmt.Printf("Pick an integer from 0 to 100.\n")
+// answer := sort.Search(100, func(i int) bool {
+// fmt.Printf("Is your number <= %d? ", i)
+// fmt.Scanf("%s", &s)
+// return s != "" && s[0] == 'y'
+// })
+// fmt.Printf("Your number is %d.\n", answer)
+// }
+//
+func Search(n int, f func(int) bool) int {
+ // Define f(-1) == false and f(n) == true.
+ // Invariant: f(i-1) == false, f(j) == true.
+ i, j := 0, n
+ for i < j {
+ h := i + (j-i)/2 // avoid overflow when computing h
+ // i ≤ h < j
+ if !f(h) {
+ i = h + 1 // preserves f(i-1) == false
+ } else {
+ j = h // preserves f(j) == true
+ }
+ }
+ // i == j, f(i-1) == false, and f(j) (= f(i)) == true => answer is i.
+ return i
+}
+
+
+// Convenience wrappers for common cases.
+
+// SearchInts searches x in a sorted slice of ints and returns the index
+// as specified by Search. The array must be sorted in ascending order.
+//
+func SearchInts(a []int, x int) int {
+ return Search(len(a), func(i int) bool { return a[i] >= x })
+}
+
+
+// SearchFloats searches x in a sorted slice of floats and returns the index
+// as specified by Search. The array must be sorted in ascending order.
+//
+func SearchFloats(a []float, x float) int {
+ return Search(len(a), func(i int) bool { return a[i] >= x })
+}
+
+
+// SearchStrings searches x in a sorted slice of strings and returns the index
+// as specified by Search. The array must be sorted in ascending order.
+//
+func SearchStrings(a []string, x string) int {
+ return Search(len(a), func(i int) bool { return a[i] >= x })
+}
+
+
+// Search returns the result of applying SearchInts to the receiver and x.
+func (p IntArray) Search(x int) int { return SearchInts(p, x) }
+
+
+// Search returns the result of applying SearchFloats to the receiver and x.
+func (p FloatArray) Search(x float) int { return SearchFloats(p, x) }
+
+
+// Search returns the result of applying SearchStrings to the receiver and x.
+func (p StringArray) Search(x string) int { return SearchStrings(p, x) }
diff --git a/src/pkg/sort/search_test.go b/src/pkg/sort/search_test.go
new file mode 100644
index 000000000..e16e2c93f
--- /dev/null
+++ b/src/pkg/sort/search_test.go
@@ -0,0 +1,137 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sort
+
+import "testing"
+
+
+func f(a []int, x int) func(int) bool {
+ return func(i int) bool {
+ return a[i] >= x
+ }
+}
+
+
+var data = []int{0: -10, 1: -5, 2: 0, 3: 1, 4: 2, 5: 3, 6: 5, 7: 7, 8: 11, 9: 100, 10: 100, 11: 100, 12: 1000, 13: 10000}
+
+var tests = []struct {
+ name string
+ n int
+ f func(int) bool
+ i int
+}{
+ {"empty", 0, nil, 0},
+ {"1 1", 1, func(i int) bool { return i >= 1 }, 1},
+ {"1 true", 1, func(i int) bool { return true }, 0},
+ {"1 false", 1, func(i int) bool { return false }, 1},
+ {"1e9 991", 1e9, func(i int) bool { return i >= 991 }, 991},
+ {"1e9 true", 1e9, func(i int) bool { return true }, 0},
+ {"1e9 false", 1e9, func(i int) bool { return false }, 1e9},
+ {"data -20", len(data), f(data, -20), 0},
+ {"data -10", len(data), f(data, -10), 0},
+ {"data -9", len(data), f(data, -9), 1},
+ {"data -6", len(data), f(data, -6), 1},
+ {"data -5", len(data), f(data, -5), 1},
+ {"data 3", len(data), f(data, 3), 5},
+ {"data 11", len(data), f(data, 11), 8},
+ {"data 99", len(data), f(data, 99), 9},
+ {"data 100", len(data), f(data, 100), 9},
+ {"data 101", len(data), f(data, 101), 12},
+ {"data 10000", len(data), f(data, 10000), 13},
+ {"data 10001", len(data), f(data, 10001), 14},
+ {"descending a", 7, func(i int) bool { return []int{99, 99, 59, 42, 7, 0, -1, -1}[i] <= 7 }, 4},
+ {"descending 7", 1e9, func(i int) bool { return 1e9-i <= 7 }, 1e9 - 7},
+ {"overflow", 2e9, func(i int) bool { return false }, 2e9},
+}
+
+
+func TestSearch(t *testing.T) {
+ for _, e := range tests {
+ i := Search(e.n, e.f)
+ if i != e.i {
+ t.Errorf("%s: expected index %d; got %d", e.name, e.i, i)
+ }
+ }
+}
+
+
+// log2 computes the binary logarithm of x, rounded up to the next integer.
+// (log2(0) == 0, log2(1) == 0, log2(2) == 1, log2(3) == 2, etc.)
+//
+func log2(x int) int {
+ n := 0
+ for p := 1; p < x; p += p {
+ // p == 2**n
+ n++
+ }
+ // p/2 < x <= p == 2**n
+ return n
+}
+
+
+func TestSearchEfficiency(t *testing.T) {
+ n := 100
+ step := 1
+ for exp := 2; exp < 10; exp++ {
+ // n == 10**exp
+ // step == 10**(exp-2)
+ max := log2(n)
+ for x := 0; x < n; x += step {
+ count := 0
+ i := Search(n, func(i int) bool { count++; return i >= x })
+ if i != x {
+ t.Errorf("n = %d: expected index %d; got %d", n, x, i)
+ }
+ if count > max {
+ t.Errorf("n = %d, x = %d: expected <= %d calls; got %d", n, x, max, count)
+ }
+ }
+ n *= 10
+ step *= 10
+ }
+}
+
+
+// Smoke tests for convenience wrappers - not comprehensive.
+
+var fdata = []float{0: -3.14, 1: 0, 2: 1, 3: 2, 4: 1000.7}
+var sdata = []string{0: "f", 1: "foo", 2: "foobar", 3: "x"}
+
+var wrappertests = []struct {
+ name string
+ result int
+ i int
+}{
+ {"SearchInts", SearchInts(data, 11), 8},
+ {"SearchFloats", SearchFloats(fdata, 2.1), 4},
+ {"SearchStrings", SearchStrings(sdata, ""), 0},
+ {"IntArray.Search", IntArray(data).Search(0), 2},
+ {"FloatArray.Search", FloatArray(fdata).Search(2.0), 3},
+ {"StringArray.Search", StringArray(sdata).Search("x"), 3},
+}
+
+
+func TestSearchWrappers(t *testing.T) {
+ for _, e := range wrappertests {
+ if e.result != e.i {
+ t.Errorf("%s: expected index %d; got %d", e.name, e.i, e.result)
+ }
+ }
+}
+
+
+// Abstract exhaustive test: all sizes up to 100,
+// all possible return values. If there are any small
+// corner cases, this test exercises them.
+func TestSearchExhaustive(t *testing.T) {
+ for size := 0; size <= 100; size++ {
+ for targ := 0; targ <= size; targ++ {
+ i := Search(size, func(i int) bool { return i >= targ })
+ if i != targ {
+ t.Errorf("Search(%d, %d) = %d", size, targ, i)
+ }
+ }
+ }
+}
diff --git a/src/pkg/sort/sort.go b/src/pkg/sort/sort.go
index c5b848414..02e647fca 100644
--- a/src/pkg/sort/sort.go
+++ b/src/pkg/sort/sort.go
@@ -63,7 +63,7 @@ func swapRange(data Interface, a, b, n int) {
}
func doPivot(data Interface, lo, hi int) (midlo, midhi int) {
- m := (lo + hi) / 2
+ m := lo + (hi-lo)/2 // Written like this to avoid integer overflow.
if hi-lo > 40 {
// Tukey's ``Ninther,'' median of three medians of three.
s := (hi - lo) / 8
@@ -122,11 +122,19 @@ func doPivot(data Interface, lo, hi int) (midlo, midhi int) {
}
func quickSort(data Interface, a, b int) {
- if b-a > 7 {
+ for b-a > 7 {
mlo, mhi := doPivot(data, a, b)
- quickSort(data, a, mlo)
- quickSort(data, mhi, b)
- } else if b-a > 1 {
+ // Avoiding recursion on the larger subproblem guarantees
+ // a stack depth of at most lg(b-a).
+ if mlo-a < b-mhi {
+ quickSort(data, a, mlo)
+ a = mhi // i.e., quickSort(data, mhi, b)
+ } else {
+ quickSort(data, mhi, b)
+ b = mlo // i.e., quickSort(data, a, mlo)
+ }
+ }
+ if b-a > 1 {
insertionSort(data, a, b)
}
}
diff --git a/src/pkg/strconv/Makefile b/src/pkg/strconv/Makefile
index 57849a821..823355d85 100644
--- a/src/pkg/strconv/Makefile
+++ b/src/pkg/strconv/Makefile
@@ -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 ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=strconv
GOFILES=\
diff --git a/src/pkg/strconv/atob_test.go b/src/pkg/strconv/atob_test.go
index ffad4b21b..497df5b18 100644
--- a/src/pkg/strconv/atob_test.go
+++ b/src/pkg/strconv/atob_test.go
@@ -17,18 +17,18 @@ type atobTest struct {
}
var atobtests = []atobTest{
- atobTest{"", false, os.EINVAL},
- atobTest{"asdf", false, os.EINVAL},
- atobTest{"0", false, nil},
- atobTest{"f", false, nil},
- atobTest{"F", false, nil},
- atobTest{"FALSE", false, nil},
- atobTest{"false", false, nil},
- atobTest{"1", true, nil},
- atobTest{"t", true, nil},
- atobTest{"T", true, nil},
- atobTest{"TRUE", true, nil},
- atobTest{"true", true, nil},
+ {"", false, os.EINVAL},
+ {"asdf", false, os.EINVAL},
+ {"0", false, nil},
+ {"f", false, nil},
+ {"F", false, nil},
+ {"FALSE", false, nil},
+ {"false", false, nil},
+ {"1", true, nil},
+ {"t", true, nil},
+ {"T", true, nil},
+ {"TRUE", true, nil},
+ {"true", true, nil},
}
func TestAtob(t *testing.T) {
@@ -46,7 +46,7 @@ func TestAtob(t *testing.T) {
}
} else {
if e != nil {
- t.Errorf("%s: expected no error but got %s", test.in, test.err, e)
+ t.Errorf("%s: expected no error but got %s", test.in, e)
}
if b != test.out {
t.Errorf("%s: expected %t but got %t", test.in, test.out, b)
diff --git a/src/pkg/strconv/atof.go b/src/pkg/strconv/atof.go
index 262a8b53c..bcb138f7a 100644
--- a/src/pkg/strconv/atof.go
+++ b/src/pkg/strconv/atof.go
@@ -19,6 +19,40 @@ import (
var optimize = true // can change for testing
+func equalIgnoreCase(s1, s2 string) bool {
+ if len(s1) != len(s2) {
+ return false
+ }
+ for i := 0; i < len(s1); i++ {
+ c1 := s1[i]
+ if 'A' <= c1 && c1 <= 'Z' {
+ c1 += 'a' - 'A'
+ }
+ c2 := s2[i]
+ if 'A' <= c2 && c2 <= 'Z' {
+ c2 += 'a' - 'A'
+ }
+ if c1 != c2 {
+ return false
+ }
+ }
+ return true
+}
+
+func special(s string) (f float64, ok bool) {
+ switch {
+ case equalIgnoreCase(s, "nan"):
+ return math.NaN(), true
+ case equalIgnoreCase(s, "-inf"):
+ return math.Inf(-1), true
+ case equalIgnoreCase(s, "+inf"):
+ return math.Inf(1), true
+ case equalIgnoreCase(s, "inf"):
+ return math.Inf(1), true
+ }
+ return
+}
+
// TODO(rsc): Better truncation handling.
func stringToDecimal(s string) (neg bool, d *decimal, trunc bool, ok bool) {
i := 0
@@ -73,7 +107,7 @@ func stringToDecimal(s string) (neg bool, d *decimal, trunc bool, ok bool) {
// just be sure to move the decimal point by
// a lot (say, 100000). it doesn't matter if it's
// not the exact number.
- if i < len(s) && s[i] == 'e' {
+ if i < len(s) && (s[i] == 'e' || s[i] == 'E') {
i++
if i >= len(s) {
return
@@ -320,6 +354,10 @@ func decimalAtof32(neg bool, d *decimal, trunc bool) (f float32, ok bool) {
// away from the largest floating point number of the given size,
// Atof32 returns f = ±Inf, err.Error = os.ERANGE.
func Atof32(s string) (f float32, err os.Error) {
+ if val, ok := special(s); ok {
+ return float32(val), nil
+ }
+
neg, d, trunc, ok := stringToDecimal(s)
if !ok {
return 0, &NumError{s, os.EINVAL}
@@ -341,6 +379,10 @@ func Atof32(s string) (f float32, err os.Error) {
// Except for the type of its result, its definition is the same as that
// of Atof32.
func Atof64(s string) (f float64, err os.Error) {
+ if val, ok := special(s); ok {
+ return val, nil
+ }
+
neg, d, trunc, ok := stringToDecimal(s)
if !ok {
return 0, &NumError{s, os.EINVAL}
diff --git a/src/pkg/strconv/atof_test.go b/src/pkg/strconv/atof_test.go
index 0039a6e44..68c50bfbe 100644
--- a/src/pkg/strconv/atof_test.go
+++ b/src/pkg/strconv/atof_test.go
@@ -18,80 +18,91 @@ type atofTest struct {
}
var atoftests = []atofTest{
- atofTest{"", "0", os.EINVAL},
- atofTest{"1", "1", nil},
- atofTest{"+1", "1", nil},
- atofTest{"1x", "0", os.EINVAL},
- atofTest{"1.1.", "0", os.EINVAL},
- atofTest{"1e23", "1e+23", nil},
- atofTest{"100000000000000000000000", "1e+23", nil},
- atofTest{"1e-100", "1e-100", nil},
- atofTest{"123456700", "1.234567e+08", nil},
- atofTest{"99999999999999974834176", "9.999999999999997e+22", nil},
- atofTest{"100000000000000000000001", "1.0000000000000001e+23", nil},
- atofTest{"100000000000000008388608", "1.0000000000000001e+23", nil},
- atofTest{"100000000000000016777215", "1.0000000000000001e+23", nil},
- atofTest{"100000000000000016777216", "1.0000000000000003e+23", nil},
- atofTest{"-1", "-1", nil},
- atofTest{"-0", "-0", nil},
- atofTest{"1e-20", "1e-20", nil},
- atofTest{"625e-3", "0.625", nil},
+ {"", "0", os.EINVAL},
+ {"1", "1", nil},
+ {"+1", "1", nil},
+ {"1x", "0", os.EINVAL},
+ {"1.1.", "0", os.EINVAL},
+ {"1e23", "1e+23", nil},
+ {"1E23", "1e+23", nil},
+ {"100000000000000000000000", "1e+23", nil},
+ {"1e-100", "1e-100", nil},
+ {"123456700", "1.234567e+08", nil},
+ {"99999999999999974834176", "9.999999999999997e+22", nil},
+ {"100000000000000000000001", "1.0000000000000001e+23", nil},
+ {"100000000000000008388608", "1.0000000000000001e+23", nil},
+ {"100000000000000016777215", "1.0000000000000001e+23", nil},
+ {"100000000000000016777216", "1.0000000000000003e+23", nil},
+ {"-1", "-1", nil},
+ {"-0", "-0", nil},
+ {"1e-20", "1e-20", nil},
+ {"625e-3", "0.625", nil},
+
+ // NaNs
+ {"nan", "NaN", nil},
+ {"NaN", "NaN", nil},
+ {"NAN", "NaN", nil},
+
+ // Infs
+ {"inf", "+Inf", nil},
+ {"-Inf", "-Inf", nil},
+ {"+INF", "+Inf", nil},
// largest float64
- atofTest{"1.7976931348623157e308", "1.7976931348623157e+308", nil},
- atofTest{"-1.7976931348623157e308", "-1.7976931348623157e+308", nil},
+ {"1.7976931348623157e308", "1.7976931348623157e+308", nil},
+ {"-1.7976931348623157e308", "-1.7976931348623157e+308", nil},
// next float64 - too large
- atofTest{"1.7976931348623159e308", "+Inf", os.ERANGE},
- atofTest{"-1.7976931348623159e308", "-Inf", os.ERANGE},
+ {"1.7976931348623159e308", "+Inf", os.ERANGE},
+ {"-1.7976931348623159e308", "-Inf", os.ERANGE},
// the border is ...158079
// borderline - okay
- atofTest{"1.7976931348623158e308", "1.7976931348623157e+308", nil},
- atofTest{"-1.7976931348623158e308", "-1.7976931348623157e+308", nil},
+ {"1.7976931348623158e308", "1.7976931348623157e+308", nil},
+ {"-1.7976931348623158e308", "-1.7976931348623157e+308", nil},
// borderline - too large
- atofTest{"1.797693134862315808e308", "+Inf", os.ERANGE},
- atofTest{"-1.797693134862315808e308", "-Inf", os.ERANGE},
+ {"1.797693134862315808e308", "+Inf", os.ERANGE},
+ {"-1.797693134862315808e308", "-Inf", os.ERANGE},
// a little too large
- atofTest{"1e308", "1e+308", nil},
- atofTest{"2e308", "+Inf", os.ERANGE},
- atofTest{"1e309", "+Inf", os.ERANGE},
+ {"1e308", "1e+308", nil},
+ {"2e308", "+Inf", os.ERANGE},
+ {"1e309", "+Inf", os.ERANGE},
// way too large
- atofTest{"1e310", "+Inf", os.ERANGE},
- atofTest{"-1e310", "-Inf", os.ERANGE},
- atofTest{"1e400", "+Inf", os.ERANGE},
- atofTest{"-1e400", "-Inf", os.ERANGE},
- atofTest{"1e400000", "+Inf", os.ERANGE},
- atofTest{"-1e400000", "-Inf", os.ERANGE},
+ {"1e310", "+Inf", os.ERANGE},
+ {"-1e310", "-Inf", os.ERANGE},
+ {"1e400", "+Inf", os.ERANGE},
+ {"-1e400", "-Inf", os.ERANGE},
+ {"1e400000", "+Inf", os.ERANGE},
+ {"-1e400000", "-Inf", os.ERANGE},
// denormalized
- atofTest{"1e-305", "1e-305", nil},
- atofTest{"1e-306", "1e-306", nil},
- atofTest{"1e-307", "1e-307", nil},
- atofTest{"1e-308", "1e-308", nil},
- atofTest{"1e-309", "1e-309", nil},
- atofTest{"1e-310", "1e-310", nil},
- atofTest{"1e-322", "1e-322", nil},
+ {"1e-305", "1e-305", nil},
+ {"1e-306", "1e-306", nil},
+ {"1e-307", "1e-307", nil},
+ {"1e-308", "1e-308", nil},
+ {"1e-309", "1e-309", nil},
+ {"1e-310", "1e-310", nil},
+ {"1e-322", "1e-322", nil},
// smallest denormal
- atofTest{"5e-324", "5e-324", nil},
- atofTest{"4e-324", "5e-324", nil},
- atofTest{"3e-324", "5e-324", nil},
+ {"5e-324", "5e-324", nil},
+ {"4e-324", "5e-324", nil},
+ {"3e-324", "5e-324", nil},
// too small
- atofTest{"2e-324", "0", nil},
+ {"2e-324", "0", nil},
// way too small
- atofTest{"1e-350", "0", nil},
- atofTest{"1e-400000", "0", nil},
+ {"1e-350", "0", nil},
+ {"1e-400000", "0", nil},
// try to overflow exponent
- atofTest{"1e-4294967296", "0", nil},
- atofTest{"1e+4294967296", "+Inf", os.ERANGE},
- atofTest{"1e-18446744073709551616", "0", nil},
- atofTest{"1e+18446744073709551616", "+Inf", os.ERANGE},
+ {"1e-4294967296", "0", nil},
+ {"1e+4294967296", "+Inf", os.ERANGE},
+ {"1e-18446744073709551616", "0", nil},
+ {"1e+18446744073709551616", "+Inf", os.ERANGE},
// Parse errors
- atofTest{"1e", "0", os.EINVAL},
- atofTest{"1e-", "0", os.EINVAL},
- atofTest{".e-1", "0", os.EINVAL},
+ {"1e", "0", os.EINVAL},
+ {"1e-", "0", os.EINVAL},
+ {".e-1", "0", os.EINVAL},
}
func init() {
@@ -112,14 +123,14 @@ func testAtof(t *testing.T, opt bool) {
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\n",
+ t.Errorf("Atof64(%v) = %v, %v want %v, %v",
test.in, out, err, test.out, test.err)
}
out, err = AtofN(test.in, 64)
outs = FtoaN(out, 'g', -1, 64)
if outs != test.out || !reflect.DeepEqual(err, test.err) {
- t.Errorf("AtofN(%v, 64) = %v, %v want %v, %v\n",
+ t.Errorf("AtofN(%v, 64) = %v, %v want %v, %v",
test.in, out, err, test.out, test.err)
}
@@ -127,7 +138,7 @@ func testAtof(t *testing.T, opt bool) {
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\n",
+ t.Errorf("Atof32(%v) = %v, %v want %v, %v # %v",
test.in, out32, err, test.out, test.err, out)
}
@@ -135,7 +146,7 @@ func testAtof(t *testing.T, opt bool) {
out32 = float32(out)
outs = FtoaN(float64(out32), 'g', -1, 32)
if outs != test.out || !reflect.DeepEqual(err, test.err) {
- t.Errorf("AtofN(%v, 32) = %v, %v want %v, %v # %v\n",
+ t.Errorf("AtofN(%v, 32) = %v, %v want %v, %v # %v",
test.in, out32, err, test.out, test.err, out)
}
}
@@ -144,7 +155,7 @@ func testAtof(t *testing.T, opt bool) {
outf, err := Atof(test.in)
outs := Ftoa(outf, 'g', -1)
if outs != test.out || !reflect.DeepEqual(err, test.err) {
- t.Errorf("Ftoa(%v) = %v, %v want %v, %v # %v\n",
+ t.Errorf("Ftoa(%v) = %v, %v want %v, %v # %v",
test.in, outf, err, test.out, test.err, out)
}
}
diff --git a/src/pkg/strconv/atoi.go b/src/pkg/strconv/atoi.go
index e82b6cdba..f7b845672 100644
--- a/src/pkg/strconv/atoi.go
+++ b/src/pkg/strconv/atoi.go
@@ -11,7 +11,7 @@ type NumError struct {
Error os.Error
}
-func (e *NumError) String() string { return "parsing " + e.Num + ": " + e.Error.String() }
+func (e *NumError) String() string { return `parsing "` + e.Num + `": ` + e.Error.String() }
func computeIntsize() uint {
diff --git a/src/pkg/strconv/atoi_test.go b/src/pkg/strconv/atoi_test.go
index 7df930342..0b9f29553 100644
--- a/src/pkg/strconv/atoi_test.go
+++ b/src/pkg/strconv/atoi_test.go
@@ -18,37 +18,37 @@ type atoui64Test struct {
}
var atoui64tests = []atoui64Test{
- atoui64Test{"", 0, os.EINVAL},
- atoui64Test{"0", 0, nil},
- atoui64Test{"1", 1, nil},
- atoui64Test{"12345", 12345, nil},
- atoui64Test{"012345", 12345, nil},
- atoui64Test{"12345x", 0, os.EINVAL},
- atoui64Test{"98765432100", 98765432100, nil},
- atoui64Test{"18446744073709551615", 1<<64 - 1, nil},
- atoui64Test{"18446744073709551616", 1<<64 - 1, os.ERANGE},
- atoui64Test{"18446744073709551620", 1<<64 - 1, os.ERANGE},
+ {"", 0, os.EINVAL},
+ {"0", 0, nil},
+ {"1", 1, nil},
+ {"12345", 12345, nil},
+ {"012345", 12345, nil},
+ {"12345x", 0, os.EINVAL},
+ {"98765432100", 98765432100, nil},
+ {"18446744073709551615", 1<<64 - 1, nil},
+ {"18446744073709551616", 1<<64 - 1, os.ERANGE},
+ {"18446744073709551620", 1<<64 - 1, os.ERANGE},
}
var btoui64tests = []atoui64Test{
- atoui64Test{"", 0, os.EINVAL},
- atoui64Test{"0", 0, nil},
- atoui64Test{"1", 1, nil},
- atoui64Test{"12345", 12345, nil},
- atoui64Test{"012345", 012345, nil},
- atoui64Test{"0x12345", 0x12345, nil},
- atoui64Test{"0X12345", 0x12345, nil},
- atoui64Test{"12345x", 0, os.EINVAL},
- atoui64Test{"98765432100", 98765432100, nil},
- atoui64Test{"18446744073709551615", 1<<64 - 1, nil},
- atoui64Test{"18446744073709551616", 1<<64 - 1, os.ERANGE},
- atoui64Test{"18446744073709551620", 1<<64 - 1, os.ERANGE},
- atoui64Test{"0xFFFFFFFFFFFFFFFF", 1<<64 - 1, nil},
- atoui64Test{"0x10000000000000000", 1<<64 - 1, os.ERANGE},
- atoui64Test{"01777777777777777777777", 1<<64 - 1, nil},
- atoui64Test{"01777777777777777777778", 0, os.EINVAL},
- atoui64Test{"02000000000000000000000", 1<<64 - 1, os.ERANGE},
- atoui64Test{"0200000000000000000000", 1 << 61, nil},
+ {"", 0, os.EINVAL},
+ {"0", 0, nil},
+ {"1", 1, nil},
+ {"12345", 12345, nil},
+ {"012345", 012345, nil},
+ {"0x12345", 0x12345, nil},
+ {"0X12345", 0x12345, nil},
+ {"12345x", 0, os.EINVAL},
+ {"98765432100", 98765432100, nil},
+ {"18446744073709551615", 1<<64 - 1, nil},
+ {"18446744073709551616", 1<<64 - 1, os.ERANGE},
+ {"18446744073709551620", 1<<64 - 1, os.ERANGE},
+ {"0xFFFFFFFFFFFFFFFF", 1<<64 - 1, nil},
+ {"0x10000000000000000", 1<<64 - 1, os.ERANGE},
+ {"01777777777777777777777", 1<<64 - 1, nil},
+ {"01777777777777777777778", 0, os.EINVAL},
+ {"02000000000000000000000", 1<<64 - 1, os.ERANGE},
+ {"0200000000000000000000", 1 << 61, nil},
}
type atoi64Test struct {
@@ -58,47 +58,47 @@ type atoi64Test struct {
}
var atoi64tests = []atoi64Test{
- atoi64Test{"", 0, os.EINVAL},
- atoi64Test{"0", 0, nil},
- atoi64Test{"-0", 0, nil},
- atoi64Test{"1", 1, nil},
- atoi64Test{"-1", -1, nil},
- atoi64Test{"12345", 12345, nil},
- atoi64Test{"-12345", -12345, nil},
- atoi64Test{"012345", 12345, nil},
- atoi64Test{"-012345", -12345, nil},
- atoi64Test{"98765432100", 98765432100, nil},
- atoi64Test{"-98765432100", -98765432100, nil},
- atoi64Test{"9223372036854775807", 1<<63 - 1, nil},
- atoi64Test{"-9223372036854775807", -(1<<63 - 1), nil},
- atoi64Test{"9223372036854775808", 1<<63 - 1, os.ERANGE},
- atoi64Test{"-9223372036854775808", -1 << 63, nil},
- atoi64Test{"9223372036854775809", 1<<63 - 1, os.ERANGE},
- atoi64Test{"-9223372036854775809", -1 << 63, os.ERANGE},
+ {"", 0, os.EINVAL},
+ {"0", 0, nil},
+ {"-0", 0, nil},
+ {"1", 1, nil},
+ {"-1", -1, nil},
+ {"12345", 12345, nil},
+ {"-12345", -12345, nil},
+ {"012345", 12345, nil},
+ {"-012345", -12345, nil},
+ {"98765432100", 98765432100, nil},
+ {"-98765432100", -98765432100, nil},
+ {"9223372036854775807", 1<<63 - 1, nil},
+ {"-9223372036854775807", -(1<<63 - 1), nil},
+ {"9223372036854775808", 1<<63 - 1, os.ERANGE},
+ {"-9223372036854775808", -1 << 63, nil},
+ {"9223372036854775809", 1<<63 - 1, os.ERANGE},
+ {"-9223372036854775809", -1 << 63, os.ERANGE},
}
var btoi64tests = []atoi64Test{
- atoi64Test{"", 0, os.EINVAL},
- atoi64Test{"0", 0, nil},
- atoi64Test{"-0", 0, nil},
- atoi64Test{"1", 1, nil},
- atoi64Test{"-1", -1, nil},
- atoi64Test{"12345", 12345, nil},
- atoi64Test{"-12345", -12345, nil},
- atoi64Test{"012345", 012345, nil},
- atoi64Test{"-012345", -012345, nil},
- atoi64Test{"0x12345", 0x12345, nil},
- atoi64Test{"-0X12345", -0x12345, nil},
- atoi64Test{"12345x", 0, os.EINVAL},
- atoi64Test{"-12345x", 0, os.EINVAL},
- atoi64Test{"98765432100", 98765432100, nil},
- atoi64Test{"-98765432100", -98765432100, nil},
- atoi64Test{"9223372036854775807", 1<<63 - 1, nil},
- atoi64Test{"-9223372036854775807", -(1<<63 - 1), nil},
- atoi64Test{"9223372036854775808", 1<<63 - 1, os.ERANGE},
- atoi64Test{"-9223372036854775808", -1 << 63, nil},
- atoi64Test{"9223372036854775809", 1<<63 - 1, os.ERANGE},
- atoi64Test{"-9223372036854775809", -1 << 63, os.ERANGE},
+ {"", 0, os.EINVAL},
+ {"0", 0, nil},
+ {"-0", 0, nil},
+ {"1", 1, nil},
+ {"-1", -1, nil},
+ {"12345", 12345, nil},
+ {"-12345", -12345, nil},
+ {"012345", 012345, nil},
+ {"-012345", -012345, nil},
+ {"0x12345", 0x12345, nil},
+ {"-0X12345", -0x12345, nil},
+ {"12345x", 0, os.EINVAL},
+ {"-12345x", 0, os.EINVAL},
+ {"98765432100", 98765432100, nil},
+ {"-98765432100", -98765432100, nil},
+ {"9223372036854775807", 1<<63 - 1, nil},
+ {"-9223372036854775807", -(1<<63 - 1), nil},
+ {"9223372036854775808", 1<<63 - 1, os.ERANGE},
+ {"-9223372036854775808", -1 << 63, nil},
+ {"9223372036854775809", 1<<63 - 1, os.ERANGE},
+ {"-9223372036854775809", -1 << 63, os.ERANGE},
}
type atoui32Test struct {
@@ -108,15 +108,15 @@ type atoui32Test struct {
}
var atoui32tests = []atoui32Test{
- atoui32Test{"", 0, os.EINVAL},
- atoui32Test{"0", 0, nil},
- atoui32Test{"1", 1, nil},
- atoui32Test{"12345", 12345, nil},
- atoui32Test{"012345", 12345, nil},
- atoui32Test{"12345x", 0, os.EINVAL},
- atoui32Test{"987654321", 987654321, nil},
- atoui32Test{"4294967295", 1<<32 - 1, nil},
- atoui32Test{"4294967296", 1<<32 - 1, os.ERANGE},
+ {"", 0, os.EINVAL},
+ {"0", 0, nil},
+ {"1", 1, nil},
+ {"12345", 12345, nil},
+ {"012345", 12345, nil},
+ {"12345x", 0, os.EINVAL},
+ {"987654321", 987654321, nil},
+ {"4294967295", 1<<32 - 1, nil},
+ {"4294967296", 1<<32 - 1, os.ERANGE},
}
type atoi32Test struct {
@@ -126,25 +126,25 @@ type atoi32Test struct {
}
var atoi32tests = []atoi32Test{
- atoi32Test{"", 0, os.EINVAL},
- atoi32Test{"0", 0, nil},
- atoi32Test{"-0", 0, nil},
- atoi32Test{"1", 1, nil},
- atoi32Test{"-1", -1, nil},
- atoi32Test{"12345", 12345, nil},
- atoi32Test{"-12345", -12345, nil},
- atoi32Test{"012345", 12345, nil},
- atoi32Test{"-012345", -12345, nil},
- atoi32Test{"12345x", 0, os.EINVAL},
- atoi32Test{"-12345x", 0, os.EINVAL},
- atoi32Test{"987654321", 987654321, nil},
- atoi32Test{"-987654321", -987654321, nil},
- atoi32Test{"2147483647", 1<<31 - 1, nil},
- atoi32Test{"-2147483647", -(1<<31 - 1), nil},
- atoi32Test{"2147483648", 1<<31 - 1, os.ERANGE},
- atoi32Test{"-2147483648", -1 << 31, nil},
- atoi32Test{"2147483649", 1<<31 - 1, os.ERANGE},
- atoi32Test{"-2147483649", -1 << 31, os.ERANGE},
+ {"", 0, os.EINVAL},
+ {"0", 0, nil},
+ {"-0", 0, nil},
+ {"1", 1, nil},
+ {"-1", -1, nil},
+ {"12345", 12345, nil},
+ {"-12345", -12345, nil},
+ {"012345", 12345, nil},
+ {"-012345", -12345, nil},
+ {"12345x", 0, os.EINVAL},
+ {"-12345x", 0, os.EINVAL},
+ {"987654321", 987654321, nil},
+ {"-987654321", -987654321, nil},
+ {"2147483647", 1<<31 - 1, nil},
+ {"-2147483647", -(1<<31 - 1), nil},
+ {"2147483648", 1<<31 - 1, os.ERANGE},
+ {"-2147483648", -1 << 31, nil},
+ {"2147483649", 1<<31 - 1, os.ERANGE},
+ {"-2147483649", -1 << 31, os.ERANGE},
}
func init() {
@@ -193,7 +193,7 @@ func TestAtoui64(t *testing.T) {
test := &atoui64tests[i]
out, err := Atoui64(test.in)
if test.out != out || !reflect.DeepEqual(test.err, err) {
- t.Errorf("Atoui64(%q) = %v, %v want %v, %v\n",
+ t.Errorf("Atoui64(%q) = %v, %v want %v, %v",
test.in, out, err, test.out, test.err)
}
}
@@ -204,7 +204,7 @@ func TestBtoui64(t *testing.T) {
test := &btoui64tests[i]
out, err := Btoui64(test.in, 0)
if test.out != out || !reflect.DeepEqual(test.err, err) {
- t.Errorf("Btoui64(%q) = %v, %v want %v, %v\n",
+ t.Errorf("Btoui64(%q) = %v, %v want %v, %v",
test.in, out, err, test.out, test.err)
}
}
@@ -215,7 +215,7 @@ func TestAtoi64(t *testing.T) {
test := &atoi64tests[i]
out, err := Atoi64(test.in)
if test.out != out || !reflect.DeepEqual(test.err, err) {
- t.Errorf("Atoi64(%q) = %v, %v want %v, %v\n",
+ t.Errorf("Atoi64(%q) = %v, %v want %v, %v",
test.in, out, err, test.out, test.err)
}
}
@@ -226,7 +226,7 @@ func TestBtoi64(t *testing.T) {
test := &btoi64tests[i]
out, err := Btoi64(test.in, 0)
if test.out != out || !reflect.DeepEqual(test.err, err) {
- t.Errorf("Btoi64(%q) = %v, %v want %v, %v\n",
+ t.Errorf("Btoi64(%q) = %v, %v want %v, %v",
test.in, out, err, test.out, test.err)
}
}
@@ -239,7 +239,7 @@ func TestAtoui(t *testing.T) {
test := &atoui32tests[i]
out, err := Atoui(test.in)
if test.out != uint32(out) || !reflect.DeepEqual(test.err, err) {
- t.Errorf("Atoui(%q) = %v, %v want %v, %v\n",
+ t.Errorf("Atoui(%q) = %v, %v want %v, %v",
test.in, out, err, test.out, test.err)
}
}
@@ -248,7 +248,7 @@ func TestAtoui(t *testing.T) {
test := &atoui64tests[i]
out, err := Atoui(test.in)
if test.out != uint64(out) || !reflect.DeepEqual(test.err, err) {
- t.Errorf("Atoui(%q) = %v, %v want %v, %v\n",
+ t.Errorf("Atoui(%q) = %v, %v want %v, %v",
test.in, out, err, test.out, test.err)
}
}
@@ -262,7 +262,7 @@ func TestAtoi(t *testing.T) {
test := &atoi32tests[i]
out, err := Atoi(test.in)
if test.out != int32(out) || !reflect.DeepEqual(test.err, err) {
- t.Errorf("Atoi(%q) = %v, %v want %v, %v\n",
+ t.Errorf("Atoi(%q) = %v, %v want %v, %v",
test.in, out, err, test.out, test.err)
}
}
@@ -271,7 +271,7 @@ func TestAtoi(t *testing.T) {
test := &atoi64tests[i]
out, err := Atoi(test.in)
if test.out != int64(out) || !reflect.DeepEqual(test.err, err) {
- t.Errorf("Atoi(%q) = %v, %v want %v, %v\n",
+ t.Errorf("Atoi(%q) = %v, %v want %v, %v",
test.in, out, err, test.out, test.err)
}
}
diff --git a/src/pkg/strconv/decimal.go b/src/pkg/strconv/decimal.go
index 3be61d7bc..3a5cf1ba6 100644
--- a/src/pkg/strconv/decimal.go
+++ b/src/pkg/strconv/decimal.go
@@ -187,34 +187,34 @@ var leftcheats = []leftCheat{
int(log2*NR+1), $0, 2**NR)
}'
*/
- leftCheat{0, ""},
- leftCheat{1, "5"}, // * 2
- leftCheat{1, "25"}, // * 4
- leftCheat{1, "125"}, // * 8
- leftCheat{2, "625"}, // * 16
- leftCheat{2, "3125"}, // * 32
- leftCheat{2, "15625"}, // * 64
- leftCheat{3, "78125"}, // * 128
- leftCheat{3, "390625"}, // * 256
- leftCheat{3, "1953125"}, // * 512
- leftCheat{4, "9765625"}, // * 1024
- leftCheat{4, "48828125"}, // * 2048
- leftCheat{4, "244140625"}, // * 4096
- leftCheat{4, "1220703125"}, // * 8192
- leftCheat{5, "6103515625"}, // * 16384
- leftCheat{5, "30517578125"}, // * 32768
- leftCheat{5, "152587890625"}, // * 65536
- leftCheat{6, "762939453125"}, // * 131072
- leftCheat{6, "3814697265625"}, // * 262144
- leftCheat{6, "19073486328125"}, // * 524288
- leftCheat{7, "95367431640625"}, // * 1048576
- leftCheat{7, "476837158203125"}, // * 2097152
- leftCheat{7, "2384185791015625"}, // * 4194304
- leftCheat{7, "11920928955078125"}, // * 8388608
- leftCheat{8, "59604644775390625"}, // * 16777216
- leftCheat{8, "298023223876953125"}, // * 33554432
- leftCheat{8, "1490116119384765625"}, // * 67108864
- leftCheat{9, "7450580596923828125"}, // * 134217728
+ {0, ""},
+ {1, "5"}, // * 2
+ {1, "25"}, // * 4
+ {1, "125"}, // * 8
+ {2, "625"}, // * 16
+ {2, "3125"}, // * 32
+ {2, "15625"}, // * 64
+ {3, "78125"}, // * 128
+ {3, "390625"}, // * 256
+ {3, "1953125"}, // * 512
+ {4, "9765625"}, // * 1024
+ {4, "48828125"}, // * 2048
+ {4, "244140625"}, // * 4096
+ {4, "1220703125"}, // * 8192
+ {5, "6103515625"}, // * 16384
+ {5, "30517578125"}, // * 32768
+ {5, "152587890625"}, // * 65536
+ {6, "762939453125"}, // * 131072
+ {6, "3814697265625"}, // * 262144
+ {6, "19073486328125"}, // * 524288
+ {7, "95367431640625"}, // * 1048576
+ {7, "476837158203125"}, // * 2097152
+ {7, "2384185791015625"}, // * 4194304
+ {7, "11920928955078125"}, // * 8388608
+ {8, "59604644775390625"}, // * 16777216
+ {8, "298023223876953125"}, // * 33554432
+ {8, "1490116119384765625"}, // * 67108864
+ {9, "7450580596923828125"}, // * 134217728
}
// Is the leading prefix of b lexicographically less than s?
diff --git a/src/pkg/strconv/decimal_test.go b/src/pkg/strconv/decimal_test.go
index 5f73450cd..9b7903516 100644
--- a/src/pkg/strconv/decimal_test.go
+++ b/src/pkg/strconv/decimal_test.go
@@ -16,17 +16,17 @@ type shiftTest struct {
}
var shifttests = []shiftTest{
- shiftTest{0, -100, "0"},
- shiftTest{0, 100, "0"},
- shiftTest{1, 100, "1267650600228229401496703205376"},
- shiftTest{1, -100,
+ {0, -100, "0"},
+ {0, 100, "0"},
+ {1, 100, "1267650600228229401496703205376"},
+ {1, -100,
"0.00000000000000000000000000000078886090522101180541" +
"17285652827862296732064351090230047702789306640625",
},
- shiftTest{12345678, 8, "3160493568"},
- shiftTest{12345678, -8, "48225.3046875"},
- shiftTest{195312, 9, "99999744"},
- shiftTest{1953125, 9, "1000000000"},
+ {12345678, 8, "3160493568"},
+ {12345678, -8, "48225.3046875"},
+ {195312, 9, "99999744"},
+ {1953125, 9, "1000000000"},
}
func TestDecimalShift(t *testing.T) {
@@ -34,7 +34,7 @@ func TestDecimalShift(t *testing.T) {
test := &shifttests[i]
s := NewDecimal(test.i).Shift(test.shift).String()
if s != test.out {
- t.Errorf("Decimal %v << %v = %v, want %v\n",
+ t.Errorf("Decimal %v << %v = %v, want %v",
test.i, test.shift, s, test.out)
}
}
@@ -48,21 +48,21 @@ type roundTest struct {
}
var roundtests = []roundTest{
- roundTest{0, 4, "0", "0", "0", 0},
- roundTest{12344999, 4, "12340000", "12340000", "12350000", 12340000},
- roundTest{12345000, 4, "12340000", "12340000", "12350000", 12340000},
- roundTest{12345001, 4, "12340000", "12350000", "12350000", 12350000},
- roundTest{23454999, 4, "23450000", "23450000", "23460000", 23450000},
- roundTest{23455000, 4, "23450000", "23460000", "23460000", 23460000},
- roundTest{23455001, 4, "23450000", "23460000", "23460000", 23460000},
+ {0, 4, "0", "0", "0", 0},
+ {12344999, 4, "12340000", "12340000", "12350000", 12340000},
+ {12345000, 4, "12340000", "12340000", "12350000", 12340000},
+ {12345001, 4, "12340000", "12350000", "12350000", 12350000},
+ {23454999, 4, "23450000", "23450000", "23460000", 23450000},
+ {23455000, 4, "23450000", "23460000", "23460000", 23460000},
+ {23455001, 4, "23450000", "23460000", "23460000", 23460000},
- roundTest{99994999, 4, "99990000", "99990000", "100000000", 99990000},
- roundTest{99995000, 4, "99990000", "100000000", "100000000", 100000000},
- roundTest{99999999, 4, "99990000", "100000000", "100000000", 100000000},
+ {99994999, 4, "99990000", "99990000", "100000000", 99990000},
+ {99995000, 4, "99990000", "100000000", "100000000", 100000000},
+ {99999999, 4, "99990000", "100000000", "100000000", 100000000},
- roundTest{12994999, 4, "12990000", "12990000", "13000000", 12990000},
- roundTest{12995000, 4, "12990000", "13000000", "13000000", 13000000},
- roundTest{12999999, 4, "12990000", "13000000", "13000000", 13000000},
+ {12994999, 4, "12990000", "12990000", "13000000", 12990000},
+ {12995000, 4, "12990000", "13000000", "13000000", 13000000},
+ {12999999, 4, "12990000", "13000000", "13000000", 13000000},
}
func TestDecimalRound(t *testing.T) {
@@ -70,17 +70,17 @@ func TestDecimalRound(t *testing.T) {
test := &roundtests[i]
s := NewDecimal(test.i).RoundDown(test.nd).String()
if s != test.down {
- t.Errorf("Decimal %v RoundDown %d = %v, want %v\n",
+ t.Errorf("Decimal %v RoundDown %d = %v, want %v",
test.i, test.nd, s, test.down)
}
s = NewDecimal(test.i).Round(test.nd).String()
if s != test.round {
- t.Errorf("Decimal %v Round %d = %v, want %v\n",
+ t.Errorf("Decimal %v Round %d = %v, want %v",
test.i, test.nd, s, test.down)
}
s = NewDecimal(test.i).RoundUp(test.nd).String()
if s != test.up {
- t.Errorf("Decimal %v RoundUp %d = %v, want %v\n",
+ t.Errorf("Decimal %v RoundUp %d = %v, want %v",
test.i, test.nd, s, test.up)
}
}
@@ -93,16 +93,16 @@ type roundIntTest struct {
}
var roundinttests = []roundIntTest{
- roundIntTest{0, 100, 0},
- roundIntTest{512, -8, 2},
- roundIntTest{513, -8, 2},
- roundIntTest{640, -8, 2},
- roundIntTest{641, -8, 3},
- roundIntTest{384, -8, 2},
- roundIntTest{385, -8, 2},
- roundIntTest{383, -8, 1},
- roundIntTest{1, 100, 1<<64 - 1},
- roundIntTest{1000, 0, 1000},
+ {0, 100, 0},
+ {512, -8, 2},
+ {513, -8, 2},
+ {640, -8, 2},
+ {641, -8, 3},
+ {384, -8, 2},
+ {385, -8, 2},
+ {383, -8, 1},
+ {1, 100, 1<<64 - 1},
+ {1000, 0, 1000},
}
func TestDecimalRoundedInteger(t *testing.T) {
@@ -110,7 +110,7 @@ func TestDecimalRoundedInteger(t *testing.T) {
test := roundinttests[i]
int := NewDecimal(test.i).Shift(test.shift).RoundedInteger()
if int != test.int {
- t.Errorf("Decimal %v >> %v RoundedInteger = %v, want %v\n",
+ t.Errorf("Decimal %v >> %v RoundedInteger = %v, want %v",
test.i, test.shift, int, test.int)
}
}
diff --git a/src/pkg/strconv/fp_test.go b/src/pkg/strconv/fp_test.go
index 4cbadf316..305adcc0c 100644
--- a/src/pkg/strconv/fp_test.go
+++ b/src/pkg/strconv/fp_test.go
@@ -118,7 +118,7 @@ func TestFp(t *testing.T) {
}
a := strings.Split(line, " ", -1)
if len(a) != 4 {
- t.Error("testfp.txt:", lineno, ": wrong field count\n")
+ t.Error("testfp.txt:", lineno, ": wrong field count")
continue
}
var s string
diff --git a/src/pkg/strconv/ftoa.go b/src/pkg/strconv/ftoa.go
index 3659243c7..a6091fc6c 100644
--- a/src/pkg/strconv/ftoa.go
+++ b/src/pkg/strconv/ftoa.go
@@ -42,13 +42,15 @@ var FloatSize = floatsize()
// The format fmt is one of
// 'b' (-ddddp±ddd, a binary exponent),
// 'e' (-d.dddde±dd, a decimal exponent),
-// 'f' (-ddd.dddd, no exponent), or
-// 'g' ('e' for large exponents, 'f' otherwise).
+// 'E' (-d.ddddE±dd, a decimal exponent),
+// 'f' (-ddd.dddd, no exponent),
+// 'g' ('e' for large exponents, 'f' otherwise), or
+// 'G' ('E' for large exponents, 'f' otherwise).
//
// The precision prec controls the number of digits
-// (excluding the exponent) printed by the 'e', 'f', and 'g' formats.
-// For 'e' and 'f' it is the number of digits after the decimal point.
-// For 'g' it is the total number of digits.
+// (excluding the exponent) printed by the 'e', 'E', 'f', 'g', and 'G' formats.
+// For 'e', 'E', and 'f' it is the number of digits after the decimal point.
+// For 'g' and 'G' it is the total number of digits.
// The special precision -1 uses the smallest number of digits
// necessary such that Atof32 will return f exactly.
//
diff --git a/src/pkg/strconv/ftoa_test.go b/src/pkg/strconv/ftoa_test.go
index 49832b626..6044afdae 100644
--- a/src/pkg/strconv/ftoa_test.go
+++ b/src/pkg/strconv/ftoa_test.go
@@ -25,99 +25,99 @@ const (
)
var ftoatests = []ftoaTest{
- ftoaTest{1, 'e', 5, "1.00000e+00"},
- ftoaTest{1, 'f', 5, "1.00000"},
- ftoaTest{1, 'g', 5, "1"},
- ftoaTest{1, 'g', -1, "1"},
- ftoaTest{20, 'g', -1, "20"},
- ftoaTest{1234567.8, 'g', -1, "1.2345678e+06"},
- ftoaTest{200000, 'g', -1, "200000"},
- ftoaTest{2000000, 'g', -1, "2e+06"},
+ {1, 'e', 5, "1.00000e+00"},
+ {1, 'f', 5, "1.00000"},
+ {1, 'g', 5, "1"},
+ {1, 'g', -1, "1"},
+ {20, 'g', -1, "20"},
+ {1234567.8, 'g', -1, "1.2345678e+06"},
+ {200000, 'g', -1, "200000"},
+ {2000000, 'g', -1, "2e+06"},
// g conversion and zero suppression
- ftoaTest{400, 'g', 2, "4e+02"},
- ftoaTest{40, 'g', 2, "40"},
- ftoaTest{4, 'g', 2, "4"},
- ftoaTest{.4, 'g', 2, "0.4"},
- ftoaTest{.04, 'g', 2, "0.04"},
- ftoaTest{.004, 'g', 2, "0.004"},
- ftoaTest{.0004, 'g', 2, "0.0004"},
- ftoaTest{.00004, 'g', 2, "4e-05"},
- ftoaTest{.000004, 'g', 2, "4e-06"},
-
- ftoaTest{0, 'e', 5, "0.00000e+00"},
- ftoaTest{0, 'f', 5, "0.00000"},
- ftoaTest{0, 'g', 5, "0"},
- ftoaTest{0, 'g', -1, "0"},
-
- ftoaTest{-1, 'e', 5, "-1.00000e+00"},
- ftoaTest{-1, 'f', 5, "-1.00000"},
- ftoaTest{-1, 'g', 5, "-1"},
- ftoaTest{-1, 'g', -1, "-1"},
-
- ftoaTest{12, 'e', 5, "1.20000e+01"},
- ftoaTest{12, 'f', 5, "12.00000"},
- ftoaTest{12, 'g', 5, "12"},
- ftoaTest{12, 'g', -1, "12"},
-
- ftoaTest{123456700, 'e', 5, "1.23457e+08"},
- ftoaTest{123456700, 'f', 5, "123456700.00000"},
- ftoaTest{123456700, 'g', 5, "1.2346e+08"},
- ftoaTest{123456700, 'g', -1, "1.234567e+08"},
-
- ftoaTest{1.2345e6, 'e', 5, "1.23450e+06"},
- ftoaTest{1.2345e6, 'f', 5, "1234500.00000"},
- ftoaTest{1.2345e6, 'g', 5, "1.2345e+06"},
-
- ftoaTest{1e23, 'e', 17, "9.99999999999999916e+22"},
- ftoaTest{1e23, 'f', 17, "99999999999999991611392.00000000000000000"},
- ftoaTest{1e23, 'g', 17, "9.9999999999999992e+22"},
-
- ftoaTest{1e23, 'e', -1, "1e+23"},
- ftoaTest{1e23, 'f', -1, "100000000000000000000000"},
- ftoaTest{1e23, 'g', -1, "1e+23"},
-
- ftoaTest{below1e23, 'e', 17, "9.99999999999999748e+22"},
- ftoaTest{below1e23, 'f', 17, "99999999999999974834176.00000000000000000"},
- ftoaTest{below1e23, 'g', 17, "9.9999999999999975e+22"},
-
- ftoaTest{below1e23, 'e', -1, "9.999999999999997e+22"},
- ftoaTest{below1e23, 'f', -1, "99999999999999970000000"},
- ftoaTest{below1e23, 'g', -1, "9.999999999999997e+22"},
-
- ftoaTest{above1e23, 'e', 17, "1.00000000000000008e+23"},
- ftoaTest{above1e23, 'f', 17, "100000000000000008388608.00000000000000000"},
- ftoaTest{above1e23, 'g', 17, "1.0000000000000001e+23"},
-
- ftoaTest{above1e23, 'e', -1, "1.0000000000000001e+23"},
- ftoaTest{above1e23, 'f', -1, "100000000000000010000000"},
- ftoaTest{above1e23, 'g', -1, "1.0000000000000001e+23"},
-
- ftoaTest{fdiv(5e-304, 1e20), 'g', -1, "5e-324"},
- ftoaTest{fdiv(-5e-304, 1e20), 'g', -1, "-5e-324"},
-
- ftoaTest{32, 'g', -1, "32"},
- ftoaTest{32, 'g', 0, "3e+01"},
-
- ftoaTest{100, 'x', -1, "%x"},
-
- ftoaTest{math.NaN(), 'g', -1, "NaN"},
- ftoaTest{-math.NaN(), 'g', -1, "NaN"},
- ftoaTest{math.Inf(0), 'g', -1, "+Inf"},
- ftoaTest{math.Inf(-1), 'g', -1, "-Inf"},
- ftoaTest{-math.Inf(0), 'g', -1, "-Inf"},
-
- ftoaTest{-1, 'b', -1, "-4503599627370496p-52"},
+ {400, 'g', 2, "4e+02"},
+ {40, 'g', 2, "40"},
+ {4, 'g', 2, "4"},
+ {.4, 'g', 2, "0.4"},
+ {.04, 'g', 2, "0.04"},
+ {.004, 'g', 2, "0.004"},
+ {.0004, 'g', 2, "0.0004"},
+ {.00004, 'g', 2, "4e-05"},
+ {.000004, 'g', 2, "4e-06"},
+
+ {0, 'e', 5, "0.00000e+00"},
+ {0, 'f', 5, "0.00000"},
+ {0, 'g', 5, "0"},
+ {0, 'g', -1, "0"},
+
+ {-1, 'e', 5, "-1.00000e+00"},
+ {-1, 'f', 5, "-1.00000"},
+ {-1, 'g', 5, "-1"},
+ {-1, 'g', -1, "-1"},
+
+ {12, 'e', 5, "1.20000e+01"},
+ {12, 'f', 5, "12.00000"},
+ {12, 'g', 5, "12"},
+ {12, 'g', -1, "12"},
+
+ {123456700, 'e', 5, "1.23457e+08"},
+ {123456700, 'f', 5, "123456700.00000"},
+ {123456700, 'g', 5, "1.2346e+08"},
+ {123456700, 'g', -1, "1.234567e+08"},
+
+ {1.2345e6, 'e', 5, "1.23450e+06"},
+ {1.2345e6, 'f', 5, "1234500.00000"},
+ {1.2345e6, 'g', 5, "1.2345e+06"},
+
+ {1e23, 'e', 17, "9.99999999999999916e+22"},
+ {1e23, 'f', 17, "99999999999999991611392.00000000000000000"},
+ {1e23, 'g', 17, "9.9999999999999992e+22"},
+
+ {1e23, 'e', -1, "1e+23"},
+ {1e23, 'f', -1, "100000000000000000000000"},
+ {1e23, 'g', -1, "1e+23"},
+
+ {below1e23, 'e', 17, "9.99999999999999748e+22"},
+ {below1e23, 'f', 17, "99999999999999974834176.00000000000000000"},
+ {below1e23, 'g', 17, "9.9999999999999975e+22"},
+
+ {below1e23, 'e', -1, "9.999999999999997e+22"},
+ {below1e23, 'f', -1, "99999999999999970000000"},
+ {below1e23, 'g', -1, "9.999999999999997e+22"},
+
+ {above1e23, 'e', 17, "1.00000000000000008e+23"},
+ {above1e23, 'f', 17, "100000000000000008388608.00000000000000000"},
+ {above1e23, 'g', 17, "1.0000000000000001e+23"},
+
+ {above1e23, 'e', -1, "1.0000000000000001e+23"},
+ {above1e23, 'f', -1, "100000000000000010000000"},
+ {above1e23, 'g', -1, "1.0000000000000001e+23"},
+
+ {fdiv(5e-304, 1e20), 'g', -1, "5e-324"},
+ {fdiv(-5e-304, 1e20), 'g', -1, "-5e-324"},
+
+ {32, 'g', -1, "32"},
+ {32, 'g', 0, "3e+01"},
+
+ {100, 'x', -1, "%x"},
+
+ {math.NaN(), 'g', -1, "NaN"},
+ {-math.NaN(), 'g', -1, "NaN"},
+ {math.Inf(0), 'g', -1, "+Inf"},
+ {math.Inf(-1), 'g', -1, "-Inf"},
+ {-math.Inf(0), 'g', -1, "-Inf"},
+
+ {-1, 'b', -1, "-4503599627370496p-52"},
// fixed bugs
- ftoaTest{0.9, 'f', 1, "0.9"},
- ftoaTest{0.09, 'f', 1, "0.1"},
- ftoaTest{0.0999, 'f', 1, "0.1"},
- ftoaTest{0.05, 'f', 1, "0.1"},
- ftoaTest{0.05, 'f', 0, "0"},
- ftoaTest{0.5, 'f', 1, "0.5"},
- ftoaTest{0.5, 'f', 0, "0"},
- ftoaTest{1.5, 'f', 0, "2"},
+ {0.9, 'f', 1, "0.9"},
+ {0.09, 'f', 1, "0.1"},
+ {0.0999, 'f', 1, "0.1"},
+ {0.05, 'f', 1, "0.1"},
+ {0.05, 'f', 0, "0"},
+ {0.5, 'f', 1, "0.5"},
+ {0.5, 'f', 0, "0"},
+ {1.5, 'f', 0, "2"},
}
func TestFtoa(t *testing.T) {
diff --git a/src/pkg/strconv/itoa_test.go b/src/pkg/strconv/itoa_test.go
index 039ef4446..8514b21e4 100644
--- a/src/pkg/strconv/itoa_test.go
+++ b/src/pkg/strconv/itoa_test.go
@@ -16,60 +16,60 @@ type itob64Test struct {
}
var itob64tests = []itob64Test{
- itob64Test{0, 10, "0"},
- itob64Test{1, 10, "1"},
- itob64Test{-1, 10, "-1"},
- itob64Test{12345678, 10, "12345678"},
- itob64Test{-987654321, 10, "-987654321"},
- itob64Test{1<<31 - 1, 10, "2147483647"},
- itob64Test{-1<<31 + 1, 10, "-2147483647"},
- itob64Test{1 << 31, 10, "2147483648"},
- itob64Test{-1 << 31, 10, "-2147483648"},
- itob64Test{1<<31 + 1, 10, "2147483649"},
- itob64Test{-1<<31 - 1, 10, "-2147483649"},
- itob64Test{1<<32 - 1, 10, "4294967295"},
- itob64Test{-1<<32 + 1, 10, "-4294967295"},
- itob64Test{1 << 32, 10, "4294967296"},
- itob64Test{-1 << 32, 10, "-4294967296"},
- itob64Test{1<<32 + 1, 10, "4294967297"},
- itob64Test{-1<<32 - 1, 10, "-4294967297"},
- itob64Test{1 << 50, 10, "1125899906842624"},
- itob64Test{1<<63 - 1, 10, "9223372036854775807"},
- itob64Test{-1<<63 + 1, 10, "-9223372036854775807"},
- itob64Test{-1 << 63, 10, "-9223372036854775808"},
-
- itob64Test{0, 2, "0"},
- itob64Test{10, 2, "1010"},
- itob64Test{-1, 2, "-1"},
- itob64Test{1 << 15, 2, "1000000000000000"},
-
- itob64Test{-8, 8, "-10"},
- itob64Test{057635436545, 8, "57635436545"},
- itob64Test{1 << 24, 8, "100000000"},
-
- itob64Test{16, 16, "10"},
- itob64Test{-0x123456789abcdef, 16, "-123456789abcdef"},
- itob64Test{1<<63 - 1, 16, "7fffffffffffffff"},
- itob64Test{1<<63 - 1, 2, "111111111111111111111111111111111111111111111111111111111111111"},
-
- itob64Test{16, 17, "g"},
- itob64Test{25, 25, "10"},
- itob64Test{(((((17*35+24)*35+21)*35+34)*35+12)*35+24)*35 + 32, 35, "holycow"},
- itob64Test{(((((17*36+24)*36+21)*36+34)*36+12)*36+24)*36 + 32, 36, "holycow"},
+ {0, 10, "0"},
+ {1, 10, "1"},
+ {-1, 10, "-1"},
+ {12345678, 10, "12345678"},
+ {-987654321, 10, "-987654321"},
+ {1<<31 - 1, 10, "2147483647"},
+ {-1<<31 + 1, 10, "-2147483647"},
+ {1 << 31, 10, "2147483648"},
+ {-1 << 31, 10, "-2147483648"},
+ {1<<31 + 1, 10, "2147483649"},
+ {-1<<31 - 1, 10, "-2147483649"},
+ {1<<32 - 1, 10, "4294967295"},
+ {-1<<32 + 1, 10, "-4294967295"},
+ {1 << 32, 10, "4294967296"},
+ {-1 << 32, 10, "-4294967296"},
+ {1<<32 + 1, 10, "4294967297"},
+ {-1<<32 - 1, 10, "-4294967297"},
+ {1 << 50, 10, "1125899906842624"},
+ {1<<63 - 1, 10, "9223372036854775807"},
+ {-1<<63 + 1, 10, "-9223372036854775807"},
+ {-1 << 63, 10, "-9223372036854775808"},
+
+ {0, 2, "0"},
+ {10, 2, "1010"},
+ {-1, 2, "-1"},
+ {1 << 15, 2, "1000000000000000"},
+
+ {-8, 8, "-10"},
+ {057635436545, 8, "57635436545"},
+ {1 << 24, 8, "100000000"},
+
+ {16, 16, "10"},
+ {-0x123456789abcdef, 16, "-123456789abcdef"},
+ {1<<63 - 1, 16, "7fffffffffffffff"},
+ {1<<63 - 1, 2, "111111111111111111111111111111111111111111111111111111111111111"},
+
+ {16, 17, "g"},
+ {25, 25, "10"},
+ {(((((17*35+24)*35+21)*35+34)*35+12)*35+24)*35 + 32, 35, "holycow"},
+ {(((((17*36+24)*36+21)*36+34)*36+12)*36+24)*36 + 32, 36, "holycow"},
}
func TestItoa(t *testing.T) {
for _, test := range itob64tests {
s := Itob64(test.in, test.base)
if s != test.out {
- t.Errorf("Itob64(%v, %v) = %v want %v\n",
+ t.Errorf("Itob64(%v, %v) = %v want %v",
test.in, test.base, s, test.out)
}
if test.in >= 0 {
s := Uitob64(uint64(test.in), test.base)
if s != test.out {
- t.Errorf("Uitob64(%v, %v) = %v want %v\n",
+ t.Errorf("Uitob64(%v, %v) = %v want %v",
test.in, test.base, s, test.out)
}
}
@@ -77,14 +77,14 @@ func TestItoa(t *testing.T) {
if int64(int(test.in)) == test.in {
s := Itob(int(test.in), test.base)
if s != test.out {
- t.Errorf("Itob(%v, %v) = %v want %v\n",
+ t.Errorf("Itob(%v, %v) = %v want %v",
test.in, test.base, s, test.out)
}
if test.in >= 0 {
s := Uitob(uint(test.in), test.base)
if s != test.out {
- t.Errorf("Uitob(%v, %v) = %v want %v\n",
+ t.Errorf("Uitob(%v, %v) = %v want %v",
test.in, test.base, s, test.out)
}
}
@@ -93,14 +93,14 @@ func TestItoa(t *testing.T) {
if test.base == 10 {
s := Itoa64(test.in)
if s != test.out {
- t.Errorf("Itoa64(%v) = %v want %v\n",
+ t.Errorf("Itoa64(%v) = %v want %v",
test.in, s, test.out)
}
if test.in >= 0 {
s := Uitob64(uint64(test.in), test.base)
if s != test.out {
- t.Errorf("Uitob64(%v, %v) = %v want %v\n",
+ t.Errorf("Uitob64(%v, %v) = %v want %v",
test.in, test.base, s, test.out)
}
}
@@ -108,14 +108,14 @@ func TestItoa(t *testing.T) {
if int64(int(test.in)) == test.in {
s := Itoa(int(test.in))
if s != test.out {
- t.Errorf("Itoa(%v) = %v want %v\n",
+ 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\n",
+ t.Errorf("Uitoa(%v) = %v want %v",
test.in, s, test.out)
}
}
@@ -131,26 +131,26 @@ type uitob64Test struct {
}
var uitob64tests = []uitob64Test{
- uitob64Test{1<<63 - 1, 10, "9223372036854775807"},
- uitob64Test{1 << 63, 10, "9223372036854775808"},
- uitob64Test{1<<63 + 1, 10, "9223372036854775809"},
- uitob64Test{1<<64 - 2, 10, "18446744073709551614"},
- uitob64Test{1<<64 - 1, 10, "18446744073709551615"},
- uitob64Test{1<<64 - 1, 2, "1111111111111111111111111111111111111111111111111111111111111111"},
+ {1<<63 - 1, 10, "9223372036854775807"},
+ {1 << 63, 10, "9223372036854775808"},
+ {1<<63 + 1, 10, "9223372036854775809"},
+ {1<<64 - 2, 10, "18446744073709551614"},
+ {1<<64 - 1, 10, "18446744073709551615"},
+ {1<<64 - 1, 2, "1111111111111111111111111111111111111111111111111111111111111111"},
}
func TestUitoa(t *testing.T) {
for _, test := range uitob64tests {
s := Uitob64(test.in, test.base)
if s != test.out {
- t.Errorf("Uitob64(%v, %v) = %v want %v\n",
+ t.Errorf("Uitob64(%v, %v) = %v want %v",
test.in, test.base, s, test.out)
}
if uint64(uint(test.in)) == test.in {
s := Uitob(uint(test.in), test.base)
if s != test.out {
- t.Errorf("Uitob(%v, %v) = %v want %v\n",
+ t.Errorf("Uitob(%v, %v) = %v want %v",
test.in, test.base, s, test.out)
}
}
@@ -158,14 +158,14 @@ func TestUitoa(t *testing.T) {
if test.base == 10 {
s := Uitoa64(test.in)
if s != test.out {
- t.Errorf("Uitoa64(%v) = %v want %v\n",
+ t.Errorf("Uitoa64(%v) = %v want %v",
test.in, s, test.out)
}
if uint64(uint(test.in)) == test.in {
s := Uitoa(uint(test.in))
if s != test.out {
- t.Errorf("Uitoa(%v) = %v want %v\n",
+ t.Errorf("Uitoa(%v) = %v want %v",
test.in, s, test.out)
}
}
diff --git a/src/pkg/strconv/quote.go b/src/pkg/strconv/quote.go
index 53774ee6f..ed5889723 100644
--- a/src/pkg/strconv/quote.go
+++ b/src/pkg/strconv/quote.go
@@ -100,11 +100,12 @@ func unhex(b byte) (v int, ok bool) {
// UnquoteChar decodes the first character or byte in the escaped string
// or character literal represented by the string s.
// It returns four values:
-// 1) value, the decoded Unicode code point or byte value;
-// 2) multibyte, a boolean indicating whether the decoded character
-// requires a multibyte UTF-8 representation;
-// 3) tail, the remainder of the string after the character; and
-// 4) an error that will be nil if the character is syntactically valid.
+//
+// 1) value, the decoded Unicode code point or byte value;
+// 2) multibyte, a boolean indicating whether the decoded character requires a multibyte UTF-8 representation;
+// 3) tail, the remainder of the string after the character; and
+// 4) an error that will be nil if the character is syntactically valid.
+//
// The second argument, quote, specifies the type of literal being parsed
// and therefore which escaped quote character is permitted.
// If set to a single quote, it permits the sequence \' and disallows unescaped '.
@@ -233,7 +234,7 @@ func Unquote(s string) (t string, err os.Error) {
s = s[1 : n-1]
if quote == '`' {
- if strings.Index(s, "`") >= 0 {
+ if strings.Contains(s, "`") {
return "", os.EINVAL
}
return s, nil
diff --git a/src/pkg/strconv/quote_test.go b/src/pkg/strconv/quote_test.go
index 31784879a..1235fcb9a 100644
--- a/src/pkg/strconv/quote_test.go
+++ b/src/pkg/strconv/quote_test.go
@@ -16,12 +16,12 @@ type quoteTest struct {
}
var quotetests = []quoteTest{
- quoteTest{"\a\b\f\r\n\t\v", `"\a\b\f\r\n\t\v"`},
- quoteTest{"\\", `"\\"`},
- quoteTest{"abc\xffdef", `"abc\xffdef"`},
- quoteTest{"\u263a", `"\u263a"`},
- quoteTest{"\U0010ffff", `"\U0010ffff"`},
- quoteTest{"\x04", `"\x04"`},
+ {"\a\b\f\r\n\t\v", `"\a\b\f\r\n\t\v"`},
+ {"\\", `"\\"`},
+ {"abc\xffdef", `"abc\xffdef"`},
+ {"\u263a", `"\u263a"`},
+ {"\U0010ffff", `"\U0010ffff"`},
+ {"\x04", `"\x04"`},
}
func TestQuote(t *testing.T) {
@@ -39,44 +39,44 @@ type canBackquoteTest struct {
}
var canbackquotetests = []canBackquoteTest{
- canBackquoteTest{"`", false},
- canBackquoteTest{string(0), false},
- canBackquoteTest{string(1), false},
- canBackquoteTest{string(2), false},
- canBackquoteTest{string(3), false},
- canBackquoteTest{string(4), false},
- canBackquoteTest{string(5), false},
- canBackquoteTest{string(6), false},
- canBackquoteTest{string(7), false},
- canBackquoteTest{string(8), false},
- canBackquoteTest{string(9), true}, // \t
- canBackquoteTest{string(10), false},
- canBackquoteTest{string(11), false},
- canBackquoteTest{string(12), false},
- canBackquoteTest{string(13), false},
- canBackquoteTest{string(14), false},
- canBackquoteTest{string(15), false},
- canBackquoteTest{string(16), false},
- canBackquoteTest{string(17), false},
- canBackquoteTest{string(18), false},
- canBackquoteTest{string(19), false},
- canBackquoteTest{string(20), false},
- canBackquoteTest{string(21), false},
- canBackquoteTest{string(22), false},
- canBackquoteTest{string(23), false},
- canBackquoteTest{string(24), false},
- canBackquoteTest{string(25), false},
- canBackquoteTest{string(26), false},
- canBackquoteTest{string(27), false},
- canBackquoteTest{string(28), false},
- canBackquoteTest{string(29), false},
- canBackquoteTest{string(30), false},
- canBackquoteTest{string(31), false},
- canBackquoteTest{`' !"#$%&'()*+,-./:;<=>?@[\]^_{|}~`, true},
- canBackquoteTest{`0123456789`, true},
- canBackquoteTest{`ABCDEFGHIJKLMNOPQRSTUVWXYZ`, true},
- canBackquoteTest{`abcdefghijklmnopqrstuvwxyz`, true},
- canBackquoteTest{`☺`, true},
+ {"`", false},
+ {string(0), false},
+ {string(1), false},
+ {string(2), false},
+ {string(3), false},
+ {string(4), false},
+ {string(5), false},
+ {string(6), false},
+ {string(7), false},
+ {string(8), false},
+ {string(9), true}, // \t
+ {string(10), false},
+ {string(11), false},
+ {string(12), false},
+ {string(13), false},
+ {string(14), false},
+ {string(15), false},
+ {string(16), false},
+ {string(17), false},
+ {string(18), false},
+ {string(19), false},
+ {string(20), false},
+ {string(21), false},
+ {string(22), false},
+ {string(23), false},
+ {string(24), false},
+ {string(25), false},
+ {string(26), false},
+ {string(27), false},
+ {string(28), false},
+ {string(29), false},
+ {string(30), false},
+ {string(31), false},
+ {`' !"#$%&'()*+,-./:;<=>?@[\]^_{|}~`, true},
+ {`0123456789`, true},
+ {`ABCDEFGHIJKLMNOPQRSTUVWXYZ`, true},
+ {`abcdefghijklmnopqrstuvwxyz`, true},
+ {`☺`, true},
}
func TestCanBackquote(t *testing.T) {
@@ -89,41 +89,41 @@ func TestCanBackquote(t *testing.T) {
}
var unquotetests = []quoteTest{
- quoteTest{`""`, ""},
- quoteTest{`"a"`, "a"},
- quoteTest{`"abc"`, "abc"},
- quoteTest{`"☺"`, "☺"},
- quoteTest{`"hello world"`, "hello world"},
- quoteTest{`"\xFF"`, "\xFF"},
- quoteTest{`"\377"`, "\377"},
- quoteTest{`"\u1234"`, "\u1234"},
- quoteTest{`"\U00010111"`, "\U00010111"},
- quoteTest{`"\U0001011111"`, "\U0001011111"},
- quoteTest{`"\a\b\f\n\r\t\v\\\""`, "\a\b\f\n\r\t\v\\\""},
- quoteTest{`"'"`, "'"},
+ {`""`, ""},
+ {`"a"`, "a"},
+ {`"abc"`, "abc"},
+ {`"☺"`, "☺"},
+ {`"hello world"`, "hello world"},
+ {`"\xFF"`, "\xFF"},
+ {`"\377"`, "\377"},
+ {`"\u1234"`, "\u1234"},
+ {`"\U00010111"`, "\U00010111"},
+ {`"\U0001011111"`, "\U0001011111"},
+ {`"\a\b\f\n\r\t\v\\\""`, "\a\b\f\n\r\t\v\\\""},
+ {`"'"`, "'"},
- quoteTest{`'a'`, "a"},
- quoteTest{`'☹'`, "☹"},
- quoteTest{`'\a'`, "\a"},
- quoteTest{`'\x10'`, "\x10"},
- quoteTest{`'\377'`, "\377"},
- quoteTest{`'\u1234'`, "\u1234"},
- quoteTest{`'\U00010111'`, "\U00010111"},
- quoteTest{`'\t'`, "\t"},
- quoteTest{`' '`, " "},
- quoteTest{`'\''`, "'"},
- quoteTest{`'"'`, "\""},
+ {`'a'`, "a"},
+ {`'☹'`, "☹"},
+ {`'\a'`, "\a"},
+ {`'\x10'`, "\x10"},
+ {`'\377'`, "\377"},
+ {`'\u1234'`, "\u1234"},
+ {`'\U00010111'`, "\U00010111"},
+ {`'\t'`, "\t"},
+ {`' '`, " "},
+ {`'\''`, "'"},
+ {`'"'`, "\""},
- quoteTest{"``", ``},
- quoteTest{"`a`", `a`},
- quoteTest{"`abc`", `abc`},
- quoteTest{"`☺`", `☺`},
- quoteTest{"`hello world`", `hello world`},
- quoteTest{"`\\xFF`", `\xFF`},
- quoteTest{"`\\377`", `\377`},
- quoteTest{"`\\`", `\`},
- quoteTest{"` `", ` `},
- quoteTest{"` `", ` `},
+ {"``", ``},
+ {"`a`", `a`},
+ {"`abc`", `abc`},
+ {"`☺`", `☺`},
+ {"`hello world`", `hello world`},
+ {"`\\xFF`", `\xFF`},
+ {"`\\377`", `\377`},
+ {"`\\`", `\`},
+ {"` `", ` `},
+ {"` `", ` `},
}
var misquoted = []string{
diff --git a/src/pkg/strings/Makefile b/src/pkg/strings/Makefile
index 9bae470e9..c1be58243 100644
--- a/src/pkg/strings/Makefile
+++ b/src/pkg/strings/Makefile
@@ -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 ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=strings
GOFILES=\
diff --git a/src/pkg/strings/strings.go b/src/pkg/strings/strings.go
index 5d3d61e19..98a0d5731 100644
--- a/src/pkg/strings/strings.go
+++ b/src/pkg/strings/strings.go
@@ -28,8 +28,10 @@ func explode(s string, n int) []string {
a[i] = string(rune)
cur += size
}
- // add the rest
- a[i] = s[cur:]
+ // add the rest, if there is any
+ if cur < len(s) {
+ a[i] = s[cur:]
+ }
return a
}
@@ -59,6 +61,11 @@ func Count(s, sep string) int {
return n
}
+// Contains returns true if substr is within s.
+func Contains(s, substr string) bool {
+ return Index(s, substr) != -1
+}
+
// Index returns the index of the first instance of sep in s, or -1 if sep is not present in s.
func Index(s, sep string) int {
n := len(sep)
@@ -135,6 +142,24 @@ func IndexAny(s, chars string) int {
return -1
}
+// LastIndexAny returns the index of the last instance of any Unicode code
+// point from chars in s, or -1 if no Unicode code point from chars is
+// present in s.
+func LastIndexAny(s, chars string) int {
+ if len(chars) > 0 {
+ for i := len(s); i > 0; {
+ rune, size := utf8.DecodeLastRuneInString(s[0:i])
+ i -= size
+ for _, m := range chars {
+ if rune == m {
+ return i
+ }
+ }
+ }
+ }
+ return -1
+}
+
// Generic split: splits after each instance of sep,
// including sepSave bytes of sep in the subarrays.
func genSplit(s, sep string, sepSave, n int) []string {
@@ -163,16 +188,22 @@ func genSplit(s, sep string, sepSave, n int) []string {
return a[0 : na+1]
}
-// Split splits the string s around each instance of sep, returning an array of substrings of s.
-// If sep is empty, Split splits s after each UTF-8 sequence.
-// If n >= 0, Split splits s into at most n substrings; the last substring will be the unsplit remainder.
-// Thus if n == 0, the result will be nil.
+// Split slices s into substrings separated by sep and returns a slice of
+// the substrings between those separators.
+// If sep is empty, Split splits after each UTF-8 sequence.
+// The count determines the number of substrings to return:
+// n > 0: at most n substrings; the last substring will be the unsplit remainder.
+// n == 0: the result is nil (zero substrings)
+// n < 0: all substrings
func Split(s, sep string, n int) []string { return genSplit(s, sep, 0, n) }
-// SplitAfter splits the string s after each instance of sep, returning an array of substrings of s.
-// If sep is empty, SplitAfter splits s after each UTF-8 sequence.
-// If n >= 0, SplitAfter splits s into at most n substrings; the last substring will be the unsplit remainder.
-// Thus if n == 0, the result will be nil.
+// SplitAfter slices s into substrings after each instance of sep and
+// returns a slice of those substrings.
+// If sep is empty, Split splits after each UTF-8 sequence.
+// The count determines the number of substrings to return:
+// n > 0: at most n substrings; the last substring will be the unsplit remainder.
+// n == 0: the result is nil (zero substrings)
+// n < 0: all substrings
func SplitAfter(s, sep string, n int) []string {
return genSplit(s, sep, len(sep), n)
}
@@ -183,9 +214,9 @@ func Fields(s string) []string {
return FieldsFunc(s, unicode.IsSpace)
}
-// FieldsFunc splits the string s at each run of Unicode code points c satifying f(c)
-// and returns an array of slices of s. If no code points in s satisfy f(c), an empty slice
-// is returned.
+// FieldsFunc splits the string s at each run of Unicode code points c satisfying f(c)
+// and returns an array of slices of s. If all code points in s satisfy f(c) or the
+// string is empty, an empty slice is returned.
func FieldsFunc(s string, f func(int) bool) []string {
// First count the fields.
n := 0
@@ -286,7 +317,7 @@ func Map(mapping func(rune int) int, s string) string {
copy(nb, b[0:nbytes])
b = nb
}
- nbytes += utf8.EncodeRune(rune, b[nbytes:maxbytes])
+ nbytes += utf8.EncodeRune(b[nbytes:maxbytes], rune)
}
}
return string(b[0:nbytes])
@@ -333,6 +364,52 @@ func ToTitleSpecial(_case unicode.SpecialCase, s string) string {
return Map(func(r int) int { return _case.ToTitle(r) }, s)
}
+// isSeparator reports whether the rune could mark a word boundary.
+// TODO: update when package unicode captures more of the properties.
+func isSeparator(rune int) bool {
+ // ASCII alphanumerics and underscore are not separators
+ if rune <= 0x7F {
+ switch {
+ case '0' <= rune && rune <= '9':
+ return false
+ case 'a' <= rune && rune <= 'z':
+ return false
+ case 'A' <= rune && rune <= 'Z':
+ return false
+ case rune == '_':
+ return false
+ }
+ return true
+ }
+ // Letters and digits are not separators
+ if unicode.IsLetter(rune) || unicode.IsDigit(rune) {
+ return false
+ }
+ // Otherwise, all we can do for now is treat spaces as separators.
+ return unicode.IsSpace(rune)
+}
+
+// BUG(r): The rule Title uses for word boundaries does not handle Unicode punctuation properly.
+
+// Title returns a copy of the string s with all Unicode letters that begin words
+// mapped to their title case.
+func Title(s string) string {
+ // Use a closure here to remember state.
+ // Hackish but effective. Depends on Map scanning in order and calling
+ // the closure once per rune.
+ prev := ' '
+ return Map(
+ func(r int) int {
+ if isSeparator(prev) {
+ prev = r
+ return unicode.ToTitle(r)
+ }
+ prev = r
+ return r
+ },
+ s)
+}
+
// TrimLeftFunc returns a slice of the string s with all leading
// Unicode code points c satisfying f(c) removed.
func TrimLeftFunc(s string, f func(r int) bool) string {
@@ -376,8 +453,7 @@ func LastIndexFunc(s string, f func(r int) bool) int {
// indexFunc is the same as IndexFunc except that if
// truth==false, the sense of the predicate function is
-// inverted. We could use IndexFunc directly, but this
-// way saves a closure allocation.
+// inverted.
func indexFunc(s string, f func(r int) bool, truth bool) int {
start := 0
for start < len(s) {
@@ -396,37 +472,14 @@ 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. We could use IndexFunc directly, but this
-// way saves a closure allocation.
+// inverted.
func lastIndexFunc(s string, f func(r int) bool, truth bool) int {
- end := len(s)
- for end > 0 {
- start := end - 1
- rune := int(s[start])
- if rune >= utf8.RuneSelf {
- // Back up & look for beginning of rune. Mustn't pass start.
- for start--; start >= 0; start-- {
- if utf8.RuneStart(s[start]) {
- break
- }
- }
- if start < 0 {
- return -1
- }
- var wid int
- rune, wid = utf8.DecodeRuneInString(s[start:end])
-
- // If we've decoded fewer bytes than we expected,
- // we've got some invalid UTF-8, so make sure we return
- // the last possible index in s.
- if start+wid < end && f(utf8.RuneError) == truth {
- return end - 1
- }
- }
+ for i := len(s); i > 0; {
+ rune, size := utf8.DecodeLastRuneInString(s[0:i])
+ i -= size
if f(rune) == truth {
- return start
+ return i
}
- end = start
}
return -1
}
@@ -497,21 +550,10 @@ func Replace(s, old, new string, n int) string {
} else {
j += Index(s[start:], old)
}
- w += copyString(t[w:], s[start:j])
- w += copyString(t[w:], new)
+ w += copy(t[w:], s[start:j])
+ w += copy(t[w:], new)
start = j + len(old)
}
- w += copyString(t[w:], s[start:])
+ w += copy(t[w:], s[start:])
return string(t[0:w])
}
-
-func copyString(dst []byte, src string) int {
- n := len(dst)
- if n > len(src) {
- n = len(src)
- }
- for i := 0; i < n; i++ {
- dst[i] = src[i]
- }
- return n
-}
diff --git a/src/pkg/strings/strings_test.go b/src/pkg/strings/strings_test.go
index 06f1f1de1..734fdd33d 100644
--- a/src/pkg/strings/strings_test.go
+++ b/src/pkg/strings/strings_test.go
@@ -36,55 +36,68 @@ type IndexTest struct {
}
var indexTests = []IndexTest{
- IndexTest{"", "", 0},
- IndexTest{"", "a", -1},
- IndexTest{"", "foo", -1},
- IndexTest{"fo", "foo", -1},
- IndexTest{"foo", "foo", 0},
- IndexTest{"oofofoofooo", "f", 2},
- IndexTest{"oofofoofooo", "foo", 4},
- IndexTest{"barfoobarfoo", "foo", 3},
- IndexTest{"foo", "", 0},
- IndexTest{"foo", "o", 1},
- IndexTest{"abcABCabc", "A", 3},
+ {"", "", 0},
+ {"", "a", -1},
+ {"", "foo", -1},
+ {"fo", "foo", -1},
+ {"foo", "foo", 0},
+ {"oofofoofooo", "f", 2},
+ {"oofofoofooo", "foo", 4},
+ {"barfoobarfoo", "foo", 3},
+ {"foo", "", 0},
+ {"foo", "o", 1},
+ {"abcABCabc", "A", 3},
// cases with one byte strings - test special case in Index()
- IndexTest{"", "a", -1},
- IndexTest{"x", "a", -1},
- IndexTest{"x", "x", 0},
- IndexTest{"abc", "a", 0},
- IndexTest{"abc", "b", 1},
- IndexTest{"abc", "c", 2},
- IndexTest{"abc", "x", -1},
+ {"", "a", -1},
+ {"x", "a", -1},
+ {"x", "x", 0},
+ {"abc", "a", 0},
+ {"abc", "b", 1},
+ {"abc", "c", 2},
+ {"abc", "x", -1},
}
var lastIndexTests = []IndexTest{
- IndexTest{"", "", 0},
- IndexTest{"", "a", -1},
- IndexTest{"", "foo", -1},
- IndexTest{"fo", "foo", -1},
- IndexTest{"foo", "foo", 0},
- IndexTest{"foo", "f", 0},
- IndexTest{"oofofoofooo", "f", 7},
- IndexTest{"oofofoofooo", "foo", 7},
- IndexTest{"barfoobarfoo", "foo", 9},
- IndexTest{"foo", "", 3},
- IndexTest{"foo", "o", 2},
- IndexTest{"abcABCabc", "A", 3},
- IndexTest{"abcABCabc", "a", 6},
+ {"", "", 0},
+ {"", "a", -1},
+ {"", "foo", -1},
+ {"fo", "foo", -1},
+ {"foo", "foo", 0},
+ {"foo", "f", 0},
+ {"oofofoofooo", "f", 7},
+ {"oofofoofooo", "foo", 7},
+ {"barfoobarfoo", "foo", 9},
+ {"foo", "", 3},
+ {"foo", "o", 2},
+ {"abcABCabc", "A", 3},
+ {"abcABCabc", "a", 6},
}
var indexAnyTests = []IndexTest{
- IndexTest{"", "", -1},
- IndexTest{"", "a", -1},
- IndexTest{"", "abc", -1},
- IndexTest{"a", "", -1},
- IndexTest{"a", "a", 0},
- IndexTest{"aaa", "a", 0},
- IndexTest{"abc", "xyz", -1},
- IndexTest{"abc", "xcz", 2},
- IndexTest{"a☺b☻c☹d", "uvw☻xyz", 2 + len("☺")},
- IndexTest{"aRegExp*", ".(|)*+?^$[]", 7},
- IndexTest{dots + dots + dots, " ", -1},
+ {"", "", -1},
+ {"", "a", -1},
+ {"", "abc", -1},
+ {"a", "", -1},
+ {"a", "a", 0},
+ {"aaa", "a", 0},
+ {"abc", "xyz", -1},
+ {"abc", "xcz", 2},
+ {"a☺b☻c☹d", "uvw☻xyz", 2 + len("☺")},
+ {"aRegExp*", ".(|)*+?^$[]", 7},
+ {dots + dots + dots, " ", -1},
+}
+var lastIndexAnyTests = []IndexTest{
+ {"", "", -1},
+ {"", "a", -1},
+ {"", "abc", -1},
+ {"a", "", -1},
+ {"a", "a", 0},
+ {"aaa", "a", 2},
+ {"abc", "xyz", -1},
+ {"abc", "ab", 1},
+ {"a☺b☻c☹d", "uvw☻xyz", 2 + len("☺")},
+ {"a.RegExp*", ".(|)*+?^$[]", 8},
+ {dots + dots + dots, " ", -1},
}
// Execute f on each test case. funcName should be the name of f; it's used
@@ -98,9 +111,10 @@ func runIndexTests(t *testing.T, f func(s, sep string) int, funcName string, tes
}
}
-func TestIndex(t *testing.T) { runIndexTests(t, Index, "Index", indexTests) }
-func TestLastIndex(t *testing.T) { runIndexTests(t, LastIndex, "LastIndex", lastIndexTests) }
-func TestIndexAny(t *testing.T) { runIndexTests(t, IndexAny, "IndexAny", indexAnyTests) }
+func TestIndex(t *testing.T) { runIndexTests(t, Index, "Index", indexTests) }
+func TestLastIndex(t *testing.T) { runIndexTests(t, LastIndex, "LastIndex", lastIndexTests) }
+func TestIndexAny(t *testing.T) { runIndexTests(t, IndexAny, "IndexAny", indexAnyTests) }
+func TestLastIndexAny(t *testing.T) { runIndexTests(t, LastIndexAny, "LastIndexAny", lastIndexAnyTests) }
type ExplodeTest struct {
s string
@@ -109,9 +123,10 @@ type ExplodeTest struct {
}
var explodetests = []ExplodeTest{
- ExplodeTest{abcd, 4, []string{"a", "b", "c", "d"}},
- ExplodeTest{faces, 3, []string{"☺", "☻", "☹"}},
- ExplodeTest{abcd, 2, []string{"a", "bcd"}},
+ {"", -1, []string{}},
+ {abcd, 4, []string{"a", "b", "c", "d"}},
+ {faces, 3, []string{"☺", "☻", "☹"}},
+ {abcd, 2, []string{"a", "bcd"}},
}
func TestExplode(t *testing.T) {
@@ -136,19 +151,19 @@ type SplitTest struct {
}
var splittests = []SplitTest{
- SplitTest{abcd, "a", 0, nil},
- SplitTest{abcd, "a", -1, []string{"", "bcd"}},
- SplitTest{abcd, "z", -1, []string{"abcd"}},
- SplitTest{abcd, "", -1, []string{"a", "b", "c", "d"}},
- SplitTest{commas, ",", -1, []string{"1", "2", "3", "4"}},
- SplitTest{dots, "...", -1, []string{"1", ".2", ".3", ".4"}},
- SplitTest{faces, "☹", -1, []string{"☺☻", ""}},
- SplitTest{faces, "~", -1, []string{faces}},
- SplitTest{faces, "", -1, []string{"☺", "☻", "☹"}},
- SplitTest{"1 2 3 4", " ", 3, []string{"1", "2", "3 4"}},
- SplitTest{"1 2", " ", 3, []string{"1", "2"}},
- SplitTest{"123", "", 2, []string{"1", "23"}},
- SplitTest{"123", "", 17, []string{"1", "2", "3"}},
+ {abcd, "a", 0, nil},
+ {abcd, "a", -1, []string{"", "bcd"}},
+ {abcd, "z", -1, []string{"abcd"}},
+ {abcd, "", -1, []string{"a", "b", "c", "d"}},
+ {commas, ",", -1, []string{"1", "2", "3", "4"}},
+ {dots, "...", -1, []string{"1", ".2", ".3", ".4"}},
+ {faces, "☹", -1, []string{"☺☻", ""}},
+ {faces, "~", -1, []string{faces}},
+ {faces, "", -1, []string{"☺", "☻", "☹"}},
+ {"1 2 3 4", " ", 3, []string{"1", "2", "3 4"}},
+ {"1 2", " ", 3, []string{"1", "2"}},
+ {"123", "", 2, []string{"1", "23"}},
+ {"123", "", 17, []string{"1", "2", "3"}},
}
func TestSplit(t *testing.T) {
@@ -169,19 +184,19 @@ func TestSplit(t *testing.T) {
}
var splitaftertests = []SplitTest{
- SplitTest{abcd, "a", -1, []string{"a", "bcd"}},
- SplitTest{abcd, "z", -1, []string{"abcd"}},
- SplitTest{abcd, "", -1, []string{"a", "b", "c", "d"}},
- SplitTest{commas, ",", -1, []string{"1,", "2,", "3,", "4"}},
- SplitTest{dots, "...", -1, []string{"1...", ".2...", ".3...", ".4"}},
- SplitTest{faces, "☹", -1, []string{"☺☻☹", ""}},
- SplitTest{faces, "~", -1, []string{faces}},
- SplitTest{faces, "", -1, []string{"☺", "☻", "☹"}},
- SplitTest{"1 2 3 4", " ", 3, []string{"1 ", "2 ", "3 4"}},
- SplitTest{"1 2 3", " ", 3, []string{"1 ", "2 ", "3"}},
- SplitTest{"1 2", " ", 3, []string{"1 ", "2"}},
- SplitTest{"123", "", 2, []string{"1", "23"}},
- SplitTest{"123", "", 17, []string{"1", "2", "3"}},
+ {abcd, "a", -1, []string{"a", "bcd"}},
+ {abcd, "z", -1, []string{"abcd"}},
+ {abcd, "", -1, []string{"a", "b", "c", "d"}},
+ {commas, ",", -1, []string{"1,", "2,", "3,", "4"}},
+ {dots, "...", -1, []string{"1...", ".2...", ".3...", ".4"}},
+ {faces, "☹", -1, []string{"☺☻☹", ""}},
+ {faces, "~", -1, []string{faces}},
+ {faces, "", -1, []string{"☺", "☻", "☹"}},
+ {"1 2 3 4", " ", 3, []string{"1 ", "2 ", "3 4"}},
+ {"1 2 3", " ", 3, []string{"1 ", "2 ", "3"}},
+ {"1 2", " ", 3, []string{"1 ", "2"}},
+ {"123", "", 2, []string{"1", "23"}},
+ {"123", "", 17, []string{"1", "2", "3"}},
}
func TestSplitAfter(t *testing.T) {
@@ -204,17 +219,17 @@ type FieldsTest struct {
}
var fieldstests = []FieldsTest{
- FieldsTest{"", []string{}},
- FieldsTest{" ", []string{}},
- FieldsTest{" \t ", []string{}},
- FieldsTest{" abc ", []string{"abc"}},
- FieldsTest{"1 2 3 4", []string{"1", "2", "3", "4"}},
- FieldsTest{"1 2 3 4", []string{"1", "2", "3", "4"}},
- FieldsTest{"1\t\t2\t\t3\t4", []string{"1", "2", "3", "4"}},
- FieldsTest{"1\u20002\u20013\u20024", []string{"1", "2", "3", "4"}},
- FieldsTest{"\u2000\u2001\u2002", []string{}},
- FieldsTest{"\n™\t™\n", []string{"™", "™"}},
- FieldsTest{faces, []string{faces}},
+ {"", []string{}},
+ {" ", []string{}},
+ {" \t ", []string{}},
+ {" abc ", []string{"abc"}},
+ {"1 2 3 4", []string{"1", "2", "3", "4"}},
+ {"1 2 3 4", []string{"1", "2", "3", "4"}},
+ {"1\t\t2\t\t3\t4", []string{"1", "2", "3", "4"}},
+ {"1\u20002\u20013\u20024", []string{"1", "2", "3", "4"}},
+ {"\u2000\u2001\u2002", []string{}},
+ {"\n™\t™\n", []string{"™", "™"}},
+ {faces, []string{faces}},
}
func TestFields(t *testing.T) {
@@ -230,10 +245,10 @@ func TestFields(t *testing.T) {
func TestFieldsFunc(t *testing.T) {
pred := func(c int) bool { return c == 'X' }
var fieldsFuncTests = []FieldsTest{
- FieldsTest{"", []string{}},
- FieldsTest{"XX", []string{}},
- FieldsTest{"XXhiXXX", []string{"hi"}},
- FieldsTest{"aXXbXXXcX", []string{"a", "b", "c"}},
+ {"", []string{}},
+ {"XX", []string{}},
+ {"XXhiXXX", []string{"hi"}},
+ {"aXXbXXXcX", []string{"a", "b", "c"}},
}
for _, tt := range fieldsFuncTests {
a := FieldsFunc(tt.s, pred)
@@ -261,40 +276,40 @@ func runStringTests(t *testing.T, f func(string) string, funcName string, testCa
}
var upperTests = []StringTest{
- StringTest{"", ""},
- StringTest{"abc", "ABC"},
- StringTest{"AbC123", "ABC123"},
- StringTest{"azAZ09_", "AZAZ09_"},
- StringTest{"\u0250\u0250\u0250\u0250\u0250", "\u2C6F\u2C6F\u2C6F\u2C6F\u2C6F"}, // grows one byte per char
+ {"", ""},
+ {"abc", "ABC"},
+ {"AbC123", "ABC123"},
+ {"azAZ09_", "AZAZ09_"},
+ {"\u0250\u0250\u0250\u0250\u0250", "\u2C6F\u2C6F\u2C6F\u2C6F\u2C6F"}, // grows one byte per char
}
var lowerTests = []StringTest{
- StringTest{"", ""},
- StringTest{"abc", "abc"},
- StringTest{"AbC123", "abc123"},
- StringTest{"azAZ09_", "azaz09_"},
- StringTest{"\u2C6D\u2C6D\u2C6D\u2C6D\u2C6D", "\u0251\u0251\u0251\u0251\u0251"}, // shrinks one byte per char
+ {"", ""},
+ {"abc", "abc"},
+ {"AbC123", "abc123"},
+ {"azAZ09_", "azaz09_"},
+ {"\u2C6D\u2C6D\u2C6D\u2C6D\u2C6D", "\u0251\u0251\u0251\u0251\u0251"}, // shrinks one byte per char
}
const space = "\t\v\r\f\n\u0085\u00a0\u2000\u3000"
var trimSpaceTests = []StringTest{
- StringTest{"", ""},
- StringTest{"abc", "abc"},
- StringTest{space + "abc" + space, "abc"},
- StringTest{" ", ""},
- StringTest{" \t\r\n \t\t\r\r\n\n ", ""},
- StringTest{" \t\r\n x\t\t\r\r\n\n ", "x"},
- StringTest{" \u2000\t\r\n x\t\t\r\r\ny\n \u3000", "x\t\t\r\r\ny"},
- StringTest{"1 \t\r\n2", "1 \t\r\n2"},
- StringTest{" x\x80", "x\x80"},
- StringTest{" x\xc0", "x\xc0"},
- StringTest{"x \xc0\xc0 ", "x \xc0\xc0"},
- StringTest{"x \xc0", "x \xc0"},
- StringTest{"x \xc0 ", "x \xc0"},
- StringTest{"x \xc0\xc0 ", "x \xc0\xc0"},
- StringTest{"x ☺\xc0\xc0 ", "x ☺\xc0\xc0"},
- StringTest{"x ☺ ", "x ☺"},
+ {"", ""},
+ {"abc", "abc"},
+ {space + "abc" + space, "abc"},
+ {" ", ""},
+ {" \t\r\n \t\t\r\r\n\n ", ""},
+ {" \t\r\n x\t\t\r\r\n\n ", "x"},
+ {" \u2000\t\r\n x\t\t\r\r\ny\n \u3000", "x\t\t\r\r\ny"},
+ {"1 \t\r\n2", "1 \t\r\n2"},
+ {" x\x80", "x\x80"},
+ {" x\xc0", "x\xc0"},
+ {"x \xc0\xc0 ", "x \xc0\xc0"},
+ {"x \xc0", "x \xc0"},
+ {"x \xc0 ", "x \xc0"},
+ {"x \xc0\xc0 ", "x \xc0\xc0"},
+ {"x ☺\xc0\xc0 ", "x ☺\xc0\xc0"},
+ {"x ☺ ", "x ☺"},
}
func tenRunes(rune int) string {
@@ -397,48 +412,29 @@ type TrimTest struct {
}
var trimTests = []TrimTest{
- TrimTest{Trim, "abba", "a", "bb"},
- TrimTest{Trim, "abba", "ab", ""},
- TrimTest{TrimLeft, "abba", "ab", ""},
- TrimTest{TrimRight, "abba", "ab", ""},
- TrimTest{TrimLeft, "abba", "a", "bba"},
- TrimTest{TrimRight, "abba", "a", "abb"},
- TrimTest{Trim, "<tag>", "<>", "tag"},
- TrimTest{Trim, "* listitem", " *", "listitem"},
- TrimTest{Trim, `"quote"`, `"`, "quote"},
- TrimTest{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
- TrimTest{Trim, "abba", "", "abba"},
- TrimTest{Trim, "", "123", ""},
- TrimTest{Trim, "", "", ""},
- TrimTest{TrimLeft, "abba", "", "abba"},
- TrimTest{TrimLeft, "", "123", ""},
- TrimTest{TrimLeft, "", "", ""},
- TrimTest{TrimRight, "abba", "", "abba"},
- TrimTest{TrimRight, "", "123", ""},
- TrimTest{TrimRight, "", "", ""},
- TrimTest{TrimRight, "☺\xc0", "☺", "☺\xc0"},
-}
-
-// naiveTrimRight implements a version of TrimRight
-// by scanning forwards from the start of s.
-func naiveTrimRight(s string, cutset string) string {
- i := -1
- for j, r := range s {
- if IndexRune(cutset, r) == -1 {
- i = j
- }
- }
- if i >= 0 && s[i] >= utf8.RuneSelf {
- _, wid := utf8.DecodeRuneInString(s[i:])
- i += wid
- } else {
- i++
- }
- return s[0:i]
+ {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)
@@ -456,16 +452,14 @@ func TestTrim(t *testing.T) {
if actual != tc.out {
t.Errorf("%s(%q, %q) = %q; want %q", name, tc.in, tc.cutset, actual, tc.out)
}
- // test equivalence of TrimRight to naive version
- if tc.f == TrimRight {
- naive := naiveTrimRight(tc.in, tc.cutset)
- if naive != actual {
- t.Errorf("TrimRight(%q, %q) = %q, want %q", tc.in, tc.cutset, actual, naive)
- }
- }
}
}
+type predicate struct {
+ f func(r int) bool
+ name string
+}
+
var isSpace = predicate{unicode.IsSpace, "IsSpace"}
var isDigit = predicate{unicode.IsDigit, "IsDigit"}
var isUpper = predicate{unicode.IsUpper, "IsUpper"}
@@ -476,11 +470,6 @@ var isValidRune = predicate{
"IsValidRune",
}
-type predicate struct {
- f func(r int) bool
- name string
-}
-
type TrimFuncTest struct {
f predicate
in, out string
@@ -496,13 +485,13 @@ func not(p predicate) predicate {
}
var trimFuncTests = []TrimFuncTest{
- TrimFuncTest{isSpace, space + " hello " + space, "hello"},
- TrimFuncTest{isDigit, "\u0e50\u0e5212hello34\u0e50\u0e51", "hello"},
- TrimFuncTest{isUpper, "\u2C6F\u2C6F\u2C6F\u2C6FABCDhelloEF\u2C6F\u2C6FGH\u2C6F\u2C6F", "hello"},
- TrimFuncTest{not(isSpace), "hello" + space + "hello", space},
- TrimFuncTest{not(isDigit), "hello\u0e50\u0e521234\u0e50\u0e51helo", "\u0e50\u0e521234\u0e50\u0e51"},
- TrimFuncTest{isValidRune, "ab\xc0a\xc0cd", "\xc0a\xc0"},
- TrimFuncTest{not(isValidRune), "\xc0a\xc0", "a"},
+ {isSpace, space + " hello " + space, "hello"},
+ {isDigit, "\u0e50\u0e5212hello34\u0e50\u0e51", "hello"},
+ {isUpper, "\u2C6F\u2C6F\u2C6F\u2C6FABCDhelloEF\u2C6F\u2C6FGH\u2C6F\u2C6F", "hello"},
+ {not(isSpace), "hello" + space + "hello", space},
+ {not(isDigit), "hello\u0e50\u0e521234\u0e50\u0e51helo", "\u0e50\u0e521234\u0e50\u0e51"},
+ {isValidRune, "ab\xc0a\xc0cd", "\xc0a\xc0"},
+ {not(isValidRune), "\xc0a\xc0", "a"},
}
func TestTrimFunc(t *testing.T) {
@@ -521,24 +510,25 @@ type IndexFuncTest struct {
}
var indexFuncTests = []IndexFuncTest{
- IndexFuncTest{"", isValidRune, -1, -1},
- IndexFuncTest{"abc", isDigit, -1, -1},
- IndexFuncTest{"0123", isDigit, 0, 3},
- IndexFuncTest{"a1b", isDigit, 1, 1},
- IndexFuncTest{space, isSpace, 0, len(space) - 3}, // last rune in space is 3 bytes
- IndexFuncTest{"\u0e50\u0e5212hello34\u0e50\u0e51", isDigit, 0, 18},
- IndexFuncTest{"\u2C6F\u2C6F\u2C6F\u2C6FABCDhelloEF\u2C6F\u2C6FGH\u2C6F\u2C6F", isUpper, 0, 34},
- IndexFuncTest{"12\u0e50\u0e52hello34\u0e50\u0e51", not(isDigit), 8, 12},
-
- // broken unicode tests
- IndexFuncTest{"\x801", isDigit, 1, 1},
- IndexFuncTest{"\x80abc", isDigit, -1, -1},
- IndexFuncTest{"\xc0a\xc0", isValidRune, 1, 1},
- IndexFuncTest{"\xc0a\xc0", not(isValidRune), 0, 2},
- IndexFuncTest{"\xc0☺\xc0", not(isValidRune), 0, 4},
- IndexFuncTest{"\xc0☺\xc0\xc0", not(isValidRune), 0, 5},
- IndexFuncTest{"ab\xc0a\xc0cd", not(isValidRune), 2, 4},
- IndexFuncTest{"a\xe0\x80cd", not(isValidRune), 1, 2},
+ {"", isValidRune, -1, -1},
+ {"abc", isDigit, -1, -1},
+ {"0123", isDigit, 0, 3},
+ {"a1b", isDigit, 1, 1},
+ {space, isSpace, 0, len(space) - 3}, // last rune in space is 3 bytes
+ {"\u0e50\u0e5212hello34\u0e50\u0e51", isDigit, 0, 18},
+ {"\u2C6F\u2C6F\u2C6F\u2C6FABCDhelloEF\u2C6F\u2C6FGH\u2C6F\u2C6F", isUpper, 0, 34},
+ {"12\u0e50\u0e52hello34\u0e50\u0e51", not(isDigit), 8, 12},
+
+ // tests of invalid UTF-8
+ {"\x801", isDigit, 1, 1},
+ {"\x80abc", isDigit, -1, -1},
+ {"\xc0a\xc0", isValidRune, 1, 1},
+ {"\xc0a\xc0", not(isValidRune), 0, 2},
+ {"\xc0☺\xc0", not(isValidRune), 0, 4},
+ {"\xc0☺\xc0\xc0", not(isValidRune), 0, 5},
+ {"ab\xc0a\xc0cd", not(isValidRune), 2, 4},
+ {"a\xe0\x80cd", not(isValidRune), 1, 2},
+ {"\x80\x80\x80\x80", not(isValidRune), 0, 3},
}
func TestIndexFunc(t *testing.T) {
@@ -619,13 +609,13 @@ type RepeatTest struct {
}
var RepeatTests = []RepeatTest{
- RepeatTest{"", "", 0},
- RepeatTest{"", "", 1},
- RepeatTest{"", "", 2},
- RepeatTest{"-", "", 0},
- RepeatTest{"-", "-", 1},
- RepeatTest{"-", "----------", 10},
- RepeatTest{"abc ", "abc abc abc ", 3},
+ {"", "", 0},
+ {"", "", 1},
+ {"", "", 2},
+ {"-", "", 0},
+ {"-", "-", 1},
+ {"-", "----------", 10},
+ {"abc ", "abc abc abc ", 3},
}
func TestRepeat(t *testing.T) {
@@ -657,13 +647,13 @@ type RunesTest struct {
}
var RunesTests = []RunesTest{
- RunesTest{"", []int{}, false},
- RunesTest{" ", []int{32}, false},
- RunesTest{"ABC", []int{65, 66, 67}, false},
- RunesTest{"abc", []int{97, 98, 99}, false},
- RunesTest{"\u65e5\u672c\u8a9e", []int{26085, 26412, 35486}, false},
- RunesTest{"ab\x80c", []int{97, 98, 0xFFFD, 99}, true},
- RunesTest{"ab\xc0c", []int{97, 98, 0xFFFD, 99}, true},
+ {"", []int{}, false},
+ {" ", []int{32}, false},
+ {"ABC", []int{65, 66, 67}, false},
+ {"abc", []int{97, 98, 99}, false},
+ {"\u65e5\u672c\u8a9e", []int{26085, 26412, 35486}, false},
+ {"ab\x80c", []int{97, 98, 0xFFFD, 99}, true},
+ {"ab\xc0c", []int{97, 98, 0xFFFD, 99}, true},
}
func TestRunes(t *testing.T) {
@@ -713,25 +703,25 @@ type ReplaceTest struct {
}
var ReplaceTests = []ReplaceTest{
- ReplaceTest{"hello", "l", "L", 0, "hello"},
- ReplaceTest{"hello", "l", "L", -1, "heLLo"},
- ReplaceTest{"hello", "x", "X", -1, "hello"},
- ReplaceTest{"", "x", "X", -1, ""},
- ReplaceTest{"radar", "r", "<r>", -1, "<r>ada<r>"},
- ReplaceTest{"", "", "<>", -1, "<>"},
- ReplaceTest{"banana", "a", "<>", -1, "b<>n<>n<>"},
- ReplaceTest{"banana", "a", "<>", 1, "b<>nana"},
- ReplaceTest{"banana", "a", "<>", 1000, "b<>n<>n<>"},
- ReplaceTest{"banana", "an", "<>", -1, "b<><>a"},
- ReplaceTest{"banana", "ana", "<>", -1, "b<>na"},
- ReplaceTest{"banana", "", "<>", -1, "<>b<>a<>n<>a<>n<>a<>"},
- ReplaceTest{"banana", "", "<>", 10, "<>b<>a<>n<>a<>n<>a<>"},
- ReplaceTest{"banana", "", "<>", 6, "<>b<>a<>n<>a<>n<>a"},
- ReplaceTest{"banana", "", "<>", 5, "<>b<>a<>n<>a<>na"},
- ReplaceTest{"banana", "", "<>", 1, "<>banana"},
- ReplaceTest{"banana", "a", "a", -1, "banana"},
- ReplaceTest{"banana", "a", "a", 1, "banana"},
- ReplaceTest{"☺☻☹", "", "<>", -1, "<>☺<>☻<>☹<>"},
+ {"hello", "l", "L", 0, "hello"},
+ {"hello", "l", "L", -1, "heLLo"},
+ {"hello", "x", "X", -1, "hello"},
+ {"", "x", "X", -1, ""},
+ {"radar", "r", "<r>", -1, "<r>ada<r>"},
+ {"", "", "<>", -1, "<>"},
+ {"banana", "a", "<>", -1, "b<>n<>n<>"},
+ {"banana", "a", "<>", 1, "b<>nana"},
+ {"banana", "a", "<>", 1000, "b<>n<>n<>"},
+ {"banana", "an", "<>", -1, "b<><>a"},
+ {"banana", "ana", "<>", -1, "b<>na"},
+ {"banana", "", "<>", -1, "<>b<>a<>n<>a<>n<>a<>"},
+ {"banana", "", "<>", 10, "<>b<>a<>n<>a<>n<>a<>"},
+ {"banana", "", "<>", 6, "<>b<>a<>n<>a<>n<>a"},
+ {"banana", "", "<>", 5, "<>b<>a<>n<>a<>na"},
+ {"banana", "", "<>", 1, "<>banana"},
+ {"banana", "a", "a", -1, "banana"},
+ {"banana", "a", "a", 1, "banana"},
+ {"☺☻☹", "", "<>", -1, "<>☺<>☻<>☹<>"},
}
func TestReplace(t *testing.T) {
@@ -741,3 +731,46 @@ func TestReplace(t *testing.T) {
}
}
}
+
+type TitleTest struct {
+ in, out string
+}
+
+var TitleTests = []TitleTest{
+ {"", ""},
+ {"a", "A"},
+ {" aaa aaa aaa ", " Aaa Aaa Aaa "},
+ {" Aaa Aaa Aaa ", " Aaa Aaa Aaa "},
+ {"123a456", "123a456"},
+ {"double-blind", "Double-Blind"},
+ {"ÿøû", "Ÿøû"},
+}
+
+func TestTitle(t *testing.T) {
+ for _, tt := range TitleTests {
+ if s := Title(tt.in); s != tt.out {
+ t.Errorf("Title(%q) = %q, want %q", tt.in, s, tt.out)
+ }
+ }
+}
+
+type ContainsTest struct {
+ str, substr string
+ expected bool
+}
+
+var ContainsTests = []ContainsTest{
+ {"abc", "bc", true},
+ {"abc", "bcd", false},
+ {"abc", "", true},
+ {"", "a", false},
+}
+
+func TestContains(t *testing.T) {
+ for _, ct := range ContainsTests {
+ if Contains(ct.str, ct.substr) != ct.expected {
+ t.Errorf("Contains(%s, %s) = %v, want %v",
+ ct.str, ct.substr, !ct.expected, ct.expected)
+ }
+ }
+}
diff --git a/src/pkg/sync/Makefile b/src/pkg/sync/Makefile
index 4b9a05816..f843795b0 100644
--- a/src/pkg/sync/Makefile
+++ b/src/pkg/sync/Makefile
@@ -2,11 +2,12 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=sync
GOFILES=\
mutex.go\
+ once.go \
rwmutex.go\
# 386-specific object files
diff --git a/src/pkg/sync/asm_arm5.s b/src/pkg/sync/asm_arm5.s
index 3cdca0b87..2cb496887 100644
--- a/src/pkg/sync/asm_arm5.s
+++ b/src/pkg/sync/asm_arm5.s
@@ -16,7 +16,7 @@ TEXT ·cas(SB),7,$0
MOVW 4(FP), R1 // old
MOVW 8(FP), R2 // new
MOVW $1, R3
- MOVW $cas_mutex(SB), R4
+ MOVW $runtime·cas_mutex(SB), R4
l:
SWPW (R4), R3 // acquire mutex
CMP $0, R3
diff --git a/src/pkg/sync/mutex.go b/src/pkg/sync/mutex.go
index b170370bc..9a2bb2bb4 100644
--- a/src/pkg/sync/mutex.go
+++ b/src/pkg/sync/mutex.go
@@ -3,9 +3,10 @@
// license that can be found in the LICENSE file.
// The sync package provides basic synchronization primitives
-// such as mutual exclusion locks. These are intended for use
-// by low-level library routines. Higher-level synchronization
-// is better done via channels and communication.
+// such as mutual exclusion locks. Other than the Once type,
+// most are intended for use by low-level library routines.
+// Higher-level synchronization is better done via channels
+// and communication.
package sync
import "runtime"
diff --git a/src/pkg/sync/once.go b/src/pkg/sync/once.go
new file mode 100644
index 000000000..8c877cdec
--- /dev/null
+++ b/src/pkg/sync/once.go
@@ -0,0 +1,35 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sync
+
+// Once is an object that will perform exactly one action.
+type Once struct {
+ m Mutex
+ done bool
+}
+
+// Do calls the function f if and only if the method is being called for the
+// first time with this receiver. In other words, given
+// var once Once
+// if Do(f) is called multiple times, only the first call will invoke f,
+// even if f has a different value in each invocation. A new instance of
+// Once is required for each function to execute.
+//
+// Do is intended for initialization that must be run exactly once. Since f
+// is niladic, it may be necessary to use a function literal to capture the
+// arguments to a function to be invoked by Do:
+// config.once.Do(func() { config.init(filename) })
+//
+// Because no call to Do returns until the one call to f returns, if f causes
+// Do to be called, it will deadlock.
+//
+func (o *Once) Do(f func()) {
+ o.m.Lock()
+ defer o.m.Unlock()
+ if !o.done {
+ o.done = true
+ f()
+ }
+}
diff --git a/src/pkg/sync/once_test.go b/src/pkg/sync/once_test.go
new file mode 100644
index 000000000..155954a49
--- /dev/null
+++ b/src/pkg/sync/once_test.go
@@ -0,0 +1,37 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sync_test
+
+import (
+ . "sync"
+ "testing"
+)
+
+type one int
+
+func (o *one) Increment() {
+ *o++
+}
+
+func run(once *Once, o *one, c chan bool) {
+ once.Do(func() { o.Increment() })
+ c <- true
+}
+
+func TestOnce(t *testing.T) {
+ o := new(one)
+ once := new(Once)
+ c := make(chan bool)
+ const N = 10
+ for i := 0; i < N; i++ {
+ go run(once, o, c)
+ }
+ for i := 0; i < N; i++ {
+ <-c
+ }
+ if *o != 1 {
+ t.Errorf("once failed: %d is not 1", *o)
+ }
+}
diff --git a/src/pkg/sync/rwmutex.go b/src/pkg/sync/rwmutex.go
index 0058cf252..06fd0b0ff 100644
--- a/src/pkg/sync/rwmutex.go
+++ b/src/pkg/sync/rwmutex.go
@@ -21,7 +21,7 @@ type RWMutex struct {
// RLock locks rw for reading.
// If the lock is already locked for writing or there is a writer already waiting
-// to r the lock, RLock blocks until the writer has released the lock.
+// to release the lock, RLock blocks until the writer has released the lock.
func (rw *RWMutex) RLock() {
// Use rw.r.Lock() to block granting the RLock if a goroutine
// is waiting for its Lock. This is the prevent starvation of W in
diff --git a/src/pkg/syscall/Makefile b/src/pkg/syscall/Makefile
index 3ac99bad9..061b0056c 100644
--- a/src/pkg/syscall/Makefile
+++ b/src/pkg/syscall/Makefile
@@ -2,12 +2,11 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=syscall
GOFILES=\
str.go\
- exec.go\
syscall.go\
syscall_$(GOARCH).go\
syscall_$(GOOS).go\
@@ -20,16 +19,19 @@ GOFILES=\
GOFILES_freebsd=\
syscall_bsd.go\
syscall_unix.go\
+ exec_unix.go\
GOFILES_darwin=\
syscall_bsd.go\
syscall_unix.go\
+ exec_unix.go\
GOFILES_linux=\
syscall_unix.go\
+ exec_unix.go\
-GOFILES_nacl=\
- syscall_unix.go\
+GOFILES_windows=\
+ exec_windows.go
OFILES=\
asm_$(GOOS)_$(GOARCH).$O\
diff --git a/src/pkg/syscall/asm_linux_amd64.s b/src/pkg/syscall/asm_linux_amd64.s
index cfb44434a..20a5a4fb7 100644
--- a/src/pkg/syscall/asm_linux_amd64.s
+++ b/src/pkg/syscall/asm_linux_amd64.s
@@ -82,3 +82,26 @@ ok1:
MOVQ DX, 48(SP) // r2
MOVQ $0, 56(SP) // errno
RET
+
+TEXT ·Gettimeofday(SB),7,$0
+ MOVQ 8(SP), DI
+ MOVQ $0, SI
+ MOVQ $0xffffffffff600000, AX
+ CALL AX
+
+ CMPQ AX, $0xfffffffffffff001
+ JLS ok7
+ NEGQ AX
+ MOVQ AX, 16(SP) // errno
+ RET
+ok7:
+ MOVQ $0, 16(SP) // errno
+ RET
+
+TEXT ·Time(SB),7,$0
+ MOVQ 8(SP), DI
+ MOVQ $0xffffffffff600400, AX
+ CALL AX
+ MOVQ AX, 16(SP) // tt
+ MOVQ $0, 24(SP) // errno
+ RET
diff --git a/src/pkg/syscall/asm_linux_arm.s b/src/pkg/syscall/asm_linux_arm.s
index 830d41c78..04dbdb624 100644
--- a/src/pkg/syscall/asm_linux_arm.s
+++ b/src/pkg/syscall/asm_linux_arm.s
@@ -17,9 +17,21 @@ TEXT ·Syscall(SB),7,$0
MOVW 12(SP), R1
MOVW 16(SP), R2
SWI $0
- MOVW R0, 20(SP) // r1
- MOVW R1, 24(SP) // r2
+ MOVW $0xfffff001, R1
+ CMP R1, R0
+ BLS ok
+ MOVW $-1, R1
+ MOVW R1, 20(SP) // r1
+ MOVW $0, R2
+ MOVW R2, 24(SP) // r2
+ RSB $0, R0, R0
+ MOVW R0, 28(SP) // errno
+ BL runtime·exitsyscall(SB)
+ RET
+ok:
+ MOVW R0, 20(SP) // r1
MOVW $0, R0
+ MOVW R0, 24(SP) // r2
MOVW R0, 28(SP) // errno
BL runtime·exitsyscall(SB)
RET
@@ -36,13 +48,57 @@ TEXT ·Syscall6(SB),7,$0
MOVW 24(SP), R4
MOVW 28(SP), R5
SWI $0
- MOVW R0, 32(SP) // r1
+ MOVW $0xfffff001, R6
+ CMP R6, R0
+ BLS ok6
+ MOVW $-1, R1
+ MOVW R1, 32(SP) // r1
+ MOVW $0, R2
+ MOVW R2, 36(SP) // r2
+ RSB $0, R0, R0
+ MOVW R0, 40(SP) // errno
+ BL runtime·exitsyscall(SB)
+ RET
+ok6:
+ MOVW R0, 32(SP) // r1
MOVW R1, 36(SP) // r2
MOVW $0, R0
MOVW R0, 40(SP) // errno
BL runtime·exitsyscall(SB)
RET
+#define SYS__LLSEEK 140 /* from zsysnum_linux_arm.go */
+// func Seek(fd int, offset int64, whence int) (newoffset int64, errno int)
+// Implemented in assembly to avoid allocation when
+// taking the address of the return value newoffset.
+// Underlying system call is
+// llseek(int fd, int offhi, int offlo, int64 *result, int whence)
+TEXT ·Seek(SB),7,$0
+ BL runtime·entersyscall(SB)
+ MOVW $SYS__LLSEEK, R7 // syscall entry
+ MOVW 4(SP), R0 // fd
+ MOVW 12(SP), R1 // offset-high
+ MOVW 8(SP), R2 // offset-low
+ MOVW $20(SP), R3
+ MOVW 16(SP), R4 // whence
+ SWI $0
+ MOVW $0xfffff001, R6
+ CMP R6, R0
+ BLS okseek
+ MOVW $0, R1
+ MOVW R1, 20(SP)
+ MOVW R1, 24(SP)
+ RSB $0, R0, R0
+ MOVW R0, 28(SP) // errno
+ BL runtime·exitsyscall(SB)
+ RET
+okseek:
+ // system call filled in newoffset already
+ MOVW $0, R0
+ MOVW R0, 28(SP) // errno
+ BL runtime·exitsyscall(SB)
+ RET
+
// func RawSyscall(trap uintptr, a1, a2, a3 uintptr) (r1, r2, err uintptr);
TEXT ·RawSyscall(SB),7,$0
MOVW 4(SP), R7 // syscall entry
@@ -50,8 +106,20 @@ TEXT ·RawSyscall(SB),7,$0
MOVW 12(SP), R1
MOVW 16(SP), R2
SWI $0
- MOVW R0, 20(SP) // r1
- MOVW R1, 24(SP) // r2
+ MOVW $0xfffff001, R1
+ CMP R1, R0
+ BLS ok1
+ MOVW $-1, R1
+ MOVW R1, 20(SP) // r1
+ MOVW $0, R2
+ MOVW R2, 24(SP) // r2
+ RSB $0, R0, R0
+ MOVW R0, 28(SP) // errno
+ RET
+ok1:
+ MOVW R0, 20(SP) // r1
MOVW $0, R0
+ MOVW R0, 24(SP) // r2
MOVW R0, 28(SP) // errno
RET
+
diff --git a/src/pkg/syscall/asm_nacl_386.s b/src/pkg/syscall/asm_nacl_386.s
deleted file mode 100644
index 166d2acf0..000000000
--- a/src/pkg/syscall/asm_nacl_386.s
+++ /dev/null
@@ -1,119 +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.
-
-//
-// System calls for 386, Native Client
-//
-
-#define SYSCALL(x) $(0x10000+x * 32)
-
-// func Syscall(trap uintptr, a1, a2, a3 uintptr) (r1, r2, err uintptr);
-// Trap # in AX, args in BX CX DX SI DI, return in AX
-
-TEXT ·Syscall(SB),7,$20
- CALL runtime·entersyscall(SB)
- MOVL trap+0(FP), AX // syscall entry
- MOVL a1+4(FP), BX
- MOVL a2+8(FP), CX
- MOVL a3+12(FP), DX
- MOVL $0, SI
- MOVL $0, DI
-
- MOVL BX, 0(SP)
- MOVL CX, 4(SP)
- MOVL DX, 8(SP)
- MOVL SI, 12(SP)
- MOVL DI, 16(SP)
-
- // Call $(0x10000+32*AX)
- SHLL $5, AX
- ADDL $0x10000, AX
- CALL AX
-
- CMPL AX, $0xfffff001
- JLS ok
- MOVL $-1, r1+16(FP)
- MOVL $0, r2+20(FP)
- NEGL AX
- MOVL AX, errno+24(FP)
- CALL runtime·exitsyscall(SB)
- RET
-ok:
- MOVL AX, r1+16(FP)
- MOVL DX, r2+20(FP)
- MOVL $0, errno+24(FP)
- CALL runtime·exitsyscall(SB)
- RET
-
-// func Syscall6(trap uintptr, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr);
-TEXT ·Syscall6(SB),7,$24
- CALL runtime·entersyscall(SB)
- MOVL a1+4(FP), BX
- MOVL a2+8(FP), CX
- MOVL a3+12(FP), DX
- MOVL a4+16(FP), SI
- MOVL a5+20(FP), DI
- MOVL a6+24(FP), AX
-
- MOVL BX, 0(SP)
- MOVL CX, 4(SP)
- MOVL DX, 8(SP)
- MOVL SI, 12(SP)
- MOVL DI, 16(SP)
- MOVL AX, 20(SP)
-
- // Call $(0x10000+32*trap)
- MOVL trap+0(FP), AX // syscall entry
- SHLL $5, AX
- ADDL $0x10000, AX
- CALL AX
-
- CMPL AX, $0xfffff001
- JLS ok6
- MOVL $-1, r1+28(FP)
- MOVL $0, r2+32(FP)
- NEGL AX
- MOVL AX, errno+36(FP)
- CALL runtime·exitsyscall(SB)
- RET
-ok6:
- MOVL AX, r1+28(FP)
- MOVL DX, r2+32(FP)
- MOVL $0, errno+36(FP)
- CALL runtime·exitsyscall(SB)
- RET
-
-// func RawSyscall(trap uintptr, a1, a2, a3 uintptr) (r1, r2, err uintptr);
-TEXT ·RawSyscall(SB),7,$20
- MOVL trap+0(FP), AX // syscall entry
- MOVL a1+4(FP), BX
- MOVL a2+8(FP), CX
- MOVL a3+12(FP), DX
- MOVL $0, SI
- MOVL $0, DI
-
- MOVL BX, 0(SP)
- MOVL CX, 4(SP)
- MOVL DX, 8(SP)
- MOVL SI, 12(SP)
- MOVL DI, 16(SP)
-
- // Call $(0x10000+32*AX)
- SHLL $5, AX
- ADDL $0x10000, AX
- CALL AX
-
- CMPL AX, $0xfffff001
- JLS ok1
- MOVL $-1, r1+16(FP)
- MOVL $0, r2+20(FP)
- NEGL AX
- MOVL AX, errno+24(FP)
- RET
-ok1:
- MOVL AX, r1+16(FP)
- MOVL DX, r2+20(FP)
- MOVL $0, errno+24(FP)
- RET
-
diff --git a/src/pkg/syscall/exec.go b/src/pkg/syscall/exec_unix.go
index c7f7893e7..c7f7893e7 100644
--- a/src/pkg/syscall/exec.go
+++ b/src/pkg/syscall/exec_unix.go
diff --git a/src/pkg/syscall/exec_windows.go b/src/pkg/syscall/exec_windows.go
new file mode 100644
index 000000000..c3ed3ba98
--- /dev/null
+++ b/src/pkg/syscall/exec_windows.go
@@ -0,0 +1,203 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Fork, exec, wait, etc.
+
+package syscall
+
+import (
+ "sync"
+ "utf16"
+)
+
+// Windows doesn't have a good concept of just Exec in the documented API.
+// However, the kernel32 CreateProcess does a good job with
+// ForkExec.
+
+var ForkLock sync.RWMutex
+
+// Joins an array of string with sep
+// From the "strings" package. Modified.
+func stringJoin(a []string, sep string, escape escapeFunc) string {
+ if len(a) == 0 {
+ return ""
+ }
+ if len(a) == 1 {
+ return a[0]
+ }
+ n := len(sep) * (len(a) - 1)
+ for i := 0; i < len(a); i++ {
+ a[i] = escape(a[i])
+ n += len(a[i])
+ }
+
+ b := make([]byte, n)
+ bp := 0
+ for i := 0; i < len(a); i++ {
+ s := a[i]
+ for j := 0; j < len(s); j++ {
+ b[bp] = s[j]
+ bp++
+ }
+ if i+1 < len(a) {
+ s = sep
+ for j := 0; j < len(s); j++ {
+ b[bp] = s[j]
+ bp++
+ }
+ }
+ }
+ return string(b)
+}
+
+//Env block is a sequence of null terminated strings followed by a null.
+//Last bytes are two unicode nulls, or four null bytes.
+func createEnvBlock(envv []string) *uint16 {
+ if len(envv) == 0 {
+ return &utf16.Encode([]int("\x00\x00"))[0]
+ }
+ length := 0
+ for _, s := range envv {
+ length += len(s) + 1
+ }
+ length += 1
+
+ b := make([]byte, length)
+ i := 0
+ for _, s := range envv {
+ l := len(s)
+ copy(b[i:i+l], []byte(s))
+ copy(b[i+l:i+l+1], []byte{0})
+ i = i + l + 1
+ }
+ copy(b[i:i+1], []byte{0})
+
+ return &utf16.Encode([]int(string(b)))[0]
+}
+
+type escapeFunc func(s string) string
+
+//escapes quotes by " -> ""
+//Also string -> "string"
+func escapeAddQuotes(s string) string {
+ //normal ascii char, one byte wide
+ rune := byte('"')
+ l := len(s)
+ n := 0
+ for i := 0; i < l; i++ {
+ if s[i] == rune {
+ n++
+ }
+ }
+ qs := make([]byte, l+n+2)
+
+ qs[0] = rune
+ j := 1
+ for i := 0; i < l; i++ {
+ qs[i+j] = s[i]
+ if s[i] == rune {
+ j++
+ qs[i+j] = rune
+ }
+ }
+ qs[len(qs)-1] = rune
+ return string(qs)
+}
+
+
+func CloseOnExec(fd int) {
+ return
+}
+
+func SetNonblock(fd int, nonblocking bool) (errno int) {
+ return 0
+}
+
+
+// TODO(kardia): Add trace
+//The command and arguments are passed via the Command line parameter.
+func forkExec(argv0 string, argv []string, envv []string, traceme bool, dir string, fd []int) (pid int, err int) {
+ if traceme == true {
+ return 0, EWINDOWS
+ }
+
+ if len(fd) > 3 {
+ return 0, EWINDOWS
+ }
+
+ //CreateProcess will throw an error if the dir is not set to a valid dir
+ // thus get the working dir if dir is empty.
+ if len(dir) == 0 {
+ if wd, ok := Getwd(); ok == 0 {
+ dir = wd
+ }
+ }
+
+ startupInfo := new(StartupInfo)
+ processInfo := new(ProcessInformation)
+
+ GetStartupInfo(startupInfo)
+
+ startupInfo.Flags = STARTF_USESTDHANDLES
+ startupInfo.StdInput = 0
+ startupInfo.StdOutput = 0
+ startupInfo.StdErr = 0
+
+ var currentProc, _ = GetCurrentProcess()
+ if len(fd) > 0 && fd[0] > 0 {
+ if ok, err := DuplicateHandle(currentProc, int32(fd[0]), currentProc, &startupInfo.StdInput, 0, true, DUPLICATE_SAME_ACCESS); !ok {
+ return 0, err
+ }
+ defer CloseHandle(int32(startupInfo.StdInput))
+ }
+ if len(fd) > 1 && fd[1] > 0 {
+ if ok, err := DuplicateHandle(currentProc, int32(fd[1]), currentProc, &startupInfo.StdOutput, 0, true, DUPLICATE_SAME_ACCESS); !ok {
+ return 0, err
+ }
+ defer CloseHandle(int32(startupInfo.StdOutput))
+ }
+ if len(fd) > 2 && fd[2] > 0 {
+ if ok, err := DuplicateHandle(currentProc, int32(fd[2]), currentProc, &startupInfo.StdErr, 0, true, DUPLICATE_SAME_ACCESS); !ok {
+ return 0, err
+ }
+ defer CloseHandle(int32(startupInfo.StdErr))
+ }
+ if len(argv) == 0 {
+ argv = []string{""}
+ }
+ // argv0 must not be longer then 256 chars
+ // but the entire cmd line can have up to 32k chars (msdn)
+ ok, err := CreateProcess(
+ nil,
+ StringToUTF16Ptr(escapeAddQuotes(argv0)+" "+stringJoin(argv[1:], " ", escapeAddQuotes)),
+ nil, //ptr to struct lpProcessAttributes
+ nil, //ptr to struct lpThreadAttributes
+ true, //bInheritHandles
+ CREATE_UNICODE_ENVIRONMENT, //Flags
+ createEnvBlock(envv), //env block, NULL uses parent env
+ StringToUTF16Ptr(dir),
+ startupInfo,
+ processInfo)
+
+ if ok {
+ pid = int(processInfo.ProcessId)
+ CloseHandle(processInfo.Process)
+ CloseHandle(processInfo.Thread)
+ }
+ return
+}
+
+func ForkExec(argv0 string, argv []string, envv []string, dir string, fd []int) (pid int, err int) {
+ return forkExec(argv0, argv, envv, false, dir, fd)
+}
+
+// PtraceForkExec is like ForkExec, but starts the child in a traced state.
+func PtraceForkExec(argv0 string, argv []string, envv []string, dir string, fd []int) (pid int, err int) {
+ return forkExec(argv0, argv, envv, true, dir, fd)
+}
+
+// Ordinary exec.
+func Exec(argv0 string, argv []string, envv []string) (err int) {
+ return EWINDOWS
+}
diff --git a/src/pkg/syscall/mkall.sh b/src/pkg/syscall/mkall.sh
index 12d8c3310..a1f8ae2ff 100755
--- a/src/pkg/syscall/mkall.sh
+++ b/src/pkg/syscall/mkall.sh
@@ -102,12 +102,12 @@ _* | *_ | _)
freebsd_386)
mkerrors="$mkerrors -f -m32"
mksyscall="./mksyscall.sh -l32"
- mksysnum="./mksysnum_freebsd.sh /usr/src/sys/kern/syscalls.master"
+ mksysnum="curl -s 'http://svn.freebsd.org/viewvc/base/head/sys/kern/syscalls.master?view=markup' | ./mksysnum_freebsd.sh"
mktypes="godefs -gsyscall -f-m32"
;;
freebsd_amd64)
mkerrors="$mkerrors -f -m64"
- mksysnum="./mksysnum_freebsd.sh /usr/src/sys/kern/syscalls.master"
+ mksysnum="curl -s 'http://svn.freebsd.org/viewvc/base/head/sys/kern/syscalls.master?view=markup' | ./mksysnum_freebsd.sh"
mktypes="godefs -gsyscall -f-m64"
;;
darwin_386)
@@ -137,24 +137,22 @@ nacl_386)
NACL="/home/rsc/pub/nacl/native_client"
NACLRUN="$NACL/src/trusted/service_runtime"
NACLSDK="$NACL/src/third_party/nacl_sdk/linux/sdk/nacl-sdk/nacl"
- mksyscall="./mksyscall.sh -l32"
+ mksyscall="./mksyscall.sh -l32 -nacl"
mksysnum="./mksysnum_nacl.sh $NACLRUN/include/bits/nacl_syscalls.h"
mktypes="godefs -gsyscall -f-m32 -f-I$NACLSDK/include -f-I$NACL"
mkerrors="./mkerrors_nacl.sh $NACLRUN/include/sys/errno.h"
;;
linux_arm)
- ARM="/home/kaib/public/linux-2.6.28"
- mksyscall="./mksyscall.sh -l32"
- mksysnum="./mksysnum_linux.sh $ARM/arch/arm/include/asm/unistd.h"
-# mktypes="godefs -gsyscall -carm-gcc -f-I$ARM/arch/arm/include -f-I$ARM/include -f-D__deprecated='' -f-I$ARM/arch/arm/mach-at91/include -f-DCONFIG_ARCH_AT91SAM9260 "
- mktypes="godefs -gsyscall -carm-gcc"
- mkerrors='GORUN="qemu-arm -cpu cortex-a8" ./mkerrors.sh'
+ mkerrors="$mkerrors"
+ mksyscall="./mksyscall.sh -b32"
+ mksysnum="./mksysnum_linux.sh /usr/include/asm/unistd.h"
+ mktypes="godefs -gsyscall"
;;
windows_386)
mksyscall="./mksyscall_windows.sh -l32"
mksysnum=
mktypes=
- mkerrors=
+ mkerrors="./mkerrors_windows.sh -f -m32"
;;
*)
echo 'unrecognized $GOOS_$GOARCH: ' "$GOOSARCH" 1>&2
diff --git a/src/pkg/syscall/mkerrors.sh b/src/pkg/syscall/mkerrors.sh
index 3e55ea770..3605b57b2 100755
--- a/src/pkg/syscall/mkerrors.sh
+++ b/src/pkg/syscall/mkerrors.sh
@@ -11,14 +11,7 @@ unset LANG
export LC_ALL=C
export LC_CTYPE=C
-case "$GOARCH" in
-arm)
- GCC=arm-gcc
- ;;
-*)
- GCC=gcc
- ;;
-esac
+GCC=gcc
uname=$(uname)
@@ -30,8 +23,15 @@ includes_Linux='
#include <sys/types.h>
#include <sys/epoll.h>
+#include <sys/inotify.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
#include <linux/ptrace.h>
#include <linux/wait.h>
+#include <linux/if_tun.h>
+#include <net/if.h>
+#include <netpacket/packet.h>
'
includes_Darwin='
@@ -85,20 +85,27 @@ done
echo "${!indirect} $includes" | $GCC -x c - -E -dM $ccflags |
awk '
$1 != "#define" || $2 ~ /\(/ {next}
-
+
$2 ~ /^E([ABCD]X|[BIS]P|[SD]I|S|FL)$/ {next} # 386 registers
$2 ~ /^(SIGEV_|SIGSTKSZ|SIGRT(MIN|MAX))/ {next}
+ $2 ~ /^(SCM_SRCRT)$/ {next}
+ $2 ~ /^(MAP_FAILED)$/ {next}
+ $2 !~ /^ETH_/ &&
$2 ~ /^E[A-Z0-9_]+$/ ||
$2 ~ /^SIG[^_]/ ||
- $2 ~ /^(AF|SOCK|SO|SOL|IPPROTO|IP|IPV6|TCP|EVFILT|EV|SHUT|PROT|MAP)_/ ||
+ $2 ~ /^IN_/ ||
+ $2 ~ /^(AF|SOCK|SO|SOL|IPPROTO|IP|IPV6|TCP|EVFILT|EV|SHUT|PROT|MAP|PACKET|MSG|SCM|IFF)_/ ||
$2 == "SOMAXCONN" ||
$2 == "NAME_MAX" ||
+ $2 == "IFNAMSIZ" ||
+ $2 ~ /^TUN(SET|GET|ATTACH|DETACH)/ ||
$2 ~ /^(O|F|FD|NAME|S|PTRACE)_/ ||
+ $2 ~ /^SIO/ ||
$2 ~ /^W[A-Z0-9]+$/ {printf("\t$%s = %s,\n", $2, $2)}
$2 ~ /^__WCOREFLAG$/ {next}
$2 ~ /^__W[A-Z0-9]+$/ {printf("\t$%s = %s,\n", substr($2,3), $2)}
-
+
{next}
' | sort
@@ -141,6 +148,12 @@ int errors[] = {
/bin/echo '
};
+static int
+intcmp(const void *a, const void *b)
+{
+ return *(int*)a - *(int*)b;
+}
+
int
main(void)
{
@@ -149,17 +162,16 @@ main(void)
printf("\n\n// Error table\n");
printf("var errors = [...]string {\n");
+ qsort(errors, nelem(errors), sizeof errors[0], intcmp);
for(i=0; i<nelem(errors); i++) {
e = errors[i];
- for(j=0; j<i; j++)
- if(errors[j] == e) // duplicate value
- goto next;
+ if(i > 0 && errors[i-1] == e)
+ continue;
strcpy(buf, strerror(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;
printf("\t%d: \"%s\",\n", e, buf);
- next:;
}
printf("}\n\n");
return 0;
@@ -168,4 +180,4 @@ main(void)
'
) >_errors.c
-$GCC $ccflags -static -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.c
diff --git a/src/pkg/syscall/mkerrors_nacl.sh b/src/pkg/syscall/mkerrors_nacl.sh
deleted file mode 100755
index f8abff9c2..000000000
--- a/src/pkg/syscall/mkerrors_nacl.sh
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/bin/sh
-# Copyright 2009 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-# Generate Go code listing error values (ENAMETOOLONG etc)
-# for Native Client.
-
-echo '// mkerrors_nacl.sh' "$@"
-echo '// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT'
-echo
-echo 'package syscall'
-echo
-echo 'const ('
-perl -n -e '
- if(/#define\s+NACL_ABI_(\S*)\s+([0-9]+)/) {
- print "\t$1 = $2;\n"
- }
-' $1
-echo ' ENACL = 99; /* otherwise unused */'
-echo ')'
-echo
-echo
-echo '// Error table'
-echo 'var errors = [...]string {'
-perl -n -e '
- if(/#define\s+NACL_ABI_(\S*)\s+([0-9]+)\s+\/\* (.*) \*\//) {
- $err = $1;
- $text = $3;
- if($text =~ /^[A-Z][a-z]/) {
- # lowercase first letter: Bad -> bad, but STREAM -> STREAM.
- $l = substr($text, 0, 1);
- $rest = substr($text, 1);
- $l =~ y/A-Z/a-z/;
- $text = $l . $rest;
- }
- print "\t$err: \"$text\",\n";
- }
-' $1
-echo ' ENACL: "not supported by native client",'
-echo '}'
diff --git a/src/pkg/syscall/mkerrors_windows.sh b/src/pkg/syscall/mkerrors_windows.sh
new file mode 100755
index 000000000..f5d4914cf
--- /dev/null
+++ b/src/pkg/syscall/mkerrors_windows.sh
@@ -0,0 +1,210 @@
+#!/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.
+
+# Generate Go code listing errors and other #defined constant
+# values (ENAMETOOLONG etc.), by asking the preprocessor
+# about the definitions.
+
+unset LANG
+export LC_ALL=C
+export LC_CTYPE=C
+
+case "$GOARCH" in
+arm)
+ GCC=arm-gcc
+ ;;
+*)
+ GCC=gcc
+ ;;
+esac
+
+uname=$(uname)
+
+includes_Linux='
+#define _LARGEFILE_SOURCE
+#define _LARGEFILE64_SOURCE
+#define _FILE_OFFSET_BITS 64
+#define _GNU_SOURCE
+
+#include <sys/types.h>
+#include <sys/epoll.h>
+#include <linux/ptrace.h>
+#include <linux/wait.h>
+'
+
+includes_Darwin='
+#define __DARWIN_UNIX03 0
+#define KERNEL
+#define _DARWIN_USE_64_BIT_INODE
+#include <sys/wait.h>
+#include <sys/event.h>
+'
+
+includes_FreeBSD='
+#include <sys/wait.h>
+#include <sys/event.h>
+'
+
+includes='
+#include <sys/types.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/tcp.h>
+#include <errno.h>
+#include <sys/signal.h>
+#include <signal.h>
+'
+
+ccflags=""
+next=false
+for i
+do
+ if $next; then
+ ccflags="$ccflags $i"
+ next=false
+ elif [ "$i" = "-f" ]; then
+ next=true
+ fi
+done
+
+# These are go errors that will be mapped directly to windows errors
+goerrors='
+ENOENT:ERROR_FILE_NOT_FOUND
+ENOTDIR:ERROR_DIRECTORY
+'
+
+# Pull out just the error names for later.
+i=$(
+ for j in "$goerrors"
+ do
+ echo "$j"
+ done |
+ awk -F: '
+ { if (NR > 1) printf("|") }
+ { printf("%s", $1) }
+ '
+)
+errors=$(
+ echo '#include <errno.h>' | $GCC -x c - -E -dM $ccflags |
+ awk '
+ $1 != "#define" || $2 ~ /\(/ {next}
+ $2 ~ /^('$i')$/ {next}
+ $2 ~ /^E[A-Z0-9_]+$/ { print $2 }
+ {next}
+ ' | sort
+)
+
+echo '// mkerrors_windows.sh' "$@"
+echo '// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT'
+echo
+echo 'package syscall'
+
+# Run C program to print error strings.
+(
+ /bin/echo "
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+#include <string.h>
+
+#define nelem(x) (sizeof(x)/sizeof((x)[0]))
+
+enum { A = 'A', Z = 'Z', a = 'a', z = 'z' }; // avoid need for single quotes below
+
+struct {
+ char *goname;
+ char *winname;
+} goerrors[] = {
+"
+ for i in $goerrors
+ do
+ j=`echo $i | cut -d: -f1`
+ k=`echo $i | cut -d: -f2`
+ echo ' {"'$j'", "'$k'"},'
+ done
+
+ # Use /bin/echo to avoid builtin echo,
+ # which interprets \n itself
+ /bin/echo '
+};
+
+struct {
+ char *name;
+ int value;
+} errors[] = {
+'
+ for i in $errors
+ do
+ echo ' {"'$i'",' $i'},'
+ done
+
+ # Use /bin/echo to avoid builtin echo,
+ # which interprets \n itself
+ /bin/echo '
+};
+
+int
+main(void)
+{
+ int i, j, e, iota = 1;
+ char buf[1024];
+
+ 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(")\n");
+
+ printf("\n// Windows reserves errors >= 1<<29 for application use.\n");
+ printf("const APPLICATION_ERROR = 1 << 29\n");
+
+ printf("\n// Invented values to support what package os and others expects.\n");
+ printf("const (\n");
+ for(i=0; i<nelem(errors); i++) {
+ e = errors[i].value;
+ strcpy(buf, strerror(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;
+ printf("\t%s", errors[i].name);
+ if(iota) {
+ printf(" = APPLICATION_ERROR + iota");
+ iota = !iota;
+ }
+ printf("\n");
+
+ }
+ printf("\tEWINDOWS\n");
+ printf(")\n");
+
+ printf("\n// Error strings for invented errors\n");
+ printf("var errors = [...]string {\n");
+ for(i=0; i<nelem(errors); i++) {
+ e = errors[i].value;
+ for(j=0; j<i; j++)
+ if(errors[j].value == e) // duplicate value
+ goto next;
+ strcpy(buf, strerror(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;
+ printf("\t%s - APPLICATION_ERROR: \"%s\",\n", errors[i].name, buf);
+ next:;
+ }
+ printf("\tEWINDOWS - APPLICATION_ERROR: \"not supported by windows\",\n");
+ printf("}\n\n");
+ return 0;
+}
+
+'
+) >_errors.c
+
+$GCC $ccflags -static -o _errors _errors.c && $GORUN ./_errors && rm -f _errors.c _errors
diff --git a/src/pkg/syscall/mksyscall.sh b/src/pkg/syscall/mksyscall.sh
index 215882552..79d19d0d0 100755
--- a/src/pkg/syscall/mksyscall.sh
+++ b/src/pkg/syscall/mksyscall.sh
@@ -16,6 +16,7 @@
$cmdline = "mksyscall.sh " . join(' ', @ARGV);
$errors = 0;
$_32bit = "";
+$nacl = 0;
if($ARGV[0] eq "-b32") {
$_32bit = "big-endian";
@@ -24,6 +25,10 @@ if($ARGV[0] eq "-b32") {
$_32bit = "little-endian";
shift;
}
+if($ARGV[0] eq "-nacl") {
+ $nacl = 1;
+ shift;
+}
if($ARGV[0] =~ /^-/) {
print STDERR "usage: mksyscall.sh [-b32 | -l32] [file ...]\n";
@@ -72,8 +77,14 @@ while(<>) {
my @in = parseparamlist($in);
my @out = parseparamlist($out);
+ # Try in vain to keep people from editing this file.
+ # The theory is that they jump into the middle of the file
+ # without reading the header.
+ $text .= "// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n\n";
+
# Go function header.
- $text .= sprintf "func %s(%s) (%s) {\n", $func, join(', ', @in), join(', ', @out);
+ my $out_decl = @out ? sprintf(" (%s)", join(', ', @out)) : "";
+ $text .= sprintf "func %s(%s)%s {\n", $func, join(', ', @in), $out_decl;
# Prepare arguments to Syscall.
my @args = ();
@@ -88,15 +99,21 @@ while(<>) {
# Convert slice into pointer, length.
# Have to be careful not to take address of &a[0] if len == 0:
# pass nil in that case.
- $text .= "\tvar _p$n *$1;\n";
- $text .= "\tif len($name) > 0 { _p$n = \&${name}[0]; }\n";
- push @args, "uintptr(unsafe.Pointer(_p$n))", "uintptr(len($name))";
+ $text .= "\tvar _p$n unsafe.Pointer\n";
+ $text .= "\tif len($name) > 0 {\n\t\t_p$n = unsafe.Pointer(\&${name}[0])\n\t}";
+ if($nacl) {
+ # NaCl rejects zero length write with nil pointer,
+ # so use non-nil pointer.
+ $text .= " else {\n\t\t_p$n = unsafe.Pointer(&_zero[0])\n\t}";
+ }
+ $text .= "\n";
+ push @args, "uintptr(_p$n)", "uintptr(len($name))";
$n++;
} elsif($type eq "int64" && $_32bit ne "") {
if($_32bit eq "big-endian") {
- push @args, "uintptr($name >> 32)", "uintptr($name)";
+ push @args, "uintptr($name>>32)", "uintptr($name)";
} else {
- push @args, "uintptr($name)", "uintptr($name >> 32)";
+ push @args, "uintptr($name)", "uintptr($name>>32)";
}
} else {
push @args, "uintptr($name)";
@@ -159,19 +176,22 @@ while(<>) {
$ret[$i] = sprintf("r%d", $i);
$ret[$i+1] = sprintf("r%d", $i+1);
}
- $body .= "\t$name = $type($reg);\n";
+ $body .= "\t$name = $type($reg)\n";
}
if ($ret[0] eq "_" && $ret[1] eq "_" && $ret[2] eq "_") {
- $text .= "\t$call;\n";
+ $text .= "\t$call\n";
} else {
- $text .= "\t$ret[0], $ret[1], $ret[2] := $call;\n";
+ $text .= "\t$ret[0], $ret[1], $ret[2] := $call\n";
}
$text .= $body;
- $text .= "\treturn;\n";
+ $text .= "\treturn\n";
$text .= "}\n\n";
}
+chomp $text;
+chomp $text;
+
if($errors) {
exit 1;
}
@@ -185,6 +205,5 @@ package syscall
import "unsafe"
$text
-
EOF
exit 0;
diff --git a/src/pkg/syscall/mksyscall_windows.sh b/src/pkg/syscall/mksyscall_windows.sh
index f9b4584fc..9695d3f22 100755
--- a/src/pkg/syscall/mksyscall_windows.sh
+++ b/src/pkg/syscall/mksyscall_windows.sh
@@ -15,13 +15,13 @@
# * 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 number,
+# * Each function, that returns errno, 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
# at end of //sys declaration, like
-# //sys LoadLibrary(libname string) (handle uint32, errno int) [failretval=-1] = LoadLibraryA
-# and is 0 by default.
+# //sys LoadLibrary(libname string) (handle uint32, errno int) [failretval==-1] = LoadLibraryA
+# and is [failretval==0] by default.
$cmdline = "mksyscall_windows.sh " . join(' ', @ARGV);
$errors = 0;
@@ -74,12 +74,12 @@ while(<>) {
# Line must be of the form
# func Open(path string, mode int, perm int) (fd int, errno int)
# Split into name, in params, out params.
- if(!/^\/\/sys (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:\[failretval=(.*)\])?\s*(?:=\s*(?:(\w*)\.)?(\w*))?$/) {
+ if(!/^\/\/sys (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:\[failretval(.*)\])?\s*(?:=\s*(?:(\w*)\.)?(\w*))?$/) {
print STDERR "$ARGV:$.: malformed //sys declaration\n";
$errors = 1;
next;
}
- my ($func, $in, $out, $failretval, $modname, $sysname) = ($1, $2, $3, $4, $5, $6);
+ my ($func, $in, $out, $failcond, $modname, $sysname) = ($1, $2, $3, $4, $5, $6);
# Split argument lists on comma.
my @in = parseparamlist($in);
@@ -104,8 +104,8 @@ while(<>) {
$sysvarname = "proc$sysname";
# Returned value when failed
- if($failretval eq "") {
- $failretval = "0";
+ if($failcond eq "") {
+ $failcond = "==0";
}
# Decide which version of api is used: ascii or unicode.
@@ -145,6 +145,10 @@ while(<>) {
} else {
push @args, "uintptr($name)", "uintptr($name >> 32)";
}
+ } elsif($type eq "bool") {
+ $text .= "\tvar _p$n uint32;\n";
+ $text .= "\tif $name { _p$n = 1; } else { _p$n = 0;}\n";
+ push @args, "uintptr(_p$n)";
} else {
push @args, "uintptr($name)";
}
@@ -167,6 +171,11 @@ while(<>) {
while(@args < 9) {
push @args, "0";
}
+ } elsif(@args <= 12) {
+ $asm = "Syscall12";
+ while(@args < 12) {
+ push @args, "0";
+ }
} else {
print STDERR "$ARGV:$.: too many arguments to system call\n";
}
@@ -207,25 +216,34 @@ while(<>) {
$ret[$i] = sprintf("r%d", $i);
$ret[$i+1] = sprintf("r%d", $i+1);
}
+ my $rettype = $type;
+ if($type =~ /^\*/) {
+ $reg = "unsafe.Pointer($reg)";
+ $rettype = "($rettype)";
+ }
if($i == 0) {
if($type eq "bool") {
$failexpr = "!$name";
} elsif($name eq "errno") {
$ret[$i] = "r1";
- $failexpr = "int(r1) == $failretval";
+ $failexpr = "int(r1) $failcond";
} else {
- $failexpr = "$name == $failretval";
+ $failexpr = "$name $failcond";
}
}
if($name eq "errno") {
# Set errno to "last error" only if returned value indicate failure
$body .= "\tif $failexpr {\n";
- $body .= "\t\t$name = $type($reg);\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}\n";
$body .= "\t} else {\n";
$body .= "\t\t$name = 0;\n";
$body .= "\t}\n";
} else {
- $body .= "\t$name = $type($reg);\n";
+ $body .= "\t$name = $rettype($reg);\n";
}
push @pout, sprintf "\"%s=\", %s, ", $name, $name;
}
diff --git a/src/pkg/syscall/mksysnum_linux.sh b/src/pkg/syscall/mksysnum_linux.sh
index 74a1931bb..89ece8a91 100755
--- a/src/pkg/syscall/mksysnum_linux.sh
+++ b/src/pkg/syscall/mksysnum_linux.sh
@@ -14,12 +14,20 @@ package syscall
const(
EOF
+sub fmt {
+ my ($name, $num) = @_;
+ $name =~ y/a-z/A-Z/;
+ print " SYS_$name = $num;\n";
+}
+
+my $prev;
while(<>){
if(/^#define __NR_(\w+)\s+([0-9]+)/){
- my $name = "SYS_$1";
- my $num = $2;
- $name =~ y/a-z/A-Z/;
- print " $name = $num;\n";
+ $prev = $2;
+ fmt($1, $2);
+ }
+ elsif(/^#define __NR_(\w+)\s+\(\w+\+([0-9]+)\)/){
+ fmt($1, $prev+$2)
}
}
diff --git a/src/pkg/syscall/mksysnum_nacl.sh b/src/pkg/syscall/mksysnum_nacl.sh
deleted file mode 100644
index f42f45056..000000000
--- a/src/pkg/syscall/mksysnum_nacl.sh
+++ /dev/null
@@ -1,29 +0,0 @@
-#!/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.
-
-my $command = "mksysnum_nacl.sh ". join(' ', @ARGV);
-
-print <<EOF;
-// $command
-// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
-
-package syscall
-
-const(
-EOF
-
-while(<>){
- if(/^#define NACL_sys_(\w+)\s+([0-9]+)/){
- my $name = "SYS_$1";
- my $num = $2;
- $name =~ y/a-z/A-Z/;
- print " $name = $num;\n";
- }
-}
-
-print <<EOF;
-)
-
-EOF
diff --git a/src/pkg/syscall/syscall.go b/src/pkg/syscall/syscall.go
index 46f5c9876..b7761a699 100644
--- a/src/pkg/syscall/syscall.go
+++ b/src/pkg/syscall/syscall.go
@@ -21,9 +21,7 @@ func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr)
// containing the text of s.
func StringByteSlice(s string) []byte {
a := make([]byte, len(s)+1)
- for i := 0; i < len(s); i++ {
- a[i] = s[i]
- }
+ copy(a, s)
return a
}
diff --git a/src/pkg/syscall/syscall_bsd.go b/src/pkg/syscall/syscall_bsd.go
index 14dfab153..ff99fd9e6 100644
--- a/src/pkg/syscall/syscall_bsd.go
+++ b/src/pkg/syscall/syscall_bsd.go
@@ -1,4 +1,4 @@
-// Copyright 2009,2010 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.
@@ -239,8 +239,8 @@ func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, int) {
break
}
}
- bytes := (*[len(pp.Path)]byte)(unsafe.Pointer(&pp.Path[0]))
- sa.Name = string(bytes[0:n])
+ bytes := (*[10000]byte)(unsafe.Pointer(&pp.Path[0]))[0:n]
+ sa.Name = string(bytes)
return sa, 0
case AF_INET:
@@ -323,8 +323,10 @@ func Socket(domain, typ, proto int) (fd, errno int) {
return
}
+//sys socketpair(domain int, typ int, proto int, fd *[2]int) (errno int)
+
func Socketpair(domain, typ, proto int) (fd [2]int, errno int) {
- fd, errno = socketpair(domain, typ, proto)
+ errno = socketpair(domain, typ, proto, &fd)
return
}
@@ -483,6 +485,13 @@ func Futimes(fd int, tv []Timeval) (errno int) {
//sys fcntl(fd int, cmd int, arg int) (val int, errno int)
+func Recvmsg(fd int, p, oob []byte, from Sockaddr, flags int) (n, oobn int, recvflags int, errno int) {
+ return 0, 0, 0, EAFNOSUPPORT
+}
+
+func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (errno int) {
+ return EAFNOSUPPORT
+}
// TODO: wrap
// Acct(name nil-string) (errno int)
@@ -493,5 +502,3 @@ func Futimes(fd int, tv []Timeval) (errno int) {
// Msync(addr *byte, len int, flags int) (errno int)
// Munmap(addr *byte, len int) (errno int)
// Ptrace(req int, pid int, addr uintptr, data int) (ret uintptr, errno int)
-// Recvmsg(s int, msg *Msghdr, flags int) (n int, errno int)
-// Sendmsg(s int, msg *Msghdr, flags int) (n int, errno int)
diff --git a/src/pkg/syscall/syscall_darwin.go b/src/pkg/syscall/syscall_darwin.go
index 263588558..ab83af5c1 100644
--- a/src/pkg/syscall/syscall_darwin.go
+++ b/src/pkg/syscall/syscall_darwin.go
@@ -25,11 +25,11 @@ func Kill(pid int, signum int) (errno int) { return kill(pid, signum, 1) }
/*
* Exposed directly
*/
-//sys Access(path string, flags int) (errno int)
+//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 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)
@@ -39,7 +39,7 @@ func Kill(pid int, signum int) (errno int) { return kill(pid, signum, 1) }
//sys Exit(code int)
//sys Fchdir(fd int) (errno int)
//sys Fchflags(path string, flags int) (errno int)
-//sys Fchmod(fd int, mode 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)
@@ -68,10 +68,10 @@ func Kill(pid int, signum int) (errno int) { return kill(pid, signum, 1) }
//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 int) (errno int)
-//sys Mkfifo(path string, mode int) (errno int)
-//sys Mknod(path string, mode int, dev int) (errno int)
-//sys Open(path string, mode int, perm int) (fd int, 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 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)
diff --git a/src/pkg/syscall/syscall_freebsd.go b/src/pkg/syscall/syscall_freebsd.go
index acf636797..ee947be20 100644
--- a/src/pkg/syscall/syscall_freebsd.go
+++ b/src/pkg/syscall/syscall_freebsd.go
@@ -17,11 +17,11 @@ const OS = "freebsd"
/*
* Exposed directly
*/
-//sys Access(path string, flags int) (errno int)
+//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 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)
@@ -30,7 +30,7 @@ const OS = "freebsd"
//sys Exit(code int)
//sys Fchdir(fd int) (errno int)
//sys Fchflags(path string, flags int) (errno int)
-//sys Fchmod(fd int, mode 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)
@@ -61,11 +61,11 @@ const OS = "freebsd"
//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 int) (errno int)
-//sys Mkfifo(path string, mode int) (errno int)
-//sys Mknod(path string, mode int, dev int) (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 int) (fd 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)
diff --git a/src/pkg/syscall/syscall_linux.go b/src/pkg/syscall/syscall_linux.go
index 2ce3c0882..a65e41dc6 100644
--- a/src/pkg/syscall/syscall_linux.go
+++ b/src/pkg/syscall/syscall_linux.go
@@ -19,13 +19,13 @@ const OS = "linux"
* Wrapped
*/
-//sys open(path string, mode int, perm int) (fd int, errno int)
-func Open(path string, mode int, perm int) (fd int, errno int) {
+//sys open(path string, mode int, perm uint32) (fd int, errno int)
+func Open(path string, mode int, perm uint32) (fd int, errno int) {
return open(path, mode|O_LARGEFILE, perm)
}
-//sys openat(dirfd int, path string, flags int, mode int) (fd int, errno int)
-func Openat(dirfd int, path string, flags int, mode int) (fd int, errno int) {
+//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) {
return openat(dirfd, path, flags|O_LARGEFILE, mode)
}
@@ -261,8 +261,47 @@ func (sa *SockaddrUnix) sockaddr() (uintptr, _Socklen, int) {
return uintptr(unsafe.Pointer(&sa.raw)), 1 + _Socklen(n) + 1, 0
}
+type SockaddrLinklayer struct {
+ Protocol uint16
+ Ifindex int
+ Hatype uint16
+ Pkttype uint8
+ Halen uint8
+ Addr [8]byte
+ raw RawSockaddrLinklayer
+}
+
+func (sa *SockaddrLinklayer) sockaddr() (uintptr, _Socklen, int) {
+ if sa.Ifindex < 0 || sa.Ifindex > 0x7fffffff {
+ return 0, 0, EINVAL
+ }
+ sa.raw.Family = AF_PACKET
+ sa.raw.Protocol = sa.Protocol
+ sa.raw.Ifindex = int32(sa.Ifindex)
+ sa.raw.Hatype = sa.Hatype
+ sa.raw.Pkttype = sa.Pkttype
+ sa.raw.Halen = sa.Halen
+ for i := 0; i < len(sa.Addr); i++ {
+ sa.raw.Addr[i] = sa.Addr[i]
+ }
+ return uintptr(unsafe.Pointer(&sa.raw)), SizeofSockaddrLinklayer, 0
+}
+
func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, int) {
switch rsa.Addr.Family {
+ case AF_PACKET:
+ pp := (*RawSockaddrLinklayer)(unsafe.Pointer(rsa))
+ sa := new(SockaddrLinklayer)
+ sa.Protocol = pp.Protocol
+ sa.Ifindex = int(pp.Ifindex)
+ sa.Hatype = pp.Hatype
+ sa.Pkttype = pp.Pkttype
+ sa.Halen = pp.Halen
+ for i := 0; i < len(sa.Addr); i++ {
+ sa.Addr[i] = pp.Addr[i]
+ }
+ return sa, 0
+
case AF_UNIX:
pp := (*RawSockaddrUnix)(unsafe.Pointer(rsa))
sa := new(SockaddrUnix)
@@ -284,8 +323,8 @@ func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, int) {
for n < len(pp.Path) && pp.Path[n] != 0 {
n++
}
- bytes := (*[len(pp.Path)]byte)(unsafe.Pointer(&pp.Path[0]))
- sa.Name = string(bytes[0:n])
+ bytes := (*[10000]byte)(unsafe.Pointer(&pp.Path[0]))[0:n]
+ sa.Name = string(bytes)
return sa, 0
case AF_INET:
@@ -369,7 +408,7 @@ func Socket(domain, typ, proto int) (fd, errno int) {
}
func Socketpair(domain, typ, proto int) (fd [2]int, errno int) {
- fd, errno = socketpair(domain, typ, proto)
+ errno = socketpair(domain, typ, proto, &fd)
return
}
@@ -408,6 +447,72 @@ func Sendto(fd int, p []byte, flags int, to Sockaddr) (errno int) {
return sendto(fd, p, flags, ptr, n)
}
+func Recvmsg(fd int, p, oob []byte, from Sockaddr, flags int) (n, oobn int, recvflags int, errno int) {
+ var msg Msghdr
+ var rsa RawSockaddrAny
+ msg.Name = (*byte)(unsafe.Pointer(&rsa))
+ msg.Namelen = uint32(SizeofSockaddrAny)
+ var iov Iovec
+ if len(p) > 0 {
+ iov.Base = (*byte)(unsafe.Pointer(&p[0]))
+ iov.SetLen(len(p))
+ }
+ var dummy byte
+ if len(oob) > 0 {
+ // receive at least one normal byte
+ if len(p) == 0 {
+ iov.Base = &dummy
+ iov.SetLen(1)
+ }
+ msg.Control = (*byte)(unsafe.Pointer(&oob[0]))
+ msg.SetControllen(len(oob))
+ }
+ msg.Iov = &iov
+ msg.Iovlen = 1
+ if n, errno = recvmsg(fd, &msg, flags); errno != 0 {
+ return
+ }
+ oobn = int(msg.Controllen)
+ recvflags = int(msg.Flags)
+ return
+}
+
+func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (errno int) {
+ var ptr uintptr
+ var nsock _Socklen
+ if to != nil {
+ var err int
+ ptr, nsock, err = to.sockaddr()
+ if err != 0 {
+ return err
+ }
+ }
+ var msg Msghdr
+ msg.Name = (*byte)(unsafe.Pointer(ptr))
+ msg.Namelen = uint32(nsock)
+ var iov Iovec
+ if len(p) > 0 {
+ iov.Base = (*byte)(unsafe.Pointer(&p[0]))
+ iov.SetLen(len(p))
+ }
+ var dummy byte
+ if len(oob) > 0 {
+ // send at least one normal byte
+ if len(p) == 0 {
+ iov.Base = &dummy
+ iov.SetLen(1)
+ }
+ msg.Control = (*byte)(unsafe.Pointer(&oob[0]))
+ msg.SetControllen(len(oob))
+ }
+ msg.Iov = &iov
+ msg.Iovlen = 1
+ if errno = sendmsg(fd, &msg, flags); errno != 0 {
+ return
+ }
+ return
+}
+
// BindToDevice binds the socket associated with fd to device.
func BindToDevice(fd int, device string) (errno int) {
return SetsockoptString(fd, SOL_SOCKET, SO_BINDTODEVICE, device)
@@ -553,38 +658,35 @@ func PtraceDetach(pid int) (errno int) { return ptrace(PTRACE_DETACH, pid, 0, 0)
// Sendto
// Recvfrom
-// Sendmsg
-// Recvmsg
// Socketpair
// Getsockopt
/*
* Direct access
*/
-//sys Access(path string, mode int) (errno int)
+//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 int) (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 int) (fd int, errno int)
+//sys Creat(path string, mode uint32) (fd int, errno int)
//sys Dup(oldfd int) (fd int, errno int)
//sys Dup2(oldfd int, newfd int) (fd int, errno int)
//sys EpollCreate(size int) (fd int, errno int)
//sys EpollCtl(epfd int, op int, fd int, event *EpollEvent) (errno int)
//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, errno int)
//sys Exit(code int) = SYS_EXIT_GROUP
-//sys Faccessat(dirfd int, path string, mode int, flags int) (errno int)
-//sys Fallocate(fd int, mode int, off int64, len int64) (errno int)
+//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 int) (errno int)
-//sys Fchmodat(dirfd int, path string, mode int, flags 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 Fsync(fd int) (errno int)
-//sys Ftruncate(fd int, length int64) (errno int)
//sys Getdents(fd int, buf []byte) (n int, errno int) = SYS_GETDENTS64
//sys Getpgid(pid int) (pgid int, errno int)
//sys Getpgrp() (pid int)
@@ -593,19 +695,20 @@ func PtraceDetach(pid int) (errno int) { return ptrace(PTRACE_DETACH, pid, 0, 0)
//sys Getrlimit(resource int, rlim *Rlimit) (errno int)
//sys Getrusage(who int, rusage *Rusage) (errno int)
//sys Gettid() (tid int)
-//sys Gettimeofday(tv *Timeval) (errno int)
+//sys InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, errno int)
+//sys InotifyInit() (fd int, errno int)
+//sys InotifyInit1(flags int) (fd int, errno int)
+//sys InotifyRmWatch(fd int, watchdesc uint32) (success int, errno int)
//sys 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 int) (errno int)
-//sys Mkdirat(dirfd int, path string, mode int) (errno int)
-//sys Mknod(path string, mode int, dev int) (errno int)
-//sys Mknodat(dirfd int, path string, mode int, dev int) (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 Nanosleep(time *Timespec, leftover *Timespec) (errno int)
//sys Pause() (errno int)
//sys PivotRoot(newroot string, putold string) (errno int) = SYS_PIVOT_ROOT
-//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 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)
@@ -618,15 +721,12 @@ func PtraceDetach(pid int) (errno int) { return ptrace(PTRACE_DETACH, pid, 0, 0)
//sys Setsid() (pid int, errno int)
//sys Settimeofday(tv *Timeval) (errno int)
//sys Setuid(uid int) (errno int)
-//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, errno int)
//sys Symlink(oldpath string, newpath string) (errno int)
//sys Sync()
//sys Sysinfo(info *Sysinfo_t) (errno int)
//sys Tee(rfd int, wfd int, len int, flags int) (n int64, errno int)
//sys Tgkill(tgid int, tid int, sig int) (errno int)
-//sys Time(t *Time_t) (tt Time_t, errno int)
//sys Times(tms *Tms) (ticks uintptr, errno int)
-//sys Truncate(path string, length int64) (errno int)
//sys Umask(mask int) (oldmask int)
//sys Uname(buf *Utsname) (errno int)
//sys Unlink(path string) (errno int)
@@ -677,9 +777,6 @@ func PtraceDetach(pid int) (errno int) { return ptrace(PTRACE_DETACH, pid, 0, 0)
// Getpmsg
// Getpriority
// Getxattr
-// InotifyAddWatch
-// InotifyInit
-// InotifyRmWatch
// IoCancel
// IoDestroy
// IoGetevents
diff --git a/src/pkg/syscall/syscall_linux_386.go b/src/pkg/syscall/syscall_linux_386.go
index 4a2e92f0a..5bd3406de 100644
--- a/src/pkg/syscall/syscall_linux_386.go
+++ b/src/pkg/syscall/syscall_linux_386.go
@@ -30,6 +30,7 @@ func NsecToTimeval(nsec int64) (tv Timeval) {
//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 Getegid() (egid int) = SYS_GETEGID32
//sys Geteuid() (euid int) = SYS_GETEUID32
//sys Getgid() (gid int) = SYS_GETGID32
@@ -38,6 +39,8 @@ func NsecToTimeval(nsec int64) (tv Timeval) {
//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 Setfsgid(gid int) (errno int) = SYS_SETFSGID32
//sys Setfsuid(uid int) (errno int) = SYS_SETFSUID32
//sys Setgid(gid int) (errno int) = SYS_SETGID32
@@ -45,8 +48,10 @@ func NsecToTimeval(nsec int64) (tv Timeval) {
//sys Setresgid(rgid int, egid int, sgid int) (errno int) = SYS_SETRESGID32
//sys Setresuid(ruid int, euid int, suid int) (errno int) = SYS_SETRESUID32
//sys 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
//sys getgroups(n int, list *_Gid_t) (nn int, errno int) = SYS_GETGROUPS32
//sys 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
@@ -55,6 +60,10 @@ func NsecToTimeval(nsec int64) (tv Timeval) {
// Implemented in assembly to avoid allocation.
func Seek(fd int, offset int64, whence int) (newoffset int64, errno int)
+// Vsyscalls on amd64.
+//sys Gettimeofday(tv *Timeval) (errno int)
+//sys Time(t *Time_t) (tt Time_t, errno int)
+
// On x86 Linux, all the socket calls go through an extra indirection,
// I think because the 5-register system call interface can't handle
// the 6-argument calls like sendto and recvfrom. Instead the
@@ -100,10 +109,8 @@ func getpeername(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int) {
return
}
-func socketpair(domain int, typ int, proto int) (fd [2]int, errno int) {
- var f [2]int
- _, errno = socketcall(_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(&f)), 0, 0)
- fd = f
+func socketpair(domain int, typ int, flags int, fd *[2]int) (errno int) {
+ _, errno = socketcall(_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(flags), uintptr(unsafe.Pointer(fd)), 0, 0)
return
}
@@ -145,6 +152,16 @@ func sendto(s int, p []byte, flags int, to uintptr, addrlen _Socklen) (errno int
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)
+ 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)
+ return
+}
+
func Listen(s int, n int) (errno int) {
_, errno = socketcall(_LISTEN, uintptr(s), uintptr(n), 0, 0, 0, 0)
return
@@ -170,3 +187,15 @@ func Statfs(path string, buf *Statfs_t) (errno int) {
func (r *PtraceRegs) PC() uint64 { return uint64(uint32(r.Eip)) }
func (r *PtraceRegs) SetPC(pc uint64) { r.Eip = int32(pc) }
+
+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_linux_amd64.go b/src/pkg/syscall/syscall_linux_amd64.go
index 8e5471af7..ae108bd18 100644
--- a/src/pkg/syscall/syscall_linux_amd64.go
+++ b/src/pkg/syscall/syscall_linux_amd64.go
@@ -8,6 +8,7 @@ package syscall
//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 Getegid() (egid int)
//sys Geteuid() (euid int)
//sys Getgid() (gid int)
@@ -17,6 +18,8 @@ package syscall
//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 Setfsgid(gid int) (errno int)
@@ -27,9 +30,11 @@ package syscall
//sys Setresuid(ruid int, euid int, suid int) (errno int)
//sys 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)
@@ -37,13 +42,19 @@ package syscall
//sys setgroups(n int, list *_Gid_t) (errno int)
//sys setsockopt(s int, level int, name int, val uintptr, vallen int) (errno int)
//sys socket(domain int, typ int, proto int) (fd int, errno int)
+//sys socketpair(domain int, typ int, proto int, fd *[2]int) (errno int)
//sys getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int)
//sys 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)
func Getpagesize() int { return 4096 }
+func Gettimeofday(tv *Timeval) (errno int)
+func Time(t *Time_t) (tt Time_t, errno int)
+
func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
func NsecToTimespec(nsec int64) (ts Timespec) {
@@ -64,3 +75,15 @@ func NsecToTimeval(nsec int64) (tv Timeval) {
func (r *PtraceRegs) PC() uint64 { return r.Rip }
func (r *PtraceRegs) SetPC(pc uint64) { r.Rip = pc }
+
+func (iov *Iovec) SetLen(length int) {
+ iov.Len = uint64(length)
+}
+
+func (msghdr *Msghdr) SetControllen(length int) {
+ msghdr.Controllen = uint64(length)
+}
+
+func (cmsg *Cmsghdr) SetLen(length int) {
+ cmsg.Len = uint64(length)
+}
diff --git a/src/pkg/syscall/syscall_linux_arm.go b/src/pkg/syscall/syscall_linux_arm.go
index 06052f409..1fc7a7b18 100644
--- a/src/pkg/syscall/syscall_linux_arm.go
+++ b/src/pkg/syscall/syscall_linux_arm.go
@@ -4,14 +4,7 @@
package syscall
-// These seem not to be defined in our gcc's ARM headers
-// and are thus missing from zerrors_linux_arm.go.
-const (
- WSTOPPED = 0x7f
- O_CLOEXEC = 0
- EPOLLRDHUP = EPOLLHUP
- EPOLLONESHOT = 0x40000000
-)
+import "unsafe"
func Getpagesize() int { return 4096 }
@@ -30,6 +23,35 @@ func NsecToTimeval(nsec int64) (tv Timeval) {
return
}
+// Pread and Pwrite are special: they insert padding before the int64.
+// (Ftruncate and truncate are not; go figure.)
+
+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
+}
+
+// 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)
@@ -41,19 +63,22 @@ func NsecToTimeval(nsec int64) (tv Timeval) {
//sys 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 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 Fstatfs(fd int, buf *Statfs_t) (errno int)
+//sys Fstat(fd int, stat *Stat_t) (errno int) = SYS_FSTAT64
+//sys Fstatfs(fd int, buf *Statfs_t) (errno int) = SYS_FSTATFS64
+//sys Ftruncate(fd int, length int64) (errno int) = SYS_FTRUNCATE64
//sys Getegid() (egid int)
//sys Geteuid() (euid int)
//sys Getgid() (gid int)
//sys 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 Seek(fd int, offset int64, whence int) (off int64, errno int) = SYS_LSEEK
+//sys Lstat(path string, stat *Stat_t) (errno int) = SYS_LSTAT64
//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)
@@ -63,10 +88,28 @@ func NsecToTimeval(nsec int64) (tv Timeval) {
//sys Setresuid(ruid int, euid int, suid int) (errno int)
//sys Setreuid(ruid int, euid int) (errno int)
//sys Shutdown(fd int, how int) (errno int)
-//sys Stat(path string, stat *Stat_t) (errno int)
-//sys Statfs(path string, buf *Statfs_t) (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 Truncate(path string, length int64) (errno int) = SYS_TRUNCATE64
+
+// Vsyscalls on amd64.
+//sys Gettimeofday(tv *Timeval) (errno int)
+//sys Time(t *Time_t) (tt Time_t, errno int)
// TODO(kaib): add support for tracing
func (r *PtraceRegs) PC() uint64 { return 0 }
func (r *PtraceRegs) SetPC(pc uint64) {}
+
+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_nacl.go b/src/pkg/syscall/syscall_nacl.go
deleted file mode 100644
index 0b592cc51..000000000
--- a/src/pkg/syscall/syscall_nacl.go
+++ /dev/null
@@ -1,353 +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.
-
-// Native Client system calls.
-
-package syscall
-
-const OS = "nacl"
-
-// Auto-generated
-
-//sys Chmod(path string, mode int) (errno int)
-//sys Clock() (clock int)
-//sys Close(fd int) (errno int)
-//sys Exit(code int)
-//sys Fstat(fd int, stat *Stat_t) (errno int)
-//sys Getdents(fd int, buf []byte) (n int, errno int)
-//sys Getpid() (pid int)
-//sys Gettimeofday(tv *Timeval) (errno int)
-//sys Open(path string, mode int, perm int) (fd int, errno int)
-//sys Read(fd int, p []byte) (n int, errno int)
-//sys read(fd int, buf *byte, nbuf int) (n int, errno int)
-//sys Stat(path string, stat *Stat_t) (errno int)
-//sys Write(fd int, p []byte) (n int, errno int)
-
-//sys MultimediaInit(subsys int) (errno int)
-//sys MultimediaShutdown() (errno int)
-
-//sys CondCreate() (cv int, errno int)
-//sys CondWait(cv int, mutex int) (errno int)
-//sys CondSignal(cv int) (errno int)
-//sys CondBroadcast(cv int) (errno int)
-//sys CondTimedWaitAbs(cv int, mutex int, abstime *Timespec) (errno int)
-//sys MutexCreate() (mutex int, errno int)
-//sys MutexLock(mutex int) (errno int)
-//sys MutexUnlock(mutex int) (errno int)
-//sys MutexTryLock(mutex int) (errno int) = SYS_MUTEX_TRYLOCK
-//sys SemCreate() (sema int, errno int)
-//sys SemWait(sema int) (errno int)
-//sys SemPost(sema int) (errno int)
-//sys VideoInit(dx int, dy int) (errno int)
-//sys VideoUpdate(data *uint32) (errno int)
-//sys VideoPollEvent(ev *byte) (errno int)
-//sys VideoShutdown() (errno int)
-//sys AudioInit(fmt int, nreq int, data *int) (errno int)
-//sys AudioShutdown() (errno int)
-//sys AudioStream(data *uint16, size *uintptr) (errno int)
-
-// Hand-written
-
-func Seek(fd int, offset int64, whence int) (newoffset int64, errno int) {
- // Offset passed to system call is 32 bits. Failure of vision by NaCl.
- if int64(int32(offset)) != offset {
- return 0, ERANGE
- }
- o, _, e := Syscall(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(whence))
- return int64(o), int(e)
-}
-
-// Sleep by waiting on a condition variable that will never be signaled.
-// TODO(rsc): Replace when NaCl adds a proper sleep system call.
-var tcv, tmu int
-
-func init() {
- tmu, _ = MutexCreate()
- tcv, _ = CondCreate()
-}
-
-func Sleep(ns int64) (errno int) {
- ts := NsecToTimespec(ns)
- var tv Timeval
- if errno = Gettimeofday(&tv); errno != 0 {
- return
- }
- ts.Sec += tv.Sec
- ts.Nsec += tv.Usec * 1000
- switch {
- case ts.Nsec >= 1e9:
- ts.Nsec -= 1e9
- ts.Sec++
- case ts.Nsec <= -1e9:
- ts.Nsec += 1e9
- ts.Sec--
- }
- if errno = MutexLock(tmu); errno != 0 {
- return
- }
- errno = CondTimedWaitAbs(tcv, tmu, &ts)
- if e := MutexUnlock(tmu); e != 0 && errno == 0 {
- errno = e
- }
- return
-}
-
-// Implemented in NaCl but not here; maybe later:
-// SYS_IOCTL
-// SYS_IMC_*
-// SYS_MMAP ???
-// SYS_SRPC_*
-// SYS_SYSCONF
-
-// Implemented in NaCl but not here; used by runtime instead:
-// SYS_SYSBRK
-// SYS_MMAP
-// SYS_MUNMAP
-// SYS_THREAD_*
-// SYS_TLS_*
-// SYS_SCHED_YIELD
-
-// #define'd in NaCl but not picked up by mkerrors_nacl.sh.
-
-const EWOULDBLOCK = EAGAIN
-
-// Not implemented in NaCl but needed to compile other packages.
-
-const (
- SIGTRAP = 5
-)
-
-func Pipe(p []int) (errno int) { return ENACL }
-
-func fcntl(fd, cmd, arg int) (val int, errno int) {
- return 0, ENACL
-}
-
-func Pread(fd int, p []byte, offset int64) (n int, errno int) {
- return 0, ENACL
-}
-
-func Pwrite(fd int, p []byte, offset int64) (n int, errno int) {
- return 0, ENACL
-}
-
-func Mkdir(path string, mode int) (errno int) { return ENACL }
-
-func Lstat(path string, stat *Stat_t) (errno int) {
- return Stat(path, stat)
-}
-
-func Chdir(path string) (errno int) { return ENACL }
-
-func Fchdir(fd int) (errno int) { return ENACL }
-
-func Unlink(path string) (errno int) { return ENACL }
-
-func Rmdir(path string) (errno int) { return ENACL }
-
-func Link(oldpath, newpath string) (errno int) {
- return ENACL
-}
-
-func Symlink(path, link string) (errno int) { return ENACL }
-
-func Readlink(path string, buf []byte) (n int, errno int) {
- return 0, ENACL
-}
-
-func Rename(oldpath, newpath string) (errno int) {
- return ENACL
-}
-
-func Fchmod(fd int, mode int) (errno int) { return ENACL }
-
-func Chown(path string, uid int, gid int) (errno int) {
- return ENACL
-}
-
-func Lchown(path string, uid int, gid int) (errno int) {
- return ENACL
-}
-
-func Fchown(fd int, uid int, gid int) (errno int) {
- return ENACL
-}
-
-func Utimes(path string, tv []Timeval) (errno int) {
- return ENACL
-}
-
-func Futimes(fd int, tv []Timeval) (errno int) {
- return ENACL
-}
-
-func Truncate(name string, size int64) (errno int) {
- return ENACL
-}
-
-func Ftruncate(fd int, length int64) (errno int) {
- return ENACL
-}
-
-// NaCL doesn't actually implement Getwd, but it also
-// don't implement Chdir, so the fallback algorithm
-// fails worse than calling Getwd does.
-
-const ImplementsGetwd = true
-
-func Getwd() (wd string, errno int) { return "", ENACL }
-
-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 Getppid() (ppid int) { return -1 }
-
-func Getgroups() (gids []int, errno int) { return nil, ENACL }
-
-type Sockaddr interface {
- sockaddr()
-}
-
-type SockaddrInet4 struct {
- Port int
- Addr [4]byte
-}
-
-func (*SockaddrInet4) sockaddr() {}
-
-type SockaddrInet6 struct {
- Port int
- Addr [16]byte
-}
-
-func (*SockaddrInet6) sockaddr() {}
-
-type SockaddrUnix struct {
- Name string
-}
-
-func (*SockaddrUnix) sockaddr() {}
-
-const (
- AF_INET = 1 + iota
- AF_INET6
- AF_UNIX
- IPPROTO_TCP
- SOCK_DGRAM
- SOCK_STREAM
- SOCK_RAW
- SOL_SOCKET
- SOMAXCONN
- SO_DONTROUTE
- SO_KEEPALIVE
- SO_LINGER
- SO_RCVBUF
- SO_REUSEADDR
- SO_SNDBUF
- TCP_NODELAY
- WNOHANG
- WSTOPPED
- PTRACE_TRACEME
- SO_BROADCAST = 0
- SHUT_RDWR = 0
-)
-
-func Accept(fd int) (nfd int, sa Sockaddr, errno int) {
- return 0, nil, ENACL
-}
-
-func Getsockname(fd int) (sa Sockaddr, errno int) {
- return nil, ENACL
-}
-
-func Getpeername(fd int) (sa Sockaddr, errno int) {
- return nil, ENACL
-}
-
-func Bind(fd int, sa Sockaddr) (errno int) { return ENACL }
-
-func BindToDevice(fd int, device string) (errno int) { return ENACL }
-
-func Connect(fd int, sa Sockaddr) (errno int) { return ENACL }
-
-func Socket(domain, typ, proto int) (fd, errno int) {
- return 0, ENACL
-}
-
-func SetsockoptInt(fd, level, opt int, value int) (errno int) {
- return ENACL
-}
-
-func Shutdown(fd, how int) (errno int) { return ENACL }
-
-func Recvfrom(fd int, p []byte, flags int) (n int, from Sockaddr, errno int) {
- return 0, nil, ENACL
-}
-
-func Sendto(fd int, p []byte, flags int, to Sockaddr) (errno int) {
- return ENACL
-}
-
-func SetsockoptTimeval(fd, level, opt int, tv *Timeval) (errno int) {
- return ENACL
-}
-
-type Linger struct {
- Onoff int32
- Linger int32
-}
-
-func SetsockoptLinger(fd, level, opt int, l *Linger) (errno int) {
- return ENACL
-}
-
-func Listen(s int, n int) (errno int) { return ENACL }
-
-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
-}
-
-func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, errno int) {
- return 0, ENACL
-}
-
-type WaitStatus uint32
-
-func (WaitStatus) Exited() bool { return false }
-
-func (WaitStatus) ExitStatus() int { return -1 }
-
-func (WaitStatus) Signal() int { return -1 }
-
-func (WaitStatus) CoreDump() bool { return false }
-
-func (WaitStatus) Stopped() bool { return false }
-
-func (WaitStatus) Continued() bool { return false }
-
-func (WaitStatus) StopSignal() int { return -1 }
-
-func (WaitStatus) Signaled() bool { return false }
-
-func (WaitStatus) TrapCause() int { return -1 }
diff --git a/src/pkg/syscall/syscall_nacl_386.go b/src/pkg/syscall/syscall_nacl_386.go
deleted file mode 100644
index 86ed66f88..000000000
--- a/src/pkg/syscall/syscall_nacl_386.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 syscall
-
-func Getpagesize() int { return 4096 }
-
-func NsecToTimeval(nsec int64) (tv Timeval) {
- tv.Sec = int32(nsec / 1e9)
- tv.Usec = int32(nsec % 1e9 / 1e3)
- return
-}
-
-func NsecToTimespec(nsec int64) (ts Timespec) {
- ts.Sec = int32(nsec / 1e9)
- ts.Nsec = int32(nsec % 1e9)
- return
-}
diff --git a/src/pkg/syscall/syscall_windows.go b/src/pkg/syscall/syscall_windows.go
index 86badb8e9..33a86ce25 100644
--- a/src/pkg/syscall/syscall_windows.go
+++ b/src/pkg/syscall/syscall_windows.go
@@ -70,16 +70,11 @@ func UTF16ToString(s []uint16) string {
// the UTF-8 string s, with a terminating NUL added.
func StringToUTF16Ptr(s string) *uint16 { return &StringToUTF16(s)[0] }
-func NsecToTimeval(nsec int64) (tv Timeval) {
- tv.Sec = int32(nsec / 1e9)
- tv.Usec = int32(nsec % 1e9 / 1e3)
- return
-}
-
// dll helpers
// implemented in ../pkg/runtime/windows/syscall.cgo
func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2, lasterr uintptr)
+func Syscall12(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 uintptr) (r1, r2, lasterr uintptr)
func loadlibraryex(filename uintptr) (handle uint32)
func getprocaddress(handle uint32, procname uintptr) (proc uintptr)
@@ -108,13 +103,13 @@ func getSysProcAddr(m uint32, pname string) uintptr {
//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 ExitProcess(exitcode uint32)
-//sys CreateFile(name *uint16, access uint32, mode uint32, sa *byte, createmode uint32, attrs uint32, templatefile int32) (handle int32, errno int) [failretval=-1] = CreateFileW
+//sys CreateFile(name *uint16, access uint32, mode uint32, sa *byte, createmode uint32, attrs uint32, templatefile int32) (handle int32, errno int) [failretval==-1] = CreateFileW
//sys ReadFile(handle int32, buf []byte, done *uint32, overlapped *Overlapped) (ok bool, errno int)
//sys WriteFile(handle int32, buf []byte, done *uint32, overlapped *Overlapped) (ok bool, errno int)
-//sys SetFilePointer(handle int32, lowoffset int32, highoffsetptr *int32, whence uint32) (newlowoffset uint32, errno int) [failretval=0xffffffff]
+//sys SetFilePointer(handle int32, lowoffset int32, highoffsetptr *int32, whence uint32) (newlowoffset uint32, errno int) [failretval==0xffffffff]
//sys CloseHandle(handle int32) (ok bool, errno int)
-//sys GetStdHandle(stdhandle int32) (handle int32, errno int) [failretval=-1]
-//sys FindFirstFile(name *uint16, data *Win32finddata) (handle int32, errno int) [failretval=-1] = FindFirstFileW
+//sys GetStdHandle(stdhandle int32) (handle int32, errno int) [failretval==-1]
+//sys FindFirstFile(name *uint16, data *Win32finddata) (handle int32, errno int) [failretval==-1] = FindFirstFileW
//sys FindNextFile(handle int32, data *Win32finddata) (ok bool, errno int) = FindNextFileW
//sys FindClose(handle int32) (ok bool, errno int)
//sys GetFileInformationByHandle(handle int32, data *ByHandleFileInformation) (ok bool, errno int)
@@ -128,28 +123,56 @@ func getSysProcAddr(m uint32, pname string) uintptr {
//sys SetEndOfFile(handle int32) (ok bool, errno int)
//sys GetSystemTimeAsFileTime(time *Filetime)
//sys sleep(msec uint32) = Sleep
-//sys GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, errno int) [failretval=0xffffffff]
+//sys GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, errno int) [failretval==0xffffffff]
//sys CreateIoCompletionPort(filehandle int32, cphandle int32, key uint32, threadcnt uint32) (handle int32, errno int)
//sys GetQueuedCompletionStatus(cphandle int32, qty *uint32, key *uint32, overlapped **Overlapped, timeout uint32) (ok bool, errno int)
+//sys CreateProcess(appName *int16, commandLine *uint16, procSecurity *int16, threadSecurity *int16, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfo, outProcInfo *ProcessInformation) (ok bool, errno int) = CreateProcessW
+//sys GetStartupInfo(startupInfo *StartupInfo) (ok bool, errno int) = GetStartupInfoW
+//sys GetCurrentProcess() (pseudoHandle int32, errno int)
+//sys DuplicateHandle(hSourceProcessHandle int32, hSourceHandle int32, hTargetProcessHandle int32, lpTargetHandle *int32, dwDesiredAccess uint32, bInheritHandle bool, dwOptions uint32) (ok bool, errno int)
+//sys WaitForSingleObject(handle int32, waitMilliseconds uint32) (event uint32, errno int) [failretval==0xffffffff]
//sys GetTempPath(buflen uint32, buf *uint16) (n uint32, errno int) = GetTempPathW
+//sys CreatePipe(readhandle *uint32, writehandle *uint32, lpsa *byte, size uint32) (ok bool, errno int)
+//sys GetFileType(filehandle uint32) (n uint32, errno int)
+//sys CryptAcquireContext(provhandle *uint32, container *uint16, provider *uint16, provtype uint32, flags uint32) (ok bool, errno int) = advapi32.CryptAcquireContextW
+//sys CryptReleaseContext(provhandle uint32, flags uint32) (ok bool, errno int) = advapi32.CryptReleaseContext
+//sys CryptGenRandom(provhandle uint32, buflen uint32, buf *byte) (ok bool, errno int) = advapi32.CryptGenRandom
+//sys OpenProcess(da uint32,b int, pid uint32) (handle uint32, errno int)
+//sys GetExitCodeProcess(h uint32, c *uint32) (ok bool, errno int)
+//sys GetEnvironmentStrings() (envs *uint16, errno int) [failretval==nil] = kernel32.GetEnvironmentStringsW
+//sys FreeEnvironmentStrings(envs *uint16) (ok bool, errno int) = kernel32.FreeEnvironmentStringsW
+//sys GetEnvironmentVariable(name *uint16, buffer *uint16, size uint32) (n uint32, errno int) = kernel32.GetEnvironmentVariableW
+//sys SetEnvironmentVariable(name *uint16, value *uint16) (ok bool, errno int) = kernel32.SetEnvironmentVariableW
+//sys SetFileTime(handle int32, ctime *Filetime, atime *Filetime, wtime *Filetime) (ok bool, errno int)
+//sys GetFileAttributes(name *uint16) (attrs uint32, errno int) [failretval==INVALID_FILE_ATTRIBUTES] = kernel32.GetFileAttributesW
+//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 uint32) (handle uint32, errno int) [failretval!=0]
// syscall interface implementation for other packages
func Errstr(errno int) string {
- if errno == EWINDOWS {
- return "not supported by windows"
+ // 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(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_ARGUMENT_ARRAY, 0, uint32(errno), 0, b, nil)
+ n, err := FormatMessage(flags, 0, uint32(errno), 0, b, nil)
if err != 0 {
return "error " + str(errno) + " (FormatMessage failed with err=" + str(err) + ")"
}
- return string(utf16.Decode(b[0 : n-1]))
+ // 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 Open(path string, mode int, perm int) (fd int, errno int) {
+func Open(path string, mode int, perm uint32) (fd int, errno int) {
if len(path) == 0 {
return -1, ERROR_FILE_NOT_FOUND
}
@@ -165,6 +188,10 @@ func Open(path string, mode int, perm int) (fd int, errno int) {
if mode&O_CREAT != 0 {
access |= GENERIC_WRITE
}
+ if mode&O_APPEND != 0 {
+ access &^= GENERIC_WRITE
+ access |= FILE_APPEND_DATA
+ }
sharemode := uint32(FILE_SHARE_READ | FILE_SHARE_WRITE)
var createmode uint32
switch {
@@ -187,7 +214,7 @@ func Read(fd int, p []byte) (n int, errno int) {
var done uint32
if ok, e := ReadFile(int32(fd), p, &done, nil); !ok {
if e == ERROR_BROKEN_PIPE {
- // BUG(brainman): work around ERROR_BROKEN_PIPE is returned on reading EOF from stdin
+ // NOTE(brainman): work around ERROR_BROKEN_PIPE is returned on reading EOF from stdin
return 0, 0
}
return 0, e
@@ -251,6 +278,11 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, errno int) {
}
hi := int32(offset >> 32)
lo := int32(offset)
+ // use GetFileType to check pipe, pipe can't do seek
+ ft, _ := GetFileType(uint32(fd))
+ if ft == FILE_TYPE_PIPE {
+ return 0, EPIPE
+ }
rlo, e := SetFilePointer(int32(fd), lo, &hi, w)
if e != 0 {
return 0, e
@@ -277,6 +309,24 @@ func getStdHandle(h int32) (fd int) {
}
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
@@ -309,7 +359,7 @@ func Chdir(path string) (errno int) {
return 0
}
-func Mkdir(path string, mode int) (errno int) {
+func Mkdir(path string, mode uint32) (errno int) {
if ok, e := CreateDirectory(&StringToUTF16(path)[0], nil); !ok {
return e
}
@@ -366,10 +416,7 @@ func Ftruncate(fd int, length int64) (errno int) {
func Gettimeofday(tv *Timeval) (errno int) {
var ft Filetime
GetSystemTimeAsFileTime(&ft)
- ms := ft.Microseconds()
- // split into sec / usec
- tv.Sec = int32(ms / 1e6)
- tv.Usec = int32(ms) - tv.Sec
+ *tv = NsecToTimeval(ft.Nanoseconds())
return 0
}
@@ -378,27 +425,66 @@ func Sleep(nsec int64) (errno int) {
return 0
}
-// TODO(brainman): implement Utimes, or rewrite os.file.Chtimes() instead
+func Pipe(p []int) (errno int) {
+ if len(p) != 2 {
+ return EINVAL
+ }
+ var r, w uint32
+ if ok, errno := CreatePipe(&r, &w, nil, 0); !ok {
+ return errno
+ }
+ p[0] = int(r)
+ p[1] = int(w)
+ return 0
+}
+
func Utimes(path string, tv []Timeval) (errno int) {
- return EWINDOWS
+ 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 {
+ return e
+ }
+ defer Close(int(h))
+ a := NsecToFiletime(tv[0].Nanoseconds())
+ w := NsecToFiletime(tv[1].Nanoseconds())
+ if ok, e := SetFileTime(h, nil, &a, &w); !ok {
+ return e
+ }
+ return 0
}
// net api calls
//sys WSAStartup(verreq uint32, data *WSAData) (sockerrno int) = wsock32.WSAStartup
-//sys WSACleanup() (errno int) [failretval=-1] = wsock32.WSACleanup
-//sys socket(af int32, typ int32, protocol int32) (handle int32, errno int) [failretval=-1] = wsock32.socket
-//sys setsockopt(s int32, level int32, optname int32, optval *byte, optlen int32) (errno int) [failretval=-1] = wsock32.setsockopt
-//sys bind(s int32, name uintptr, namelen int32) (errno int) [failretval=-1] = wsock32.bind
-//sys connect(s int32, name uintptr, namelen int32) (errno int) [failretval=-1] = wsock32.connect
-//sys getsockname(s int32, rsa *RawSockaddrAny, addrlen *int32) (errno int) [failretval=-1] = wsock32.getsockname
-//sys getpeername(s int32, rsa *RawSockaddrAny, addrlen *int32) (errno int) [failretval=-1] = wsock32.getpeername
-//sys listen(s int32, backlog int32) (errno int) [failretval=-1] = wsock32.listen
-//sys shutdown(s int32, how int32) (errno int) [failretval=-1] = wsock32.shutdown
+//sys WSACleanup() (errno int) [failretval==-1] = wsock32.WSACleanup
+//sys socket(af int32, typ int32, protocol int32) (handle int32, errno int) [failretval==-1] = wsock32.socket
+//sys setsockopt(s int32, level int32, optname int32, optval *byte, optlen int32) (errno int) [failretval==-1] = wsock32.setsockopt
+//sys bind(s int32, name uintptr, namelen int32) (errno int) [failretval==-1] = wsock32.bind
+//sys connect(s int32, name uintptr, namelen int32) (errno int) [failretval==-1] = wsock32.connect
+//sys getsockname(s int32, rsa *RawSockaddrAny, addrlen *int32) (errno int) [failretval==-1] = wsock32.getsockname
+//sys getpeername(s int32, rsa *RawSockaddrAny, addrlen *int32) (errno int) [failretval==-1] = wsock32.getpeername
+//sys listen(s int32, backlog int32) (errno int) [failretval==-1] = wsock32.listen
+//sys shutdown(s int32, how int32) (errno int) [failretval==-1] = wsock32.shutdown
+//sys Closesocket(s int32) (errno int) [failretval==-1] = wsock32.closesocket
//sys AcceptEx(ls uint32, as uint32, buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, recvd *uint32, overlapped *Overlapped) (ok bool, 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 uint32, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, overlapped *Overlapped, croutine *byte) (errno int) [failretval=-1] = ws2_32.WSARecv
-//sys WSASend(s uint32, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, overlapped *Overlapped, croutine *byte) (errno int) [failretval=-1] = ws2_32.WSASend
+//sys WSARecv(s uint32, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, overlapped *Overlapped, croutine *byte) (errno int) [failretval==-1] = ws2_32.WSARecv
+//sys WSASend(s uint32, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, overlapped *Overlapped, croutine *byte) (errno int) [failretval==-1] = ws2_32.WSASend
+//sys WSARecvFrom(s uint32, 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 uint32, 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 Ntohs(netshort uint16) (u uint16) = ws2_32.ntohs
+//sys DnsQuery(name string, qtype uint16, options uint32, extra *byte, qrs **DNSRecord, pr *byte) (status uint32) = dnsapi.DnsQuery_W
+//sys DnsRecordListFree(rl *DNSRecord, freetype uint32) = dnsapi.DnsRecordListFree
+
+// For testing: clients can set this flag to force
+// creation of IPv6 sockets to return EAFNOSUPPORT.
+var SocketDisableIPv6 bool
type RawSockaddrInet4 struct {
Family uint16
@@ -482,6 +568,9 @@ func (rsa *RawSockaddrAny) Sockaddr() (Sockaddr, int) {
}
func Socket(domain, typ, proto int) (fd, errno int) {
+ if domain == AF_INET6 && SocketDisableIPv6 {
+ return -1, EAFNOSUPPORT
+ }
h, e := socket(int32(domain), int32(typ), int32(proto))
return int(h), int(e)
}
@@ -553,6 +642,15 @@ func GetAcceptIOCPSockaddrs(attrs *byte) (lsa, rsa Sockaddr) {
return
}
+func WSASendto(s uint32, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, to Sockaddr, overlapped *Overlapped, croutine *byte) (errno int) {
+ rsa, l, err := to.sockaddr()
+ if err != 0 {
+ return err
+ }
+ errno = WSASendTo(s, bufs, bufcnt, sent, flags, (*RawSockaddrAny)(unsafe.Pointer(rsa)), l, overlapped, croutine)
+ return
+}
+
// TODO(brainman): fix all needed for net
func Accept(fd int) (nfd int, sa Sockaddr, errno int) { return 0, nil, EWINDOWS }
@@ -581,12 +679,15 @@ func Fchdir(fd int) (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 Chmod(path string, mode int) (errno int) { return EWINDOWS }
-func Fchmod(fd int, mode int) (errno int) { return EWINDOWS }
+func Chmod(path string, mode uint32) (errno int) { return EWINDOWS }
+func Fchmod(fd int, 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 int, uid int, gid int) (errno int) { return EWINDOWS }
+// TODO(brainman): use FlushFileBuffers Windows api to implement Fsync.
+func Fsync(fd int) (errno int) { return EWINDOWS }
+
func Getuid() (uid int) { return -1 }
func Geteuid() (euid int) { return -1 }
func Getgid() (gid int) { return -1 }
@@ -595,8 +696,6 @@ func Getgroups() (gids []int, errno int) { return nil, EWINDOWS }
// TODO(brainman): fix all this meaningless code, it is here to compile exec.go
-func Pipe(p []int) (errno int) { return EWINDOWS }
-
func read(fd int, buf *byte, nbuf int) (n int, errno int) {
return 0, EWINDOWS
}
@@ -634,15 +733,36 @@ type Rusage struct {
Nivcsw int32
}
+type WaitStatus struct {
+ Status uint32
+ ExitCode uint32
+}
+
func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, errno int) {
- return 0, EWINDOWS
+ const da = STANDARD_RIGHTS_READ | PROCESS_QUERY_INFORMATION | SYNCHRONIZE
+ handle, errno := OpenProcess(da, 0, uint32(pid))
+ if errno != 0 {
+ return 0, errno
+ }
+ defer CloseHandle(int32(handle))
+ e, errno := WaitForSingleObject(int32(handle), INFINITE)
+ var c uint32
+ if ok, errno := GetExitCodeProcess(handle, &c); !ok {
+ return 0, errno
+ }
+ *wstatus = WaitStatus{e, c}
+ return pid, 0
}
-type WaitStatus uint32
-func (WaitStatus) Exited() bool { return false }
+func (w WaitStatus) Exited() bool { return w.Status == WAIT_OBJECT_0 }
-func (WaitStatus) ExitStatus() int { return -1 }
+func (w WaitStatus) ExitStatus() int {
+ if w.Status == WAIT_OBJECT_0 {
+ return int(w.ExitCode)
+ }
+ return -1
+}
func (WaitStatus) Signal() int { return -1 }
@@ -654,6 +774,6 @@ func (WaitStatus) Continued() bool { return false }
func (WaitStatus) StopSignal() int { return -1 }
-func (WaitStatus) Signaled() bool { return false }
+func (w WaitStatus) Signaled() bool { return w.Status == WAIT_OBJECT_0 }
func (WaitStatus) TrapCause() int { return -1 }
diff --git a/src/pkg/syscall/types_linux.c b/src/pkg/syscall/types_linux.c
index 284e8bf1d..4752e3122 100644
--- a/src/pkg/syscall/types_linux.c
+++ b/src/pkg/syscall/types_linux.c
@@ -13,12 +13,13 @@ Input to godefs. See also mkerrors.sh and mkall.sh
#include <dirent.h>
#include <fcntl.h>
-#include <linux/user.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>
@@ -34,6 +35,7 @@ Input to godefs. See also mkerrors.sh and mkall.sh
#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 <time.h>
@@ -90,6 +92,7 @@ union sockaddr_all {
struct sockaddr_in s2; // these pad it out
struct sockaddr_in6 s3;
struct sockaddr_un s4;
+ struct sockaddr_ll s5;
};
struct sockaddr_any {
@@ -100,6 +103,7 @@ struct sockaddr_any {
typedef struct sockaddr_in $RawSockaddrInet4;
typedef struct sockaddr_in6 $RawSockaddrInet6;
typedef struct sockaddr_un $RawSockaddrUnix;
+typedef struct sockaddr_ll $RawSockaddrLinklayer;
typedef struct sockaddr $RawSockaddr;
typedef struct sockaddr_any $RawSockaddrAny;
typedef socklen_t $_Socklen;
@@ -107,15 +111,26 @@ typedef struct linger $Linger;
typedef struct iovec $Iovec;
typedef struct msghdr $Msghdr;
typedef struct cmsghdr $Cmsghdr;
+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),
$SizeofLinger = sizeof(struct linger),
$SizeofMsghdr = sizeof(struct msghdr),
$SizeofCmsghdr = sizeof(struct cmsghdr),
+ $SizeofUcred = sizeof(struct ucred),
+};
+
+
+// Inotify
+typedef struct inotify_event $InotifyEvent;
+
+enum {
+ $SizeofInotifyEvent = sizeof(struct inotify_event)
};
diff --git a/src/pkg/syscall/types_nacl.c b/src/pkg/syscall/types_nacl.c
deleted file mode 100644
index b99d203b2..000000000
--- a/src/pkg/syscall/types_nacl.c
+++ /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.
-
-/*
-Input to godefs. See also mkerrors.sh and mkall.sh
- */
-
-#define _LARGEFILE_SOURCE
-#define _LARGEFILE64_SOURCE
-#define _FILE_OFFSET_BITS 64
-#define _GNU_SOURCE
-
-#define __native_client__ 1
-
-#define suseconds_t nacl_suseconds_t_1
-#include <sys/types.h>
-#undef suseconds_t
-
-#include <sys/dirent.h>
-#include <sys/mman.h>
-#include <sys/fcntl.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/unistd.h>
-#include <sys/mman.h>
-
-// Machine characteristics; for internal use.
-
-enum
-{
- $sizeofPtr = sizeof(void*),
- $sizeofShort = sizeof(short),
- $sizeofInt = sizeof(int),
- $sizeofLong = sizeof(long),
- $sizeofLongLong = sizeof(long long),
-};
-
-// Mmap constants
-enum {
- $PROT_READ = PROT_READ,
- $PROT_WRITE = PROT_WRITE,
- $MAP_SHARED = MAP_SHARED,
-};
-
-// Unimplemented system calls
-enum {
- $SYS_FORK = 0,
- $SYS_PTRACE = 0,
- $SYS_CHDIR = 0,
- $SYS_DUP2 = 0,
- $SYS_FCNTL = 0,
- $SYS_EXECVE = 0,
-};
-
-// Basic types
-
-typedef short $_C_short;
-typedef int $_C_int;
-typedef long $_C_long;
-typedef long long $_C_long_long;
-typedef off_t $_C_off_t;
-
-// Time
-
-typedef struct timespec $Timespec;
-typedef struct timeval $Timeval;
-typedef time_t $Time_t;
-
-// Processes
-
-//typedef struct rusage $Rusage;
-//typedef struct rlimit $Rlimit;
-
-typedef gid_t $_Gid_t;
-
-// Files
-
-enum
-{
- $O_RDONLY = O_RDONLY,
- $O_WRONLY = O_WRONLY,
- $O_RDWR = O_RDWR,
- $O_APPEND = O_APPEND,
- $O_ASYNC = O_ASYNC,
- $O_CREAT = O_CREAT,
- $O_NOCTTY = 0, // not supported
- $O_NONBLOCK = O_NONBLOCK,
- $O_SYNC = O_SYNC,
- $O_TRUNC = O_TRUNC,
- $O_EXCL = O_EXCL,
- $O_CLOEXEC = 0, // not supported
-
- $F_GETFD = F_GETFD,
- $F_SETFD = F_SETFD,
-
- $F_GETFL = F_GETFL,
- $F_SETFL = F_SETFL,
-
- $FD_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 dirent $Dirent;
diff --git a/src/pkg/syscall/zerrors_darwin_386.go b/src/pkg/syscall/zerrors_darwin_386.go
index f82cc4034..16a24924d 100644
--- a/src/pkg/syscall/zerrors_darwin_386.go
+++ b/src/pkg/syscall/zerrors_darwin_386.go
@@ -1,7 +1,7 @@
-// mkerrors.sh
+// mkerrors.sh -f -m32
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
-// godefs -gsyscall _const.c
+// godefs -c gcc -f -m32 -gsyscall -f -m32 _const.c
// MACHINE GENERATED - DO NOT EDIT.
@@ -576,7 +576,7 @@ const (
WEXITED = 0x4
WNOHANG = 0x1
WNOWAIT = 0x20
- WORDSIZE = 0x40
+ WORDSIZE = 0x20
WSTOPPED = 0x7f
WUNTRACED = 0x2
)
@@ -586,107 +586,107 @@ const (
// 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",
- 13: "permission denied",
- 48: "address already in use",
- 49: "can't assign requested address",
- 47: "address family not supported by protocol family",
- 35: "resource temporarily unavailable",
- 37: "operation already in progress",
- 80: "authentication error",
- 86: "bad CPU type in executable",
- 85: "bad executable (or shared library)",
+ 8: "exec format error",
9: "bad file descriptor",
- 88: "malformed Mach-o file",
- 94: "bad message",
- 72: "RPC struct is bad",
- 16: "resource busy",
- 89: "operation canceled",
10: "no child processes",
- 53: "software caused connection abort",
- 61: "connection refused",
- 54: "connection reset by peer",
11: "resource deadlock avoided",
- 39: "destination address required",
- 83: "device error",
- 33: "numerical argument out of domain",
- 69: "disc quota exceeded",
- 17: "file exists",
+ 12: "cannot allocate memory",
+ 13: "permission denied",
14: "bad address",
- 27: "file too large",
- 79: "inappropriate file type or format",
- 64: "host is down",
- 65: "no route to host",
- 90: "identifier removed",
- 92: "illegal byte sequence",
- 36: "operation now in progress",
- 4: "interrupted system call",
- 22: "invalid argument",
- 5: "input/output error",
- 56: "socket is already connected",
+ 15: "block device required",
+ 16: "resource busy",
+ 17: "file exists",
+ 18: "cross-device link",
+ 19: "operation not supported by device",
+ 20: "not a directory",
21: "is a directory",
- 103: "policy not found",
- 62: "too many levels of symbolic links",
+ 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",
- 95: "EMULTIHOP (Reserved)",
- 63: "file name too long",
- 81: "need authenticator",
+ 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",
- 52: "network dropped connection on reset",
51: "network is unreachable",
- 23: "too many open files in system",
- 93: "attribute not found",
+ 52: "network dropped connection on reset",
+ 53: "software caused connection abort",
+ 54: "connection reset by peer",
55: "no buffer space available",
- 96: "no message available on STREAM",
- 19: "operation not supported by device",
- 2: "no such file or directory",
- 8: "exec format error",
- 77: "no locks available",
- 97: "ENOLINK (Reserved)",
- 12: "cannot allocate memory",
- 91: "no message of desired type",
- 42: "protocol not available",
- 28: "no space left on device",
- 98: "no STREAM resources",
- 99: "not a STREAM",
- 78: "function not implemented",
- 15: "block device required",
+ 56: "socket is already connected",
57: "socket is not connected",
- 20: "not a directory",
+ 58: "can't send after socket shutdown",
+ 59: "too many references: can't splice",
+ 60: "operation 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",
- 38: "socket operation on non-socket",
- 45: "operation not supported",
- 25: "inappropriate ioctl for device",
- 6: "device not configured",
- 102: "operation not supported on socket",
- 84: "value too large to be stored in data type",
- 1: "operation not permitted",
- 46: "protocol family not supported",
- 32: "broken pipe",
67: "too many processes",
- 76: "bad procedure for program",
- 75: "program version wrong",
- 74: "RPC prog. not avail",
- 100: "protocol error",
- 43: "protocol not supported",
- 41: "protocol wrong type for socket",
- 82: "device power is off",
- 34: "result too large",
+ 68: "too many users",
+ 69: "disc quota exceeded",
+ 70: "stale NFS file handle",
71: "too many levels of remote in path",
- 30: "read-only file system",
+ 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: "device power is off",
+ 83: "device error",
+ 84: "value too large to be stored in data type",
+ 85: "bad executable (or shared library)",
+ 86: "bad CPU type in executable",
87: "shared library version mismatch",
- 58: "can't send after socket shutdown",
- 44: "socket type not supported",
- 29: "illegal seek",
- 3: "no such process",
- 70: "stale NFS file handle",
+ 88: "malformed Mach-o file",
+ 89: "operation canceled",
+ 90: "identifier removed",
+ 91: "no message of desired type",
+ 92: "illegal byte sequence",
+ 93: "attribute not found",
+ 94: "bad message",
+ 95: "EMULTIHOP (Reserved)",
+ 96: "no message available on STREAM",
+ 97: "ENOLINK (Reserved)",
+ 98: "no STREAM resources",
+ 99: "not a STREAM",
+ 100: "protocol error",
101: "STREAM ioctl timeout",
- 60: "operation timed out",
- 59: "too many references: can't splice",
- 26: "text file busy",
- 68: "too many users",
- 18: "cross-device link",
+ 102: "operation not supported on socket",
+ 103: "policy not found",
}
diff --git a/src/pkg/syscall/zerrors_darwin_amd64.go b/src/pkg/syscall/zerrors_darwin_amd64.go
index f82cc4034..869c002d7 100644
--- a/src/pkg/syscall/zerrors_darwin_amd64.go
+++ b/src/pkg/syscall/zerrors_darwin_amd64.go
@@ -1,7 +1,7 @@
// mkerrors.sh
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
-// godefs -gsyscall _const.c
+// godefs -c gcc -gsyscall _const.c
// MACHINE GENERATED - DO NOT EDIT.
@@ -586,107 +586,107 @@ const (
// 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",
- 13: "permission denied",
- 48: "address already in use",
- 49: "can't assign requested address",
- 47: "address family not supported by protocol family",
- 35: "resource temporarily unavailable",
- 37: "operation already in progress",
- 80: "authentication error",
- 86: "bad CPU type in executable",
- 85: "bad executable (or shared library)",
+ 8: "exec format error",
9: "bad file descriptor",
- 88: "malformed Mach-o file",
- 94: "bad message",
- 72: "RPC struct is bad",
- 16: "resource busy",
- 89: "operation canceled",
10: "no child processes",
- 53: "software caused connection abort",
- 61: "connection refused",
- 54: "connection reset by peer",
11: "resource deadlock avoided",
- 39: "destination address required",
- 83: "device error",
- 33: "numerical argument out of domain",
- 69: "disc quota exceeded",
- 17: "file exists",
+ 12: "cannot allocate memory",
+ 13: "permission denied",
14: "bad address",
- 27: "file too large",
- 79: "inappropriate file type or format",
- 64: "host is down",
- 65: "no route to host",
- 90: "identifier removed",
- 92: "illegal byte sequence",
- 36: "operation now in progress",
- 4: "interrupted system call",
- 22: "invalid argument",
- 5: "input/output error",
- 56: "socket is already connected",
+ 15: "block device required",
+ 16: "resource busy",
+ 17: "file exists",
+ 18: "cross-device link",
+ 19: "operation not supported by device",
+ 20: "not a directory",
21: "is a directory",
- 103: "policy not found",
- 62: "too many levels of symbolic links",
+ 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",
- 95: "EMULTIHOP (Reserved)",
- 63: "file name too long",
- 81: "need authenticator",
+ 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",
- 52: "network dropped connection on reset",
51: "network is unreachable",
- 23: "too many open files in system",
- 93: "attribute not found",
+ 52: "network dropped connection on reset",
+ 53: "software caused connection abort",
+ 54: "connection reset by peer",
55: "no buffer space available",
- 96: "no message available on STREAM",
- 19: "operation not supported by device",
- 2: "no such file or directory",
- 8: "exec format error",
- 77: "no locks available",
- 97: "ENOLINK (Reserved)",
- 12: "cannot allocate memory",
- 91: "no message of desired type",
- 42: "protocol not available",
- 28: "no space left on device",
- 98: "no STREAM resources",
- 99: "not a STREAM",
- 78: "function not implemented",
- 15: "block device required",
+ 56: "socket is already connected",
57: "socket is not connected",
- 20: "not a directory",
+ 58: "can't send after socket shutdown",
+ 59: "too many references: can't splice",
+ 60: "operation 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",
- 38: "socket operation on non-socket",
- 45: "operation not supported",
- 25: "inappropriate ioctl for device",
- 6: "device not configured",
- 102: "operation not supported on socket",
- 84: "value too large to be stored in data type",
- 1: "operation not permitted",
- 46: "protocol family not supported",
- 32: "broken pipe",
67: "too many processes",
- 76: "bad procedure for program",
- 75: "program version wrong",
- 74: "RPC prog. not avail",
- 100: "protocol error",
- 43: "protocol not supported",
- 41: "protocol wrong type for socket",
- 82: "device power is off",
- 34: "result too large",
+ 68: "too many users",
+ 69: "disc quota exceeded",
+ 70: "stale NFS file handle",
71: "too many levels of remote in path",
- 30: "read-only file system",
+ 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: "device power is off",
+ 83: "device error",
+ 84: "value too large to be stored in data type",
+ 85: "bad executable (or shared library)",
+ 86: "bad CPU type in executable",
87: "shared library version mismatch",
- 58: "can't send after socket shutdown",
- 44: "socket type not supported",
- 29: "illegal seek",
- 3: "no such process",
- 70: "stale NFS file handle",
+ 88: "malformed Mach-o file",
+ 89: "operation canceled",
+ 90: "identifier removed",
+ 91: "no message of desired type",
+ 92: "illegal byte sequence",
+ 93: "attribute not found",
+ 94: "bad message",
+ 95: "EMULTIHOP (Reserved)",
+ 96: "no message available on STREAM",
+ 97: "ENOLINK (Reserved)",
+ 98: "no STREAM resources",
+ 99: "not a STREAM",
+ 100: "protocol error",
101: "STREAM ioctl timeout",
- 60: "operation timed out",
- 59: "too many references: can't splice",
- 26: "text file busy",
- 68: "too many users",
- 18: "cross-device link",
+ 102: "operation not supported on socket",
+ 103: "policy not found",
}
diff --git a/src/pkg/syscall/zerrors_freebsd_386.go b/src/pkg/syscall/zerrors_freebsd_386.go
index a519f3479..830fe7471 100644
--- a/src/pkg/syscall/zerrors_freebsd_386.go
+++ b/src/pkg/syscall/zerrors_freebsd_386.go
@@ -1,7 +1,7 @@
-// mkerrors.sh
+// mkerrors.sh -f -m32
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
-// godefs -gsyscall _const.c
+// godefs -c gcc -f -m32 -gsyscall -f -m32 _const.c
// MACHINE GENERATED - DO NOT EDIT.
@@ -9,526 +9,585 @@ package syscall
// Constants
const (
- AF_APPLETALK = 0x10
- AF_ARP = 0x23
- AF_ATM = 0x1e
- AF_BLUETOOTH = 0x24
- 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_HYLINK = 0xf
- AF_IEEE80211 = 0x25
- AF_IMPLINK = 0x3
- AF_INET = 0x2
- AF_INET6 = 0x1c
- AF_IPX = 0x17
- AF_ISDN = 0x1a
- AF_ISO = 0x7
- AF_LAT = 0xe
- AF_LINK = 0x12
- AF_LOCAL = 0x1
- AF_MAX = 0x26
- AF_NATM = 0x1d
- AF_NETBIOS = 0x6
- AF_NETGRAPH = 0x20
- AF_OSI = 0x7
- AF_PUP = 0x4
- AF_ROUTE = 0x11
- AF_SCLUSTER = 0x22
- AF_SIP = 0x18
- AF_SLOW = 0x21
- AF_SNA = 0xb
- AF_UNIX = 0x1
- AF_UNSPEC = 0
- AF_VENDOR00 = 0x27
- AF_VENDOR01 = 0x29
- AF_VENDOR02 = 0x2b
- AF_VENDOR03 = 0x2d
- AF_VENDOR04 = 0x2f
- AF_VENDOR05 = 0x31
- AF_VENDOR06 = 0x33
- AF_VENDOR07 = 0x35
- AF_VENDOR08 = 0x37
- AF_VENDOR09 = 0x39
- AF_VENDOR10 = 0x3b
- AF_VENDOR11 = 0x3d
- AF_VENDOR12 = 0x3f
- AF_VENDOR13 = 0x41
- AF_VENDOR14 = 0x43
- AF_VENDOR15 = 0x45
- AF_VENDOR16 = 0x47
- AF_VENDOR17 = 0x49
- AF_VENDOR18 = 0x4b
- AF_VENDOR19 = 0x4d
- AF_VENDOR20 = 0x4f
- AF_VENDOR21 = 0x51
- AF_VENDOR22 = 0x53
- AF_VENDOR23 = 0x55
- AF_VENDOR24 = 0x57
- AF_VENDOR25 = 0x59
- AF_VENDOR26 = 0x5b
- AF_VENDOR27 = 0x5d
- AF_VENDOR28 = 0x5f
- AF_VENDOR29 = 0x61
- AF_VENDOR30 = 0x63
- AF_VENDOR31 = 0x65
- AF_VENDOR32 = 0x67
- AF_VENDOR33 = 0x69
- AF_VENDOR34 = 0x6b
- AF_VENDOR35 = 0x6d
- AF_VENDOR36 = 0x6f
- AF_VENDOR37 = 0x71
- AF_VENDOR38 = 0x73
- AF_VENDOR39 = 0x75
- AF_VENDOR40 = 0x77
- AF_VENDOR41 = 0x79
- AF_VENDOR42 = 0x7b
- AF_VENDOR43 = 0x7d
- AF_VENDOR44 = 0x7f
- AF_VENDOR45 = 0x81
- AF_VENDOR46 = 0x83
- AF_VENDOR47 = 0x85
- 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
- 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 = 0x5c
- 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
- 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
- EVFILT_NETDEV = -0x8
- EVFILT_PROC = -0x5
- EVFILT_READ = -0x1
- EVFILT_SIGNAL = -0x6
- EVFILT_SYSCOUNT = 0xa
- 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
- EWOULDBLOCK = 0x23
- EXDEV = 0x12
- FD_CLOEXEC = 0x1
- FD_SETSIZE = 0x400
- F_CANCEL = 0x5
- F_DUP2FD = 0xa
- F_DUPFD = 0
- F_GETFD = 0x1
- F_GETFL = 0x3
- F_GETLK = 0xb
- F_GETOWN = 0x5
- F_OGETLK = 0x7
- F_OSETLK = 0x8
- F_OSETLKW = 0x9
- F_RDLCK = 0x1
- F_SETFD = 0x2
- F_SETFL = 0x4
- F_SETLK = 0xc
- F_SETLKW = 0xd
- F_SETLK_REMOTE = 0xe
- F_SETOWN = 0x6
- F_UNLCK = 0x2
- F_UNLCKSYS = 0x4
- F_WRLCK = 0x3
- 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_CARP = 0x70
- IPPROTO_CFTP = 0x3e
- IPPROTO_CHAOS = 0x10
- IPPROTO_CMTP = 0x26
- IPPROTO_CPHB = 0x49
- IPPROTO_CPNX = 0x48
- IPPROTO_DDP = 0x25
- IPPROTO_DGP = 0x56
- IPPROTO_DIVERT = 0x102
- 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_MOBILE = 0x37
- IPPROTO_MTP = 0x5c
- IPPROTO_MUX = 0x12
- IPPROTO_ND = 0x4d
- IPPROTO_NHRP = 0x36
- IPPROTO_NONE = 0x3b
- IPPROTO_NSP = 0x1f
- IPPROTO_NVPII = 0xb
- IPPROTO_OLD_DIVERT = 0xfe
- IPPROTO_OSPFIGP = 0x59
- IPPROTO_PFSYNC = 0xf0
- 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_SKIP = 0x39
- IPPROTO_SPACER = 0x7fff
- IPPROTO_SRPC = 0x5a
- IPPROTO_ST = 0x7
- IPPROTO_SVMTP = 0x52
- IPPROTO_SWIPE = 0x35
- IPPROTO_TCF = 0x57
- IPPROTO_TCP = 0x6
- IPPROTO_TLSP = 0x38
- 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
- IP_ADD_MEMBERSHIP = 0xc
- IP_ADD_SOURCE_MEMBERSHIP = 0x46
- IP_BINDANY = 0x18
- IP_BLOCK_SOURCE = 0x48
- IP_DEFAULT_MULTICAST_LOOP = 0x1
- IP_DEFAULT_MULTICAST_TTL = 0x1
- IP_DONTFRAG = 0x43
- 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 = 0x32
- IP_FW_DEL = 0x33
- IP_FW_FLUSH = 0x34
- IP_FW_GET = 0x36
- IP_FW_NAT_CFG = 0x38
- IP_FW_NAT_DEL = 0x39
- IP_FW_NAT_GET_CONFIG = 0x3a
- IP_FW_NAT_GET_LOG = 0x3b
- IP_FW_RESETLOG = 0x37
- IP_FW_TABLE_ADD = 0x28
- IP_FW_TABLE_DEL = 0x29
- IP_FW_TABLE_FLUSH = 0x2a
- IP_FW_TABLE_GETSIZE = 0x2b
- IP_FW_TABLE_LIST = 0x2c
- IP_FW_ZERO = 0x35
- IP_HDRINCL = 0x2
- IP_IPSEC_POLICY = 0x15
- IP_MAX_GROUP_SRC_FILTER = 0x200
- IP_MAX_MEMBERSHIPS = 0xfff
- IP_MAX_SOCK_MUTE_FILTER = 0x80
- IP_MAX_SOCK_SRC_FILTER = 0x80
- IP_MAX_SOURCE_FILTER = 0x400
- IP_MINTTL = 0x42
- IP_MIN_MEMBERSHIPS = 0x1f
- IP_MSFILTER = 0x4a
- IP_MULTICAST_IF = 0x9
- IP_MULTICAST_LOOP = 0xb
- IP_MULTICAST_TTL = 0xa
- IP_MULTICAST_VIF = 0xe
- IP_ONESBCAST = 0x17
- 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 = 0x41
- IP_RETOPTS = 0x8
- IP_RSVP_OFF = 0x10
- IP_RSVP_ON = 0xf
- IP_RSVP_VIF_OFF = 0x12
- IP_RSVP_VIF_ON = 0x11
- IP_SENDSRCADDR = 0x7
- IP_TOS = 0x3
- IP_TTL = 0x4
- IP_UNBLOCK_SOURCE = 0x49
- O_ACCMODE = 0x3
- O_APPEND = 0x8
- O_ASYNC = 0x40
- O_CREAT = 0x200
- O_DIRECT = 0x10000
- O_DIRECTORY = 0x20000
- O_EXCL = 0x800
- O_EXEC = 0x40000
- O_EXLOCK = 0x20
- O_FSYNC = 0x80
- O_NDELAY = 0x4
- O_NOCTTY = 0x8000
- O_NOFOLLOW = 0x100
- O_NONBLOCK = 0x4
- O_RDONLY = 0
- O_RDWR = 0x2
- O_SHLOCK = 0x10
- O_SYNC = 0x80
- O_TRUNC = 0x400
- O_TTY_INIT = 0x80000
- O_WRONLY = 0x1
- 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
- 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
- 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_ACCEPTFILTER = 0x1000
- SO_BINTIME = 0x2000
- SO_BROADCAST = 0x20
- SO_DEBUG = 0x1
- SO_DONTROUTE = 0x10
- SO_ERROR = 0x1007
- SO_KEEPALIVE = 0x8
- SO_LABEL = 0x1009
- SO_LINGER = 0x80
- SO_LISTENINCQLEN = 0x1013
- SO_LISTENQLEN = 0x1012
- SO_LISTENQLIMIT = 0x1011
- SO_NOSIGPIPE = 0x800
- SO_NO_DDP = 0x8000
- SO_NO_OFFLOAD = 0x4000
- SO_OOBINLINE = 0x100
- SO_PEERLABEL = 0x1010
- SO_RCVBUF = 0x1002
- SO_RCVLOWAT = 0x1004
- SO_RCVTIMEO = 0x1006
- SO_REUSEADDR = 0x4
- SO_REUSEPORT = 0x200
- SO_SETFIB = 0x1014
- SO_SNDBUF = 0x1001
- SO_SNDLOWAT = 0x1003
- SO_SNDTIMEO = 0x1005
- SO_TIMESTAMP = 0x400
- SO_TYPE = 0x1008
- SO_USELOOPBACK = 0x40
- TCP_CA_NAME_MAX = 0x10
- TCP_CONGESTION = 0x40
- TCP_INFO = 0x20
- TCP_MAXBURST = 0x4
- TCP_MAXHLEN = 0x3c
- TCP_MAXOLEN = 0x28
- TCP_MAXSEG = 0x2
- TCP_MAXWIN = 0xffff
- TCP_MAX_SACK = 0x4
- TCP_MAX_WINSHIFT = 0xe
- TCP_MD5SIG = 0x10
- TCP_MINMSS = 0xd8
- TCP_MSS = 0x200
- TCP_NODELAY = 0x1
- TCP_NOOPT = 0x8
- TCP_NOPUSH = 0x4
- WCONTINUED = 0x4
- WCOREFLAG = 0x80
- WLINUXCLONE = 0x80000000
- WNOHANG = 0x1
- WNOWAIT = 0x8
- WSTOPPED = 0x2
- WUNTRACED = 0x2
+ AF_APPLETALK = 0x10
+ AF_ARP = 0x23
+ AF_ATM = 0x1e
+ AF_BLUETOOTH = 0x24
+ 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_HYLINK = 0xf
+ AF_IEEE80211 = 0x25
+ AF_IMPLINK = 0x3
+ AF_INET = 0x2
+ AF_INET6 = 0x1c
+ AF_IPX = 0x17
+ AF_ISDN = 0x1a
+ AF_ISO = 0x7
+ AF_LAT = 0xe
+ AF_LINK = 0x12
+ AF_LOCAL = 0x1
+ AF_MAX = 0x26
+ AF_NATM = 0x1d
+ AF_NETBIOS = 0x6
+ AF_NETGRAPH = 0x20
+ AF_OSI = 0x7
+ AF_PUP = 0x4
+ AF_ROUTE = 0x11
+ AF_SCLUSTER = 0x22
+ AF_SIP = 0x18
+ AF_SLOW = 0x21
+ AF_SNA = 0xb
+ AF_UNIX = 0x1
+ AF_UNSPEC = 0
+ AF_VENDOR00 = 0x27
+ AF_VENDOR01 = 0x29
+ AF_VENDOR02 = 0x2b
+ AF_VENDOR03 = 0x2d
+ AF_VENDOR04 = 0x2f
+ AF_VENDOR05 = 0x31
+ AF_VENDOR06 = 0x33
+ AF_VENDOR07 = 0x35
+ AF_VENDOR08 = 0x37
+ AF_VENDOR09 = 0x39
+ AF_VENDOR10 = 0x3b
+ AF_VENDOR11 = 0x3d
+ AF_VENDOR12 = 0x3f
+ AF_VENDOR13 = 0x41
+ AF_VENDOR14 = 0x43
+ AF_VENDOR15 = 0x45
+ AF_VENDOR16 = 0x47
+ AF_VENDOR17 = 0x49
+ AF_VENDOR18 = 0x4b
+ AF_VENDOR19 = 0x4d
+ AF_VENDOR20 = 0x4f
+ AF_VENDOR21 = 0x51
+ AF_VENDOR22 = 0x53
+ AF_VENDOR23 = 0x55
+ AF_VENDOR24 = 0x57
+ AF_VENDOR25 = 0x59
+ AF_VENDOR26 = 0x5b
+ AF_VENDOR27 = 0x5d
+ AF_VENDOR28 = 0x5f
+ AF_VENDOR29 = 0x61
+ AF_VENDOR30 = 0x63
+ AF_VENDOR31 = 0x65
+ AF_VENDOR32 = 0x67
+ AF_VENDOR33 = 0x69
+ AF_VENDOR34 = 0x6b
+ AF_VENDOR35 = 0x6d
+ AF_VENDOR36 = 0x6f
+ AF_VENDOR37 = 0x71
+ AF_VENDOR38 = 0x73
+ AF_VENDOR39 = 0x75
+ AF_VENDOR40 = 0x77
+ AF_VENDOR41 = 0x79
+ AF_VENDOR42 = 0x7b
+ AF_VENDOR43 = 0x7d
+ AF_VENDOR44 = 0x7f
+ AF_VENDOR45 = 0x81
+ AF_VENDOR46 = 0x83
+ AF_VENDOR47 = 0x85
+ 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
+ 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 = 0x5c
+ 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
+ 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
+ EVFILT_NETDEV = -0x8
+ EVFILT_PROC = -0x5
+ EVFILT_READ = -0x1
+ EVFILT_SIGNAL = -0x6
+ EVFILT_SYSCOUNT = 0xa
+ 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
+ EWOULDBLOCK = 0x23
+ EXDEV = 0x12
+ FD_CLOEXEC = 0x1
+ FD_SETSIZE = 0x400
+ F_CANCEL = 0x5
+ F_DUP2FD = 0xa
+ F_DUPFD = 0
+ F_GETFD = 0x1
+ F_GETFL = 0x3
+ F_GETLK = 0xb
+ F_GETOWN = 0x5
+ F_OGETLK = 0x7
+ F_OSETLK = 0x8
+ F_OSETLKW = 0x9
+ F_RDLCK = 0x1
+ F_SETFD = 0x2
+ F_SETFL = 0x4
+ F_SETLK = 0xc
+ F_SETLKW = 0xd
+ F_SETLK_REMOTE = 0xe
+ F_SETOWN = 0x6
+ F_UNLCK = 0x2
+ F_UNLCKSYS = 0x4
+ F_WRLCK = 0x3
+ 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_CARP = 0x70
+ IPPROTO_CFTP = 0x3e
+ IPPROTO_CHAOS = 0x10
+ IPPROTO_CMTP = 0x26
+ IPPROTO_CPHB = 0x49
+ IPPROTO_CPNX = 0x48
+ IPPROTO_DDP = 0x25
+ IPPROTO_DGP = 0x56
+ IPPROTO_DIVERT = 0x102
+ 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_MOBILE = 0x37
+ IPPROTO_MTP = 0x5c
+ IPPROTO_MUX = 0x12
+ IPPROTO_ND = 0x4d
+ IPPROTO_NHRP = 0x36
+ IPPROTO_NONE = 0x3b
+ IPPROTO_NSP = 0x1f
+ IPPROTO_NVPII = 0xb
+ IPPROTO_OLD_DIVERT = 0xfe
+ IPPROTO_OSPFIGP = 0x59
+ IPPROTO_PFSYNC = 0xf0
+ 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_SKIP = 0x39
+ IPPROTO_SPACER = 0x7fff
+ IPPROTO_SRPC = 0x5a
+ IPPROTO_ST = 0x7
+ IPPROTO_SVMTP = 0x52
+ IPPROTO_SWIPE = 0x35
+ IPPROTO_TCF = 0x57
+ IPPROTO_TCP = 0x6
+ IPPROTO_TLSP = 0x38
+ 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_AUTOFLOWLABEL = 0x3b
+ IPV6_BINDV6ONLY = 0x1b
+ IPV6_CHECKSUM = 0x1a
+ IPV6_DEFAULT_MULTICAST_HOPS = 0x1
+ IPV6_DEFAULT_MULTICAST_LOOP = 0x1
+ IPV6_DEFHLIM = 0x40
+ IPV6_DONTFRAG = 0x3e
+ IPV6_DSTOPTS = 0x32
+ 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 = 0x2f
+ IPV6_HOPOPTS = 0x31
+ IPV6_IPSEC_POLICY = 0x1c
+ IPV6_JOIN_GROUP = 0xc
+ IPV6_LEAVE_GROUP = 0xd
+ IPV6_MAXHLIM = 0xff
+ IPV6_MAXOPTHDR = 0x800
+ IPV6_MAXPACKET = 0xffff
+ IPV6_MMTU = 0x500
+ IPV6_MSFILTER = 0x4a
+ IPV6_MULTICAST_HOPS = 0xa
+ IPV6_MULTICAST_IF = 0x9
+ IPV6_MULTICAST_LOOP = 0xb
+ IPV6_NEXTHOP = 0x30
+ IPV6_PATHMTU = 0x2c
+ IPV6_PKTINFO = 0x2e
+ IPV6_PORTRANGE = 0xe
+ IPV6_PORTRANGE_DEFAULT = 0
+ IPV6_PORTRANGE_HIGH = 0x1
+ IPV6_PORTRANGE_LOW = 0x2
+ IPV6_PREFER_TEMPADDR = 0x3f
+ IPV6_RECVDSTOPTS = 0x28
+ IPV6_RECVHOPLIMIT = 0x25
+ IPV6_RECVHOPOPTS = 0x27
+ IPV6_RECVPATHMTU = 0x2b
+ IPV6_RECVPKTINFO = 0x24
+ IPV6_RECVRTHDR = 0x26
+ IPV6_RECVTCLASS = 0x39
+ IPV6_RTHDR = 0x33
+ IPV6_RTHDRDSTOPTS = 0x23
+ IPV6_RTHDR_LOOSE = 0
+ IPV6_RTHDR_STRICT = 0x1
+ IPV6_RTHDR_TYPE_0 = 0
+ 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_ADD_SOURCE_MEMBERSHIP = 0x46
+ IP_BLOCK_SOURCE = 0x48
+ IP_DEFAULT_MULTICAST_LOOP = 0x1
+ IP_DEFAULT_MULTICAST_TTL = 0x1
+ IP_DF = 0x4000
+ IP_DONTFRAG = 0x43
+ IP_DROP_MEMBERSHIP = 0xd
+ IP_DROP_SOURCE_MEMBERSHIP = 0x47
+ IP_DUMMYNET3 = 0x31
+ IP_DUMMYNET_CONFIGURE = 0x3c
+ IP_DUMMYNET_DEL = 0x3d
+ IP_DUMMYNET_FLUSH = 0x3e
+ IP_DUMMYNET_GET = 0x40
+ IP_FAITH = 0x16
+ IP_FW3 = 0x30
+ IP_FW_ADD = 0x32
+ IP_FW_DEL = 0x33
+ IP_FW_FLUSH = 0x34
+ IP_FW_GET = 0x36
+ IP_FW_NAT_CFG = 0x38
+ IP_FW_NAT_DEL = 0x39
+ IP_FW_NAT_GET_CONFIG = 0x3a
+ IP_FW_NAT_GET_LOG = 0x3b
+ IP_FW_RESETLOG = 0x37
+ IP_FW_TABLE_ADD = 0x28
+ IP_FW_TABLE_DEL = 0x29
+ IP_FW_TABLE_FLUSH = 0x2a
+ IP_FW_TABLE_GETSIZE = 0x2b
+ IP_FW_TABLE_LIST = 0x2c
+ IP_FW_ZERO = 0x35
+ IP_HDRINCL = 0x2
+ IP_IPSEC_POLICY = 0x15
+ IP_MAXPACKET = 0xffff
+ IP_MAX_MEMBERSHIPS = 0xfff
+ IP_MAX_SOURCE_FILTER = 0x400
+ IP_MF = 0x2000
+ IP_MINTTL = 0x42
+ IP_MIN_MEMBERSHIPS = 0x1f
+ IP_MSFILTER = 0x4a
+ IP_MSS = 0x240
+ IP_MULTICAST_IF = 0x9
+ IP_MULTICAST_LOOP = 0xb
+ IP_MULTICAST_TTL = 0xa
+ IP_MULTICAST_VIF = 0xe
+ IP_OFFMASK = 0x1fff
+ IP_ONESBCAST = 0x17
+ 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 = 0x41
+ 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_SENDSRCADDR = 0x7
+ IP_TOS = 0x3
+ IP_TTL = 0x4
+ IP_UNBLOCK_SOURCE = 0x49
+ O_ACCMODE = 0x3
+ O_APPEND = 0x8
+ O_ASYNC = 0x40
+ O_CREAT = 0x200
+ O_DIRECT = 0x10000
+ O_EXCL = 0x800
+ O_EXLOCK = 0x20
+ O_FSYNC = 0x80
+ O_NDELAY = 0x4
+ O_NOCTTY = 0x8000
+ O_NOFOLLOW = 0x100
+ O_NONBLOCK = 0x4
+ O_RDONLY = 0
+ O_RDWR = 0x2
+ O_SHLOCK = 0x10
+ O_SYNC = 0x80
+ O_TRUNC = 0x400
+ O_WRONLY = 0x1
+ 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
+ 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
+ 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_ACCEPTFILTER = 0x1000
+ SO_BINTIME = 0x2000
+ SO_BROADCAST = 0x20
+ SO_DEBUG = 0x1
+ SO_DONTROUTE = 0x10
+ SO_ERROR = 0x1007
+ SO_KEEPALIVE = 0x8
+ SO_LABEL = 0x1009
+ SO_LINGER = 0x80
+ SO_LISTENINCQLEN = 0x1013
+ SO_LISTENQLEN = 0x1012
+ SO_LISTENQLIMIT = 0x1011
+ SO_NOSIGPIPE = 0x800
+ SO_NO_DDP = 0x8000
+ SO_NO_OFFLOAD = 0x4000
+ SO_OOBINLINE = 0x100
+ SO_PEERLABEL = 0x1010
+ SO_RCVBUF = 0x1002
+ SO_RCVLOWAT = 0x1004
+ SO_RCVTIMEO = 0x1006
+ SO_REUSEADDR = 0x4
+ SO_REUSEPORT = 0x200
+ SO_SETFIB = 0x1014
+ SO_SNDBUF = 0x1001
+ SO_SNDLOWAT = 0x1003
+ SO_SNDTIMEO = 0x1005
+ SO_TIMESTAMP = 0x400
+ SO_TYPE = 0x1008
+ SO_USELOOPBACK = 0x40
+ TCP_CA_NAME_MAX = 0x10
+ TCP_CONGESTION = 0x40
+ TCP_INFO = 0x20
+ TCP_MAXBURST = 0x4
+ TCP_MAXHLEN = 0x3c
+ TCP_MAXOLEN = 0x28
+ TCP_MAXSEG = 0x2
+ TCP_MAXWIN = 0xffff
+ TCP_MAX_SACK = 0x4
+ TCP_MAX_WINSHIFT = 0xe
+ TCP_MD5SIG = 0x10
+ TCP_MINMSS = 0xd8
+ TCP_MSS = 0x200
+ TCP_NODELAY = 0x1
+ TCP_NOOPT = 0x8
+ TCP_NOPUSH = 0x4
+ WCONTINUED = 0x4
+ WCOREFLAG = 0x80
+ WLINUXCLONE = 0x80000000
+ WNOHANG = 0x1
+ WNOWAIT = 0x8
+ WSTOPPED = 0x2
+ WUNTRACED = 0x2
)
// Types
@@ -536,96 +595,96 @@ const (
// 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",
- 13: "permission denied",
- 48: "address already in use",
- 49: "can't assign requested address",
- 47: "address family not supported by protocol family",
- 35: "resource temporarily unavailable",
- 37: "operation already in progress",
- 80: "authentication error",
+ 8: "exec format error",
9: "bad file descriptor",
- 89: "bad message",
- 72: "RPC struct is bad",
- 16: "device busy",
- 85: "operation canceled",
10: "no child processes",
- 53: "software caused connection abort",
- 61: "connection refused",
- 54: "connection reset by peer",
11: "resource deadlock avoided",
- 39: "destination address required",
- 33: "numerical argument out of domain",
- 88: "programming error",
- 69: "disc quota exceeded",
- 17: "file exists",
+ 12: "cannot allocate memory",
+ 13: "permission denied",
14: "bad address",
- 27: "file too large",
- 79: "inappropriate file type or format",
- 64: "host is down",
- 65: "no route to host",
- 82: "identifier removed",
- 86: "illegal byte sequence",
- 36: "operation now in progress",
- 4: "interrupted system call",
- 22: "invalid argument",
- 5: "input/output error",
- 56: "socket is already connected",
+ 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",
- 92: "protocol error",
- 62: "too many levels of symbolic links",
+ 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",
- 90: "multihop attempted",
- 63: "file name too long",
- 81: "need authenticator",
+ 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",
- 52: "network dropped connection on reset",
51: "network is unreachable",
- 23: "too many open files in system",
- 87: "attribute not found",
+ 52: "network dropped connection on reset",
+ 53: "software caused connection abort",
+ 54: "connection reset by peer",
55: "no buffer space available",
- 19: "operation not supported by device",
- 2: "no such file or directory",
- 8: "exec format error",
- 77: "no locks available",
- 91: "link has been severed",
- 12: "cannot allocate memory",
- 83: "no message of desired type",
- 42: "protocol not available",
- 28: "no space left on device",
- 78: "function not implemented",
- 15: "block device required",
+ 56: "socket is already connected",
57: "socket is not connected",
- 20: "not a directory",
+ 58: "can't send after socket shutdown",
+ 59: "too many references: can't splice",
+ 60: "operation 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",
- 38: "socket operation on non-socket",
- 45: "operation not supported",
- 25: "inappropriate ioctl for device",
- 6: "device not configured",
- 84: "value too large to be stored in data type",
- 1: "operation not permitted",
- 46: "protocol family not supported",
- 32: "broken pipe",
67: "too many processes",
- 76: "bad procedure for program",
- 75: "program version wrong",
- 74: "RPC prog. not avail",
- 43: "protocol not supported",
- 41: "protocol wrong type for socket",
- 34: "result too large",
+ 68: "too many users",
+ 69: "disc quota exceeded",
+ 70: "stale NFS file handle",
71: "too many levels of remote in path",
- 30: "read-only file system",
+ 72: "RPC struct is bad",
73: "RPC version wrong",
- 58: "can't send after socket shutdown",
- 44: "socket type not supported",
- 29: "illegal seek",
- 3: "no such process",
- 70: "stale NFS file handle",
- 60: "operation timed out",
- 59: "too many references: can't splice",
- 26: "text file busy",
- 68: "too many users",
- 18: "cross-device link",
+ 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: "identifier removed",
+ 83: "no message of desired type",
+ 84: "value too large to be stored in data type",
+ 85: "operation canceled",
+ 86: "illegal byte sequence",
+ 87: "attribute not found",
+ 88: "programming error",
+ 89: "bad message",
+ 90: "multihop attempted",
+ 91: "link has been severed",
+ 92: "protocol error",
}
diff --git a/src/pkg/syscall/zerrors_freebsd_amd64.go b/src/pkg/syscall/zerrors_freebsd_amd64.go
index 4f8970a81..1ccafae30 100644
--- a/src/pkg/syscall/zerrors_freebsd_amd64.go
+++ b/src/pkg/syscall/zerrors_freebsd_amd64.go
@@ -605,96 +605,96 @@ const (
// 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",
- 13: "permission denied",
- 48: "address already in use",
- 49: "can't assign requested address",
- 47: "address family not supported by protocol family",
- 35: "resource temporarily unavailable",
- 37: "operation already in progress",
- 80: "authentication error",
+ 8: "exec format error",
9: "bad file descriptor",
- 89: "bad message",
- 72: "RPC struct is bad",
- 16: "device busy",
- 85: "operation canceled",
10: "no child processes",
- 53: "software caused connection abort",
- 61: "connection refused",
- 54: "connection reset by peer",
11: "resource deadlock avoided",
- 39: "destination address required",
- 33: "numerical argument out of domain",
- 88: "programming error",
- 69: "disc quota exceeded",
- 17: "file exists",
+ 12: "cannot allocate memory",
+ 13: "permission denied",
14: "bad address",
- 27: "file too large",
- 79: "inappropriate file type or format",
- 64: "host is down",
- 65: "no route to host",
- 82: "identifier removed",
- 86: "illegal byte sequence",
- 36: "operation now in progress",
- 4: "interrupted system call",
- 22: "invalid argument",
- 5: "input/output error",
- 56: "socket is already connected",
+ 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",
- 92: "protocol error",
- 62: "too many levels of symbolic links",
+ 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",
- 90: "multihop attempted",
- 63: "file name too long",
- 81: "need authenticator",
+ 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",
- 52: "network dropped connection on reset",
51: "network is unreachable",
- 23: "too many open files in system",
- 87: "attribute not found",
+ 52: "network dropped connection on reset",
+ 53: "software caused connection abort",
+ 54: "connection reset by peer",
55: "no buffer space available",
- 19: "operation not supported by device",
- 2: "no such file or directory",
- 8: "exec format error",
- 77: "no locks available",
- 91: "link has been severed",
- 12: "cannot allocate memory",
- 83: "no message of desired type",
- 42: "protocol not available",
- 28: "no space left on device",
- 78: "function not implemented",
- 15: "block device required",
+ 56: "socket is already connected",
57: "socket is not connected",
- 20: "not a directory",
+ 58: "can't send after socket shutdown",
+ 59: "too many references: can't splice",
+ 60: "operation 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",
- 38: "socket operation on non-socket",
- 45: "operation not supported",
- 25: "inappropriate ioctl for device",
- 6: "device not configured",
- 84: "value too large to be stored in data type",
- 1: "operation not permitted",
- 46: "protocol family not supported",
- 32: "broken pipe",
67: "too many processes",
- 76: "bad procedure for program",
- 75: "program version wrong",
- 74: "RPC prog. not avail",
- 43: "protocol not supported",
- 41: "protocol wrong type for socket",
- 34: "result too large",
+ 68: "too many users",
+ 69: "disc quota exceeded",
+ 70: "stale NFS file handle",
71: "too many levels of remote in path",
- 30: "read-only file system",
+ 72: "RPC struct is bad",
73: "RPC version wrong",
- 58: "can't send after socket shutdown",
- 44: "socket type not supported",
- 29: "illegal seek",
- 3: "no such process",
- 70: "stale NFS file handle",
- 60: "operation timed out",
- 59: "too many references: can't splice",
- 26: "text file busy",
- 68: "too many users",
- 18: "cross-device link",
+ 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: "identifier removed",
+ 83: "no message of desired type",
+ 84: "value too large to be stored in data type",
+ 85: "operation canceled",
+ 86: "illegal byte sequence",
+ 87: "attribute not found",
+ 88: "programming error",
+ 89: "bad message",
+ 90: "multihop attempted",
+ 91: "link has been severed",
+ 92: "protocol error",
}
diff --git a/src/pkg/syscall/zerrors_linux_386.go b/src/pkg/syscall/zerrors_linux_386.go
index ae3e75973..fe45d23f1 100644
--- a/src/pkg/syscall/zerrors_linux_386.go
+++ b/src/pkg/syscall/zerrors_linux_386.go
@@ -16,27 +16,34 @@ const (
AF_AX25 = 0x3
AF_BLUETOOTH = 0x1f
AF_BRIDGE = 0x7
+ AF_CAN = 0x1d
AF_DECnet = 0xc
AF_ECONET = 0x13
AF_FILE = 0x1
+ AF_IEEE802154 = 0x24
AF_INET = 0x2
AF_INET6 = 0xa
AF_IPX = 0x4
AF_IRDA = 0x17
+ AF_ISDN = 0x22
AF_IUCV = 0x20
AF_KEY = 0xf
+ AF_LLC = 0x1a
AF_LOCAL = 0x1
- AF_MAX = 0x22
+ AF_MAX = 0x25
AF_NETBEUI = 0xd
AF_NETLINK = 0x10
AF_NETROM = 0x6
AF_PACKET = 0x11
+ AF_PHONET = 0x23
AF_PPPOX = 0x18
+ AF_RDS = 0x15
AF_ROSE = 0xb
AF_ROUTE = 0x10
AF_RXRPC = 0x21
AF_SECURITY = 0xe
AF_SNA = 0x16
+ AF_TIPC = 0x1e
AF_UNIX = 0x1
AF_UNSPEC = 0
AF_WANPIPE = 0x19
@@ -160,9 +167,11 @@ const (
EPOLLRDNORM = 0x40
EPOLLWRBAND = 0x200
EPOLLWRNORM = 0x100
+ EPOLL_CLOEXEC = 0x80000
EPOLL_CTL_ADD = 0x1
EPOLL_CTL_DEL = 0x2
EPOLL_CTL_MOD = 0x3
+ EPOLL_NONBLOCK = 0x800
EPROTO = 0x47
EPROTONOSUPPORT = 0x5d
EPROTOTYPE = 0x5b
@@ -171,6 +180,7 @@ const (
EREMOTE = 0x42
EREMOTEIO = 0x79
ERESTART = 0x55
+ ERFKILL = 0x84
EROFS = 0x1e
ESHUTDOWN = 0x6c
ESOCKTNOSUPPORT = 0x5e
@@ -189,7 +199,6 @@ const (
EWOULDBLOCK = 0xb
EXDEV = 0x12
EXFULL = 0x36
- EXPR_NEST_MAX = 0x20
FD_CLOEXEC = 0x1
FD_SETSIZE = 0x400
F_DUPFD = 0
@@ -201,6 +210,7 @@ const (
F_GETLK = 0xc
F_GETLK64 = 0xc
F_GETOWN = 0x9
+ F_GETOWN_EX = 0x10
F_GETSIG = 0xb
F_LOCK = 0x1
F_NOTIFY = 0x402
@@ -214,6 +224,7 @@ const (
F_SETLKW = 0xe
F_SETLKW64 = 0xe
F_SETOWN = 0x8
+ F_SETOWN_EX = 0xf
F_SETSIG = 0xa
F_SHLCK = 0x8
F_TEST = 0x3
@@ -221,8 +232,69 @@ const (
F_ULOCK = 0
F_UNLCK = 0x2
F_WRLCK = 0x1
+ IFF_ALLMULTI = 0x200
+ IFF_AUTOMEDIA = 0x4000
+ IFF_BROADCAST = 0x2
+ IFF_DEBUG = 0x4
+ IFF_DYNAMIC = 0x8000
+ IFF_LOOPBACK = 0x8
+ IFF_MASTER = 0x400
+ IFF_MULTICAST = 0x1000
+ IFF_NOARP = 0x80
+ IFF_NOTRAILERS = 0x20
+ IFF_NO_PI = 0x1000
+ IFF_ONE_QUEUE = 0x2000
+ IFF_POINTOPOINT = 0x10
+ IFF_PORTSEL = 0x2000
+ IFF_PROMISC = 0x100
+ IFF_RUNNING = 0x40
+ IFF_SLAVE = 0x800
+ IFF_TAP = 0x2
+ IFF_TUN = 0x1
+ IFF_TUN_EXCL = 0x8000
+ IFF_UP = 0x1
+ IFF_VNET_HDR = 0x4000
+ IFNAMSIZ = 0x10
+ IN_ACCESS = 0x1
+ IN_ALL_EVENTS = 0xfff
+ IN_ATTRIB = 0x4
+ 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_CLOEXEC = 0x80000
+ IN_CLOSE = 0x18
+ IN_CLOSE_NOWRITE = 0x10
+ IN_CLOSE_WRITE = 0x8
+ IN_CREATE = 0x100
+ IN_DELETE = 0x200
+ IN_DELETE_SELF = 0x400
+ IN_DONT_FOLLOW = 0x2000000
+ IN_IGNORED = 0x8000
+ IN_ISDIR = 0x40000000
+ IN_LOOPBACKNET = 0x7f
+ IN_MASK_ADD = 0x20000000
+ IN_MODIFY = 0x2
+ IN_MOVE = 0xc0
+ IN_MOVED_FROM = 0x40
+ IN_MOVED_TO = 0x80
+ IN_MOVE_SELF = 0x800
+ IN_NONBLOCK = 0x800
+ IN_ONESHOT = 0x80000000
+ IN_ONLYDIR = 0x1000000
+ IN_OPEN = 0x20
+ IN_Q_OVERFLOW = 0x4000
+ IN_UNMOUNT = 0x2000
IPPROTO_AH = 0x33
IPPROTO_COMP = 0x6c
+ IPPROTO_DCCP = 0x21
IPPROTO_DSTOPTS = 0x3c
IPPROTO_EGP = 0x8
IPPROTO_ENCAP = 0x62
@@ -248,6 +320,7 @@ const (
IPPROTO_TCP = 0x6
IPPROTO_TP = 0x1d
IPPROTO_UDP = 0x11
+ IPPROTO_UDPLITE = 0x88
IPV6_2292DSTOPTS = 0x4
IPV6_2292HOPLIMIT = 0x8
IPV6_2292HOPOPTS = 0x3
@@ -276,6 +349,7 @@ const (
IPV6_PKTINFO = 0x32
IPV6_PMTUDISC_DO = 0x2
IPV6_PMTUDISC_DONT = 0
+ IPV6_PMTUDISC_PROBE = 0x3
IPV6_PMTUDISC_WANT = 0x1
IPV6_RECVDSTOPTS = 0x3a
IPV6_RECVERR = 0x19
@@ -321,6 +395,7 @@ const (
IP_PMTUDISC = 0xa
IP_PMTUDISC_DO = 0x2
IP_PMTUDISC_DONT = 0
+ IP_PMTUDISC_PROBE = 0x3
IP_PMTUDISC_WANT = 0x1
IP_RECVERR = 0xb
IP_RECVOPTS = 0x6
@@ -333,6 +408,40 @@ const (
IP_TOS = 0x1
IP_TTL = 0x2
IP_UNBLOCK_SOURCE = 0x25
+ MAP_32BIT = 0x40
+ MAP_ANON = 0x20
+ MAP_ANONYMOUS = 0x20
+ MAP_DENYWRITE = 0x800
+ MAP_EXECUTABLE = 0x1000
+ MAP_FILE = 0
+ MAP_FIXED = 0x10
+ MAP_GROWSDOWN = 0x100
+ MAP_LOCKED = 0x2000
+ MAP_NONBLOCK = 0x10000
+ MAP_NORESERVE = 0x4000
+ MAP_POPULATE = 0x8000
+ MAP_PRIVATE = 0x2
+ MAP_SHARED = 0x1
+ MAP_STACK = 0x20000
+ MAP_TYPE = 0xf
+ MSG_CMSG_CLOEXEC = 0x40000000
+ MSG_CONFIRM = 0x800
+ MSG_CTRUNC = 0x8
+ MSG_DONTROUTE = 0x4
+ MSG_DONTWAIT = 0x40
+ MSG_EOR = 0x80
+ MSG_ERRQUEUE = 0x2000
+ MSG_FIN = 0x200
+ MSG_MORE = 0x8000
+ MSG_NOSIGNAL = 0x4000
+ MSG_OOB = 0x1
+ MSG_PEEK = 0x2
+ MSG_PROXY = 0x10
+ MSG_RST = 0x1000
+ MSG_SYN = 0x400
+ MSG_TRUNC = 0x20
+ MSG_TRYHARD = 0x4
+ MSG_WAITALL = 0x100
NAME_MAX = 0xff
O_ACCMODE = 0x3
O_APPEND = 0x400
@@ -356,7 +465,38 @@ const (
O_SYNC = 0x1000
O_TRUNC = 0x200
O_WRONLY = 0x1
+ PACKET_ADD_MEMBERSHIP = 0x1
+ PACKET_BROADCAST = 0x1
+ PACKET_DROP_MEMBERSHIP = 0x2
+ PACKET_FASTROUTE = 0x6
+ PACKET_HOST = 0
+ PACKET_LOOPBACK = 0x5
+ PACKET_MR_ALLMULTI = 0x2
+ PACKET_MR_MULTICAST = 0
+ PACKET_MR_PROMISC = 0x1
+ PACKET_MULTICAST = 0x2
+ PACKET_OTHERHOST = 0x3
+ PACKET_OUTGOING = 0x4
+ PACKET_RECV_OUTPUT = 0x3
+ PACKET_RX_RING = 0x5
+ PACKET_STATISTICS = 0x6
+ PROT_EXEC = 0x4
+ PROT_GROWSDOWN = 0x1000000
+ PROT_GROWSUP = 0x2000000
+ PROT_NONE = 0
+ PROT_READ = 0x1
+ PROT_WRITE = 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
@@ -393,11 +533,17 @@ const (
PTRACE_SETREGS = 0xd
PTRACE_SETSIGINFO = 0x4203
PTRACE_SET_THREAD_AREA = 0x1a
+ PTRACE_SINGLEBLOCK = 0x21
PTRACE_SINGLESTEP = 0x9
PTRACE_SYSCALL = 0x18
PTRACE_SYSEMU = 0x1f
PTRACE_SYSEMU_SINGLESTEP = 0x20
PTRACE_TRACEME = 0
+ SCM_CREDENTIALS = 0x2
+ SCM_RIGHTS = 0x1
+ SCM_TIMESTAMP = 0x1d
+ SCM_TIMESTAMPING = 0x25
+ SCM_TIMESTAMPNS = 0x23
SHUT_RD = 0
SHUT_RDWR = 0x2
SHUT_WR = 0x1
@@ -436,7 +582,69 @@ const (
SIGWINCH = 0x1c
SIGXCPU = 0x18
SIGXFSZ = 0x19
+ SIOCADDDLCI = 0x8980
+ SIOCADDMULTI = 0x8931
+ SIOCADDRT = 0x890b
+ SIOCATMARK = 0x8905
+ SIOCDARP = 0x8953
+ SIOCDELDLCI = 0x8981
+ SIOCDELMULTI = 0x8932
+ SIOCDELRT = 0x890c
+ SIOCDEVPRIVATE = 0x89f0
+ SIOCDIFADDR = 0x8936
+ SIOCDRARP = 0x8960
+ SIOCGARP = 0x8954
+ SIOCGIFADDR = 0x8915
+ SIOCGIFBR = 0x8940
+ SIOCGIFBRDADDR = 0x8919
+ SIOCGIFCONF = 0x8912
+ SIOCGIFCOUNT = 0x8938
+ SIOCGIFDSTADDR = 0x8917
+ SIOCGIFENCAP = 0x8925
+ SIOCGIFFLAGS = 0x8913
+ SIOCGIFHWADDR = 0x8927
+ SIOCGIFINDEX = 0x8933
+ SIOCGIFMAP = 0x8970
+ SIOCGIFMEM = 0x891f
+ SIOCGIFMETRIC = 0x891d
+ SIOCGIFMTU = 0x8921
+ SIOCGIFNAME = 0x8910
+ SIOCGIFNETMASK = 0x891b
+ SIOCGIFPFLAGS = 0x8935
+ SIOCGIFSLAVE = 0x8929
+ SIOCGIFTXQLEN = 0x8942
+ SIOCGPGRP = 0x8904
+ SIOCGRARP = 0x8961
+ SIOCGSTAMP = 0x8906
+ SIOCGSTAMPNS = 0x8907
+ SIOCPROTOPRIVATE = 0x89e0
+ SIOCRTMSG = 0x890d
+ SIOCSARP = 0x8955
+ SIOCSIFADDR = 0x8916
+ SIOCSIFBR = 0x8941
+ SIOCSIFBRDADDR = 0x891a
+ SIOCSIFDSTADDR = 0x8918
+ SIOCSIFENCAP = 0x8926
+ SIOCSIFFLAGS = 0x8914
+ SIOCSIFHWADDR = 0x8924
+ SIOCSIFHWBROADCAST = 0x8937
+ SIOCSIFLINK = 0x8911
+ SIOCSIFMAP = 0x8971
+ SIOCSIFMEM = 0x8920
+ SIOCSIFMETRIC = 0x891e
+ SIOCSIFMTU = 0x8922
+ SIOCSIFNAME = 0x8923
+ SIOCSIFNETMASK = 0x891c
+ SIOCSIFPFLAGS = 0x8934
+ SIOCSIFSLAVE = 0x8930
+ SIOCSIFTXQLEN = 0x8943
+ SIOCSPGRP = 0x8902
+ SIOCSRARP = 0x8962
+ SIOGIFINDEX = 0x8933
+ SOCK_CLOEXEC = 0x80000
+ SOCK_DCCP = 0x6
SOCK_DGRAM = 0x2
+ SOCK_NONBLOCK = 0x800
SOCK_PACKET = 0xa
SOCK_RAW = 0x3
SOCK_RDM = 0x4
@@ -462,10 +670,12 @@ const (
SO_BSDCOMPAT = 0xe
SO_DEBUG = 0x1
SO_DETACH_FILTER = 0x1b
+ SO_DOMAIN = 0x27
SO_DONTROUTE = 0x5
SO_ERROR = 0x4
SO_KEEPALIVE = 0x9
SO_LINGER = 0xd
+ SO_MARK = 0x24
SO_NO_CHECK = 0xb
SO_OOBINLINE = 0xa
SO_PASSCRED = 0x10
@@ -474,6 +684,7 @@ const (
SO_PEERNAME = 0x1c
SO_PEERSEC = 0x1f
SO_PRIORITY = 0xc
+ SO_PROTOCOL = 0x26
SO_RCVBUF = 0x8
SO_RCVBUFFORCE = 0x21
SO_RCVLOWAT = 0x12
@@ -487,6 +698,7 @@ const (
SO_SNDLOWAT = 0x13
SO_SNDTIMEO = 0x15
SO_TIMESTAMP = 0x1d
+ SO_TIMESTAMPING = 0x25
SO_TIMESTAMPNS = 0x23
SO_TYPE = 0x3
S_BLKSIZE = 0x200
@@ -534,6 +746,19 @@ const (
TCP_QUICKACK = 0xc
TCP_SYNCNT = 0x7
TCP_WINDOW_CLAMP = 0xa
+ TUNGETFEATURES = 0x800454cf
+ TUNGETIFF = 0x800454d2
+ TUNGETSNDBUF = 0x800454d3
+ TUNSETDEBUG = 0x400454c9
+ TUNSETGROUP = 0x400454ce
+ TUNSETIFF = 0x400454ca
+ TUNSETLINK = 0x400454cd
+ TUNSETNOCSUM = 0x400454c8
+ TUNSETOFFLOAD = 0x400454d0
+ TUNSETOWNER = 0x400454cc
+ TUNSETPERSIST = 0x400454cb
+ TUNSETSNDBUF = 0x400454d4
+ TUNSETTXFILTER = 0x400454d1
WALL = 0x40000000
WCLONE = 0x80000000
WCONTINUED = 0x8
@@ -551,133 +776,134 @@ const (
// 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: "no such device or address",
7: "argument list too long",
- 13: "permission denied",
- 98: "address already in use",
- 99: "cannot assign requested address",
- 68: "advertise error",
- 97: "address family not supported by protocol",
- 11: "resource temporarily unavailable",
- 114: "operation already in progress",
- 52: "invalid exchange",
+ 8: "exec format error",
9: "bad file descriptor",
- 77: "file descriptor in bad state",
- 74: "bad message",
- 53: "invalid request descriptor",
- 56: "invalid request code",
- 57: "invalid slot",
- 59: "bad font file format",
- 16: "device or resource busy",
- 125: "operation canceled",
10: "no child processes",
- 44: "channel number out of range",
- 70: "communication error on send",
- 103: "software caused connection abort",
- 111: "connection refused",
- 104: "connection reset by peer",
- 35: "resource deadlock avoided",
- 89: "destination address required",
- 33: "numerical argument out of domain",
- 73: "RFS specific error",
- 122: "disk quota exceeded",
- 17: "file exists",
+ 11: "resource temporarily unavailable",
+ 12: "cannot allocate memory",
+ 13: "permission denied",
14: "bad address",
+ 15: "block device required",
+ 16: "device or resource busy",
+ 17: "file exists",
+ 18: "invalid cross-device link",
+ 19: "no such 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",
- 112: "host is down",
- 113: "no route to host",
+ 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: "numerical result out of range",
+ 35: "resource deadlock avoided",
+ 36: "file name too long",
+ 37: "no locks available",
+ 38: "function not implemented",
+ 39: "directory not empty",
+ 40: "too many levels of symbolic links",
+ 42: "no message of desired type",
43: "identifier removed",
- 84: "invalid or incomplete multibyte or wide character",
- 115: "operation now in progress",
- 4: "interrupted system call",
- 22: "invalid argument",
- 5: "input/output error",
- 106: "transport endpoint is already connected",
- 21: "is a directory",
- 120: "is a named type file",
- 127: "key has expired",
- 129: "key was rejected by service",
- 128: "key has been revoked",
- 51: "level 2 halted",
+ 44: "channel number out of range",
45: "level 2 not synchronized",
46: "level 3 halted",
47: "level 3 reset",
- 79: "can not access a needed shared library",
- 80: "accessing a corrupted shared library",
- 83: "cannot exec a shared library directly",
- 82: "attempting to link in too many shared libraries",
- 81: ".lib section in a.out corrupted",
48: "link number out of range",
- 40: "too many levels of symbolic links",
- 124: "wrong medium type",
- 24: "too many open files",
- 31: "too many links",
- 90: "message too long",
- 72: "multihop attempted",
- 36: "file name too long",
- 119: "no XENIX semaphores available",
- 100: "network is down",
- 102: "network dropped connection on reset",
- 101: "network is unreachable",
- 23: "too many open files in system",
- 55: "no anode",
- 105: "no buffer space available",
+ 49: "protocol driver not attached",
50: "no CSI structure available",
+ 51: "level 2 halted",
+ 52: "invalid exchange",
+ 53: "invalid request descriptor",
+ 54: "exchange full",
+ 55: "no anode",
+ 56: "invalid request code",
+ 57: "invalid slot",
+ 59: "bad font file format",
+ 60: "device not a stream",
61: "no data available",
- 19: "no such device",
- 2: "no such file or directory",
- 8: "exec format error",
- 126: "required key not available",
- 37: "no locks available",
- 67: "link has been severed",
- 123: "no medium found",
- 12: "cannot allocate memory",
- 42: "no message of desired type",
+ 62: "timer expired",
+ 63: "out of streams resources",
64: "machine is not on the network",
65: "package not installed",
- 92: "protocol not available",
- 28: "no space left on device",
- 63: "out of streams resources",
- 60: "device not a stream",
- 38: "function not implemented",
- 15: "block device required",
- 107: "transport endpoint is not connected",
- 20: "not a directory",
- 39: "directory not empty",
- 118: "not a XENIX named type file",
- 131: "state not recoverable",
- 88: "socket operation on non-socket",
- 95: "operation not supported",
- 25: "inappropriate ioctl for device",
- 76: "name not unique on network",
- 6: "no such device or address",
- 75: "value too large for defined data type",
- 130: "owner died",
- 1: "operation not permitted",
- 96: "protocol family not supported",
- 32: "broken pipe",
+ 66: "object is remote",
+ 67: "link has been severed",
+ 68: "advertise error",
+ 69: "srmount error",
+ 70: "communication error on send",
71: "protocol error",
- 93: "protocol not supported",
- 91: "protocol wrong type for socket",
- 34: "numerical result out of range",
+ 72: "multihop attempted",
+ 73: "RFS specific error",
+ 74: "bad message",
+ 75: "value too large for defined data type",
+ 76: "name not unique on network",
+ 77: "file descriptor in bad state",
78: "remote address changed",
- 66: "object is remote",
- 121: "remote I/O error",
+ 79: "can not access a needed shared library",
+ 80: "accessing a corrupted shared library",
+ 81: ".lib section in a.out corrupted",
+ 82: "attempting to link in too many shared libraries",
+ 83: "cannot exec a shared library directly",
+ 84: "invalid or incomplete multibyte or wide character",
85: "interrupted system call should be restarted",
- 30: "read-only file system",
- 108: "cannot send after transport endpoint shutdown",
- 94: "socket type not supported",
- 29: "illegal seek",
- 3: "no such process",
- 69: "srmount error",
- 116: "stale NFS file handle",
86: "streams pipe error",
- 62: "timer expired",
- 110: "connection timed out",
+ 87: "too many users",
+ 88: "socket operation on non-socket",
+ 89: "destination address required",
+ 90: "message too long",
+ 91: "protocol wrong type for socket",
+ 92: "protocol not available",
+ 93: "protocol not supported",
+ 94: "socket type not supported",
+ 95: "operation not supported",
+ 96: "protocol family not supported",
+ 97: "address family not supported by protocol",
+ 98: "address already in use",
+ 99: "cannot assign requested address",
+ 100: "network is down",
+ 101: "network is unreachable",
+ 102: "network dropped connection on reset",
+ 103: "software caused connection abort",
+ 104: "connection reset by peer",
+ 105: "no buffer space available",
+ 106: "transport endpoint is already connected",
+ 107: "transport endpoint is not connected",
+ 108: "cannot send after transport endpoint shutdown",
109: "too many references: cannot splice",
- 26: "text file busy",
+ 110: "connection timed out",
+ 111: "connection refused",
+ 112: "host is down",
+ 113: "no route to host",
+ 114: "operation already in progress",
+ 115: "operation now in progress",
+ 116: "stale NFS file handle",
117: "structure needs cleaning",
- 49: "protocol driver not attached",
- 87: "too many users",
- 18: "invalid cross-device link",
- 54: "exchange full",
+ 118: "not a XENIX named type file",
+ 119: "no XENIX semaphores available",
+ 120: "is a named type file",
+ 121: "remote I/O error",
+ 122: "disk quota exceeded",
+ 123: "no medium found",
+ 124: "wrong medium type",
+ 125: "operation canceled",
+ 126: "required key not available",
+ 127: "key has expired",
+ 128: "key has been revoked",
+ 129: "key was rejected by service",
+ 130: "owner died",
+ 131: "state not recoverable",
+ 132: "unknown error 132",
}
diff --git a/src/pkg/syscall/zerrors_linux_amd64.go b/src/pkg/syscall/zerrors_linux_amd64.go
index c9ee470c4..f9404d089 100644
--- a/src/pkg/syscall/zerrors_linux_amd64.go
+++ b/src/pkg/syscall/zerrors_linux_amd64.go
@@ -1,7 +1,7 @@
// mkerrors.sh -f -m64
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
-// godefs -f -m64 -gsyscall -f -m64 _const.c
+// godefs -c gcc -f -m64 -gsyscall -f -m64 _const.c
// MACHINE GENERATED - DO NOT EDIT.
@@ -16,27 +16,34 @@ const (
AF_AX25 = 0x3
AF_BLUETOOTH = 0x1f
AF_BRIDGE = 0x7
+ AF_CAN = 0x1d
AF_DECnet = 0xc
AF_ECONET = 0x13
AF_FILE = 0x1
+ AF_IEEE802154 = 0x24
AF_INET = 0x2
AF_INET6 = 0xa
AF_IPX = 0x4
AF_IRDA = 0x17
+ AF_ISDN = 0x22
AF_IUCV = 0x20
AF_KEY = 0xf
+ AF_LLC = 0x1a
AF_LOCAL = 0x1
- AF_MAX = 0x22
+ AF_MAX = 0x25
AF_NETBEUI = 0xd
AF_NETLINK = 0x10
AF_NETROM = 0x6
AF_PACKET = 0x11
+ AF_PHONET = 0x23
AF_PPPOX = 0x18
+ AF_RDS = 0x15
AF_ROSE = 0xb
AF_ROUTE = 0x10
AF_RXRPC = 0x21
AF_SECURITY = 0xe
AF_SNA = 0x16
+ AF_TIPC = 0x1e
AF_UNIX = 0x1
AF_UNSPEC = 0
AF_WANPIPE = 0x19
@@ -160,9 +167,11 @@ const (
EPOLLRDNORM = 0x40
EPOLLWRBAND = 0x200
EPOLLWRNORM = 0x100
+ EPOLL_CLOEXEC = 0x80000
EPOLL_CTL_ADD = 0x1
EPOLL_CTL_DEL = 0x2
EPOLL_CTL_MOD = 0x3
+ EPOLL_NONBLOCK = 0x800
EPROTO = 0x47
EPROTONOSUPPORT = 0x5d
EPROTOTYPE = 0x5b
@@ -171,6 +180,7 @@ const (
EREMOTE = 0x42
EREMOTEIO = 0x79
ERESTART = 0x55
+ ERFKILL = 0x84
EROFS = 0x1e
ESHUTDOWN = 0x6c
ESOCKTNOSUPPORT = 0x5e
@@ -189,7 +199,6 @@ const (
EWOULDBLOCK = 0xb
EXDEV = 0x12
EXFULL = 0x36
- EXPR_NEST_MAX = 0x20
FD_CLOEXEC = 0x1
FD_SETSIZE = 0x400
F_DUPFD = 0
@@ -201,6 +210,7 @@ const (
F_GETLK = 0x5
F_GETLK64 = 0x5
F_GETOWN = 0x9
+ F_GETOWN_EX = 0x10
F_GETSIG = 0xb
F_LOCK = 0x1
F_NOTIFY = 0x402
@@ -214,6 +224,7 @@ const (
F_SETLKW = 0x7
F_SETLKW64 = 0x7
F_SETOWN = 0x8
+ F_SETOWN_EX = 0xf
F_SETSIG = 0xa
F_SHLCK = 0x8
F_TEST = 0x3
@@ -221,8 +232,69 @@ const (
F_ULOCK = 0
F_UNLCK = 0x2
F_WRLCK = 0x1
+ IFF_ALLMULTI = 0x200
+ IFF_AUTOMEDIA = 0x4000
+ IFF_BROADCAST = 0x2
+ IFF_DEBUG = 0x4
+ IFF_DYNAMIC = 0x8000
+ IFF_LOOPBACK = 0x8
+ IFF_MASTER = 0x400
+ IFF_MULTICAST = 0x1000
+ IFF_NOARP = 0x80
+ IFF_NOTRAILERS = 0x20
+ IFF_NO_PI = 0x1000
+ IFF_ONE_QUEUE = 0x2000
+ IFF_POINTOPOINT = 0x10
+ IFF_PORTSEL = 0x2000
+ IFF_PROMISC = 0x100
+ IFF_RUNNING = 0x40
+ IFF_SLAVE = 0x800
+ IFF_TAP = 0x2
+ IFF_TUN = 0x1
+ IFF_TUN_EXCL = 0x8000
+ IFF_UP = 0x1
+ IFF_VNET_HDR = 0x4000
+ IFNAMSIZ = 0x10
+ IN_ACCESS = 0x1
+ IN_ALL_EVENTS = 0xfff
+ IN_ATTRIB = 0x4
+ 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_CLOEXEC = 0x80000
+ IN_CLOSE = 0x18
+ IN_CLOSE_NOWRITE = 0x10
+ IN_CLOSE_WRITE = 0x8
+ IN_CREATE = 0x100
+ IN_DELETE = 0x200
+ IN_DELETE_SELF = 0x400
+ IN_DONT_FOLLOW = 0x2000000
+ IN_IGNORED = 0x8000
+ IN_ISDIR = 0x40000000
+ IN_LOOPBACKNET = 0x7f
+ IN_MASK_ADD = 0x20000000
+ IN_MODIFY = 0x2
+ IN_MOVE = 0xc0
+ IN_MOVED_FROM = 0x40
+ IN_MOVED_TO = 0x80
+ IN_MOVE_SELF = 0x800
+ IN_NONBLOCK = 0x800
+ IN_ONESHOT = 0x80000000
+ IN_ONLYDIR = 0x1000000
+ IN_OPEN = 0x20
+ IN_Q_OVERFLOW = 0x4000
+ IN_UNMOUNT = 0x2000
IPPROTO_AH = 0x33
IPPROTO_COMP = 0x6c
+ IPPROTO_DCCP = 0x21
IPPROTO_DSTOPTS = 0x3c
IPPROTO_EGP = 0x8
IPPROTO_ENCAP = 0x62
@@ -248,6 +320,7 @@ const (
IPPROTO_TCP = 0x6
IPPROTO_TP = 0x1d
IPPROTO_UDP = 0x11
+ IPPROTO_UDPLITE = 0x88
IPV6_2292DSTOPTS = 0x4
IPV6_2292HOPLIMIT = 0x8
IPV6_2292HOPOPTS = 0x3
@@ -276,6 +349,7 @@ const (
IPV6_PKTINFO = 0x32
IPV6_PMTUDISC_DO = 0x2
IPV6_PMTUDISC_DONT = 0
+ IPV6_PMTUDISC_PROBE = 0x3
IPV6_PMTUDISC_WANT = 0x1
IPV6_RECVDSTOPTS = 0x3a
IPV6_RECVERR = 0x19
@@ -321,6 +395,7 @@ const (
IP_PMTUDISC = 0xa
IP_PMTUDISC_DO = 0x2
IP_PMTUDISC_DONT = 0
+ IP_PMTUDISC_PROBE = 0x3
IP_PMTUDISC_WANT = 0x1
IP_RECVERR = 0xb
IP_RECVOPTS = 0x6
@@ -333,6 +408,40 @@ const (
IP_TOS = 0x1
IP_TTL = 0x2
IP_UNBLOCK_SOURCE = 0x25
+ MAP_32BIT = 0x40
+ MAP_ANON = 0x20
+ MAP_ANONYMOUS = 0x20
+ MAP_DENYWRITE = 0x800
+ MAP_EXECUTABLE = 0x1000
+ MAP_FILE = 0
+ MAP_FIXED = 0x10
+ MAP_GROWSDOWN = 0x100
+ MAP_LOCKED = 0x2000
+ MAP_NONBLOCK = 0x10000
+ MAP_NORESERVE = 0x4000
+ MAP_POPULATE = 0x8000
+ MAP_PRIVATE = 0x2
+ MAP_SHARED = 0x1
+ MAP_STACK = 0x20000
+ MAP_TYPE = 0xf
+ MSG_CMSG_CLOEXEC = 0x40000000
+ MSG_CONFIRM = 0x800
+ MSG_CTRUNC = 0x8
+ MSG_DONTROUTE = 0x4
+ MSG_DONTWAIT = 0x40
+ MSG_EOR = 0x80
+ MSG_ERRQUEUE = 0x2000
+ MSG_FIN = 0x200
+ MSG_MORE = 0x8000
+ MSG_NOSIGNAL = 0x4000
+ MSG_OOB = 0x1
+ MSG_PEEK = 0x2
+ MSG_PROXY = 0x10
+ MSG_RST = 0x1000
+ MSG_SYN = 0x400
+ MSG_TRUNC = 0x20
+ MSG_TRYHARD = 0x4
+ MSG_WAITALL = 0x100
NAME_MAX = 0xff
O_ACCMODE = 0x3
O_APPEND = 0x400
@@ -356,8 +465,39 @@ const (
O_SYNC = 0x1000
O_TRUNC = 0x200
O_WRONLY = 0x1
+ PACKET_ADD_MEMBERSHIP = 0x1
+ PACKET_BROADCAST = 0x1
+ PACKET_DROP_MEMBERSHIP = 0x2
+ PACKET_FASTROUTE = 0x6
+ PACKET_HOST = 0
+ PACKET_LOOPBACK = 0x5
+ PACKET_MR_ALLMULTI = 0x2
+ PACKET_MR_MULTICAST = 0
+ PACKET_MR_PROMISC = 0x1
+ PACKET_MULTICAST = 0x2
+ PACKET_OTHERHOST = 0x3
+ PACKET_OUTGOING = 0x4
+ PACKET_RECV_OUTPUT = 0x3
+ PACKET_RX_RING = 0x5
+ PACKET_STATISTICS = 0x6
+ PROT_EXEC = 0x4
+ PROT_GROWSDOWN = 0x1000000
+ PROT_GROWSUP = 0x2000000
+ PROT_NONE = 0
+ PROT_READ = 0x1
+ PROT_WRITE = 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
@@ -394,9 +534,17 @@ const (
PTRACE_SETREGS = 0xd
PTRACE_SETSIGINFO = 0x4203
PTRACE_SET_THREAD_AREA = 0x1a
+ PTRACE_SINGLEBLOCK = 0x21
PTRACE_SINGLESTEP = 0x9
PTRACE_SYSCALL = 0x18
+ PTRACE_SYSEMU = 0x1f
+ PTRACE_SYSEMU_SINGLESTEP = 0x20
PTRACE_TRACEME = 0
+ SCM_CREDENTIALS = 0x2
+ SCM_RIGHTS = 0x1
+ SCM_TIMESTAMP = 0x1d
+ SCM_TIMESTAMPING = 0x25
+ SCM_TIMESTAMPNS = 0x23
SHUT_RD = 0
SHUT_RDWR = 0x2
SHUT_WR = 0x1
@@ -435,7 +583,69 @@ const (
SIGWINCH = 0x1c
SIGXCPU = 0x18
SIGXFSZ = 0x19
+ SIOCADDDLCI = 0x8980
+ SIOCADDMULTI = 0x8931
+ SIOCADDRT = 0x890b
+ SIOCATMARK = 0x8905
+ SIOCDARP = 0x8953
+ SIOCDELDLCI = 0x8981
+ SIOCDELMULTI = 0x8932
+ SIOCDELRT = 0x890c
+ SIOCDEVPRIVATE = 0x89f0
+ SIOCDIFADDR = 0x8936
+ SIOCDRARP = 0x8960
+ SIOCGARP = 0x8954
+ SIOCGIFADDR = 0x8915
+ SIOCGIFBR = 0x8940
+ SIOCGIFBRDADDR = 0x8919
+ SIOCGIFCONF = 0x8912
+ SIOCGIFCOUNT = 0x8938
+ SIOCGIFDSTADDR = 0x8917
+ SIOCGIFENCAP = 0x8925
+ SIOCGIFFLAGS = 0x8913
+ SIOCGIFHWADDR = 0x8927
+ SIOCGIFINDEX = 0x8933
+ SIOCGIFMAP = 0x8970
+ SIOCGIFMEM = 0x891f
+ SIOCGIFMETRIC = 0x891d
+ SIOCGIFMTU = 0x8921
+ SIOCGIFNAME = 0x8910
+ SIOCGIFNETMASK = 0x891b
+ SIOCGIFPFLAGS = 0x8935
+ SIOCGIFSLAVE = 0x8929
+ SIOCGIFTXQLEN = 0x8942
+ SIOCGPGRP = 0x8904
+ SIOCGRARP = 0x8961
+ SIOCGSTAMP = 0x8906
+ SIOCGSTAMPNS = 0x8907
+ SIOCPROTOPRIVATE = 0x89e0
+ SIOCRTMSG = 0x890d
+ SIOCSARP = 0x8955
+ SIOCSIFADDR = 0x8916
+ SIOCSIFBR = 0x8941
+ SIOCSIFBRDADDR = 0x891a
+ SIOCSIFDSTADDR = 0x8918
+ SIOCSIFENCAP = 0x8926
+ SIOCSIFFLAGS = 0x8914
+ SIOCSIFHWADDR = 0x8924
+ SIOCSIFHWBROADCAST = 0x8937
+ SIOCSIFLINK = 0x8911
+ SIOCSIFMAP = 0x8971
+ SIOCSIFMEM = 0x8920
+ SIOCSIFMETRIC = 0x891e
+ SIOCSIFMTU = 0x8922
+ SIOCSIFNAME = 0x8923
+ SIOCSIFNETMASK = 0x891c
+ SIOCSIFPFLAGS = 0x8934
+ SIOCSIFSLAVE = 0x8930
+ SIOCSIFTXQLEN = 0x8943
+ SIOCSPGRP = 0x8902
+ SIOCSRARP = 0x8962
+ SIOGIFINDEX = 0x8933
+ SOCK_CLOEXEC = 0x80000
+ SOCK_DCCP = 0x6
SOCK_DGRAM = 0x2
+ SOCK_NONBLOCK = 0x800
SOCK_PACKET = 0xa
SOCK_RAW = 0x3
SOCK_RDM = 0x4
@@ -461,10 +671,12 @@ const (
SO_BSDCOMPAT = 0xe
SO_DEBUG = 0x1
SO_DETACH_FILTER = 0x1b
+ SO_DOMAIN = 0x27
SO_DONTROUTE = 0x5
SO_ERROR = 0x4
SO_KEEPALIVE = 0x9
SO_LINGER = 0xd
+ SO_MARK = 0x24
SO_NO_CHECK = 0xb
SO_OOBINLINE = 0xa
SO_PASSCRED = 0x10
@@ -473,6 +685,7 @@ const (
SO_PEERNAME = 0x1c
SO_PEERSEC = 0x1f
SO_PRIORITY = 0xc
+ SO_PROTOCOL = 0x26
SO_RCVBUF = 0x8
SO_RCVBUFFORCE = 0x21
SO_RCVLOWAT = 0x12
@@ -486,6 +699,7 @@ const (
SO_SNDLOWAT = 0x13
SO_SNDTIMEO = 0x15
SO_TIMESTAMP = 0x1d
+ SO_TIMESTAMPING = 0x25
SO_TIMESTAMPNS = 0x23
SO_TYPE = 0x3
S_BLKSIZE = 0x200
@@ -533,6 +747,19 @@ const (
TCP_QUICKACK = 0xc
TCP_SYNCNT = 0x7
TCP_WINDOW_CLAMP = 0xa
+ TUNGETFEATURES = 0x800454cf
+ TUNGETIFF = 0x800454d2
+ TUNGETSNDBUF = 0x800454d3
+ TUNSETDEBUG = 0x400454c9
+ TUNSETGROUP = 0x400454ce
+ TUNSETIFF = 0x400454ca
+ TUNSETLINK = 0x400454cd
+ TUNSETNOCSUM = 0x400454c8
+ TUNSETOFFLOAD = 0x400454d0
+ TUNSETOWNER = 0x400454cc
+ TUNSETPERSIST = 0x400454cb
+ TUNSETSNDBUF = 0x400454d4
+ TUNSETTXFILTER = 0x400454d1
WALL = 0x40000000
WCLONE = 0x80000000
WCONTINUED = 0x8
@@ -550,133 +777,134 @@ const (
// 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: "no such device or address",
7: "argument list too long",
- 13: "permission denied",
- 98: "address already in use",
- 99: "cannot assign requested address",
- 68: "advertise error",
- 97: "address family not supported by protocol",
- 11: "resource temporarily unavailable",
- 114: "operation already in progress",
- 52: "invalid exchange",
+ 8: "exec format error",
9: "bad file descriptor",
- 77: "file descriptor in bad state",
- 74: "bad message",
- 53: "invalid request descriptor",
- 56: "invalid request code",
- 57: "invalid slot",
- 59: "bad font file format",
- 16: "device or resource busy",
- 125: "operation canceled",
10: "no child processes",
- 44: "channel number out of range",
- 70: "communication error on send",
- 103: "software caused connection abort",
- 111: "connection refused",
- 104: "connection reset by peer",
- 35: "resource deadlock avoided",
- 89: "destination address required",
- 33: "numerical argument out of domain",
- 73: "RFS specific error",
- 122: "disk quota exceeded",
- 17: "file exists",
+ 11: "resource temporarily unavailable",
+ 12: "cannot allocate memory",
+ 13: "permission denied",
14: "bad address",
+ 15: "block device required",
+ 16: "device or resource busy",
+ 17: "file exists",
+ 18: "invalid cross-device link",
+ 19: "no such 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",
- 112: "host is down",
- 113: "no route to host",
+ 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: "numerical result out of range",
+ 35: "resource deadlock avoided",
+ 36: "file name too long",
+ 37: "no locks available",
+ 38: "function not implemented",
+ 39: "directory not empty",
+ 40: "too many levels of symbolic links",
+ 42: "no message of desired type",
43: "identifier removed",
- 84: "invalid or incomplete multibyte or wide character",
- 115: "operation now in progress",
- 4: "interrupted system call",
- 22: "invalid argument",
- 5: "input/output error",
- 106: "transport endpoint is already connected",
- 21: "is a directory",
- 120: "is a named type file",
- 127: "key has expired",
- 129: "key was rejected by service",
- 128: "key has been revoked",
- 51: "level 2 halted",
+ 44: "channel number out of range",
45: "level 2 not synchronized",
46: "level 3 halted",
47: "level 3 reset",
- 79: "can not access a needed shared library",
- 80: "accessing a corrupted shared library",
- 83: "cannot exec a shared library directly",
- 82: "attempting to link in too many shared libraries",
- 81: ".lib section in a.out corrupted",
48: "link number out of range",
- 40: "too many levels of symbolic links",
- 124: "wrong medium type",
- 24: "too many open files",
- 31: "too many links",
- 90: "message too long",
- 72: "multihop attempted",
- 36: "file name too long",
- 119: "no XENIX semaphores available",
- 100: "network is down",
- 102: "network dropped connection on reset",
- 101: "network is unreachable",
- 23: "too many open files in system",
- 55: "no anode",
- 105: "no buffer space available",
+ 49: "protocol driver not attached",
50: "no CSI structure available",
+ 51: "level 2 halted",
+ 52: "invalid exchange",
+ 53: "invalid request descriptor",
+ 54: "exchange full",
+ 55: "no anode",
+ 56: "invalid request code",
+ 57: "invalid slot",
+ 59: "bad font file format",
+ 60: "device not a stream",
61: "no data available",
- 19: "no such device",
- 2: "no such file or directory",
- 8: "exec format error",
- 126: "required key not available",
- 37: "no locks available",
- 67: "link has been severed",
- 123: "no medium found",
- 12: "cannot allocate memory",
- 42: "no message of desired type",
+ 62: "timer expired",
+ 63: "out of streams resources",
64: "machine is not on the network",
65: "package not installed",
- 92: "protocol not available",
- 28: "no space left on device",
- 63: "out of streams resources",
- 60: "device not a stream",
- 38: "function not implemented",
- 15: "block device required",
- 107: "transport endpoint is not connected",
- 20: "not a directory",
- 39: "directory not empty",
- 118: "not a XENIX named type file",
- 131: "state not recoverable",
- 88: "socket operation on non-socket",
- 95: "operation not supported",
- 25: "inappropriate ioctl for device",
- 76: "name not unique on network",
- 6: "no such device or address",
- 75: "value too large for defined data type",
- 130: "owner died",
- 1: "operation not permitted",
- 96: "protocol family not supported",
- 32: "broken pipe",
+ 66: "object is remote",
+ 67: "link has been severed",
+ 68: "advertise error",
+ 69: "srmount error",
+ 70: "communication error on send",
71: "protocol error",
- 93: "protocol not supported",
- 91: "protocol wrong type for socket",
- 34: "numerical result out of range",
+ 72: "multihop attempted",
+ 73: "RFS specific error",
+ 74: "bad message",
+ 75: "value too large for defined data type",
+ 76: "name not unique on network",
+ 77: "file descriptor in bad state",
78: "remote address changed",
- 66: "object is remote",
- 121: "remote I/O error",
+ 79: "can not access a needed shared library",
+ 80: "accessing a corrupted shared library",
+ 81: ".lib section in a.out corrupted",
+ 82: "attempting to link in too many shared libraries",
+ 83: "cannot exec a shared library directly",
+ 84: "invalid or incomplete multibyte or wide character",
85: "interrupted system call should be restarted",
- 30: "read-only file system",
- 108: "cannot send after transport endpoint shutdown",
- 94: "socket type not supported",
- 29: "illegal seek",
- 3: "no such process",
- 69: "srmount error",
- 116: "stale NFS file handle",
86: "streams pipe error",
- 62: "timer expired",
- 110: "connection timed out",
+ 87: "too many users",
+ 88: "socket operation on non-socket",
+ 89: "destination address required",
+ 90: "message too long",
+ 91: "protocol wrong type for socket",
+ 92: "protocol not available",
+ 93: "protocol not supported",
+ 94: "socket type not supported",
+ 95: "operation not supported",
+ 96: "protocol family not supported",
+ 97: "address family not supported by protocol",
+ 98: "address already in use",
+ 99: "cannot assign requested address",
+ 100: "network is down",
+ 101: "network is unreachable",
+ 102: "network dropped connection on reset",
+ 103: "software caused connection abort",
+ 104: "connection reset by peer",
+ 105: "no buffer space available",
+ 106: "transport endpoint is already connected",
+ 107: "transport endpoint is not connected",
+ 108: "cannot send after transport endpoint shutdown",
109: "too many references: cannot splice",
- 26: "text file busy",
+ 110: "connection timed out",
+ 111: "connection refused",
+ 112: "host is down",
+ 113: "no route to host",
+ 114: "operation already in progress",
+ 115: "operation now in progress",
+ 116: "stale NFS file handle",
117: "structure needs cleaning",
- 49: "protocol driver not attached",
- 87: "too many users",
- 18: "invalid cross-device link",
- 54: "exchange full",
+ 118: "not a XENIX named type file",
+ 119: "no XENIX semaphores available",
+ 120: "is a named type file",
+ 121: "remote I/O error",
+ 122: "disk quota exceeded",
+ 123: "no medium found",
+ 124: "wrong medium type",
+ 125: "operation canceled",
+ 126: "required key not available",
+ 127: "key has expired",
+ 128: "key has been revoked",
+ 129: "key was rejected by service",
+ 130: "owner died",
+ 131: "state not recoverable",
+ 132: "unknown error 132",
}
diff --git a/src/pkg/syscall/zerrors_linux_arm.go b/src/pkg/syscall/zerrors_linux_arm.go
index c706eed35..1f8b1830b 100644
--- a/src/pkg/syscall/zerrors_linux_arm.go
+++ b/src/pkg/syscall/zerrors_linux_arm.go
@@ -1,7 +1,7 @@
// mkerrors.sh
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
-// godefs -c arm-gcc -gsyscall _const.c
+// godefs -c gcc -gsyscall _const.c
// MACHINE GENERATED - DO NOT EDIT.
@@ -23,9 +23,11 @@ const (
AF_INET6 = 0xa
AF_IPX = 0x4
AF_IRDA = 0x17
+ AF_ISDN = 0x22
+ AF_IUCV = 0x20
AF_KEY = 0xf
AF_LOCAL = 0x1
- AF_MAX = 0x20
+ AF_MAX = 0x23
AF_NETBEUI = 0xd
AF_NETLINK = 0x10
AF_NETROM = 0x6
@@ -33,6 +35,7 @@ const (
AF_PPPOX = 0x18
AF_ROSE = 0xb
AF_ROUTE = 0x10
+ AF_RXRPC = 0x21
AF_SECURITY = 0xe
AF_SNA = 0x16
AF_UNIX = 0x1
@@ -152,15 +155,19 @@ const (
EPOLLHUP = 0x10
EPOLLIN = 0x1
EPOLLMSG = 0x400
+ EPOLLONESHOT = 0x40000000
EPOLLOUT = 0x4
EPOLLPRI = 0x2
EPOLLRDBAND = 0x80
+ EPOLLRDHUP = 0x2000
EPOLLRDNORM = 0x40
EPOLLWRBAND = 0x200
EPOLLWRNORM = 0x100
+ EPOLL_CLOEXEC = 0x80000
EPOLL_CTL_ADD = 0x1
EPOLL_CTL_DEL = 0x2
EPOLL_CTL_MOD = 0x3
+ EPOLL_NONBLOCK = 0x800
EPROTO = 0x47
EPROTONOSUPPORT = 0x5d
EPROTOTYPE = 0x5b
@@ -169,6 +176,7 @@ const (
EREMOTE = 0x42
EREMOTEIO = 0x79
ERESTART = 0x55
+ ERFKILL = 0x84
EROFS = 0x1e
ESHUTDOWN = 0x6c
ESOCKTNOSUPPORT = 0x5e
@@ -187,10 +195,10 @@ const (
EWOULDBLOCK = 0xb
EXDEV = 0x12
EXFULL = 0x36
- EXPR_NEST_MAX = 0x20
FD_CLOEXEC = 0x1
FD_SETSIZE = 0x400
F_DUPFD = 0
+ F_DUPFD_CLOEXEC = 0x406
F_EXLCK = 0x4
F_GETFD = 0x1
F_GETFL = 0x3
@@ -218,8 +226,46 @@ const (
F_ULOCK = 0
F_UNLCK = 0x2
F_WRLCK = 0x1
+ IN_ACCESS = 0x1
+ IN_ALL_EVENTS = 0xfff
+ IN_ATTRIB = 0x4
+ 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_CLOEXEC = 0x80000
+ IN_CLOSE = 0x18
+ IN_CLOSE_NOWRITE = 0x10
+ IN_CLOSE_WRITE = 0x8
+ IN_CREATE = 0x100
+ IN_DELETE = 0x200
+ IN_DELETE_SELF = 0x400
+ IN_DONT_FOLLOW = 0x2000000
+ IN_IGNORED = 0x8000
+ IN_ISDIR = 0x40000000
+ IN_LOOPBACKNET = 0x7f
+ IN_MASK_ADD = 0x20000000
+ IN_MODIFY = 0x2
+ IN_MOVE = 0xc0
+ IN_MOVED_FROM = 0x40
+ IN_MOVED_TO = 0x80
+ IN_MOVE_SELF = 0x800
+ IN_NONBLOCK = 0x800
+ IN_ONESHOT = 0x80000000
+ IN_ONLYDIR = 0x1000000
+ IN_OPEN = 0x20
+ IN_Q_OVERFLOW = 0x4000
+ IN_UNMOUNT = 0x2000
IPPROTO_AH = 0x33
IPPROTO_COMP = 0x6c
+ IPPROTO_DCCP = 0x21
IPPROTO_DSTOPTS = 0x3c
IPPROTO_EGP = 0x8
IPPROTO_ENCAP = 0x62
@@ -241,18 +287,29 @@ const (
IPPROTO_RAW = 0xff
IPPROTO_ROUTING = 0x2b
IPPROTO_RSVP = 0x2e
+ IPPROTO_SCTP = 0x84
IPPROTO_TCP = 0x6
IPPROTO_TP = 0x1d
IPPROTO_UDP = 0x11
+ IPPROTO_UDPLITE = 0x88
+ IPV6_2292DSTOPTS = 0x4
+ IPV6_2292HOPLIMIT = 0x8
+ IPV6_2292HOPOPTS = 0x3
+ IPV6_2292PKTINFO = 0x2
+ IPV6_2292PKTOPTIONS = 0x6
+ IPV6_2292RTHDR = 0x5
IPV6_ADDRFORM = 0x1
IPV6_ADD_MEMBERSHIP = 0x14
IPV6_AUTHHDR = 0xa
IPV6_CHECKSUM = 0x7
IPV6_DROP_MEMBERSHIP = 0x15
- IPV6_DSTOPTS = 0x4
- IPV6_HOPLIMIT = 0x8
- IPV6_HOPOPTS = 0x3
+ IPV6_DSTOPTS = 0x3b
+ IPV6_HOPLIMIT = 0x34
+ IPV6_HOPOPTS = 0x36
+ IPV6_IPSEC_POLICY = 0x22
+ IPV6_JOIN_ANYCAST = 0x1b
IPV6_JOIN_GROUP = 0x14
+ IPV6_LEAVE_ANYCAST = 0x1c
IPV6_LEAVE_GROUP = 0x15
IPV6_MTU = 0x18
IPV6_MTU_DISCOVER = 0x17
@@ -260,29 +317,43 @@ const (
IPV6_MULTICAST_IF = 0x11
IPV6_MULTICAST_LOOP = 0x13
IPV6_NEXTHOP = 0x9
- IPV6_PKTINFO = 0x2
- IPV6_PKTOPTIONS = 0x6
+ IPV6_PKTINFO = 0x32
IPV6_PMTUDISC_DO = 0x2
IPV6_PMTUDISC_DONT = 0
+ IPV6_PMTUDISC_PROBE = 0x3
IPV6_PMTUDISC_WANT = 0x1
+ IPV6_RECVDSTOPTS = 0x3a
IPV6_RECVERR = 0x19
+ IPV6_RECVHOPLIMIT = 0x33
+ IPV6_RECVHOPOPTS = 0x35
+ IPV6_RECVPKTINFO = 0x31
+ IPV6_RECVRTHDR = 0x38
+ IPV6_RECVTCLASS = 0x42
IPV6_ROUTER_ALERT = 0x16
- IPV6_RTHDR = 0x5
+ IPV6_RTHDR = 0x39
+ IPV6_RTHDRDSTOPTS = 0x37
IPV6_RTHDR_LOOSE = 0
IPV6_RTHDR_STRICT = 0x1
IPV6_RTHDR_TYPE_0 = 0
- IPV6_RXDSTOPTS = 0x4
- IPV6_RXHOPOPTS = 0x3
+ IPV6_RXDSTOPTS = 0x3b
+ IPV6_RXHOPOPTS = 0x36
+ IPV6_TCLASS = 0x43
IPV6_UNICAST_HOPS = 0x10
+ IPV6_V6ONLY = 0x1a
+ IPV6_XFRM_POLICY = 0x23
IP_ADD_MEMBERSHIP = 0x23
+ IP_ADD_SOURCE_MEMBERSHIP = 0x27
+ IP_BLOCK_SOURCE = 0x26
IP_DEFAULT_MULTICAST_LOOP = 0x1
IP_DEFAULT_MULTICAST_TTL = 0x1
IP_DF = 0x4000
IP_DROP_MEMBERSHIP = 0x24
+ IP_DROP_SOURCE_MEMBERSHIP = 0x28
IP_HDRINCL = 0x3
IP_MAXPACKET = 0xffff
IP_MAX_MEMBERSHIPS = 0x14
IP_MF = 0x2000
+ IP_MSFILTER = 0x29
IP_MSS = 0x240
IP_MTU_DISCOVER = 0xa
IP_MULTICAST_IF = 0x20
@@ -295,6 +366,7 @@ const (
IP_PMTUDISC = 0xa
IP_PMTUDISC_DO = 0x2
IP_PMTUDISC_DONT = 0
+ IP_PMTUDISC_PROBE = 0x3
IP_PMTUDISC_WANT = 0x1
IP_RECVERR = 0xb
IP_RECVOPTS = 0x6
@@ -306,10 +378,12 @@ const (
IP_ROUTER_ALERT = 0x5
IP_TOS = 0x1
IP_TTL = 0x2
+ IP_UNBLOCK_SOURCE = 0x25
NAME_MAX = 0xff
O_ACCMODE = 0x3
O_APPEND = 0x400
O_ASYNC = 0x2000
+ O_CLOEXEC = 0x80000
O_CREAT = 0x40
O_DIRECT = 0x10000
O_DIRECTORY = 0x4000
@@ -318,6 +392,7 @@ const (
O_FSYNC = 0x1000
O_LARGEFILE = 0x20000
O_NDELAY = 0x800
+ O_NOATIME = 0x40000
O_NOCTTY = 0x100
O_NOFOLLOW = 0x8000
O_NONBLOCK = 0x800
@@ -336,10 +411,12 @@ const (
PTRACE_EVENT_FORK = 0x1
PTRACE_EVENT_VFORK = 0x2
PTRACE_EVENT_VFORK_DONE = 0x5
+ PTRACE_GETCRUNCHREGS = 0x19
PTRACE_GETEVENTMSG = 0x4201
PTRACE_GETFPREGS = 0xe
PTRACE_GETREGS = 0xc
PTRACE_GETSIGINFO = 0x4202
+ PTRACE_GETVFPREGS = 0x1b
PTRACE_GETWMMXREGS = 0x12
PTRACE_GET_THREAD_AREA = 0x16
PTRACE_KILL = 0x8
@@ -358,11 +435,14 @@ const (
PTRACE_POKEDATA = 0x5
PTRACE_POKETEXT = 0x4
PTRACE_POKEUSR = 0x6
+ PTRACE_SETCRUNCHREGS = 0x1a
PTRACE_SETFPREGS = 0xf
PTRACE_SETOPTIONS = 0x4200
PTRACE_SETREGS = 0xd
PTRACE_SETSIGINFO = 0x4203
+ PTRACE_SETVFPREGS = 0x1c
PTRACE_SETWMMXREGS = 0x13
+ PTRACE_SET_SYSCALL = 0x17
PTRACE_SINGLESTEP = 0x9
PTRACE_SYSCALL = 0x18
PTRACE_TRACEME = 0
@@ -404,7 +484,10 @@ const (
SIGWINCH = 0x1c
SIGXCPU = 0x18
SIGXFSZ = 0x19
+ SOCK_CLOEXEC = 0x80000
+ SOCK_DCCP = 0x6
SOCK_DGRAM = 0x2
+ SOCK_NONBLOCK = 0x800
SOCK_PACKET = 0xa
SOCK_RAW = 0x3
SOCK_RDM = 0x4
@@ -434,14 +517,17 @@ const (
SO_ERROR = 0x4
SO_KEEPALIVE = 0x9
SO_LINGER = 0xd
+ SO_MARK = 0x24
SO_NO_CHECK = 0xb
SO_OOBINLINE = 0xa
SO_PASSCRED = 0x10
+ SO_PASSSEC = 0x22
SO_PEERCRED = 0x11
SO_PEERNAME = 0x1c
SO_PEERSEC = 0x1f
SO_PRIORITY = 0xc
SO_RCVBUF = 0x8
+ SO_RCVBUFFORCE = 0x21
SO_RCVLOWAT = 0x12
SO_RCVTIMEO = 0x14
SO_REUSEADDR = 0x2
@@ -449,9 +535,12 @@ const (
SO_SECURITY_ENCRYPTION_NETWORK = 0x18
SO_SECURITY_ENCRYPTION_TRANSPORT = 0x17
SO_SNDBUF = 0x7
+ SO_SNDBUFFORCE = 0x20
SO_SNDLOWAT = 0x13
SO_SNDTIMEO = 0x15
SO_TIMESTAMP = 0x1d
+ SO_TIMESTAMPING = 0x25
+ SO_TIMESTAMPNS = 0x23
SO_TYPE = 0x3
S_BLKSIZE = 0x200
S_IEXEC = 0x40
@@ -480,6 +569,7 @@ const (
S_IXGRP = 0x8
S_IXOTH = 0x1
S_IXUSR = 0x40
+ TCP_CONGESTION = 0xd
TCP_CORK = 0x3
TCP_DEFER_ACCEPT = 0x9
TCP_INFO = 0xb
@@ -490,6 +580,8 @@ const (
TCP_MAXSEG = 0x2
TCP_MAXWIN = 0xffff
TCP_MAX_WINSHIFT = 0xe
+ TCP_MD5SIG = 0xe
+ TCP_MD5SIG_MAXKEYLEN = 0x50
TCP_MSS = 0x200
TCP_NODELAY = 0x1
TCP_QUICKACK = 0xc
@@ -497,9 +589,13 @@ const (
TCP_WINDOW_CLAMP = 0xa
WALL = 0x40000000
WCLONE = 0x80000000
- WCOREFLAG = 0x80
+ WCONTINUED = 0x8
+ WEXITED = 0x4
WNOHANG = 0x1
+ WNOTHREAD = 0x20000000
+ WNOWAIT = 0x1000000
WORDSIZE = 0x20
+ WSTOPPED = 0x2
WUNTRACED = 0x2
)
@@ -551,9 +647,9 @@ var errors = [...]string{
106: "transport endpoint is already connected",
21: "is a directory",
120: "is a named type file",
- 127: "unknown error 127",
- 129: "unknown error 129",
- 128: "unknown error 128",
+ 127: "key has expired",
+ 129: "key was rejected by service",
+ 128: "key has been revoked",
51: "level 2 halted",
45: "level 2 not synchronized",
46: "level 3 halted",
@@ -583,7 +679,7 @@ var errors = [...]string{
19: "no such device",
2: "no such file or directory",
8: "exec format error",
- 126: "unknown error 126",
+ 126: "required key not available",
37: "no locks available",
67: "link has been severed",
123: "no medium found",
@@ -601,14 +697,14 @@ var errors = [...]string{
20: "not a directory",
39: "directory not empty",
118: "not a XENIX named type file",
- 131: "unknown error 131",
+ 131: "state not recoverable",
88: "socket operation on non-socket",
95: "operation not supported",
25: "inappropriate ioctl for device",
76: "name not unique on network",
6: "no such device or address",
75: "value too large for defined data type",
- 130: "unknown error 130",
+ 130: "owner died",
1: "operation not permitted",
96: "protocol family not supported",
32: "broken pipe",
@@ -620,6 +716,7 @@ var errors = [...]string{
66: "object is remote",
121: "remote I/O error",
85: "interrupted system call should be restarted",
+ 132: "unknown error 132",
30: "read-only file system",
108: "cannot send after transport endpoint shutdown",
94: "socket type not supported",
diff --git a/src/pkg/syscall/zerrors_nacl_386.go b/src/pkg/syscall/zerrors_nacl_386.go
deleted file mode 100644
index 5ae05a132..000000000
--- a/src/pkg/syscall/zerrors_nacl_386.go
+++ /dev/null
@@ -1,246 +0,0 @@
-// mkerrors_nacl.sh /home/rsc/pub/nacl/native_client/src/trusted/service_runtime/include/sys/errno.h
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
-
-package syscall
-
-const (
- EPERM = 1
- ENOENT = 2
- ESRCH = 3
- EINTR = 4
- EIO = 5
- ENXIO = 6
- E2BIG = 7
- ENOEXEC = 8
- EBADF = 9
- ECHILD = 10
- EAGAIN = 11
- ENOMEM = 12
- EACCES = 13
- EFAULT = 14
- EBUSY = 16
- EEXIST = 17
- EXDEV = 18
- ENODEV = 19
- ENOTDIR = 20
- EISDIR = 21
- EINVAL = 22
- ENFILE = 23
- EMFILE = 24
- ENOTTY = 25
- EFBIG = 27
- ENOSPC = 28
- ESPIPE = 29
- EROFS = 30
- EMLINK = 31
- EPIPE = 32
- ENAMETOOLONG = 36
- ENOSYS = 38
- EDQUOT = 122
- EDOM = 33
- ERANGE = 34
- ENOMSG = 35
- ECHRNG = 37
- EL3HLT = 39
- EL3RST = 40
- ELNRNG = 41
- EUNATCH = 42
- ENOCSI = 43
- EL2HLT = 44
- EDEADLK = 45
- ENOLCK = 46
- EBADE = 50
- EBADR = 51
- EXFULL = 52
- ENOANO = 53
- EBADRQC = 54
- EBADSLT = 55
- EBFONT = 57
- ENOSTR = 60
- ENODATA = 61
- ETIME = 62
- ENOSR = 63
- ENONET = 64
- ENOPKG = 65
- EREMOTE = 66
- ENOLINK = 67
- EADV = 68
- ESRMNT = 69
- ECOMM = 70
- EPROTO = 71
- EMULTIHOP = 74
- ELBIN = 75
- EDOTDOT = 76
- EBADMSG = 77
- EFTYPE = 79
- ENOTUNIQ = 80
- EBADFD = 81
- EREMCHG = 82
- ELIBACC = 83
- ELIBBAD = 84
- ELIBSCN = 85
- ELIBMAX = 86
- ELIBEXEC = 87
- ENMFILE = 89
- ENOTEMPTY = 90
- ELOOP = 92
- EOPNOTSUPP = 95
- EPFNOSUPPORT = 96
- ECONNRESET = 104
- ENOBUFS = 105
- EAFNOSUPPORT = 106
- EPROTOTYPE = 107
- ENOTSOCK = 108
- ENOPROTOOPT = 109
- ESHUTDOWN = 110
- ECONNREFUSED = 111
- EADDRINUSE = 112
- ECONNABORTED = 113
- ENETUNREACH = 114
- ENETDOWN = 115
- ETIMEDOUT = 116
- EHOSTDOWN = 117
- EHOSTUNREACH = 118
- EINPROGRESS = 119
- EALREADY = 120
- EDESTADDRREQ = 121
- EPROTONOSUPPORT = 123
- ESOCKTNOSUPPORT = 124
- EADDRNOTAVAIL = 125
- ENETRESET = 126
- EISCONN = 127
- ENOTCONN = 128
- ETOOMANYREFS = 129
- EPROCLIM = 130
- EUSERS = 131
- ESTALE = 133
- ENOMEDIUM = 135
- ENOSHARE = 136
- ECASECLASH = 137
- EILSEQ = 138
- EOVERFLOW = 139
- ECANCELED = 140
- EL2NSYNC = 88
- EIDRM = 91
- EMSGSIZE = 132
- ENACL = 99 /* otherwise unused */
-)
-
-
-// Error table
-var errors = [...]string{
- EPERM: "operation not permitted",
- ENOENT: "no such file or directory",
- ESRCH: "no such process",
- EINTR: "interrupted system call",
- EIO: "I/O error",
- ENXIO: "no such device or address",
- E2BIG: "argument list too long",
- ENOEXEC: "exec format error",
- EBADF: "bad file number",
- ECHILD: "no child processes",
- EAGAIN: "try again",
- ENOMEM: "out of memory",
- EACCES: "permission denied",
- EFAULT: "bad address",
- EBUSY: "device or resource busy",
- EEXIST: "file exists",
- EXDEV: "cross-device link",
- ENODEV: "no such device",
- ENOTDIR: "not a directory",
- EISDIR: "is a directory",
- EINVAL: "invalid argument",
- ENFILE: "file table overflow",
- EMFILE: "too many open files",
- ENOTTY: "not a typewriter",
- EFBIG: "file too large",
- ENOSPC: "no space left on device",
- ESPIPE: "illegal seek",
- EROFS: "read-only file system",
- EMLINK: "too many links",
- EPIPE: "broken pipe",
- ENAMETOOLONG: "file name too long",
- ENOSYS: "function not implemented",
- EDQUOT: "quota exceeded",
- EDOM: "math arg out of domain of func",
- ERANGE: "math result not representable",
- ENOMSG: "no message of desired type",
- ECHRNG: "channel number out of range",
- EL3HLT: "level 3 halted",
- EL3RST: "level 3 reset",
- ELNRNG: "link number out of range",
- EUNATCH: "protocol driver not attached",
- ENOCSI: "no CSI structure available",
- EL2HLT: "level 2 halted",
- EDEADLK: "deadlock condition",
- ENOLCK: "no record locks available",
- EBADE: "invalid exchange",
- EBADR: "invalid request descriptor",
- EXFULL: "exchange full",
- ENOANO: "no anode",
- EBADRQC: "invalid request code",
- EBADSLT: "invalid slot",
- EBFONT: "bad font file fmt",
- ENOSTR: "device not a stream",
- ENODATA: "no data (for no delay io)",
- ETIME: "timer expired",
- ENOSR: "out of streams resources",
- ENONET: "machine is not on the network",
- ENOPKG: "package not installed",
- EREMOTE: "the object is remote",
- ENOLINK: "the link has been severed",
- EADV: "advertise error",
- ESRMNT: "srmount error",
- ECOMM: "communication error on send",
- EPROTO: "protocol error",
- EMULTIHOP: "multihop attempted",
- ELBIN: "inode is remote (not really error)",
- EDOTDOT: "cross mount point (not really error)",
- EBADMSG: "trying to read unreadable message",
- EFTYPE: "inappropriate file type or format",
- ENOTUNIQ: "given log. name not unique",
- EBADFD: "f.d. invalid for this operation",
- EREMCHG: "remote address changed",
- ELIBACC: "can't access a needed shared lib",
- ELIBBAD: "accessing a corrupted shared lib",
- ELIBSCN: ".lib section in a.out corrupted",
- ELIBMAX: "attempting to link in too many libs",
- ELIBEXEC: "attempting to exec a shared library",
- ENMFILE: "no more files",
- ENOTEMPTY: "directory not empty",
- ELOOP: "too many symbolic links",
- EOPNOTSUPP: "operation not supported on transport endpoint",
- EPFNOSUPPORT: "protocol family not supported",
- ECONNRESET: "connection reset by peer",
- ENOBUFS: "no buffer space available",
- EAFNOSUPPORT: "address family not supported by protocol family",
- EPROTOTYPE: "protocol wrong type for socket",
- ENOTSOCK: "socket operation on non-socket",
- ENOPROTOOPT: "protocol not available",
- ESHUTDOWN: "can't send after socket shutdown",
- ECONNREFUSED: "connection refused",
- EADDRINUSE: "address already in use",
- ECONNABORTED: "connection aborted",
- ENETUNREACH: "network is unreachable",
- ENETDOWN: "network interface is not configured",
- ETIMEDOUT: "connection timed out",
- EHOSTDOWN: "host is down",
- EHOSTUNREACH: "host is unreachable",
- EINPROGRESS: "connection already in progress",
- EALREADY: "socket already connected",
- EDESTADDRREQ: "destination address required",
- EPROTONOSUPPORT: "unknown protocol",
- ESOCKTNOSUPPORT: "socket type not supported",
- EADDRNOTAVAIL: "address not available",
- EISCONN: "socket is already connected",
- ENOTCONN: "socket is not connected",
- ENOMEDIUM: "no medium (in tape drive)",
- ENOSHARE: "no such host or network path",
- ECASECLASH: "filename exists with different case",
- EOVERFLOW: "value too large for defined data type",
- ECANCELED: "operation canceled.",
- EL2NSYNC: "level 2 not synchronized",
- EIDRM: "identifier removed",
- EMSGSIZE: "message too long",
- ENACL: "not supported by native client",
-}
diff --git a/src/pkg/syscall/zerrors_windows_386.go b/src/pkg/syscall/zerrors_windows_386.go
index 4f3a5811b..a6bed6ea6 100644
--- a/src/pkg/syscall/zerrors_windows_386.go
+++ b/src/pkg/syscall/zerrors_windows_386.go
@@ -1,144 +1,280 @@
-// mkerrors_nacl.sh /home/rsc/pub/nacl/native_client/src/trusted/service_runtime/include/sys/errno.h
+// mkerrors_windows.sh -f -m32
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
package syscall
-// TODO(brainman): populate errors in zerrors_windows.go
-
+// Go names for Windows errors.
const (
- ERROR_FILE_NOT_FOUND = 2
- ERROR_NO_MORE_FILES = 18
- ERROR_BROKEN_PIPE = 109
- ERROR_INSUFFICIENT_BUFFER = 122
- ERROR_MOD_NOT_FOUND = 126
- ERROR_PROC_NOT_FOUND = 127
- ERROR_DIRECTORY = 267
- ERROR_IO_PENDING = 997
- // TODO(brainman): should use value for EWINDOWS that does not clashes with anything else
- EWINDOWS = 99999 /* otherwise unused */
+ ENOENT = ERROR_FILE_NOT_FOUND
+ ENOTDIR = ERROR_DIRECTORY
)
-// TODO(brainman): fix all needed for os
+// Windows reserves errors >= 1<<29 for application use.
+const APPLICATION_ERROR = 1 << 29
+// Invented values to support what package os and others expects.
const (
- EPERM = 1
- ENOENT = 2
- ESRCH = 3
- EINTR = 4
- EIO = 5
- ENXIO = 6
- E2BIG = 7
- ENOEXEC = 8
- EBADF = 9
- ECHILD = 10
- EAGAIN = 11
- ENOMEM = 12
- EACCES = 13
- EFAULT = 14
- EBUSY = 16
- EEXIST = 17
- EXDEV = 18
- ENODEV = 19
- ENOTDIR = ERROR_DIRECTORY
- EISDIR = 21
- EINVAL = 22
- ENFILE = 23
- EMFILE = 24
- ENOTTY = 25
- EFBIG = 27
- ENOSPC = 28
- ESPIPE = 29
- EROFS = 30
- EMLINK = 31
- EPIPE = 32
- ENAMETOOLONG = 36
- ENOSYS = 38
- EDQUOT = 122
- EDOM = 33
- ERANGE = 34
- ENOMSG = 35
- ECHRNG = 37
- EL3HLT = 39
- EL3RST = 40
- ELNRNG = 41
- EUNATCH = 42
- ENOCSI = 43
- EL2HLT = 44
- EDEADLK = 45
- ENOLCK = 46
- EBADE = 50
- EBADR = 51
- EXFULL = 52
- ENOANO = 53
- EBADRQC = 54
- EBADSLT = 55
- EBFONT = 57
- ENOSTR = 60
- ENODATA = 61
- ETIME = 62
- ENOSR = 63
- ENONET = 64
- ENOPKG = 65
- EREMOTE = 66
- ENOLINK = 67
- EADV = 68
- ESRMNT = 69
- ECOMM = 70
- EPROTO = 71
- EMULTIHOP = 74
- ELBIN = 75
- EDOTDOT = 76
- EBADMSG = 77
- EFTYPE = 79
- ENOTUNIQ = 80
- EBADFD = 81
- EREMCHG = 82
- ELIBACC = 83
- ELIBBAD = 84
- ELIBSCN = 85
- ELIBMAX = 86
- ELIBEXEC = 87
- ENMFILE = 89
- ENOTEMPTY = 90
- ELOOP = 92
- EOPNOTSUPP = 95
- EPFNOSUPPORT = 96
- ECONNRESET = 104
- ENOBUFS = 105
- EAFNOSUPPORT = 106
- EPROTOTYPE = 107
- ENOTSOCK = 108
- ENOPROTOOPT = 109
- ESHUTDOWN = 110
- ECONNREFUSED = 111
- EADDRINUSE = 112
- ECONNABORTED = 113
- ENETUNREACH = 114
- ENETDOWN = 115
- ETIMEDOUT = 116
- EHOSTDOWN = 117
- EHOSTUNREACH = 118
- EINPROGRESS = 119
- EALREADY = 120
- EDESTADDRREQ = 121
- EPROTONOSUPPORT = 123
- ESOCKTNOSUPPORT = 124
- EADDRNOTAVAIL = 125
- ENETRESET = 126
- EISCONN = 127
- ENOTCONN = 128
- ETOOMANYREFS = 129
- EPROCLIM = 130
- EUSERS = 131
- EWOULDBLOCK = 141
- ESTALE = 133
- ENOMEDIUM = 135
- ENOSHARE = 136
- ECASECLASH = 137
- EILSEQ = 138
- EOVERFLOW = 139
- ECANCELED = 140
- EL2NSYNC = 88
- EIDRM = 91
- EMSGSIZE = 132
+ E2BIG = APPLICATION_ERROR + iota
+ EACCES
+ EADDRINUSE
+ EADDRNOTAVAIL
+ EADV
+ EAFNOSUPPORT
+ EAGAIN
+ EALREADY
+ EBADE
+ EBADF
+ EBADFD
+ EBADMSG
+ EBADR
+ EBADRQC
+ EBADSLT
+ EBFONT
+ EBUSY
+ ECANCELED
+ ECHILD
+ ECHRNG
+ ECOMM
+ ECONNABORTED
+ ECONNREFUSED
+ ECONNRESET
+ EDEADLK
+ EDEADLOCK
+ EDESTADDRREQ
+ EDOM
+ EDOTDOT
+ EDQUOT
+ EEXIST
+ EFAULT
+ EFBIG
+ EHOSTDOWN
+ EHOSTUNREACH
+ EIDRM
+ EILSEQ
+ EINPROGRESS
+ EINTR
+ EINVAL
+ EIO
+ EISCONN
+ EISDIR
+ EISNAM
+ EKEYEXPIRED
+ EKEYREJECTED
+ EKEYREVOKED
+ EL2HLT
+ EL2NSYNC
+ EL3HLT
+ EL3RST
+ ELIBACC
+ ELIBBAD
+ ELIBEXEC
+ ELIBMAX
+ ELIBSCN
+ ELNRNG
+ ELOOP
+ EMEDIUMTYPE
+ EMFILE
+ EMLINK
+ EMSGSIZE
+ EMULTIHOP
+ ENAMETOOLONG
+ ENAVAIL
+ ENETDOWN
+ ENETRESET
+ ENETUNREACH
+ ENFILE
+ ENOANO
+ ENOBUFS
+ ENOCSI
+ ENODATA
+ ENODEV
+ ENOEXEC
+ ENOKEY
+ ENOLCK
+ ENOLINK
+ ENOMEDIUM
+ ENOMEM
+ ENOMSG
+ ENONET
+ ENOPKG
+ ENOPROTOOPT
+ ENOSPC
+ ENOSR
+ ENOSTR
+ ENOSYS
+ ENOTBLK
+ ENOTCONN
+ ENOTEMPTY
+ ENOTNAM
+ ENOTRECOVERABLE
+ ENOTSOCK
+ ENOTSUP
+ ENOTTY
+ ENOTUNIQ
+ ENXIO
+ EOPNOTSUPP
+ EOVERFLOW
+ EOWNERDEAD
+ EPERM
+ EPFNOSUPPORT
+ EPIPE
+ EPROTO
+ EPROTONOSUPPORT
+ EPROTOTYPE
+ ERANGE
+ EREMCHG
+ EREMOTE
+ EREMOTEIO
+ ERESTART
+ EROFS
+ ESHUTDOWN
+ ESOCKTNOSUPPORT
+ ESPIPE
+ ESRCH
+ ESRMNT
+ ESTALE
+ ESTRPIPE
+ ETIME
+ ETIMEDOUT
+ ETOOMANYREFS
+ ETXTBSY
+ EUCLEAN
+ EUNATCH
+ EUSERS
+ EWOULDBLOCK
+ EXDEV
+ EXFULL
+ EWINDOWS
)
+
+// Error strings for invented errors
+var errors = [...]string{
+ E2BIG - APPLICATION_ERROR: "argument list too long",
+ EACCES - APPLICATION_ERROR: "permission denied",
+ EADDRINUSE - APPLICATION_ERROR: "address already in use",
+ EADDRNOTAVAIL - APPLICATION_ERROR: "cannot assign requested address",
+ EADV - APPLICATION_ERROR: "advertise error",
+ EAFNOSUPPORT - APPLICATION_ERROR: "address family not supported by protocol",
+ EAGAIN - APPLICATION_ERROR: "resource temporarily unavailable",
+ EALREADY - APPLICATION_ERROR: "operation already in progress",
+ EBADE - APPLICATION_ERROR: "invalid exchange",
+ EBADF - APPLICATION_ERROR: "bad file descriptor",
+ EBADFD - APPLICATION_ERROR: "file descriptor in bad state",
+ EBADMSG - APPLICATION_ERROR: "bad message",
+ EBADR - APPLICATION_ERROR: "invalid request descriptor",
+ EBADRQC - APPLICATION_ERROR: "invalid request code",
+ EBADSLT - APPLICATION_ERROR: "invalid slot",
+ EBFONT - APPLICATION_ERROR: "bad font file format",
+ EBUSY - APPLICATION_ERROR: "device or resource busy",
+ ECANCELED - APPLICATION_ERROR: "operation canceled",
+ ECHILD - APPLICATION_ERROR: "no child processes",
+ ECHRNG - APPLICATION_ERROR: "channel number out of range",
+ ECOMM - APPLICATION_ERROR: "communication error on send",
+ ECONNABORTED - APPLICATION_ERROR: "software caused connection abort",
+ ECONNREFUSED - APPLICATION_ERROR: "connection refused",
+ ECONNRESET - APPLICATION_ERROR: "connection reset by peer",
+ EDEADLK - APPLICATION_ERROR: "resource deadlock avoided",
+ EDESTADDRREQ - APPLICATION_ERROR: "destination address required",
+ EDOM - APPLICATION_ERROR: "numerical argument out of domain",
+ EDOTDOT - APPLICATION_ERROR: "RFS specific error",
+ EDQUOT - APPLICATION_ERROR: "disk quota exceeded",
+ EEXIST - APPLICATION_ERROR: "file exists",
+ EFAULT - APPLICATION_ERROR: "bad address",
+ EFBIG - APPLICATION_ERROR: "file too large",
+ EHOSTDOWN - APPLICATION_ERROR: "host is down",
+ EHOSTUNREACH - APPLICATION_ERROR: "no route to host",
+ EIDRM - APPLICATION_ERROR: "identifier removed",
+ EILSEQ - APPLICATION_ERROR: "invalid or incomplete multibyte or wide character",
+ EINPROGRESS - APPLICATION_ERROR: "operation now in progress",
+ EINTR - APPLICATION_ERROR: "interrupted system call",
+ EINVAL - APPLICATION_ERROR: "invalid argument",
+ EIO - APPLICATION_ERROR: "input/output error",
+ EISCONN - APPLICATION_ERROR: "transport endpoint is already connected",
+ EISDIR - APPLICATION_ERROR: "is a directory",
+ EISNAM - APPLICATION_ERROR: "is a named type file",
+ EKEYEXPIRED - APPLICATION_ERROR: "key has expired",
+ EKEYREJECTED - APPLICATION_ERROR: "key was rejected by service",
+ EKEYREVOKED - APPLICATION_ERROR: "key has been revoked",
+ EL2HLT - APPLICATION_ERROR: "level 2 halted",
+ EL2NSYNC - APPLICATION_ERROR: "level 2 not synchronized",
+ EL3HLT - APPLICATION_ERROR: "level 3 halted",
+ EL3RST - APPLICATION_ERROR: "level 3 reset",
+ ELIBACC - APPLICATION_ERROR: "can not access a needed shared library",
+ ELIBBAD - APPLICATION_ERROR: "accessing a corrupted shared library",
+ ELIBEXEC - APPLICATION_ERROR: "cannot exec a shared library directly",
+ ELIBMAX - APPLICATION_ERROR: "attempting to link in too many shared libraries",
+ ELIBSCN - APPLICATION_ERROR: ".lib section in a.out corrupted",
+ ELNRNG - APPLICATION_ERROR: "link number out of range",
+ ELOOP - APPLICATION_ERROR: "too many levels of symbolic links",
+ EMEDIUMTYPE - APPLICATION_ERROR: "wrong medium type",
+ EMFILE - APPLICATION_ERROR: "too many open files",
+ EMLINK - APPLICATION_ERROR: "too many links",
+ EMSGSIZE - APPLICATION_ERROR: "message too long",
+ EMULTIHOP - APPLICATION_ERROR: "multihop attempted",
+ ENAMETOOLONG - APPLICATION_ERROR: "file name too long",
+ ENAVAIL - APPLICATION_ERROR: "no XENIX semaphores available",
+ ENETDOWN - APPLICATION_ERROR: "network is down",
+ ENETRESET - APPLICATION_ERROR: "network dropped connection on reset",
+ ENETUNREACH - APPLICATION_ERROR: "network is unreachable",
+ ENFILE - APPLICATION_ERROR: "too many open files in system",
+ ENOANO - APPLICATION_ERROR: "no anode",
+ ENOBUFS - APPLICATION_ERROR: "no buffer space available",
+ ENOCSI - APPLICATION_ERROR: "no CSI structure available",
+ ENODATA - APPLICATION_ERROR: "no data available",
+ ENODEV - APPLICATION_ERROR: "no such device",
+ ENOEXEC - APPLICATION_ERROR: "exec format error",
+ ENOKEY - APPLICATION_ERROR: "required key not available",
+ ENOLCK - APPLICATION_ERROR: "no locks available",
+ ENOLINK - APPLICATION_ERROR: "link has been severed",
+ ENOMEDIUM - APPLICATION_ERROR: "no medium found",
+ ENOMEM - APPLICATION_ERROR: "cannot allocate memory",
+ ENOMSG - APPLICATION_ERROR: "no message of desired type",
+ ENONET - APPLICATION_ERROR: "machine is not on the network",
+ ENOPKG - APPLICATION_ERROR: "package not installed",
+ ENOPROTOOPT - APPLICATION_ERROR: "protocol not available",
+ ENOSPC - APPLICATION_ERROR: "no space left on device",
+ ENOSR - APPLICATION_ERROR: "out of streams resources",
+ ENOSTR - APPLICATION_ERROR: "device not a stream",
+ ENOSYS - APPLICATION_ERROR: "function not implemented",
+ ENOTBLK - APPLICATION_ERROR: "block device required",
+ ENOTCONN - APPLICATION_ERROR: "transport endpoint is not connected",
+ ENOTEMPTY - APPLICATION_ERROR: "directory not empty",
+ ENOTNAM - APPLICATION_ERROR: "not a XENIX named type file",
+ ENOTRECOVERABLE - APPLICATION_ERROR: "state not recoverable",
+ ENOTSOCK - APPLICATION_ERROR: "socket operation on non-socket",
+ ENOTSUP - APPLICATION_ERROR: "operation not supported",
+ ENOTTY - APPLICATION_ERROR: "inappropriate ioctl for device",
+ ENOTUNIQ - APPLICATION_ERROR: "name not unique on network",
+ ENXIO - APPLICATION_ERROR: "no such device or address",
+ EOVERFLOW - APPLICATION_ERROR: "value too large for defined data type",
+ EOWNERDEAD - APPLICATION_ERROR: "owner died",
+ EPERM - APPLICATION_ERROR: "operation not permitted",
+ EPFNOSUPPORT - APPLICATION_ERROR: "protocol family not supported",
+ EPIPE - APPLICATION_ERROR: "broken pipe",
+ EPROTO - APPLICATION_ERROR: "protocol error",
+ EPROTONOSUPPORT - APPLICATION_ERROR: "protocol not supported",
+ EPROTOTYPE - APPLICATION_ERROR: "protocol wrong type for socket",
+ ERANGE - APPLICATION_ERROR: "numerical result out of range",
+ EREMCHG - APPLICATION_ERROR: "remote address changed",
+ EREMOTE - APPLICATION_ERROR: "object is remote",
+ EREMOTEIO - APPLICATION_ERROR: "remote I/O error",
+ ERESTART - APPLICATION_ERROR: "interrupted system call should be restarted",
+ EROFS - APPLICATION_ERROR: "read-only file system",
+ ESHUTDOWN - APPLICATION_ERROR: "cannot send after transport endpoint shutdown",
+ ESOCKTNOSUPPORT - APPLICATION_ERROR: "socket type not supported",
+ ESPIPE - APPLICATION_ERROR: "illegal seek",
+ ESRCH - APPLICATION_ERROR: "no such process",
+ ESRMNT - APPLICATION_ERROR: "srmount error",
+ ESTALE - APPLICATION_ERROR: "stale NFS file handle",
+ ESTRPIPE - APPLICATION_ERROR: "streams pipe error",
+ ETIME - APPLICATION_ERROR: "timer expired",
+ ETIMEDOUT - APPLICATION_ERROR: "connection timed out",
+ ETOOMANYREFS - APPLICATION_ERROR: "too many references: cannot splice",
+ ETXTBSY - APPLICATION_ERROR: "text file busy",
+ EUCLEAN - APPLICATION_ERROR: "structure needs cleaning",
+ EUNATCH - APPLICATION_ERROR: "protocol driver not attached",
+ EUSERS - APPLICATION_ERROR: "too many users",
+ EXDEV - APPLICATION_ERROR: "invalid cross-device link",
+ EXFULL - APPLICATION_ERROR: "exchange full",
+ EWINDOWS - APPLICATION_ERROR: "not supported by windows",
+}
diff --git a/src/pkg/syscall/zsyscall_darwin_386.go b/src/pkg/syscall/zsyscall_darwin_386.go
index 78e21ca44..9718e5def 100644
--- a/src/pkg/syscall/zsyscall_darwin_386.go
+++ b/src/pkg/syscall/zsyscall_darwin_386.go
@@ -5,6 +5,8 @@ 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, errno int) {
r0, _, e1 := Syscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
n = int(r0)
@@ -12,12 +14,16 @@ func getgroups(ngid int, gid *_Gid_t) (n int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func setgroups(ngid int, gid *_Gid_t) (errno int) {
_, _, e1 := Syscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
errno = int(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) {
r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
wpid = int(r0)
@@ -25,6 +31,8 @@ func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func pipe() (r int, w int, errno int) {
r0, r1, e1 := Syscall(SYS_PIPE, 0, 0, 0)
r = int(r0)
@@ -33,6 +41,8 @@ func pipe() (r int, w int, errno int) {
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) {
r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
fd = int(r0)
@@ -40,18 +50,24 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func bind(s int, addr uintptr, addrlen _Socklen) (errno int) {
_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
errno = int(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) {
_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
errno = int(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) {
r0, _, e1 := Syscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
fd = int(r0)
@@ -59,14 +75,7 @@ func socket(domain int, typ int, proto int) (fd int, errno int) {
return
}
-func socketpair(domain int, typ int, proto int) (fd [2]int, errno int) {
- var f [2]int
- _, _, e1 := Syscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(&f)), 0, 0)
- fd = f
- errno = int(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 int) (errno int) {
_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
@@ -74,45 +83,65 @@ func setsockopt(s int, level int, name int, val uintptr, vallen int) (errno int)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int) {
_, _, e1 := Syscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
errno = int(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) {
_, _, e1 := Syscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Shutdown(s int, how int) (errno int) {
_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0)
errno = int(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) {
+ _, _, e1 := Syscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
+ errno = int(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) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(p) > 0 {
- _p0 = &p[0]
+ _p0 = unsafe.Pointer(&p[0])
}
- r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
+ 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)
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) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(buf) > 0 {
- _p0 = &buf[0]
+ _p0 = unsafe.Pointer(&buf[0])
}
- _, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
+ _, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, errno int) {
r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
n = int(r0)
@@ -120,28 +149,36 @@ func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, time
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) {
- var _p0 *_C_int
+ var _p0 unsafe.Pointer
if len(mib) > 0 {
- _p0 = &mib[0]
+ _p0 = unsafe.Pointer(&mib[0])
}
- _, _, e1 := Syscall6(SYS___SYSCTL, uintptr(unsafe.Pointer(_p0)), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
+ _, _, 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)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func utimes(path string, timeval *[2]Timeval) (errno int) {
_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(timeval)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func futimes(fd int, timeval *[2]Timeval) (errno int) {
_, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0)
errno = int(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) {
r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
val = int(r0)
@@ -149,60 +186,80 @@ func fcntl(fd int, cmd int, arg int) (val int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func kill(pid int, signum int, posix int) (errno int) {
_, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), uintptr(posix))
errno = int(e1)
return
}
-func Access(path string, flags int) (errno int) {
- _, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), 0)
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Access(path string, mode uint32) (errno int) {
+ _, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Adjtime(delta *Timeval, olddelta *Timeval) (errno int) {
_, _, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Chdir(path string) (errno int) {
_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Chflags(path string, flags int) (errno int) {
_, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), 0)
errno = int(e1)
return
}
-func Chmod(path string, mode int) (errno int) {
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chmod(path string, mode uint32) (errno int) {
_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
errno = int(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) {
_, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid))
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Chroot(path string) (errno int) {
_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Close(fd int) (errno int) {
_, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Dup(fd int) (nfd int, errno int) {
r0, _, e1 := Syscall(SYS_DUP, uintptr(fd), 0, 0)
nfd = int(r0)
@@ -210,53 +267,71 @@ func Dup(fd int) (nfd int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Dup2(from int, to int) (errno int) {
_, _, e1 := Syscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
errno = int(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) {
_, _, e1 := Syscall(SYS_EXCHANGEDATA, uintptr(unsafe.Pointer(StringBytePtr(path1))), uintptr(unsafe.Pointer(StringBytePtr(path2))), uintptr(options))
errno = int(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) (errno int) {
_, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Fchflags(path string, flags int) (errno int) {
_, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), 0)
errno = int(e1)
return
}
-func Fchmod(fd int, mode int) (errno int) {
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchmod(fd int, mode uint32) (errno int) {
_, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
errno = int(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) {
_, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Flock(fd int, how int) (errno int) {
_, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
errno = int(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) {
r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0)
val = int(r0)
@@ -264,76 +339,98 @@ func Fpathconf(fd int, name int) (val int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Fstat(fd int, stat *Stat_t) (errno int) {
_, _, e1 := Syscall(SYS_FSTAT64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Fstatfs(fd int, stat *Statfs_t) (errno int) {
_, _, e1 := Syscall(SYS_FSTATFS64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Fsync(fd int) (errno int) {
_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Ftruncate(fd int, length int64) (errno int) {
_, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), uintptr(length), uintptr(length>>32))
errno = int(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) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(buf) > 0 {
- _p0 = &buf[0]
+ _p0 = unsafe.Pointer(&buf[0])
}
- r0, _, e1 := Syscall6(SYS_GETDIRENTRIES64, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
+ r0, _, e1 := Syscall6(SYS_GETDIRENTRIES64, uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
n = int(r0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getdtablesize() (size int) {
r0, _, _ := Syscall(SYS_GETDTABLESIZE, 0, 0, 0)
size = int(r0)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getegid() (egid int) {
r0, _, _ := Syscall(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, _, _ := Syscall(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, errno int) {
- var _p0 *Statfs_t
+ var _p0 unsafe.Pointer
if len(buf) > 0 {
- _p0 = &buf[0]
+ _p0 = unsafe.Pointer(&buf[0])
}
- r0, _, e1 := Syscall(SYS_GETFSSTAT64, uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(flags))
+ r0, _, e1 := Syscall(SYS_GETFSSTAT64, uintptr(_p0), uintptr(len(buf)), uintptr(flags))
n = int(r0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getgid() (gid int) {
r0, _, _ := Syscall(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, errno int) {
r0, _, e1 := Syscall(SYS_GETPGID, uintptr(pid), 0, 0)
pgid = int(r0)
@@ -341,24 +438,32 @@ func Getpgid(pid int) (pgid int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getpgrp() (pgrp int) {
r0, _, _ := Syscall(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, _, _ := Syscall(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, _, _ := Syscall(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, errno int) {
r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
prio = int(r0)
@@ -366,18 +471,24 @@ func Getpriority(which int, who int) (prio int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getrlimit(which int, lim *Rlimit) (errno int) {
_, _, e1 := Syscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getrusage(who int, rusage *Rusage) (errno int) {
_, _, e1 := Syscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getsid(pid int) (sid int, errno int) {
r0, _, e1 := Syscall(SYS_GETSID, uintptr(pid), 0, 0)
sid = int(r0)
@@ -385,18 +496,24 @@ func Getsid(pid int) (sid int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getuid() (uid int) {
r0, _, _ := Syscall(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 Kqueue() (fd int, errno int) {
r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0)
fd = int(r0)
@@ -404,55 +521,73 @@ func Kqueue() (fd int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Lchown(path string, uid int, gid int) (errno int) {
_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid))
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Link(path string, link string) (errno int) {
_, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(StringBytePtr(link))), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Listen(s int, backlog int) (errno int) {
_, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Lstat(path string, stat *Stat_t) (errno int) {
_, _, e1 := Syscall(SYS_LSTAT64, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0)
errno = int(e1)
return
}
-func Mkdir(path string, mode int) (errno int) {
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mkdir(path string, mode uint32) (errno int) {
_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
errno = int(e1)
return
}
-func Mkfifo(path string, mode int) (errno int) {
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mkfifo(path string, mode uint32) (errno int) {
_, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
errno = int(e1)
return
}
-func Mknod(path string, mode int, dev int) (errno int) {
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mknod(path string, mode uint32, dev int) (errno int) {
_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(dev))
errno = int(e1)
return
}
-func Open(path string, mode int, perm int) (fd int, errno int) {
+// 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) {
r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(perm))
fd = int(r0)
errno = int(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) {
r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(name), 0)
val = int(r0)
@@ -460,68 +595,84 @@ func Pathconf(path string, name int) (val int, errno int) {
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) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(p) > 0 {
- _p0 = &p[0]
+ _p0 = unsafe.Pointer(&p[0])
}
- r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
+ r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
n = int(r0)
errno = int(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) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(p) > 0 {
- _p0 = &p[0]
+ _p0 = unsafe.Pointer(&p[0])
}
- r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
+ r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
n = int(r0)
errno = int(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) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(p) > 0 {
- _p0 = &p[0]
+ _p0 = unsafe.Pointer(&p[0])
}
- r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)))
+ r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
n = int(r0)
errno = int(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) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(buf) > 0 {
- _p0 = &buf[0]
+ _p0 = unsafe.Pointer(&buf[0])
}
- r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)))
+ r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(_p0), uintptr(len(buf)))
n = int(r0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Rename(from string, to string) (errno int) {
_, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(StringBytePtr(from))), uintptr(unsafe.Pointer(StringBytePtr(to))), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Revoke(path string) (errno int) {
_, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Rmdir(path string) (errno int) {
_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
errno = int(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) {
r0, r1, e1 := Syscall6(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(offset>>32), uintptr(whence), 0, 0)
newoffset = int64(int64(r1)<<32 | int64(r0))
@@ -529,72 +680,96 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, errno int) {
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) {
_, _, 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)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setegid(egid int) (errno int) {
_, _, e1 := Syscall(SYS_SETEGID, uintptr(egid), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Seteuid(euid int) (errno int) {
_, _, e1 := Syscall(SYS_SETEUID, uintptr(euid), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setgid(gid int) (errno int) {
_, _, e1 := Syscall(SYS_SETGID, uintptr(gid), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setlogin(name string) (errno int) {
_, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(StringBytePtr(name))), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setpgid(pid int, pgid int) (errno int) {
_, _, e1 := Syscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
errno = int(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) {
_, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio))
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setprivexec(flag int) (errno int) {
_, _, e1 := Syscall(SYS_SETPRIVEXEC, uintptr(flag), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setregid(rgid int, egid int) (errno int) {
_, _, e1 := Syscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setreuid(ruid int, euid int) (errno int) {
_, _, e1 := Syscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setrlimit(which int, lim *Rlimit) (errno int) {
_, _, e1 := Syscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setsid() (pid int, errno int) {
r0, _, e1 := Syscall(SYS_SETSID, 0, 0, 0)
pid = int(r0)
@@ -602,83 +777,109 @@ func Setsid() (pid int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Settimeofday(tp *Timeval) (errno int) {
_, _, e1 := Syscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setuid(uid int) (errno int) {
_, _, e1 := Syscall(SYS_SETUID, uintptr(uid), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Stat(path string, stat *Stat_t) (errno int) {
_, _, e1 := Syscall(SYS_STAT64, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Statfs(path string, stat *Statfs_t) (errno int) {
_, _, e1 := Syscall(SYS_STATFS64, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Symlink(path string, link string) (errno int) {
_, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(StringBytePtr(link))), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Sync() (errno int) {
_, _, e1 := Syscall(SYS_SYNC, 0, 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Truncate(path string, length int64) (errno int) {
_, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(length), uintptr(length>>32))
errno = int(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 Undelete(path string) (errno int) {
_, _, e1 := Syscall(SYS_UNDELETE, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Unlink(path string) (errno int) {
_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Unmount(path string, flags int) (errno int) {
_, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), 0)
errno = int(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) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(p) > 0 {
- _p0 = &p[0]
+ _p0 = unsafe.Pointer(&p[0])
}
- r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)))
+ r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
n = int(r0)
errno = int(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) {
r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
n = int(r0)
@@ -686,6 +887,8 @@ func read(fd int, buf *byte, nbuf int) (n int, errno int) {
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) {
r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
n = int(r0)
@@ -693,6 +896,8 @@ func write(fd int, buf *byte, nbuf int) (n int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func gettimeofday(tp *Timeval) (sec int32, usec int32, errno int) {
r0, r1, e1 := Syscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0)
sec = int32(r0)
diff --git a/src/pkg/syscall/zsyscall_darwin_amd64.go b/src/pkg/syscall/zsyscall_darwin_amd64.go
index 96a4bd0f0..6dca1987c 100644
--- a/src/pkg/syscall/zsyscall_darwin_amd64.go
+++ b/src/pkg/syscall/zsyscall_darwin_amd64.go
@@ -5,6 +5,8 @@ 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, errno int) {
r0, _, e1 := Syscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
n = int(r0)
@@ -12,12 +14,16 @@ func getgroups(ngid int, gid *_Gid_t) (n int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func setgroups(ngid int, gid *_Gid_t) (errno int) {
_, _, e1 := Syscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
errno = int(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) {
r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
wpid = int(r0)
@@ -25,6 +31,8 @@ func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func pipe() (r int, w int, errno int) {
r0, r1, e1 := Syscall(SYS_PIPE, 0, 0, 0)
r = int(r0)
@@ -33,6 +41,8 @@ func pipe() (r int, w int, errno int) {
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) {
r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
fd = int(r0)
@@ -40,18 +50,24 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func bind(s int, addr uintptr, addrlen _Socklen) (errno int) {
_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
errno = int(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) {
_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
errno = int(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) {
r0, _, e1 := Syscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
fd = int(r0)
@@ -59,13 +75,7 @@ func socket(domain int, typ int, proto int) (fd int, errno int) {
return
}
-func socketpair(domain int, typ int, proto int) (fd [2]int, errno int) {
- var f [2]int
- _, _, e1 := Syscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(&f)), 0, 0)
- fd = f
- errno = int(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 int) (errno int) {
_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
@@ -73,45 +83,65 @@ func setsockopt(s int, level int, name int, val uintptr, vallen int) (errno int)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int) {
_, _, e1 := Syscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
errno = int(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) {
_, _, e1 := Syscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Shutdown(s int, how int) (errno int) {
_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0)
errno = int(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) {
+ _, _, e1 := Syscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
+ errno = int(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) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(p) > 0 {
- _p0 = &p[0]
+ _p0 = unsafe.Pointer(&p[0])
}
- r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
+ 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)
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) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(buf) > 0 {
- _p0 = &buf[0]
+ _p0 = unsafe.Pointer(&buf[0])
}
- _, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
+ _, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, errno int) {
r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
n = int(r0)
@@ -119,28 +149,36 @@ func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, time
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) {
- var _p0 *_C_int
+ var _p0 unsafe.Pointer
if len(mib) > 0 {
- _p0 = &mib[0]
+ _p0 = unsafe.Pointer(&mib[0])
}
- _, _, e1 := Syscall6(SYS___SYSCTL, uintptr(unsafe.Pointer(_p0)), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
+ _, _, 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)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func utimes(path string, timeval *[2]Timeval) (errno int) {
_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(timeval)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func futimes(fd int, timeval *[2]Timeval) (errno int) {
_, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0)
errno = int(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) {
r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
val = int(r0)
@@ -148,60 +186,80 @@ func fcntl(fd int, cmd int, arg int) (val int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func kill(pid int, signum int, posix int) (errno int) {
_, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), uintptr(posix))
errno = int(e1)
return
}
-func Access(path string, flags int) (errno int) {
- _, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), 0)
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Access(path string, mode uint32) (errno int) {
+ _, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Adjtime(delta *Timeval, olddelta *Timeval) (errno int) {
_, _, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Chdir(path string) (errno int) {
_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Chflags(path string, flags int) (errno int) {
_, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), 0)
errno = int(e1)
return
}
-func Chmod(path string, mode int) (errno int) {
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chmod(path string, mode uint32) (errno int) {
_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
errno = int(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) {
_, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid))
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Chroot(path string) (errno int) {
_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Close(fd int) (errno int) {
_, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Dup(fd int) (nfd int, errno int) {
r0, _, e1 := Syscall(SYS_DUP, uintptr(fd), 0, 0)
nfd = int(r0)
@@ -209,53 +267,71 @@ func Dup(fd int) (nfd int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Dup2(from int, to int) (errno int) {
_, _, e1 := Syscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
errno = int(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) {
_, _, e1 := Syscall(SYS_EXCHANGEDATA, uintptr(unsafe.Pointer(StringBytePtr(path1))), uintptr(unsafe.Pointer(StringBytePtr(path2))), uintptr(options))
errno = int(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) (errno int) {
_, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Fchflags(path string, flags int) (errno int) {
_, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), 0)
errno = int(e1)
return
}
-func Fchmod(fd int, mode int) (errno int) {
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchmod(fd int, mode uint32) (errno int) {
_, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
errno = int(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) {
_, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Flock(fd int, how int) (errno int) {
_, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
errno = int(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) {
r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0)
val = int(r0)
@@ -263,76 +339,98 @@ func Fpathconf(fd int, name int) (val int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Fstat(fd int, stat *Stat_t) (errno int) {
_, _, e1 := Syscall(SYS_FSTAT64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Fstatfs(fd int, stat *Statfs_t) (errno int) {
_, _, e1 := Syscall(SYS_FSTATFS64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Fsync(fd int) (errno int) {
_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Ftruncate(fd int, length int64) (errno int) {
_, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), uintptr(length), 0)
errno = int(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) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(buf) > 0 {
- _p0 = &buf[0]
+ _p0 = unsafe.Pointer(&buf[0])
}
- r0, _, e1 := Syscall6(SYS_GETDIRENTRIES64, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
+ r0, _, e1 := Syscall6(SYS_GETDIRENTRIES64, uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
n = int(r0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getdtablesize() (size int) {
r0, _, _ := Syscall(SYS_GETDTABLESIZE, 0, 0, 0)
size = int(r0)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getegid() (egid int) {
r0, _, _ := Syscall(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, _, _ := Syscall(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, errno int) {
- var _p0 *Statfs_t
+ var _p0 unsafe.Pointer
if len(buf) > 0 {
- _p0 = &buf[0]
+ _p0 = unsafe.Pointer(&buf[0])
}
- r0, _, e1 := Syscall(SYS_GETFSSTAT64, uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(flags))
+ r0, _, e1 := Syscall(SYS_GETFSSTAT64, uintptr(_p0), uintptr(len(buf)), uintptr(flags))
n = int(r0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getgid() (gid int) {
r0, _, _ := Syscall(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, errno int) {
r0, _, e1 := Syscall(SYS_GETPGID, uintptr(pid), 0, 0)
pgid = int(r0)
@@ -340,24 +438,32 @@ func Getpgid(pid int) (pgid int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getpgrp() (pgrp int) {
r0, _, _ := Syscall(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, _, _ := Syscall(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, _, _ := Syscall(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, errno int) {
r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
prio = int(r0)
@@ -365,18 +471,24 @@ func Getpriority(which int, who int) (prio int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getrlimit(which int, lim *Rlimit) (errno int) {
_, _, e1 := Syscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getrusage(who int, rusage *Rusage) (errno int) {
_, _, e1 := Syscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getsid(pid int) (sid int, errno int) {
r0, _, e1 := Syscall(SYS_GETSID, uintptr(pid), 0, 0)
sid = int(r0)
@@ -384,18 +496,24 @@ func Getsid(pid int) (sid int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getuid() (uid int) {
r0, _, _ := Syscall(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 Kqueue() (fd int, errno int) {
r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0)
fd = int(r0)
@@ -403,55 +521,73 @@ func Kqueue() (fd int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Lchown(path string, uid int, gid int) (errno int) {
_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid))
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Link(path string, link string) (errno int) {
_, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(StringBytePtr(link))), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Listen(s int, backlog int) (errno int) {
_, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Lstat(path string, stat *Stat_t) (errno int) {
_, _, e1 := Syscall(SYS_LSTAT64, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0)
errno = int(e1)
return
}
-func Mkdir(path string, mode int) (errno int) {
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mkdir(path string, mode uint32) (errno int) {
_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
errno = int(e1)
return
}
-func Mkfifo(path string, mode int) (errno int) {
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mkfifo(path string, mode uint32) (errno int) {
_, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
errno = int(e1)
return
}
-func Mknod(path string, mode int, dev int) (errno int) {
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mknod(path string, mode uint32, dev int) (errno int) {
_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(dev))
errno = int(e1)
return
}
-func Open(path string, mode int, perm int) (fd int, errno int) {
+// 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) {
r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(perm))
fd = int(r0)
errno = int(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) {
r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(name), 0)
val = int(r0)
@@ -459,68 +595,84 @@ func Pathconf(path string, name int) (val int, errno int) {
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) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(p) > 0 {
- _p0 = &p[0]
+ _p0 = unsafe.Pointer(&p[0])
}
- r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(offset), 0, 0)
+ r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0)
n = int(r0)
errno = int(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) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(p) > 0 {
- _p0 = &p[0]
+ _p0 = unsafe.Pointer(&p[0])
}
- r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(offset), 0, 0)
+ r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0)
n = int(r0)
errno = int(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) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(p) > 0 {
- _p0 = &p[0]
+ _p0 = unsafe.Pointer(&p[0])
}
- r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)))
+ r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
n = int(r0)
errno = int(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) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(buf) > 0 {
- _p0 = &buf[0]
+ _p0 = unsafe.Pointer(&buf[0])
}
- r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)))
+ r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(_p0), uintptr(len(buf)))
n = int(r0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Rename(from string, to string) (errno int) {
_, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(StringBytePtr(from))), uintptr(unsafe.Pointer(StringBytePtr(to))), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Revoke(path string) (errno int) {
_, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Rmdir(path string) (errno int) {
_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
errno = int(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) {
r0, _, e1 := Syscall(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(whence))
newoffset = int64(r0)
@@ -528,72 +680,96 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, errno int) {
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) {
_, _, 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)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setegid(egid int) (errno int) {
_, _, e1 := Syscall(SYS_SETEGID, uintptr(egid), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Seteuid(euid int) (errno int) {
_, _, e1 := Syscall(SYS_SETEUID, uintptr(euid), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setgid(gid int) (errno int) {
_, _, e1 := Syscall(SYS_SETGID, uintptr(gid), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setlogin(name string) (errno int) {
_, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(StringBytePtr(name))), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setpgid(pid int, pgid int) (errno int) {
_, _, e1 := Syscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
errno = int(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) {
_, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio))
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setprivexec(flag int) (errno int) {
_, _, e1 := Syscall(SYS_SETPRIVEXEC, uintptr(flag), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setregid(rgid int, egid int) (errno int) {
_, _, e1 := Syscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setreuid(ruid int, euid int) (errno int) {
_, _, e1 := Syscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setrlimit(which int, lim *Rlimit) (errno int) {
_, _, e1 := Syscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setsid() (pid int, errno int) {
r0, _, e1 := Syscall(SYS_SETSID, 0, 0, 0)
pid = int(r0)
@@ -601,83 +777,109 @@ func Setsid() (pid int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Settimeofday(tp *Timeval) (errno int) {
_, _, e1 := Syscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setuid(uid int) (errno int) {
_, _, e1 := Syscall(SYS_SETUID, uintptr(uid), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Stat(path string, stat *Stat_t) (errno int) {
_, _, e1 := Syscall(SYS_STAT64, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Statfs(path string, stat *Statfs_t) (errno int) {
_, _, e1 := Syscall(SYS_STATFS64, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Symlink(path string, link string) (errno int) {
_, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(StringBytePtr(link))), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Sync() (errno int) {
_, _, e1 := Syscall(SYS_SYNC, 0, 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Truncate(path string, length int64) (errno int) {
_, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(length), 0)
errno = int(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 Undelete(path string) (errno int) {
_, _, e1 := Syscall(SYS_UNDELETE, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Unlink(path string) (errno int) {
_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Unmount(path string, flags int) (errno int) {
_, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), 0)
errno = int(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) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(p) > 0 {
- _p0 = &p[0]
+ _p0 = unsafe.Pointer(&p[0])
}
- r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)))
+ r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
n = int(r0)
errno = int(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) {
r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
n = int(r0)
@@ -685,6 +887,8 @@ func read(fd int, buf *byte, nbuf int) (n int, errno int) {
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) {
r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
n = int(r0)
@@ -692,6 +896,8 @@ func write(fd int, buf *byte, nbuf int) (n int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func gettimeofday(tp *Timeval) (sec int64, usec int32, errno int) {
r0, r1, e1 := Syscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0)
sec = int64(r0)
diff --git a/src/pkg/syscall/zsyscall_freebsd_386.go b/src/pkg/syscall/zsyscall_freebsd_386.go
index 611beacf6..627a9a24d 100644
--- a/src/pkg/syscall/zsyscall_freebsd_386.go
+++ b/src/pkg/syscall/zsyscall_freebsd_386.go
@@ -5,6 +5,8 @@ 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, errno int) {
r0, _, e1 := Syscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
n = int(r0)
@@ -12,12 +14,16 @@ func getgroups(ngid int, gid *_Gid_t) (n int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func setgroups(ngid int, gid *_Gid_t) (errno int) {
_, _, e1 := Syscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
errno = int(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) {
r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
wpid = int(r0)
@@ -25,6 +31,8 @@ func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func pipe() (r int, w int, errno int) {
r0, r1, e1 := Syscall(SYS_PIPE, 0, 0, 0)
r = int(r0)
@@ -33,6 +41,8 @@ func pipe() (r int, w int, errno int) {
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) {
r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
fd = int(r0)
@@ -40,18 +50,24 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func bind(s int, addr uintptr, addrlen _Socklen) (errno int) {
_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
errno = int(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) {
_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
errno = int(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) {
r0, _, e1 := Syscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
fd = int(r0)
@@ -59,13 +75,7 @@ func socket(domain int, typ int, proto int) (fd int, errno int) {
return
}
-func socketpair(domain int, typ int, proto int) (fd [2]int, errno int) {
- var f [2]int
- _, _, e1 := Syscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(&f)), 0, 0)
- fd = f
- errno = int(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 int) (errno int) {
_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
@@ -73,45 +83,65 @@ func setsockopt(s int, level int, name int, val uintptr, vallen int) (errno int)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int) {
_, _, e1 := Syscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
errno = int(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) {
_, _, e1 := Syscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Shutdown(s int, how int) (errno int) {
_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0)
errno = int(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) {
+ _, _, e1 := Syscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
+ errno = int(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) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(p) > 0 {
- _p0 = &p[0]
+ _p0 = unsafe.Pointer(&p[0])
}
- r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
+ 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)
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) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(buf) > 0 {
- _p0 = &buf[0]
+ _p0 = unsafe.Pointer(&buf[0])
}
- _, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
+ _, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, errno int) {
r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
n = int(r0)
@@ -119,28 +149,36 @@ func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, time
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) {
- var _p0 *_C_int
+ var _p0 unsafe.Pointer
if len(mib) > 0 {
- _p0 = &mib[0]
+ _p0 = unsafe.Pointer(&mib[0])
}
- _, _, e1 := Syscall6(SYS___SYSCTL, uintptr(unsafe.Pointer(_p0)), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
+ _, _, 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)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func utimes(path string, timeval *[2]Timeval) (errno int) {
_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(timeval)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func futimes(fd int, timeval *[2]Timeval) (errno int) {
_, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0)
errno = int(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) {
r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
val = int(r0)
@@ -148,54 +186,72 @@ func fcntl(fd int, cmd int, arg int) (val int, errno int) {
return
}
-func Access(path string, flags int) (errno int) {
- _, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), 0)
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Access(path string, mode uint32) (errno int) {
+ _, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Adjtime(delta *Timeval, olddelta *Timeval) (errno int) {
_, _, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Chdir(path string) (errno int) {
_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Chflags(path string, flags int) (errno int) {
_, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), 0)
errno = int(e1)
return
}
-func Chmod(path string, mode int) (errno int) {
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chmod(path string, mode uint32) (errno int) {
_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
errno = int(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) {
_, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid))
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Chroot(path string) (errno int) {
_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Close(fd int) (errno int) {
_, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Dup(fd int) (nfd int, errno int) {
r0, _, e1 := Syscall(SYS_DUP, uintptr(fd), 0, 0)
nfd = int(r0)
@@ -203,47 +259,63 @@ func Dup(fd int) (nfd int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Dup2(from int, to int) (errno int) {
_, _, e1 := Syscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
errno = int(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) (errno int) {
_, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Fchflags(path string, flags int) (errno int) {
_, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), 0)
errno = int(e1)
return
}
-func Fchmod(fd int, mode int) (errno int) {
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchmod(fd int, mode uint32) (errno int) {
_, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
errno = int(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) {
_, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Flock(fd int, how int) (errno int) {
_, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
errno = int(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) {
r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0)
val = int(r0)
@@ -251,76 +323,98 @@ func Fpathconf(fd int, name int) (val int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Fstat(fd int, stat *Stat_t) (errno int) {
_, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Fstatfs(fd int, stat *Statfs_t) (errno int) {
_, _, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Fsync(fd int) (errno int) {
_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Ftruncate(fd int, length int64) (errno int) {
_, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), uintptr(length), uintptr(length>>32))
errno = int(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) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(buf) > 0 {
- _p0 = &buf[0]
+ _p0 = unsafe.Pointer(&buf[0])
}
- r0, _, e1 := Syscall6(SYS_GETDIRENTRIES, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
+ r0, _, e1 := Syscall6(SYS_GETDIRENTRIES, uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
n = int(r0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getdtablesize() (size int) {
r0, _, _ := Syscall(SYS_GETDTABLESIZE, 0, 0, 0)
size = int(r0)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getegid() (egid int) {
r0, _, _ := Syscall(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, _, _ := Syscall(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, errno int) {
- var _p0 *Statfs_t
+ var _p0 unsafe.Pointer
if len(buf) > 0 {
- _p0 = &buf[0]
+ _p0 = unsafe.Pointer(&buf[0])
}
- r0, _, e1 := Syscall(SYS_GETFSSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(flags))
+ r0, _, e1 := Syscall(SYS_GETFSSTAT, uintptr(_p0), uintptr(len(buf)), uintptr(flags))
n = int(r0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getgid() (gid int) {
r0, _, _ := Syscall(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, errno int) {
r0, _, e1 := Syscall(SYS_GETPGID, uintptr(pid), 0, 0)
pgid = int(r0)
@@ -328,24 +422,32 @@ func Getpgid(pid int) (pgid int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getpgrp() (pgrp int) {
r0, _, _ := Syscall(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, _, _ := Syscall(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, _, _ := Syscall(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, errno int) {
r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
prio = int(r0)
@@ -353,18 +455,24 @@ func Getpriority(which int, who int) (prio int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getrlimit(which int, lim *Rlimit) (errno int) {
_, _, e1 := Syscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getrusage(who int, rusage *Rusage) (errno int) {
_, _, e1 := Syscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getsid(pid int) (sid int, errno int) {
r0, _, e1 := Syscall(SYS_GETSID, uintptr(pid), 0, 0)
sid = int(r0)
@@ -372,30 +480,40 @@ func Getsid(pid int) (sid int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Gettimeofday(tv *Timeval) (errno int) {
_, _, e1 := Syscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getuid() (uid int) {
r0, _, _ := Syscall(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) (errno int) {
_, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Kqueue() (fd int, errno int) {
r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0)
fd = int(r0)
@@ -403,61 +521,81 @@ func Kqueue() (fd int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Lchown(path string, uid int, gid int) (errno int) {
_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid))
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Link(path string, link string) (errno int) {
_, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(StringBytePtr(link))), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Listen(s int, backlog int) (errno int) {
_, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Lstat(path string, stat *Stat_t) (errno int) {
_, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0)
errno = int(e1)
return
}
-func Mkdir(path string, mode int) (errno int) {
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mkdir(path string, mode uint32) (errno int) {
_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
errno = int(e1)
return
}
-func Mkfifo(path string, mode int) (errno int) {
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mkfifo(path string, mode uint32) (errno int) {
_, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
errno = int(e1)
return
}
-func Mknod(path string, mode int, dev int) (errno int) {
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mknod(path string, mode uint32, dev int) (errno int) {
_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(dev))
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Nanosleep(time *Timespec, leftover *Timespec) (errno int) {
_, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0)
errno = int(e1)
return
}
-func Open(path string, mode int, perm int) (fd int, errno int) {
+// 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) {
r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(perm))
fd = int(r0)
errno = int(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) {
r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(name), 0)
val = int(r0)
@@ -465,68 +603,84 @@ func Pathconf(path string, name int) (val int, errno int) {
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) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(p) > 0 {
- _p0 = &p[0]
+ _p0 = unsafe.Pointer(&p[0])
}
- r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
+ r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
n = int(r0)
errno = int(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) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(p) > 0 {
- _p0 = &p[0]
+ _p0 = unsafe.Pointer(&p[0])
}
- r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
+ r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
n = int(r0)
errno = int(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) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(p) > 0 {
- _p0 = &p[0]
+ _p0 = unsafe.Pointer(&p[0])
}
- r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)))
+ r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
n = int(r0)
errno = int(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) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(buf) > 0 {
- _p0 = &buf[0]
+ _p0 = unsafe.Pointer(&buf[0])
}
- r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)))
+ r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(_p0), uintptr(len(buf)))
n = int(r0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Rename(from string, to string) (errno int) {
_, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(StringBytePtr(from))), uintptr(unsafe.Pointer(StringBytePtr(to))), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Revoke(path string) (errno int) {
_, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Rmdir(path string) (errno int) {
_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
errno = int(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) {
r0, r1, e1 := Syscall6(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(offset>>32), uintptr(whence), 0, 0)
newoffset = int64(int64(r1)<<32 | int64(r0))
@@ -534,66 +688,88 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, errno int) {
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) {
_, _, 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)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setegid(egid int) (errno int) {
_, _, e1 := Syscall(SYS_SETEGID, uintptr(egid), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Seteuid(euid int) (errno int) {
_, _, e1 := Syscall(SYS_SETEUID, uintptr(euid), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setgid(gid int) (errno int) {
_, _, e1 := Syscall(SYS_SETGID, uintptr(gid), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setlogin(name string) (errno int) {
_, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(StringBytePtr(name))), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setpgid(pid int, pgid int) (errno int) {
_, _, e1 := Syscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
errno = int(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) {
_, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio))
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setregid(rgid int, egid int) (errno int) {
_, _, e1 := Syscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setreuid(ruid int, euid int) (errno int) {
_, _, e1 := Syscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setrlimit(which int, lim *Rlimit) (errno int) {
_, _, e1 := Syscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setsid() (pid int, errno int) {
r0, _, e1 := Syscall(SYS_SETSID, 0, 0, 0)
pid = int(r0)
@@ -601,83 +777,109 @@ func Setsid() (pid int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Settimeofday(tp *Timeval) (errno int) {
_, _, e1 := Syscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setuid(uid int) (errno int) {
_, _, e1 := Syscall(SYS_SETUID, uintptr(uid), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Stat(path string, stat *Stat_t) (errno int) {
_, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Statfs(path string, stat *Statfs_t) (errno int) {
_, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Symlink(path string, link string) (errno int) {
_, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(StringBytePtr(link))), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Sync() (errno int) {
_, _, e1 := Syscall(SYS_SYNC, 0, 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Truncate(path string, length int64) (errno int) {
_, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(length), uintptr(length>>32))
errno = int(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 Undelete(path string) (errno int) {
_, _, e1 := Syscall(SYS_UNDELETE, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Unlink(path string) (errno int) {
_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Unmount(path string, flags int) (errno int) {
_, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), 0)
errno = int(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) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(p) > 0 {
- _p0 = &p[0]
+ _p0 = unsafe.Pointer(&p[0])
}
- r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)))
+ r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
n = int(r0)
errno = int(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) {
r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
n = int(r0)
@@ -685,6 +887,8 @@ func read(fd int, buf *byte, nbuf int) (n int, errno int) {
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) {
r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
n = int(r0)
diff --git a/src/pkg/syscall/zsyscall_freebsd_amd64.go b/src/pkg/syscall/zsyscall_freebsd_amd64.go
index f6c050ee5..8872367b1 100644
--- a/src/pkg/syscall/zsyscall_freebsd_amd64.go
+++ b/src/pkg/syscall/zsyscall_freebsd_amd64.go
@@ -5,6 +5,8 @@ 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, errno int) {
r0, _, e1 := Syscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
n = int(r0)
@@ -12,12 +14,16 @@ func getgroups(ngid int, gid *_Gid_t) (n int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func setgroups(ngid int, gid *_Gid_t) (errno int) {
_, _, e1 := Syscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
errno = int(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) {
r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
wpid = int(r0)
@@ -25,6 +31,8 @@ func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func pipe() (r int, w int, errno int) {
r0, r1, e1 := Syscall(SYS_PIPE, 0, 0, 0)
r = int(r0)
@@ -33,6 +41,8 @@ func pipe() (r int, w int, errno int) {
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) {
r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
fd = int(r0)
@@ -40,18 +50,24 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func bind(s int, addr uintptr, addrlen _Socklen) (errno int) {
_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
errno = int(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) {
_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
errno = int(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) {
r0, _, e1 := Syscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
fd = int(r0)
@@ -59,14 +75,7 @@ func socket(domain int, typ int, proto int) (fd int, errno int) {
return
}
-func socketpair(domain int, typ int, proto int) (fd [2]int, errno int) {
- var f [2]int
- _, _, e1 := Syscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(&f)), 0, 0)
- fd = f
- errno = int(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 int) (errno int) {
_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
@@ -74,45 +83,65 @@ func setsockopt(s int, level int, name int, val uintptr, vallen int) (errno int)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int) {
_, _, e1 := Syscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
errno = int(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) {
_, _, e1 := Syscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Shutdown(s int, how int) (errno int) {
_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0)
errno = int(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) {
+ _, _, e1 := Syscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
+ errno = int(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) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(p) > 0 {
- _p0 = &p[0]
+ _p0 = unsafe.Pointer(&p[0])
}
- r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
+ 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)
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) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(buf) > 0 {
- _p0 = &buf[0]
+ _p0 = unsafe.Pointer(&buf[0])
}
- _, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
+ _, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, timeout *Timespec) (n int, errno int) {
r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
n = int(r0)
@@ -120,28 +149,36 @@ func kevent(kq int, change uintptr, nchange int, event uintptr, nevent int, time
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) {
- var _p0 *_C_int
+ var _p0 unsafe.Pointer
if len(mib) > 0 {
- _p0 = &mib[0]
+ _p0 = unsafe.Pointer(&mib[0])
}
- _, _, e1 := Syscall6(SYS___SYSCTL, uintptr(unsafe.Pointer(_p0)), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
+ _, _, 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)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func utimes(path string, timeval *[2]Timeval) (errno int) {
_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(timeval)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func futimes(fd int, timeval *[2]Timeval) (errno int) {
_, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0)
errno = int(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) {
r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
val = int(r0)
@@ -149,54 +186,72 @@ func fcntl(fd int, cmd int, arg int) (val int, errno int) {
return
}
-func Access(path string, flags int) (errno int) {
- _, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), 0)
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Access(path string, mode uint32) (errno int) {
+ _, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Adjtime(delta *Timeval, olddelta *Timeval) (errno int) {
_, _, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Chdir(path string) (errno int) {
_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Chflags(path string, flags int) (errno int) {
_, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), 0)
errno = int(e1)
return
}
-func Chmod(path string, mode int) (errno int) {
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chmod(path string, mode uint32) (errno int) {
_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
errno = int(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) {
_, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid))
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Chroot(path string) (errno int) {
_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Close(fd int) (errno int) {
_, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Dup(fd int) (nfd int, errno int) {
r0, _, e1 := Syscall(SYS_DUP, uintptr(fd), 0, 0)
nfd = int(r0)
@@ -204,47 +259,63 @@ func Dup(fd int) (nfd int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Dup2(from int, to int) (errno int) {
_, _, e1 := Syscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
errno = int(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) (errno int) {
_, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Fchflags(path string, flags int) (errno int) {
_, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), 0)
errno = int(e1)
return
}
-func Fchmod(fd int, mode int) (errno int) {
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchmod(fd int, mode uint32) (errno int) {
_, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
errno = int(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) {
_, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Flock(fd int, how int) (errno int) {
_, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
errno = int(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) {
r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0)
val = int(r0)
@@ -252,76 +323,98 @@ func Fpathconf(fd int, name int) (val int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Fstat(fd int, stat *Stat_t) (errno int) {
_, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Fstatfs(fd int, stat *Statfs_t) (errno int) {
_, _, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Fsync(fd int) (errno int) {
_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Ftruncate(fd int, length int64) (errno int) {
_, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), uintptr(length), 0)
errno = int(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) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(buf) > 0 {
- _p0 = &buf[0]
+ _p0 = unsafe.Pointer(&buf[0])
}
- r0, _, e1 := Syscall6(SYS_GETDIRENTRIES, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
+ r0, _, e1 := Syscall6(SYS_GETDIRENTRIES, uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
n = int(r0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getdtablesize() (size int) {
r0, _, _ := Syscall(SYS_GETDTABLESIZE, 0, 0, 0)
size = int(r0)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getegid() (egid int) {
r0, _, _ := Syscall(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, _, _ := Syscall(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, errno int) {
- var _p0 *Statfs_t
+ var _p0 unsafe.Pointer
if len(buf) > 0 {
- _p0 = &buf[0]
+ _p0 = unsafe.Pointer(&buf[0])
}
- r0, _, e1 := Syscall(SYS_GETFSSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(flags))
+ r0, _, e1 := Syscall(SYS_GETFSSTAT, uintptr(_p0), uintptr(len(buf)), uintptr(flags))
n = int(r0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getgid() (gid int) {
r0, _, _ := Syscall(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, errno int) {
r0, _, e1 := Syscall(SYS_GETPGID, uintptr(pid), 0, 0)
pgid = int(r0)
@@ -329,24 +422,32 @@ func Getpgid(pid int) (pgid int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getpgrp() (pgrp int) {
r0, _, _ := Syscall(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, _, _ := Syscall(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, _, _ := Syscall(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, errno int) {
r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
prio = int(r0)
@@ -354,18 +455,24 @@ func Getpriority(which int, who int) (prio int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getrlimit(which int, lim *Rlimit) (errno int) {
_, _, e1 := Syscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getrusage(who int, rusage *Rusage) (errno int) {
_, _, e1 := Syscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getsid(pid int) (sid int, errno int) {
r0, _, e1 := Syscall(SYS_GETSID, uintptr(pid), 0, 0)
sid = int(r0)
@@ -373,30 +480,40 @@ func Getsid(pid int) (sid int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Gettimeofday(tv *Timeval) (errno int) {
_, _, e1 := Syscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getuid() (uid int) {
r0, _, _ := Syscall(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) (errno int) {
_, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Kqueue() (fd int, errno int) {
r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0)
fd = int(r0)
@@ -404,61 +521,81 @@ func Kqueue() (fd int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Lchown(path string, uid int, gid int) (errno int) {
_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid))
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Link(path string, link string) (errno int) {
_, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(StringBytePtr(link))), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Listen(s int, backlog int) (errno int) {
_, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Lstat(path string, stat *Stat_t) (errno int) {
_, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0)
errno = int(e1)
return
}
-func Mkdir(path string, mode int) (errno int) {
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mkdir(path string, mode uint32) (errno int) {
_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
errno = int(e1)
return
}
-func Mkfifo(path string, mode int) (errno int) {
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mkfifo(path string, mode uint32) (errno int) {
_, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
errno = int(e1)
return
}
-func Mknod(path string, mode int, dev int) (errno int) {
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mknod(path string, mode uint32, dev int) (errno int) {
_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(dev))
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Nanosleep(time *Timespec, leftover *Timespec) (errno int) {
_, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0)
errno = int(e1)
return
}
-func Open(path string, mode int, perm int) (fd int, errno int) {
+// 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) {
r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(perm))
fd = int(r0)
errno = int(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) {
r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(name), 0)
val = int(r0)
@@ -466,68 +603,84 @@ func Pathconf(path string, name int) (val int, errno int) {
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) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(p) > 0 {
- _p0 = &p[0]
+ _p0 = unsafe.Pointer(&p[0])
}
- r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(offset), 0, 0)
+ r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0)
n = int(r0)
errno = int(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) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(p) > 0 {
- _p0 = &p[0]
+ _p0 = unsafe.Pointer(&p[0])
}
- r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(offset), 0, 0)
+ r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0)
n = int(r0)
errno = int(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) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(p) > 0 {
- _p0 = &p[0]
+ _p0 = unsafe.Pointer(&p[0])
}
- r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)))
+ r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
n = int(r0)
errno = int(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) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(buf) > 0 {
- _p0 = &buf[0]
+ _p0 = unsafe.Pointer(&buf[0])
}
- r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)))
+ r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(_p0), uintptr(len(buf)))
n = int(r0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Rename(from string, to string) (errno int) {
_, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(StringBytePtr(from))), uintptr(unsafe.Pointer(StringBytePtr(to))), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Revoke(path string) (errno int) {
_, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Rmdir(path string) (errno int) {
_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
errno = int(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) {
r0, _, e1 := Syscall(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(whence))
newoffset = int64(r0)
@@ -535,66 +688,88 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, errno int) {
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) {
_, _, 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)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setegid(egid int) (errno int) {
_, _, e1 := Syscall(SYS_SETEGID, uintptr(egid), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Seteuid(euid int) (errno int) {
_, _, e1 := Syscall(SYS_SETEUID, uintptr(euid), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setgid(gid int) (errno int) {
_, _, e1 := Syscall(SYS_SETGID, uintptr(gid), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setlogin(name string) (errno int) {
_, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(StringBytePtr(name))), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setpgid(pid int, pgid int) (errno int) {
_, _, e1 := Syscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
errno = int(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) {
_, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio))
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setregid(rgid int, egid int) (errno int) {
_, _, e1 := Syscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setreuid(ruid int, euid int) (errno int) {
_, _, e1 := Syscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setrlimit(which int, lim *Rlimit) (errno int) {
_, _, e1 := Syscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setsid() (pid int, errno int) {
r0, _, e1 := Syscall(SYS_SETSID, 0, 0, 0)
pid = int(r0)
@@ -602,83 +777,109 @@ func Setsid() (pid int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Settimeofday(tp *Timeval) (errno int) {
_, _, e1 := Syscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setuid(uid int) (errno int) {
_, _, e1 := Syscall(SYS_SETUID, uintptr(uid), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Stat(path string, stat *Stat_t) (errno int) {
_, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Statfs(path string, stat *Statfs_t) (errno int) {
_, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Symlink(path string, link string) (errno int) {
_, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(StringBytePtr(link))), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Sync() (errno int) {
_, _, e1 := Syscall(SYS_SYNC, 0, 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Truncate(path string, length int64) (errno int) {
_, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(length), 0)
errno = int(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 Undelete(path string) (errno int) {
_, _, e1 := Syscall(SYS_UNDELETE, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Unlink(path string) (errno int) {
_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Unmount(path string, flags int) (errno int) {
_, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), 0)
errno = int(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) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(p) > 0 {
- _p0 = &p[0]
+ _p0 = unsafe.Pointer(&p[0])
}
- r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)))
+ r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
n = int(r0)
errno = int(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) {
r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
n = int(r0)
@@ -686,6 +887,8 @@ func read(fd int, buf *byte, nbuf int) (n int, errno int) {
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) {
r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
n = int(r0)
diff --git a/src/pkg/syscall/zsyscall_linux_386.go b/src/pkg/syscall/zsyscall_linux_386.go
index c1670f31e..aa8c41a31 100644
--- a/src/pkg/syscall/zsyscall_linux_386.go
+++ b/src/pkg/syscall/zsyscall_linux_386.go
@@ -5,49 +5,63 @@ package syscall
import "unsafe"
-func open(path string, mode int, perm int) (fd int, errno int) {
+// 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) {
r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(perm))
fd = int(r0)
errno = int(e1)
return
}
-func openat(dirfd int, path string, flags int, mode int) (fd int, errno int) {
+// 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) {
r0, _, e1 := Syscall6(SYS_OPENAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), uintptr(mode), 0, 0)
fd = int(r0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func pipe(p *[2]_C_int) (errno int) {
_, _, e1 := Syscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func utimes(path string, times *[2]Timeval) (errno int) {
_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(times)), 0)
errno = int(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) {
_, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(times)))
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getcwd(buf []byte) (n int, errno int) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(buf) > 0 {
- _p0 = &buf[0]
+ _p0 = unsafe.Pointer(&buf[0])
}
- r0, _, e1 := Syscall(SYS_GETCWD, uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), 0)
+ r0, _, e1 := Syscall(SYS_GETCWD, uintptr(_p0), uintptr(len(buf)), 0)
n = int(r0)
errno = int(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) {
r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
wpid = int(r0)
@@ -55,24 +69,32 @@ func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err
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) {
_, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0)
errno = int(e1)
return
}
-func Access(path string, mode int) (errno int) {
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Access(path string, mode uint32) (errno int) {
_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Acct(path string) (errno int) {
_, _, e1 := Syscall(SYS_ACCT, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Adjtimex(buf *Timex) (state int, errno int) {
r0, _, e1 := Syscall(SYS_ADJTIMEX, uintptr(unsafe.Pointer(buf)), 0, 0)
state = int(r0)
@@ -80,37 +102,49 @@ func Adjtimex(buf *Timex) (state int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Chdir(path string) (errno int) {
_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
errno = int(e1)
return
}
-func Chmod(path string, mode int) (errno int) {
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chmod(path string, mode uint32) (errno int) {
_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Chroot(path string) (errno int) {
_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Close(fd int) (errno int) {
_, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
errno = int(e1)
return
}
-func Creat(path string, mode int) (fd int, errno int) {
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Creat(path string, mode uint32) (fd int, errno int) {
r0, _, e1 := Syscall(SYS_CREAT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
fd = int(r0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Dup(oldfd int) (fd int, errno int) {
r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), 0, 0)
fd = int(r0)
@@ -118,6 +152,8 @@ func Dup(oldfd int) (fd int, errno int) {
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 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0)
fd = int(r0)
@@ -125,6 +161,8 @@ func Dup2(oldfd int, newfd int) (fd int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func EpollCreate(size int) (fd int, errno int) {
r0, _, e1 := Syscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0)
fd = int(r0)
@@ -132,64 +170,84 @@ func EpollCreate(size int) (fd int, errno int) {
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) {
_, _, e1 := Syscall6(SYS_EPOLL_CTL, uintptr(epfd), uintptr(op), uintptr(fd), uintptr(unsafe.Pointer(event)), 0, 0)
errno = int(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) {
- var _p0 *EpollEvent
+ var _p0 unsafe.Pointer
if len(events) > 0 {
- _p0 = &events[0]
+ _p0 = unsafe.Pointer(&events[0])
}
- r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(unsafe.Pointer(_p0)), uintptr(len(events)), uintptr(msec), 0, 0)
+ r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
n = int(r0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Exit(code int) {
Syscall(SYS_EXIT_GROUP, uintptr(code), 0, 0)
return
}
-func Faccessat(dirfd int, path string, mode int, flags int) (errno 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) {
_, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(flags), 0, 0)
errno = int(e1)
return
}
-func Fallocate(fd int, mode int, off int64, len int64) (errno int) {
+// 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), uintptr(off>>32), uintptr(len), uintptr(len>>32))
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Fchdir(fd int) (errno int) {
_, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
errno = int(e1)
return
}
-func Fchmod(fd int, mode int) (errno int) {
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchmod(fd int, mode uint32) (errno int) {
_, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
errno = int(e1)
return
}
-func Fchmodat(dirfd int, path string, mode int, flags int) (errno int) {
+// 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) {
_, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(flags), 0, 0)
errno = int(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) {
_, _, e1 := Syscall6(SYS_FCHOWNAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid), uintptr(flags), 0)
errno = int(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) {
r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
val = int(r0)
@@ -197,35 +255,37 @@ func fcntl(fd int, cmd int, arg int) (val int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Fdatasync(fd int) (errno int) {
_, _, e1 := Syscall(SYS_FDATASYNC, uintptr(fd), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Fsync(fd int) (errno int) {
_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
errno = int(e1)
return
}
-func Ftruncate(fd int, length int64) (errno int) {
- _, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), uintptr(length), uintptr(length>>32))
- errno = int(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) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(buf) > 0 {
- _p0 = &buf[0]
+ _p0 = unsafe.Pointer(&buf[0])
}
- r0, _, e1 := Syscall(SYS_GETDENTS64, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)))
+ r0, _, e1 := Syscall(SYS_GETDENTS64, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
n = int(r0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getpgid(pid int) (pgid int, errno int) {
r0, _, e1 := Syscall(SYS_GETPGID, uintptr(pid), 0, 0)
pgid = int(r0)
@@ -233,207 +293,267 @@ func Getpgid(pid int) (pgid int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getpgrp() (pid int) {
r0, _, _ := Syscall(SYS_GETPGRP, 0, 0, 0)
pid = int(r0)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getpid() (pid int) {
r0, _, _ := Syscall(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, _, _ := Syscall(SYS_GETPPID, 0, 0, 0)
ppid = int(r0)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getrlimit(resource int, rlim *Rlimit) (errno int) {
_, _, e1 := Syscall(SYS_GETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getrusage(who int, rusage *Rusage) (errno int) {
_, _, e1 := Syscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Gettid() (tid int) {
r0, _, _ := Syscall(SYS_GETTID, 0, 0, 0)
tid = int(r0)
return
}
-func Gettimeofday(tv *Timeval) (errno int) {
- _, _, e1 := Syscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
+// 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) {
+ r0, _, e1 := Syscall(SYS_INOTIFY_ADD_WATCH, uintptr(fd), uintptr(unsafe.Pointer(StringBytePtr(pathname))), uintptr(mask))
+ watchdesc = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func InotifyInit() (fd int, errno int) {
+ r0, _, e1 := Syscall(SYS_INOTIFY_INIT, 0, 0, 0)
+ fd = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func InotifyInit1(flags int) (fd int, errno int) {
+ r0, _, e1 := Syscall(SYS_INOTIFY_INIT1, uintptr(flags), 0, 0)
+ fd = int(r0)
errno = int(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) {
+ r0, _, e1 := Syscall(SYS_INOTIFY_RM_WATCH, uintptr(fd), uintptr(watchdesc), 0)
+ success = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Kill(pid int, sig int) (errno int) {
_, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(sig), 0)
errno = int(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) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(buf) > 0 {
- _p0 = &buf[0]
+ _p0 = unsafe.Pointer(&buf[0])
}
- r0, _, e1 := Syscall(SYS_SYSLOG, uintptr(typ), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)))
+ r0, _, e1 := Syscall(SYS_SYSLOG, uintptr(typ), uintptr(_p0), uintptr(len(buf)))
n = int(r0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Link(oldpath string, newpath string) (errno int) {
_, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(StringBytePtr(oldpath))), uintptr(unsafe.Pointer(StringBytePtr(newpath))), 0)
errno = int(e1)
return
}
-func Mkdir(path string, mode int) (errno int) {
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mkdir(path string, mode uint32) (errno int) {
_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
errno = int(e1)
return
}
-func Mkdirat(dirfd int, path string, mode int) (errno int) {
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mkdirat(dirfd int, path string, mode uint32) (errno int) {
_, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode))
errno = int(e1)
return
}
-func Mknod(path string, mode int, dev int) (errno int) {
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mknod(path string, mode uint32, dev int) (errno int) {
_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(dev))
errno = int(e1)
return
}
-func Mknodat(dirfd int, path string, mode int, dev int) (errno int) {
+// 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) {
_, _, 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 Nanosleep(time *Timespec, leftover *Timespec) (errno int) {
_, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Pause() (errno int) {
_, _, e1 := Syscall(SYS_PAUSE, 0, 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func PivotRoot(newroot string, putold string) (errno int) {
_, _, e1 := Syscall(SYS_PIVOT_ROOT, uintptr(unsafe.Pointer(StringBytePtr(newroot))), uintptr(unsafe.Pointer(StringBytePtr(putold))), 0)
errno = int(e1)
return
}
-func Pread(fd int, p []byte, offset int64) (n int, errno int) {
- var _p0 *byte
- if len(p) > 0 {
- _p0 = &p[0]
- }
- r0, _, e1 := Syscall6(SYS_PREAD64, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
- n = int(r0)
- errno = int(e1)
- return
-}
-
-func Pwrite(fd int, p []byte, offset int64) (n int, errno int) {
- var _p0 *byte
- if len(p) > 0 {
- _p0 = &p[0]
- }
- r0, _, e1 := Syscall6(SYS_PWRITE64, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
- n = int(r0)
- errno = int(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) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(p) > 0 {
- _p0 = &p[0]
+ _p0 = unsafe.Pointer(&p[0])
}
- r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)))
+ r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
n = int(r0)
errno = int(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) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(buf) > 0 {
- _p0 = &buf[0]
+ _p0 = unsafe.Pointer(&buf[0])
}
- r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)))
+ r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(_p0), uintptr(len(buf)))
n = int(r0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Rename(oldpath string, newpath string) (errno int) {
_, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(StringBytePtr(oldpath))), uintptr(unsafe.Pointer(StringBytePtr(newpath))), 0)
errno = int(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) {
_, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(olddirfd), uintptr(unsafe.Pointer(StringBytePtr(oldpath))), uintptr(newdirfd), uintptr(unsafe.Pointer(StringBytePtr(newpath))), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Rmdir(path string) (errno int) {
_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setdomainname(p []byte) (errno int) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(p) > 0 {
- _p0 = &p[0]
+ _p0 = unsafe.Pointer(&p[0])
}
- _, _, e1 := Syscall(SYS_SETDOMAINNAME, uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), 0)
+ _, _, e1 := Syscall(SYS_SETDOMAINNAME, uintptr(_p0), uintptr(len(p)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Sethostname(p []byte) (errno int) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(p) > 0 {
- _p0 = &p[0]
+ _p0 = unsafe.Pointer(&p[0])
}
- _, _, e1 := Syscall(SYS_SETHOSTNAME, uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), 0)
+ _, _, e1 := Syscall(SYS_SETHOSTNAME, uintptr(_p0), uintptr(len(p)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setpgid(pid int, pgid int) (errno int) {
_, _, e1 := Syscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setrlimit(resource int, rlim *Rlimit) (errno int) {
_, _, e1 := Syscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setsid() (pid int, errno int) {
r0, _, e1 := Syscall(SYS_SETSID, 0, 0, 0)
pid = int(r0)
@@ -441,24 +561,23 @@ func Setsid() (pid int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Settimeofday(tv *Timeval) (errno int) {
_, _, e1 := Syscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setuid(uid int) (errno int) {
_, _, e1 := Syscall(SYS_SETUID, uintptr(uid), 0, 0)
errno = int(e1)
return
}
-func Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, errno int) {
- r0, r1, e1 := Syscall6(SYS_SPLICE, uintptr(rfd), uintptr(unsafe.Pointer(roff)), uintptr(wfd), uintptr(unsafe.Pointer(woff)), uintptr(len), uintptr(flags))
- n = int64(int64(r1)<<32 | int64(r0))
- errno = int(e1)
- return
-}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Symlink(oldpath string, newpath string) (errno int) {
_, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(StringBytePtr(oldpath))), uintptr(unsafe.Pointer(StringBytePtr(newpath))), 0)
@@ -466,17 +585,23 @@ func Symlink(oldpath string, newpath string) (errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Sync() {
Syscall(SYS_SYNC, 0, 0, 0)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Sysinfo(info *Sysinfo_t) (errno int) {
_, _, e1 := Syscall(SYS_SYSINFO, uintptr(unsafe.Pointer(info)), 0, 0)
errno = int(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) {
r0, r1, e1 := Syscall6(SYS_TEE, uintptr(rfd), uintptr(wfd), uintptr(len), uintptr(flags), 0, 0)
n = int64(int64(r1)<<32 | int64(r0))
@@ -484,18 +609,15 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Tgkill(tgid int, tid int, sig int) (errno int) {
_, _, e1 := Syscall(SYS_TGKILL, uintptr(tgid), uintptr(tid), uintptr(sig))
errno = int(e1)
return
}
-func Time(t *Time_t) (tt Time_t, errno int) {
- r0, _, e1 := Syscall(SYS_TIME, uintptr(unsafe.Pointer(t)), 0, 0)
- tt = Time_t(r0)
- errno = int(e1)
- return
-}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Times(tms *Tms) (ticks uintptr, errno int) {
r0, _, e1 := Syscall(SYS_TIMES, uintptr(unsafe.Pointer(tms)), 0, 0)
@@ -504,11 +626,7 @@ func Times(tms *Tms) (ticks uintptr, errno int) {
return
}
-func Truncate(path string, length int64) (errno int) {
- _, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(length), uintptr(length>>32))
- errno = int(e1)
- return
-}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Umask(mask int) (oldmask int) {
r0, _, _ := Syscall(SYS_UMASK, uintptr(mask), 0, 0)
@@ -516,59 +634,77 @@ func Umask(mask int) (oldmask int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Uname(buf *Utsname) (errno int) {
_, _, e1 := Syscall(SYS_UNAME, uintptr(unsafe.Pointer(buf)), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Unlink(path string) (errno int) {
_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Unlinkat(dirfd int, path string) (errno int) {
_, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Unshare(flags int) (errno int) {
_, _, e1 := Syscall(SYS_UNSHARE, uintptr(flags), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Ustat(dev int, ubuf *Ustat_t) (errno int) {
_, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Utime(path string, buf *Utimbuf) (errno int) {
_, _, e1 := Syscall(SYS_UTIME, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(buf)), 0)
errno = int(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) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(p) > 0 {
- _p0 = &p[0]
+ _p0 = unsafe.Pointer(&p[0])
}
- r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)))
+ r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
n = int(r0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func exitThread(code int) (errno int) {
_, _, e1 := Syscall(SYS_EXIT, uintptr(code), 0, 0)
errno = int(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) {
r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(np))
n = int(r0)
@@ -576,6 +712,8 @@ func read(fd int, p *byte, np int) (n int, errno int) {
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) {
r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(np))
n = int(r0)
@@ -583,126 +721,219 @@ func write(fd int, p *byte, np int) (n int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Chown(path string, uid int, gid int) (errno int) {
_, _, e1 := Syscall(SYS_CHOWN32, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid))
errno = int(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) {
_, _, e1 := Syscall(SYS_FCHOWN32, uintptr(fd), uintptr(uid), uintptr(gid))
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Fstat(fd int, stat *Stat_t) (errno int) {
_, _, e1 := Syscall(SYS_FSTAT64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Ftruncate(fd int, length int64) (errno int) {
+ _, _, e1 := Syscall(SYS_FTRUNCATE64, uintptr(fd), uintptr(length), uintptr(length>>32))
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getegid() (egid int) {
r0, _, _ := Syscall(SYS_GETEGID32, 0, 0, 0)
egid = int(r0)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Geteuid() (euid int) {
r0, _, _ := Syscall(SYS_GETEUID32, 0, 0, 0)
euid = int(r0)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getgid() (gid int) {
r0, _, _ := Syscall(SYS_GETGID32, 0, 0, 0)
gid = int(r0)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getuid() (uid int) {
r0, _, _ := Syscall(SYS_GETUID32, 0, 0, 0)
uid = int(r0)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Ioperm(from int, num int, on int) (errno int) {
_, _, e1 := Syscall(SYS_IOPERM, uintptr(from), uintptr(num), uintptr(on))
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Iopl(level int) (errno int) {
_, _, e1 := Syscall(SYS_IOPL, uintptr(level), 0, 0)
errno = int(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) {
_, _, e1 := Syscall(SYS_LCHOWN32, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid))
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Lstat(path string, stat *Stat_t) (errno int) {
_, _, e1 := Syscall(SYS_LSTAT64, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0)
errno = int(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) {
+ 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)), uintptr(offset), uintptr(offset>>32), 0)
+ n = int(r0)
+ errno = int(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) {
+ 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)), uintptr(offset), uintptr(offset>>32), 0)
+ n = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setfsgid(gid int) (errno int) {
_, _, e1 := Syscall(SYS_SETFSGID32, uintptr(gid), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setfsuid(uid int) (errno int) {
_, _, e1 := Syscall(SYS_SETFSUID32, uintptr(uid), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setgid(gid int) (errno int) {
_, _, e1 := Syscall(SYS_SETGID32, uintptr(gid), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setregid(rgid int, egid int) (errno int) {
_, _, e1 := Syscall(SYS_SETREGID32, uintptr(rgid), uintptr(egid), 0)
errno = int(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) {
_, _, e1 := Syscall(SYS_SETRESGID32, uintptr(rgid), uintptr(egid), uintptr(sgid))
errno = int(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) {
_, _, e1 := Syscall(SYS_SETRESUID32, uintptr(ruid), uintptr(euid), uintptr(suid))
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setreuid(ruid int, euid int) (errno int) {
_, _, e1 := Syscall(SYS_SETREUID32, uintptr(ruid), uintptr(euid), 0)
errno = int(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) {
+ 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)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Stat(path string, stat *Stat_t) (errno int) {
_, _, e1 := Syscall(SYS_STAT64, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0)
errno = int(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) {
_, _, e1 := Syscall6(SYS_SYNC_FILE_RANGE, uintptr(fd), uintptr(off), uintptr(off>>32), uintptr(n), uintptr(n>>32), uintptr(flags))
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Truncate(path string, length int64) (errno int) {
+ _, _, e1 := Syscall(SYS_TRUNCATE64, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(length), uintptr(length>>32))
+ errno = int(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) {
r0, _, e1 := Syscall(SYS_GETGROUPS32, uintptr(n), uintptr(unsafe.Pointer(list)), 0)
nn = int(r0)
@@ -710,15 +941,36 @@ func getgroups(n int, list *_Gid_t) (nn int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func setgroups(n int, list *_Gid_t) (errno int) {
_, _, e1 := Syscall(SYS_SETGROUPS32, uintptr(n), uintptr(unsafe.Pointer(list)), 0)
errno = int(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) {
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)
return
}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Gettimeofday(tv *Timeval) (errno int) {
+ _, _, e1 := Syscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
+ errno = int(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) {
+ r0, _, e1 := Syscall(SYS_TIME, uintptr(unsafe.Pointer(t)), 0, 0)
+ tt = Time_t(r0)
+ errno = int(e1)
+ return
+}
diff --git a/src/pkg/syscall/zsyscall_linux_amd64.go b/src/pkg/syscall/zsyscall_linux_amd64.go
index 87e545987..2759c5c8b 100644
--- a/src/pkg/syscall/zsyscall_linux_amd64.go
+++ b/src/pkg/syscall/zsyscall_linux_amd64.go
@@ -5,49 +5,63 @@ package syscall
import "unsafe"
-func open(path string, mode int, perm int) (fd int, errno int) {
+// 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) {
r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(perm))
fd = int(r0)
errno = int(e1)
return
}
-func openat(dirfd int, path string, flags int, mode int) (fd int, errno int) {
+// 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) {
r0, _, e1 := Syscall6(SYS_OPENAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), uintptr(mode), 0, 0)
fd = int(r0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func pipe(p *[2]_C_int) (errno int) {
_, _, e1 := Syscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func utimes(path string, times *[2]Timeval) (errno int) {
_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(times)), 0)
errno = int(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) {
_, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(times)))
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getcwd(buf []byte) (n int, errno int) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(buf) > 0 {
- _p0 = &buf[0]
+ _p0 = unsafe.Pointer(&buf[0])
}
- r0, _, e1 := Syscall(SYS_GETCWD, uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), 0)
+ r0, _, e1 := Syscall(SYS_GETCWD, uintptr(_p0), uintptr(len(buf)), 0)
n = int(r0)
errno = int(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) {
r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
wpid = int(r0)
@@ -55,24 +69,32 @@ func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err
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) {
_, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0)
errno = int(e1)
return
}
-func Access(path string, mode int) (errno int) {
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Access(path string, mode uint32) (errno int) {
_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Acct(path string) (errno int) {
_, _, e1 := Syscall(SYS_ACCT, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Adjtimex(buf *Timex) (state int, errno int) {
r0, _, e1 := Syscall(SYS_ADJTIMEX, uintptr(unsafe.Pointer(buf)), 0, 0)
state = int(r0)
@@ -80,37 +102,49 @@ func Adjtimex(buf *Timex) (state int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Chdir(path string) (errno int) {
_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
errno = int(e1)
return
}
-func Chmod(path string, mode int) (errno int) {
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chmod(path string, mode uint32) (errno int) {
_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Chroot(path string) (errno int) {
_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Close(fd int) (errno int) {
_, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
errno = int(e1)
return
}
-func Creat(path string, mode int) (fd int, errno int) {
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Creat(path string, mode uint32) (fd int, errno int) {
r0, _, e1 := Syscall(SYS_CREAT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
fd = int(r0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Dup(oldfd int) (fd int, errno int) {
r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), 0, 0)
fd = int(r0)
@@ -118,6 +152,8 @@ func Dup(oldfd int) (fd int, errno int) {
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 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0)
fd = int(r0)
@@ -125,6 +161,8 @@ func Dup2(oldfd int, newfd int) (fd int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func EpollCreate(size int) (fd int, errno int) {
r0, _, e1 := Syscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0)
fd = int(r0)
@@ -132,64 +170,84 @@ func EpollCreate(size int) (fd int, errno int) {
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) {
_, _, e1 := Syscall6(SYS_EPOLL_CTL, uintptr(epfd), uintptr(op), uintptr(fd), uintptr(unsafe.Pointer(event)), 0, 0)
errno = int(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) {
- var _p0 *EpollEvent
+ var _p0 unsafe.Pointer
if len(events) > 0 {
- _p0 = &events[0]
+ _p0 = unsafe.Pointer(&events[0])
}
- r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(unsafe.Pointer(_p0)), uintptr(len(events)), uintptr(msec), 0, 0)
+ r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
n = int(r0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Exit(code int) {
Syscall(SYS_EXIT_GROUP, uintptr(code), 0, 0)
return
}
-func Faccessat(dirfd int, path string, mode int, flags int) (errno 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) {
_, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(flags), 0, 0)
errno = int(e1)
return
}
-func Fallocate(fd int, mode int, off int64, len int64) (errno int) {
+// 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), uintptr(len), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Fchdir(fd int) (errno int) {
_, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
errno = int(e1)
return
}
-func Fchmod(fd int, mode int) (errno int) {
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchmod(fd int, mode uint32) (errno int) {
_, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
errno = int(e1)
return
}
-func Fchmodat(dirfd int, path string, mode int, flags int) (errno int) {
+// 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) {
_, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(flags), 0, 0)
errno = int(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) {
_, _, e1 := Syscall6(SYS_FCHOWNAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid), uintptr(flags), 0)
errno = int(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) {
r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
val = int(r0)
@@ -197,35 +255,37 @@ func fcntl(fd int, cmd int, arg int) (val int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Fdatasync(fd int) (errno int) {
_, _, e1 := Syscall(SYS_FDATASYNC, uintptr(fd), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Fsync(fd int) (errno int) {
_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
errno = int(e1)
return
}
-func Ftruncate(fd int, length int64) (errno int) {
- _, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), uintptr(length), 0)
- errno = int(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) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(buf) > 0 {
- _p0 = &buf[0]
+ _p0 = unsafe.Pointer(&buf[0])
}
- r0, _, e1 := Syscall(SYS_GETDENTS64, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)))
+ r0, _, e1 := Syscall(SYS_GETDENTS64, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
n = int(r0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getpgid(pid int) (pgid int, errno int) {
r0, _, e1 := Syscall(SYS_GETPGID, uintptr(pid), 0, 0)
pgid = int(r0)
@@ -233,207 +293,267 @@ func Getpgid(pid int) (pgid int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getpgrp() (pid int) {
r0, _, _ := Syscall(SYS_GETPGRP, 0, 0, 0)
pid = int(r0)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getpid() (pid int) {
r0, _, _ := Syscall(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, _, _ := Syscall(SYS_GETPPID, 0, 0, 0)
ppid = int(r0)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getrlimit(resource int, rlim *Rlimit) (errno int) {
_, _, e1 := Syscall(SYS_GETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getrusage(who int, rusage *Rusage) (errno int) {
_, _, e1 := Syscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Gettid() (tid int) {
r0, _, _ := Syscall(SYS_GETTID, 0, 0, 0)
tid = int(r0)
return
}
-func Gettimeofday(tv *Timeval) (errno int) {
- _, _, e1 := Syscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
+// 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) {
+ r0, _, e1 := Syscall(SYS_INOTIFY_ADD_WATCH, uintptr(fd), uintptr(unsafe.Pointer(StringBytePtr(pathname))), uintptr(mask))
+ watchdesc = int(r0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func InotifyInit() (fd int, errno int) {
+ r0, _, e1 := Syscall(SYS_INOTIFY_INIT, 0, 0, 0)
+ fd = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func InotifyInit1(flags int) (fd int, errno int) {
+ r0, _, e1 := Syscall(SYS_INOTIFY_INIT1, uintptr(flags), 0, 0)
+ fd = int(r0)
+ errno = int(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) {
+ r0, _, e1 := Syscall(SYS_INOTIFY_RM_WATCH, uintptr(fd), uintptr(watchdesc), 0)
+ success = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Kill(pid int, sig int) (errno int) {
_, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(sig), 0)
errno = int(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) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(buf) > 0 {
- _p0 = &buf[0]
+ _p0 = unsafe.Pointer(&buf[0])
}
- r0, _, e1 := Syscall(SYS_SYSLOG, uintptr(typ), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)))
+ r0, _, e1 := Syscall(SYS_SYSLOG, uintptr(typ), uintptr(_p0), uintptr(len(buf)))
n = int(r0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Link(oldpath string, newpath string) (errno int) {
_, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(StringBytePtr(oldpath))), uintptr(unsafe.Pointer(StringBytePtr(newpath))), 0)
errno = int(e1)
return
}
-func Mkdir(path string, mode int) (errno int) {
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mkdir(path string, mode uint32) (errno int) {
_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
errno = int(e1)
return
}
-func Mkdirat(dirfd int, path string, mode int) (errno int) {
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mkdirat(dirfd int, path string, mode uint32) (errno int) {
_, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode))
errno = int(e1)
return
}
-func Mknod(path string, mode int, dev int) (errno int) {
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mknod(path string, mode uint32, dev int) (errno int) {
_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(dev))
errno = int(e1)
return
}
-func Mknodat(dirfd int, path string, mode int, dev int) (errno int) {
+// 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) {
_, _, 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 Nanosleep(time *Timespec, leftover *Timespec) (errno int) {
_, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Pause() (errno int) {
_, _, e1 := Syscall(SYS_PAUSE, 0, 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func PivotRoot(newroot string, putold string) (errno int) {
_, _, e1 := Syscall(SYS_PIVOT_ROOT, uintptr(unsafe.Pointer(StringBytePtr(newroot))), uintptr(unsafe.Pointer(StringBytePtr(putold))), 0)
errno = int(e1)
return
}
-func Pread(fd int, p []byte, offset int64) (n int, errno int) {
- var _p0 *byte
- if len(p) > 0 {
- _p0 = &p[0]
- }
- r0, _, e1 := Syscall6(SYS_PREAD64, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(offset), 0, 0)
- n = int(r0)
- errno = int(e1)
- return
-}
-
-func Pwrite(fd int, p []byte, offset int64) (n int, errno int) {
- var _p0 *byte
- if len(p) > 0 {
- _p0 = &p[0]
- }
- r0, _, e1 := Syscall6(SYS_PWRITE64, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(offset), 0, 0)
- n = int(r0)
- errno = int(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) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(p) > 0 {
- _p0 = &p[0]
+ _p0 = unsafe.Pointer(&p[0])
}
- r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)))
+ r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
n = int(r0)
errno = int(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) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(buf) > 0 {
- _p0 = &buf[0]
+ _p0 = unsafe.Pointer(&buf[0])
}
- r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)))
+ r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(_p0), uintptr(len(buf)))
n = int(r0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Rename(oldpath string, newpath string) (errno int) {
_, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(StringBytePtr(oldpath))), uintptr(unsafe.Pointer(StringBytePtr(newpath))), 0)
errno = int(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) {
_, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(olddirfd), uintptr(unsafe.Pointer(StringBytePtr(oldpath))), uintptr(newdirfd), uintptr(unsafe.Pointer(StringBytePtr(newpath))), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Rmdir(path string) (errno int) {
_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setdomainname(p []byte) (errno int) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(p) > 0 {
- _p0 = &p[0]
+ _p0 = unsafe.Pointer(&p[0])
}
- _, _, e1 := Syscall(SYS_SETDOMAINNAME, uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), 0)
+ _, _, e1 := Syscall(SYS_SETDOMAINNAME, uintptr(_p0), uintptr(len(p)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Sethostname(p []byte) (errno int) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(p) > 0 {
- _p0 = &p[0]
+ _p0 = unsafe.Pointer(&p[0])
}
- _, _, e1 := Syscall(SYS_SETHOSTNAME, uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), 0)
+ _, _, e1 := Syscall(SYS_SETHOSTNAME, uintptr(_p0), uintptr(len(p)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setpgid(pid int, pgid int) (errno int) {
_, _, e1 := Syscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setrlimit(resource int, rlim *Rlimit) (errno int) {
_, _, e1 := Syscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setsid() (pid int, errno int) {
r0, _, e1 := Syscall(SYS_SETSID, 0, 0, 0)
pid = int(r0)
@@ -441,24 +561,23 @@ func Setsid() (pid int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Settimeofday(tv *Timeval) (errno int) {
_, _, e1 := Syscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setuid(uid int) (errno int) {
_, _, e1 := Syscall(SYS_SETUID, uintptr(uid), 0, 0)
errno = int(e1)
return
}
-func Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, errno int) {
- 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)
- return
-}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Symlink(oldpath string, newpath string) (errno int) {
_, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(StringBytePtr(oldpath))), uintptr(unsafe.Pointer(StringBytePtr(newpath))), 0)
@@ -466,17 +585,23 @@ func Symlink(oldpath string, newpath string) (errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Sync() {
Syscall(SYS_SYNC, 0, 0, 0)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Sysinfo(info *Sysinfo_t) (errno int) {
_, _, e1 := Syscall(SYS_SYSINFO, uintptr(unsafe.Pointer(info)), 0, 0)
errno = int(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) {
r0, _, e1 := Syscall6(SYS_TEE, uintptr(rfd), uintptr(wfd), uintptr(len), uintptr(flags), 0, 0)
n = int64(r0)
@@ -484,18 +609,15 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Tgkill(tgid int, tid int, sig int) (errno int) {
_, _, e1 := Syscall(SYS_TGKILL, uintptr(tgid), uintptr(tid), uintptr(sig))
errno = int(e1)
return
}
-func Time(t *Time_t) (tt Time_t, errno int) {
- r0, _, e1 := Syscall(SYS_TIME, uintptr(unsafe.Pointer(t)), 0, 0)
- tt = Time_t(r0)
- errno = int(e1)
- return
-}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Times(tms *Tms) (ticks uintptr, errno int) {
r0, _, e1 := Syscall(SYS_TIMES, uintptr(unsafe.Pointer(tms)), 0, 0)
@@ -504,11 +626,7 @@ func Times(tms *Tms) (ticks uintptr, errno int) {
return
}
-func Truncate(path string, length int64) (errno int) {
- _, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(length), 0)
- errno = int(e1)
- return
-}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Umask(mask int) (oldmask int) {
r0, _, _ := Syscall(SYS_UMASK, uintptr(mask), 0, 0)
@@ -516,59 +634,77 @@ func Umask(mask int) (oldmask int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Uname(buf *Utsname) (errno int) {
_, _, e1 := Syscall(SYS_UNAME, uintptr(unsafe.Pointer(buf)), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Unlink(path string) (errno int) {
_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Unlinkat(dirfd int, path string) (errno int) {
_, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Unshare(flags int) (errno int) {
_, _, e1 := Syscall(SYS_UNSHARE, uintptr(flags), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Ustat(dev int, ubuf *Ustat_t) (errno int) {
_, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Utime(path string, buf *Utimbuf) (errno int) {
_, _, e1 := Syscall(SYS_UTIME, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(buf)), 0)
errno = int(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) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(p) > 0 {
- _p0 = &p[0]
+ _p0 = unsafe.Pointer(&p[0])
}
- r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)))
+ r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
n = int(r0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func exitThread(code int) (errno int) {
_, _, e1 := Syscall(SYS_EXIT, uintptr(code), 0, 0)
errno = int(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) {
r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(np))
n = int(r0)
@@ -576,6 +712,8 @@ func read(fd int, p *byte, np int) (n int, errno int) {
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) {
r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(np))
n = int(r0)
@@ -583,84 +721,146 @@ func write(fd int, p *byte, np int) (n int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Chown(path string, uid int, gid int) (errno int) {
_, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid))
errno = int(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) {
_, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Fstat(fd int, stat *Stat_t) (errno int) {
_, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Fstatfs(fd int, buf *Statfs_t) (errno int) {
_, _, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(buf)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Ftruncate(fd int, length int64) (errno int) {
+ _, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), uintptr(length), 0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getegid() (egid int) {
r0, _, _ := Syscall(SYS_GETEGID, 0, 0, 0)
egid = int(r0)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Geteuid() (euid int) {
r0, _, _ := Syscall(SYS_GETEUID, 0, 0, 0)
euid = int(r0)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getgid() (gid int) {
r0, _, _ := Syscall(SYS_GETGID, 0, 0, 0)
gid = int(r0)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getuid() (uid int) {
r0, _, _ := Syscall(SYS_GETUID, 0, 0, 0)
uid = int(r0)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Ioperm(from int, num int, on int) (errno int) {
_, _, e1 := Syscall(SYS_IOPERM, uintptr(from), uintptr(num), uintptr(on))
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Iopl(level int) (errno int) {
_, _, e1 := Syscall(SYS_IOPL, uintptr(level), 0, 0)
errno = int(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) {
_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid))
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Listen(s int, n int) (errno int) {
_, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(n), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Lstat(path string, stat *Stat_t) (errno int) {
_, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0)
errno = int(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) {
+ 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)), uintptr(offset), 0, 0)
+ n = int(r0)
+ errno = int(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) {
+ 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)), uintptr(offset), 0, 0)
+ n = int(r0)
+ errno = int(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) {
r0, _, e1 := Syscall(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(whence))
off = int64(r0)
@@ -668,6 +868,8 @@ func Seek(fd int, offset int64, whence int) (off int64, errno int) {
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) {
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)
@@ -675,72 +877,113 @@ func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setfsgid(gid int) (errno int) {
_, _, e1 := Syscall(SYS_SETFSGID, uintptr(gid), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setfsuid(uid int) (errno int) {
_, _, e1 := Syscall(SYS_SETFSUID, uintptr(uid), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setgid(gid int) (errno int) {
_, _, e1 := Syscall(SYS_SETGID, uintptr(gid), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setregid(rgid int, egid int) (errno int) {
_, _, e1 := Syscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0)
errno = int(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) {
_, _, e1 := Syscall(SYS_SETRESGID, uintptr(rgid), uintptr(egid), uintptr(sgid))
errno = int(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) {
_, _, e1 := Syscall(SYS_SETRESUID, uintptr(ruid), uintptr(euid), uintptr(suid))
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setreuid(ruid int, euid int) (errno int) {
_, _, e1 := Syscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Shutdown(fd int, how int) (errno int) {
_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(fd), uintptr(how), 0)
errno = int(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) {
+ 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)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Stat(path string, stat *Stat_t) (errno int) {
_, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Statfs(path string, buf *Statfs_t) (errno int) {
_, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(buf)), 0)
errno = int(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) {
_, _, e1 := Syscall6(SYS_SYNC_FILE_RANGE, uintptr(fd), uintptr(off), uintptr(n), uintptr(flags), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Truncate(path string, length int64) (errno int) {
+ _, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(length), 0)
+ errno = int(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) {
r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
fd = int(r0)
@@ -748,18 +991,24 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func bind(s int, addr uintptr, addrlen _Socklen) (errno int) {
_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
errno = int(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) {
_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
errno = int(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) {
r0, _, e1 := Syscall(SYS_GETGROUPS, uintptr(n), uintptr(unsafe.Pointer(list)), 0)
nn = int(r0)
@@ -767,18 +1016,24 @@ func getgroups(n int, list *_Gid_t) (nn int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func setgroups(n int, list *_Gid_t) (errno int) {
_, _, e1 := Syscall(SYS_SETGROUPS, uintptr(n), uintptr(unsafe.Pointer(list)), 0)
errno = int(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 int) (errno int) {
_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
errno = int(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) {
r0, _, e1 := Syscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
fd = int(r0)
@@ -786,43 +1041,68 @@ func socket(domain int, typ int, proto int) (fd int, errno int) {
return
}
-func socketpair(domain int, typ int, proto int) (fd [2]int, errno int) {
- var f [2]int
- _, _, e1 := Syscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(&f)), 0, 0)
- fd = f
+// 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) {
+ _, _, e1 := Syscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
errno = int(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) {
_, _, e1 := Syscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
errno = int(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) {
_, _, e1 := Syscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
errno = int(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) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(p) > 0 {
- _p0 = &p[0]
+ _p0 = unsafe.Pointer(&p[0])
}
- r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
+ 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)
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) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(buf) > 0 {
- _p0 = &buf[0]
+ _p0 = unsafe.Pointer(&buf[0])
}
- _, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
+ _, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
+ errno = int(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) {
+ r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ n = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func sendmsg(s int, msg *Msghdr, flags int) (errno int) {
+ _, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
errno = int(e1)
return
}
diff --git a/src/pkg/syscall/zsyscall_linux_arm.go b/src/pkg/syscall/zsyscall_linux_arm.go
index 36ff34294..711108577 100644
--- a/src/pkg/syscall/zsyscall_linux_arm.go
+++ b/src/pkg/syscall/zsyscall_linux_arm.go
@@ -1,53 +1,67 @@
-// mksyscall.sh -l32 syscall_linux.go syscall_linux_arm.go
+// mksyscall.sh -b32 syscall_linux.go syscall_linux_arm.go
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
package syscall
import "unsafe"
-func open(path string, mode int, perm int) (fd int, errno int) {
+// 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) {
r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(perm))
fd = int(r0)
errno = int(e1)
return
}
-func openat(dirfd int, path string, flags int, mode int) (fd int, errno int) {
+// 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) {
r0, _, e1 := Syscall6(SYS_OPENAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(flags), uintptr(mode), 0, 0)
fd = int(r0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func pipe(p *[2]_C_int) (errno int) {
_, _, e1 := Syscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func utimes(path string, times *[2]Timeval) (errno int) {
_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(times)), 0)
errno = int(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) {
_, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(times)))
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getcwd(buf []byte) (n int, errno int) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(buf) > 0 {
- _p0 = &buf[0]
+ _p0 = unsafe.Pointer(&buf[0])
}
- r0, _, e1 := Syscall(SYS_GETCWD, uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), 0)
+ r0, _, e1 := Syscall(SYS_GETCWD, uintptr(_p0), uintptr(len(buf)), 0)
n = int(r0)
errno = int(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) {
r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
wpid = int(r0)
@@ -55,24 +69,32 @@ func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err
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) {
_, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0)
errno = int(e1)
return
}
-func Access(path string, mode int) (errno int) {
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Access(path string, mode uint32) (errno int) {
_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Acct(path string) (errno int) {
_, _, e1 := Syscall(SYS_ACCT, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Adjtimex(buf *Timex) (state int, errno int) {
r0, _, e1 := Syscall(SYS_ADJTIMEX, uintptr(unsafe.Pointer(buf)), 0, 0)
state = int(r0)
@@ -80,37 +102,49 @@ func Adjtimex(buf *Timex) (state int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Chdir(path string) (errno int) {
_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
errno = int(e1)
return
}
-func Chmod(path string, mode int) (errno int) {
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chmod(path string, mode uint32) (errno int) {
_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Chroot(path string) (errno int) {
_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Close(fd int) (errno int) {
_, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
errno = int(e1)
return
}
-func Creat(path string, mode int) (fd int, errno int) {
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Creat(path string, mode uint32) (fd int, errno int) {
r0, _, e1 := Syscall(SYS_CREAT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
fd = int(r0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Dup(oldfd int) (fd int, errno int) {
r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), 0, 0)
fd = int(r0)
@@ -118,6 +152,8 @@ func Dup(oldfd int) (fd int, errno int) {
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 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0)
fd = int(r0)
@@ -125,6 +161,8 @@ func Dup2(oldfd int, newfd int) (fd int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func EpollCreate(size int) (fd int, errno int) {
r0, _, e1 := Syscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0)
fd = int(r0)
@@ -132,64 +170,84 @@ func EpollCreate(size int) (fd int, errno int) {
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) {
_, _, e1 := Syscall6(SYS_EPOLL_CTL, uintptr(epfd), uintptr(op), uintptr(fd), uintptr(unsafe.Pointer(event)), 0, 0)
errno = int(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) {
- var _p0 *EpollEvent
+ var _p0 unsafe.Pointer
if len(events) > 0 {
- _p0 = &events[0]
+ _p0 = unsafe.Pointer(&events[0])
}
- r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(unsafe.Pointer(_p0)), uintptr(len(events)), uintptr(msec), 0, 0)
+ r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
n = int(r0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Exit(code int) {
Syscall(SYS_EXIT_GROUP, uintptr(code), 0, 0)
return
}
-func Faccessat(dirfd int, path string, mode int, flags int) (errno 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) {
_, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(flags), 0, 0)
errno = int(e1)
return
}
-func Fallocate(fd int, mode int, off int64, len int64) (errno int) {
- _, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off), uintptr(off>>32), uintptr(len), uintptr(len>>32))
+// 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)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Fchdir(fd int) (errno int) {
_, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
errno = int(e1)
return
}
-func Fchmod(fd int, mode int) (errno int) {
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchmod(fd int, mode uint32) (errno int) {
_, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
errno = int(e1)
return
}
-func Fchmodat(dirfd int, path string, mode int, flags int) (errno int) {
+// 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) {
_, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(flags), 0, 0)
errno = int(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) {
_, _, e1 := Syscall6(SYS_FCHOWNAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid), uintptr(flags), 0)
errno = int(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) {
r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
val = int(r0)
@@ -197,35 +255,37 @@ func fcntl(fd int, cmd int, arg int) (val int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Fdatasync(fd int) (errno int) {
_, _, e1 := Syscall(SYS_FDATASYNC, uintptr(fd), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Fsync(fd int) (errno int) {
_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
errno = int(e1)
return
}
-func Ftruncate(fd int, length int64) (errno int) {
- _, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), uintptr(length), uintptr(length>>32))
- errno = int(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) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(buf) > 0 {
- _p0 = &buf[0]
+ _p0 = unsafe.Pointer(&buf[0])
}
- r0, _, e1 := Syscall(SYS_GETDENTS64, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)))
+ r0, _, e1 := Syscall(SYS_GETDENTS64, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
n = int(r0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getpgid(pid int) (pgid int, errno int) {
r0, _, e1 := Syscall(SYS_GETPGID, uintptr(pid), 0, 0)
pgid = int(r0)
@@ -233,207 +293,267 @@ func Getpgid(pid int) (pgid int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getpgrp() (pid int) {
r0, _, _ := Syscall(SYS_GETPGRP, 0, 0, 0)
pid = int(r0)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getpid() (pid int) {
r0, _, _ := Syscall(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, _, _ := Syscall(SYS_GETPPID, 0, 0, 0)
ppid = int(r0)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getrlimit(resource int, rlim *Rlimit) (errno int) {
_, _, e1 := Syscall(SYS_GETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getrusage(who int, rusage *Rusage) (errno int) {
_, _, e1 := Syscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Gettid() (tid int) {
r0, _, _ := Syscall(SYS_GETTID, 0, 0, 0)
tid = int(r0)
return
}
-func Gettimeofday(tv *Timeval) (errno int) {
- _, _, e1 := Syscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
+// 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) {
+ r0, _, e1 := Syscall(SYS_INOTIFY_ADD_WATCH, uintptr(fd), uintptr(unsafe.Pointer(StringBytePtr(pathname))), uintptr(mask))
+ watchdesc = int(r0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func InotifyInit() (fd int, errno int) {
+ r0, _, e1 := Syscall(SYS_INOTIFY_INIT, 0, 0, 0)
+ fd = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func InotifyInit1(flags int) (fd int, errno int) {
+ r0, _, e1 := Syscall(SYS_INOTIFY_INIT1, uintptr(flags), 0, 0)
+ fd = int(r0)
+ errno = int(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) {
+ r0, _, e1 := Syscall(SYS_INOTIFY_RM_WATCH, uintptr(fd), uintptr(watchdesc), 0)
+ success = int(r0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Kill(pid int, sig int) (errno int) {
_, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(sig), 0)
errno = int(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) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(buf) > 0 {
- _p0 = &buf[0]
+ _p0 = unsafe.Pointer(&buf[0])
}
- r0, _, e1 := Syscall(SYS_SYSLOG, uintptr(typ), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)))
+ r0, _, e1 := Syscall(SYS_SYSLOG, uintptr(typ), uintptr(_p0), uintptr(len(buf)))
n = int(r0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Link(oldpath string, newpath string) (errno int) {
_, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(StringBytePtr(oldpath))), uintptr(unsafe.Pointer(StringBytePtr(newpath))), 0)
errno = int(e1)
return
}
-func Mkdir(path string, mode int) (errno int) {
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mkdir(path string, mode uint32) (errno int) {
_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
errno = int(e1)
return
}
-func Mkdirat(dirfd int, path string, mode int) (errno int) {
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mkdirat(dirfd int, path string, mode uint32) (errno int) {
_, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode))
errno = int(e1)
return
}
-func Mknod(path string, mode int, dev int) (errno int) {
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mknod(path string, mode uint32, dev int) (errno int) {
_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(dev))
errno = int(e1)
return
}
-func Mknodat(dirfd int, path string, mode int, dev int) (errno int) {
+// 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) {
_, _, 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 Nanosleep(time *Timespec, leftover *Timespec) (errno int) {
_, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Pause() (errno int) {
_, _, e1 := Syscall(SYS_PAUSE, 0, 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func PivotRoot(newroot string, putold string) (errno int) {
_, _, e1 := Syscall(SYS_PIVOT_ROOT, uintptr(unsafe.Pointer(StringBytePtr(newroot))), uintptr(unsafe.Pointer(StringBytePtr(putold))), 0)
errno = int(e1)
return
}
-func Pread(fd int, p []byte, offset int64) (n int, errno int) {
- var _p0 *byte
- if len(p) > 0 {
- _p0 = &p[0]
- }
- r0, _, e1 := Syscall6(SYS_PREAD64, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
- n = int(r0)
- errno = int(e1)
- return
-}
-
-func Pwrite(fd int, p []byte, offset int64) (n int, errno int) {
- var _p0 *byte
- if len(p) > 0 {
- _p0 = &p[0]
- }
- r0, _, e1 := Syscall6(SYS_PWRITE64, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
- n = int(r0)
- errno = int(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) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(p) > 0 {
- _p0 = &p[0]
+ _p0 = unsafe.Pointer(&p[0])
}
- r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)))
+ r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
n = int(r0)
errno = int(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) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(buf) > 0 {
- _p0 = &buf[0]
+ _p0 = unsafe.Pointer(&buf[0])
}
- r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)))
+ r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(_p0), uintptr(len(buf)))
n = int(r0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Rename(oldpath string, newpath string) (errno int) {
_, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(StringBytePtr(oldpath))), uintptr(unsafe.Pointer(StringBytePtr(newpath))), 0)
errno = int(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) {
_, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(olddirfd), uintptr(unsafe.Pointer(StringBytePtr(oldpath))), uintptr(newdirfd), uintptr(unsafe.Pointer(StringBytePtr(newpath))), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Rmdir(path string) (errno int) {
_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setdomainname(p []byte) (errno int) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(p) > 0 {
- _p0 = &p[0]
+ _p0 = unsafe.Pointer(&p[0])
}
- _, _, e1 := Syscall(SYS_SETDOMAINNAME, uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), 0)
+ _, _, e1 := Syscall(SYS_SETDOMAINNAME, uintptr(_p0), uintptr(len(p)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Sethostname(p []byte) (errno int) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(p) > 0 {
- _p0 = &p[0]
+ _p0 = unsafe.Pointer(&p[0])
}
- _, _, e1 := Syscall(SYS_SETHOSTNAME, uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), 0)
+ _, _, e1 := Syscall(SYS_SETHOSTNAME, uintptr(_p0), uintptr(len(p)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setpgid(pid int, pgid int) (errno int) {
_, _, e1 := Syscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setrlimit(resource int, rlim *Rlimit) (errno int) {
_, _, e1 := Syscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setsid() (pid int, errno int) {
r0, _, e1 := Syscall(SYS_SETSID, 0, 0, 0)
pid = int(r0)
@@ -441,24 +561,23 @@ func Setsid() (pid int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Settimeofday(tv *Timeval) (errno int) {
_, _, e1 := Syscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setuid(uid int) (errno int) {
_, _, e1 := Syscall(SYS_SETUID, uintptr(uid), 0, 0)
errno = int(e1)
return
}
-func Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, errno int) {
- r0, r1, e1 := Syscall6(SYS_SPLICE, uintptr(rfd), uintptr(unsafe.Pointer(roff)), uintptr(wfd), uintptr(unsafe.Pointer(woff)), uintptr(len), uintptr(flags))
- n = int64(int64(r1)<<32 | int64(r0))
- errno = int(e1)
- return
-}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Symlink(oldpath string, newpath string) (errno int) {
_, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(StringBytePtr(oldpath))), uintptr(unsafe.Pointer(StringBytePtr(newpath))), 0)
@@ -466,36 +585,39 @@ func Symlink(oldpath string, newpath string) (errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Sync() {
Syscall(SYS_SYNC, 0, 0, 0)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Sysinfo(info *Sysinfo_t) (errno int) {
_, _, e1 := Syscall(SYS_SYSINFO, uintptr(unsafe.Pointer(info)), 0, 0)
errno = int(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) {
r0, r1, e1 := Syscall6(SYS_TEE, uintptr(rfd), uintptr(wfd), uintptr(len), uintptr(flags), 0, 0)
- n = int64(int64(r1)<<32 | int64(r0))
+ n = int64(int64(r0)<<32 | int64(r1))
errno = int(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) {
_, _, e1 := Syscall(SYS_TGKILL, uintptr(tgid), uintptr(tid), uintptr(sig))
errno = int(e1)
return
}
-func Time(t *Time_t) (tt Time_t, errno int) {
- r0, _, e1 := Syscall(SYS_TIME, uintptr(unsafe.Pointer(t)), 0, 0)
- tt = Time_t(r0)
- errno = int(e1)
- return
-}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Times(tms *Tms) (ticks uintptr, errno int) {
r0, _, e1 := Syscall(SYS_TIMES, uintptr(unsafe.Pointer(tms)), 0, 0)
@@ -504,11 +626,7 @@ func Times(tms *Tms) (ticks uintptr, errno int) {
return
}
-func Truncate(path string, length int64) (errno int) {
- _, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(length), uintptr(length>>32))
- errno = int(e1)
- return
-}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Umask(mask int) (oldmask int) {
r0, _, _ := Syscall(SYS_UMASK, uintptr(mask), 0, 0)
@@ -516,59 +634,77 @@ func Umask(mask int) (oldmask int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Uname(buf *Utsname) (errno int) {
_, _, e1 := Syscall(SYS_UNAME, uintptr(unsafe.Pointer(buf)), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Unlink(path string) (errno int) {
_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(StringBytePtr(path))), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Unlinkat(dirfd int, path string) (errno int) {
_, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(StringBytePtr(path))), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Unshare(flags int) (errno int) {
_, _, e1 := Syscall(SYS_UNSHARE, uintptr(flags), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Ustat(dev int, ubuf *Ustat_t) (errno int) {
_, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Utime(path string, buf *Utimbuf) (errno int) {
_, _, e1 := Syscall(SYS_UTIME, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(buf)), 0)
errno = int(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) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(p) > 0 {
- _p0 = &p[0]
+ _p0 = unsafe.Pointer(&p[0])
}
- r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)))
+ r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
n = int(r0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func exitThread(code int) (errno int) {
_, _, e1 := Syscall(SYS_EXIT, uintptr(code), 0, 0)
errno = int(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) {
r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(np))
n = int(r0)
@@ -576,6 +712,8 @@ func read(fd int, p *byte, np int) (n int, errno int) {
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) {
r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(np))
n = int(r0)
@@ -583,6 +721,8 @@ func write(fd int, p *byte, np int) (n int, errno int) {
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) {
r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
fd = int(r0)
@@ -590,18 +730,24 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func bind(s int, addr uintptr, addrlen _Socklen) (errno int) {
_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
errno = int(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) {
_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
errno = int(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) {
r0, _, e1 := Syscall(SYS_GETGROUPS32, uintptr(n), uintptr(unsafe.Pointer(list)), 0)
nn = int(r0)
@@ -609,18 +755,24 @@ func getgroups(n int, list *_Gid_t) (nn int, errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func setgroups(n int, list *_Gid_t) (errno int) {
_, _, e1 := Syscall(SYS_SETGROUPS32, uintptr(n), uintptr(unsafe.Pointer(list)), 0)
errno = int(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 int) (errno int) {
_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
errno = int(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) {
r0, _, e1 := Syscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
fd = int(r0)
@@ -628,13 +780,7 @@ func socket(domain int, typ int, proto int) (fd int, errno int) {
return
}
-func socketpair(domain int, typ int, proto int) (fd [2]int, errno int) {
- var f [2]int
- _, _, e1 := Syscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(&f)), 0, 0)
- fd = f
- errno = int(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) {
_, _, e1 := Syscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
@@ -642,105 +788,161 @@ func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int) {
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (errno int) {
_, _, e1 := Syscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
errno = int(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) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(p) > 0 {
- _p0 = &p[0]
+ _p0 = unsafe.Pointer(&p[0])
}
- r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
+ 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)
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) {
- var _p0 *byte
+ var _p0 unsafe.Pointer
if len(buf) > 0 {
- _p0 = &buf[0]
+ _p0 = unsafe.Pointer(&buf[0])
}
- _, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
+ _, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
+ errno = int(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) {
+ _, _, e1 := Syscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(flags), uintptr(unsafe.Pointer(fd)), 0, 0)
+ errno = int(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) {
+ r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ n = int(r0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func sendmsg(s int, msg *Msghdr, flags int) (errno int) {
+ _, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Chown(path string, uid int, gid int) (errno int) {
_, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid))
errno = int(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) {
_, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Fstat(fd int, stat *Stat_t) (errno int) {
- _, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
+ _, _, e1 := Syscall(SYS_FSTAT64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Fstatfs(fd int, buf *Statfs_t) (errno int) {
- _, _, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(buf)), 0)
+ _, _, e1 := Syscall(SYS_FSTATFS64, uintptr(fd), uintptr(unsafe.Pointer(buf)), 0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Ftruncate(fd int, length int64) (errno int) {
+ _, _, e1 := Syscall(SYS_FTRUNCATE64, uintptr(fd), uintptr(length>>32), uintptr(length))
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getegid() (egid int) {
r0, _, _ := Syscall(SYS_GETEGID, 0, 0, 0)
egid = int(r0)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Geteuid() (euid int) {
r0, _, _ := Syscall(SYS_GETEUID, 0, 0, 0)
euid = int(r0)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getgid() (gid int) {
r0, _, _ := Syscall(SYS_GETGID, 0, 0, 0)
gid = int(r0)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getuid() (uid int) {
r0, _, _ := Syscall(SYS_GETUID, 0, 0, 0)
uid = int(r0)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Lchown(path string, uid int, gid int) (errno int) {
_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(uid), uintptr(gid))
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Listen(s int, n int) (errno int) {
_, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(n), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Lstat(path string, stat *Stat_t) (errno int) {
- _, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0)
+ _, _, e1 := Syscall(SYS_LSTAT64, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0)
errno = int(e1)
return
}
-func Seek(fd int, offset int64, whence int) (off int64, errno int) {
- r0, r1, e1 := Syscall6(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(offset>>32), uintptr(whence), 0, 0)
- off = int64(int64(r1)<<32 | int64(r0))
- errno = int(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) {
r0, _, e1 := Syscall6(SYS__NEWSELECT, uintptr(nfd), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0)
@@ -749,62 +951,116 @@ func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setfsgid(gid int) (errno int) {
_, _, e1 := Syscall(SYS_SETFSGID, uintptr(gid), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setfsuid(uid int) (errno int) {
_, _, e1 := Syscall(SYS_SETFSUID, uintptr(uid), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setgid(gid int) (errno int) {
_, _, e1 := Syscall(SYS_SETGID, uintptr(gid), 0, 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setregid(rgid int, egid int) (errno int) {
_, _, e1 := Syscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0)
errno = int(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) {
_, _, e1 := Syscall(SYS_SETRESGID, uintptr(rgid), uintptr(egid), uintptr(sgid))
errno = int(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) {
_, _, e1 := Syscall(SYS_SETRESUID, uintptr(ruid), uintptr(euid), uintptr(suid))
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Setreuid(ruid int, euid int) (errno int) {
_, _, e1 := Syscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Shutdown(fd int, how int) (errno int) {
_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(fd), uintptr(how), 0)
errno = int(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) {
+ 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)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Stat(path string, stat *Stat_t) (errno int) {
- _, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0)
+ _, _, e1 := Syscall(SYS_STAT64, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0)
errno = int(e1)
return
}
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Statfs(path string, buf *Statfs_t) (errno int) {
- _, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(buf)), 0)
+ _, _, e1 := Syscall(SYS_STATFS64, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(buf)), 0)
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Truncate(path string, length int64) (errno int) {
+ _, _, e1 := Syscall(SYS_TRUNCATE64, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(length>>32), uintptr(length))
+ errno = int(e1)
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Gettimeofday(tv *Timeval) (errno int) {
+ _, _, e1 := Syscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
+ errno = int(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) {
+ r0, _, e1 := Syscall(SYS_TIME, uintptr(unsafe.Pointer(t)), 0, 0)
+ tt = Time_t(r0)
errno = int(e1)
return
}
diff --git a/src/pkg/syscall/zsyscall_nacl_386.go b/src/pkg/syscall/zsyscall_nacl_386.go
deleted file mode 100644
index 34a0bd466..000000000
--- a/src/pkg/syscall/zsyscall_nacl_386.go
+++ /dev/null
@@ -1,229 +0,0 @@
-// mksyscall.sh -l32 syscall_nacl.go syscall_nacl_386.go
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
-
-package syscall
-
-import "unsafe"
-
-func Chmod(path string, mode int) (errno int) {
- _, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), 0)
- errno = int(e1)
- return
-}
-
-func Clock() (clock int) {
- r0, _, _ := Syscall(SYS_CLOCK, 0, 0, 0)
- clock = int(r0)
- return
-}
-
-func Close(fd int) (errno int) {
- _, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
- errno = int(e1)
- return
-}
-
-func Exit(code int) {
- Syscall(SYS_EXIT, uintptr(code), 0, 0)
- return
-}
-
-func Fstat(fd int, stat *Stat_t) (errno int) {
- _, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
- errno = int(e1)
- return
-}
-
-func Getdents(fd int, buf []byte) (n int, errno int) {
- var _p0 *byte
- if len(buf) > 0 {
- _p0 = &buf[0]
- }
- r0, _, e1 := Syscall(SYS_GETDENTS, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)))
- n = int(r0)
- errno = int(e1)
- return
-}
-
-func Getpid() (pid int) {
- r0, _, _ := Syscall(SYS_GETPID, 0, 0, 0)
- pid = int(r0)
- return
-}
-
-func Gettimeofday(tv *Timeval) (errno int) {
- _, _, e1 := Syscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
- errno = int(e1)
- return
-}
-
-func Open(path string, mode int, perm int) (fd int, errno int) {
- r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(mode), uintptr(perm))
- fd = int(r0)
- errno = int(e1)
- return
-}
-
-func Read(fd int, p []byte) (n int, errno int) {
- var _p0 *byte
- if len(p) > 0 {
- _p0 = &p[0]
- }
- r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)))
- n = int(r0)
- errno = int(e1)
- return
-}
-
-func read(fd int, buf *byte, nbuf int) (n int, errno int) {
- r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
- n = int(r0)
- errno = int(e1)
- return
-}
-
-func Stat(path string, stat *Stat_t) (errno int) {
- _, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(StringBytePtr(path))), uintptr(unsafe.Pointer(stat)), 0)
- errno = int(e1)
- return
-}
-
-func Write(fd int, p []byte) (n int, errno int) {
- var _p0 *byte
- if len(p) > 0 {
- _p0 = &p[0]
- }
- r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)))
- n = int(r0)
- errno = int(e1)
- return
-}
-
-func MultimediaInit(subsys int) (errno int) {
- _, _, e1 := Syscall(SYS_MULTIMEDIA_INIT, uintptr(subsys), 0, 0)
- errno = int(e1)
- return
-}
-
-func MultimediaShutdown() (errno int) {
- _, _, e1 := Syscall(SYS_MULTIMEDIA_SHUTDOWN, 0, 0, 0)
- errno = int(e1)
- return
-}
-
-func CondCreate() (cv int, errno int) {
- r0, _, e1 := Syscall(SYS_COND_CREATE, 0, 0, 0)
- cv = int(r0)
- errno = int(e1)
- return
-}
-
-func CondWait(cv int, mutex int) (errno int) {
- _, _, e1 := Syscall(SYS_COND_WAIT, uintptr(cv), uintptr(mutex), 0)
- errno = int(e1)
- return
-}
-
-func CondSignal(cv int) (errno int) {
- _, _, e1 := Syscall(SYS_COND_SIGNAL, uintptr(cv), 0, 0)
- errno = int(e1)
- return
-}
-
-func CondBroadcast(cv int) (errno int) {
- _, _, e1 := Syscall(SYS_COND_BROADCAST, uintptr(cv), 0, 0)
- errno = int(e1)
- return
-}
-
-func CondTimedWaitAbs(cv int, mutex int, abstime *Timespec) (errno int) {
- _, _, e1 := Syscall(SYS_COND_TIMED_WAIT_ABS, uintptr(cv), uintptr(mutex), uintptr(unsafe.Pointer(abstime)))
- errno = int(e1)
- return
-}
-
-func MutexCreate() (mutex int, errno int) {
- r0, _, e1 := Syscall(SYS_MUTEX_CREATE, 0, 0, 0)
- mutex = int(r0)
- errno = int(e1)
- return
-}
-
-func MutexLock(mutex int) (errno int) {
- _, _, e1 := Syscall(SYS_MUTEX_LOCK, uintptr(mutex), 0, 0)
- errno = int(e1)
- return
-}
-
-func MutexUnlock(mutex int) (errno int) {
- _, _, e1 := Syscall(SYS_MUTEX_UNLOCK, uintptr(mutex), 0, 0)
- errno = int(e1)
- return
-}
-
-func MutexTryLock(mutex int) (errno int) {
- _, _, e1 := Syscall(SYS_MUTEX_TRYLOCK, uintptr(mutex), 0, 0)
- errno = int(e1)
- return
-}
-
-func SemCreate() (sema int, errno int) {
- r0, _, e1 := Syscall(SYS_SEM_CREATE, 0, 0, 0)
- sema = int(r0)
- errno = int(e1)
- return
-}
-
-func SemWait(sema int) (errno int) {
- _, _, e1 := Syscall(SYS_SEM_WAIT, uintptr(sema), 0, 0)
- errno = int(e1)
- return
-}
-
-func SemPost(sema int) (errno int) {
- _, _, e1 := Syscall(SYS_SEM_POST, uintptr(sema), 0, 0)
- errno = int(e1)
- return
-}
-
-func VideoInit(dx int, dy int) (errno int) {
- _, _, e1 := Syscall(SYS_VIDEO_INIT, uintptr(dx), uintptr(dy), 0)
- errno = int(e1)
- return
-}
-
-func VideoUpdate(data *uint32) (errno int) {
- _, _, e1 := Syscall(SYS_VIDEO_UPDATE, uintptr(unsafe.Pointer(data)), 0, 0)
- errno = int(e1)
- return
-}
-
-func VideoPollEvent(ev *byte) (errno int) {
- _, _, e1 := Syscall(SYS_VIDEO_POLL_EVENT, uintptr(unsafe.Pointer(ev)), 0, 0)
- errno = int(e1)
- return
-}
-
-func VideoShutdown() (errno int) {
- _, _, e1 := Syscall(SYS_VIDEO_SHUTDOWN, 0, 0, 0)
- errno = int(e1)
- return
-}
-
-func AudioInit(fmt int, nreq int, data *int) (errno int) {
- _, _, e1 := Syscall(SYS_AUDIO_INIT, uintptr(fmt), uintptr(nreq), uintptr(unsafe.Pointer(data)))
- errno = int(e1)
- return
-}
-
-func AudioShutdown() (errno int) {
- _, _, e1 := Syscall(SYS_AUDIO_SHUTDOWN, 0, 0, 0)
- errno = int(e1)
- return
-}
-
-func AudioStream(data *uint16, size *uintptr) (errno int) {
- _, _, e1 := Syscall(SYS_AUDIO_STREAM, uintptr(unsafe.Pointer(data)), uintptr(unsafe.Pointer(size)), 0)
- errno = int(e1)
- return
-}
diff --git a/src/pkg/syscall/zsyscall_windows_386.go b/src/pkg/syscall/zsyscall_windows_386.go
index be5dd031c..29880f2b2 100644
--- a/src/pkg/syscall/zsyscall_windows_386.go
+++ b/src/pkg/syscall/zsyscall_windows_386.go
@@ -7,8 +7,11 @@ import "unsafe"
var (
modkernel32 = loadDll("kernel32.dll")
+ modadvapi32 = loadDll("advapi32.dll")
+ modshell32 = loadDll("shell32.dll")
modwsock32 = loadDll("wsock32.dll")
modws2_32 = loadDll("ws2_32.dll")
+ moddnsapi = loadDll("dnsapi.dll")
procGetLastError = getSysProcAddr(modkernel32, "GetLastError")
procLoadLibraryW = getSysProcAddr(modkernel32, "LoadLibraryW")
@@ -40,7 +43,28 @@ var (
procGetTimeZoneInformation = getSysProcAddr(modkernel32, "GetTimeZoneInformation")
procCreateIoCompletionPort = getSysProcAddr(modkernel32, "CreateIoCompletionPort")
procGetQueuedCompletionStatus = getSysProcAddr(modkernel32, "GetQueuedCompletionStatus")
+ procCreateProcessW = getSysProcAddr(modkernel32, "CreateProcessW")
+ procGetStartupInfoW = getSysProcAddr(modkernel32, "GetStartupInfoW")
+ procGetCurrentProcess = getSysProcAddr(modkernel32, "GetCurrentProcess")
+ procDuplicateHandle = getSysProcAddr(modkernel32, "DuplicateHandle")
+ procWaitForSingleObject = getSysProcAddr(modkernel32, "WaitForSingleObject")
procGetTempPathW = getSysProcAddr(modkernel32, "GetTempPathW")
+ procCreatePipe = getSysProcAddr(modkernel32, "CreatePipe")
+ procGetFileType = getSysProcAddr(modkernel32, "GetFileType")
+ procCryptAcquireContextW = getSysProcAddr(modadvapi32, "CryptAcquireContextW")
+ procCryptReleaseContext = getSysProcAddr(modadvapi32, "CryptReleaseContext")
+ procCryptGenRandom = getSysProcAddr(modadvapi32, "CryptGenRandom")
+ procOpenProcess = getSysProcAddr(modkernel32, "OpenProcess")
+ procGetExitCodeProcess = getSysProcAddr(modkernel32, "GetExitCodeProcess")
+ procGetEnvironmentStringsW = getSysProcAddr(modkernel32, "GetEnvironmentStringsW")
+ procFreeEnvironmentStringsW = getSysProcAddr(modkernel32, "FreeEnvironmentStringsW")
+ procGetEnvironmentVariableW = getSysProcAddr(modkernel32, "GetEnvironmentVariableW")
+ procSetEnvironmentVariableW = getSysProcAddr(modkernel32, "SetEnvironmentVariableW")
+ procSetFileTime = getSysProcAddr(modkernel32, "SetFileTime")
+ procGetFileAttributesW = getSysProcAddr(modkernel32, "GetFileAttributesW")
+ procGetCommandLineW = getSysProcAddr(modkernel32, "GetCommandLineW")
+ procCommandLineToArgvW = getSysProcAddr(modshell32, "CommandLineToArgvW")
+ procLocalFree = getSysProcAddr(modkernel32, "LocalFree")
procWSAStartup = getSysProcAddr(modwsock32, "WSAStartup")
procWSACleanup = getSysProcAddr(modwsock32, "WSACleanup")
procsocket = getSysProcAddr(modwsock32, "socket")
@@ -51,10 +75,18 @@ var (
procgetpeername = getSysProcAddr(modwsock32, "getpeername")
proclisten = getSysProcAddr(modwsock32, "listen")
procshutdown = getSysProcAddr(modwsock32, "shutdown")
+ procclosesocket = getSysProcAddr(modwsock32, "closesocket")
procAcceptEx = getSysProcAddr(modwsock32, "AcceptEx")
procGetAcceptExSockaddrs = getSysProcAddr(modwsock32, "GetAcceptExSockaddrs")
procWSARecv = getSysProcAddr(modws2_32, "WSARecv")
procWSASend = getSysProcAddr(modws2_32, "WSASend")
+ procWSARecvFrom = getSysProcAddr(modws2_32, "WSARecvFrom")
+ procWSASendTo = getSysProcAddr(modws2_32, "WSASendTo")
+ procgethostbyname = getSysProcAddr(modws2_32, "gethostbyname")
+ procgetservbyname = getSysProcAddr(modws2_32, "getservbyname")
+ procntohs = getSysProcAddr(modws2_32, "ntohs")
+ procDnsQuery_W = getSysProcAddr(moddnsapi, "DnsQuery_W")
+ procDnsRecordListFree = getSysProcAddr(moddnsapi, "DnsRecordListFree")
)
func GetLastError() (lasterrno int) {
@@ -67,7 +99,11 @@ func LoadLibrary(libname string) (handle uint32, errno int) {
r0, _, e1 := Syscall(procLoadLibraryW, uintptr(unsafe.Pointer(StringToUTF16Ptr(libname))), 0, 0)
handle = uint32(r0)
if handle == 0 {
- errno = int(e1)
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
} else {
errno = 0
}
@@ -78,7 +114,11 @@ func FreeLibrary(handle uint32) (ok bool, errno int) {
r0, _, e1 := Syscall(procFreeLibrary, uintptr(handle), 0, 0)
ok = bool(r0 != 0)
if !ok {
- errno = int(e1)
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
} else {
errno = 0
}
@@ -89,7 +129,11 @@ func GetProcAddress(module uint32, procname string) (proc uint32, errno int) {
r0, _, e1 := Syscall(procGetProcAddress, uintptr(module), uintptr(unsafe.Pointer(StringBytePtr(procname))), 0)
proc = uint32(r0)
if proc == 0 {
- errno = int(e1)
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
} else {
errno = 0
}
@@ -100,7 +144,11 @@ func GetVersion() (ver uint32, errno int) {
r0, _, e1 := Syscall(procGetVersion, 0, 0, 0)
ver = uint32(r0)
if ver == 0 {
- errno = int(e1)
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
} else {
errno = 0
}
@@ -115,7 +163,11 @@ func FormatMessage(flags uint32, msgsrc uint32, msgid uint32, langid uint32, buf
r0, _, e1 := Syscall9(procFormatMessageW, uintptr(flags), uintptr(msgsrc), uintptr(msgid), uintptr(langid), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(args)), 0, 0)
n = uint32(r0)
if n == 0 {
- errno = int(e1)
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
} else {
errno = 0
}
@@ -131,7 +183,11 @@ func CreateFile(name *uint16, access uint32, mode uint32, sa *byte, createmode u
r0, _, e1 := Syscall9(procCreateFileW, uintptr(unsafe.Pointer(name)), uintptr(access), uintptr(mode), uintptr(unsafe.Pointer(sa)), uintptr(createmode), uintptr(attrs), uintptr(templatefile), 0, 0)
handle = int32(r0)
if handle == -1 {
- errno = int(e1)
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
} else {
errno = 0
}
@@ -146,7 +202,11 @@ func ReadFile(handle int32, buf []byte, done *uint32, overlapped *Overlapped) (o
r0, _, e1 := Syscall6(procReadFile, uintptr(handle), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(done)), uintptr(unsafe.Pointer(overlapped)), 0)
ok = bool(r0 != 0)
if !ok {
- errno = int(e1)
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
} else {
errno = 0
}
@@ -161,7 +221,11 @@ func WriteFile(handle int32, buf []byte, done *uint32, overlapped *Overlapped) (
r0, _, e1 := Syscall6(procWriteFile, uintptr(handle), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(done)), uintptr(unsafe.Pointer(overlapped)), 0)
ok = bool(r0 != 0)
if !ok {
- errno = int(e1)
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
} else {
errno = 0
}
@@ -172,7 +236,11 @@ func SetFilePointer(handle int32, lowoffset int32, highoffsetptr *int32, whence
r0, _, e1 := Syscall6(procSetFilePointer, uintptr(handle), uintptr(lowoffset), uintptr(unsafe.Pointer(highoffsetptr)), uintptr(whence), 0, 0)
newlowoffset = uint32(r0)
if newlowoffset == 0xffffffff {
- errno = int(e1)
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
} else {
errno = 0
}
@@ -183,7 +251,11 @@ func CloseHandle(handle int32) (ok bool, errno int) {
r0, _, e1 := Syscall(procCloseHandle, uintptr(handle), 0, 0)
ok = bool(r0 != 0)
if !ok {
- errno = int(e1)
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
} else {
errno = 0
}
@@ -194,7 +266,11 @@ func GetStdHandle(stdhandle int32) (handle int32, errno int) {
r0, _, e1 := Syscall(procGetStdHandle, uintptr(stdhandle), 0, 0)
handle = int32(r0)
if handle == -1 {
- errno = int(e1)
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
} else {
errno = 0
}
@@ -205,7 +281,11 @@ func FindFirstFile(name *uint16, data *Win32finddata) (handle int32, errno int)
r0, _, e1 := Syscall(procFindFirstFileW, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(data)), 0)
handle = int32(r0)
if handle == -1 {
- errno = int(e1)
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
} else {
errno = 0
}
@@ -216,7 +296,11 @@ func FindNextFile(handle int32, data *Win32finddata) (ok bool, errno int) {
r0, _, e1 := Syscall(procFindNextFileW, uintptr(handle), uintptr(unsafe.Pointer(data)), 0)
ok = bool(r0 != 0)
if !ok {
- errno = int(e1)
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
} else {
errno = 0
}
@@ -227,7 +311,11 @@ func FindClose(handle int32) (ok bool, errno int) {
r0, _, e1 := Syscall(procFindClose, uintptr(handle), 0, 0)
ok = bool(r0 != 0)
if !ok {
- errno = int(e1)
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
} else {
errno = 0
}
@@ -238,7 +326,11 @@ func GetFileInformationByHandle(handle int32, data *ByHandleFileInformation) (ok
r0, _, e1 := Syscall(procGetFileInformationByHandle, uintptr(handle), uintptr(unsafe.Pointer(data)), 0)
ok = bool(r0 != 0)
if !ok {
- errno = int(e1)
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
} else {
errno = 0
}
@@ -249,7 +341,11 @@ func GetCurrentDirectory(buflen uint32, buf *uint16) (n uint32, errno int) {
r0, _, e1 := Syscall(procGetCurrentDirectoryW, uintptr(buflen), uintptr(unsafe.Pointer(buf)), 0)
n = uint32(r0)
if n == 0 {
- errno = int(e1)
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
} else {
errno = 0
}
@@ -260,7 +356,11 @@ func SetCurrentDirectory(path *uint16) (ok bool, errno int) {
r0, _, e1 := Syscall(procSetCurrentDirectoryW, uintptr(unsafe.Pointer(path)), 0, 0)
ok = bool(r0 != 0)
if !ok {
- errno = int(e1)
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
} else {
errno = 0
}
@@ -271,7 +371,11 @@ func CreateDirectory(path *uint16, sa *byte) (ok bool, errno int) {
r0, _, e1 := Syscall(procCreateDirectoryW, uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(sa)), 0)
ok = bool(r0 != 0)
if !ok {
- errno = int(e1)
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
} else {
errno = 0
}
@@ -282,7 +386,11 @@ func RemoveDirectory(path *uint16) (ok bool, errno int) {
r0, _, e1 := Syscall(procRemoveDirectoryW, uintptr(unsafe.Pointer(path)), 0, 0)
ok = bool(r0 != 0)
if !ok {
- errno = int(e1)
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
} else {
errno = 0
}
@@ -293,7 +401,11 @@ func DeleteFile(path *uint16) (ok bool, errno int) {
r0, _, e1 := Syscall(procDeleteFileW, uintptr(unsafe.Pointer(path)), 0, 0)
ok = bool(r0 != 0)
if !ok {
- errno = int(e1)
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
} else {
errno = 0
}
@@ -304,7 +416,11 @@ func MoveFile(from *uint16, to *uint16) (ok bool, errno int) {
r0, _, e1 := Syscall(procMoveFileW, uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(to)), 0)
ok = bool(r0 != 0)
if !ok {
- errno = int(e1)
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
} else {
errno = 0
}
@@ -315,7 +431,11 @@ func GetComputerName(buf *uint16, n *uint32) (ok bool, errno int) {
r0, _, e1 := Syscall(procGetComputerNameW, uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(n)), 0)
ok = bool(r0 != 0)
if !ok {
- errno = int(e1)
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
} else {
errno = 0
}
@@ -326,7 +446,11 @@ func SetEndOfFile(handle int32) (ok bool, errno int) {
r0, _, e1 := Syscall(procSetEndOfFile, uintptr(handle), 0, 0)
ok = bool(r0 != 0)
if !ok {
- errno = int(e1)
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
} else {
errno = 0
}
@@ -347,7 +471,11 @@ func GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, errno int) {
r0, _, e1 := Syscall(procGetTimeZoneInformation, uintptr(unsafe.Pointer(tzi)), 0, 0)
rc = uint32(r0)
if rc == 0xffffffff {
- errno = int(e1)
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
} else {
errno = 0
}
@@ -358,7 +486,11 @@ func CreateIoCompletionPort(filehandle int32, cphandle int32, key uint32, thread
r0, _, e1 := Syscall6(procCreateIoCompletionPort, uintptr(filehandle), uintptr(cphandle), uintptr(key), uintptr(threadcnt), 0, 0)
handle = int32(r0)
if handle == 0 {
- errno = int(e1)
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
} else {
errno = 0
}
@@ -369,7 +501,98 @@ func GetQueuedCompletionStatus(cphandle int32, qty *uint32, key *uint32, overlap
r0, _, e1 := Syscall6(procGetQueuedCompletionStatus, uintptr(cphandle), uintptr(unsafe.Pointer(qty)), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(overlapped)), uintptr(timeout), 0)
ok = bool(r0 != 0)
if !ok {
- errno = int(e1)
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func CreateProcess(appName *int16, commandLine *uint16, procSecurity *int16, threadSecurity *int16, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfo, outProcInfo *ProcessInformation) (ok bool, errno int) {
+ var _p0 uint32
+ if inheritHandles {
+ _p0 = 1
+ } else {
+ _p0 = 0
+ }
+ r0, _, e1 := Syscall12(procCreateProcessW, 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)
+ ok = bool(r0 != 0)
+ if !ok {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func GetStartupInfo(startupInfo *StartupInfo) (ok bool, errno int) {
+ r0, _, e1 := Syscall(procGetStartupInfoW, uintptr(unsafe.Pointer(startupInfo)), 0, 0)
+ ok = bool(r0 != 0)
+ if !ok {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func GetCurrentProcess() (pseudoHandle int32, errno int) {
+ r0, _, e1 := Syscall(procGetCurrentProcess, 0, 0, 0)
+ pseudoHandle = int32(r0)
+ if pseudoHandle == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func DuplicateHandle(hSourceProcessHandle int32, hSourceHandle int32, hTargetProcessHandle int32, lpTargetHandle *int32, dwDesiredAccess uint32, bInheritHandle bool, dwOptions uint32) (ok bool, errno int) {
+ var _p0 uint32
+ if bInheritHandle {
+ _p0 = 1
+ } else {
+ _p0 = 0
+ }
+ r0, _, e1 := Syscall9(procDuplicateHandle, uintptr(hSourceProcessHandle), uintptr(hSourceHandle), uintptr(hTargetProcessHandle), uintptr(unsafe.Pointer(lpTargetHandle)), uintptr(dwDesiredAccess), uintptr(_p0), uintptr(dwOptions), 0, 0)
+ ok = bool(r0 != 0)
+ if !ok {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func WaitForSingleObject(handle int32, waitMilliseconds uint32) (event uint32, errno int) {
+ r0, _, e1 := Syscall(procWaitForSingleObject, uintptr(handle), uintptr(waitMilliseconds), 0)
+ event = uint32(r0)
+ if event == 0xffffffff {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
} else {
errno = 0
}
@@ -380,7 +603,242 @@ func GetTempPath(buflen uint32, buf *uint16) (n uint32, errno int) {
r0, _, e1 := Syscall(procGetTempPathW, uintptr(buflen), uintptr(unsafe.Pointer(buf)), 0)
n = uint32(r0)
if n == 0 {
- errno = int(e1)
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func CreatePipe(readhandle *uint32, writehandle *uint32, lpsa *byte, size uint32) (ok bool, errno int) {
+ r0, _, e1 := Syscall6(procCreatePipe, uintptr(unsafe.Pointer(readhandle)), uintptr(unsafe.Pointer(writehandle)), uintptr(unsafe.Pointer(lpsa)), uintptr(size), 0, 0)
+ ok = bool(r0 != 0)
+ if !ok {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func GetFileType(filehandle uint32) (n uint32, errno int) {
+ r0, _, e1 := Syscall(procGetFileType, uintptr(filehandle), 0, 0)
+ n = uint32(r0)
+ if n == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func CryptAcquireContext(provhandle *uint32, container *uint16, provider *uint16, provtype uint32, flags uint32) (ok bool, errno int) {
+ r0, _, e1 := Syscall6(procCryptAcquireContextW, uintptr(unsafe.Pointer(provhandle)), uintptr(unsafe.Pointer(container)), uintptr(unsafe.Pointer(provider)), uintptr(provtype), uintptr(flags), 0)
+ ok = bool(r0 != 0)
+ if !ok {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func CryptReleaseContext(provhandle uint32, flags uint32) (ok bool, errno int) {
+ r0, _, e1 := Syscall(procCryptReleaseContext, uintptr(provhandle), uintptr(flags), 0)
+ ok = bool(r0 != 0)
+ if !ok {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func CryptGenRandom(provhandle uint32, buflen uint32, buf *byte) (ok bool, errno int) {
+ r0, _, e1 := Syscall(procCryptGenRandom, uintptr(provhandle), uintptr(buflen), uintptr(unsafe.Pointer(buf)))
+ ok = bool(r0 != 0)
+ if !ok {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func OpenProcess(da uint32, b int, pid uint32) (handle uint32, errno int) {
+ r0, _, e1 := Syscall(procOpenProcess, uintptr(da), uintptr(b), uintptr(pid))
+ handle = uint32(r0)
+ if handle == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func GetExitCodeProcess(h uint32, c *uint32) (ok bool, errno int) {
+ r0, _, e1 := Syscall(procGetExitCodeProcess, uintptr(h), uintptr(unsafe.Pointer(c)), 0)
+ ok = bool(r0 != 0)
+ if !ok {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func GetEnvironmentStrings() (envs *uint16, errno int) {
+ r0, _, e1 := Syscall(procGetEnvironmentStringsW, 0, 0, 0)
+ envs = (*uint16)(unsafe.Pointer(r0))
+ if envs == nil {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func FreeEnvironmentStrings(envs *uint16) (ok bool, errno int) {
+ r0, _, e1 := Syscall(procFreeEnvironmentStringsW, uintptr(unsafe.Pointer(envs)), 0, 0)
+ ok = bool(r0 != 0)
+ if !ok {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func GetEnvironmentVariable(name *uint16, buffer *uint16, size uint32) (n uint32, errno int) {
+ r0, _, e1 := Syscall(procGetEnvironmentVariableW, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(buffer)), uintptr(size))
+ n = uint32(r0)
+ if n == 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func SetEnvironmentVariable(name *uint16, value *uint16) (ok bool, errno int) {
+ r0, _, e1 := Syscall(procSetEnvironmentVariableW, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(value)), 0)
+ ok = bool(r0 != 0)
+ if !ok {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func SetFileTime(handle int32, ctime *Filetime, atime *Filetime, wtime *Filetime) (ok bool, errno int) {
+ r0, _, e1 := Syscall6(procSetFileTime, uintptr(handle), uintptr(unsafe.Pointer(ctime)), uintptr(unsafe.Pointer(atime)), uintptr(unsafe.Pointer(wtime)), 0, 0)
+ ok = bool(r0 != 0)
+ if !ok {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func GetFileAttributes(name *uint16) (attrs uint32, errno int) {
+ r0, _, e1 := Syscall(procGetFileAttributesW, uintptr(unsafe.Pointer(name)), 0, 0)
+ attrs = uint32(r0)
+ if attrs == INVALID_FILE_ATTRIBUTES {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func GetCommandLine() (cmd *uint16) {
+ r0, _, _ := Syscall(procGetCommandLineW, 0, 0, 0)
+ cmd = (*uint16)(unsafe.Pointer(r0))
+ return
+}
+
+func CommandLineToArgv(cmd *uint16, argc *int32) (argv *[8192]*[8192]uint16, errno int) {
+ r0, _, e1 := Syscall(procCommandLineToArgvW, 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)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func LocalFree(hmem uint32) (handle uint32, errno int) {
+ r0, _, e1 := Syscall(procLocalFree, uintptr(hmem), 0, 0)
+ handle = uint32(r0)
+ if handle != 0 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
} else {
errno = 0
}
@@ -396,7 +854,11 @@ func WSAStartup(verreq uint32, data *WSAData) (sockerrno int) {
func WSACleanup() (errno int) {
r1, _, e1 := Syscall(procWSACleanup, 0, 0, 0)
if int(r1) == -1 {
- errno = int(e1)
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
} else {
errno = 0
}
@@ -407,7 +869,11 @@ func socket(af int32, typ int32, protocol int32) (handle int32, errno int) {
r0, _, e1 := Syscall(procsocket, uintptr(af), uintptr(typ), uintptr(protocol))
handle = int32(r0)
if handle == -1 {
- errno = int(e1)
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
} else {
errno = 0
}
@@ -417,7 +883,11 @@ func socket(af int32, typ int32, protocol int32) (handle int32, errno int) {
func setsockopt(s int32, level int32, optname int32, optval *byte, optlen int32) (errno int) {
r1, _, e1 := Syscall6(procsetsockopt, uintptr(s), uintptr(level), uintptr(optname), uintptr(unsafe.Pointer(optval)), uintptr(optlen), 0)
if int(r1) == -1 {
- errno = int(e1)
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
} else {
errno = 0
}
@@ -427,7 +897,11 @@ func setsockopt(s int32, level int32, optname int32, optval *byte, optlen int32)
func bind(s int32, name uintptr, namelen int32) (errno int) {
r1, _, e1 := Syscall(procbind, uintptr(s), uintptr(name), uintptr(namelen))
if int(r1) == -1 {
- errno = int(e1)
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
} else {
errno = 0
}
@@ -437,7 +911,11 @@ func bind(s int32, name uintptr, namelen int32) (errno int) {
func connect(s int32, name uintptr, namelen int32) (errno int) {
r1, _, e1 := Syscall(procconnect, uintptr(s), uintptr(name), uintptr(namelen))
if int(r1) == -1 {
- errno = int(e1)
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
} else {
errno = 0
}
@@ -447,7 +925,11 @@ func connect(s int32, name uintptr, namelen int32) (errno int) {
func getsockname(s int32, rsa *RawSockaddrAny, addrlen *int32) (errno int) {
r1, _, e1 := Syscall(procgetsockname, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
if int(r1) == -1 {
- errno = int(e1)
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
} else {
errno = 0
}
@@ -457,7 +939,11 @@ func getsockname(s int32, rsa *RawSockaddrAny, addrlen *int32) (errno int) {
func getpeername(s int32, rsa *RawSockaddrAny, addrlen *int32) (errno int) {
r1, _, e1 := Syscall(procgetpeername, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
if int(r1) == -1 {
- errno = int(e1)
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
} else {
errno = 0
}
@@ -467,7 +953,11 @@ func getpeername(s int32, rsa *RawSockaddrAny, addrlen *int32) (errno int) {
func listen(s int32, backlog int32) (errno int) {
r1, _, e1 := Syscall(proclisten, uintptr(s), uintptr(backlog), 0)
if int(r1) == -1 {
- errno = int(e1)
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
} else {
errno = 0
}
@@ -477,7 +967,25 @@ func listen(s int32, backlog int32) (errno int) {
func shutdown(s int32, how int32) (errno int) {
r1, _, e1 := Syscall(procshutdown, uintptr(s), uintptr(how), 0)
if int(r1) == -1 {
- errno = int(e1)
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func Closesocket(s int32) (errno int) {
+ r1, _, e1 := Syscall(procclosesocket, uintptr(s), 0, 0)
+ if int(r1) == -1 {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
} else {
errno = 0
}
@@ -488,7 +996,11 @@ func AcceptEx(ls uint32, as uint32, buf *byte, rxdatalen uint32, laddrlen uint32
r0, _, e1 := Syscall9(procAcceptEx, uintptr(ls), uintptr(as), uintptr(unsafe.Pointer(buf)), uintptr(rxdatalen), uintptr(laddrlen), uintptr(raddrlen), uintptr(unsafe.Pointer(recvd)), uintptr(unsafe.Pointer(overlapped)), 0)
ok = bool(r0 != 0)
if !ok {
- errno = int(e1)
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
} else {
errno = 0
}
@@ -503,7 +1015,11 @@ func GetAcceptExSockaddrs(buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen
func WSARecv(s uint32, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, overlapped *Overlapped, croutine *byte) (errno int) {
r1, _, e1 := Syscall9(procWSARecv, 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 {
- errno = int(e1)
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
} else {
errno = 0
}
@@ -513,9 +1029,88 @@ func WSARecv(s uint32, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32
func WSASend(s uint32, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, overlapped *Overlapped, croutine *byte) (errno int) {
r1, _, e1 := Syscall9(procWSASend, 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 {
- errno = int(e1)
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func WSARecvFrom(s uint32, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, from *RawSockaddrAny, fromlen *int32, overlapped *Overlapped, croutine *byte) (errno int) {
+ r1, _, e1 := Syscall9(procWSARecvFrom, 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)
+ } else {
+ errno = EINVAL
+ }
} else {
errno = 0
}
return
}
+
+func WSASendTo(s uint32, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, to *RawSockaddrAny, tolen int32, overlapped *Overlapped, croutine *byte) (errno int) {
+ r1, _, e1 := Syscall9(procWSASendTo, 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)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func GetHostByName(name string) (h *Hostent, errno int) {
+ r0, _, e1 := Syscall(procgethostbyname, uintptr(unsafe.Pointer(StringBytePtr(name))), 0, 0)
+ h = (*Hostent)(unsafe.Pointer(r0))
+ if h == nil {
+ if e1 != 0 {
+ errno = int(e1)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func GetServByName(name string, proto string) (s *Servent, errno int) {
+ r0, _, e1 := Syscall(procgetservbyname, 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)
+ } else {
+ errno = EINVAL
+ }
+ } else {
+ errno = 0
+ }
+ return
+}
+
+func Ntohs(netshort uint16) (u uint16) {
+ r0, _, _ := Syscall(procntohs, uintptr(netshort), 0, 0)
+ u = uint16(r0)
+ return
+}
+
+func DnsQuery(name string, qtype uint16, options uint32, extra *byte, qrs **DNSRecord, pr *byte) (status uint32) {
+ r0, _, _ := Syscall6(procDnsQuery_W, uintptr(unsafe.Pointer(StringToUTF16Ptr(name))), uintptr(qtype), uintptr(options), uintptr(unsafe.Pointer(extra)), uintptr(unsafe.Pointer(qrs)), uintptr(unsafe.Pointer(pr)))
+ status = uint32(r0)
+ return
+}
+
+func DnsRecordListFree(rl *DNSRecord, freetype uint32) {
+ Syscall(procDnsRecordListFree, uintptr(unsafe.Pointer(rl)), uintptr(freetype), 0)
+ return
+}
diff --git a/src/pkg/syscall/zsysnum_freebsd_386.go b/src/pkg/syscall/zsysnum_freebsd_386.go
index b7c6abeca..a5b7b664f 100644
--- a/src/pkg/syscall/zsysnum_freebsd_386.go
+++ b/src/pkg/syscall/zsysnum_freebsd_386.go
@@ -1,4 +1,4 @@
-// mksysnum_freebsd.sh /usr/src/sys/kern/syscalls.master
+// mksysnum_freebsd.sh
// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
package syscall
@@ -317,4 +317,5 @@ 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_PSELECT = 522 // { int pselect(int nd, fd_set *in, \
)
diff --git a/src/pkg/syscall/zsysnum_freebsd_amd64.go b/src/pkg/syscall/zsysnum_freebsd_amd64.go
index b7c6abeca..4286b487d 100644
--- a/src/pkg/syscall/zsysnum_freebsd_amd64.go
+++ b/src/pkg/syscall/zsysnum_freebsd_amd64.go
@@ -1,4 +1,4 @@
-// mksysnum_freebsd.sh /usr/src/sys/kern/syscalls.master
+// mksysnum_freebsd.sh
// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
package syscall
@@ -317,4 +317,5 @@ 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_PSELECT = 522 // { int pselect(int nd, fd_set *in, \
)
diff --git a/src/pkg/syscall/zsysnum_linux_386.go b/src/pkg/syscall/zsysnum_linux_386.go
index fca0a1a6a..55529adaa 100644
--- a/src/pkg/syscall/zsysnum_linux_386.go
+++ b/src/pkg/syscall/zsysnum_linux_386.go
@@ -262,6 +262,14 @@ const (
SYS_REMAP_FILE_PAGES = 257
SYS_SET_TID_ADDRESS = 258
SYS_TIMER_CREATE = 259
+ SYS_TIMER_SETTIME = 260
+ SYS_TIMER_GETTIME = 261
+ SYS_TIMER_GETOVERRUN = 262
+ SYS_TIMER_DELETE = 263
+ SYS_CLOCK_SETTIME = 264
+ SYS_CLOCK_GETTIME = 265
+ SYS_CLOCK_GETRES = 266
+ SYS_CLOCK_NANOSLEEP = 267
SYS_STATFS64 = 268
SYS_FSTATFS64 = 269
SYS_TGKILL = 270
@@ -272,6 +280,11 @@ const (
SYS_GET_MEMPOLICY = 275
SYS_SET_MEMPOLICY = 276
SYS_MQ_OPEN = 277
+ SYS_MQ_UNLINK = 278
+ SYS_MQ_TIMEDSEND = 279
+ SYS_MQ_TIMEDRECEIVE = 280
+ SYS_MQ_NOTIFY = 281
+ SYS_MQ_GETSETATTR = 282
SYS_KEXEC_LOAD = 283
SYS_WAITID = 284
SYS_ADD_KEY = 286
@@ -310,9 +323,19 @@ const (
SYS_EPOLL_PWAIT = 319
SYS_UTIMENSAT = 320
SYS_SIGNALFD = 321
- SYS_TIMERFD = 322
+ SYS_TIMERFD_CREATE = 322
SYS_EVENTFD = 323
SYS_FALLOCATE = 324
+ SYS_TIMERFD_SETTIME = 325
+ SYS_TIMERFD_GETTIME = 326
+ SYS_SIGNALFD4 = 327
+ SYS_EVENTFD2 = 328
+ SYS_EPOLL_CREATE1 = 329
+ SYS_DUP3 = 330
+ SYS_PIPE2 = 331
+ SYS_INOTIFY_INIT1 = 332
+ SYS_PREADV = 333
+ SYS_PWRITEV = 334
+ SYS_RT_TGSIGQUEUEINFO = 335
+ SYS_PERF_EVENT_OPEN = 336
)
-
-func _darwin_system_call_conflict() {}
diff --git a/src/pkg/syscall/zsysnum_linux_amd64.go b/src/pkg/syscall/zsysnum_linux_amd64.go
index e7a292994..2621999c7 100644
--- a/src/pkg/syscall/zsysnum_linux_amd64.go
+++ b/src/pkg/syscall/zsysnum_linux_amd64.go
@@ -287,9 +287,20 @@ const (
SYS_UTIMENSAT = 280
SYS_EPOLL_PWAIT = 281
SYS_SIGNALFD = 282
- SYS_TIMERFD = 283
+ SYS_TIMERFD_CREATE = 283
SYS_EVENTFD = 284
SYS_FALLOCATE = 285
+ SYS_TIMERFD_SETTIME = 286
+ SYS_TIMERFD_GETTIME = 287
+ SYS_ACCEPT4 = 288
+ SYS_SIGNALFD4 = 289
+ SYS_EVENTFD2 = 290
+ SYS_EPOLL_CREATE1 = 291
+ SYS_DUP3 = 292
+ SYS_PIPE2 = 293
+ SYS_INOTIFY_INIT1 = 294
+ SYS_PREADV = 295
+ SYS_PWRITEV = 296
+ SYS_RT_TGSIGQUEUEINFO = 297
+ SYS_PERF_EVENT_OPEN = 298
)
-
-func _darwin_system_call_conflict() {}
diff --git a/src/pkg/syscall/zsysnum_nacl_386.go b/src/pkg/syscall/zsysnum_nacl_386.go
deleted file mode 100644
index 4099b2507..000000000
--- a/src/pkg/syscall/zsysnum_nacl_386.go
+++ /dev/null
@@ -1,61 +0,0 @@
-// mksysnum_nacl.sh /home/rsc/pub/nacl/native_client/src/trusted/service_runtime/include/bits/nacl_syscalls.h
-// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
-
-package syscall
-
-const (
- SYS_NULL = 1
- SYS_OPEN = 10
- SYS_CLOSE = 11
- SYS_READ = 12
- SYS_WRITE = 13
- SYS_LSEEK = 14
- SYS_IOCTL = 15
- SYS_STAT = 16
- SYS_FSTAT = 17
- SYS_CHMOD = 18
- SYS_SYSBRK = 20
- SYS_MMAP = 21
- SYS_MUNMAP = 22
- SYS_GETDENTS = 23
- SYS_EXIT = 30
- SYS_GETPID = 31
- SYS_SCHED_YIELD = 32
- SYS_SYSCONF = 33
- SYS_GETTIMEOFDAY = 40
- SYS_CLOCK = 41
- SYS_MULTIMEDIA_INIT = 50
- SYS_MULTIMEDIA_SHUTDOWN = 51
- SYS_VIDEO_INIT = 52
- SYS_VIDEO_SHUTDOWN = 53
- SYS_VIDEO_UPDATE = 54
- SYS_VIDEO_POLL_EVENT = 55
- SYS_AUDIO_INIT = 56
- SYS_AUDIO_SHUTDOWN = 57
- SYS_AUDIO_STREAM = 58
- SYS_IMC_MAKEBOUNDSOCK = 60
- SYS_IMC_ACCEPT = 61
- SYS_IMC_CONNECT = 62
- SYS_IMC_SENDMSG = 63
- SYS_IMC_RECVMSG = 64
- SYS_IMC_MEM_OBJ_CREATE = 65
- SYS_IMC_SOCKETPAIR = 66
- SYS_MUTEX_CREATE = 70
- SYS_MUTEX_LOCK = 71
- SYS_MUTEX_TRYLOCK = 72
- SYS_MUTEX_UNLOCK = 73
- SYS_COND_CREATE = 74
- SYS_COND_WAIT = 75
- SYS_COND_SIGNAL = 76
- SYS_COND_BROADCAST = 77
- SYS_COND_TIMED_WAIT_ABS = 79
- SYS_THREAD_CREATE = 80
- SYS_THREAD_EXIT = 81
- SYS_TLS_INIT = 82
- SYS_THREAD_NICE = 83
- SYS_SRPC_GET_FD = 90
- SYS_SEM_CREATE = 100
- SYS_SEM_WAIT = 101
- SYS_SEM_POST = 102
- SYS_SEM_GET_VALUE = 103
-)
diff --git a/src/pkg/syscall/zsysnum_windows_386.go b/src/pkg/syscall/zsysnum_windows_386.go
index 9cccb3ef0..36bf065d1 100644
--- a/src/pkg/syscall/zsysnum_windows_386.go
+++ b/src/pkg/syscall/zsysnum_windows_386.go
@@ -1,4 +1,3 @@
-// mksysnum_nacl.sh /home/rsc/pub/nacl/native_client/src/trusted/service_runtime/include/bits/nacl_syscalls.h
-// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+// nothing to see here
package syscall
diff --git a/src/pkg/syscall/ztypes_linux_386.go b/src/pkg/syscall/ztypes_linux_386.go
index 866c11959..0603168aa 100644
--- a/src/pkg/syscall/ztypes_linux_386.go
+++ b/src/pkg/syscall/ztypes_linux_386.go
@@ -6,19 +6,22 @@ package syscall
// Constants
const (
- sizeofPtr = 0x4
- sizeofShort = 0x2
- sizeofInt = 0x4
- sizeofLong = 0x4
- sizeofLongLong = 0x8
- PathMax = 0x1000
- SizeofSockaddrInet4 = 0x10
- SizeofSockaddrInet6 = 0x1c
- SizeofSockaddrAny = 0x70
- SizeofSockaddrUnix = 0x6e
- SizeofLinger = 0x8
- SizeofMsghdr = 0x1c
- SizeofCmsghdr = 0xc
+ sizeofPtr = 0x4
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x4
+ sizeofLongLong = 0x8
+ PathMax = 0x1000
+ SizeofSockaddrInet4 = 0x10
+ SizeofSockaddrInet6 = 0x1c
+ SizeofSockaddrAny = 0x70
+ SizeofSockaddrUnix = 0x6e
+ SizeofSockaddrLinklayer = 0x14
+ SizeofLinger = 0x8
+ SizeofMsghdr = 0x1c
+ SizeofCmsghdr = 0xc
+ SizeofUcred = 0xc
+ SizeofInotifyEvent = 0x10
)
// Types
@@ -61,6 +64,7 @@ type Timex struct {
Calcnt int32
Errcnt int32
Stbcnt int32
+ Tai int32
Pad0 int32
Pad1 int32
Pad2 int32
@@ -72,7 +76,6 @@ type Timex struct {
Pad8 int32
Pad9 int32
Pad10 int32
- Pad11 int32
}
type Time_t int32
@@ -179,6 +182,16 @@ type RawSockaddrUnix struct {
Path [108]int8
}
+type RawSockaddrLinklayer struct {
+ Family uint16
+ Protocol uint16
+ Ifindex int32
+ Hatype uint16
+ Pkttype uint8
+ Halen uint8
+ Addr [8]uint8
+}
+
type RawSockaddr struct {
Family uint16
Data [14]int8
@@ -217,6 +230,19 @@ type Cmsghdr struct {
Type int32
}
+type Ucred struct {
+ Pid int32
+ Uid uint32
+ Gid uint32
+}
+
+type InotifyEvent struct {
+ Wd int32
+ Mask uint32
+ Cookie uint32
+ Len uint32
+}
+
type PtraceRegs struct {
Ebx int32
Ecx int32
@@ -225,22 +251,16 @@ type PtraceRegs struct {
Edi int32
Ebp int32
Eax int32
- Ds uint16
- X__ds uint16
- Es uint16
- X__es uint16
- Fs uint16
- X__fs uint16
- Gs uint16
- X__gs uint16
+ Xds int32
+ Xes int32
+ Xfs int32
+ Xgs int32
Orig_eax int32
Eip int32
- Cs uint16
- X__cs uint16
+ Xcs int32
Eflags int32
Esp int32
- Ss uint16
- X__ss uint16
+ Xss int32
}
type FdSet struct {
diff --git a/src/pkg/syscall/ztypes_linux_amd64.go b/src/pkg/syscall/ztypes_linux_amd64.go
index a5fc0ab53..b975a8732 100644
--- a/src/pkg/syscall/ztypes_linux_amd64.go
+++ b/src/pkg/syscall/ztypes_linux_amd64.go
@@ -6,19 +6,22 @@ package syscall
// Constants
const (
- sizeofPtr = 0x8
- sizeofShort = 0x2
- sizeofInt = 0x4
- sizeofLong = 0x8
- sizeofLongLong = 0x8
- PathMax = 0x1000
- SizeofSockaddrInet4 = 0x10
- SizeofSockaddrInet6 = 0x1c
- SizeofSockaddrAny = 0x70
- SizeofSockaddrUnix = 0x6e
- SizeofLinger = 0x8
- SizeofMsghdr = 0x38
- SizeofCmsghdr = 0x10
+ sizeofPtr = 0x8
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x8
+ sizeofLongLong = 0x8
+ PathMax = 0x1000
+ SizeofSockaddrInet4 = 0x10
+ SizeofSockaddrInet6 = 0x1c
+ SizeofSockaddrAny = 0x70
+ SizeofSockaddrUnix = 0x6e
+ SizeofSockaddrLinklayer = 0x14
+ SizeofLinger = 0x8
+ SizeofMsghdr = 0x38
+ SizeofCmsghdr = 0x10
+ SizeofUcred = 0xc
+ SizeofInotifyEvent = 0x10
)
// Types
@@ -64,6 +67,7 @@ type Timex struct {
Calcnt int64
Errcnt int64
Stbcnt int64
+ Tai int32
Pad3 int32
Pad4 int32
Pad5 int32
@@ -75,7 +79,6 @@ type Timex struct {
Pad11 int32
Pad12 int32
Pad13 int32
- Pad14 int32
}
type Time_t int64
@@ -119,21 +122,21 @@ type Rlimit struct {
type _Gid_t uint32
type Stat_t struct {
- Dev uint64
- Ino uint64
- Nlink uint64
- Mode uint32
- Uid uint32
- Gid uint32
- Pad0 int32
- Rdev uint64
- Size int64
- Blksize int64
- Blocks int64
- Atim Timespec
- Mtim Timespec
- Ctim Timespec
- __unused [3]int64
+ Dev uint64
+ Ino uint64
+ Nlink uint64
+ Mode uint32
+ Uid uint32
+ Gid uint32
+ X__pad0 int32
+ Rdev uint64
+ Size int64
+ Blksize int64
+ Blocks int64
+ Atim Timespec
+ Mtim Timespec
+ Ctim Timespec
+ X__unused [3]int64
}
type Statfs_t struct {
@@ -179,6 +182,16 @@ type RawSockaddrUnix struct {
Path [108]int8
}
+type RawSockaddrLinklayer struct {
+ Family uint16
+ Protocol uint16
+ Ifindex int32
+ Hatype uint16
+ Pkttype uint8
+ Halen uint8
+ Addr [8]uint8
+}
+
type RawSockaddr struct {
Family uint16
Data [14]int8
@@ -219,6 +232,19 @@ type Cmsghdr struct {
Type int32
}
+type Ucred struct {
+ Pid int32
+ Uid uint32
+ Gid uint32
+}
+
+type InotifyEvent struct {
+ Wd int32
+ Mask uint32
+ Cookie uint32
+ Len uint32
+}
+
type PtraceRegs struct {
R15 uint64
R14 uint64
@@ -268,7 +294,7 @@ type Sysinfo_t struct {
Totalhigh uint64
Freehigh uint64
Unit uint32
- _f [2]int8
+ X_f [2]int8
Pad1 [4]byte
}
diff --git a/src/pkg/syscall/ztypes_linux_arm.go b/src/pkg/syscall/ztypes_linux_arm.go
index 0bf608f4d..450f2008b 100644
--- a/src/pkg/syscall/ztypes_linux_arm.go
+++ b/src/pkg/syscall/ztypes_linux_arm.go
@@ -1,21 +1,32 @@
-// godefs -gsyscall -f-m32 types_linux.c
+// 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
+
package syscall
// Constants
const (
- sizeofPtr = 0x4
- sizeofShort = 0x2
- sizeofInt = 0x4
- sizeofLong = 0x4
- sizeofLongLong = 0x8
- PathMax = 0x1000
- SizeofSockaddrInet4 = 0x10
- SizeofSockaddrInet6 = 0x1c
- SizeofSockaddrAny = 0x1c
- SizeofSockaddrUnix = 0x6e
+ sizeofPtr = 0x4
+ sizeofShort = 0x2
+ sizeofInt = 0x4
+ sizeofLong = 0x4
+ sizeofLongLong = 0x8
+ PathMax = 0x1000
+ SizeofSockaddrInet4 = 0x10
+ SizeofSockaddrInet6 = 0x1c
+ SizeofSockaddrAny = 0x70
+ SizeofSockaddrUnix = 0x6e
+ SizeofSockaddrLinklayer = 0x14
+ SizeofLinger = 0x8
+ SizeofMsghdr = 0x1c
+ SizeofCmsghdr = 0xc
+ SizeofUcred = 0xc
+ SizeofInotifyEvent = 0x10
)
// Types
@@ -58,6 +69,7 @@ type Timex struct {
Calcnt int32
Errcnt int32
Stbcnt int32
+ Tai int32
Pad0 int32
Pad1 int32
Pad2 int32
@@ -69,7 +81,6 @@ type Timex struct {
Pad8 int32
Pad9 int32
Pad10 int32
- Pad11 int32
}
type Time_t int32
@@ -113,24 +124,25 @@ type Rlimit struct {
type _Gid_t uint32
type Stat_t struct {
- Dev uint64
- __pad1 uint16
- Pad0 [2]byte
- __st_ino uint32
- Mode uint32
- Nlink uint32
- Uid uint32
- Gid uint32
- Rdev uint64
- __pad2 uint16
- Pad1 [2]byte
- Size int64
- Blksize int32
- Blocks int64
- Atim Timespec
- Mtim Timespec
- Ctim Timespec
- Ino uint64
+ Dev uint64
+ X__pad1 uint16
+ Pad0 [2]byte
+ X__st_ino uint32
+ Mode uint32
+ Nlink uint32
+ Uid uint32
+ Gid uint32
+ Rdev uint64
+ X__pad2 uint16
+ Pad1 [6]byte
+ Size int64
+ Blksize int32
+ Pad2 [4]byte
+ Blocks int64
+ Atim Timespec
+ Mtim Timespec
+ Ctim Timespec
+ Ino uint64
}
type Statfs_t struct {
@@ -145,6 +157,7 @@ type Statfs_t struct {
Namelen int32
Frsize int32
Spare [5]int32
+ Pad0 [4]byte
}
type Dirent struct {
@@ -152,8 +165,8 @@ type Dirent struct {
Off int64
Reclen uint16
Type uint8
- Name [256]int8
- Pad0 [1]byte
+ Name [256]uint8
+ Pad0 [5]byte
}
type RawSockaddrInet4 struct {
@@ -176,14 +189,24 @@ type RawSockaddrUnix struct {
Path [108]int8
}
+type RawSockaddrLinklayer struct {
+ Family uint16
+ Protocol uint16
+ Ifindex int32
+ Hatype uint16
+ Pkttype uint8
+ Halen uint8
+ Addr [8]uint8
+}
+
type RawSockaddr struct {
Family uint16
- Data [14]int8
+ Data [14]uint8
}
type RawSockaddrAny struct {
Addr RawSockaddr
- Pad [12]int8
+ Pad [96]uint8
}
type _Socklen uint32
@@ -193,32 +216,42 @@ type Linger struct {
Linger int32
}
-type PtraceRegs struct {
- Ebx int32
- Ecx int32
- Edx int32
- Esi int32
- Edi int32
- Ebp int32
- Eax int32
- Ds uint16
- __ds uint16
- Es uint16
- __es uint16
- Fs uint16
- __fs uint16
- Gs uint16
- __gs uint16
- Orig_eax int32
- Eip int32
- Cs uint16
- __cs uint16
- Eflags int32
- Esp int32
- Ss uint16
- __ss uint16
+type Iovec struct {
+ Base *byte
+ Len 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 Ucred struct {
+ Pid int32
+ Uid uint32
+ Gid uint32
+}
+
+type InotifyEvent struct {
+ Wd int32
+ Mask uint32
+ Cookie uint32
+ Len uint32
+}
+
+type PtraceRegs struct{}
+
type FdSet struct {
Bits [32]int32
}
@@ -237,27 +270,28 @@ type Sysinfo_t struct {
Totalhigh uint32
Freehigh uint32
Unit uint32
- _f [8]int8
+ X_f [8]uint8
}
type Utsname struct {
- Sysname [65]int8
- Nodename [65]int8
- Release [65]int8
- Version [65]int8
- Machine [65]int8
- Domainname [65]int8
+ Sysname [65]uint8
+ Nodename [65]uint8
+ Release [65]uint8
+ Version [65]uint8
+ Machine [65]uint8
+ Domainname [65]uint8
}
type Ustat_t struct {
Tfree int32
Tinode uint32
- Fname [6]int8
- Fpack [6]int8
+ Fname [6]uint8
+ Fpack [6]uint8
}
type EpollEvent struct {
Events uint32
+ PadFd int32
Fd int32
Pad int32
}
diff --git a/src/pkg/syscall/ztypes_nacl.go b/src/pkg/syscall/ztypes_nacl.go
deleted file mode 100644
index 4a3465a2e..000000000
--- a/src/pkg/syscall/ztypes_nacl.go
+++ /dev/null
@@ -1,9 +0,0 @@
-// godefs -gsyscall -f-m32 -f-I/home/rsc/pub/nacl/native_client/src/third_party/nacl_sdk/linux/sdk/nacl-sdk/nacl/include -f-I/home/rsc/pub/nacl/native_client/src/trusted/service_runtime/include types_nacl.c
-
-// MACHINE GENERATED - DO NOT EDIT.
-
-package syscall
-
-// Constants
-
-// Types
diff --git a/src/pkg/syscall/ztypes_nacl_386.go b/src/pkg/syscall/ztypes_nacl_386.go
deleted file mode 100644
index 524a196f9..000000000
--- a/src/pkg/syscall/ztypes_nacl_386.go
+++ /dev/null
@@ -1,105 +0,0 @@
-// godefs -gsyscall -f-m32 -f-I/home/rsc/pub/nacl/native_client/src/third_party/nacl_sdk/linux/sdk/nacl-sdk/nacl/include -f-I/home/rsc/pub/nacl/native_client types_nacl.c
-
-// MACHINE GENERATED - DO NOT EDIT.
-
-package syscall
-
-// Constants
-const (
- sizeofPtr = 0x4
- sizeofShort = 0x2
- sizeofInt = 0x4
- sizeofLong = 0x4
- sizeofLongLong = 0x8
- PROT_READ = 0x1
- PROT_WRITE = 0x2
- MAP_SHARED = 0x1
- SYS_FORK = 0
- SYS_PTRACE = 0
- SYS_CHDIR = 0
- SYS_DUP2 = 0
- SYS_FCNTL = 0
- SYS_EXECVE = 0
- O_RDONLY = 0
- O_WRONLY = 0x1
- O_RDWR = 0x2
- O_APPEND = 0x400
- O_ASYNC = 0x2000
- O_CREAT = 0x40
- O_NOCTTY = 0
- O_NONBLOCK = 0x800
- O_SYNC = 0x1000
- O_TRUNC = 0x200
- O_CLOEXEC = 0
- O_EXCL = 0
- F_GETFD = 0x1
- F_SETFD = 0x2
- F_GETFL = 0x3
- F_SETFL = 0x4
- FD_CLOEXEC = 0
- S_IFMT = 0x1f000
- 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
-)
-
-// Types
-
-type _C_short int16
-
-type _C_int int32
-
-type _C_long int32
-
-type _C_long_long int64
-
-type _C_off_t int32
-
-type Timespec struct {
- Sec int32
- Nsec int32
-}
-
-type Timeval struct {
- Sec int32
- Usec int32
-}
-
-type Time_t int32
-
-type _Gid_t uint32
-
-type Stat_t struct {
- Dev int64
- Ino uint32
- Mode uint32
- Nlink uint32
- Uid uint32
- Gid uint32
- __padding int32
- Rdev int64
- Size int32
- Blksize int32
- Blocks int32
- Atime int32
- Mtime int32
- Ctime int32
-}
-
-type Dirent struct {
- Ino uint32
- Off int32
- Reclen uint16
- Name [256]int8
- Pad0 [2]byte
-}
diff --git a/src/pkg/syscall/ztypes_windows_386.go b/src/pkg/syscall/ztypes_windows_386.go
index 315a8ac21..e67165f23 100644
--- a/src/pkg/syscall/ztypes_windows_386.go
+++ b/src/pkg/syscall/ztypes_windows_386.go
@@ -1,7 +1,3 @@
-// godefs -gsyscall -f-m32 types_linux.c
-
-// MACHINE GENERATED - DO NOT EDIT.
-
package syscall
// TODO(brainman): autogenerate types in ztypes_windows_386.go
@@ -22,6 +18,20 @@ const (
)
const (
+ // Windows errors.
+ ERROR_FILE_NOT_FOUND = 2
+ ERROR_PATH_NOT_FOUND = 3
+ ERROR_NO_MORE_FILES = 18
+ ERROR_BROKEN_PIPE = 109
+ ERROR_INSUFFICIENT_BUFFER = 122
+ ERROR_MOD_NOT_FOUND = 126
+ ERROR_PROC_NOT_FOUND = 127
+ ERROR_ENVVAR_NOT_FOUND = 203
+ ERROR_DIRECTORY = 267
+ ERROR_IO_PENDING = 997
+)
+
+const (
// Invented values to support what package os expects.
O_RDONLY = 0x00000
O_WRONLY = 0x00001
@@ -43,6 +53,9 @@ const (
GENERIC_EXECUTE = 0x20000000
GENERIC_ALL = 0x10000000
+ FILE_APPEND_DATA = 0x00000004
+ FILE_WRITE_ATTRIBUTES = 0x00000100
+
FILE_SHARE_READ = 0x00000001
FILE_SHARE_WRITE = 0x00000002
FILE_SHARE_DELETE = 0x00000004
@@ -53,12 +66,18 @@ const (
FILE_ATTRIBUTE_ARCHIVE = 0x00000020
FILE_ATTRIBUTE_NORMAL = 0x00000080
+ INVALID_FILE_ATTRIBUTES = 0xffffffff
+
CREATE_NEW = 1
CREATE_ALWAYS = 2
OPEN_EXISTING = 3
OPEN_ALWAYS = 4
TRUNCATE_EXISTING = 5
+ STARTF_USESTDHANDLES = 0x00000100
+ DUPLICATE_CLOSE_SOURCE = 0x00000001
+ DUPLICATE_SAME_ACCESS = 0x00000002
+
STD_INPUT_HANDLE = -10
STD_OUTPUT_HANDLE = -11
STD_ERROR_HANDLE = -12
@@ -75,7 +94,8 @@ const (
FORMAT_MESSAGE_ARGUMENT_ARRAY = 8192
FORMAT_MESSAGE_MAX_WIDTH_MASK = 255
- MAX_PATH = 260
+ MAX_PATH = 260
+ MAX_LONG_PATH = 32768
MAX_COMPUTERNAME_LENGTH = 15
@@ -83,9 +103,47 @@ const (
TIME_ZONE_ID_STANDARD = 1
TIME_ZONE_ID_DAYLIGHT = 2
+ IGNORE = 0
INFINITE = 0xffffffff
- WAIT_TIMEOUT = 258
+ WAIT_TIMEOUT = 258
+ WAIT_ABANDONED = 0x00000080
+ WAIT_OBJECT_0 = 0x00000000
+ WAIT_FAILED = 0xFFFFFFFF
+
+ CREATE_UNICODE_ENVIRONMENT = 0x00000400
+
+ STANDARD_RIGHTS_READ = 0x00020000
+ PROCESS_QUERY_INFORMATION = 0x00000400
+ SYNCHRONIZE = 0x00100000
+)
+
+const (
+ // wincrypt.h
+ PROV_RSA_FULL = 1
+ PROV_RSA_SIG = 2
+ PROV_DSS = 3
+ PROV_FORTEZZA = 4
+ PROV_MS_EXCHANGE = 5
+ PROV_SSL = 6
+ PROV_RSA_SCHANNEL = 12
+ PROV_DSS_DH = 13
+ PROV_EC_ECDSA_SIG = 14
+ PROV_EC_ECNRA_SIG = 15
+ PROV_EC_ECDSA_FULL = 16
+ PROV_EC_ECNRA_FULL = 17
+ PROV_DH_SCHANNEL = 18
+ PROV_SPYRUS_LYNKS = 20
+ PROV_RNG = 21
+ PROV_INTEL_SEC = 22
+ PROV_REPLACE_OWF = 23
+ PROV_RSA_AES = 24
+ CRYPT_VERIFYCONTEXT = 0xF0000000
+ CRYPT_NEWKEYSET = 0x00000008
+ CRYPT_DELETEKEYSET = 0x00000010
+ CRYPT_MACHINE_KEYSET = 0x00000020
+ CRYPT_SILENT = 0x00000040
+ CRYPT_DEFAULT_CONTAINER_OPTIONAL = 0x00000080
)
// Types
@@ -104,6 +162,16 @@ type Timeval struct {
Usec int32
}
+func (tv *Timeval) Nanoseconds() int64 {
+ return (int64(tv.Sec)*1e6 + int64(tv.Usec)) * 1e3
+}
+
+func NsecToTimeval(nsec int64) (tv Timeval) {
+ tv.Sec = int32(nsec / 1e9)
+ tv.Usec = int32(nsec % 1e9 / 1e3)
+ return
+}
+
type Overlapped struct {
Internal uint32
InternalHigh uint32
@@ -117,14 +185,25 @@ type Filetime struct {
HighDateTime uint32
}
-func (ft *Filetime) Microseconds() int64 {
+func (ft *Filetime) Nanoseconds() int64 {
// 100-nanosecond intervals since January 1, 1601
- ms := int64(ft.HighDateTime)<<32 + int64(ft.LowDateTime)
- // convert into microseconds
- ms /= 10
+ nsec := int64(ft.HighDateTime)<<32 + int64(ft.LowDateTime)
// change starting time to the Epoch (00:00:00 UTC, January 1, 1970)
- ms -= 11644473600000000
- return ms
+ nsec -= 116444736000000000
+ // convert into nanoseconds
+ nsec *= 100
+ return nsec
+}
+
+func NsecToFiletime(nsec int64) (ft Filetime) {
+ // convert into 100-nanosecond
+ nsec /= 100
+ // change starting time to January 1, 1601
+ nsec += 116444736000000000
+ // split into high / low
+ ft.LowDateTime = uint32(nsec & 0xffffffff)
+ ft.HighDateTime = uint32(nsec >> 32 & 0xffffffff)
+ return ft
}
type Win32finddata struct {
@@ -153,6 +232,34 @@ type ByHandleFileInformation struct {
FileIndexLow uint32
}
+type StartupInfo struct {
+ Cb uint32
+ _ *uint16
+ Desktop *uint16
+ Title *uint16
+ X uint32
+ Y uint32
+ XSize uint32
+ YSize uint32
+ XCountChars uint32
+ YCountChars uint32
+ FillAttribute uint32
+ Flags uint32
+ ShowWindow uint16
+ _ uint16
+ _ *byte
+ StdInput int32
+ StdOutput int32
+ StdErr int32
+}
+
+type ProcessInformation struct {
+ Process int32
+ Thread int32
+ ProcessId uint32
+ ThreadId uint32
+}
+
// Invented values to support what package os expects.
type Stat_t struct {
Windata Win32finddata
@@ -183,9 +290,10 @@ type Timezoneinformation struct {
// Socket related.
const (
- AF_UNIX = 1
- AF_INET = 2
- AF_INET6 = 23
+ AF_UNIX = 1
+ AF_INET = 2
+ AF_INET6 = 23
+ AF_NETBIOS = 17
SOCK_STREAM = 1
SOCK_DGRAM = 2
@@ -205,6 +313,9 @@ const (
SO_SNDBUF = 0x1001
SO_UPDATE_ACCEPT_CONTEXT = 0x700b
+ IPPROTO_IPV6 = 0x29
+ IPV6_V6ONLY = 0x1b
+
SOMAXCONN = 5
TCP_NODELAY = 1
@@ -264,3 +375,110 @@ const (
S_IWUSR = 0x80
S_IXUSR = 0x40
)
+
+const (
+ FILE_TYPE_CHAR = 0x0002
+ FILE_TYPE_DISK = 0x0001
+ FILE_TYPE_PIPE = 0x0003
+ FILE_TYPE_REMOTE = 0x8000
+ FILE_TYPE_UNKNOWN = 0x0000
+)
+
+type Hostent struct {
+ Name *byte
+ Aliases **byte
+ AddrType uint16
+ Length uint16
+ AddrList **byte
+}
+
+type Servent struct {
+ Name *byte
+ Aliases **byte
+ Port uint16
+ Proto *byte
+}
+
+const (
+ DNS_TYPE_A = 0x0001
+ DNS_TYPE_NS = 0x0002
+ DNS_TYPE_MD = 0x0003
+ DNS_TYPE_MF = 0x0004
+ DNS_TYPE_CNAME = 0x0005
+ DNS_TYPE_SOA = 0x0006
+ DNS_TYPE_MB = 0x0007
+ DNS_TYPE_MG = 0x0008
+ DNS_TYPE_MR = 0x0009
+ DNS_TYPE_NULL = 0x000a
+ DNS_TYPE_WKS = 0x000b
+ DNS_TYPE_PTR = 0x000c
+ DNS_TYPE_HINFO = 0x000d
+ DNS_TYPE_MINFO = 0x000e
+ DNS_TYPE_MX = 0x000f
+ DNS_TYPE_TEXT = 0x0010
+ DNS_TYPE_RP = 0x0011
+ DNS_TYPE_AFSDB = 0x0012
+ DNS_TYPE_X25 = 0x0013
+ DNS_TYPE_ISDN = 0x0014
+ DNS_TYPE_RT = 0x0015
+ DNS_TYPE_NSAP = 0x0016
+ DNS_TYPE_NSAPPTR = 0x0017
+ DNS_TYPE_SIG = 0x0018
+ DNS_TYPE_KEY = 0x0019
+ DNS_TYPE_PX = 0x001a
+ DNS_TYPE_GPOS = 0x001b
+ DNS_TYPE_AAAA = 0x001c
+ DNS_TYPE_LOC = 0x001d
+ DNS_TYPE_NXT = 0x001e
+ DNS_TYPE_EID = 0x001f
+ DNS_TYPE_NIMLOC = 0x0020
+ DNS_TYPE_SRV = 0x0021
+ DNS_TYPE_ATMA = 0x0022
+ DNS_TYPE_NAPTR = 0x0023
+ DNS_TYPE_KX = 0x0024
+ DNS_TYPE_CERT = 0x0025
+ DNS_TYPE_A6 = 0x0026
+ DNS_TYPE_DNAME = 0x0027
+ DNS_TYPE_SINK = 0x0028
+ DNS_TYPE_OPT = 0x0029
+ DNS_TYPE_DS = 0x002B
+ DNS_TYPE_RRSIG = 0x002E
+ DNS_TYPE_NSEC = 0x002F
+ DNS_TYPE_DNSKEY = 0x0030
+ DNS_TYPE_DHCID = 0x0031
+ DNS_TYPE_UINFO = 0x0064
+ DNS_TYPE_UID = 0x0065
+ DNS_TYPE_GID = 0x0066
+ DNS_TYPE_UNSPEC = 0x0067
+ DNS_TYPE_ADDRS = 0x00f8
+ DNS_TYPE_TKEY = 0x00f9
+ DNS_TYPE_TSIG = 0x00fa
+ DNS_TYPE_IXFR = 0x00fb
+ DNS_TYPE_AXFR = 0x00fc
+ DNS_TYPE_MAILB = 0x00fd
+ DNS_TYPE_MAILA = 0x00fe
+ DNS_TYPE_ALL = 0x00ff
+ DNS_TYPE_ANY = 0x00ff
+ DNS_TYPE_WINS = 0xff01
+ DNS_TYPE_WINSR = 0xff02
+ DNS_TYPE_NBSTAT = 0xff01
+)
+
+type DNSSRVData struct {
+ Target *uint16
+ Priority uint16
+ Weight uint16
+ Port uint16
+ Pad uint16
+}
+
+type DNSRecord struct {
+ Next *DNSRecord
+ Name *uint16
+ Type uint16
+ Length uint16
+ Dw uint32
+ Ttl uint32
+ Reserved uint32
+ Data [40]byte
+}
diff --git a/src/pkg/syslog/Makefile b/src/pkg/syslog/Makefile
index f05d4aef4..cf6863c87 100644
--- a/src/pkg/syslog/Makefile
+++ b/src/pkg/syslog/Makefile
@@ -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 ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=syslog
GOFILES=\
diff --git a/src/pkg/syslog/syslog.go b/src/pkg/syslog/syslog.go
index 527321f57..4924a76d0 100644
--- a/src/pkg/syslog/syslog.go
+++ b/src/pkg/syslog/syslog.go
@@ -140,5 +140,5 @@ func NewLogger(p Priority, flag int) *log.Logger {
if err != nil {
return nil
}
- return log.New(s, nil, "", flag)
+ return log.New(s, "", flag)
}
diff --git a/src/pkg/syslog/syslog_test.go b/src/pkg/syslog/syslog_test.go
index 7fc90678c..063ab71b4 100644
--- a/src/pkg/syslog/syslog_test.go
+++ b/src/pkg/syslog/syslog_test.go
@@ -47,7 +47,7 @@ func TestNew(t *testing.T) {
func TestNewLogger(t *testing.T) {
f := NewLogger(LOG_INFO, 0)
if f == nil {
- t.Errorf("NewLogger() failed\n")
+ t.Error("NewLogger() failed")
}
}
diff --git a/src/pkg/tabwriter/Makefile b/src/pkg/tabwriter/Makefile
index 5beb88f0f..bdc888784 100644
--- a/src/pkg/tabwriter/Makefile
+++ b/src/pkg/tabwriter/Makefile
@@ -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 ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=tabwriter
GOFILES=\
diff --git a/src/pkg/tabwriter/tabwriter.go b/src/pkg/tabwriter/tabwriter.go
index e6ce3232a..848703e8c 100644
--- a/src/pkg/tabwriter/tabwriter.go
+++ b/src/pkg/tabwriter/tabwriter.go
@@ -12,7 +12,6 @@ package tabwriter
import (
"bytes"
- "container/vector"
"io"
"os"
"utf8"
@@ -34,9 +33,8 @@ type cell struct {
}
-// A Writer is a filter that inserts padding around
-// tab-delimited columns in its input to align them
-// in the output.
+// A Writer is a filter that inserts padding around tab-delimited
+// columns in its input to align them in the output.
//
// The Writer treats incoming bytes as UTF-8 encoded text consisting
// of cells terminated by (horizontal or vertical) tabs or line
@@ -48,24 +46,27 @@ type cell struct {
// Note that cells are tab-terminated, not tab-separated: trailing
// non-tab text at the end of a line does not form a column cell.
//
+// The Writer assumes that all Unicode code points have the same width;
+// this may not be true in some fonts.
+//
// If DiscardEmptyColumns is set, empty columns that are terminated
// entirely by vertical (or "soft") tabs are discarded. Columns
// terminated by horizontal (or "hard") tabs are not affected by
// this flag.
//
-// A segment of text may be escaped by bracketing it with Escape
-// characters. The tabwriter strips the Escape characters but otherwise
-// passes escaped text segments through unchanged. In particular, it
-// does not interpret any tabs or line breaks within the segment.
-//
-// The Writer assumes that all characters have the same width;
-// this may not be true in some fonts, especially with certain
-// UTF-8 characters.
-//
// If a Writer is configured to filter HTML, HTML tags and entities
// are simply passed through. The widths of tags and entities are
// assumed to be zero (tags) and one (entities) for formatting purposes.
//
+// A segment of text may be escaped by bracketing it with Escape
+// characters. The tabwriter passes escaped text segments through
+// unchanged. In particular, it does not interpret any tabs or line
+// breaks within the segment. If the StripEscape flag is set, the
+// Escape characters are stripped from the output; otherwise they
+// are passed through as well. For the purpose of formatting, the
+// width of the escaped text is always computed excluding the Escape
+// characters.
+//
// The formfeed character ('\f') acts like a newline but it also
// terminates all columns in the current line (effectively calling
// Flush). Cells in the next line start new columns. Unless found
@@ -86,19 +87,16 @@ type Writer struct {
flags uint
// current state
- buf bytes.Buffer // collected text excluding tabs or line breaks
- pos int // buffer position up to which cell.width of incomplete cell has been computed
- cell cell // current incomplete cell; cell.width is up to buf[pos] excluding ignored sections
- endChar byte // terminating char of escaped sequence (Escape for escapes, '>', ';' for HTML tags/entities, or 0)
- lines vector.Vector // list of lines; each line is a list of cells
- widths vector.IntVector // list of column widths in runes - re-used during formatting
+ buf bytes.Buffer // collected text excluding tabs or line breaks
+ pos int // buffer position up to which cell.width of incomplete cell has been computed
+ cell cell // current incomplete cell; cell.width is up to buf[pos] excluding ignored sections
+ endChar byte // terminating char of escaped sequence (Escape for escapes, '>', ';' for HTML tags/entities, or 0)
+ lines [][]cell // list of lines; each line is a list of cells
+ widths []int // list of column widths in runes - re-used during formatting
}
-func (b *Writer) addLine() { b.lines.Push(new(vector.Vector)) }
-
-
-func (b *Writer) line(i int) *vector.Vector { return b.lines.At(i).(*vector.Vector) }
+func (b *Writer) addLine() { b.lines = append(b.lines, []cell{}) }
// Reset the current state.
@@ -107,8 +105,8 @@ func (b *Writer) reset() {
b.pos = 0
b.cell = cell{}
b.endChar = 0
- b.lines.Resize(0, 0)
- b.widths.Resize(0, 0)
+ b.lines = b.lines[0:0]
+ b.widths = b.widths[0:0]
b.addLine()
}
@@ -122,9 +120,9 @@ func (b *Writer) reset() {
// - cell.width is text width in runes of that cell from the start of the cell to
// position pos; html tags and entities are excluded from this width if html
// filtering is enabled
-// - the sizes and widths of processed text are kept in the lines vector
-// which contains a vector of cells for each line
-// - the widths vector is a temporary vector with current widths used during
+// - the sizes and widths of processed text are kept in the lines list
+// which contains a list of cells for each line
+// - the widths list is a temporary list with current widths used during
// formatting; it is kept in Writer because it's re-used
//
// |<---------- size ---------->|
@@ -143,6 +141,10 @@ const (
// and ending in ';') as single characters (width = 1).
FilterHTML uint = 1 << iota
+ // Strip Escape characters bracketing escaped text segments
+ // instead of passing them through unchanged with the text.
+ StripEscape
+
// Force right-alignment of cell content.
// Default is left-alignment.
AlignRight
@@ -165,7 +167,7 @@ const (
// specifies the filter output. The remaining parameters control the formatting:
//
// minwidth minimal cell width including any padding
-// tabwidth width of tab characters (equivalent number of spaces)
+// tabwidth width of tab characters (equivalent number of spaces)
// padding padding added to a cell before computing its width
// padchar ASCII char used for padding
// if padchar == '\t', the Writer will assume that the
@@ -207,11 +209,9 @@ func (b *Writer) Init(output io.Writer, minwidth, tabwidth, padding int, padchar
// debugging support (keep code around)
func (b *Writer) dump() {
pos := 0
- for i := 0; i < b.lines.Len(); i++ {
- line := b.line(i)
+ for i, line := range b.lines {
print("(", i, ") ")
- for j := 0; j < line.Len(); j++ {
- c := line.At(j).(cell)
+ for _, c := range line {
print("[", string(b.buf.Bytes()[pos:pos+c.size]), "]")
pos += c.size
}
@@ -280,14 +280,12 @@ var vbar = []byte{'|'}
func (b *Writer) writeLines(pos0 int, line0, line1 int) (pos int) {
pos = pos0
for i := line0; i < line1; i++ {
- line := b.line(i)
+ line := b.lines[i]
// if TabIndent is set, use tabs to pad leading empty cells
useTabs := b.flags&TabIndent != 0
- for j := 0; j < line.Len(); j++ {
- c := line.At(j).(cell)
-
+ for j, c := range line {
if j > 0 && b.flags&Debug != 0 {
// indicate column break
b.write0(vbar)
@@ -295,8 +293,8 @@ func (b *Writer) writeLines(pos0 int, line0, line1 int) (pos int) {
if c.size == 0 {
// empty cell
- if j < b.widths.Len() {
- b.writePadding(c.width, b.widths.At(j), useTabs)
+ if j < len(b.widths) {
+ b.writePadding(c.width, b.widths[j], useTabs)
}
} else {
// non-empty cell
@@ -304,12 +302,12 @@ func (b *Writer) writeLines(pos0 int, line0, line1 int) (pos int) {
if b.flags&AlignRight == 0 { // align left
b.write0(b.buf.Bytes()[pos : pos+c.size])
pos += c.size
- if j < b.widths.Len() {
- b.writePadding(c.width, b.widths.At(j), false)
+ if j < len(b.widths) {
+ b.writePadding(c.width, b.widths[j], false)
}
} else { // align right
- if j < b.widths.Len() {
- b.writePadding(c.width, b.widths.At(j), false)
+ if j < len(b.widths) {
+ b.writePadding(c.width, b.widths[j], false)
}
b.write0(b.buf.Bytes()[pos : pos+c.size])
pos += c.size
@@ -317,7 +315,7 @@ func (b *Writer) writeLines(pos0 int, line0, line1 int) (pos int) {
}
}
- if i+1 == b.lines.Len() {
+ if i+1 == len(b.lines) {
// last buffered line - we don't have a newline, so just write
// any outstanding buffered data
b.write0(b.buf.Bytes()[pos : pos+b.cell.size])
@@ -338,11 +336,11 @@ func (b *Writer) writeLines(pos0 int, line0, line1 int) (pos int) {
//
func (b *Writer) format(pos0 int, line0, line1 int) (pos int) {
pos = pos0
- column := b.widths.Len()
+ column := len(b.widths)
for this := line0; this < line1; this++ {
- line := b.line(this)
+ line := b.lines[this]
- if column < line.Len()-1 {
+ if column < len(line)-1 {
// cell exists in this column => this line
// has more cells than the previous line
// (the last cell per line is ignored because cells are
@@ -358,10 +356,10 @@ func (b *Writer) format(pos0 int, line0, line1 int) (pos int) {
width := b.minwidth // minimal column width
discardable := true // true if all cells in this column are empty and "soft"
for ; this < line1; this++ {
- line = b.line(this)
- if column < line.Len()-1 {
+ line = b.lines[this]
+ if column < len(line)-1 {
// cell exists in this column
- c := line.At(column).(cell)
+ c := line[column]
// update width
if w := c.width + b.padding; w > width {
width = w
@@ -383,9 +381,9 @@ func (b *Writer) format(pos0 int, line0, line1 int) (pos int) {
// format and print all columns to the right of this column
// (we know the widths of this column and all columns to the left)
- b.widths.Push(width)
+ b.widths = append(b.widths, width) // push width
pos = b.format(pos, line0, this)
- b.widths.Pop()
+ b.widths = b.widths[0 : len(b.widths)-1] // pop width
line0 = this
}
}
@@ -441,6 +439,9 @@ func (b *Writer) endEscape() {
switch b.endChar {
case Escape:
b.updateWidth()
+ if b.flags&StripEscape == 0 {
+ b.cell.width -= 2 // don't count the Escape chars
+ }
case '>': // tag of zero width
case ';':
b.cell.width++ // entity, count as one rune
@@ -455,10 +456,10 @@ func (b *Writer) endEscape() {
//
func (b *Writer) terminateCell(htab bool) int {
b.cell.htab = htab
- line := b.line(b.lines.Len() - 1)
- line.Push(b.cell)
+ line := &b.lines[len(b.lines)-1]
+ *line = append(*line, b.cell)
b.cell = cell{}
- return line.Len()
+ return len(*line)
}
@@ -488,7 +489,7 @@ func (b *Writer) Flush() (err os.Error) {
}
// format contents of buffer
- b.format(0, 0, b.lines.Len())
+ b.format(0, 0, len(b.lines))
return
}
@@ -538,7 +539,10 @@ func (b *Writer) Write(buf []byte) (n int, err os.Error) {
// start of escaped sequence
b.append(buf[n:i])
b.updateWidth()
- n = i + 1 // exclude Escape
+ n = i
+ if b.flags&StripEscape != 0 {
+ n++ // strip Escape
+ }
b.startEscape(Escape)
case '<', '&':
@@ -557,8 +561,8 @@ func (b *Writer) Write(buf []byte) (n int, err os.Error) {
if ch == b.endChar {
// end of tag/entity
j := i + 1
- if ch == Escape {
- j = i // exclude Escape
+ if ch == Escape && b.flags&StripEscape != 0 {
+ j = i // strip Escape
}
b.append(buf[n:j])
n = i + 1 // ch consumed
diff --git a/src/pkg/tabwriter/tabwriter_test.go b/src/pkg/tabwriter/tabwriter_test.go
index 1cad62530..043d9154e 100644
--- a/src/pkg/tabwriter/tabwriter_test.go
+++ b/src/pkg/tabwriter/tabwriter_test.go
@@ -43,10 +43,10 @@ func (b *buffer) String() string { return string(b.a) }
func write(t *testing.T, testname string, w *Writer, src string) {
written, err := io.WriteString(w, src)
if err != nil {
- t.Errorf("--- test: %s\n--- src:\n%s\n--- write error: %v\n", testname, src, err)
+ t.Errorf("--- test: %s\n--- src:\n%q\n--- write error: %v\n", testname, src, err)
}
if written != len(src) {
- t.Errorf("--- test: %s\n--- src:\n%s\n--- written = %d, len(src) = %d\n", testname, src, written, len(src))
+ t.Errorf("--- test: %s\n--- src:\n%q\n--- written = %d, len(src) = %d\n", testname, src, written, len(src))
}
}
@@ -54,12 +54,12 @@ func write(t *testing.T, testname string, w *Writer, src string) {
func verify(t *testing.T, testname string, w *Writer, b *buffer, src, expected string) {
err := w.Flush()
if err != nil {
- t.Errorf("--- test: %s\n--- src:\n%s\n--- flush error: %v\n", testname, src, err)
+ t.Errorf("--- test: %s\n--- src:\n%q\n--- flush error: %v\n", testname, src, err)
}
res := b.String()
if res != expected {
- t.Errorf("--- test: %s\n--- src:\n%s\n--- found:\n%s\n--- expected:\n%s\n", testname, src, res, expected)
+ t.Errorf("--- test: %s\n--- src:\n%q\n--- found:\n%q\n--- expected:\n%q\n", testname, src, res, expected)
}
}
@@ -72,216 +72,244 @@ func check(t *testing.T, testname string, minwidth, tabwidth, padding int, padch
w.Init(&b, minwidth, tabwidth, padding, padchar, flags)
// write all at once
+ title := testname + " (written all at once)"
b.clear()
- write(t, testname, &w, src)
- verify(t, testname, &w, &b, src, expected)
+ write(t, title, &w, src)
+ verify(t, title, &w, &b, src, expected)
// write byte-by-byte
+ title = testname + " (written byte-by-byte)"
b.clear()
for i := 0; i < len(src); i++ {
- write(t, testname, &w, src[i:i+1])
+ write(t, title, &w, src[i:i+1])
}
- verify(t, testname, &w, &b, src, expected)
+ verify(t, title, &w, &b, src, expected)
// write using Fibonacci slice sizes
+ title = testname + " (written in fibonacci slices)"
b.clear()
for i, d := 0, 0; i < len(src); {
- write(t, testname, &w, src[i:i+d])
+ write(t, title, &w, src[i:i+d])
i, d = i+d, d+1
if i+d > len(src) {
d = len(src) - i
}
}
- verify(t, testname, &w, &b, src, expected)
+ verify(t, title, &w, &b, src, expected)
}
-type entry struct {
+var tests = []struct {
testname string
minwidth, tabwidth, padding int
padchar byte
flags uint
src, expected string
-}
-
-
-var tests = []entry{
- entry{
+}{
+ {
"1a",
8, 0, 1, '.', 0,
"",
"",
},
- entry{
+ {
"1a debug",
8, 0, 1, '.', Debug,
"",
"",
},
- entry{
+ {
+ "1b esc stripped",
+ 8, 0, 1, '.', StripEscape,
+ "\xff\xff",
+ "",
+ },
+
+ {
"1b esc",
8, 0, 1, '.', 0,
"\xff\xff",
- "",
+ "\xff\xff",
+ },
+
+ {
+ "1c esc stripped",
+ 8, 0, 1, '.', StripEscape,
+ "\xff\t\xff",
+ "\t",
},
- entry{
+ {
"1c esc",
8, 0, 1, '.', 0,
"\xff\t\xff",
- "\t",
+ "\xff\t\xff",
},
- entry{
+ {
+ "1d esc stripped",
+ 8, 0, 1, '.', StripEscape,
+ "\xff\"foo\t\n\tbar\"\xff",
+ "\"foo\t\n\tbar\"",
+ },
+
+ {
"1d esc",
8, 0, 1, '.', 0,
"\xff\"foo\t\n\tbar\"\xff",
- "\"foo\t\n\tbar\"",
+ "\xff\"foo\t\n\tbar\"\xff",
+ },
+
+ {
+ "1e esc stripped",
+ 8, 0, 1, '.', StripEscape,
+ "abc\xff\tdef", // unterminated escape
+ "abc\tdef",
},
- entry{
+ {
"1e esc",
8, 0, 1, '.', 0,
"abc\xff\tdef", // unterminated escape
- "abc\tdef",
+ "abc\xff\tdef",
},
- entry{
+ {
"2",
8, 0, 1, '.', 0,
"\n\n\n",
"\n\n\n",
},
- entry{
+ {
"3",
8, 0, 1, '.', 0,
"a\nb\nc",
"a\nb\nc",
},
- entry{
+ {
"4a",
8, 0, 1, '.', 0,
"\t", // '\t' terminates an empty cell on last line - nothing to print
"",
},
- entry{
+ {
"4b",
8, 0, 1, '.', AlignRight,
"\t", // '\t' terminates an empty cell on last line - nothing to print
"",
},
- entry{
+ {
"5",
8, 0, 1, '.', 0,
"*\t*",
"*.......*",
},
- entry{
+ {
"5b",
8, 0, 1, '.', 0,
"*\t*\n",
"*.......*\n",
},
- entry{
+ {
"5c",
8, 0, 1, '.', 0,
"*\t*\t",
"*.......*",
},
- entry{
+ {
"5c debug",
8, 0, 1, '.', Debug,
"*\t*\t",
"*.......|*",
},
- entry{
+ {
"5d",
8, 0, 1, '.', AlignRight,
"*\t*\t",
".......**",
},
- entry{
+ {
"6",
8, 0, 1, '.', 0,
"\t\n",
"........\n",
},
- entry{
+ {
"7a",
8, 0, 1, '.', 0,
"a) foo",
"a) foo",
},
- entry{
+ {
"7b",
8, 0, 1, ' ', 0,
"b) foo\tbar",
"b) foo bar",
},
- entry{
+ {
"7c",
8, 0, 1, '.', 0,
"c) foo\tbar\t",
"c) foo..bar",
},
- entry{
+ {
"7d",
8, 0, 1, '.', 0,
"d) foo\tbar\n",
"d) foo..bar\n",
},
- entry{
+ {
"7e",
8, 0, 1, '.', 0,
"e) foo\tbar\t\n",
"e) foo..bar.....\n",
},
- entry{
+ {
"7f",
8, 0, 1, '.', FilterHTML,
"f) f&lt;o\t<b>bar</b>\t\n",
"f) f&lt;o..<b>bar</b>.....\n",
},
- entry{
+ {
"7g",
8, 0, 1, '.', FilterHTML,
"g) f&lt;o\t<b>bar</b>\t non-terminated entity &amp",
"g) f&lt;o..<b>bar</b>..... non-terminated entity &amp",
},
- entry{
+ {
"7g debug",
8, 0, 1, '.', FilterHTML | Debug,
"g) f&lt;o\t<b>bar</b>\t non-terminated entity &amp",
"g) f&lt;o..|<b>bar</b>.....| non-terminated entity &amp",
},
- entry{
+ {
"8",
8, 0, 1, '*', 0,
"Hello, world!\n",
"Hello, world!\n",
},
- entry{
+ {
"9a",
1, 0, 0, '.', 0,
"1\t2\t3\t4\n" +
@@ -291,7 +319,7 @@ var tests = []entry{
"11222333344444\n",
},
- entry{
+ {
"9b",
1, 0, 0, '.', FilterHTML,
"1\t2<!---\f--->\t3\t4\n" + // \f inside HTML is ignored
@@ -301,7 +329,7 @@ var tests = []entry{
"11222333344444\n",
},
- entry{
+ {
"9c",
1, 0, 0, '.', 0,
"1\t2\t3\t4\f" + // \f causes a newline and flush
@@ -311,7 +339,7 @@ var tests = []entry{
"11222333344444\n",
},
- entry{
+ {
"9c debug",
1, 0, 0, '.', Debug,
"1\t2\t3\t4\f" + // \f causes a newline and flush
@@ -322,21 +350,21 @@ var tests = []entry{
"11|222|3333|44444\n",
},
- entry{
+ {
"10a",
5, 0, 0, '.', 0,
"1\t2\t3\t4\n",
"1....2....3....4\n",
},
- entry{
+ {
"10b",
5, 0, 0, '.', 0,
"1\t2\t3\t4\t\n",
"1....2....3....4....\n",
},
- entry{
+ {
"11",
8, 0, 1, '.', 0,
"本\tb\tc\n" +
@@ -348,7 +376,7 @@ var tests = []entry{
"aaa.....bbbb\n",
},
- entry{
+ {
"12a",
8, 0, 1, ' ', AlignRight,
"a\tè\tc\t\n" +
@@ -360,7 +388,7 @@ var tests = []entry{
" aaa èèèè\n",
},
- entry{
+ {
"12b",
2, 0, 0, ' ', 0,
"a\tb\tc\n" +
@@ -372,7 +400,7 @@ var tests = []entry{
"aaabbbb\n",
},
- entry{
+ {
"12c",
8, 0, 1, '_', 0,
"a\tb\tc\n" +
@@ -384,7 +412,7 @@ var tests = []entry{
"aaa_____bbbb\n",
},
- entry{
+ {
"13a",
4, 0, 1, '-', 0,
"4444\t日本語\t22\t1\t333\n" +
@@ -404,7 +432,7 @@ var tests = []entry{
"1------1------999999999-0000000000\n",
},
- entry{
+ {
"13b",
4, 0, 3, '.', 0,
"4444\t333\t22\t1\t333\n" +
@@ -424,7 +452,7 @@ var tests = []entry{
"1........1........999999999...0000000000\n",
},
- entry{
+ {
"13c",
8, 8, 1, '\t', FilterHTML,
"4444\t333\t22\t1\t333\n" +
@@ -444,7 +472,7 @@ var tests = []entry{
"1\t1\t<font color=red attr=日本語>999999999</font>\t0000000000\n",
},
- entry{
+ {
"14",
1, 0, 2, ' ', AlignRight,
".0\t.3\t2.4\t-5.1\t\n" +
@@ -462,7 +490,7 @@ var tests = []entry{
" .0 1.2 44.4 -13.3",
},
- entry{
+ {
"14 debug",
1, 0, 2, ' ', AlignRight | Debug,
".0\t.3\t2.4\t-5.1\t\n" +
@@ -480,35 +508,35 @@ var tests = []entry{
" .0| 1.2| 44.4| -13.3|",
},
- entry{
+ {
"15a",
4, 0, 0, '.', 0,
"a\t\tb",
"a.......b",
},
- entry{
+ {
"15b",
4, 0, 0, '.', DiscardEmptyColumns,
"a\t\tb", // htabs - do not discard column
"a.......b",
},
- entry{
+ {
"15c",
4, 0, 0, '.', DiscardEmptyColumns,
"a\v\vb",
"a...b",
},
- entry{
+ {
"15d",
4, 0, 0, '.', AlignRight | DiscardEmptyColumns,
"a\v\vb",
"...ab",
},
- entry{
+ {
"16a",
100, 100, 0, '\t', 0,
"a\tb\t\td\n" +
@@ -524,7 +552,7 @@ var tests = []entry{
"a\tb\tc\td\te\n",
},
- entry{
+ {
"16b",
100, 100, 0, '\t', DiscardEmptyColumns,
"a\vb\v\vd\n" +
@@ -540,7 +568,7 @@ var tests = []entry{
"a\tb\tc\td\te\n",
},
- entry{
+ {
"16b debug",
100, 100, 0, '\t', DiscardEmptyColumns | Debug,
"a\vb\v\vd\n" +
@@ -556,7 +584,7 @@ var tests = []entry{
"a\t|b\t|c\t|d\t|e\n",
},
- entry{
+ {
"16c",
100, 100, 0, '\t', DiscardEmptyColumns,
"a\tb\t\td\n" + // hard tabs - do not discard column
@@ -572,7 +600,7 @@ var tests = []entry{
"a\tb\tc\td\te\n",
},
- entry{
+ {
"16c debug",
100, 100, 0, '\t', DiscardEmptyColumns | Debug,
"a\tb\t\td\n" + // hard tabs - do not discard column
diff --git a/src/pkg/template/Makefile b/src/pkg/template/Makefile
index c9c79f799..4915527b4 100644
--- a/src/pkg/template/Makefile
+++ b/src/pkg/template/Makefile
@@ -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 ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=template
GOFILES=\
diff --git a/src/pkg/template/format.go b/src/pkg/template/format.go
index 8a31de970..9156b0808 100644
--- a/src/pkg/template/format.go
+++ b/src/pkg/template/format.go
@@ -16,12 +16,14 @@ import (
// 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, value interface{}, format string) {
- if b, ok := value.([]byte); ok {
- w.Write(b)
- return
+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)
+ fmt.Fprint(w, value...)
}
var (
@@ -60,11 +62,15 @@ func HTMLEscape(w io.Writer, s []byte) {
}
// HTMLFormatter formats arbitrary values for HTML
-func HTMLFormatter(w io.Writer, value interface{}, format string) {
- b, ok := value.([]byte)
+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)
+ fmt.Fprint(&buf, value...)
b = buf.Bytes()
}
HTMLEscape(w, b)
diff --git a/src/pkg/template/template.go b/src/pkg/template/template.go
index 11371abe7..a67dbf8ad 100644
--- a/src/pkg/template/template.go
+++ b/src/pkg/template/template.go
@@ -18,10 +18,11 @@
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])
- - the result of invoking a niladic single-valued method with that name
- (result = data.field())
+
+ - The name of a field of a struct (result = data.field),
+ - The value stored in a map under that key (result = data[field]), or
+ - The result of invoking a niladic single-valued method with that name
+ (result = data.field())
Major constructs ({} are metacharacters; [] marks optional elements):
@@ -43,9 +44,11 @@
is present, ZZZ is executed between iterations of XXX.
{field}
+ {field1 field2 ...}
{field|formatter}
+ {field1 field2...|formatter}
- Insert the value of the field into the output. Field is
+ 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.
@@ -54,9 +57,11 @@
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, data interface{}, formatter string)
- where wr is the destination for output, data is the field
- value, and formatter is its name at the invocation site.
+ func(wr io.Writer, formatter string, data ...interface{})
+ where wr is the destination for output, data holds the field
+ values at the instantiation, and formatter is its name at
+ the invocation site. The default formatter just concatenates
+ the string representations of the fields.
*/
package template
@@ -68,6 +73,8 @@ import (
"os"
"reflect"
"strings"
+ "unicode"
+ "utf8"
)
// Errors returned during parsing and execution. Users may extract the information and reformat
@@ -100,7 +107,7 @@ const (
// FormatterMap is the type describing the mapping from formatter
// names to the functions that implement them.
-type FormatterMap map[string]func(io.Writer, interface{}, string)
+type FormatterMap map[string]func(io.Writer, string, ...interface{})
// Built-in formatters.
var builtins = FormatterMap{
@@ -122,11 +129,11 @@ type literalElement struct {
text []byte
}
-// A variable to be evaluated
+// A variable invocation to be evaluated
type variableElement struct {
linenum int
- name string
- formatter string // TODO(r): implement pipelines
+ word []string // The fields in the invocation.
+ formatter string // TODO(r): implement pipelines
}
// A .section block, possibly with a .or
@@ -184,13 +191,19 @@ func New(fmap FormatterMap) *Template {
// 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)})
+ 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)})
+ 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
@@ -216,12 +229,10 @@ func equal(s []byte, n int, t []byte) bool {
// 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 the white space on
+// Action tokens on a line by themselves drop any space on
// either side, up to and including the newline.
func (t *Template) nextItem() []byte {
- special := false // is this a {.foo} directive, which means trim white space?
- // Delete surrounding white space if this {.foo} is the only thing on the line.
- trimSpace := t.p == 0 || t.buf[t.p-1] == '\n'
+ startOfLine := t.p == 0 || t.buf[t.p-1] == '\n'
start := t.p
var i int
newline := func() {
@@ -234,13 +245,7 @@ func (t *Template) nextItem() []byte {
break
}
}
- if trimSpace {
- start = i
- } else if i > start {
- // white space is valid text
- t.p = i
- return t.buf[start:i]
- }
+ leadingSpace := i > start
// What's left is nothing, newline, delimited string, or plain text
Switch:
switch {
@@ -249,21 +254,50 @@ Switch:
case t.buf[i] == '\n':
newline()
case equal(t.buf, i, t.ldelim):
- i += len(t.ldelim) // position after delimiter
- if i+1 < len(t.buf) && (t.buf[i] == '.' || t.buf[i] == '#') {
- special = true
- }
+ left := i // Start of left delimiter.
+ right := -1 // Will be (immediately after) right delimiter.
+ haveText := false // Delimiters contain text.
+ i += len(t.ldelim)
+ // Find the end of the action.
for ; i < len(t.buf); i++ {
if t.buf[i] == '\n' {
break
}
if equal(t.buf, i, t.rdelim) {
i += len(t.rdelim)
- break Switch
+ right = i
+ break
+ }
+ haveText = true
+ }
+ if right < 0 {
+ t.parseError("unmatched opening delimiter")
+ return nil
+ }
+ // Is this a special action (starts with '.' or '#') and the only thing on the line?
+ if startOfLine && haveText {
+ firstChar := t.buf[left+len(t.ldelim)]
+ if firstChar == '.' || firstChar == '#' {
+ // It's special and the first thing on the line. Is it the last?
+ for j := right; j < len(t.buf) && white(t.buf[j]); j++ {
+ if t.buf[j] == '\n' {
+ // Yes it is. Drop the surrounding space and return the {.foo}
+ t.linenum++
+ t.p = j + 1
+ return t.buf[left:right]
+ }
+ }
}
}
- t.parseError("unmatched opening delimiter")
- return nil
+ // No it's not. If there's leading space, return that.
+ if leadingSpace {
+ // not trimming space: return leading white space if there is some.
+ t.p = left
+ return t.buf[start:left]
+ }
+ // Return the word, leave the trailing space.
+ start = left
+ break
default:
for ; i < len(t.buf); i++ {
if t.buf[i] == '\n' {
@@ -276,15 +310,6 @@ Switch:
}
}
item := t.buf[start:i]
- if special && trimSpace {
- // consume trailing white space
- for ; i < len(t.buf) && white(t.buf[i]); i++ {
- if t.buf[i] == '\n' {
- newline()
- break // stop before newline
- }
- }
- }
t.p = i
return item
}
@@ -305,15 +330,7 @@ func words(buf []byte) []string {
if start == p { // no text left
break
}
- if i == cap(s) {
- ns := make([]string, 2*cap(s))
- for j := range s {
- ns[j] = s[j]
- }
- s = ns
- }
- s = s[0 : i+1]
- s[i] = string(buf[start:p])
+ s = append(s, string(buf[start:p]))
}
return s
}
@@ -345,7 +362,7 @@ func (t *Template) analyze(item []byte) (tok int, w []string) {
t.parseError("empty directive")
return
}
- if len(w) == 1 && w[0][0] != '.' {
+ if len(w) > 0 && w[0][0] != '.' {
tok = tokVariable
return
}
@@ -388,16 +405,18 @@ func (t *Template) analyze(item []byte) (tok int, w []string) {
// -- Parsing
// Allocate a new variable-evaluation element.
-func (t *Template) newVariable(name_formatter string) (v *variableElement) {
- name := name_formatter
+func (t *Template) newVariable(words []string) (v *variableElement) {
+ // The words are tokenized elements from the {item}. The last one may be of
+ // the form "|fmt". For example: {a b c|d}
formatter := ""
- bar := strings.Index(name_formatter, "|")
+ lastWord := words[len(words)-1]
+ bar := strings.Index(lastWord, "|")
if bar >= 0 {
- name = name_formatter[0:bar]
- formatter = name_formatter[bar+1:]
+ words[len(words)-1] = lastWord[0:bar]
+ formatter = lastWord[bar+1:]
}
// Probably ok, so let's build it.
- v = &variableElement{t.linenum, name, formatter}
+ v = &variableElement{t.linenum, words, formatter}
// We could remember the function address here and avoid the lookup later,
// but it's more dynamic to let the user change the map contents underfoot.
@@ -443,7 +462,7 @@ func (t *Template) parseSimple(item []byte) (done bool, tok int, w []string) {
}
return
case tokVariable:
- t.elems.Push(t.newVariable(w[0]))
+ t.elems.Push(t.newVariable(w))
return
}
return false, tok, w
@@ -577,17 +596,17 @@ func (t *Template) parse() {
// 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 lookup(v reflect.Value, name string) reflect.Value {
+func (t *Template) lookup(st *state, v reflect.Value, name string) reflect.Value {
for v != nil {
typ := v.Type()
if n := v.Type().NumMethod(); n > 0 {
for i := 0; i < n; i++ {
m := typ.Method(i)
mtyp := m.Type
- // We must check receiver type because of a bug in the reflection type tables:
- // it should not be possible to find a method with the wrong receiver type but
- // this can happen due to value/pointer receiver mismatch.
- if m.Name == name && mtyp.NumIn() == 1 && mtyp.NumOut() == 1 && mtyp.In(0) == typ {
+ 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]
}
}
@@ -598,6 +617,9 @@ func lookup(v reflect.Value, name string) reflect.Value {
case *reflect.InterfaceValue:
v = av.Elem()
case *reflect.StructValue:
+ if !isExported(name) {
+ t.execError(st, t.linenum, "name not exported: %s in type %s", name, st.data.Type())
+ }
return av.FieldByName(name)
case *reflect.MapValue:
return av.Elem(reflect.NewValue(name))
@@ -630,14 +652,14 @@ loop:
// The value coming in (st.data) might need indirecting to reach
// a struct while the return value is not indirected - that is,
// it represents the actual named field.
-func (st *state) findVar(s string) reflect.Value {
+func (t *Template) findVar(st *state, s string) reflect.Value {
if s == "@" {
return st.data
}
data := st.data
for _, elem := range strings.Split(s, ".", -1) {
// Look up field; data must be a struct or map.
- data = lookup(data, elem)
+ data = t.lookup(st, data, elem)
if data == nil {
return nil
}
@@ -665,12 +687,12 @@ func empty(v reflect.Value) bool {
case *reflect.SliceValue:
return v.Len() == 0
}
- return true
+ 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 := st.findVar(name)
+ field := t.findVar(st, name)
if field == nil {
if st.parent == nil {
t.execError(st, t.linenum, "name not found: %s in type %s", name, st.data.Type())
@@ -684,20 +706,24 @@ func (t *Template) varValue(name string, st *state) reflect.Value {
// If it has a formatter attached ({var|formatter}) run that too.
func (t *Template) writeVariable(v *variableElement, st *state) {
formatter := v.formatter
- val := t.varValue(v.name, st).Interface()
+ // Turn the words of the invocation into values.
+ val := make([]interface{}, len(v.word))
+ for i, word := range v.word {
+ val[i] = t.varValue(word, st).Interface()
+ }
// is it in user-supplied map?
if t.fmap != nil {
if fn, ok := t.fmap[formatter]; ok {
- fn(st.wr, val, formatter)
+ fn(st.wr, formatter, val...)
return
}
}
// is it in builtin map?
if fn, ok := builtins[formatter]; ok {
- fn(st.wr, val, formatter)
+ fn(st.wr, formatter, val...)
return
}
- t.execError(st, v.linenum, "missing formatter %s for variable %s", formatter, v.name)
+ t.execError(st, v.linenum, "missing formatter %s for variable %s", formatter, v.word[0])
}
// Execute element i. Return next index to execute.
@@ -888,6 +914,16 @@ func (t *Template) Parse(s string) (err os.Error) {
return nil
}
+// ParseFile is like Parse but reads the template definition from the
+// named file.
+func (t *Template) ParseFile(filename string) (err os.Error) {
+ b, err := ioutil.ReadFile(filename)
+ if err != nil {
+ return err
+ }
+ return t.Parse(string(b))
+}
+
// Execute applies a parsed template to the specified data object,
// generating output to wr.
func (t *Template) Execute(data interface{}, wr io.Writer) (err os.Error) {
diff --git a/src/pkg/template/template_test.go b/src/pkg/template/template_test.go
index a6267bfcc..57f297e8f 100644
--- a/src/pkg/template/template_test.go
+++ b/src/pkg/template/template_test.go
@@ -12,6 +12,7 @@ import (
"io/ioutil"
"json"
"os"
+ "strings"
"testing"
)
@@ -20,40 +21,40 @@ type Test struct {
}
type T struct {
- item string
- value string
+ Item string
+ Value string
}
type U struct {
- mp map[string]int
+ Mp map[string]int
}
type S struct {
- header string
- integer int
- raw string
- innerT T
- innerPointerT *T
- data []T
- pdata []*T
- empty []*T
- emptystring string
- null []*T
- vec *vector.Vector
- true bool
- false bool
- mp map[string]string
- json interface{}
- innermap U
- stringmap map[string]string
- bytes []byte
- iface interface{}
- ifaceptr interface{}
+ Header string
+ Integer int
+ Raw string
+ InnerT T
+ InnerPointerT *T
+ Data []T
+ Pdata []*T
+ Empty []*T
+ Emptystring string
+ Null []*T
+ Vec *vector.Vector
+ True bool
+ False bool
+ Mp map[string]string
+ JSON interface{}
+ Innermap U
+ Stringmap map[string]string
+ Bytes []byte
+ Iface interface{}
+ Ifaceptr interface{}
}
-func (s *S) pointerMethod() string { return "ptrmethod!" }
+func (s *S) PointerMethod() string { return "ptrmethod!" }
-func (s S) valueMethod() string { return "valmethod!" }
+func (s S) ValueMethod() string { return "valmethod!" }
var t1 = T{"ItemNumber1", "ValueNumber1"}
var t2 = T{"ItemNumber2", "ValueNumber2"}
@@ -76,16 +77,25 @@ func plus1(v interface{}) string {
return fmt.Sprint(i + 1)
}
-func writer(f func(interface{}) string) func(io.Writer, interface{}, string) {
- return func(w io.Writer, v interface{}, format string) {
- io.WriteString(w, f(v))
+func writer(f func(interface{}) string) func(io.Writer, string, ...interface{}) {
+ return func(w io.Writer, format string, v ...interface{}) {
+ if len(v) != 1 {
+ panic("test writer expected one arg")
+ }
+ io.WriteString(w, f(v[0]))
}
}
+func multiword(w io.Writer, format string, value ...interface{}) {
+ for _, v := range value {
+ fmt.Fprintf(w, "<%v>", v)
+ }
+}
var formatters = FormatterMap{
"uppercase": writer(uppercase),
"+1": writer(plus1),
+ "multiword": multiword,
}
var tests = []*Test{
@@ -98,51 +108,53 @@ var tests = []*Test{
&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",
+ in: "{Header}={Integer}\n",
out: "Header=77\n",
},
// Method at top level
&Test{
- in: "ptrmethod={pointerMethod}\n",
+ in: "ptrmethod={PointerMethod}\n",
out: "ptrmethod=ptrmethod!\n",
},
&Test{
- in: "valmethod={valueMethod}\n",
+ in: "valmethod={ValueMethod}\n",
out: "valmethod=valmethod!\n",
},
// Section
&Test{
- in: "{.section data }\n" +
+ 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" +
+ in: "{.section Data }\n" +
+ "{Header}={Integer}\n" +
"{.end}\n",
out: "Header=77\n",
},
&Test{
- in: "{.section pdata }\n" +
- "{header}={integer}\n" +
+ in: "{.section Pdata }\n" +
+ "{Header}={Integer}\n" +
"{.end}\n",
out: "Header=77\n",
},
&Test{
- in: "{.section pdata }\n" +
+ in: "{.section Pdata }\n" +
"data present\n" +
"{.or}\n" +
"data not present\n" +
@@ -151,7 +163,7 @@ var tests = []*Test{
out: "data present\n",
},
&Test{
- in: "{.section empty }\n" +
+ in: "{.section Empty }\n" +
"data present\n" +
"{.or}\n" +
"data not present\n" +
@@ -160,7 +172,7 @@ var tests = []*Test{
out: "data not present\n",
},
&Test{
- in: "{.section null }\n" +
+ in: "{.section Null }\n" +
"data present\n" +
"{.or}\n" +
"data not present\n" +
@@ -169,10 +181,10 @@ var tests = []*Test{
out: "data not present\n",
},
&Test{
- in: "{.section pdata }\n" +
- "{header}={integer}\n" +
+ in: "{.section Pdata }\n" +
+ "{Header}={Integer}\n" +
"{.section @ }\n" +
- "{header}={integer}\n" +
+ "{Header}={Integer}\n" +
"{.end}\n" +
"{.end}\n",
@@ -181,16 +193,23 @@ var tests = []*Test{
},
&Test{
- in: "{.section data}{.end} {header}\n",
+ in: "{.section Data}{.end} {Header}\n",
out: " Header\n",
},
+ &Test{
+ in: "{.section Integer}{@}{.end}",
+
+ out: "77",
+ },
+
+
// Repeated
&Test{
- in: "{.section pdata }\n" +
+ in: "{.section Pdata }\n" +
"{.repeated section @ }\n" +
- "{item}={value}\n" +
+ "{Item}={Value}\n" +
"{.end}\n" +
"{.end}\n",
@@ -198,9 +217,9 @@ var tests = []*Test{
"ItemNumber2=ValueNumber2\n",
},
&Test{
- in: "{.section pdata }\n" +
+ in: "{.section Pdata }\n" +
"{.repeated section @ }\n" +
- "{item}={value}\n" +
+ "{Item}={Value}\n" +
"{.or}\n" +
"this should not appear\n" +
"{.end}\n" +
@@ -211,8 +230,8 @@ var tests = []*Test{
},
&Test{
in: "{.section @ }\n" +
- "{.repeated section empty }\n" +
- "{item}={value}\n" +
+ "{.repeated section Empty }\n" +
+ "{Item}={Value}\n" +
"{.or}\n" +
"this should appear: empty field\n" +
"{.end}\n" +
@@ -221,8 +240,8 @@ var tests = []*Test{
out: "this should appear: empty field\n",
},
&Test{
- in: "{.repeated section pdata }\n" +
- "{item}\n" +
+ in: "{.repeated section Pdata }\n" +
+ "{Item}\n" +
"{.alternates with}\n" +
"is\nover\nmultiple\nlines\n" +
"{.end}\n",
@@ -232,8 +251,8 @@ var tests = []*Test{
"ItemNumber2\n",
},
&Test{
- in: "{.repeated section pdata }\n" +
- "{item}\n" +
+ in: "{.repeated section Pdata }\n" +
+ "{Item}\n" +
"{.alternates with}\n" +
"is\nover\nmultiple\nlines\n" +
" {.end}\n",
@@ -243,9 +262,9 @@ var tests = []*Test{
"ItemNumber2\n",
},
&Test{
- in: "{.section pdata }\n" +
+ in: "{.section Pdata }\n" +
"{.repeated section @ }\n" +
- "{item}={value}\n" +
+ "{Item}={Value}\n" +
"{.alternates with}DIVIDER\n" +
"{.or}\n" +
"this should not appear\n" +
@@ -257,7 +276,7 @@ var tests = []*Test{
"ItemNumber2=ValueNumber2\n",
},
&Test{
- in: "{.repeated section vec }\n" +
+ in: "{.repeated section Vec }\n" +
"{@}\n" +
"{.end}\n",
@@ -266,28 +285,28 @@ var tests = []*Test{
},
// Same but with a space before {.end}: was a bug.
&Test{
- in: "{.repeated section vec }\n" +
+ in: "{.repeated section Vec }\n" +
"{@} {.end}\n",
out: "elt1 elt2 \n",
},
&Test{
- in: "{.repeated section integer}{.end}",
+ in: "{.repeated section Integer}{.end}",
- err: "line 1: .repeated: cannot repeat integer (type int)",
+ err: "line 1: .repeated: cannot repeat Integer (type int)",
},
// Nested names
&Test{
in: "{.section @ }\n" +
- "{innerT.item}={innerT.value}\n" +
+ "{InnerT.Item}={InnerT.Value}\n" +
"{.end}",
out: "ItemNumber1=ValueNumber1\n",
},
&Test{
in: "{.section @ }\n" +
- "{innerT.item}={.section innerT}{.section value}{@}{.end}{.end}\n" +
+ "{InnerT.Item}={.section InnerT}{.section Value}{@}{.end}{.end}\n" +
"{.end}",
out: "ItemNumber1=ValueNumber1\n",
@@ -296,9 +315,9 @@ var tests = []*Test{
// Formatters
&Test{
- in: "{.section pdata }\n" +
- "{header|uppercase}={integer|+1}\n" +
- "{header|html}={integer|str}\n" +
+ in: "{.section Pdata }\n" +
+ "{Header|uppercase}={Integer|+1}\n" +
+ "{Header|html}={Integer|str}\n" +
"{.end}\n",
out: "HEADER=78\n" +
@@ -306,29 +325,41 @@ var tests = []*Test{
},
&Test{
- in: "{raw}\n" +
- "{raw|html}\n",
+ in: "{.section Pdata }\n" +
+ "{Header|uppercase}={Integer Header|multiword}\n" +
+ "{Header|html}={Header Integer|multiword}\n" +
+ "{Header|html}={Header Integer}\n" +
+ "{.end}\n",
+
+ out: "HEADER=<77><Header>\n" +
+ "Header=<Header><77>\n" +
+ "Header=Header77\n",
+ },
+
+ &Test{
+ in: "{Raw}\n" +
+ "{Raw|html}\n",
out: "&<>!@ #$%^\n" +
"&amp;&lt;&gt;!@ #$%^\n",
},
&Test{
- in: "{.section emptystring}emptystring{.end}\n" +
- "{.section header}header{.end}\n",
+ 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",
+ in: "{.section True}1{.or}2{.end}\n" +
+ "{.section False}3{.or}4{.end}\n",
out: "1\n4\n",
},
&Test{
- in: "{bytes}",
+ in: "{Bytes}",
out: "hello",
},
@@ -336,58 +367,66 @@ var tests = []*Test{
// Maps
&Test{
- in: "{mp.mapkey}\n",
+ in: "{Mp.mapkey}\n",
out: "Ahoy!\n",
},
&Test{
- in: "{innermap.mp.innerkey}\n",
+ in: "{Innermap.Mp.innerkey}\n",
out: "55\n",
},
&Test{
- in: "{.section innermap}{.section mp}{innerkey}{.end}{.end}\n",
+ in: "{.section Innermap}{.section Mp}{innerkey}{.end}{.end}\n",
out: "55\n",
},
&Test{
- in: "{.section json}{.repeated section maps}{a}{b}{.end}{.end}\n",
+ in: "{.section JSON}{.repeated section maps}{a}{b}{.end}{.end}\n",
out: "1234\n",
},
&Test{
- in: "{stringmap.stringkey1}\n",
+ in: "{Stringmap.stringkey1}\n",
out: "stringresult\n",
},
&Test{
- in: "{.repeated section stringmap}\n" +
+ in: "{.repeated section Stringmap}\n" +
"{@}\n" +
"{.end}",
out: "stringresult\n" +
"stringresult\n",
},
+ &Test{
+ in: "{.repeated section Stringmap}\n" +
+ "\t{@}\n" +
+ "{.end}",
+
+ out: "\tstringresult\n" +
+ "\tstringresult\n",
+ },
// Interface values
&Test{
- in: "{iface}",
+ in: "{Iface}",
out: "[1 2 3]",
},
&Test{
- in: "{.repeated section iface}{@}{.alternates with} {.end}",
+ in: "{.repeated section Iface}{@}{.alternates with} {.end}",
out: "1 2 3",
},
&Test{
- in: "{.section iface}{@}{.end}",
+ in: "{.section Iface}{@}{.end}",
out: "[1 2 3]",
},
&Test{
- in: "{.section ifaceptr}{item} {value}{.end}",
+ in: "{.section Ifaceptr}{Item} {Value}{.end}",
out: "Item Value",
},
@@ -398,45 +437,59 @@ func TestAll(t *testing.T) {
testAll(t, func(test *Test) (*Template, os.Error) { return Parse(test.in, formatters) })
// ParseFile
testAll(t, func(test *Test) (*Template, os.Error) {
- ioutil.WriteFile("_test/test.tmpl", []byte(test.in), 0600)
+ err := ioutil.WriteFile("_test/test.tmpl", []byte(test.in), 0600)
+ if err != nil {
+ t.Error("unexpected write error:", err)
+ return nil, err
+ }
return ParseFile("_test/test.tmpl", formatters)
})
+ // tmpl.ParseFile
+ testAll(t, func(test *Test) (*Template, os.Error) {
+ err := ioutil.WriteFile("_test/test.tmpl", []byte(test.in), 0600)
+ if err != nil {
+ t.Error("unexpected write error:", err)
+ return nil, err
+ }
+ tmpl := New(formatters)
+ return tmpl, tmpl.ParseFile("_test/test.tmpl")
+ })
}
func testAll(t *testing.T, parseFunc func(*Test) (*Template, os.Error)) {
s := new(S)
// initialized by hand for clarity.
- s.header = "Header"
- s.integer = 77
- s.raw = "&<>!@ #$%^"
- s.innerT = t1
- s.data = []T{t1, t2}
- s.pdata = []*T{&t1, &t2}
- s.empty = []*T{}
- s.null = nil
- s.vec = new(vector.Vector)
- s.vec.Push("elt1")
- s.vec.Push("elt2")
- s.true = true
- s.false = false
- s.mp = make(map[string]string)
- s.mp["mapkey"] = "Ahoy!"
- json.Unmarshal([]byte(`{"maps":[{"a":1,"b":2},{"a":3,"b":4}]}`), &s.json)
- s.innermap.mp = make(map[string]int)
- s.innermap.mp["innerkey"] = 55
- s.stringmap = make(map[string]string)
- s.stringmap["stringkey1"] = "stringresult" // the same value so repeated section is order-independent
- s.stringmap["stringkey2"] = "stringresult"
- s.bytes = []byte("hello")
- s.iface = []int{1, 2, 3}
- s.ifaceptr = &T{"Item", "Value"}
+ s.Header = "Header"
+ s.Integer = 77
+ s.Raw = "&<>!@ #$%^"
+ s.InnerT = t1
+ s.Data = []T{t1, t2}
+ s.Pdata = []*T{&t1, &t2}
+ s.Empty = []*T{}
+ s.Null = nil
+ s.Vec = new(vector.Vector)
+ s.Vec.Push("elt1")
+ s.Vec.Push("elt2")
+ s.True = true
+ s.False = false
+ s.Mp = make(map[string]string)
+ s.Mp["mapkey"] = "Ahoy!"
+ json.Unmarshal([]byte(`{"maps":[{"a":1,"b":2},{"a":3,"b":4}]}`), &s.JSON)
+ s.Innermap.Mp = make(map[string]int)
+ s.Innermap.Mp["innerkey"] = 55
+ s.Stringmap = make(map[string]string)
+ s.Stringmap["stringkey1"] = "stringresult" // the same value so repeated section is order-independent
+ s.Stringmap["stringkey2"] = "stringresult"
+ s.Bytes = []byte("hello")
+ s.Iface = []int{1, 2, 3}
+ s.Ifaceptr = &T{"Item", "Value"}
var buf bytes.Buffer
for _, test := range tests {
buf.Reset()
tmpl, err := parseFunc(test)
if err != nil {
- t.Error("unexpected parse error:", err)
+ t.Error("unexpected parse error: ", err)
continue
}
err = tmpl.Execute(s, &buf)
@@ -555,10 +608,10 @@ func TestCustomDelims(t *testing.T) {
func TestVarIndirection(t *testing.T) {
s := new(S)
// initialized by hand for clarity.
- s.innerPointerT = &t1
+ s.InnerPointerT = &t1
var buf bytes.Buffer
- input := "{.section @}{innerPointerT}{.end}"
+ input := "{.section @}{InnerPointerT}{.end}"
tmpl, err := Parse(input, nil)
if err != nil {
t.Fatal("unexpected parse error:", err)
@@ -577,9 +630,31 @@ func TestHTMLFormatterWithByte(t *testing.T) {
s := "Test string."
b := []byte(s)
var buf bytes.Buffer
- HTMLFormatter(&buf, b, "")
+ HTMLFormatter(&buf, "", b)
bs := buf.String()
if bs != s {
t.Errorf("munged []byte, expected: %s got: %s", s, bs)
}
}
+
+type UF struct {
+ I int
+ s string
+}
+
+func TestReferenceToUnexported(t *testing.T) {
+ u := &UF{3, "hello"}
+ var buf bytes.Buffer
+ input := "{.section @}{I}{s}{.end}"
+ tmpl, err := Parse(input, nil)
+ if err != nil {
+ t.Fatal("unexpected parse error:", err)
+ }
+ err = tmpl.Execute(u, &buf)
+ if err == nil {
+ t.Fatal("expected execute error, got none")
+ }
+ if strings.Index(err.String(), "not exported") < 0 {
+ t.Fatal("expected unexported error; got", err)
+ }
+}
diff --git a/src/pkg/testing/Makefile b/src/pkg/testing/Makefile
index 64485489e..9e8bd1756 100644
--- a/src/pkg/testing/Makefile
+++ b/src/pkg/testing/Makefile
@@ -2,12 +2,11 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=testing
GOFILES=\
benchmark.go\
- regexp.go\
testing.go\
include ../../Make.pkg
diff --git a/src/pkg/testing/benchmark.go b/src/pkg/testing/benchmark.go
index 6266de932..ad938027d 100644
--- a/src/pkg/testing/benchmark.go
+++ b/src/pkg/testing/benchmark.go
@@ -15,7 +15,7 @@ var matchBenchmarks = flag.String("benchmarks", "", "regular expression to selec
// An internal type but exported because it is cross-package; part of the implementation
// of gotest.
-type Benchmark struct {
+type InternalBenchmark struct {
Name string
F func(b *B)
}
@@ -24,7 +24,7 @@ type Benchmark struct {
// timing and to specify the number of iterations to run.
type B struct {
N int
- benchmark Benchmark
+ benchmark InternalBenchmark
ns int64
bytes int64
start int64
@@ -117,7 +117,7 @@ func roundUp(n int) int {
// 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() {
+func (b *B) run() BenchmarkResult {
// Run the benchmark for a single iteration in case it's expensive.
n := 1
b.runN(n)
@@ -138,31 +138,58 @@ func (b *B) run() {
n = roundUp(n)
b.runN(n)
}
- ns := b.nsPerOp()
+ return BenchmarkResult{b.N, b.ns, b.bytes}
+
+}
+
+// The results of a benchmark run.
+type BenchmarkResult struct {
+ N int // The number of iterations.
+ Ns int64 // The total time taken.
+ Bytes int64 // The total number of bytes processed.
+}
+
+func (r BenchmarkResult) NsPerOp() int64 {
+ if r.N <= 0 {
+ return 0
+ }
+ return r.Ns / int64(r.N)
+}
+
+func (r BenchmarkResult) String() string {
+ ns := r.NsPerOp()
mb := ""
- if ns > 0 && b.bytes > 0 {
- mb = fmt.Sprintf("\t%7.2f MB/s", (float64(b.bytes)/1e6)/(float64(ns)/1e9))
+ if ns > 0 && r.Bytes > 0 {
+ mb = fmt.Sprintf("\t%7.2f MB/s", (float64(r.Bytes)/1e6)/(float64(ns)/1e9))
}
- fmt.Printf("%s\t%8d\t%10d ns/op%s\n", b.benchmark.Name, b.N, b.nsPerOp(), mb)
+ return fmt.Sprintf("%8d\t%10d ns/op%s", r.N, ns, mb)
}
// An internal function but exported because it is cross-package; part of the implementation
// of gotest.
-func RunBenchmarks(benchmarks []Benchmark) {
+func RunBenchmarks(matchString func(pat, str string) (bool, os.Error), benchmarks []InternalBenchmark) {
// If no flag was specified, don't run benchmarks.
if len(*matchBenchmarks) == 0 {
return
}
- re, err := CompileRegexp(*matchBenchmarks)
- if err != "" {
- println("invalid regexp for -benchmarks:", err)
- os.Exit(1)
- }
for _, Benchmark := range benchmarks {
- if !re.MatchString(Benchmark.Name) {
+ matched, err := matchString(*matchBenchmarks, Benchmark.Name)
+ if err != nil {
+ println("invalid regexp for -benchmarks:", err.String())
+ os.Exit(1)
+ }
+ if !matched {
continue
}
b := &B{benchmark: Benchmark}
- b.run()
+ r := b.run()
+ fmt.Printf("%s\t%v\n", Benchmark.Name, r)
}
}
+
+// Benchmark benchmarks a single function. Useful for creating
+// custom benchmarks that do not use gotest.
+func Benchmark(f func(b *B)) BenchmarkResult {
+ b := &B{benchmark: InternalBenchmark{"", f}}
+ return b.run()
+}
diff --git a/src/pkg/testing/iotest/Makefile b/src/pkg/testing/iotest/Makefile
index 2b9abd4b3..43a047cc9 100644
--- a/src/pkg/testing/iotest/Makefile
+++ b/src/pkg/testing/iotest/Makefile
@@ -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 ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=testing/iotest
GOFILES=\
diff --git a/src/pkg/testing/iotest/logger.go b/src/pkg/testing/iotest/logger.go
index 5e511bdf6..c3bf5df3c 100644
--- a/src/pkg/testing/iotest/logger.go
+++ b/src/pkg/testing/iotest/logger.go
@@ -18,15 +18,15 @@ type writeLogger struct {
func (l *writeLogger) Write(p []byte) (n int, err os.Error) {
n, err = l.w.Write(p)
if err != nil {
- log.Stdoutf("%s %x: %v", l.prefix, p[0:n], err)
+ log.Printf("%s %x: %v", l.prefix, p[0:n], err)
} else {
- log.Stdoutf("%s %x", l.prefix, p[0:n])
+ log.Printf("%s %x", l.prefix, p[0:n])
}
return
}
// NewWriteLogger returns a writer that behaves like w except
-// that it logs (using log.Stdout) each write to standard output,
+// that it logs (using log.Printf) each write to standard error,
// printing the prefix and the hexadecimal data written.
func NewWriteLogger(prefix string, w io.Writer) io.Writer {
return &writeLogger{prefix, w}
@@ -40,15 +40,15 @@ type readLogger struct {
func (l *readLogger) Read(p []byte) (n int, err os.Error) {
n, err = l.r.Read(p)
if err != nil {
- log.Stdoutf("%s %x: %v", l.prefix, p[0:n], err)
+ log.Printf("%s %x: %v", l.prefix, p[0:n], err)
} else {
- log.Stdoutf("%s %x", l.prefix, p[0:n])
+ log.Printf("%s %x", l.prefix, p[0:n])
}
return
}
// NewReadLogger returns a reader that behaves like r except
-// that it logs (using log.Stdout) each read to standard output,
+// that it logs (using log.Print) each read to standard error,
// printing the prefix and the hexadecimal data written.
func NewReadLogger(prefix string, r io.Reader) io.Reader {
return &readLogger{prefix, r}
diff --git a/src/pkg/testing/quick/Makefile b/src/pkg/testing/quick/Makefile
index 0e97f2af2..6d3b736b0 100644
--- a/src/pkg/testing/quick/Makefile
+++ b/src/pkg/testing/quick/Makefile
@@ -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 ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=testing/quick
GOFILES=\
diff --git a/src/pkg/testing/regexp.go b/src/pkg/testing/regexp.go
deleted file mode 100644
index 78d801d51..000000000
--- a/src/pkg/testing/regexp.go
+++ /dev/null
@@ -1,831 +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.
-
-// The testing package implements a simple regular expression library.
-// It is a reduced version of the regular expression package suitable
-// for use in tests; it avoids many dependencies.
-//
-// The syntax of the regular expressions accepted is:
-//
-// regexp:
-// concatenation { '|' concatenation }
-// concatenation:
-// { closure }
-// closure:
-// term [ '*' | '+' | '?' ]
-// term:
-// '^'
-// '$'
-// '.'
-// character
-// '[' [ '^' ] character-ranges ']'
-// '(' regexp ')'
-//
-
-package testing
-
-import (
- "utf8"
-)
-
-var debug = false
-
-// Error codes returned by failures to parse an expression.
-var (
- ErrInternal = "internal error"
- ErrUnmatchedLpar = "unmatched '('"
- ErrUnmatchedRpar = "unmatched ')'"
- ErrUnmatchedLbkt = "unmatched '['"
- ErrUnmatchedRbkt = "unmatched ']'"
- ErrBadRange = "bad range in character class"
- ErrExtraneousBackslash = "extraneous backslash"
- ErrBadClosure = "repeated closure (**, ++, etc.)"
- ErrBareClosure = "closure applies to nothing"
- ErrBadBackslash = "illegal backslash escape"
-)
-
-// An instruction executed by the NFA
-type instr interface {
- kind() int // the type of this instruction: _CHAR, _ANY, etc.
- next() instr // the instruction to execute after this one
- setNext(i instr)
- index() int
- setIndex(i int)
- print()
-}
-
-// Fields and methods common to all instructions
-type common struct {
- _next instr
- _index int
-}
-
-func (c *common) next() instr { return c._next }
-func (c *common) setNext(i instr) { c._next = i }
-func (c *common) index() int { return c._index }
-func (c *common) setIndex(i int) { c._index = i }
-
-// The representation of a compiled regular expression.
-// The public interface is entirely through methods.
-type Regexp struct {
- expr string // the original expression
- inst []instr
- start instr
- nbra int // number of brackets in expression, for subexpressions
-}
-
-const (
- _START = iota // beginning of program
- _END // end of program: success
- _BOT // '^' beginning of text
- _EOT // '$' end of text
- _CHAR // 'a' regular character
- _CHARCLASS // [a-z] character class
- _ANY // '.' any character including newline
- _NOTNL // [^\n] special case: any character but newline
- _BRA // '(' parenthesized expression
- _EBRA // ')'; end of '(' parenthesized expression
- _ALT // '|' alternation
- _NOP // do nothing; makes it easy to link without patching
-)
-
-// --- START start of program
-type _Start struct {
- common
-}
-
-func (start *_Start) kind() int { return _START }
-func (start *_Start) print() { print("start") }
-
-// --- END end of program
-type _End struct {
- common
-}
-
-func (end *_End) kind() int { return _END }
-func (end *_End) print() { print("end") }
-
-// --- BOT beginning of text
-type _Bot struct {
- common
-}
-
-func (bot *_Bot) kind() int { return _BOT }
-func (bot *_Bot) print() { print("bot") }
-
-// --- EOT end of text
-type _Eot struct {
- common
-}
-
-func (eot *_Eot) kind() int { return _EOT }
-func (eot *_Eot) print() { print("eot") }
-
-// --- CHAR a regular character
-type _Char struct {
- common
- char int
-}
-
-func (char *_Char) kind() int { return _CHAR }
-func (char *_Char) print() { print("char ", string(char.char)) }
-
-func newChar(char int) *_Char {
- c := new(_Char)
- c.char = char
- return c
-}
-
-// --- CHARCLASS [a-z]
-
-type _CharClass struct {
- common
- char int
- negate bool // is character class negated? ([^a-z])
- // stored pairwise: [a-z] is (a,z); x is (x,x):
- ranges []int
-}
-
-func (cclass *_CharClass) kind() int { return _CHARCLASS }
-
-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
- n := len(cclass.ranges)
- if n >= cap(cclass.ranges) {
- nr := make([]int, n, 2*n)
- for i, j := range nr {
- nr[i] = j
- }
- cclass.ranges = nr
- }
- cclass.ranges = cclass.ranges[0 : n+2]
- cclass.ranges[n] = a
- n++
- cclass.ranges[n] = b
- n++
-}
-
-func (cclass *_CharClass) matches(c int) bool {
- for i := 0; i < len(cclass.ranges); i = i + 2 {
- min := cclass.ranges[i]
- max := cclass.ranges[i+1]
- if min <= c && c <= max {
- return !cclass.negate
- }
- }
- return cclass.negate
-}
-
-func newCharClass() *_CharClass {
- c := new(_CharClass)
- c.ranges = make([]int, 0, 20)
- return c
-}
-
-// --- ANY any character
-type _Any struct {
- common
-}
-
-func (any *_Any) kind() int { return _ANY }
-func (any *_Any) print() { print("any") }
-
-// --- NOTNL any character but newline
-type _NotNl struct {
- common
-}
-
-func (notnl *_NotNl) kind() int { return _NOTNL }
-func (notnl *_NotNl) print() { print("notnl") }
-
-// --- BRA parenthesized expression
-type _Bra struct {
- common
- n int // subexpression number
-}
-
-func (bra *_Bra) kind() int { return _BRA }
-func (bra *_Bra) print() { print("bra", bra.n) }
-
-// --- EBRA end of parenthesized expression
-type _Ebra struct {
- common
- n int // subexpression number
-}
-
-func (ebra *_Ebra) kind() int { return _EBRA }
-func (ebra *_Ebra) print() { print("ebra ", ebra.n) }
-
-// --- ALT alternation
-type _Alt struct {
- common
- left instr // other branch
-}
-
-func (alt *_Alt) kind() int { return _ALT }
-func (alt *_Alt) print() { print("alt(", alt.left.index(), ")") }
-
-// --- NOP no operation
-type _Nop struct {
- common
-}
-
-func (nop *_Nop) kind() int { return _NOP }
-func (nop *_Nop) print() { print("nop") }
-
-func (re *Regexp) add(i instr) instr {
- n := len(re.inst)
- i.setIndex(len(re.inst))
- if n >= cap(re.inst) {
- ni := make([]instr, n, 2*n)
- for i, j := range re.inst {
- ni[i] = j
- }
- re.inst = ni
- }
- re.inst = re.inst[0 : n+1]
- re.inst[n] = i
- return i
-}
-
-type parser struct {
- re *Regexp
- nlpar int // number of unclosed lpars
- pos int
- ch int
-}
-
-func (p *parser) error(err string) {
- panic(err)
-}
-
-const endOfFile = -1
-
-func (p *parser) c() int { return p.ch }
-
-func (p *parser) nextc() int {
- if p.pos >= len(p.re.expr) {
- p.ch = endOfFile
- } else {
- c, w := utf8.DecodeRuneInString(p.re.expr[p.pos:])
- p.ch = c
- p.pos += w
- }
- return p.ch
-}
-
-func newParser(re *Regexp) *parser {
- p := new(parser)
- p.re = re
- p.nextc() // load p.ch
- return p
-}
-
-func special(c int) bool {
- s := `\.+*?()|[]^$`
- for i := 0; i < len(s); i++ {
- if c == int(s[i]) {
- return true
- }
- }
- return false
-}
-
-func specialcclass(c int) bool {
- s := `\-[]`
- for i := 0; i < len(s); i++ {
- if c == int(s[i]) {
- return true
- }
- }
- return false
-}
-
-func (p *parser) charClass() instr {
- cc := newCharClass()
- if p.c() == '^' {
- cc.negate = true
- p.nextc()
- }
- left := -1
- for {
- switch c := p.c(); c {
- case ']', endOfFile:
- if left >= 0 {
- p.error(ErrBadRange)
- }
- // Is it [^\n]?
- if cc.negate && len(cc.ranges) == 2 &&
- cc.ranges[0] == '\n' && cc.ranges[1] == '\n' {
- nl := new(_NotNl)
- p.re.add(nl)
- return nl
- }
- p.re.add(cc)
- return cc
- case '-': // do this before backslash processing
- p.error(ErrBadRange)
- case '\\':
- c = p.nextc()
- switch {
- case c == endOfFile:
- p.error(ErrExtraneousBackslash)
- case c == 'n':
- c = '\n'
- case specialcclass(c):
- // c is as delivered
- default:
- p.error(ErrBadBackslash)
- }
- fallthrough
- default:
- 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)
- }
- }
- }
- return nil
-}
-
-func (p *parser) term() (start, end instr) {
- switch c := p.c(); c {
- case '|', endOfFile:
- return nil, nil
- case '*', '+':
- p.error(ErrBareClosure)
- return
- case ')':
- if p.nlpar == 0 {
- p.error(ErrUnmatchedRpar)
- }
- return nil, nil
- case ']':
- p.error(ErrUnmatchedRbkt)
- case '^':
- p.nextc()
- start = p.re.add(new(_Bot))
- return start, start
- case '$':
- p.nextc()
- start = p.re.add(new(_Eot))
- return start, start
- case '.':
- p.nextc()
- start = p.re.add(new(_Any))
- 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 := new(_Bra)
- p.re.add(bra)
- ebra := new(_Ebra)
- p.re.add(ebra)
- bra.n = nbra
- ebra.n = nbra
- if start == nil {
- if end == nil {
- p.error(ErrInternal)
- }
- start = ebra
- } else {
- end.setNext(ebra)
- }
- bra.setNext(start)
- return bra, ebra
- case '\\':
- c = p.nextc()
- switch {
- case c == endOfFile:
- p.error(ErrExtraneousBackslash)
- return
- case c == 'n':
- c = '\n'
- case special(c):
- // c is as delivered
- default:
- p.error(ErrBadBackslash)
- }
- fallthrough
- default:
- p.nextc()
- start = newChar(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 := new(_Alt)
- p.re.add(alt)
- end.setNext(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 := new(_Alt)
- p.re.add(alt)
- end.setNext(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 := new(_Alt)
- p.re.add(alt)
- nop := new(_Nop)
- p.re.add(nop)
- alt.left = start // alternate branch is start
- alt.setNext(nop) // follow on to nop
- end.setNext(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(new(_Nop))
- return nop, nop
- }
- return
- case start == nil: // this is first element of concatenation
- start, end = nstart, nend
- default:
- end.setNext(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 := new(_Alt)
- p.re.add(alt)
- alt.left = start
- alt.setNext(nstart)
- nop := new(_Nop)
- p.re.add(nop)
- end.setNext(nop)
- nend.setNext(nop)
- start, end = alt, nop
- }
- }
- panic("unreachable")
-}
-
-func unNop(i instr) instr {
- for i.kind() == _NOP {
- i = i.next()
- }
- return i
-}
-
-func (re *Regexp) eliminateNops() {
- for i := 0; i < len(re.inst); i++ {
- inst := re.inst[i]
- if inst.kind() == _END {
- continue
- }
- inst.setNext(unNop(inst.next()))
- if inst.kind() == _ALT {
- alt := inst.(*_Alt)
- alt.left = unNop(alt.left)
- }
- }
-}
-
-func (re *Regexp) doParse() {
- p := newParser(re)
- start := new(_Start)
- re.add(start)
- s, e := p.regexp()
- start.setNext(s)
- re.start = start
- e.setNext(re.add(new(_End)))
- re.eliminateNops()
-}
-
-// CompileRegexp parses a regular expression and returns, if successful, a Regexp
-// object that can be used to match against text.
-func CompileRegexp(str string) (regexp *Regexp, error string) {
- regexp = new(Regexp)
- // doParse will panic if there is a parse error.
- defer func() {
- if e := recover(); e != nil {
- regexp = nil
- error = e.(string) // Will re-panic if error was not a string, e.g. nil-pointer exception
- }
- }()
- regexp.expr = str
- regexp.inst = make([]instr, 0, 20)
- regexp.doParse()
- return
-}
-
-// MustCompileRegexp is like CompileRegexp 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 := CompileRegexp(str)
- if error != "" {
- panic(`regexp: compiling "` + str + `": ` + error)
- }
- return regexp
-}
-
-type state struct {
- inst instr // next instruction to execute
- match []int // pairs of bracketing submatches. 0th is start,end
-}
-
-// Append new state to to-do list. Leftmost-longest wins so avoid
-// adding a state that's already active.
-func addState(s []state, inst instr, match []int) []state {
- index := inst.index()
- l := len(s)
- pos := match[0]
- // TODO: Once the state is a vector and we can do insert, have inputs always
- // go in order correctly and this "earlier" test is never necessary,
- for i := 0; i < l; i++ {
- if s[i].inst.index() == index && // same instruction
- s[i].match[0] < pos { // earlier match already going; lefmost wins
- return s
- }
- }
- if l == cap(s) {
- s1 := make([]state, 2*l)[0:l]
- for i := 0; i < l; i++ {
- s1[i] = s[i]
- }
- s = s1
- }
- s = s[0 : l+1]
- s[l].inst = inst
- s[l].match = match
- return s
-}
-
-// Accepts either string or bytes - the logic is identical either way.
-// If bytes == nil, scan str.
-func (re *Regexp) doExecute(str string, bytes []byte, pos int) []int {
- var s [2][]state // TODO: use a vector when state values (not ptrs) can be vector elements
- s[0] = make([]state, 10)[0:0]
- s[1] = make([]state, 10)[0:0]
- in, out := 0, 1
- var final state
- found := false
- end := len(str)
- if bytes != nil {
- end = len(bytes)
- }
- for pos <= end {
- if !found {
- // prime the pump if we haven't seen a match yet
- match := make([]int, 2*(re.nbra+1))
- for i := 0; i < len(match); i++ {
- match[i] = -1 // no match seen; catches cases like "a(b)?c" on "ac"
- }
- match[0] = pos
- s[out] = addState(s[out], re.start.next(), match)
- }
- in, out = out, in // old out state is new in state
- s[out] = s[out][0:0] // clear out state
- if len(s[in]) == 0 {
- // machine has completed
- break
- }
- charwidth := 1
- c := endOfFile
- if pos < end {
- if bytes == nil {
- c, charwidth = utf8.DecodeRuneInString(str[pos:end])
- } else {
- c, charwidth = utf8.DecodeRune(bytes[pos:end])
- }
- }
- for i := 0; i < len(s[in]); i++ {
- st := s[in][i]
- switch s[in][i].inst.kind() {
- case _BOT:
- if pos == 0 {
- s[in] = addState(s[in], st.inst.next(), st.match)
- }
- case _EOT:
- if pos == end {
- s[in] = addState(s[in], st.inst.next(), st.match)
- }
- case _CHAR:
- if c == st.inst.(*_Char).char {
- s[out] = addState(s[out], st.inst.next(), st.match)
- }
- case _CHARCLASS:
- if st.inst.(*_CharClass).matches(c) {
- s[out] = addState(s[out], st.inst.next(), st.match)
- }
- case _ANY:
- if c != endOfFile {
- s[out] = addState(s[out], st.inst.next(), st.match)
- }
- case _NOTNL:
- if c != endOfFile && c != '\n' {
- s[out] = addState(s[out], st.inst.next(), st.match)
- }
- case _BRA:
- n := st.inst.(*_Bra).n
- st.match[2*n] = pos
- s[in] = addState(s[in], st.inst.next(), st.match)
- case _EBRA:
- n := st.inst.(*_Ebra).n
- st.match[2*n+1] = pos
- s[in] = addState(s[in], st.inst.next(), st.match)
- case _ALT:
- s[in] = addState(s[in], st.inst.(*_Alt).left, st.match)
- // give other branch a copy of this match vector
- s1 := make([]int, 2*(re.nbra+1))
- for i := 0; i < len(s1); i++ {
- s1[i] = st.match[i]
- }
- s[in] = addState(s[in], st.inst.next(), s1)
- case _END:
- // choose leftmost longest
- if !found || // first
- st.match[0] < final.match[0] || // leftmost
- (st.match[0] == final.match[0] && pos > final.match[1]) { // longest
- final = st
- final.match[1] = pos
- }
- found = true
- default:
- st.inst.print()
- panic("unknown instruction in execute")
- }
- }
- pos += charwidth
- }
- return final.match
-}
-
-
-// ExecuteString matches the Regexp against the string s.
-// The return value is an array of integers, in pairs, identifying the positions of
-// substrings matched by the expression.
-// s[a[0]:a[1]] is the substring matched by the entire expression.
-// s[a[2*i]:a[2*i+1]] for i > 0 is the substring matched by the ith parenthesized subexpression.
-// A negative value means the subexpression did not match any element of the string.
-// An empty array means "no match".
-func (re *Regexp) ExecuteString(s string) (a []int) {
- return re.doExecute(s, nil, 0)
-}
-
-
-// Execute matches the Regexp against the byte slice b.
-// The return value is an array of integers, in pairs, identifying the positions of
-// subslices matched by the expression.
-// b[a[0]:a[1]] is the subslice matched by the entire expression.
-// b[a[2*i]:a[2*i+1]] for i > 0 is the subslice matched by the ith parenthesized subexpression.
-// A negative value means the subexpression did not match any element of the slice.
-// An empty array means "no match".
-func (re *Regexp) Execute(b []byte) (a []int) { return re.doExecute("", b, 0) }
-
-
-// MatchString returns whether the Regexp matches the string s.
-// The return value is a boolean: true for match, false for no match.
-func (re *Regexp) MatchString(s string) bool { return len(re.doExecute(s, nil, 0)) > 0 }
-
-
-// Match returns whether the Regexp matches the byte slice b.
-// The return value is a boolean: true for match, false for no match.
-func (re *Regexp) Match(b []byte) bool { return len(re.doExecute("", b, 0)) > 0 }
-
-
-// MatchStrings matches the Regexp against the string s.
-// The return value is an array of strings matched by the expression.
-// a[0] is the substring matched by the entire expression.
-// a[i] for i > 0 is the substring matched by the ith parenthesized subexpression.
-// An empty array means ``no match''.
-func (re *Regexp) MatchStrings(s string) (a []string) {
- r := re.doExecute(s, nil, 0)
- if r == nil {
- return nil
- }
- a = make([]string, len(r)/2)
- for i := 0; i < len(r); i += 2 {
- if r[i] != -1 { // -1 means no match for this subexpression
- a[i/2] = s[r[i]:r[i+1]]
- }
- }
- return
-}
-
-// MatchSlices matches the Regexp against the byte slice b.
-// The return value is an array of subslices matched by the expression.
-// a[0] is the subslice matched by the entire expression.
-// a[i] for i > 0 is the subslice matched by the ith parenthesized subexpression.
-// An empty array means ``no match''.
-func (re *Regexp) MatchSlices(b []byte) (a [][]byte) {
- r := re.doExecute("", b, 0)
- if r == nil {
- return nil
- }
- a = make([][]byte, len(r)/2)
- for i := 0; i < len(r); i += 2 {
- if r[i] != -1 { // -1 means no match for this subexpression
- a[i/2] = b[r[i]:r[i+1]]
- }
- }
- return
-}
-
-// 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 string) {
- re, err := CompileRegexp(pattern)
- if err != "" {
- return false, err
- }
- return re.MatchString(s), ""
-}
-
-// 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 string) {
- re, err := CompileRegexp(pattern)
- if err != "" {
- return false, err
- }
- return re.Match(b), ""
-}
diff --git a/src/pkg/testing/regexp_test.go b/src/pkg/testing/regexp_test.go
deleted file mode 100644
index ffeb62b5b..000000000
--- a/src/pkg/testing/regexp_test.go
+++ /dev/null
@@ -1,307 +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 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]`,
-}
-
-// TODO: nice to do this with a map
-type stringError struct {
- re string
- err string
-}
-
-var bad_re = []stringError{
- stringError{`*`, ErrBareClosure},
- stringError{`(abc`, ErrUnmatchedLpar},
- stringError{`abc)`, ErrUnmatchedRpar},
- stringError{`x[a-z`, ErrUnmatchedLbkt},
- stringError{`abc]`, ErrUnmatchedRbkt},
- stringError{`[z-a]`, ErrBadRange},
- stringError{`abc\`, ErrExtraneousBackslash},
- stringError{`a**`, ErrBadClosure},
- stringError{`a*+`, ErrBadClosure},
- stringError{`a??`, ErrBadClosure},
- stringError{`*`, ErrBareClosure},
- stringError{`\x`, ErrBadBackslash},
-}
-
-type vec []int
-
-type tester struct {
- re string
- text string
- match vec
-}
-
-var matches = []tester{
- tester{``, "", vec{0, 0}},
- tester{`a`, "a", vec{0, 1}},
- tester{`x`, "y", vec{}},
- tester{`b`, "abc", vec{1, 2}},
- tester{`.`, "a", vec{0, 1}},
- tester{`.*`, "abcdef", vec{0, 6}},
- tester{`^abcd$`, "abcd", vec{0, 4}},
- tester{`^bcd'`, "abcdef", vec{}},
- tester{`^abcd$`, "abcde", vec{}},
- tester{`a+`, "baaab", vec{1, 4}},
- tester{`a*`, "baaab", vec{0, 0}},
- tester{`[a-z]+`, "abcd", vec{0, 4}},
- tester{`[^a-z]+`, "ab1234cd", vec{2, 6}},
- tester{`[a\-\]z]+`, "az]-bcz", vec{0, 4}},
- tester{`[^\n]+`, "abcd\n", vec{0, 4}},
- tester{`[日本語]+`, "日本語日本語", vec{0, 18}},
- tester{`()`, "", vec{0, 0, 0, 0}},
- tester{`(a)`, "a", vec{0, 1, 0, 1}},
- tester{`(.)(.)`, "日a", vec{0, 4, 0, 3, 3, 4}},
- tester{`(.*)`, "", vec{0, 0, 0, 0}},
- tester{`(.*)`, "abcd", vec{0, 4, 0, 4}},
- tester{`(..)(..)`, "abcd", vec{0, 4, 0, 2, 2, 4}},
- tester{`(([^xyz]*)(d))`, "abcd", vec{0, 4, 0, 4, 0, 3, 3, 4}},
- tester{`((a|b|c)*(d))`, "abcd", vec{0, 4, 0, 4, 2, 3, 3, 4}},
- tester{`(((a|b|c)*)(d))`, "abcd", vec{0, 4, 0, 4, 0, 3, 2, 3, 3, 4}},
- tester{`a*(|(b))c*`, "aacc", vec{0, 4, 2, 2, -1, -1}},
-}
-
-func compileTest(t *T, expr string, error string) *Regexp {
- re, err := CompileRegexp(expr)
- if err != error {
- t.Error("compiling `", expr, "`; unexpected error: ", err)
- }
- return re
-}
-
-func printVec(t *T, m []int) {
- l := len(m)
- if l == 0 {
- t.Log("\t<no match>")
- } else {
- for i := 0; i < l; i = i + 2 {
- t.Log("\t", m[i], ",", m[i+1])
- }
- }
-}
-
-func printStrings(t *T, m []string) {
- l := len(m)
- if l == 0 {
- t.Log("\t<no match>")
- } else {
- for i := 0; i < l; i = i + 2 {
- t.Logf("\t%q", m[i])
- }
- }
-}
-
-func printBytes(t *T, b [][]byte) {
- l := len(b)
- if l == 0 {
- t.Log("\t<no match>")
- } else {
- for i := 0; i < l; i = i + 2 {
- t.Logf("\t%q", b[i])
- }
- }
-}
-
-func equal(m1, m2 []int) bool {
- l := len(m1)
- if l != len(m2) {
- return false
- }
- for i := 0; i < l; i++ {
- if m1[i] != m2[i] {
- return false
- }
- }
- return true
-}
-
-func equalStrings(m1, m2 []string) bool {
- l := len(m1)
- if l != len(m2) {
- return false
- }
- for i := 0; i < l; i++ {
- if m1[i] != m2[i] {
- return false
- }
- }
- return true
-}
-
-func equalBytes(m1 [][]byte, m2 []string) bool {
- l := len(m1)
- if l != len(m2) {
- return false
- }
- for i := 0; i < l; i++ {
- if string(m1[i]) != m2[i] {
- return false
- }
- }
- return true
-}
-
-func executeTest(t *T, expr string, str string, match []int) {
- re := compileTest(t, expr, "")
- if re == nil {
- return
- }
- m := re.ExecuteString(str)
- if !equal(m, match) {
- t.Error("ExecuteString failure on `", expr, "` matching `", str, "`:")
- printVec(t, m)
- t.Log("should be:")
- printVec(t, match)
- }
- // now try bytes
- m = re.Execute([]byte(str))
- if !equal(m, match) {
- t.Error("Execute failure on `", expr, "` matching `", str, "`:")
- printVec(t, m)
- t.Log("should be:")
- printVec(t, match)
- }
-}
-
-func TestGoodCompile(t *T) {
- for i := 0; i < len(good_re); i++ {
- compileTest(t, good_re[i], "")
- }
-}
-
-func TestBadCompile(t *T) {
- for i := 0; i < len(bad_re); i++ {
- compileTest(t, bad_re[i].re, bad_re[i].err)
- }
-}
-
-func TestExecute(t *T) {
- for i := 0; i < len(matches); i++ {
- test := &matches[i]
- executeTest(t, test.re, test.text, test.match)
- }
-}
-
-func matchTest(t *T, expr string, str string, match []int) {
- re := compileTest(t, expr, "")
- if re == nil {
- return
- }
- m := re.MatchString(str)
- if m != (len(match) > 0) {
- t.Error("MatchString failure on `", expr, "` matching `", str, "`:", m, "should be", len(match) > 0)
- }
- // now try bytes
- m = re.Match([]byte(str))
- if m != (len(match) > 0) {
- t.Error("Match failure on `", expr, "` matching `", str, "`:", m, "should be", len(match) > 0)
- }
-}
-
-func TestMatch(t *T) {
- for i := 0; i < len(matches); i++ {
- test := &matches[i]
- matchTest(t, test.re, test.text, test.match)
- }
-}
-
-func matchStringsTest(t *T, expr string, str string, match []int) {
- re := compileTest(t, expr, "")
- if re == nil {
- return
- }
- strs := make([]string, len(match)/2)
- for i := 0; i < len(match); i++ {
- strs[i/2] = str[match[i]:match[i+1]]
- }
- m := re.MatchStrings(str)
- if !equalStrings(m, strs) {
- t.Error("MatchStrings failure on `", expr, "` matching `", str, "`:")
- printStrings(t, m)
- t.Log("should be:")
- printStrings(t, strs)
- }
- // now try bytes
- s := re.MatchSlices([]byte(str))
- if !equalBytes(s, strs) {
- t.Error("MatchSlices failure on `", expr, "` matching `", str, "`:")
- printBytes(t, s)
- t.Log("should be:")
- printStrings(t, strs)
- }
-}
-
-func TestMatchStrings(t *T) {
- for i := 0; i < len(matches); i++ {
- test := &matches[i]
- matchTest(t, test.re, test.text, test.match)
- }
-}
-
-func matchFunctionTest(t *T, expr string, str string, match []int) {
- m, err := MatchString(expr, str)
- if err == "" {
- return
- }
- if m != (len(match) > 0) {
- t.Error("function Match failure on `", expr, "` matching `", str, "`:", m, "should be", len(match) > 0)
- }
-}
-
-func TestMatchFunction(t *T) {
- for i := 0; i < len(matches); i++ {
- test := &matches[i]
- matchFunctionTest(t, test.re, test.text, test.match)
- }
-}
-
-func BenchmarkSimpleMatch(b *B) {
- b.StopTimer()
- re, _ := CompileRegexp("a")
- b.StartTimer()
-
- for i := 0; i < b.N; i++ {
- re.MatchString("a")
- }
-}
-
-func BenchmarkUngroupedMatch(b *B) {
- b.StopTimer()
- re, _ := CompileRegexp("[a-z]+ [0-9]+ [a-z]+")
- b.StartTimer()
-
- for i := 0; i < b.N; i++ {
- re.MatchString("word 123 other")
- }
-}
-
-func BenchmarkGroupedMatch(b *B) {
- b.StopTimer()
- re, _ := CompileRegexp("([a-z]+) ([0-9]+) ([a-z]+)")
- b.StartTimer()
-
- for i := 0; i < b.N; i++ {
- re.MatchString("word 123 other")
- }
-}
diff --git a/src/pkg/testing/script/Makefile b/src/pkg/testing/script/Makefile
index 2e13aeb2f..9388d972b 100644
--- a/src/pkg/testing/script/Makefile
+++ b/src/pkg/testing/script/Makefile
@@ -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 ../../../Make.$(GOARCH)
+include ../../../Make.inc
TARG=testing/script
GOFILES=\
diff --git a/src/pkg/testing/testing.go b/src/pkg/testing/testing.go
index 763b65b05..0e04935ce 100644
--- a/src/pkg/testing/testing.go
+++ b/src/pkg/testing/testing.go
@@ -89,65 +89,65 @@ func (t *T) FailNow() {
// Log formats its arguments using default formatting, analogous to Print(),
// and records the text in the error log.
-func (t *T) Log(args ...interface{}) { t.errors += "\t" + tabify(fmt.Sprintln(args)) }
+func (t *T) Log(args ...interface{}) { t.errors += "\t" + tabify(fmt.Sprintln(args...)) }
// Log formats its arguments according to the format, analogous to Printf(),
// and records the text in the error log.
func (t *T) Logf(format string, args ...interface{}) {
- t.errors += "\t" + tabify(fmt.Sprintf(format, args))
+ t.errors += "\t" + tabify(fmt.Sprintf(format, args...))
}
// Error is equivalent to Log() followed by Fail().
func (t *T) Error(args ...interface{}) {
- t.Log(args)
+ t.Log(args...)
t.Fail()
}
// Errorf is equivalent to Logf() followed by Fail().
func (t *T) Errorf(format string, args ...interface{}) {
- t.Logf(format, args)
+ t.Logf(format, args...)
t.Fail()
}
// Fatal is equivalent to Log() followed by FailNow().
func (t *T) Fatal(args ...interface{}) {
- t.Log(args)
+ t.Log(args...)
t.FailNow()
}
// Fatalf is equivalent to Logf() followed by FailNow().
func (t *T) Fatalf(format string, args ...interface{}) {
- t.Logf(format, args)
+ t.Logf(format, args...)
t.FailNow()
}
// An internal type but exported because it is cross-package; part of the implementation
// of gotest.
-type Test struct {
+type InternalTest struct {
Name string
F func(*T)
}
-func tRunner(t *T, test *Test) {
+func tRunner(t *T, test *InternalTest) {
test.F(t)
t.ch <- t
}
// An internal function but exported because it is cross-package; part of the implementation
// of gotest.
-func Main(tests []Test) {
+func Main(matchString func(pat, str string) (bool, os.Error), tests []InternalTest) {
flag.Parse()
ok := true
if len(tests) == 0 {
println("testing: warning: no tests to run")
}
- re, err := CompileRegexp(*match)
- if err != "" {
- println("invalid regexp for -match:", err)
- os.Exit(1)
- }
for i := 0; i < len(tests); i++ {
- if !re.MatchString(tests[i].Name) {
+ matched, err := matchString(*match, tests[i].Name)
+ if err != nil {
+ println("invalid regexp for -match:", err.String())
+ os.Exit(1)
+ }
+ if !matched {
continue
}
if *chatty {
diff --git a/src/pkg/time/Makefile b/src/pkg/time/Makefile
index 6732d6a79..5213e4457 100644
--- a/src/pkg/time/Makefile
+++ b/src/pkg/time/Makefile
@@ -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 ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=time
GOFILES=\
@@ -20,9 +20,6 @@ GOFILES_darwin=\
GOFILES_linux=\
zoneinfo_unix.go\
-GOFILES_nacl=\
- zoneinfo_unix.go\
-
GOFILES_windows=\
zoneinfo_windows.go\
diff --git a/src/pkg/time/format.go b/src/pkg/time/format.go
index c04325126..7b5a8f3b6 100644
--- a/src/pkg/time/format.go
+++ b/src/pkg/time/format.go
@@ -19,10 +19,12 @@ const (
// 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.)
-// 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.
+// To define your own format, write down what the standard
+// time would look like formatted your way.
+//
+// Within the format string, an underscore _ represents a space that may be
+// replaced by a digit if the following number (a day) has two digits; for
+// compatibility with fixed-width Unix time formats.
//
// Numeric time zone offsets format as follows:
// -0700 ±hhmm
@@ -41,8 +43,8 @@ const (
RFC822Z = "02 Jan 06 1504 -0700"
RFC850 = "Monday, 02-Jan-06 15:04:05 MST"
RFC1123 = "Mon, 02 Jan 2006 15:04:05 MST"
- Kitchen = "3:04PM"
RFC3339 = "2006-01-02T15:04:05Z07:00"
+ Kitchen = "3:04PM"
)
const (
@@ -70,6 +72,7 @@ const (
stdISO8601TZ = "Z0700" // prints Z for UTC
stdISO8601ColonTZ = "Z07:00" // prints Z for UTC
stdNumTZ = "-0700" // always numeric
+ stdNumShortTZ = "-07" // always numeric
stdNumColonTZ = "-07:00" // always numeric
)
@@ -134,13 +137,16 @@ func nextStdChunk(layout string) (prefix, std, suffix string) {
return layout[0:i], layout[i : i+2], layout[i+2:]
}
- case '-': // -0700, -07:00
+ case '-': // -0700, -07:00, -07
if len(layout) >= i+5 && layout[i:i+5] == stdNumTZ {
return layout[0:i], layout[i : i+5], layout[i+5:]
}
if len(layout) >= i+6 && layout[i:i+6] == stdNumColonTZ {
return layout[0:i], layout[i : i+6], layout[i+6:]
}
+ if len(layout) >= i+3 && layout[i:i+3] == stdNumShortTZ {
+ return layout[0:i], layout[i : i+3], layout[i+3:]
+ }
case 'Z': // Z0700, Z07:00
if len(layout) >= i+5 && layout[i:i+5] == stdISO8601TZ {
return layout[0:i], layout[i : i+5], layout[i+5:]
@@ -228,7 +234,8 @@ func zeroPad(i int) string { return pad(i, "0") }
// 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.
+// RFC3339 and others describe standard representations. For more
+// information about the formats, see the documentation for ANSIC.
func (t *Time) Format(layout string) string {
b := new(bytes.Buffer)
// Each iteration generates one std value.
@@ -331,7 +338,12 @@ func (t *Time) Format(layout string) string {
}
// String returns a Unix-style representation of the time value.
-func (t *Time) String() string { return t.Format(UnixDate) }
+func (t *Time) String() string {
+ if t == nil {
+ return "<nil>"
+ }
+ return t.Format(UnixDate)
+}
var errBad = os.ErrorString("bad") // just a marker; not returned to user
@@ -405,7 +417,8 @@ func skip(value, prefix string) (string, os.Error) {
// 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.
+// representations.For more information about the formats, see the
+// documentation for ANSIC.
//
// Only those elements present in the value will be set in the returned time
// structure. Also, if the input string represents an inconsistent time
@@ -496,7 +509,7 @@ func Parse(alayout, avalue string) (*Time, os.Error) {
if t.Second < 0 || 60 <= t.Second {
rangeErrString = "second"
}
- case stdISO8601TZ, stdISO8601ColonTZ, stdNumTZ, stdNumColonTZ:
+ case stdISO8601TZ, stdISO8601ColonTZ, stdNumTZ, stdNumShortTZ, stdNumColonTZ:
if std[0] == 'Z' && len(value) >= 1 && value[0] == 'Z' {
value = value[1:]
t.Zone = "UTC"
@@ -513,6 +526,12 @@ func Parse(alayout, avalue string) (*Time, os.Error) {
break
}
sign, hh, mm, value = value[0:1], value[1:3], value[4:6], value[6:]
+ } else if std == stdNumShortTZ {
+ if len(value) < 3 {
+ err = errBad
+ break
+ }
+ sign, hh, mm, value = value[0:1], value[1:3], "00", value[3:]
} else {
if len(value) < 5 {
err = errBad
@@ -522,7 +541,7 @@ func Parse(alayout, avalue string) (*Time, os.Error) {
}
var hr, min int
hr, err = strconv.Atoi(hh)
- if err != nil {
+ if err == nil {
min, err = strconv.Atoi(mm)
}
t.ZoneOffset = (hr*60 + min) * 60 // offset is in seconds
diff --git a/src/pkg/time/sleep.go b/src/pkg/time/sleep.go
index 5de5374ce..3538775ad 100644
--- a/src/pkg/time/sleep.go
+++ b/src/pkg/time/sleep.go
@@ -7,20 +7,145 @@ package time
import (
"os"
"syscall"
+ "sync"
+ "container/heap"
)
-// Sleep pauses the current goroutine for at least ns nanoseconds. Higher resolution
-// sleeping may be provided by syscall.Nanosleep on some operating systems.
+// The event type represents a single After or AfterFunc event.
+type event struct {
+ t int64 // The absolute time that the event should fire.
+ f func(int64) // The function to call when the event fires.
+ sleeping bool // A sleeper is sleeping for this event.
+}
+
+type eventHeap []*event
+
+var events eventHeap
+var eventMutex sync.Mutex
+
+func init() {
+ events.Push(&event{1 << 62, nil, true}) // sentinel
+}
+
+// Sleep pauses the current goroutine for at least ns nanoseconds.
+// Higher resolution sleeping may be provided by syscall.Nanosleep
+// on some operating systems.
func Sleep(ns int64) os.Error {
+ _, err := sleep(Nanoseconds(), ns)
+ return err
+}
+
+// sleep takes the current time and a duration,
+// pauses for at least ns nanoseconds, and
+// returns the current time and an error.
+func sleep(t, ns int64) (int64, os.Error) {
// TODO(cw): use monotonic-time once it's available
- t := Nanoseconds()
end := t + ns
for t < end {
errno := syscall.Sleep(end - t)
if errno != 0 && errno != syscall.EINTR {
- return os.NewSyscallError("sleep", errno)
+ return 0, os.NewSyscallError("sleep", errno)
}
t = Nanoseconds()
}
- return nil
+ return t, nil
+}
+
+// After waits at least ns nanoseconds before sending the current time
+// on the returned channel.
+func After(ns int64) <-chan int64 {
+ c := make(chan int64, 1)
+ after(ns, func(t int64) { c <- t })
+ return c
+}
+
+// AfterFunc waits at least ns nanoseconds before calling f
+// in its own goroutine.
+func AfterFunc(ns int64, f func()) {
+ after(ns, func(_ int64) {
+ go f()
+ })
+}
+
+// after is the implementation of After and AfterFunc.
+// When the current time is after ns, it calls f with the current time.
+// It assumes that f will not block.
+func after(ns int64, f func(int64)) {
+ t := Nanoseconds() + ns
+ eventMutex.Lock()
+ t0 := events[0].t
+ heap.Push(events, &event{t, f, false})
+ if t < t0 {
+ go sleeper()
+ }
+ eventMutex.Unlock()
+}
+
+// sleeper continually looks at the earliest event in the queue, marks it
+// as sleeping, waits until it happens, then removes any events
+// in the queue that are due. It stops when it finds an event that is
+// already marked as sleeping. When an event is inserted before the first item,
+// a new sleeper is started.
+//
+// Scheduling vagaries mean that sleepers may not wake up in
+// exactly the order of the events that they are waiting for,
+// but this does not matter as long as there are at least as
+// many sleepers as events marked sleeping (invariant). This ensures that
+// there is always a sleeper to service the remaining events.
+//
+// A sleeper will remove at least the event it has been waiting for
+// unless the event has already been removed by another sleeper. Both
+// cases preserve the invariant described above.
+func sleeper() {
+ eventMutex.Lock()
+ e := events[0]
+ for !e.sleeping {
+ t := Nanoseconds()
+ if dt := e.t - t; dt > 0 {
+ e.sleeping = true
+ eventMutex.Unlock()
+ if nt, err := sleep(t, dt); err != nil {
+ // If sleep has encountered an error,
+ // there's not much we can do. We pretend
+ // that time really has advanced by the required
+ // amount and lie to the rest of the system.
+ t = e.t
+ } else {
+ t = nt
+ }
+ eventMutex.Lock()
+ e = events[0]
+ }
+ for t >= e.t {
+ e.f(t)
+ heap.Pop(events)
+ e = events[0]
+ }
+ }
+ eventMutex.Unlock()
+}
+
+func (eventHeap) Len() int {
+ return len(events)
+}
+
+func (eventHeap) Less(i, j int) bool {
+ return events[i].t < events[j].t
+}
+
+func (eventHeap) Swap(i, j int) {
+ events[i], events[j] = events[j], events[i]
+}
+
+func (eventHeap) Push(x interface{}) {
+ events = append(events, x.(*event))
+}
+
+func (eventHeap) Pop() interface{} {
+ // TODO: possibly shrink array.
+ n := len(events) - 1
+ e := events[n]
+ events[n] = nil
+ events = events[0:n]
+ return e
}
diff --git a/src/pkg/time/sleep_test.go b/src/pkg/time/sleep_test.go
index 7ec6c4943..9e36288f8 100644
--- a/src/pkg/time/sleep_test.go
+++ b/src/pkg/time/sleep_test.go
@@ -8,6 +8,7 @@ import (
"os"
"syscall"
"testing"
+ "sort"
. "time"
)
@@ -24,3 +25,110 @@ func TestSleep(t *testing.T) {
t.Fatalf("Sleep(%d) slept for only %d ns", delay, duration)
}
}
+
+// Test the basic function calling behavior. Correct queueing
+// behavior is tested elsewhere, since After and AfterFunc share
+// the same code.
+func TestAfterFunc(t *testing.T) {
+ i := 10
+ c := make(chan bool)
+ var f func()
+ f = func() {
+ i--
+ if i >= 0 {
+ AfterFunc(0, f)
+ Sleep(1e9)
+ } else {
+ c <- true
+ }
+ }
+
+ AfterFunc(0, f)
+ <-c
+}
+
+func BenchmarkAfterFunc(b *testing.B) {
+ i := b.N
+ c := make(chan bool)
+ var f func()
+ f = func() {
+ i--
+ if i >= 0 {
+ AfterFunc(0, f)
+ } else {
+ c <- true
+ }
+ }
+
+ AfterFunc(0, f)
+ <-c
+}
+
+func TestAfter(t *testing.T) {
+ const delay = int64(100e6)
+ start := Nanoseconds()
+ end := <-After(delay)
+ if duration := Nanoseconds() - start; duration < delay {
+ t.Fatalf("After(%d) slept for only %d ns", delay, duration)
+ }
+ if min := start + delay; end < min {
+ t.Fatalf("After(%d) expect >= %d, got %d", delay, min, end)
+ }
+}
+
+func TestAfterTick(t *testing.T) {
+ const (
+ Delta = 100 * 1e6
+ Count = 10
+ )
+ t0 := Nanoseconds()
+ for i := 0; i < Count; i++ {
+ <-After(Delta)
+ }
+ t1 := Nanoseconds()
+ ns := t1 - t0
+ target := int64(Delta * Count)
+ slop := target * 2 / 10
+ if ns < target-slop || ns > target+slop {
+ t.Fatalf("%d ticks of %g ns took %g ns, expected %g", Count, float64(Delta), float64(ns), float64(target))
+ }
+}
+
+var slots = []int{5, 3, 6, 6, 6, 1, 1, 2, 7, 9, 4, 8, 0}
+
+type afterResult struct {
+ slot int
+ t int64
+}
+
+func await(slot int, result chan<- afterResult, ac <-chan int64) {
+ result <- afterResult{slot, <-ac}
+}
+
+func TestAfterQueuing(t *testing.T) {
+ const (
+ Delta = 100 * 1e6
+ )
+ // make the result channel buffered because we don't want
+ // to depend on channel queueing semantics that might
+ // possibly change in the future.
+ result := make(chan afterResult, len(slots))
+
+ t0 := Nanoseconds()
+ for _, slot := range slots {
+ go await(slot, result, After(int64(slot)*Delta))
+ }
+ sort.SortInts(slots)
+ for _, slot := range slots {
+ r := <-result
+ if r.slot != slot {
+ t.Fatalf("after queue got slot %d, expected %d", r.slot, slot)
+ }
+ ns := r.t - t0
+ target := int64(slot * Delta)
+ slop := int64(Delta) / 4
+ if ns < target-slop || ns > target+slop {
+ t.Fatalf("after queue slot %d arrived at %g, expected [%g,%g]", slot, float64(ns), float64(target-slop), float64(target+slop))
+ }
+ }
+}
diff --git a/src/pkg/time/tick.go b/src/pkg/time/tick.go
index 05023d4d0..ddd727270 100644
--- a/src/pkg/time/tick.go
+++ b/src/pkg/time/tick.go
@@ -5,7 +5,8 @@
package time
import (
- "once"
+ "os"
+ "sync"
)
// A Ticker holds a synchronous channel that delivers `ticks' of a clock
@@ -14,13 +15,16 @@ 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 bool
+ shutdown chan bool // Buffered channel used to signal shutdown.
nextTick int64
next *Ticker
}
// Stop turns off a ticker. After Stop, no more ticks will be sent.
-func (t *Ticker) Stop() { t.shutdown = true }
+func (t *Ticker) Stop() {
+ // Make it non-blocking so multiple Stops don't block.
+ _ = t.shutdown <- true
+}
// Tick is a convenience wrapper for NewTicker providing access to the ticking
// channel only. Useful for clients that have no need to shut down the ticker.
@@ -43,11 +47,12 @@ func (a *alarmer) set(ns int64) {
case a.wakeTime > ns:
// Next tick we expect is too late; shut down the late runner
// and (after fallthrough) start a new wakeLoop.
- a.wakeMeAt <- -1
+ close(a.wakeMeAt)
fallthrough
case a.wakeMeAt == nil:
// There's no wakeLoop, start one.
- a.wakeMeAt = make(chan int64, 10)
+ a.wakeMeAt = make(chan int64)
+ a.wakeUp = make(chan bool, 1)
go wakeLoop(a.wakeMeAt, a.wakeUp)
fallthrough
case a.wakeTime == 0:
@@ -69,19 +74,10 @@ func startTickerLoop() {
// 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 but they will share the wakeUp channel and signal that this one
-// is done by giving it a negative time request.
+// wakeLoop and signal that this one is done by closing the wakeMeAt channel.
func wakeLoop(wakeMeAt chan int64, wakeUp chan bool) {
- for {
- wakeAt := <-wakeMeAt
- if wakeAt < 0 { // tickerLoop has started another wakeLoop
- return
- }
- now := Nanoseconds()
- if wakeAt > now {
- Sleep(wakeAt - now)
- now = Nanoseconds()
- }
+ for wakeAt := range wakeMeAt {
+ Sleep(wakeAt - Nanoseconds())
wakeUp <- true
}
}
@@ -92,9 +88,7 @@ func wakeLoop(wakeMeAt chan int64, wakeUp chan bool) {
func tickerLoop() {
// Represents the next alarm to be delivered.
var alarm alarmer
- // All wakeLoops deliver wakeups to this channel.
- alarm.wakeUp = make(chan bool, 10)
- var now, prevTime, wakeTime int64
+ var now, wakeTime int64
var tickers *Ticker
for {
select {
@@ -106,17 +100,13 @@ func tickerLoop() {
alarm.set(t.nextTick)
case <-alarm.wakeUp:
now = Nanoseconds()
- // Ignore an old time due to a dying wakeLoop
- if now < prevTime {
- continue
- }
wakeTime = now + 1e15 // very long in the future
var prev *Ticker = nil
// Scan list of tickers, delivering updates to those
// that need it and determining the next wake time.
// TODO(r): list should be sorted in time order.
for t := tickers; t != nil; t = t.next {
- if t.shutdown {
+ if _, ok := <-t.shutdown; ok {
// Ticker is done; remove it from list.
if prev == nil {
tickers = t.next
@@ -147,25 +137,34 @@ func tickerLoop() {
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
}
}
- prevTime = now
}
}
+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.
+// 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 {
- return nil
+ panic(os.ErrorString("non-positive interval for NewTicker"))
}
c := make(chan int64, 1) // See comment on send in tickerLoop
- t := &Ticker{c, c, ns, false, Nanoseconds() + ns, nil}
- once.Do(startTickerLoop)
+ t := &Ticker{
+ C: c,
+ c: c,
+ ns: ns,
+ shutdown: make(chan bool, 1),
+ nextTick: Nanoseconds() + ns,
+ }
+ onceStartTickerLoop.Do(startTickerLoop)
// must be run in background so global Tickers can be created
go func() { newTicker <- t }()
return t
diff --git a/src/pkg/time/tick_test.go b/src/pkg/time/tick_test.go
index d089a9b98..2a63a0f2b 100644
--- a/src/pkg/time/tick_test.go
+++ b/src/pkg/time/tick_test.go
@@ -31,7 +31,7 @@ func TestTicker(t *testing.T) {
Sleep(2 * Delta)
_, received := <-ticker.C
if received {
- t.Fatalf("Ticker did not shut down")
+ t.Fatal("Ticker did not shut down")
}
}
diff --git a/src/pkg/time/time_test.go b/src/pkg/time/time_test.go
index 32bf9652e..c86bca1b4 100644
--- a/src/pkg/time/time_test.go
+++ b/src/pkg/time/time_test.go
@@ -25,21 +25,21 @@ type TimeTest struct {
}
var utctests = []TimeTest{
- TimeTest{0, Time{1970, 1, 1, 0, 0, 0, Thursday, 0, "UTC"}},
- TimeTest{1221681866, Time{2008, 9, 17, 20, 4, 26, Wednesday, 0, "UTC"}},
- TimeTest{-1221681866, Time{1931, 4, 16, 3, 55, 34, Thursday, 0, "UTC"}},
- TimeTest{-11644473600, Time{1601, 1, 1, 0, 0, 0, Monday, 0, "UTC"}},
- TimeTest{599529660, Time{1988, 12, 31, 0, 1, 0, Saturday, 0, "UTC"}},
- TimeTest{978220860, Time{2000, 12, 31, 0, 1, 0, Sunday, 0, "UTC"}},
- TimeTest{1e18, Time{31688740476, 10, 23, 1, 46, 40, Friday, 0, "UTC"}},
- TimeTest{-1e18, Time{-31688736537, 3, 10, 22, 13, 20, Tuesday, 0, "UTC"}},
- TimeTest{0x7fffffffffffffff, Time{292277026596, 12, 4, 15, 30, 7, Sunday, 0, "UTC"}},
- TimeTest{-0x8000000000000000, Time{-292277022657, 1, 27, 8, 29, 52, Sunday, 0, "UTC"}},
+ {0, Time{1970, 1, 1, 0, 0, 0, Thursday, 0, "UTC"}},
+ {1221681866, Time{2008, 9, 17, 20, 4, 26, Wednesday, 0, "UTC"}},
+ {-1221681866, Time{1931, 4, 16, 3, 55, 34, Thursday, 0, "UTC"}},
+ {-11644473600, Time{1601, 1, 1, 0, 0, 0, Monday, 0, "UTC"}},
+ {599529660, Time{1988, 12, 31, 0, 1, 0, Saturday, 0, "UTC"}},
+ {978220860, Time{2000, 12, 31, 0, 1, 0, Sunday, 0, "UTC"}},
+ {1e18, Time{31688740476, 10, 23, 1, 46, 40, Friday, 0, "UTC"}},
+ {-1e18, Time{-31688736537, 3, 10, 22, 13, 20, Tuesday, 0, "UTC"}},
+ {0x7fffffffffffffff, Time{292277026596, 12, 4, 15, 30, 7, Sunday, 0, "UTC"}},
+ {-0x8000000000000000, Time{-292277022657, 1, 27, 8, 29, 52, Sunday, 0, "UTC"}},
}
var localtests = []TimeTest{
- TimeTest{0, Time{1969, 12, 31, 16, 0, 0, Wednesday, -8 * 60 * 60, "PST"}},
- TimeTest{1221681866, Time{2008, 9, 17, 13, 4, 26, Wednesday, -7 * 60 * 60, "PDT"}},
+ {0, Time{1969, 12, 31, 16, 0, 0, Wednesday, -8 * 60 * 60, "PST"}},
+ {1221681866, Time{2008, 9, 17, 13, 4, 26, Wednesday, -7 * 60 * 60, "PDT"}},
}
func same(t, u *Time) bool {
@@ -108,9 +108,9 @@ type TimeFormatTest struct {
}
var rfc3339Formats = []TimeFormatTest{
- TimeFormatTest{Time{2008, 9, 17, 20, 4, 26, Wednesday, 0, "UTC"}, "2008-09-17T20:04:26Z"},
- TimeFormatTest{Time{1994, 9, 17, 20, 4, 26, Wednesday, -18000, "EST"}, "1994-09-17T20:04:26-05:00"},
- TimeFormatTest{Time{2000, 12, 26, 1, 15, 6, Wednesday, 15600, "OTO"}, "2000-12-26T01:15:06+04:20"},
+ {Time{2008, 9, 17, 20, 4, 26, Wednesday, 0, "UTC"}, "2008-09-17T20:04:26Z"},
+ {Time{1994, 9, 17, 20, 4, 26, Wednesday, -18000, "EST"}, "1994-09-17T20:04:26-05:00"},
+ {Time{2000, 12, 26, 1, 15, 6, Wednesday, 15600, "OTO"}, "2000-12-26T01:15:06+04:20"},
}
func TestRFC3339Conversion(t *testing.T) {
@@ -130,16 +130,16 @@ type FormatTest struct {
}
var formatTests = []FormatTest{
- FormatTest{"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010"},
- FormatTest{"UnixDate", UnixDate, "Thu Feb 4 21:00:57 PST 2010"},
- FormatTest{"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0800 2010"},
- FormatTest{"RFC822", RFC822, "04 Feb 10 2100 PST"},
- FormatTest{"RFC850", RFC850, "Thursday, 04-Feb-10 21:00:57 PST"},
- FormatTest{"RFC1123", RFC1123, "Thu, 04 Feb 2010 21:00:57 PST"},
- FormatTest{"RFC3339", RFC3339, "2010-02-04T21:00:57-08:00"},
- FormatTest{"Kitchen", Kitchen, "9:00PM"},
- FormatTest{"am/pm", "3pm", "9pm"},
- FormatTest{"AM/PM", "3PM", "9PM"},
+ {"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010"},
+ {"UnixDate", UnixDate, "Thu Feb 4 21:00:57 PST 2010"},
+ {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0800 2010"},
+ {"RFC822", RFC822, "04 Feb 10 2100 PST"},
+ {"RFC850", RFC850, "Thursday, 04-Feb-10 21:00:57 PST"},
+ {"RFC1123", RFC1123, "Thu, 04 Feb 2010 21:00:57 PST"},
+ {"RFC3339", RFC3339, "2010-02-04T21:00:57-08:00"},
+ {"Kitchen", Kitchen, "9:00PM"},
+ {"am/pm", "3pm", "9pm"},
+ {"AM/PM", "3PM", "9PM"},
}
func TestFormat(t *testing.T) {
@@ -163,15 +163,16 @@ type ParseTest struct {
}
var parseTests = []ParseTest{
- ParseTest{"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010", false, true, 1},
- ParseTest{"UnixDate", UnixDate, "Thu Feb 4 21:00:57 PST 2010", true, true, 1},
- ParseTest{"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0800 2010", true, true, 1},
- ParseTest{"RFC850", RFC850, "Thursday, 04-Feb-10 21:00:57 PST", true, true, 1},
- ParseTest{"RFC1123", RFC1123, "Thu, 04 Feb 2010 21:00:57 PST", true, true, 1},
- ParseTest{"RFC3339", RFC3339, "2010-02-04T21:00:57-08:00", true, false, 1},
+ {"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010", false, true, 1},
+ {"UnixDate", UnixDate, "Thu Feb 4 21:00:57 PST 2010", true, true, 1},
+ {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0800 2010", true, true, 1},
+ {"RFC850", RFC850, "Thursday, 04-Feb-10 21:00:57 PST", true, true, 1},
+ {"RFC1123", RFC1123, "Thu, 04 Feb 2010 21:00:57 PST", true, true, 1},
+ {"RFC3339", RFC3339, "2010-02-04T21:00:57-08:00", true, false, 1},
+ {"custom: \"2006-01-02 15:04:05-07\"", "2006-01-02 15:04:05-07", "2010-02-04 21:00:57-08", true, false, 1},
// Amount of white space should not matter.
- ParseTest{"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010", false, true, 1},
- ParseTest{"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010", false, true, 1},
+ {"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010", false, true, 1},
+ {"ANSIC", ANSIC, "Thu Feb 4 21:00:57 2010", false, true, 1},
}
func TestParse(t *testing.T) {
@@ -186,11 +187,11 @@ func TestParse(t *testing.T) {
}
var rubyTests = []ParseTest{
- ParseTest{"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0800 2010", true, true, 1},
+ {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0800 2010", true, true, 1},
// Ignore the time zone in the test. If it parses, it'll be OK.
- ParseTest{"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0000 2010", false, true, 1},
- ParseTest{"RubyDate", RubyDate, "Thu Feb 04 21:00:57 +0000 2010", false, true, 1},
- ParseTest{"RubyDate", RubyDate, "Thu Feb 04 21:00:57 +1130 2010", false, true, 1},
+ {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 -0000 2010", false, true, 1},
+ {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 +0000 2010", false, true, 1},
+ {"RubyDate", RubyDate, "Thu Feb 04 21:00:57 +1130 2010", false, true, 1},
}
// Problematic time zone format needs special tests.
@@ -208,28 +209,28 @@ func TestRubyParse(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\n", test.name, 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\n", test.name, time.Month, 2)
+ t.Errorf("%s: bad month: %d not %d", test.name, time.Month, 2)
}
if time.Day != 4 {
- t.Errorf("%s: bad day: %d not %d\n", test.name, 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\n", test.name, 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\n", test.name, 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\n", test.name, time.Second, 57)
+ t.Errorf("%s: bad second: %d not %d", test.name, time.Second, 57)
}
if test.hasTZ && time.ZoneOffset != -28800 {
- t.Errorf("%s: bad tz offset: %d not %d\n", test.name, time.ZoneOffset, -28800)
+ t.Errorf("%s: bad tz offset: %d not %d", test.name, time.ZoneOffset, -28800)
}
if test.hasWD && time.Weekday != 4 {
- t.Errorf("%s: bad weekday: %d not %d\n", test.name, time.Weekday, 4)
+ t.Errorf("%s: bad weekday: %d not %d", test.name, time.Weekday, 4)
}
}
@@ -271,20 +272,20 @@ type ParseErrorTest struct {
}
var parseErrorTests = []ParseErrorTest{
- ParseErrorTest{ANSIC, "Feb 4 21:00:60 2010", "parse"}, // cannot parse Feb as Mon
- ParseErrorTest{ANSIC, "Thu Feb 4 21:00:57 @2010", "parse"},
- ParseErrorTest{ANSIC, "Thu Feb 4 21:00:60 2010", "second out of range"},
- ParseErrorTest{ANSIC, "Thu Feb 4 21:61:57 2010", "minute out of range"},
- ParseErrorTest{ANSIC, "Thu Feb 4 24:00:60 2010", "hour out of range"},
+ {ANSIC, "Feb 4 21:00:60 2010", "parse"}, // cannot parse Feb as Mon
+ {ANSIC, "Thu Feb 4 21:00:57 @2010", "parse"},
+ {ANSIC, "Thu Feb 4 21:00:60 2010", "second out of range"},
+ {ANSIC, "Thu Feb 4 21:61:57 2010", "minute out of range"},
+ {ANSIC, "Thu Feb 4 24:00:60 2010", "hour out of range"},
}
func TestParseErrors(t *testing.T) {
for _, test := range parseErrorTests {
_, err := Parse(test.format, test.value)
if err == nil {
- t.Errorf("expected error for %q %q\n", test.format, test.value)
+ t.Errorf("expected error for %q %q", test.format, test.value)
} else if strings.Index(err.String(), test.expect) < 0 {
- t.Errorf("expected error with %q for %q %q; got %s\n", test.expect, test.format, test.value, err)
+ t.Errorf("expected error with %q for %q %q; got %s", test.expect, test.format, test.value, err)
}
}
}
@@ -303,6 +304,17 @@ func TestMissingZone(t *testing.T) {
}
}
+func TestMinutesInTimeZone(t *testing.T) {
+ time, err := Parse(RubyDate, "Mon Jan 02 15:04:05 +0123 2006")
+ if err != nil {
+ t.Fatal("error parsing date:", err)
+ }
+ expected := (1*60 + 23) * 60
+ if time.ZoneOffset != expected {
+ t.Errorf("ZoneOffset incorrect, expected %d got %d", expected, time.ZoneOffset)
+ }
+}
+
func BenchmarkSeconds(b *testing.B) {
for i := 0; i < b.N; i++ {
Seconds()
diff --git a/src/pkg/time/zoneinfo.go b/src/pkg/time/zoneinfo.go
deleted file mode 100644
index 7884898f7..000000000
--- a/src/pkg/time/zoneinfo.go
+++ /dev/null
@@ -1,243 +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 "zoneinfo" time zone file.
-// This is a fairly standard file format used on OS X, Linux, BSD, Sun, and others.
-// See tzfile(5), http://en.wikipedia.org/wiki/Zoneinfo,
-// and ftp://munnari.oz.au/pub/oldtz/
-
-package time
-
-import (
- "io/ioutil"
- "once"
- "os"
-)
-
-const (
- headerSize = 4 + 16 + 4*7
- zoneDir = "/usr/share/zoneinfo/"
-)
-
-// Simple I/O interface to binary blob of data.
-type data struct {
- p []byte
- error bool
-}
-
-
-func (d *data) read(n int) []byte {
- if len(d.p) < n {
- d.p = nil
- d.error = true
- return nil
- }
- p := d.p[0:n]
- d.p = d.p[n:]
- return p
-}
-
-func (d *data) big4() (n uint32, ok bool) {
- p := d.read(4)
- if len(p) < 4 {
- d.error = true
- return 0, false
- }
- return uint32(p[0])<<24 | uint32(p[1])<<16 | uint32(p[2])<<8 | uint32(p[3]), true
-}
-
-func (d *data) byte() (n byte, ok bool) {
- p := d.read(1)
- if len(p) < 1 {
- d.error = true
- return 0, false
- }
- return p[0], true
-}
-
-
-// Make a string by stopping at the first NUL
-func byteString(p []byte) string {
- for i := 0; i < len(p); i++ {
- if p[i] == 0 {
- return string(p[0:i])
- }
- }
- return string(p)
-}
-
-// Parsed representation
-type zone struct {
- utcoff int
- isdst bool
- name string
-}
-
-type zonetime struct {
- time int32 // transition time, in seconds since 1970 GMT
- zone *zone // the zone that goes into effect at that time
- isstd, isutc bool // ignored - no idea what these mean
-}
-
-func parseinfo(bytes []byte) (zt []zonetime, ok bool) {
- d := data{bytes, false}
-
- // 4-byte magic "TZif"
- if magic := d.read(4); string(magic) != "TZif" {
- return nil, false
- }
-
- // 1-byte version, then 15 bytes of padding
- var p []byte
- if p = d.read(16); len(p) != 16 || p[0] != 0 && p[0] != '2' {
- return nil, false
- }
-
- // six big-endian 32-bit integers:
- // number of UTC/local indicators
- // number of standard/wall indicators
- // number of leap seconds
- // number of transition times
- // number of local time zones
- // number of characters of time zone abbrev strings
- const (
- NUTCLocal = iota
- NStdWall
- NLeap
- NTime
- NZone
- NChar
- )
- var n [6]int
- for i := 0; i < 6; i++ {
- nn, ok := d.big4()
- if !ok {
- return nil, false
- }
- n[i] = int(nn)
- }
-
- // Transition times.
- txtimes := data{d.read(n[NTime] * 4), false}
-
- // Time zone indices for transition times.
- txzones := d.read(n[NTime])
-
- // Zone info structures
- zonedata := data{d.read(n[NZone] * 6), false}
-
- // Time zone abbreviations.
- abbrev := d.read(n[NChar])
-
- // Leap-second time pairs
- d.read(n[NLeap] * 8)
-
- // Whether tx times associated with local time types
- // are specified as standard time or wall time.
- isstd := d.read(n[NStdWall])
-
- // Whether tx times associated with local time types
- // are specified as UTC or local time.
- isutc := d.read(n[NUTCLocal])
-
- if d.error { // ran out of data
- return nil, false
- }
-
- // If version == 2, the entire file repeats, this time using
- // 8-byte ints for txtimes and leap seconds.
- // We won't need those until 2106.
-
- // Now we can build up a useful data structure.
- // First the zone information.
- // utcoff[4] isdst[1] nameindex[1]
- z := make([]zone, n[NZone])
- for i := 0; i < len(z); i++ {
- var ok bool
- var n uint32
- if n, ok = zonedata.big4(); !ok {
- return nil, false
- }
- z[i].utcoff = int(n)
- var b byte
- if b, ok = zonedata.byte(); !ok {
- return nil, false
- }
- z[i].isdst = b != 0
- if b, ok = zonedata.byte(); !ok || int(b) >= len(abbrev) {
- return nil, false
- }
- z[i].name = byteString(abbrev[b:])
- }
-
- // Now the transition time info.
- zt = make([]zonetime, n[NTime])
- for i := 0; i < len(zt); i++ {
- var ok bool
- var n uint32
- if n, ok = txtimes.big4(); !ok {
- return nil, false
- }
- zt[i].time = int32(n)
- if int(txzones[i]) >= len(z) {
- return nil, false
- }
- zt[i].zone = &z[txzones[i]]
- if i < len(isstd) {
- zt[i].isstd = isstd[i] != 0
- }
- if i < len(isutc) {
- zt[i].isutc = isutc[i] != 0
- }
- }
- return zt, true
-}
-
-func readinfofile(name string) ([]zonetime, bool) {
- buf, err := ioutil.ReadFile(name)
- if err != nil {
- return nil, false
- }
- return parseinfo(buf)
-}
-
-var zones []zonetime
-
-func setupZone() {
- // consult $TZ to find the time zone to use.
- // no $TZ means use the system default /etc/localtime.
- // $TZ="" means use UTC.
- // $TZ="foo" means use /usr/share/zoneinfo/foo.
-
- tz, err := os.Getenverror("TZ")
- switch {
- case err == os.ENOENV:
- zones, _ = readinfofile("/etc/localtime")
- case len(tz) > 0:
- zones, _ = readinfofile(zoneDir + tz)
- case len(tz) == 0:
- // do nothing: use UTC
- }
-}
-
-// Look up the correct time zone (daylight savings or not) for the given unix time, in the current location.
-func lookupTimezone(sec int64) (zone string, offset int) {
- once.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
-}
diff --git a/src/pkg/time/zoneinfo_unix.go b/src/pkg/time/zoneinfo_unix.go
index 5a8c94aaf..26c86ab03 100644
--- a/src/pkg/time/zoneinfo_unix.go
+++ b/src/pkg/time/zoneinfo_unix.go
@@ -11,8 +11,8 @@ package time
import (
"io/ioutil"
- "once"
"os"
+ "sync"
)
const (
@@ -203,6 +203,7 @@ func readinfofile(name string) ([]zonetime, bool) {
}
var zones []zonetime
+var onceSetupZone sync.Once
func setupZone() {
// consult $TZ to find the time zone to use.
@@ -223,7 +224,7 @@ func setupZone() {
// 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) {
- once.Do(setupZone)
+ onceSetupZone.Do(setupZone)
if len(zones) == 0 {
return "UTC", 0
}
@@ -251,7 +252,7 @@ func lookupTimezone(sec int64) (zone string, offset int) {
// 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) {
- once.Do(setupZone)
+ onceSetupZone.Do(setupZone)
for _, z := range zones {
if name == z.zone.name {
return z.zone.utcoff, true
diff --git a/src/pkg/time/zoneinfo_windows.go b/src/pkg/time/zoneinfo_windows.go
index d249165c1..c357eec62 100644
--- a/src/pkg/time/zoneinfo_windows.go
+++ b/src/pkg/time/zoneinfo_windows.go
@@ -6,8 +6,8 @@ package time
import (
"syscall"
+ "sync"
"os"
- "once"
)
// BUG(brainman): The Windows implementation assumes that
@@ -121,6 +121,7 @@ func (zi *zoneinfo) pickZone(t *Time) *zone {
var tz zoneinfo
var initError os.Error
+var onceSetupZone sync.Once
func setupZone() {
var i syscall.Timezoneinformation
@@ -145,7 +146,7 @@ func setupZone() {
// 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) {
- once.Do(setupZone)
+ onceSetupZone.Do(setupZone)
if initError != nil {
return "", 0
}
@@ -174,7 +175,7 @@ func lookupTimezone(sec int64) (zone string, offset int) {
// 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) {
- once.Do(setupZone)
+ onceSetupZone.Do(setupZone)
if initError != nil {
return 0, false
}
diff --git a/src/pkg/nntp/Makefile b/src/pkg/try/Makefile
index 3cf3164ce..06981a6fc 100644
--- a/src/pkg/nntp/Makefile
+++ b/src/pkg/try/Makefile
@@ -2,10 +2,10 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.$(GOARCH)
+include ../../Make.inc
-TARG=nntp
+TARG=try
GOFILES=\
- nntp.go
+ try.go\
include ../../Make.pkg
diff --git a/src/pkg/try/try.go b/src/pkg/try/try.go
new file mode 100644
index 000000000..af31d0d2c
--- /dev/null
+++ b/src/pkg/try/try.go
@@ -0,0 +1,174 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package try contains the executable part of the gotry command.
+// It is not intended for general use.
+package try
+
+import (
+ "fmt"
+ "io"
+ "os"
+ "reflect"
+ "unicode"
+)
+
+var output io.Writer = os.Stdout // redirected when testing
+
+// Main is called directly from the gotry-generated Go source file to perform
+// the evaluations.
+func Main(pkg, firstArg string, functions map[string]interface{}, args []interface{}) {
+ switch len(args) {
+ case 0:
+ // Nothing to do.
+ case 1:
+ // Compiler has already evaluated the expression; just print the result.
+ printSlice(firstArg, args)
+ default:
+ // See if methods satisfy the expressions.
+ tryMethods(pkg, firstArg, args)
+ // See if functions satisfy the expressions.
+ for name, fn := range functions {
+ tryFunction(pkg, name, fn, args)
+ }
+ }
+}
+
+// printSlice prints the zeroth element of the args slice, which should (by construction)
+// itself be a slice of interface{}.
+func printSlice(firstArg string, args []interface{}) {
+ // Args should be length 1 and a slice.
+ if len(args) != 1 {
+ return
+ }
+ arg, ok := args[0].([]interface{})
+ if !ok {
+ return
+ }
+ fmt.Fprintf(output, "%s = ", firstArg)
+ if len(arg) > 1 {
+ fmt.Fprint(output, "(")
+ }
+ for i, a := range arg {
+ if i > 0 {
+ fmt.Fprint(output, ", ")
+ }
+ fmt.Fprintf(output, "%#v", a)
+ }
+ if len(arg) > 1 {
+ fmt.Fprint(output, ")")
+ }
+ fmt.Fprint(output, "\n")
+}
+
+// tryMethods sees if the zeroth arg has methods, and if so treats them as potential
+// functions to satisfy the remaining arguments.
+func tryMethods(pkg, firstArg string, args []interface{}) {
+ defer func() { recover() }()
+ // Is the first argument something with methods?
+ v := reflect.NewValue(args[0])
+ typ := v.Type()
+ if typ.NumMethod() == 0 {
+ return
+ }
+ for i := 0; i < typ.NumMethod(); i++ {
+ if unicode.IsUpper(int(typ.Method(i).Name[0])) {
+ tryMethod(pkg, firstArg, typ.Method(i), args)
+ }
+ }
+}
+
+// tryMethod converts a method to a function for tryOneFunction.
+func tryMethod(pkg, firstArg string, method reflect.Method, args []interface{}) {
+ rfn := method.Func
+ typ := method.Type
+ name := method.Name
+ tryOneFunction(pkg, firstArg, name, typ, rfn, args)
+}
+
+// tryFunction sees if fn satisfies the arguments.
+func tryFunction(pkg, name string, fn interface{}, args []interface{}) {
+ defer func() { recover() }()
+ rfn := reflect.NewValue(fn).(*reflect.FuncValue)
+ typ := rfn.Type().(*reflect.FuncType)
+ tryOneFunction(pkg, "", name, typ, rfn, args)
+}
+
+// tryOneFunction is the common code for tryMethod and tryFunction.
+func tryOneFunction(pkg, firstArg, name string, typ *reflect.FuncType, rfn *reflect.FuncValue, args []interface{}) {
+ // Any results?
+ if typ.NumOut() == 0 {
+ return // Nothing to do.
+ }
+ // Right number of arguments + results?
+ if typ.NumIn()+typ.NumOut() != len(args) {
+ return
+ }
+ // Right argument and result types?
+ for i, a := range args {
+ if i < typ.NumIn() {
+ if !compatible(a, typ.In(i)) {
+ return
+ }
+ } else {
+ if !compatible(a, typ.Out(i-typ.NumIn())) {
+ return
+ }
+ }
+ }
+ // Build the call args.
+ argsVal := make([]reflect.Value, typ.NumIn()+typ.NumOut())
+ for i, a := range args {
+ argsVal[i] = reflect.NewValue(a)
+ }
+ // Call the function and see if the results are as expected.
+ resultVal := rfn.Call(argsVal[:typ.NumIn()])
+ for i, v := range resultVal {
+ if !reflect.DeepEqual(v.Interface(), args[i+typ.NumIn()]) {
+ return
+ }
+ }
+ // Present the result including a godoc command to get more information.
+ firstIndex := 0
+ if firstArg != "" {
+ fmt.Fprintf(output, "%s.%s(", firstArg, name)
+ firstIndex = 1
+ } else {
+ fmt.Fprintf(output, "%s.%s(", pkg, name)
+ }
+ for i := firstIndex; i < typ.NumIn(); i++ {
+ if i > firstIndex {
+ fmt.Fprint(output, ", ")
+ }
+ fmt.Fprintf(output, "%#v", args[i])
+ }
+ fmt.Fprint(output, ") = ")
+ if typ.NumOut() > 1 {
+ fmt.Fprint(output, "(")
+ }
+ for i := 0; i < typ.NumOut(); i++ {
+ if i > 0 {
+ fmt.Fprint(output, ", ")
+ }
+ fmt.Fprintf(output, "%#v", resultVal[i].Interface())
+ }
+ if typ.NumOut() > 1 {
+ fmt.Fprint(output, ")")
+ }
+ fmt.Fprintf(output, " // godoc %s %s\n", pkg, name)
+}
+
+// compatible reports whether the argument is compatible with the type.
+func compatible(arg interface{}, typ reflect.Type) bool {
+ if reflect.Typeof(arg) == typ {
+ return true
+ }
+ if arg == nil {
+ // nil is OK if the type is an interface.
+ if _, ok := typ.(*reflect.InterfaceType); ok {
+ return true
+ }
+ }
+ return false
+}
diff --git a/src/pkg/try/try_test.go b/src/pkg/try/try_test.go
new file mode 100644
index 000000000..617b2c7c3
--- /dev/null
+++ b/src/pkg/try/try_test.go
@@ -0,0 +1,60 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package try
+
+import (
+ "bytes"
+ "regexp" // Used as the package to try.
+ "testing"
+)
+
+// The global functions in package regexp at time of writing.
+// Doesn't need to be updated unless the entries in this list become invalid.
+var functions = map[string]interface{}{
+ "Compile": regexp.Compile,
+ "Match": regexp.Match,
+ "MatchString": regexp.MatchString,
+ "MustCompile": regexp.MustCompile,
+ "QuoteMeta": regexp.QuoteMeta,
+}
+
+// A wraps arguments to make the test cases nicer to read.
+func A(args ...interface{}) []interface{} {
+ return args
+}
+
+type Test struct {
+ firstArg string // only needed if there is exactly one argument
+ result string // minus final newline; might be just the godoc string
+ args []interface{}
+}
+
+var testRE = regexp.MustCompile("a(.)(.)d")
+
+var tests = []Test{
+ // A simple expression. The final value is a slice in case the expression is multivalue.
+ {"3+4", "3+4 = 7", A([]interface{}{7})},
+ // A search for a function.
+ {"", "regexp QuoteMeta", A("([])", `\(\[\]\)`)},
+ // A search for a function with multiple return values.
+ {"", "regexp MatchString", A("abc", "xabcd", true, nil)},
+ // Searches for methods.
+ {"", "regexp MatchString", A(testRE, "xabcde", true)},
+ {"", "regexp NumSubexp", A(testRE, 2)},
+}
+
+func TestAll(t *testing.T) {
+ re := regexp.MustCompile(".*// godoc ")
+ for _, test := range tests {
+ b := new(bytes.Buffer)
+ output = b
+ Main("regexp", test.firstArg, functions, test.args)
+ expect := test.result + "\n"
+ got := re.ReplaceAllString(b.String(), "")
+ if got != expect {
+ t.Errorf("expected %q; got %q", expect, got)
+ }
+ }
+}
diff --git a/src/pkg/unicode/Makefile b/src/pkg/unicode/Makefile
index 0728ec881..df0b4a642 100644
--- a/src/pkg/unicode/Makefile
+++ b/src/pkg/unicode/Makefile
@@ -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 ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=unicode
GOFILES=\
diff --git a/src/pkg/unicode/digit_test.go b/src/pkg/unicode/digit_test.go
index 57a625b02..9bbccde92 100644
--- a/src/pkg/unicode/digit_test.go
+++ b/src/pkg/unicode/digit_test.go
@@ -106,12 +106,12 @@ var testLetter = []int{
func TestDigit(t *testing.T) {
for _, r := range testDigit {
if !IsDigit(r) {
- t.Errorf("IsDigit(U+%04X) = false, want true\n", r)
+ t.Errorf("IsDigit(U+%04X) = false, want true", r)
}
}
for _, r := range testLetter {
if IsDigit(r) {
- t.Errorf("IsDigit(U+%04X) = true, want false\n", r)
+ t.Errorf("IsDigit(U+%04X) = true, want false", r)
}
}
}
diff --git a/src/pkg/unicode/letter_test.go b/src/pkg/unicode/letter_test.go
index 294e79aa5..b8ef64827 100644
--- a/src/pkg/unicode/letter_test.go
+++ b/src/pkg/unicode/letter_test.go
@@ -112,121 +112,121 @@ type caseT struct {
var caseTest = []caseT{
// errors
- caseT{-1, '\n', 0xFFFD},
- caseT{UpperCase, -1, -1},
- caseT{UpperCase, 1 << 30, 1 << 30},
+ {-1, '\n', 0xFFFD},
+ {UpperCase, -1, -1},
+ {UpperCase, 1 << 30, 1 << 30},
// ASCII (special-cased so test carefully)
- caseT{UpperCase, '\n', '\n'},
- caseT{UpperCase, 'a', 'A'},
- caseT{UpperCase, 'A', 'A'},
- caseT{UpperCase, '7', '7'},
- caseT{LowerCase, '\n', '\n'},
- caseT{LowerCase, 'a', 'a'},
- caseT{LowerCase, 'A', 'a'},
- caseT{LowerCase, '7', '7'},
- caseT{TitleCase, '\n', '\n'},
- caseT{TitleCase, 'a', 'A'},
- caseT{TitleCase, 'A', 'A'},
- caseT{TitleCase, '7', '7'},
+ {UpperCase, '\n', '\n'},
+ {UpperCase, 'a', 'A'},
+ {UpperCase, 'A', 'A'},
+ {UpperCase, '7', '7'},
+ {LowerCase, '\n', '\n'},
+ {LowerCase, 'a', 'a'},
+ {LowerCase, 'A', 'a'},
+ {LowerCase, '7', '7'},
+ {TitleCase, '\n', '\n'},
+ {TitleCase, 'a', 'A'},
+ {TitleCase, 'A', 'A'},
+ {TitleCase, '7', '7'},
// Latin-1: easy to read the tests!
- caseT{UpperCase, 0x80, 0x80},
- caseT{UpperCase, 'Å', 'Å'},
- caseT{UpperCase, 'å', 'Å'},
- caseT{LowerCase, 0x80, 0x80},
- caseT{LowerCase, 'Å', 'å'},
- caseT{LowerCase, 'å', 'å'},
- caseT{TitleCase, 0x80, 0x80},
- caseT{TitleCase, 'Å', 'Å'},
- caseT{TitleCase, 'å', 'Å'},
+ {UpperCase, 0x80, 0x80},
+ {UpperCase, 'Å', 'Å'},
+ {UpperCase, 'å', 'Å'},
+ {LowerCase, 0x80, 0x80},
+ {LowerCase, 'Å', 'å'},
+ {LowerCase, 'å', 'å'},
+ {TitleCase, 0x80, 0x80},
+ {TitleCase, 'Å', 'Å'},
+ {TitleCase, 'å', 'Å'},
// 0131;LATIN SMALL LETTER DOTLESS I;Ll;0;L;;;;;N;;;0049;;0049
- caseT{UpperCase, 0x0131, 'I'},
- caseT{LowerCase, 0x0131, 0x0131},
- caseT{TitleCase, 0x0131, 'I'},
+ {UpperCase, 0x0131, 'I'},
+ {LowerCase, 0x0131, 0x0131},
+ {TitleCase, 0x0131, 'I'},
// 0133;LATIN SMALL LIGATURE IJ;Ll;0;L;<compat> 0069 006A;;;;N;LATIN SMALL LETTER I J;;0132;;0132
- caseT{UpperCase, 0x0133, 0x0132},
- caseT{LowerCase, 0x0133, 0x0133},
- caseT{TitleCase, 0x0133, 0x0132},
+ {UpperCase, 0x0133, 0x0132},
+ {LowerCase, 0x0133, 0x0133},
+ {TitleCase, 0x0133, 0x0132},
// 212A;KELVIN SIGN;Lu;0;L;004B;;;;N;DEGREES KELVIN;;;006B;
- caseT{UpperCase, 0x212A, 0x212A},
- caseT{LowerCase, 0x212A, 'k'},
- caseT{TitleCase, 0x212A, 0x212A},
+ {UpperCase, 0x212A, 0x212A},
+ {LowerCase, 0x212A, 'k'},
+ {TitleCase, 0x212A, 0x212A},
// From an UpperLower sequence
// A640;CYRILLIC CAPITAL LETTER ZEMLYA;Lu;0;L;;;;;N;;;;A641;
- caseT{UpperCase, 0xA640, 0xA640},
- caseT{LowerCase, 0xA640, 0xA641},
- caseT{TitleCase, 0xA640, 0xA640},
+ {UpperCase, 0xA640, 0xA640},
+ {LowerCase, 0xA640, 0xA641},
+ {TitleCase, 0xA640, 0xA640},
// A641;CYRILLIC SMALL LETTER ZEMLYA;Ll;0;L;;;;;N;;;A640;;A640
- caseT{UpperCase, 0xA641, 0xA640},
- caseT{LowerCase, 0xA641, 0xA641},
- caseT{TitleCase, 0xA641, 0xA640},
+ {UpperCase, 0xA641, 0xA640},
+ {LowerCase, 0xA641, 0xA641},
+ {TitleCase, 0xA641, 0xA640},
// A64E;CYRILLIC CAPITAL LETTER NEUTRAL YER;Lu;0;L;;;;;N;;;;A64F;
- caseT{UpperCase, 0xA64E, 0xA64E},
- caseT{LowerCase, 0xA64E, 0xA64F},
- caseT{TitleCase, 0xA64E, 0xA64E},
+ {UpperCase, 0xA64E, 0xA64E},
+ {LowerCase, 0xA64E, 0xA64F},
+ {TitleCase, 0xA64E, 0xA64E},
// A65F;CYRILLIC SMALL LETTER YN;Ll;0;L;;;;;N;;;A65E;;A65E
- caseT{UpperCase, 0xA65F, 0xA65E},
- caseT{LowerCase, 0xA65F, 0xA65F},
- caseT{TitleCase, 0xA65F, 0xA65E},
+ {UpperCase, 0xA65F, 0xA65E},
+ {LowerCase, 0xA65F, 0xA65F},
+ {TitleCase, 0xA65F, 0xA65E},
// From another UpperLower sequence
// 0139;LATIN CAPITAL LETTER L WITH ACUTE;Lu;0;L;004C 0301;;;;N;LATIN CAPITAL LETTER L ACUTE;;;013A;
- caseT{UpperCase, 0x0139, 0x0139},
- caseT{LowerCase, 0x0139, 0x013A},
- caseT{TitleCase, 0x0139, 0x0139},
+ {UpperCase, 0x0139, 0x0139},
+ {LowerCase, 0x0139, 0x013A},
+ {TitleCase, 0x0139, 0x0139},
// 013F;LATIN CAPITAL LETTER L WITH MIDDLE DOT;Lu;0;L;<compat> 004C 00B7;;;;N;;;;0140;
- caseT{UpperCase, 0x013f, 0x013f},
- caseT{LowerCase, 0x013f, 0x0140},
- caseT{TitleCase, 0x013f, 0x013f},
+ {UpperCase, 0x013f, 0x013f},
+ {LowerCase, 0x013f, 0x0140},
+ {TitleCase, 0x013f, 0x013f},
// 0148;LATIN SMALL LETTER N WITH CARON;Ll;0;L;006E 030C;;;;N;LATIN SMALL LETTER N HACEK;;0147;;0147
- caseT{UpperCase, 0x0148, 0x0147},
- caseT{LowerCase, 0x0148, 0x0148},
- caseT{TitleCase, 0x0148, 0x0147},
+ {UpperCase, 0x0148, 0x0147},
+ {LowerCase, 0x0148, 0x0148},
+ {TitleCase, 0x0148, 0x0147},
// Last block in the 5.1.0 table
// 10400;DESERET CAPITAL LETTER LONG I;Lu;0;L;;;;;N;;;;10428;
- caseT{UpperCase, 0x10400, 0x10400},
- caseT{LowerCase, 0x10400, 0x10428},
- caseT{TitleCase, 0x10400, 0x10400},
+ {UpperCase, 0x10400, 0x10400},
+ {LowerCase, 0x10400, 0x10428},
+ {TitleCase, 0x10400, 0x10400},
// 10427;DESERET CAPITAL LETTER EW;Lu;0;L;;;;;N;;;;1044F;
- caseT{UpperCase, 0x10427, 0x10427},
- caseT{LowerCase, 0x10427, 0x1044F},
- caseT{TitleCase, 0x10427, 0x10427},
+ {UpperCase, 0x10427, 0x10427},
+ {LowerCase, 0x10427, 0x1044F},
+ {TitleCase, 0x10427, 0x10427},
// 10428;DESERET SMALL LETTER LONG I;Ll;0;L;;;;;N;;;10400;;10400
- caseT{UpperCase, 0x10428, 0x10400},
- caseT{LowerCase, 0x10428, 0x10428},
- caseT{TitleCase, 0x10428, 0x10400},
+ {UpperCase, 0x10428, 0x10400},
+ {LowerCase, 0x10428, 0x10428},
+ {TitleCase, 0x10428, 0x10400},
// 1044F;DESERET SMALL LETTER EW;Ll;0;L;;;;;N;;;10427;;10427
- caseT{UpperCase, 0x1044F, 0x10427},
- caseT{LowerCase, 0x1044F, 0x1044F},
- caseT{TitleCase, 0x1044F, 0x10427},
+ {UpperCase, 0x1044F, 0x10427},
+ {LowerCase, 0x1044F, 0x1044F},
+ {TitleCase, 0x1044F, 0x10427},
// First one not in the 5.1.0 table
// 10450;SHAVIAN LETTER PEEP;Lo;0;L;;;;;N;;;;;
- caseT{UpperCase, 0x10450, 0x10450},
- caseT{LowerCase, 0x10450, 0x10450},
- caseT{TitleCase, 0x10450, 0x10450},
+ {UpperCase, 0x10450, 0x10450},
+ {LowerCase, 0x10450, 0x10450},
+ {TitleCase, 0x10450, 0x10450},
}
func TestIsLetter(t *testing.T) {
for _, r := range upperTest {
if !IsLetter(r) {
- t.Errorf("IsLetter(U+%04X) = false, want true\n", r)
+ t.Errorf("IsLetter(U+%04X) = false, want true", r)
}
}
for _, r := range letterTest {
if !IsLetter(r) {
- t.Errorf("IsLetter(U+%04X) = false, want true\n", r)
+ t.Errorf("IsLetter(U+%04X) = false, want true", r)
}
}
for _, r := range notletterTest {
if IsLetter(r) {
- t.Errorf("IsLetter(U+%04X) = true, want false\n", r)
+ t.Errorf("IsLetter(U+%04X) = true, want false", r)
}
}
}
@@ -234,17 +234,17 @@ func TestIsLetter(t *testing.T) {
func TestIsUpper(t *testing.T) {
for _, r := range upperTest {
if !IsUpper(r) {
- t.Errorf("IsUpper(U+%04X) = false, want true\n", r)
+ t.Errorf("IsUpper(U+%04X) = false, want true", r)
}
}
for _, r := range notupperTest {
if IsUpper(r) {
- t.Errorf("IsUpper(U+%04X) = true, want false\n", r)
+ t.Errorf("IsUpper(U+%04X) = true, want false", r)
}
}
for _, r := range notletterTest {
if IsUpper(r) {
- t.Errorf("IsUpper(U+%04X) = true, want false\n", r)
+ t.Errorf("IsUpper(U+%04X) = true, want false", r)
}
}
}
@@ -265,7 +265,7 @@ func TestTo(t *testing.T) {
for _, c := range caseTest {
r := To(c.cas, c.in)
if c.out != r {
- t.Errorf("To(U+%04X, %s) = U+%04X want U+%04X\n", c.in, caseString(c.cas), r, c.out)
+ t.Errorf("To(U+%04X, %s) = U+%04X want U+%04X", c.in, caseString(c.cas), r, c.out)
}
}
}
@@ -277,7 +277,7 @@ func TestToUpperCase(t *testing.T) {
}
r := ToUpper(c.in)
if c.out != r {
- t.Errorf("ToUpper(U+%04X) = U+%04X want U+%04X\n", c.in, r, c.out)
+ t.Errorf("ToUpper(U+%04X) = U+%04X want U+%04X", c.in, r, c.out)
}
}
}
@@ -289,7 +289,7 @@ func TestToLowerCase(t *testing.T) {
}
r := ToLower(c.in)
if c.out != r {
- t.Errorf("ToLower(U+%04X) = U+%04X want U+%04X\n", c.in, r, c.out)
+ t.Errorf("ToLower(U+%04X) = U+%04X want U+%04X", c.in, r, c.out)
}
}
}
@@ -301,7 +301,7 @@ func TestToTitleCase(t *testing.T) {
}
r := ToTitle(c.in)
if c.out != r {
- t.Errorf("ToTitle(U+%04X) = U+%04X want U+%04X\n", c.in, r, c.out)
+ t.Errorf("ToTitle(U+%04X) = U+%04X want U+%04X", c.in, r, c.out)
}
}
}
diff --git a/src/pkg/unicode/maketables.go b/src/pkg/unicode/maketables.go
index 4fc41cdea..081e1a119 100644
--- a/src/pkg/unicode/maketables.go
+++ b/src/pkg/unicode/maketables.go
@@ -157,7 +157,7 @@ func parseCategory(line string) (state State) {
char := &chars[point]
char.field = field
if char.codePoint != 0 {
- die.Logf("point U+%04x reused\n")
+ die.Logf("point %U reused\n")
}
char.codePoint = lastChar
char.category = field[FGeneralCategory]
@@ -167,7 +167,7 @@ func parseCategory(line string) (state State) {
// Decimal digit
_, err := strconv.Atoi(field[FNumericValue])
if err != nil {
- die.Log("U+%04x: bad numeric field: %s", point, err)
+ die.Log("%U: bad numeric field: %s", point, err)
}
case "Lu":
char.letter(field[FCodePoint], field[FSimpleLowercaseMapping], field[FSimpleTitlecaseMapping])
@@ -208,7 +208,7 @@ func (char *Char) letterValue(s string, cas string) int {
v, err := strconv.Btoui64(s, 16)
if err != nil {
char.dump(cas)
- die.Logf("U+%04x: bad letter(%s): %s", char.codePoint, s, err)
+ die.Logf("%U: bad letter(%s): %s", char.codePoint, s, err)
}
return int(v)
}
@@ -326,10 +326,10 @@ func printCategories() {
if *tablelist == "all" {
fmt.Println("// Categories is the set of Unicode data tables.")
fmt.Println("var Categories = map[string] []Range {")
- for k, _ := range category {
+ for k := range category {
fmt.Printf("\t%q: %s,\n", k, k)
}
- fmt.Printf("}\n\n")
+ fmt.Print("}\n\n")
}
decl := make(sort.StringArray, len(list))
@@ -377,7 +377,7 @@ func printCategories() {
for _, d := range decl {
fmt.Print(d)
}
- fmt.Println(")\n")
+ fmt.Print(")\n\n")
}
type Op func(code int) bool
@@ -493,17 +493,7 @@ func parseScript(line string, scripts map[string][]Script) {
}
}
name := matches[3]
- s, ok := scripts[name]
- if !ok || len(s) == cap(s) {
- ns := make([]Script, len(s), len(s)+100)
- for i, sc := range s {
- ns[i] = sc
- }
- s = ns
- }
- s = s[0 : len(s)+1]
- s[len(s)-1] = Script{uint32(lo), uint32(hi), name}
- scripts[name] = s
+ scripts[name] = append(scripts[name], Script{uint32(lo), uint32(hi), name})
}
// The script tables have a lot of adjacent elements. Fold them together.
@@ -604,10 +594,10 @@ func printScriptOrProperty(doProps bool) {
fmt.Println("// Scripts is the set of Unicode script tables.")
fmt.Println("var Scripts = map[string] []Range {")
}
- for k, _ := range table {
+ for k := range table {
fmt.Printf("\t%q: %s,\n", k, k)
}
- fmt.Printf("}\n\n")
+ fmt.Print("}\n\n")
}
decl := make(sort.StringArray, len(list))
@@ -628,14 +618,14 @@ func printScriptOrProperty(doProps bool) {
for _, s := range ranges {
fmt.Printf(format, s.Lo, s.Hi, s.Stride)
}
- fmt.Printf("}\n\n")
+ fmt.Print("}\n\n")
}
decl.Sort()
fmt.Println("var (")
for _, d := range decl {
fmt.Print(d)
}
- fmt.Println(")\n")
+ fmt.Print(")\n\n")
}
const (
@@ -802,7 +792,7 @@ func printCases() {
}
prevState = state
}
- fmt.Printf("}\n")
+ fmt.Print("}\n")
}
func printCaseRange(lo, hi *caseState) {
diff --git a/src/pkg/unicode/script_test.go b/src/pkg/unicode/script_test.go
index b3e980b1c..ffdc40dc0 100644
--- a/src/pkg/unicode/script_test.go
+++ b/src/pkg/unicode/script_test.go
@@ -17,171 +17,171 @@ type T struct {
// Hand-chosen tests from Unicode 5.1.0, mostly to discover when new
// scripts and categories arise.
var inTest = []T{
- T{0x06e2, "Arabic"},
- T{0x0567, "Armenian"},
- T{0x10b20, "Avestan"},
- T{0x1b37, "Balinese"},
- T{0xa6af, "Bamum"},
- T{0x09c2, "Bengali"},
- T{0x3115, "Bopomofo"},
- T{0x282d, "Braille"},
- T{0x1a1a, "Buginese"},
- T{0x1747, "Buhid"},
- T{0x156d, "Canadian_Aboriginal"},
- T{0x102a9, "Carian"},
- T{0xaa4d, "Cham"},
- T{0x13c2, "Cherokee"},
- T{0x0020, "Common"},
- T{0x1d4a5, "Common"},
- T{0x2cfc, "Coptic"},
- T{0x12420, "Cuneiform"},
- T{0x1080c, "Cypriot"},
- T{0xa663, "Cyrillic"},
- T{0x10430, "Deseret"},
- T{0x094a, "Devanagari"},
- T{0x13001, "Egyptian_Hieroglyphs"},
- T{0x1271, "Ethiopic"},
- T{0x10fc, "Georgian"},
- T{0x2c40, "Glagolitic"},
- T{0x10347, "Gothic"},
- T{0x03ae, "Greek"},
- T{0x0abf, "Gujarati"},
- T{0x0a24, "Gurmukhi"},
- T{0x3028, "Han"},
- T{0x11b8, "Hangul"},
- T{0x1727, "Hanunoo"},
- T{0x05a0, "Hebrew"},
- T{0x3058, "Hiragana"},
- T{0x10841, "Imperial_Aramaic"},
- T{0x20e6, "Inherited"},
- T{0x10b70, "Inscriptional_Pahlavi"},
- T{0x10b5a, "Inscriptional_Parthian"},
- T{0xa9d0, "Javanese"},
- T{0x1109f, "Kaithi"},
- T{0x0cbd, "Kannada"},
- T{0x30a6, "Katakana"},
- T{0xa928, "Kayah_Li"},
- T{0x10a11, "Kharoshthi"},
- T{0x17c6, "Khmer"},
- T{0x0eaa, "Lao"},
- T{0x1d79, "Latin"},
- T{0x1c10, "Lepcha"},
- T{0x1930, "Limbu"},
- T{0x1003c, "Linear_B"},
- T{0xa4e1, "Lisu"},
- T{0x10290, "Lycian"},
- T{0x10930, "Lydian"},
- T{0x0d42, "Malayalam"},
- T{0xabd0, "Meetei_Mayek"},
- T{0x1822, "Mongolian"},
- T{0x104c, "Myanmar"},
- T{0x19c3, "New_Tai_Lue"},
- T{0x07f8, "Nko"},
- T{0x169b, "Ogham"},
- T{0x1c6a, "Ol_Chiki"},
- T{0x10310, "Old_Italic"},
- T{0x103c9, "Old_Persian"},
- T{0x10a6f, "Old_South_Arabian"},
- T{0x10c20, "Old_Turkic"},
- T{0x0b3e, "Oriya"},
- T{0x10491, "Osmanya"},
- T{0xa860, "Phags_Pa"},
- T{0x10918, "Phoenician"},
- T{0xa949, "Rejang"},
- T{0x16c0, "Runic"},
- T{0x081d, "Samaritan"},
- T{0xa892, "Saurashtra"},
- T{0x10463, "Shavian"},
- T{0x0dbd, "Sinhala"},
- T{0x1ba3, "Sundanese"},
- T{0xa803, "Syloti_Nagri"},
- T{0x070f, "Syriac"},
- T{0x170f, "Tagalog"},
- T{0x176f, "Tagbanwa"},
- T{0x1972, "Tai_Le"},
- T{0x1a62, "Tai_Tham"},
- T{0xaadc, "Tai_Viet"},
- T{0x0bbf, "Tamil"},
- T{0x0c55, "Telugu"},
- T{0x07a7, "Thaana"},
- T{0x0e46, "Thai"},
- T{0x0f36, "Tibetan"},
- T{0x2d55, "Tifinagh"},
- T{0x10388, "Ugaritic"},
- T{0xa60e, "Vai"},
- T{0xa216, "Yi"},
+ {0x06e2, "Arabic"},
+ {0x0567, "Armenian"},
+ {0x10b20, "Avestan"},
+ {0x1b37, "Balinese"},
+ {0xa6af, "Bamum"},
+ {0x09c2, "Bengali"},
+ {0x3115, "Bopomofo"},
+ {0x282d, "Braille"},
+ {0x1a1a, "Buginese"},
+ {0x1747, "Buhid"},
+ {0x156d, "Canadian_Aboriginal"},
+ {0x102a9, "Carian"},
+ {0xaa4d, "Cham"},
+ {0x13c2, "Cherokee"},
+ {0x0020, "Common"},
+ {0x1d4a5, "Common"},
+ {0x2cfc, "Coptic"},
+ {0x12420, "Cuneiform"},
+ {0x1080c, "Cypriot"},
+ {0xa663, "Cyrillic"},
+ {0x10430, "Deseret"},
+ {0x094a, "Devanagari"},
+ {0x13001, "Egyptian_Hieroglyphs"},
+ {0x1271, "Ethiopic"},
+ {0x10fc, "Georgian"},
+ {0x2c40, "Glagolitic"},
+ {0x10347, "Gothic"},
+ {0x03ae, "Greek"},
+ {0x0abf, "Gujarati"},
+ {0x0a24, "Gurmukhi"},
+ {0x3028, "Han"},
+ {0x11b8, "Hangul"},
+ {0x1727, "Hanunoo"},
+ {0x05a0, "Hebrew"},
+ {0x3058, "Hiragana"},
+ {0x10841, "Imperial_Aramaic"},
+ {0x20e6, "Inherited"},
+ {0x10b70, "Inscriptional_Pahlavi"},
+ {0x10b5a, "Inscriptional_Parthian"},
+ {0xa9d0, "Javanese"},
+ {0x1109f, "Kaithi"},
+ {0x0cbd, "Kannada"},
+ {0x30a6, "Katakana"},
+ {0xa928, "Kayah_Li"},
+ {0x10a11, "Kharoshthi"},
+ {0x17c6, "Khmer"},
+ {0x0eaa, "Lao"},
+ {0x1d79, "Latin"},
+ {0x1c10, "Lepcha"},
+ {0x1930, "Limbu"},
+ {0x1003c, "Linear_B"},
+ {0xa4e1, "Lisu"},
+ {0x10290, "Lycian"},
+ {0x10930, "Lydian"},
+ {0x0d42, "Malayalam"},
+ {0xabd0, "Meetei_Mayek"},
+ {0x1822, "Mongolian"},
+ {0x104c, "Myanmar"},
+ {0x19c3, "New_Tai_Lue"},
+ {0x07f8, "Nko"},
+ {0x169b, "Ogham"},
+ {0x1c6a, "Ol_Chiki"},
+ {0x10310, "Old_Italic"},
+ {0x103c9, "Old_Persian"},
+ {0x10a6f, "Old_South_Arabian"},
+ {0x10c20, "Old_Turkic"},
+ {0x0b3e, "Oriya"},
+ {0x10491, "Osmanya"},
+ {0xa860, "Phags_Pa"},
+ {0x10918, "Phoenician"},
+ {0xa949, "Rejang"},
+ {0x16c0, "Runic"},
+ {0x081d, "Samaritan"},
+ {0xa892, "Saurashtra"},
+ {0x10463, "Shavian"},
+ {0x0dbd, "Sinhala"},
+ {0x1ba3, "Sundanese"},
+ {0xa803, "Syloti_Nagri"},
+ {0x070f, "Syriac"},
+ {0x170f, "Tagalog"},
+ {0x176f, "Tagbanwa"},
+ {0x1972, "Tai_Le"},
+ {0x1a62, "Tai_Tham"},
+ {0xaadc, "Tai_Viet"},
+ {0x0bbf, "Tamil"},
+ {0x0c55, "Telugu"},
+ {0x07a7, "Thaana"},
+ {0x0e46, "Thai"},
+ {0x0f36, "Tibetan"},
+ {0x2d55, "Tifinagh"},
+ {0x10388, "Ugaritic"},
+ {0xa60e, "Vai"},
+ {0xa216, "Yi"},
}
var outTest = []T{ // not really worth being thorough
- T{0x20, "Telugu"},
+ {0x20, "Telugu"},
}
var inCategoryTest = []T{
- T{0x0081, "Cc"},
- T{0x17b4, "Cf"},
- T{0xf0000, "Co"},
- T{0xdb80, "Cs"},
- T{0x0236, "Ll"},
- T{0x1d9d, "Lm"},
- T{0x07cf, "Lo"},
- T{0x1f8a, "Lt"},
- T{0x03ff, "Lu"},
- T{0x0bc1, "Mc"},
- T{0x20df, "Me"},
- T{0x07f0, "Mn"},
- T{0x1bb2, "Nd"},
- T{0x10147, "Nl"},
- T{0x2478, "No"},
- T{0xfe33, "Pc"},
- T{0x2011, "Pd"},
- T{0x301e, "Pe"},
- T{0x2e03, "Pf"},
- T{0x2e02, "Pi"},
- T{0x0022, "Po"},
- T{0x2770, "Ps"},
- T{0x00a4, "Sc"},
- T{0xa711, "Sk"},
- T{0x25f9, "Sm"},
- T{0x2108, "So"},
- T{0x2028, "Zl"},
- T{0x2029, "Zp"},
- T{0x202f, "Zs"},
- T{0x04aa, "letter"},
+ {0x0081, "Cc"},
+ {0x17b4, "Cf"},
+ {0xf0000, "Co"},
+ {0xdb80, "Cs"},
+ {0x0236, "Ll"},
+ {0x1d9d, "Lm"},
+ {0x07cf, "Lo"},
+ {0x1f8a, "Lt"},
+ {0x03ff, "Lu"},
+ {0x0bc1, "Mc"},
+ {0x20df, "Me"},
+ {0x07f0, "Mn"},
+ {0x1bb2, "Nd"},
+ {0x10147, "Nl"},
+ {0x2478, "No"},
+ {0xfe33, "Pc"},
+ {0x2011, "Pd"},
+ {0x301e, "Pe"},
+ {0x2e03, "Pf"},
+ {0x2e02, "Pi"},
+ {0x0022, "Po"},
+ {0x2770, "Ps"},
+ {0x00a4, "Sc"},
+ {0xa711, "Sk"},
+ {0x25f9, "Sm"},
+ {0x2108, "So"},
+ {0x2028, "Zl"},
+ {0x2029, "Zp"},
+ {0x202f, "Zs"},
+ {0x04aa, "letter"},
}
var inPropTest = []T{
- T{0x0046, "ASCII_Hex_Digit"},
- T{0x200F, "Bidi_Control"},
- T{0x2212, "Dash"},
- T{0xE0001, "Deprecated"},
- T{0x00B7, "Diacritic"},
- T{0x30FE, "Extender"},
- T{0xFF46, "Hex_Digit"},
- T{0x2E17, "Hyphen"},
- T{0x2FFB, "IDS_Binary_Operator"},
- T{0x2FF3, "IDS_Trinary_Operator"},
- T{0xFA6A, "Ideographic"},
- T{0x200D, "Join_Control"},
- T{0x0EC4, "Logical_Order_Exception"},
- T{0x2FFFF, "Noncharacter_Code_Point"},
- T{0x065E, "Other_Alphabetic"},
- T{0x2069, "Other_Default_Ignorable_Code_Point"},
- T{0x0BD7, "Other_Grapheme_Extend"},
- T{0x0387, "Other_ID_Continue"},
- T{0x212E, "Other_ID_Start"},
- T{0x2094, "Other_Lowercase"},
- T{0x2040, "Other_Math"},
- T{0x216F, "Other_Uppercase"},
- T{0x0027, "Pattern_Syntax"},
- T{0x0020, "Pattern_White_Space"},
- T{0x300D, "Quotation_Mark"},
- T{0x2EF3, "Radical"},
- T{0x061F, "STerm"},
- T{0x2071, "Soft_Dotted"},
- T{0x003A, "Terminal_Punctuation"},
- T{0x9FC3, "Unified_Ideograph"},
- T{0xFE0F, "Variation_Selector"},
- T{0x0020, "White_Space"},
+ {0x0046, "ASCII_Hex_Digit"},
+ {0x200F, "Bidi_Control"},
+ {0x2212, "Dash"},
+ {0xE0001, "Deprecated"},
+ {0x00B7, "Diacritic"},
+ {0x30FE, "Extender"},
+ {0xFF46, "Hex_Digit"},
+ {0x2E17, "Hyphen"},
+ {0x2FFB, "IDS_Binary_Operator"},
+ {0x2FF3, "IDS_Trinary_Operator"},
+ {0xFA6A, "Ideographic"},
+ {0x200D, "Join_Control"},
+ {0x0EC4, "Logical_Order_Exception"},
+ {0x2FFFF, "Noncharacter_Code_Point"},
+ {0x065E, "Other_Alphabetic"},
+ {0x2069, "Other_Default_Ignorable_Code_Point"},
+ {0x0BD7, "Other_Grapheme_Extend"},
+ {0x0387, "Other_ID_Continue"},
+ {0x212E, "Other_ID_Start"},
+ {0x2094, "Other_Lowercase"},
+ {0x2040, "Other_Math"},
+ {0x216F, "Other_Uppercase"},
+ {0x0027, "Pattern_Syntax"},
+ {0x0020, "Pattern_White_Space"},
+ {0x300D, "Quotation_Mark"},
+ {0x2EF3, "Radical"},
+ {0x061F, "STerm"},
+ {0x2071, "Soft_Dotted"},
+ {0x003A, "Terminal_Punctuation"},
+ {0x9FC3, "Unified_Ideograph"},
+ {0xFE0F, "Variation_Selector"},
+ {0x0020, "White_Space"},
}
func TestScripts(t *testing.T) {
@@ -194,13 +194,13 @@ func TestScripts(t *testing.T) {
t.Fatal(test.script, "not a known script")
}
if !Is(Scripts[test.script], test.rune) {
- t.Errorf("IsScript(%#x, %s) = false, want true\n", test.rune, test.script)
+ t.Errorf("IsScript(%#x, %s) = false, want true", test.rune, test.script)
}
notTested[test.script] = false, false
}
for _, test := range outTest {
if Is(Scripts[test.script], test.rune) {
- t.Errorf("IsScript(%#x, %s) = true, want false\n", test.rune, test.script)
+ t.Errorf("IsScript(%#x, %s) = true, want false", test.rune, test.script)
}
}
for k := range notTested {
@@ -218,7 +218,7 @@ func TestCategories(t *testing.T) {
t.Fatal(test.script, "not a known category")
}
if !Is(Categories[test.script], test.rune) {
- t.Errorf("IsCategory(%#x, %s) = false, want true\n", test.rune, test.script)
+ t.Errorf("IsCategory(%#x, %s) = false, want true", test.rune, test.script)
}
notTested[test.script] = false, false
}
@@ -237,7 +237,7 @@ func TestProperties(t *testing.T) {
t.Fatal(test.script, "not a known prop")
}
if !Is(Properties[test.script], test.rune) {
- t.Errorf("IsCategory(%#x, %s) = false, want true\n", test.rune, test.script)
+ t.Errorf("IsCategory(%#x, %s) = false, want true", test.rune, test.script)
}
notTested[test.script] = false, false
}
diff --git a/src/pkg/unicode/tables.go b/src/pkg/unicode/tables.go
index 56b478ed0..b56c9bd03 100644
--- a/src/pkg/unicode/tables.go
+++ b/src/pkg/unicode/tables.go
@@ -42,1882 +42,1882 @@ var Categories = map[string][]Range{
}
var _Lm = []Range{
- Range{0x02b0, 0x02c1, 1},
- Range{0x02c6, 0x02d1, 1},
- Range{0x02e0, 0x02e4, 1},
- Range{0x02ec, 0x02ee, 2},
- Range{0x0374, 0x037a, 6},
- Range{0x0559, 0x0640, 231},
- Range{0x06e5, 0x06e6, 1},
- Range{0x07f4, 0x07f5, 1},
- Range{0x07fa, 0x081a, 32},
- Range{0x0824, 0x0828, 4},
- Range{0x0971, 0x0e46, 1237},
- Range{0x0ec6, 0x10fc, 566},
- Range{0x17d7, 0x1843, 108},
- Range{0x1aa7, 0x1c78, 465},
- Range{0x1c79, 0x1c7d, 1},
- Range{0x1d2c, 0x1d61, 1},
- Range{0x1d78, 0x1d9b, 35},
- Range{0x1d9c, 0x1dbf, 1},
- Range{0x2071, 0x207f, 14},
- Range{0x2090, 0x2094, 1},
- Range{0x2c7d, 0x2d6f, 242},
- Range{0x2e2f, 0x3005, 470},
- Range{0x3031, 0x3035, 1},
- Range{0x303b, 0x309d, 98},
- Range{0x309e, 0x30fc, 94},
- Range{0x30fd, 0x30fe, 1},
- Range{0xa015, 0xa4f8, 1251},
- Range{0xa4f9, 0xa4fd, 1},
- Range{0xa60c, 0xa67f, 115},
- Range{0xa717, 0xa71f, 1},
- Range{0xa770, 0xa788, 24},
- Range{0xa9cf, 0xaa70, 161},
- Range{0xaadd, 0xff70, 21651},
- Range{0xff9e, 0xff9f, 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, 0x2094, 1},
+ {0x2c7d, 0x2d6f, 242},
+ {0x2e2f, 0x3005, 470},
+ {0x3031, 0x3035, 1},
+ {0x303b, 0x309d, 98},
+ {0x309e, 0x30fc, 94},
+ {0x30fd, 0x30fe, 1},
+ {0xa015, 0xa4f8, 1251},
+ {0xa4f9, 0xa4fd, 1},
+ {0xa60c, 0xa67f, 115},
+ {0xa717, 0xa71f, 1},
+ {0xa770, 0xa788, 24},
+ {0xa9cf, 0xaa70, 161},
+ {0xaadd, 0xff70, 21651},
+ {0xff9e, 0xff9f, 1},
}
var _Ll = []Range{
- Range{0x0061, 0x007a, 1},
- Range{0x00aa, 0x00b5, 11},
- Range{0x00ba, 0x00df, 37},
- Range{0x00e0, 0x00f6, 1},
- Range{0x00f8, 0x00ff, 1},
- Range{0x0101, 0x0137, 2},
- Range{0x0138, 0x0148, 2},
- Range{0x0149, 0x0177, 2},
- Range{0x017a, 0x017e, 2},
- Range{0x017f, 0x0180, 1},
- Range{0x0183, 0x0185, 2},
- Range{0x0188, 0x018c, 4},
- Range{0x018d, 0x0192, 5},
- Range{0x0195, 0x0199, 4},
- Range{0x019a, 0x019b, 1},
- Range{0x019e, 0x01a1, 3},
- Range{0x01a3, 0x01a5, 2},
- Range{0x01a8, 0x01aa, 2},
- Range{0x01ab, 0x01ad, 2},
- Range{0x01b0, 0x01b4, 4},
- Range{0x01b6, 0x01b9, 3},
- Range{0x01ba, 0x01bd, 3},
- Range{0x01be, 0x01bf, 1},
- Range{0x01c6, 0x01cc, 3},
- Range{0x01ce, 0x01dc, 2},
- Range{0x01dd, 0x01ef, 2},
- Range{0x01f0, 0x01f3, 3},
- Range{0x01f5, 0x01f9, 4},
- Range{0x01fb, 0x0233, 2},
- Range{0x0234, 0x0239, 1},
- Range{0x023c, 0x023f, 3},
- Range{0x0240, 0x0242, 2},
- Range{0x0247, 0x024f, 2},
- Range{0x0250, 0x0293, 1},
- Range{0x0295, 0x02af, 1},
- Range{0x0371, 0x0373, 2},
- Range{0x0377, 0x037b, 4},
- Range{0x037c, 0x037d, 1},
- Range{0x0390, 0x03ac, 28},
- Range{0x03ad, 0x03ce, 1},
- Range{0x03d0, 0x03d1, 1},
- Range{0x03d5, 0x03d7, 1},
- Range{0x03d9, 0x03ef, 2},
- Range{0x03f0, 0x03f3, 1},
- Range{0x03f5, 0x03fb, 3},
- Range{0x03fc, 0x0430, 52},
- Range{0x0431, 0x045f, 1},
- Range{0x0461, 0x0481, 2},
- Range{0x048b, 0x04bf, 2},
- Range{0x04c2, 0x04ce, 2},
- Range{0x04cf, 0x0525, 2},
- Range{0x0561, 0x0587, 1},
- Range{0x1d00, 0x1d2b, 1},
- Range{0x1d62, 0x1d77, 1},
- Range{0x1d79, 0x1d9a, 1},
- Range{0x1e01, 0x1e95, 2},
- Range{0x1e96, 0x1e9d, 1},
- Range{0x1e9f, 0x1eff, 2},
- Range{0x1f00, 0x1f07, 1},
- Range{0x1f10, 0x1f15, 1},
- Range{0x1f20, 0x1f27, 1},
- Range{0x1f30, 0x1f37, 1},
- Range{0x1f40, 0x1f45, 1},
- Range{0x1f50, 0x1f57, 1},
- Range{0x1f60, 0x1f67, 1},
- Range{0x1f70, 0x1f7d, 1},
- Range{0x1f80, 0x1f87, 1},
- Range{0x1f90, 0x1f97, 1},
- Range{0x1fa0, 0x1fa7, 1},
- Range{0x1fb0, 0x1fb4, 1},
- Range{0x1fb6, 0x1fb7, 1},
- Range{0x1fbe, 0x1fc2, 4},
- Range{0x1fc3, 0x1fc4, 1},
- Range{0x1fc6, 0x1fc7, 1},
- Range{0x1fd0, 0x1fd3, 1},
- Range{0x1fd6, 0x1fd7, 1},
- Range{0x1fe0, 0x1fe7, 1},
- Range{0x1ff2, 0x1ff4, 1},
- Range{0x1ff6, 0x1ff7, 1},
- Range{0x210a, 0x210e, 4},
- Range{0x210f, 0x2113, 4},
- Range{0x212f, 0x2139, 5},
- Range{0x213c, 0x213d, 1},
- Range{0x2146, 0x2149, 1},
- Range{0x214e, 0x2184, 54},
- Range{0x2c30, 0x2c5e, 1},
- Range{0x2c61, 0x2c65, 4},
- Range{0x2c66, 0x2c6c, 2},
- Range{0x2c71, 0x2c73, 2},
- Range{0x2c74, 0x2c76, 2},
- Range{0x2c77, 0x2c7c, 1},
- Range{0x2c81, 0x2ce3, 2},
- Range{0x2ce4, 0x2cec, 8},
- Range{0x2cee, 0x2d00, 18},
- Range{0x2d01, 0x2d25, 1},
- Range{0xa641, 0xa65f, 2},
- Range{0xa663, 0xa66d, 2},
- Range{0xa681, 0xa697, 2},
- Range{0xa723, 0xa72f, 2},
- Range{0xa730, 0xa731, 1},
- Range{0xa733, 0xa771, 2},
- Range{0xa772, 0xa778, 1},
- Range{0xa77a, 0xa77c, 2},
- Range{0xa77f, 0xa787, 2},
- Range{0xa78c, 0xfb00, 21364},
- Range{0xfb01, 0xfb06, 1},
- Range{0xfb13, 0xfb17, 1},
- Range{0xff41, 0xff5a, 1},
- Range{0x10428, 0x1044f, 1},
- Range{0x1d41a, 0x1d433, 1},
- Range{0x1d44e, 0x1d454, 1},
- Range{0x1d456, 0x1d467, 1},
- Range{0x1d482, 0x1d49b, 1},
- Range{0x1d4b6, 0x1d4b9, 1},
- Range{0x1d4bb, 0x1d4bd, 2},
- Range{0x1d4be, 0x1d4c3, 1},
- Range{0x1d4c5, 0x1d4cf, 1},
- Range{0x1d4ea, 0x1d503, 1},
- Range{0x1d51e, 0x1d537, 1},
- Range{0x1d552, 0x1d56b, 1},
- Range{0x1d586, 0x1d59f, 1},
- Range{0x1d5ba, 0x1d5d3, 1},
- Range{0x1d5ee, 0x1d607, 1},
- Range{0x1d622, 0x1d63b, 1},
- Range{0x1d656, 0x1d66f, 1},
- Range{0x1d68a, 0x1d6a5, 1},
- Range{0x1d6c2, 0x1d6da, 1},
- Range{0x1d6dc, 0x1d6e1, 1},
- Range{0x1d6fc, 0x1d714, 1},
- Range{0x1d716, 0x1d71b, 1},
- Range{0x1d736, 0x1d74e, 1},
- Range{0x1d750, 0x1d755, 1},
- Range{0x1d770, 0x1d788, 1},
- Range{0x1d78a, 0x1d78f, 1},
- Range{0x1d7aa, 0x1d7c2, 1},
- Range{0x1d7c4, 0x1d7c9, 1},
- Range{0x1d7cb, 0x1d7cb, 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, 0x0525, 2},
+ {0x0561, 0x0587, 1},
+ {0x1d00, 0x1d2b, 1},
+ {0x1d62, 0x1d77, 1},
+ {0x1d79, 0x1d9a, 1},
+ {0x1e01, 0x1e95, 2},
+ {0x1e96, 0x1e9d, 1},
+ {0x1e9f, 0x1eff, 2},
+ {0x1f00, 0x1f07, 1},
+ {0x1f10, 0x1f15, 1},
+ {0x1f20, 0x1f27, 1},
+ {0x1f30, 0x1f37, 1},
+ {0x1f40, 0x1f45, 1},
+ {0x1f50, 0x1f57, 1},
+ {0x1f60, 0x1f67, 1},
+ {0x1f70, 0x1f7d, 1},
+ {0x1f80, 0x1f87, 1},
+ {0x1f90, 0x1f97, 1},
+ {0x1fa0, 0x1fa7, 1},
+ {0x1fb0, 0x1fb4, 1},
+ {0x1fb6, 0x1fb7, 1},
+ {0x1fbe, 0x1fc2, 4},
+ {0x1fc3, 0x1fc4, 1},
+ {0x1fc6, 0x1fc7, 1},
+ {0x1fd0, 0x1fd3, 1},
+ {0x1fd6, 0x1fd7, 1},
+ {0x1fe0, 0x1fe7, 1},
+ {0x1ff2, 0x1ff4, 1},
+ {0x1ff6, 0x1ff7, 1},
+ {0x210a, 0x210e, 4},
+ {0x210f, 0x2113, 4},
+ {0x212f, 0x2139, 5},
+ {0x213c, 0x213d, 1},
+ {0x2146, 0x2149, 1},
+ {0x214e, 0x2184, 54},
+ {0x2c30, 0x2c5e, 1},
+ {0x2c61, 0x2c65, 4},
+ {0x2c66, 0x2c6c, 2},
+ {0x2c71, 0x2c73, 2},
+ {0x2c74, 0x2c76, 2},
+ {0x2c77, 0x2c7c, 1},
+ {0x2c81, 0x2ce3, 2},
+ {0x2ce4, 0x2cec, 8},
+ {0x2cee, 0x2d00, 18},
+ {0x2d01, 0x2d25, 1},
+ {0xa641, 0xa65f, 2},
+ {0xa663, 0xa66d, 2},
+ {0xa681, 0xa697, 2},
+ {0xa723, 0xa72f, 2},
+ {0xa730, 0xa731, 1},
+ {0xa733, 0xa771, 2},
+ {0xa772, 0xa778, 1},
+ {0xa77a, 0xa77c, 2},
+ {0xa77f, 0xa787, 2},
+ {0xa78c, 0xfb00, 21364},
+ {0xfb01, 0xfb06, 1},
+ {0xfb13, 0xfb17, 1},
+ {0xff41, 0xff5a, 1},
+ {0x10428, 0x1044f, 1},
+ {0x1d41a, 0x1d433, 1},
+ {0x1d44e, 0x1d454, 1},
+ {0x1d456, 0x1d467, 1},
+ {0x1d482, 0x1d49b, 1},
+ {0x1d4b6, 0x1d4b9, 1},
+ {0x1d4bb, 0x1d4bd, 2},
+ {0x1d4be, 0x1d4c3, 1},
+ {0x1d4c5, 0x1d4cf, 1},
+ {0x1d4ea, 0x1d503, 1},
+ {0x1d51e, 0x1d537, 1},
+ {0x1d552, 0x1d56b, 1},
+ {0x1d586, 0x1d59f, 1},
+ {0x1d5ba, 0x1d5d3, 1},
+ {0x1d5ee, 0x1d607, 1},
+ {0x1d622, 0x1d63b, 1},
+ {0x1d656, 0x1d66f, 1},
+ {0x1d68a, 0x1d6a5, 1},
+ {0x1d6c2, 0x1d6da, 1},
+ {0x1d6dc, 0x1d6e1, 1},
+ {0x1d6fc, 0x1d714, 1},
+ {0x1d716, 0x1d71b, 1},
+ {0x1d736, 0x1d74e, 1},
+ {0x1d750, 0x1d755, 1},
+ {0x1d770, 0x1d788, 1},
+ {0x1d78a, 0x1d78f, 1},
+ {0x1d7aa, 0x1d7c2, 1},
+ {0x1d7c4, 0x1d7c9, 1},
+ {0x1d7cb, 0x1d7cb, 1},
}
var _Me = []Range{
- Range{0x0488, 0x0489, 1},
- Range{0x06de, 0x20dd, 6655},
- Range{0x20de, 0x20e0, 1},
- Range{0x20e2, 0x20e4, 1},
- Range{0xa670, 0xa672, 1},
+ {0x0488, 0x0489, 1},
+ {0x06de, 0x20dd, 6655},
+ {0x20de, 0x20e0, 1},
+ {0x20e2, 0x20e4, 1},
+ {0xa670, 0xa672, 1},
}
var _Mc = []Range{
- Range{0x0903, 0x093e, 59},
- Range{0x093f, 0x0940, 1},
- Range{0x0949, 0x094c, 1},
- Range{0x094e, 0x0982, 52},
- Range{0x0983, 0x09be, 59},
- Range{0x09bf, 0x09c0, 1},
- Range{0x09c7, 0x09c8, 1},
- Range{0x09cb, 0x09cc, 1},
- Range{0x09d7, 0x0a03, 44},
- Range{0x0a3e, 0x0a40, 1},
- Range{0x0a83, 0x0abe, 59},
- Range{0x0abf, 0x0ac0, 1},
- Range{0x0ac9, 0x0acb, 2},
- Range{0x0acc, 0x0b02, 54},
- Range{0x0b03, 0x0b3e, 59},
- Range{0x0b40, 0x0b47, 7},
- Range{0x0b48, 0x0b4b, 3},
- Range{0x0b4c, 0x0b57, 11},
- Range{0x0bbe, 0x0bbf, 1},
- Range{0x0bc1, 0x0bc2, 1},
- Range{0x0bc6, 0x0bc8, 1},
- Range{0x0bca, 0x0bcc, 1},
- Range{0x0bd7, 0x0c01, 42},
- Range{0x0c02, 0x0c03, 1},
- Range{0x0c41, 0x0c44, 1},
- Range{0x0c82, 0x0c83, 1},
- Range{0x0cbe, 0x0cc0, 2},
- Range{0x0cc1, 0x0cc4, 1},
- Range{0x0cc7, 0x0cc8, 1},
- Range{0x0cca, 0x0ccb, 1},
- Range{0x0cd5, 0x0cd6, 1},
- Range{0x0d02, 0x0d03, 1},
- Range{0x0d3e, 0x0d40, 1},
- Range{0x0d46, 0x0d48, 1},
- Range{0x0d4a, 0x0d4c, 1},
- Range{0x0d57, 0x0d82, 43},
- Range{0x0d83, 0x0dcf, 76},
- Range{0x0dd0, 0x0dd1, 1},
- Range{0x0dd8, 0x0ddf, 1},
- Range{0x0df2, 0x0df3, 1},
- Range{0x0f3e, 0x0f3f, 1},
- Range{0x0f7f, 0x102b, 172},
- Range{0x102c, 0x1031, 5},
- Range{0x1038, 0x103b, 3},
- Range{0x103c, 0x1056, 26},
- Range{0x1057, 0x1062, 11},
- Range{0x1063, 0x1064, 1},
- Range{0x1067, 0x106d, 1},
- Range{0x1083, 0x1084, 1},
- Range{0x1087, 0x108c, 1},
- Range{0x108f, 0x109a, 11},
- Range{0x109b, 0x109c, 1},
- Range{0x17b6, 0x17be, 8},
- Range{0x17bf, 0x17c5, 1},
- Range{0x17c7, 0x17c8, 1},
- Range{0x1923, 0x1926, 1},
- Range{0x1929, 0x192b, 1},
- Range{0x1930, 0x1931, 1},
- Range{0x1933, 0x1938, 1},
- Range{0x19b0, 0x19c0, 1},
- Range{0x19c8, 0x19c9, 1},
- Range{0x1a19, 0x1a1b, 1},
- Range{0x1a55, 0x1a57, 2},
- Range{0x1a61, 0x1a63, 2},
- Range{0x1a64, 0x1a6d, 9},
- Range{0x1a6e, 0x1a72, 1},
- Range{0x1b04, 0x1b35, 49},
- Range{0x1b3b, 0x1b3d, 2},
- Range{0x1b3e, 0x1b41, 1},
- Range{0x1b43, 0x1b44, 1},
- Range{0x1b82, 0x1ba1, 31},
- Range{0x1ba6, 0x1ba7, 1},
- Range{0x1baa, 0x1c24, 122},
- Range{0x1c25, 0x1c2b, 1},
- Range{0x1c34, 0x1c35, 1},
- Range{0x1ce1, 0x1cf2, 17},
- Range{0xa823, 0xa824, 1},
- Range{0xa827, 0xa880, 89},
- Range{0xa881, 0xa8b4, 51},
- Range{0xa8b5, 0xa8c3, 1},
- Range{0xa952, 0xa953, 1},
- Range{0xa983, 0xa9b4, 49},
- Range{0xa9b5, 0xa9ba, 5},
- Range{0xa9bb, 0xa9bd, 2},
- Range{0xa9be, 0xa9c0, 1},
- Range{0xaa2f, 0xaa30, 1},
- Range{0xaa33, 0xaa34, 1},
- Range{0xaa4d, 0xaa7b, 46},
- Range{0xabe3, 0xabe4, 1},
- Range{0xabe6, 0xabe7, 1},
- Range{0xabe9, 0xabea, 1},
- Range{0xabec, 0x11082, 25750},
- Range{0x110b0, 0x110b2, 1},
- Range{0x110b7, 0x110b8, 1},
- Range{0x1d165, 0x1d166, 1},
- Range{0x1d16d, 0x1d172, 1},
+ {0x0903, 0x093e, 59},
+ {0x093f, 0x0940, 1},
+ {0x0949, 0x094c, 1},
+ {0x094e, 0x0982, 52},
+ {0x0983, 0x09be, 59},
+ {0x09bf, 0x09c0, 1},
+ {0x09c7, 0x09c8, 1},
+ {0x09cb, 0x09cc, 1},
+ {0x09d7, 0x0a03, 44},
+ {0x0a3e, 0x0a40, 1},
+ {0x0a83, 0x0abe, 59},
+ {0x0abf, 0x0ac0, 1},
+ {0x0ac9, 0x0acb, 2},
+ {0x0acc, 0x0b02, 54},
+ {0x0b03, 0x0b3e, 59},
+ {0x0b40, 0x0b47, 7},
+ {0x0b48, 0x0b4b, 3},
+ {0x0b4c, 0x0b57, 11},
+ {0x0bbe, 0x0bbf, 1},
+ {0x0bc1, 0x0bc2, 1},
+ {0x0bc6, 0x0bc8, 1},
+ {0x0bca, 0x0bcc, 1},
+ {0x0bd7, 0x0c01, 42},
+ {0x0c02, 0x0c03, 1},
+ {0x0c41, 0x0c44, 1},
+ {0x0c82, 0x0c83, 1},
+ {0x0cbe, 0x0cc0, 2},
+ {0x0cc1, 0x0cc4, 1},
+ {0x0cc7, 0x0cc8, 1},
+ {0x0cca, 0x0ccb, 1},
+ {0x0cd5, 0x0cd6, 1},
+ {0x0d02, 0x0d03, 1},
+ {0x0d3e, 0x0d40, 1},
+ {0x0d46, 0x0d48, 1},
+ {0x0d4a, 0x0d4c, 1},
+ {0x0d57, 0x0d82, 43},
+ {0x0d83, 0x0dcf, 76},
+ {0x0dd0, 0x0dd1, 1},
+ {0x0dd8, 0x0ddf, 1},
+ {0x0df2, 0x0df3, 1},
+ {0x0f3e, 0x0f3f, 1},
+ {0x0f7f, 0x102b, 172},
+ {0x102c, 0x1031, 5},
+ {0x1038, 0x103b, 3},
+ {0x103c, 0x1056, 26},
+ {0x1057, 0x1062, 11},
+ {0x1063, 0x1064, 1},
+ {0x1067, 0x106d, 1},
+ {0x1083, 0x1084, 1},
+ {0x1087, 0x108c, 1},
+ {0x108f, 0x109a, 11},
+ {0x109b, 0x109c, 1},
+ {0x17b6, 0x17be, 8},
+ {0x17bf, 0x17c5, 1},
+ {0x17c7, 0x17c8, 1},
+ {0x1923, 0x1926, 1},
+ {0x1929, 0x192b, 1},
+ {0x1930, 0x1931, 1},
+ {0x1933, 0x1938, 1},
+ {0x19b0, 0x19c0, 1},
+ {0x19c8, 0x19c9, 1},
+ {0x1a19, 0x1a1b, 1},
+ {0x1a55, 0x1a57, 2},
+ {0x1a61, 0x1a63, 2},
+ {0x1a64, 0x1a6d, 9},
+ {0x1a6e, 0x1a72, 1},
+ {0x1b04, 0x1b35, 49},
+ {0x1b3b, 0x1b3d, 2},
+ {0x1b3e, 0x1b41, 1},
+ {0x1b43, 0x1b44, 1},
+ {0x1b82, 0x1ba1, 31},
+ {0x1ba6, 0x1ba7, 1},
+ {0x1baa, 0x1c24, 122},
+ {0x1c25, 0x1c2b, 1},
+ {0x1c34, 0x1c35, 1},
+ {0x1ce1, 0x1cf2, 17},
+ {0xa823, 0xa824, 1},
+ {0xa827, 0xa880, 89},
+ {0xa881, 0xa8b4, 51},
+ {0xa8b5, 0xa8c3, 1},
+ {0xa952, 0xa953, 1},
+ {0xa983, 0xa9b4, 49},
+ {0xa9b5, 0xa9ba, 5},
+ {0xa9bb, 0xa9bd, 2},
+ {0xa9be, 0xa9c0, 1},
+ {0xaa2f, 0xaa30, 1},
+ {0xaa33, 0xaa34, 1},
+ {0xaa4d, 0xaa7b, 46},
+ {0xabe3, 0xabe4, 1},
+ {0xabe6, 0xabe7, 1},
+ {0xabe9, 0xabea, 1},
+ {0xabec, 0x11082, 25750},
+ {0x110b0, 0x110b2, 1},
+ {0x110b7, 0x110b8, 1},
+ {0x1d165, 0x1d166, 1},
+ {0x1d16d, 0x1d172, 1},
}
var _Mn = []Range{
- Range{0x0300, 0x036f, 1},
- Range{0x0483, 0x0487, 1},
- Range{0x0591, 0x05bd, 1},
- Range{0x05bf, 0x05c1, 2},
- Range{0x05c2, 0x05c4, 2},
- Range{0x05c5, 0x05c7, 2},
- Range{0x0610, 0x061a, 1},
- Range{0x064b, 0x065e, 1},
- Range{0x0670, 0x06d6, 102},
- Range{0x06d7, 0x06dc, 1},
- Range{0x06df, 0x06e4, 1},
- Range{0x06e7, 0x06e8, 1},
- Range{0x06ea, 0x06ed, 1},
- Range{0x0711, 0x0730, 31},
- Range{0x0731, 0x074a, 1},
- Range{0x07a6, 0x07b0, 1},
- Range{0x07eb, 0x07f3, 1},
- Range{0x0816, 0x0819, 1},
- Range{0x081b, 0x0823, 1},
- Range{0x0825, 0x0827, 1},
- Range{0x0829, 0x082d, 1},
- Range{0x0900, 0x0902, 1},
- Range{0x093c, 0x0941, 5},
- Range{0x0942, 0x0948, 1},
- Range{0x094d, 0x0951, 4},
- Range{0x0952, 0x0955, 1},
- Range{0x0962, 0x0963, 1},
- Range{0x0981, 0x09bc, 59},
- Range{0x09c1, 0x09c4, 1},
- Range{0x09cd, 0x09e2, 21},
- Range{0x09e3, 0x0a01, 30},
- Range{0x0a02, 0x0a3c, 58},
- Range{0x0a41, 0x0a42, 1},
- Range{0x0a47, 0x0a48, 1},
- Range{0x0a4b, 0x0a4d, 1},
- Range{0x0a51, 0x0a70, 31},
- Range{0x0a71, 0x0a75, 4},
- Range{0x0a81, 0x0a82, 1},
- Range{0x0abc, 0x0ac1, 5},
- Range{0x0ac2, 0x0ac5, 1},
- Range{0x0ac7, 0x0ac8, 1},
- Range{0x0acd, 0x0ae2, 21},
- Range{0x0ae3, 0x0b01, 30},
- Range{0x0b3c, 0x0b3f, 3},
- Range{0x0b41, 0x0b44, 1},
- Range{0x0b4d, 0x0b56, 9},
- Range{0x0b62, 0x0b63, 1},
- Range{0x0b82, 0x0bc0, 62},
- Range{0x0bcd, 0x0c3e, 113},
- Range{0x0c3f, 0x0c40, 1},
- Range{0x0c46, 0x0c48, 1},
- Range{0x0c4a, 0x0c4d, 1},
- Range{0x0c55, 0x0c56, 1},
- Range{0x0c62, 0x0c63, 1},
- Range{0x0cbc, 0x0cbf, 3},
- Range{0x0cc6, 0x0ccc, 6},
- Range{0x0ccd, 0x0ce2, 21},
- Range{0x0ce3, 0x0d41, 94},
- Range{0x0d42, 0x0d44, 1},
- Range{0x0d4d, 0x0d62, 21},
- Range{0x0d63, 0x0dca, 103},
- Range{0x0dd2, 0x0dd4, 1},
- Range{0x0dd6, 0x0e31, 91},
- Range{0x0e34, 0x0e3a, 1},
- Range{0x0e47, 0x0e4e, 1},
- Range{0x0eb1, 0x0eb4, 3},
- Range{0x0eb5, 0x0eb9, 1},
- Range{0x0ebb, 0x0ebc, 1},
- Range{0x0ec8, 0x0ecd, 1},
- Range{0x0f18, 0x0f19, 1},
- Range{0x0f35, 0x0f39, 2},
- Range{0x0f71, 0x0f7e, 1},
- Range{0x0f80, 0x0f84, 1},
- Range{0x0f86, 0x0f87, 1},
- Range{0x0f90, 0x0f97, 1},
- Range{0x0f99, 0x0fbc, 1},
- Range{0x0fc6, 0x102d, 103},
- Range{0x102e, 0x1030, 1},
- Range{0x1032, 0x1037, 1},
- Range{0x1039, 0x103a, 1},
- Range{0x103d, 0x103e, 1},
- Range{0x1058, 0x1059, 1},
- Range{0x105e, 0x1060, 1},
- Range{0x1071, 0x1074, 1},
- Range{0x1082, 0x1085, 3},
- Range{0x1086, 0x108d, 7},
- Range{0x109d, 0x135f, 706},
- Range{0x1712, 0x1714, 1},
- Range{0x1732, 0x1734, 1},
- Range{0x1752, 0x1753, 1},
- Range{0x1772, 0x1773, 1},
- Range{0x17b7, 0x17bd, 1},
- Range{0x17c6, 0x17c9, 3},
- Range{0x17ca, 0x17d3, 1},
- Range{0x17dd, 0x180b, 46},
- Range{0x180c, 0x180d, 1},
- Range{0x18a9, 0x1920, 119},
- Range{0x1921, 0x1922, 1},
- Range{0x1927, 0x1928, 1},
- Range{0x1932, 0x1939, 7},
- Range{0x193a, 0x193b, 1},
- Range{0x1a17, 0x1a18, 1},
- Range{0x1a56, 0x1a58, 2},
- Range{0x1a59, 0x1a5e, 1},
- Range{0x1a60, 0x1a62, 2},
- Range{0x1a65, 0x1a6c, 1},
- Range{0x1a73, 0x1a7c, 1},
- Range{0x1a7f, 0x1b00, 129},
- Range{0x1b01, 0x1b03, 1},
- Range{0x1b34, 0x1b36, 2},
- Range{0x1b37, 0x1b3a, 1},
- Range{0x1b3c, 0x1b42, 6},
- Range{0x1b6b, 0x1b73, 1},
- Range{0x1b80, 0x1b81, 1},
- Range{0x1ba2, 0x1ba5, 1},
- Range{0x1ba8, 0x1ba9, 1},
- Range{0x1c2c, 0x1c33, 1},
- Range{0x1c36, 0x1c37, 1},
- Range{0x1cd0, 0x1cd2, 1},
- Range{0x1cd4, 0x1ce0, 1},
- Range{0x1ce2, 0x1ce8, 1},
- Range{0x1ced, 0x1dc0, 211},
- Range{0x1dc1, 0x1de6, 1},
- Range{0x1dfd, 0x1dff, 1},
- Range{0x20d0, 0x20dc, 1},
- Range{0x20e1, 0x20e5, 4},
- Range{0x20e6, 0x20f0, 1},
- Range{0x2cef, 0x2cf1, 1},
- Range{0x2de0, 0x2dff, 1},
- Range{0x302a, 0x302f, 1},
- Range{0x3099, 0x309a, 1},
- Range{0xa66f, 0xa67c, 13},
- Range{0xa67d, 0xa6f0, 115},
- Range{0xa6f1, 0xa802, 273},
- Range{0xa806, 0xa80b, 5},
- Range{0xa825, 0xa826, 1},
- Range{0xa8c4, 0xa8e0, 28},
- Range{0xa8e1, 0xa8f1, 1},
- Range{0xa926, 0xa92d, 1},
- Range{0xa947, 0xa951, 1},
- Range{0xa980, 0xa982, 1},
- Range{0xa9b3, 0xa9b6, 3},
- Range{0xa9b7, 0xa9b9, 1},
- Range{0xa9bc, 0xaa29, 109},
- Range{0xaa2a, 0xaa2e, 1},
- Range{0xaa31, 0xaa32, 1},
- Range{0xaa35, 0xaa36, 1},
- Range{0xaa43, 0xaa4c, 9},
- Range{0xaab0, 0xaab2, 2},
- Range{0xaab3, 0xaab4, 1},
- Range{0xaab7, 0xaab8, 1},
- Range{0xaabe, 0xaabf, 1},
- Range{0xaac1, 0xabe5, 292},
- Range{0xabe8, 0xabed, 5},
- Range{0xfb1e, 0xfe00, 738},
- Range{0xfe01, 0xfe0f, 1},
- Range{0xfe20, 0xfe26, 1},
- Range{0x101fd, 0x10a01, 2052},
- Range{0x10a02, 0x10a03, 1},
- Range{0x10a05, 0x10a06, 1},
- Range{0x10a0c, 0x10a0f, 1},
- Range{0x10a38, 0x10a3a, 1},
- Range{0x10a3f, 0x11080, 1601},
- Range{0x11081, 0x110b3, 50},
- Range{0x110b4, 0x110b6, 1},
- Range{0x110b9, 0x110ba, 1},
- Range{0x1d167, 0x1d169, 1},
- Range{0x1d17b, 0x1d182, 1},
- Range{0x1d185, 0x1d18b, 1},
- Range{0x1d1aa, 0x1d1ad, 1},
- Range{0x1d242, 0x1d244, 1},
- Range{0xe0100, 0xe01ef, 1},
+ {0x0300, 0x036f, 1},
+ {0x0483, 0x0487, 1},
+ {0x0591, 0x05bd, 1},
+ {0x05bf, 0x05c1, 2},
+ {0x05c2, 0x05c4, 2},
+ {0x05c5, 0x05c7, 2},
+ {0x0610, 0x061a, 1},
+ {0x064b, 0x065e, 1},
+ {0x0670, 0x06d6, 102},
+ {0x06d7, 0x06dc, 1},
+ {0x06df, 0x06e4, 1},
+ {0x06e7, 0x06e8, 1},
+ {0x06ea, 0x06ed, 1},
+ {0x0711, 0x0730, 31},
+ {0x0731, 0x074a, 1},
+ {0x07a6, 0x07b0, 1},
+ {0x07eb, 0x07f3, 1},
+ {0x0816, 0x0819, 1},
+ {0x081b, 0x0823, 1},
+ {0x0825, 0x0827, 1},
+ {0x0829, 0x082d, 1},
+ {0x0900, 0x0902, 1},
+ {0x093c, 0x0941, 5},
+ {0x0942, 0x0948, 1},
+ {0x094d, 0x0951, 4},
+ {0x0952, 0x0955, 1},
+ {0x0962, 0x0963, 1},
+ {0x0981, 0x09bc, 59},
+ {0x09c1, 0x09c4, 1},
+ {0x09cd, 0x09e2, 21},
+ {0x09e3, 0x0a01, 30},
+ {0x0a02, 0x0a3c, 58},
+ {0x0a41, 0x0a42, 1},
+ {0x0a47, 0x0a48, 1},
+ {0x0a4b, 0x0a4d, 1},
+ {0x0a51, 0x0a70, 31},
+ {0x0a71, 0x0a75, 4},
+ {0x0a81, 0x0a82, 1},
+ {0x0abc, 0x0ac1, 5},
+ {0x0ac2, 0x0ac5, 1},
+ {0x0ac7, 0x0ac8, 1},
+ {0x0acd, 0x0ae2, 21},
+ {0x0ae3, 0x0b01, 30},
+ {0x0b3c, 0x0b3f, 3},
+ {0x0b41, 0x0b44, 1},
+ {0x0b4d, 0x0b56, 9},
+ {0x0b62, 0x0b63, 1},
+ {0x0b82, 0x0bc0, 62},
+ {0x0bcd, 0x0c3e, 113},
+ {0x0c3f, 0x0c40, 1},
+ {0x0c46, 0x0c48, 1},
+ {0x0c4a, 0x0c4d, 1},
+ {0x0c55, 0x0c56, 1},
+ {0x0c62, 0x0c63, 1},
+ {0x0cbc, 0x0cbf, 3},
+ {0x0cc6, 0x0ccc, 6},
+ {0x0ccd, 0x0ce2, 21},
+ {0x0ce3, 0x0d41, 94},
+ {0x0d42, 0x0d44, 1},
+ {0x0d4d, 0x0d62, 21},
+ {0x0d63, 0x0dca, 103},
+ {0x0dd2, 0x0dd4, 1},
+ {0x0dd6, 0x0e31, 91},
+ {0x0e34, 0x0e3a, 1},
+ {0x0e47, 0x0e4e, 1},
+ {0x0eb1, 0x0eb4, 3},
+ {0x0eb5, 0x0eb9, 1},
+ {0x0ebb, 0x0ebc, 1},
+ {0x0ec8, 0x0ecd, 1},
+ {0x0f18, 0x0f19, 1},
+ {0x0f35, 0x0f39, 2},
+ {0x0f71, 0x0f7e, 1},
+ {0x0f80, 0x0f84, 1},
+ {0x0f86, 0x0f87, 1},
+ {0x0f90, 0x0f97, 1},
+ {0x0f99, 0x0fbc, 1},
+ {0x0fc6, 0x102d, 103},
+ {0x102e, 0x1030, 1},
+ {0x1032, 0x1037, 1},
+ {0x1039, 0x103a, 1},
+ {0x103d, 0x103e, 1},
+ {0x1058, 0x1059, 1},
+ {0x105e, 0x1060, 1},
+ {0x1071, 0x1074, 1},
+ {0x1082, 0x1085, 3},
+ {0x1086, 0x108d, 7},
+ {0x109d, 0x135f, 706},
+ {0x1712, 0x1714, 1},
+ {0x1732, 0x1734, 1},
+ {0x1752, 0x1753, 1},
+ {0x1772, 0x1773, 1},
+ {0x17b7, 0x17bd, 1},
+ {0x17c6, 0x17c9, 3},
+ {0x17ca, 0x17d3, 1},
+ {0x17dd, 0x180b, 46},
+ {0x180c, 0x180d, 1},
+ {0x18a9, 0x1920, 119},
+ {0x1921, 0x1922, 1},
+ {0x1927, 0x1928, 1},
+ {0x1932, 0x1939, 7},
+ {0x193a, 0x193b, 1},
+ {0x1a17, 0x1a18, 1},
+ {0x1a56, 0x1a58, 2},
+ {0x1a59, 0x1a5e, 1},
+ {0x1a60, 0x1a62, 2},
+ {0x1a65, 0x1a6c, 1},
+ {0x1a73, 0x1a7c, 1},
+ {0x1a7f, 0x1b00, 129},
+ {0x1b01, 0x1b03, 1},
+ {0x1b34, 0x1b36, 2},
+ {0x1b37, 0x1b3a, 1},
+ {0x1b3c, 0x1b42, 6},
+ {0x1b6b, 0x1b73, 1},
+ {0x1b80, 0x1b81, 1},
+ {0x1ba2, 0x1ba5, 1},
+ {0x1ba8, 0x1ba9, 1},
+ {0x1c2c, 0x1c33, 1},
+ {0x1c36, 0x1c37, 1},
+ {0x1cd0, 0x1cd2, 1},
+ {0x1cd4, 0x1ce0, 1},
+ {0x1ce2, 0x1ce8, 1},
+ {0x1ced, 0x1dc0, 211},
+ {0x1dc1, 0x1de6, 1},
+ {0x1dfd, 0x1dff, 1},
+ {0x20d0, 0x20dc, 1},
+ {0x20e1, 0x20e5, 4},
+ {0x20e6, 0x20f0, 1},
+ {0x2cef, 0x2cf1, 1},
+ {0x2de0, 0x2dff, 1},
+ {0x302a, 0x302f, 1},
+ {0x3099, 0x309a, 1},
+ {0xa66f, 0xa67c, 13},
+ {0xa67d, 0xa6f0, 115},
+ {0xa6f1, 0xa802, 273},
+ {0xa806, 0xa80b, 5},
+ {0xa825, 0xa826, 1},
+ {0xa8c4, 0xa8e0, 28},
+ {0xa8e1, 0xa8f1, 1},
+ {0xa926, 0xa92d, 1},
+ {0xa947, 0xa951, 1},
+ {0xa980, 0xa982, 1},
+ {0xa9b3, 0xa9b6, 3},
+ {0xa9b7, 0xa9b9, 1},
+ {0xa9bc, 0xaa29, 109},
+ {0xaa2a, 0xaa2e, 1},
+ {0xaa31, 0xaa32, 1},
+ {0xaa35, 0xaa36, 1},
+ {0xaa43, 0xaa4c, 9},
+ {0xaab0, 0xaab2, 2},
+ {0xaab3, 0xaab4, 1},
+ {0xaab7, 0xaab8, 1},
+ {0xaabe, 0xaabf, 1},
+ {0xaac1, 0xabe5, 292},
+ {0xabe8, 0xabed, 5},
+ {0xfb1e, 0xfe00, 738},
+ {0xfe01, 0xfe0f, 1},
+ {0xfe20, 0xfe26, 1},
+ {0x101fd, 0x10a01, 2052},
+ {0x10a02, 0x10a03, 1},
+ {0x10a05, 0x10a06, 1},
+ {0x10a0c, 0x10a0f, 1},
+ {0x10a38, 0x10a3a, 1},
+ {0x10a3f, 0x11080, 1601},
+ {0x11081, 0x110b3, 50},
+ {0x110b4, 0x110b6, 1},
+ {0x110b9, 0x110ba, 1},
+ {0x1d167, 0x1d169, 1},
+ {0x1d17b, 0x1d182, 1},
+ {0x1d185, 0x1d18b, 1},
+ {0x1d1aa, 0x1d1ad, 1},
+ {0x1d242, 0x1d244, 1},
+ {0xe0100, 0xe01ef, 1},
}
var _Zl = []Range{
- Range{0x2028, 0x2028, 1},
+ {0x2028, 0x2028, 1},
}
var letter = []Range{
- Range{0x0041, 0x005a, 1},
- Range{0x0061, 0x007a, 1},
- Range{0x00aa, 0x00b5, 11},
- Range{0x00ba, 0x00c0, 6},
- Range{0x00c1, 0x00d6, 1},
- Range{0x00d8, 0x00f6, 1},
- Range{0x00f8, 0x02c1, 1},
- Range{0x02c6, 0x02d1, 1},
- Range{0x02e0, 0x02e4, 1},
- Range{0x02ec, 0x02ee, 2},
- Range{0x0370, 0x0374, 1},
- Range{0x0376, 0x0377, 1},
- Range{0x037a, 0x037d, 1},
- Range{0x0386, 0x0388, 2},
- Range{0x0389, 0x038a, 1},
- Range{0x038c, 0x038e, 2},
- Range{0x038f, 0x03a1, 1},
- Range{0x03a3, 0x03f5, 1},
- Range{0x03f7, 0x0481, 1},
- Range{0x048a, 0x0525, 1},
- Range{0x0531, 0x0556, 1},
- Range{0x0559, 0x0561, 8},
- Range{0x0562, 0x0587, 1},
- Range{0x05d0, 0x05ea, 1},
- Range{0x05f0, 0x05f2, 1},
- Range{0x0621, 0x064a, 1},
- Range{0x066e, 0x066f, 1},
- Range{0x0671, 0x06d3, 1},
- Range{0x06d5, 0x06e5, 16},
- Range{0x06e6, 0x06ee, 8},
- Range{0x06ef, 0x06fa, 11},
- Range{0x06fb, 0x06fc, 1},
- Range{0x06ff, 0x0710, 17},
- Range{0x0712, 0x072f, 1},
- Range{0x074d, 0x07a5, 1},
- Range{0x07b1, 0x07ca, 25},
- Range{0x07cb, 0x07ea, 1},
- Range{0x07f4, 0x07f5, 1},
- Range{0x07fa, 0x0800, 6},
- Range{0x0801, 0x0815, 1},
- Range{0x081a, 0x0824, 10},
- Range{0x0828, 0x0904, 220},
- Range{0x0905, 0x0939, 1},
- Range{0x093d, 0x0950, 19},
- Range{0x0958, 0x0961, 1},
- Range{0x0971, 0x0972, 1},
- Range{0x0979, 0x097f, 1},
- Range{0x0985, 0x098c, 1},
- Range{0x098f, 0x0990, 1},
- Range{0x0993, 0x09a8, 1},
- Range{0x09aa, 0x09b0, 1},
- Range{0x09b2, 0x09b6, 4},
- Range{0x09b7, 0x09b9, 1},
- Range{0x09bd, 0x09ce, 17},
- Range{0x09dc, 0x09dd, 1},
- Range{0x09df, 0x09e1, 1},
- Range{0x09f0, 0x09f1, 1},
- Range{0x0a05, 0x0a0a, 1},
- Range{0x0a0f, 0x0a10, 1},
- Range{0x0a13, 0x0a28, 1},
- Range{0x0a2a, 0x0a30, 1},
- Range{0x0a32, 0x0a33, 1},
- Range{0x0a35, 0x0a36, 1},
- Range{0x0a38, 0x0a39, 1},
- Range{0x0a59, 0x0a5c, 1},
- Range{0x0a5e, 0x0a72, 20},
- Range{0x0a73, 0x0a74, 1},
- Range{0x0a85, 0x0a8d, 1},
- Range{0x0a8f, 0x0a91, 1},
- Range{0x0a93, 0x0aa8, 1},
- Range{0x0aaa, 0x0ab0, 1},
- Range{0x0ab2, 0x0ab3, 1},
- Range{0x0ab5, 0x0ab9, 1},
- Range{0x0abd, 0x0ad0, 19},
- Range{0x0ae0, 0x0ae1, 1},
- Range{0x0b05, 0x0b0c, 1},
- Range{0x0b0f, 0x0b10, 1},
- Range{0x0b13, 0x0b28, 1},
- Range{0x0b2a, 0x0b30, 1},
- Range{0x0b32, 0x0b33, 1},
- Range{0x0b35, 0x0b39, 1},
- Range{0x0b3d, 0x0b5c, 31},
- Range{0x0b5d, 0x0b5f, 2},
- Range{0x0b60, 0x0b61, 1},
- Range{0x0b71, 0x0b83, 18},
- Range{0x0b85, 0x0b8a, 1},
- Range{0x0b8e, 0x0b90, 1},
- Range{0x0b92, 0x0b95, 1},
- Range{0x0b99, 0x0b9a, 1},
- Range{0x0b9c, 0x0b9e, 2},
- Range{0x0b9f, 0x0ba3, 4},
- Range{0x0ba4, 0x0ba8, 4},
- Range{0x0ba9, 0x0baa, 1},
- Range{0x0bae, 0x0bb9, 1},
- Range{0x0bd0, 0x0c05, 53},
- Range{0x0c06, 0x0c0c, 1},
- Range{0x0c0e, 0x0c10, 1},
- Range{0x0c12, 0x0c28, 1},
- Range{0x0c2a, 0x0c33, 1},
- Range{0x0c35, 0x0c39, 1},
- Range{0x0c3d, 0x0c58, 27},
- Range{0x0c59, 0x0c60, 7},
- Range{0x0c61, 0x0c85, 36},
- Range{0x0c86, 0x0c8c, 1},
- Range{0x0c8e, 0x0c90, 1},
- Range{0x0c92, 0x0ca8, 1},
- Range{0x0caa, 0x0cb3, 1},
- Range{0x0cb5, 0x0cb9, 1},
- Range{0x0cbd, 0x0cde, 33},
- Range{0x0ce0, 0x0ce1, 1},
- Range{0x0d05, 0x0d0c, 1},
- Range{0x0d0e, 0x0d10, 1},
- Range{0x0d12, 0x0d28, 1},
- Range{0x0d2a, 0x0d39, 1},
- Range{0x0d3d, 0x0d60, 35},
- Range{0x0d61, 0x0d7a, 25},
- Range{0x0d7b, 0x0d7f, 1},
- Range{0x0d85, 0x0d96, 1},
- Range{0x0d9a, 0x0db1, 1},
- Range{0x0db3, 0x0dbb, 1},
- Range{0x0dbd, 0x0dc0, 3},
- Range{0x0dc1, 0x0dc6, 1},
- Range{0x0e01, 0x0e30, 1},
- Range{0x0e32, 0x0e33, 1},
- Range{0x0e40, 0x0e46, 1},
- Range{0x0e81, 0x0e82, 1},
- Range{0x0e84, 0x0e87, 3},
- Range{0x0e88, 0x0e8a, 2},
- Range{0x0e8d, 0x0e94, 7},
- Range{0x0e95, 0x0e97, 1},
- Range{0x0e99, 0x0e9f, 1},
- Range{0x0ea1, 0x0ea3, 1},
- Range{0x0ea5, 0x0ea7, 2},
- Range{0x0eaa, 0x0eab, 1},
- Range{0x0ead, 0x0eb0, 1},
- Range{0x0eb2, 0x0eb3, 1},
- Range{0x0ebd, 0x0ec0, 3},
- Range{0x0ec1, 0x0ec4, 1},
- Range{0x0ec6, 0x0edc, 22},
- Range{0x0edd, 0x0f00, 35},
- Range{0x0f40, 0x0f47, 1},
- Range{0x0f49, 0x0f6c, 1},
- Range{0x0f88, 0x0f8b, 1},
- Range{0x1000, 0x102a, 1},
- Range{0x103f, 0x1050, 17},
- Range{0x1051, 0x1055, 1},
- Range{0x105a, 0x105d, 1},
- Range{0x1061, 0x1065, 4},
- Range{0x1066, 0x106e, 8},
- Range{0x106f, 0x1070, 1},
- Range{0x1075, 0x1081, 1},
- Range{0x108e, 0x10a0, 18},
- Range{0x10a1, 0x10c5, 1},
- Range{0x10d0, 0x10fa, 1},
- Range{0x10fc, 0x1100, 4},
- Range{0x1101, 0x1248, 1},
- Range{0x124a, 0x124d, 1},
- Range{0x1250, 0x1256, 1},
- Range{0x1258, 0x125a, 2},
- Range{0x125b, 0x125d, 1},
- Range{0x1260, 0x1288, 1},
- Range{0x128a, 0x128d, 1},
- Range{0x1290, 0x12b0, 1},
- Range{0x12b2, 0x12b5, 1},
- Range{0x12b8, 0x12be, 1},
- Range{0x12c0, 0x12c2, 2},
- Range{0x12c3, 0x12c5, 1},
- Range{0x12c8, 0x12d6, 1},
- Range{0x12d8, 0x1310, 1},
- Range{0x1312, 0x1315, 1},
- Range{0x1318, 0x135a, 1},
- Range{0x1380, 0x138f, 1},
- Range{0x13a0, 0x13f4, 1},
- Range{0x1401, 0x166c, 1},
- Range{0x166f, 0x167f, 1},
- Range{0x1681, 0x169a, 1},
- Range{0x16a0, 0x16ea, 1},
- Range{0x1700, 0x170c, 1},
- Range{0x170e, 0x1711, 1},
- Range{0x1720, 0x1731, 1},
- Range{0x1740, 0x1751, 1},
- Range{0x1760, 0x176c, 1},
- Range{0x176e, 0x1770, 1},
- Range{0x1780, 0x17b3, 1},
- Range{0x17d7, 0x17dc, 5},
- Range{0x1820, 0x1877, 1},
- Range{0x1880, 0x18a8, 1},
- Range{0x18aa, 0x18b0, 6},
- Range{0x18b1, 0x18f5, 1},
- Range{0x1900, 0x191c, 1},
- Range{0x1950, 0x196d, 1},
- Range{0x1970, 0x1974, 1},
- Range{0x1980, 0x19ab, 1},
- Range{0x19c1, 0x19c7, 1},
- Range{0x1a00, 0x1a16, 1},
- Range{0x1a20, 0x1a54, 1},
- Range{0x1aa7, 0x1b05, 94},
- Range{0x1b06, 0x1b33, 1},
- Range{0x1b45, 0x1b4b, 1},
- Range{0x1b83, 0x1ba0, 1},
- Range{0x1bae, 0x1baf, 1},
- Range{0x1c00, 0x1c23, 1},
- Range{0x1c4d, 0x1c4f, 1},
- Range{0x1c5a, 0x1c7d, 1},
- Range{0x1ce9, 0x1cec, 1},
- Range{0x1cee, 0x1cf1, 1},
- Range{0x1d00, 0x1dbf, 1},
- Range{0x1e00, 0x1f15, 1},
- Range{0x1f18, 0x1f1d, 1},
- Range{0x1f20, 0x1f45, 1},
- Range{0x1f48, 0x1f4d, 1},
- Range{0x1f50, 0x1f57, 1},
- Range{0x1f59, 0x1f5f, 2},
- Range{0x1f60, 0x1f7d, 1},
- Range{0x1f80, 0x1fb4, 1},
- Range{0x1fb6, 0x1fbc, 1},
- Range{0x1fbe, 0x1fc2, 4},
- Range{0x1fc3, 0x1fc4, 1},
- Range{0x1fc6, 0x1fcc, 1},
- Range{0x1fd0, 0x1fd3, 1},
- Range{0x1fd6, 0x1fdb, 1},
- Range{0x1fe0, 0x1fec, 1},
- Range{0x1ff2, 0x1ff4, 1},
- Range{0x1ff6, 0x1ffc, 1},
- Range{0x2071, 0x207f, 14},
- Range{0x2090, 0x2094, 1},
- Range{0x2102, 0x2107, 5},
- Range{0x210a, 0x2113, 1},
- Range{0x2115, 0x2119, 4},
- Range{0x211a, 0x211d, 1},
- Range{0x2124, 0x212a, 2},
- Range{0x212b, 0x212d, 1},
- Range{0x212f, 0x2139, 1},
- Range{0x213c, 0x213f, 1},
- Range{0x2145, 0x2149, 1},
- Range{0x214e, 0x2183, 53},
- Range{0x2184, 0x2c00, 2684},
- Range{0x2c01, 0x2c2e, 1},
- Range{0x2c30, 0x2c5e, 1},
- Range{0x2c60, 0x2ce4, 1},
- Range{0x2ceb, 0x2cee, 1},
- Range{0x2d00, 0x2d25, 1},
- Range{0x2d30, 0x2d65, 1},
- Range{0x2d6f, 0x2d80, 17},
- Range{0x2d81, 0x2d96, 1},
- Range{0x2da0, 0x2da6, 1},
- Range{0x2da8, 0x2dae, 1},
- Range{0x2db0, 0x2db6, 1},
- Range{0x2db8, 0x2dbe, 1},
- Range{0x2dc0, 0x2dc6, 1},
- Range{0x2dc8, 0x2dce, 1},
- Range{0x2dd0, 0x2dd6, 1},
- Range{0x2dd8, 0x2dde, 1},
- Range{0x2e2f, 0x3005, 470},
- Range{0x3006, 0x3031, 43},
- Range{0x3032, 0x3035, 1},
- Range{0x303b, 0x303c, 1},
- Range{0x3041, 0x3096, 1},
- Range{0x309d, 0x309f, 1},
- Range{0x30a1, 0x30fa, 1},
- Range{0x30fc, 0x30ff, 1},
- Range{0x3105, 0x312d, 1},
- Range{0x3131, 0x318e, 1},
- Range{0x31a0, 0x31b7, 1},
- Range{0x31f0, 0x31ff, 1},
- Range{0x3400, 0x4db5, 1},
- Range{0x4e00, 0x9fcb, 1},
- Range{0xa000, 0xa48c, 1},
- Range{0xa4d0, 0xa4fd, 1},
- Range{0xa500, 0xa60c, 1},
- Range{0xa610, 0xa61f, 1},
- Range{0xa62a, 0xa62b, 1},
- Range{0xa640, 0xa65f, 1},
- Range{0xa662, 0xa66e, 1},
- Range{0xa67f, 0xa697, 1},
- Range{0xa6a0, 0xa6e5, 1},
- Range{0xa717, 0xa71f, 1},
- Range{0xa722, 0xa788, 1},
- Range{0xa78b, 0xa78c, 1},
- Range{0xa7fb, 0xa801, 1},
- Range{0xa803, 0xa805, 1},
- Range{0xa807, 0xa80a, 1},
- Range{0xa80c, 0xa822, 1},
- Range{0xa840, 0xa873, 1},
- Range{0xa882, 0xa8b3, 1},
- Range{0xa8f2, 0xa8f7, 1},
- Range{0xa8fb, 0xa90a, 15},
- Range{0xa90b, 0xa925, 1},
- Range{0xa930, 0xa946, 1},
- Range{0xa960, 0xa97c, 1},
- Range{0xa984, 0xa9b2, 1},
- Range{0xa9cf, 0xaa00, 49},
- Range{0xaa01, 0xaa28, 1},
- Range{0xaa40, 0xaa42, 1},
- Range{0xaa44, 0xaa4b, 1},
- Range{0xaa60, 0xaa76, 1},
- Range{0xaa7a, 0xaa80, 6},
- Range{0xaa81, 0xaaaf, 1},
- Range{0xaab1, 0xaab5, 4},
- Range{0xaab6, 0xaab9, 3},
- Range{0xaaba, 0xaabd, 1},
- Range{0xaac0, 0xaac2, 2},
- Range{0xaadb, 0xaadd, 1},
- Range{0xabc0, 0xabe2, 1},
- Range{0xac00, 0xd7a3, 1},
- Range{0xd7b0, 0xd7c6, 1},
- Range{0xd7cb, 0xd7fb, 1},
- Range{0xf900, 0xfa2d, 1},
- Range{0xfa30, 0xfa6d, 1},
- Range{0xfa70, 0xfad9, 1},
- Range{0xfb00, 0xfb06, 1},
- Range{0xfb13, 0xfb17, 1},
- Range{0xfb1d, 0xfb1f, 2},
- Range{0xfb20, 0xfb28, 1},
- Range{0xfb2a, 0xfb36, 1},
- Range{0xfb38, 0xfb3c, 1},
- Range{0xfb3e, 0xfb40, 2},
- Range{0xfb41, 0xfb43, 2},
- Range{0xfb44, 0xfb46, 2},
- Range{0xfb47, 0xfbb1, 1},
- Range{0xfbd3, 0xfd3d, 1},
- Range{0xfd50, 0xfd8f, 1},
- Range{0xfd92, 0xfdc7, 1},
- Range{0xfdf0, 0xfdfb, 1},
- Range{0xfe70, 0xfe74, 1},
- Range{0xfe76, 0xfefc, 1},
- Range{0xff21, 0xff3a, 1},
- Range{0xff41, 0xff5a, 1},
- Range{0xff66, 0xffbe, 1},
- Range{0xffc2, 0xffc7, 1},
- Range{0xffca, 0xffcf, 1},
- Range{0xffd2, 0xffd7, 1},
- Range{0xffda, 0xffdc, 1},
- Range{0x10000, 0x1000b, 1},
- Range{0x1000d, 0x10026, 1},
- Range{0x10028, 0x1003a, 1},
- Range{0x1003c, 0x1003d, 1},
- Range{0x1003f, 0x1004d, 1},
- Range{0x10050, 0x1005d, 1},
- Range{0x10080, 0x100fa, 1},
- Range{0x10280, 0x1029c, 1},
- Range{0x102a0, 0x102d0, 1},
- Range{0x10300, 0x1031e, 1},
- Range{0x10330, 0x10340, 1},
- Range{0x10342, 0x10349, 1},
- Range{0x10380, 0x1039d, 1},
- Range{0x103a0, 0x103c3, 1},
- Range{0x103c8, 0x103cf, 1},
- Range{0x10400, 0x1049d, 1},
- Range{0x10800, 0x10805, 1},
- Range{0x10808, 0x1080a, 2},
- Range{0x1080b, 0x10835, 1},
- Range{0x10837, 0x10838, 1},
- Range{0x1083c, 0x1083f, 3},
- Range{0x10840, 0x10855, 1},
- Range{0x10900, 0x10915, 1},
- Range{0x10920, 0x10939, 1},
- Range{0x10a00, 0x10a10, 16},
- Range{0x10a11, 0x10a13, 1},
- Range{0x10a15, 0x10a17, 1},
- Range{0x10a19, 0x10a33, 1},
- Range{0x10a60, 0x10a7c, 1},
- Range{0x10b00, 0x10b35, 1},
- Range{0x10b40, 0x10b55, 1},
- Range{0x10b60, 0x10b72, 1},
- Range{0x10c00, 0x10c48, 1},
- Range{0x11083, 0x110af, 1},
- Range{0x12000, 0x1236e, 1},
- Range{0x13000, 0x1342e, 1},
- Range{0x1d400, 0x1d454, 1},
- Range{0x1d456, 0x1d49c, 1},
- Range{0x1d49e, 0x1d49f, 1},
- Range{0x1d4a2, 0x1d4a5, 3},
- Range{0x1d4a6, 0x1d4a9, 3},
- Range{0x1d4aa, 0x1d4ac, 1},
- Range{0x1d4ae, 0x1d4b9, 1},
- Range{0x1d4bb, 0x1d4bd, 2},
- Range{0x1d4be, 0x1d4c3, 1},
- Range{0x1d4c5, 0x1d505, 1},
- Range{0x1d507, 0x1d50a, 1},
- Range{0x1d50d, 0x1d514, 1},
- Range{0x1d516, 0x1d51c, 1},
- Range{0x1d51e, 0x1d539, 1},
- Range{0x1d53b, 0x1d53e, 1},
- Range{0x1d540, 0x1d544, 1},
- Range{0x1d546, 0x1d54a, 4},
- Range{0x1d54b, 0x1d550, 1},
- Range{0x1d552, 0x1d6a5, 1},
- Range{0x1d6a8, 0x1d6c0, 1},
- Range{0x1d6c2, 0x1d6da, 1},
- Range{0x1d6dc, 0x1d6fa, 1},
- Range{0x1d6fc, 0x1d714, 1},
- Range{0x1d716, 0x1d734, 1},
- Range{0x1d736, 0x1d74e, 1},
- Range{0x1d750, 0x1d76e, 1},
- Range{0x1d770, 0x1d788, 1},
- Range{0x1d78a, 0x1d7a8, 1},
- Range{0x1d7aa, 0x1d7c2, 1},
- Range{0x1d7c4, 0x1d7cb, 1},
- Range{0x20000, 0x2a6d6, 1},
- Range{0x2a700, 0x2b734, 1},
- Range{0x2f800, 0x2fa1d, 1},
+ {0x0041, 0x005a, 1},
+ {0x0061, 0x007a, 1},
+ {0x00aa, 0x00b5, 11},
+ {0x00ba, 0x00c0, 6},
+ {0x00c1, 0x00d6, 1},
+ {0x00d8, 0x00f6, 1},
+ {0x00f8, 0x02c1, 1},
+ {0x02c6, 0x02d1, 1},
+ {0x02e0, 0x02e4, 1},
+ {0x02ec, 0x02ee, 2},
+ {0x0370, 0x0374, 1},
+ {0x0376, 0x0377, 1},
+ {0x037a, 0x037d, 1},
+ {0x0386, 0x0388, 2},
+ {0x0389, 0x038a, 1},
+ {0x038c, 0x038e, 2},
+ {0x038f, 0x03a1, 1},
+ {0x03a3, 0x03f5, 1},
+ {0x03f7, 0x0481, 1},
+ {0x048a, 0x0525, 1},
+ {0x0531, 0x0556, 1},
+ {0x0559, 0x0561, 8},
+ {0x0562, 0x0587, 1},
+ {0x05d0, 0x05ea, 1},
+ {0x05f0, 0x05f2, 1},
+ {0x0621, 0x064a, 1},
+ {0x066e, 0x066f, 1},
+ {0x0671, 0x06d3, 1},
+ {0x06d5, 0x06e5, 16},
+ {0x06e6, 0x06ee, 8},
+ {0x06ef, 0x06fa, 11},
+ {0x06fb, 0x06fc, 1},
+ {0x06ff, 0x0710, 17},
+ {0x0712, 0x072f, 1},
+ {0x074d, 0x07a5, 1},
+ {0x07b1, 0x07ca, 25},
+ {0x07cb, 0x07ea, 1},
+ {0x07f4, 0x07f5, 1},
+ {0x07fa, 0x0800, 6},
+ {0x0801, 0x0815, 1},
+ {0x081a, 0x0824, 10},
+ {0x0828, 0x0904, 220},
+ {0x0905, 0x0939, 1},
+ {0x093d, 0x0950, 19},
+ {0x0958, 0x0961, 1},
+ {0x0971, 0x0972, 1},
+ {0x0979, 0x097f, 1},
+ {0x0985, 0x098c, 1},
+ {0x098f, 0x0990, 1},
+ {0x0993, 0x09a8, 1},
+ {0x09aa, 0x09b0, 1},
+ {0x09b2, 0x09b6, 4},
+ {0x09b7, 0x09b9, 1},
+ {0x09bd, 0x09ce, 17},
+ {0x09dc, 0x09dd, 1},
+ {0x09df, 0x09e1, 1},
+ {0x09f0, 0x09f1, 1},
+ {0x0a05, 0x0a0a, 1},
+ {0x0a0f, 0x0a10, 1},
+ {0x0a13, 0x0a28, 1},
+ {0x0a2a, 0x0a30, 1},
+ {0x0a32, 0x0a33, 1},
+ {0x0a35, 0x0a36, 1},
+ {0x0a38, 0x0a39, 1},
+ {0x0a59, 0x0a5c, 1},
+ {0x0a5e, 0x0a72, 20},
+ {0x0a73, 0x0a74, 1},
+ {0x0a85, 0x0a8d, 1},
+ {0x0a8f, 0x0a91, 1},
+ {0x0a93, 0x0aa8, 1},
+ {0x0aaa, 0x0ab0, 1},
+ {0x0ab2, 0x0ab3, 1},
+ {0x0ab5, 0x0ab9, 1},
+ {0x0abd, 0x0ad0, 19},
+ {0x0ae0, 0x0ae1, 1},
+ {0x0b05, 0x0b0c, 1},
+ {0x0b0f, 0x0b10, 1},
+ {0x0b13, 0x0b28, 1},
+ {0x0b2a, 0x0b30, 1},
+ {0x0b32, 0x0b33, 1},
+ {0x0b35, 0x0b39, 1},
+ {0x0b3d, 0x0b5c, 31},
+ {0x0b5d, 0x0b5f, 2},
+ {0x0b60, 0x0b61, 1},
+ {0x0b71, 0x0b83, 18},
+ {0x0b85, 0x0b8a, 1},
+ {0x0b8e, 0x0b90, 1},
+ {0x0b92, 0x0b95, 1},
+ {0x0b99, 0x0b9a, 1},
+ {0x0b9c, 0x0b9e, 2},
+ {0x0b9f, 0x0ba3, 4},
+ {0x0ba4, 0x0ba8, 4},
+ {0x0ba9, 0x0baa, 1},
+ {0x0bae, 0x0bb9, 1},
+ {0x0bd0, 0x0c05, 53},
+ {0x0c06, 0x0c0c, 1},
+ {0x0c0e, 0x0c10, 1},
+ {0x0c12, 0x0c28, 1},
+ {0x0c2a, 0x0c33, 1},
+ {0x0c35, 0x0c39, 1},
+ {0x0c3d, 0x0c58, 27},
+ {0x0c59, 0x0c60, 7},
+ {0x0c61, 0x0c85, 36},
+ {0x0c86, 0x0c8c, 1},
+ {0x0c8e, 0x0c90, 1},
+ {0x0c92, 0x0ca8, 1},
+ {0x0caa, 0x0cb3, 1},
+ {0x0cb5, 0x0cb9, 1},
+ {0x0cbd, 0x0cde, 33},
+ {0x0ce0, 0x0ce1, 1},
+ {0x0d05, 0x0d0c, 1},
+ {0x0d0e, 0x0d10, 1},
+ {0x0d12, 0x0d28, 1},
+ {0x0d2a, 0x0d39, 1},
+ {0x0d3d, 0x0d60, 35},
+ {0x0d61, 0x0d7a, 25},
+ {0x0d7b, 0x0d7f, 1},
+ {0x0d85, 0x0d96, 1},
+ {0x0d9a, 0x0db1, 1},
+ {0x0db3, 0x0dbb, 1},
+ {0x0dbd, 0x0dc0, 3},
+ {0x0dc1, 0x0dc6, 1},
+ {0x0e01, 0x0e30, 1},
+ {0x0e32, 0x0e33, 1},
+ {0x0e40, 0x0e46, 1},
+ {0x0e81, 0x0e82, 1},
+ {0x0e84, 0x0e87, 3},
+ {0x0e88, 0x0e8a, 2},
+ {0x0e8d, 0x0e94, 7},
+ {0x0e95, 0x0e97, 1},
+ {0x0e99, 0x0e9f, 1},
+ {0x0ea1, 0x0ea3, 1},
+ {0x0ea5, 0x0ea7, 2},
+ {0x0eaa, 0x0eab, 1},
+ {0x0ead, 0x0eb0, 1},
+ {0x0eb2, 0x0eb3, 1},
+ {0x0ebd, 0x0ec0, 3},
+ {0x0ec1, 0x0ec4, 1},
+ {0x0ec6, 0x0edc, 22},
+ {0x0edd, 0x0f00, 35},
+ {0x0f40, 0x0f47, 1},
+ {0x0f49, 0x0f6c, 1},
+ {0x0f88, 0x0f8b, 1},
+ {0x1000, 0x102a, 1},
+ {0x103f, 0x1050, 17},
+ {0x1051, 0x1055, 1},
+ {0x105a, 0x105d, 1},
+ {0x1061, 0x1065, 4},
+ {0x1066, 0x106e, 8},
+ {0x106f, 0x1070, 1},
+ {0x1075, 0x1081, 1},
+ {0x108e, 0x10a0, 18},
+ {0x10a1, 0x10c5, 1},
+ {0x10d0, 0x10fa, 1},
+ {0x10fc, 0x1100, 4},
+ {0x1101, 0x1248, 1},
+ {0x124a, 0x124d, 1},
+ {0x1250, 0x1256, 1},
+ {0x1258, 0x125a, 2},
+ {0x125b, 0x125d, 1},
+ {0x1260, 0x1288, 1},
+ {0x128a, 0x128d, 1},
+ {0x1290, 0x12b0, 1},
+ {0x12b2, 0x12b5, 1},
+ {0x12b8, 0x12be, 1},
+ {0x12c0, 0x12c2, 2},
+ {0x12c3, 0x12c5, 1},
+ {0x12c8, 0x12d6, 1},
+ {0x12d8, 0x1310, 1},
+ {0x1312, 0x1315, 1},
+ {0x1318, 0x135a, 1},
+ {0x1380, 0x138f, 1},
+ {0x13a0, 0x13f4, 1},
+ {0x1401, 0x166c, 1},
+ {0x166f, 0x167f, 1},
+ {0x1681, 0x169a, 1},
+ {0x16a0, 0x16ea, 1},
+ {0x1700, 0x170c, 1},
+ {0x170e, 0x1711, 1},
+ {0x1720, 0x1731, 1},
+ {0x1740, 0x1751, 1},
+ {0x1760, 0x176c, 1},
+ {0x176e, 0x1770, 1},
+ {0x1780, 0x17b3, 1},
+ {0x17d7, 0x17dc, 5},
+ {0x1820, 0x1877, 1},
+ {0x1880, 0x18a8, 1},
+ {0x18aa, 0x18b0, 6},
+ {0x18b1, 0x18f5, 1},
+ {0x1900, 0x191c, 1},
+ {0x1950, 0x196d, 1},
+ {0x1970, 0x1974, 1},
+ {0x1980, 0x19ab, 1},
+ {0x19c1, 0x19c7, 1},
+ {0x1a00, 0x1a16, 1},
+ {0x1a20, 0x1a54, 1},
+ {0x1aa7, 0x1b05, 94},
+ {0x1b06, 0x1b33, 1},
+ {0x1b45, 0x1b4b, 1},
+ {0x1b83, 0x1ba0, 1},
+ {0x1bae, 0x1baf, 1},
+ {0x1c00, 0x1c23, 1},
+ {0x1c4d, 0x1c4f, 1},
+ {0x1c5a, 0x1c7d, 1},
+ {0x1ce9, 0x1cec, 1},
+ {0x1cee, 0x1cf1, 1},
+ {0x1d00, 0x1dbf, 1},
+ {0x1e00, 0x1f15, 1},
+ {0x1f18, 0x1f1d, 1},
+ {0x1f20, 0x1f45, 1},
+ {0x1f48, 0x1f4d, 1},
+ {0x1f50, 0x1f57, 1},
+ {0x1f59, 0x1f5f, 2},
+ {0x1f60, 0x1f7d, 1},
+ {0x1f80, 0x1fb4, 1},
+ {0x1fb6, 0x1fbc, 1},
+ {0x1fbe, 0x1fc2, 4},
+ {0x1fc3, 0x1fc4, 1},
+ {0x1fc6, 0x1fcc, 1},
+ {0x1fd0, 0x1fd3, 1},
+ {0x1fd6, 0x1fdb, 1},
+ {0x1fe0, 0x1fec, 1},
+ {0x1ff2, 0x1ff4, 1},
+ {0x1ff6, 0x1ffc, 1},
+ {0x2071, 0x207f, 14},
+ {0x2090, 0x2094, 1},
+ {0x2102, 0x2107, 5},
+ {0x210a, 0x2113, 1},
+ {0x2115, 0x2119, 4},
+ {0x211a, 0x211d, 1},
+ {0x2124, 0x212a, 2},
+ {0x212b, 0x212d, 1},
+ {0x212f, 0x2139, 1},
+ {0x213c, 0x213f, 1},
+ {0x2145, 0x2149, 1},
+ {0x214e, 0x2183, 53},
+ {0x2184, 0x2c00, 2684},
+ {0x2c01, 0x2c2e, 1},
+ {0x2c30, 0x2c5e, 1},
+ {0x2c60, 0x2ce4, 1},
+ {0x2ceb, 0x2cee, 1},
+ {0x2d00, 0x2d25, 1},
+ {0x2d30, 0x2d65, 1},
+ {0x2d6f, 0x2d80, 17},
+ {0x2d81, 0x2d96, 1},
+ {0x2da0, 0x2da6, 1},
+ {0x2da8, 0x2dae, 1},
+ {0x2db0, 0x2db6, 1},
+ {0x2db8, 0x2dbe, 1},
+ {0x2dc0, 0x2dc6, 1},
+ {0x2dc8, 0x2dce, 1},
+ {0x2dd0, 0x2dd6, 1},
+ {0x2dd8, 0x2dde, 1},
+ {0x2e2f, 0x3005, 470},
+ {0x3006, 0x3031, 43},
+ {0x3032, 0x3035, 1},
+ {0x303b, 0x303c, 1},
+ {0x3041, 0x3096, 1},
+ {0x309d, 0x309f, 1},
+ {0x30a1, 0x30fa, 1},
+ {0x30fc, 0x30ff, 1},
+ {0x3105, 0x312d, 1},
+ {0x3131, 0x318e, 1},
+ {0x31a0, 0x31b7, 1},
+ {0x31f0, 0x31ff, 1},
+ {0x3400, 0x4db5, 1},
+ {0x4e00, 0x9fcb, 1},
+ {0xa000, 0xa48c, 1},
+ {0xa4d0, 0xa4fd, 1},
+ {0xa500, 0xa60c, 1},
+ {0xa610, 0xa61f, 1},
+ {0xa62a, 0xa62b, 1},
+ {0xa640, 0xa65f, 1},
+ {0xa662, 0xa66e, 1},
+ {0xa67f, 0xa697, 1},
+ {0xa6a0, 0xa6e5, 1},
+ {0xa717, 0xa71f, 1},
+ {0xa722, 0xa788, 1},
+ {0xa78b, 0xa78c, 1},
+ {0xa7fb, 0xa801, 1},
+ {0xa803, 0xa805, 1},
+ {0xa807, 0xa80a, 1},
+ {0xa80c, 0xa822, 1},
+ {0xa840, 0xa873, 1},
+ {0xa882, 0xa8b3, 1},
+ {0xa8f2, 0xa8f7, 1},
+ {0xa8fb, 0xa90a, 15},
+ {0xa90b, 0xa925, 1},
+ {0xa930, 0xa946, 1},
+ {0xa960, 0xa97c, 1},
+ {0xa984, 0xa9b2, 1},
+ {0xa9cf, 0xaa00, 49},
+ {0xaa01, 0xaa28, 1},
+ {0xaa40, 0xaa42, 1},
+ {0xaa44, 0xaa4b, 1},
+ {0xaa60, 0xaa76, 1},
+ {0xaa7a, 0xaa80, 6},
+ {0xaa81, 0xaaaf, 1},
+ {0xaab1, 0xaab5, 4},
+ {0xaab6, 0xaab9, 3},
+ {0xaaba, 0xaabd, 1},
+ {0xaac0, 0xaac2, 2},
+ {0xaadb, 0xaadd, 1},
+ {0xabc0, 0xabe2, 1},
+ {0xac00, 0xd7a3, 1},
+ {0xd7b0, 0xd7c6, 1},
+ {0xd7cb, 0xd7fb, 1},
+ {0xf900, 0xfa2d, 1},
+ {0xfa30, 0xfa6d, 1},
+ {0xfa70, 0xfad9, 1},
+ {0xfb00, 0xfb06, 1},
+ {0xfb13, 0xfb17, 1},
+ {0xfb1d, 0xfb1f, 2},
+ {0xfb20, 0xfb28, 1},
+ {0xfb2a, 0xfb36, 1},
+ {0xfb38, 0xfb3c, 1},
+ {0xfb3e, 0xfb40, 2},
+ {0xfb41, 0xfb43, 2},
+ {0xfb44, 0xfb46, 2},
+ {0xfb47, 0xfbb1, 1},
+ {0xfbd3, 0xfd3d, 1},
+ {0xfd50, 0xfd8f, 1},
+ {0xfd92, 0xfdc7, 1},
+ {0xfdf0, 0xfdfb, 1},
+ {0xfe70, 0xfe74, 1},
+ {0xfe76, 0xfefc, 1},
+ {0xff21, 0xff3a, 1},
+ {0xff41, 0xff5a, 1},
+ {0xff66, 0xffbe, 1},
+ {0xffc2, 0xffc7, 1},
+ {0xffca, 0xffcf, 1},
+ {0xffd2, 0xffd7, 1},
+ {0xffda, 0xffdc, 1},
+ {0x10000, 0x1000b, 1},
+ {0x1000d, 0x10026, 1},
+ {0x10028, 0x1003a, 1},
+ {0x1003c, 0x1003d, 1},
+ {0x1003f, 0x1004d, 1},
+ {0x10050, 0x1005d, 1},
+ {0x10080, 0x100fa, 1},
+ {0x10280, 0x1029c, 1},
+ {0x102a0, 0x102d0, 1},
+ {0x10300, 0x1031e, 1},
+ {0x10330, 0x10340, 1},
+ {0x10342, 0x10349, 1},
+ {0x10380, 0x1039d, 1},
+ {0x103a0, 0x103c3, 1},
+ {0x103c8, 0x103cf, 1},
+ {0x10400, 0x1049d, 1},
+ {0x10800, 0x10805, 1},
+ {0x10808, 0x1080a, 2},
+ {0x1080b, 0x10835, 1},
+ {0x10837, 0x10838, 1},
+ {0x1083c, 0x1083f, 3},
+ {0x10840, 0x10855, 1},
+ {0x10900, 0x10915, 1},
+ {0x10920, 0x10939, 1},
+ {0x10a00, 0x10a10, 16},
+ {0x10a11, 0x10a13, 1},
+ {0x10a15, 0x10a17, 1},
+ {0x10a19, 0x10a33, 1},
+ {0x10a60, 0x10a7c, 1},
+ {0x10b00, 0x10b35, 1},
+ {0x10b40, 0x10b55, 1},
+ {0x10b60, 0x10b72, 1},
+ {0x10c00, 0x10c48, 1},
+ {0x11083, 0x110af, 1},
+ {0x12000, 0x1236e, 1},
+ {0x13000, 0x1342e, 1},
+ {0x1d400, 0x1d454, 1},
+ {0x1d456, 0x1d49c, 1},
+ {0x1d49e, 0x1d49f, 1},
+ {0x1d4a2, 0x1d4a5, 3},
+ {0x1d4a6, 0x1d4a9, 3},
+ {0x1d4aa, 0x1d4ac, 1},
+ {0x1d4ae, 0x1d4b9, 1},
+ {0x1d4bb, 0x1d4bd, 2},
+ {0x1d4be, 0x1d4c3, 1},
+ {0x1d4c5, 0x1d505, 1},
+ {0x1d507, 0x1d50a, 1},
+ {0x1d50d, 0x1d514, 1},
+ {0x1d516, 0x1d51c, 1},
+ {0x1d51e, 0x1d539, 1},
+ {0x1d53b, 0x1d53e, 1},
+ {0x1d540, 0x1d544, 1},
+ {0x1d546, 0x1d54a, 4},
+ {0x1d54b, 0x1d550, 1},
+ {0x1d552, 0x1d6a5, 1},
+ {0x1d6a8, 0x1d6c0, 1},
+ {0x1d6c2, 0x1d6da, 1},
+ {0x1d6dc, 0x1d6fa, 1},
+ {0x1d6fc, 0x1d714, 1},
+ {0x1d716, 0x1d734, 1},
+ {0x1d736, 0x1d74e, 1},
+ {0x1d750, 0x1d76e, 1},
+ {0x1d770, 0x1d788, 1},
+ {0x1d78a, 0x1d7a8, 1},
+ {0x1d7aa, 0x1d7c2, 1},
+ {0x1d7c4, 0x1d7cb, 1},
+ {0x20000, 0x2a6d6, 1},
+ {0x2a700, 0x2b734, 1},
+ {0x2f800, 0x2fa1d, 1},
}
var _Zp = []Range{
- Range{0x2029, 0x2029, 1},
+ {0x2029, 0x2029, 1},
}
var _Zs = []Range{
- Range{0x0020, 0x00a0, 128},
- Range{0x1680, 0x180e, 398},
- Range{0x2000, 0x200a, 1},
- Range{0x202f, 0x205f, 48},
- Range{0x3000, 0x3000, 1},
+ {0x0020, 0x00a0, 128},
+ {0x1680, 0x180e, 398},
+ {0x2000, 0x200a, 1},
+ {0x202f, 0x205f, 48},
+ {0x3000, 0x3000, 1},
}
var _Cs = []Range{
- Range{0xd800, 0xdfff, 1},
+ {0xd800, 0xdfff, 1},
}
var _Co = []Range{
- Range{0xe000, 0xf8ff, 1},
- Range{0xf0000, 0xffffd, 1},
- Range{0x100000, 0x10fffd, 1},
+ {0xe000, 0xf8ff, 1},
+ {0xf0000, 0xffffd, 1},
+ {0x100000, 0x10fffd, 1},
}
var _Cf = []Range{
- Range{0x00ad, 0x0600, 1363},
- Range{0x0601, 0x0603, 1},
- Range{0x06dd, 0x070f, 50},
- Range{0x17b4, 0x17b5, 1},
- Range{0x200b, 0x200f, 1},
- Range{0x202a, 0x202e, 1},
- Range{0x2060, 0x2064, 1},
- Range{0x206a, 0x206f, 1},
- Range{0xfeff, 0xfff9, 250},
- Range{0xfffa, 0xfffb, 1},
- Range{0x110bd, 0x1d173, 49334},
- Range{0x1d174, 0x1d17a, 1},
- Range{0xe0001, 0xe0020, 31},
- Range{0xe0021, 0xe007f, 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},
+ {0xfeff, 0xfff9, 250},
+ {0xfffa, 0xfffb, 1},
+ {0x110bd, 0x1d173, 49334},
+ {0x1d174, 0x1d17a, 1},
+ {0xe0001, 0xe0020, 31},
+ {0xe0021, 0xe007f, 1},
}
var _Cc = []Range{
- Range{0x0001, 0x001f, 1},
- Range{0x007f, 0x009f, 1},
+ {0x0001, 0x001f, 1},
+ {0x007f, 0x009f, 1},
}
var _Po = []Range{
- Range{0x0021, 0x0023, 1},
- Range{0x0025, 0x0027, 1},
- Range{0x002a, 0x002e, 2},
- Range{0x002f, 0x003a, 11},
- Range{0x003b, 0x003f, 4},
- Range{0x0040, 0x005c, 28},
- Range{0x00a1, 0x00b7, 22},
- Range{0x00bf, 0x037e, 703},
- Range{0x0387, 0x055a, 467},
- Range{0x055b, 0x055f, 1},
- Range{0x0589, 0x05c0, 55},
- Range{0x05c3, 0x05c6, 3},
- Range{0x05f3, 0x05f4, 1},
- Range{0x0609, 0x060a, 1},
- Range{0x060c, 0x060d, 1},
- Range{0x061b, 0x061e, 3},
- Range{0x061f, 0x066a, 75},
- Range{0x066b, 0x066d, 1},
- Range{0x06d4, 0x0700, 44},
- Range{0x0701, 0x070d, 1},
- Range{0x07f7, 0x07f9, 1},
- Range{0x0830, 0x083e, 1},
- Range{0x0964, 0x0965, 1},
- Range{0x0970, 0x0df4, 1156},
- Range{0x0e4f, 0x0e5a, 11},
- Range{0x0e5b, 0x0f04, 169},
- Range{0x0f05, 0x0f12, 1},
- Range{0x0f85, 0x0fd0, 75},
- Range{0x0fd1, 0x0fd4, 1},
- Range{0x104a, 0x104f, 1},
- Range{0x10fb, 0x1361, 614},
- Range{0x1362, 0x1368, 1},
- Range{0x166d, 0x166e, 1},
- Range{0x16eb, 0x16ed, 1},
- Range{0x1735, 0x1736, 1},
- Range{0x17d4, 0x17d6, 1},
- Range{0x17d8, 0x17da, 1},
- Range{0x1800, 0x1805, 1},
- Range{0x1807, 0x180a, 1},
- Range{0x1944, 0x1945, 1},
- Range{0x19de, 0x19df, 1},
- Range{0x1a1e, 0x1a1f, 1},
- Range{0x1aa0, 0x1aa6, 1},
- Range{0x1aa8, 0x1aad, 1},
- Range{0x1b5a, 0x1b60, 1},
- Range{0x1c3b, 0x1c3f, 1},
- Range{0x1c7e, 0x1c7f, 1},
- Range{0x1cd3, 0x2016, 835},
- Range{0x2017, 0x2020, 9},
- Range{0x2021, 0x2027, 1},
- Range{0x2030, 0x2038, 1},
- Range{0x203b, 0x203e, 1},
- Range{0x2041, 0x2043, 1},
- Range{0x2047, 0x2051, 1},
- Range{0x2053, 0x2055, 2},
- Range{0x2056, 0x205e, 1},
- Range{0x2cf9, 0x2cfc, 1},
- Range{0x2cfe, 0x2cff, 1},
- Range{0x2e00, 0x2e01, 1},
- Range{0x2e06, 0x2e08, 1},
- Range{0x2e0b, 0x2e0e, 3},
- Range{0x2e0f, 0x2e16, 1},
- Range{0x2e18, 0x2e19, 1},
- Range{0x2e1b, 0x2e1e, 3},
- Range{0x2e1f, 0x2e2a, 11},
- Range{0x2e2b, 0x2e2e, 1},
- Range{0x2e30, 0x2e31, 1},
- Range{0x3001, 0x3003, 1},
- Range{0x303d, 0x30fb, 190},
- Range{0xa4fe, 0xa4ff, 1},
- Range{0xa60d, 0xa60f, 1},
- Range{0xa673, 0xa67e, 11},
- Range{0xa6f2, 0xa6f7, 1},
- Range{0xa874, 0xa877, 1},
- Range{0xa8ce, 0xa8cf, 1},
- Range{0xa8f8, 0xa8fa, 1},
- Range{0xa92e, 0xa92f, 1},
- Range{0xa95f, 0xa9c1, 98},
- Range{0xa9c2, 0xa9cd, 1},
- Range{0xa9de, 0xa9df, 1},
- Range{0xaa5c, 0xaa5f, 1},
- Range{0xaade, 0xaadf, 1},
- Range{0xabeb, 0xfe10, 21029},
- Range{0xfe11, 0xfe16, 1},
- Range{0xfe19, 0xfe30, 23},
- Range{0xfe45, 0xfe46, 1},
- Range{0xfe49, 0xfe4c, 1},
- Range{0xfe50, 0xfe52, 1},
- Range{0xfe54, 0xfe57, 1},
- Range{0xfe5f, 0xfe61, 1},
- Range{0xfe68, 0xfe6a, 2},
- Range{0xfe6b, 0xff01, 150},
- Range{0xff02, 0xff03, 1},
- Range{0xff05, 0xff07, 1},
- Range{0xff0a, 0xff0e, 2},
- Range{0xff0f, 0xff1a, 11},
- Range{0xff1b, 0xff1f, 4},
- Range{0xff20, 0xff3c, 28},
- Range{0xff61, 0xff64, 3},
- Range{0xff65, 0x10100, 411},
- Range{0x10101, 0x1039f, 670},
- Range{0x103d0, 0x10857, 1159},
- Range{0x1091f, 0x1093f, 32},
- Range{0x10a50, 0x10a58, 1},
- Range{0x10a7f, 0x10b39, 186},
- Range{0x10b3a, 0x10b3f, 1},
- Range{0x110bb, 0x110bc, 1},
- Range{0x110be, 0x110c1, 1},
- Range{0x12470, 0x12473, 1},
+ {0x0021, 0x0023, 1},
+ {0x0025, 0x0027, 1},
+ {0x002a, 0x002e, 2},
+ {0x002f, 0x003a, 11},
+ {0x003b, 0x003f, 4},
+ {0x0040, 0x005c, 28},
+ {0x00a1, 0x00b7, 22},
+ {0x00bf, 0x037e, 703},
+ {0x0387, 0x055a, 467},
+ {0x055b, 0x055f, 1},
+ {0x0589, 0x05c0, 55},
+ {0x05c3, 0x05c6, 3},
+ {0x05f3, 0x05f4, 1},
+ {0x0609, 0x060a, 1},
+ {0x060c, 0x060d, 1},
+ {0x061b, 0x061e, 3},
+ {0x061f, 0x066a, 75},
+ {0x066b, 0x066d, 1},
+ {0x06d4, 0x0700, 44},
+ {0x0701, 0x070d, 1},
+ {0x07f7, 0x07f9, 1},
+ {0x0830, 0x083e, 1},
+ {0x0964, 0x0965, 1},
+ {0x0970, 0x0df4, 1156},
+ {0x0e4f, 0x0e5a, 11},
+ {0x0e5b, 0x0f04, 169},
+ {0x0f05, 0x0f12, 1},
+ {0x0f85, 0x0fd0, 75},
+ {0x0fd1, 0x0fd4, 1},
+ {0x104a, 0x104f, 1},
+ {0x10fb, 0x1361, 614},
+ {0x1362, 0x1368, 1},
+ {0x166d, 0x166e, 1},
+ {0x16eb, 0x16ed, 1},
+ {0x1735, 0x1736, 1},
+ {0x17d4, 0x17d6, 1},
+ {0x17d8, 0x17da, 1},
+ {0x1800, 0x1805, 1},
+ {0x1807, 0x180a, 1},
+ {0x1944, 0x1945, 1},
+ {0x19de, 0x19df, 1},
+ {0x1a1e, 0x1a1f, 1},
+ {0x1aa0, 0x1aa6, 1},
+ {0x1aa8, 0x1aad, 1},
+ {0x1b5a, 0x1b60, 1},
+ {0x1c3b, 0x1c3f, 1},
+ {0x1c7e, 0x1c7f, 1},
+ {0x1cd3, 0x2016, 835},
+ {0x2017, 0x2020, 9},
+ {0x2021, 0x2027, 1},
+ {0x2030, 0x2038, 1},
+ {0x203b, 0x203e, 1},
+ {0x2041, 0x2043, 1},
+ {0x2047, 0x2051, 1},
+ {0x2053, 0x2055, 2},
+ {0x2056, 0x205e, 1},
+ {0x2cf9, 0x2cfc, 1},
+ {0x2cfe, 0x2cff, 1},
+ {0x2e00, 0x2e01, 1},
+ {0x2e06, 0x2e08, 1},
+ {0x2e0b, 0x2e0e, 3},
+ {0x2e0f, 0x2e16, 1},
+ {0x2e18, 0x2e19, 1},
+ {0x2e1b, 0x2e1e, 3},
+ {0x2e1f, 0x2e2a, 11},
+ {0x2e2b, 0x2e2e, 1},
+ {0x2e30, 0x2e31, 1},
+ {0x3001, 0x3003, 1},
+ {0x303d, 0x30fb, 190},
+ {0xa4fe, 0xa4ff, 1},
+ {0xa60d, 0xa60f, 1},
+ {0xa673, 0xa67e, 11},
+ {0xa6f2, 0xa6f7, 1},
+ {0xa874, 0xa877, 1},
+ {0xa8ce, 0xa8cf, 1},
+ {0xa8f8, 0xa8fa, 1},
+ {0xa92e, 0xa92f, 1},
+ {0xa95f, 0xa9c1, 98},
+ {0xa9c2, 0xa9cd, 1},
+ {0xa9de, 0xa9df, 1},
+ {0xaa5c, 0xaa5f, 1},
+ {0xaade, 0xaadf, 1},
+ {0xabeb, 0xfe10, 21029},
+ {0xfe11, 0xfe16, 1},
+ {0xfe19, 0xfe30, 23},
+ {0xfe45, 0xfe46, 1},
+ {0xfe49, 0xfe4c, 1},
+ {0xfe50, 0xfe52, 1},
+ {0xfe54, 0xfe57, 1},
+ {0xfe5f, 0xfe61, 1},
+ {0xfe68, 0xfe6a, 2},
+ {0xfe6b, 0xff01, 150},
+ {0xff02, 0xff03, 1},
+ {0xff05, 0xff07, 1},
+ {0xff0a, 0xff0e, 2},
+ {0xff0f, 0xff1a, 11},
+ {0xff1b, 0xff1f, 4},
+ {0xff20, 0xff3c, 28},
+ {0xff61, 0xff64, 3},
+ {0xff65, 0x10100, 411},
+ {0x10101, 0x1039f, 670},
+ {0x103d0, 0x10857, 1159},
+ {0x1091f, 0x1093f, 32},
+ {0x10a50, 0x10a58, 1},
+ {0x10a7f, 0x10b39, 186},
+ {0x10b3a, 0x10b3f, 1},
+ {0x110bb, 0x110bc, 1},
+ {0x110be, 0x110c1, 1},
+ {0x12470, 0x12473, 1},
}
var _Pi = []Range{
- Range{0x00ab, 0x2018, 8045},
- Range{0x201b, 0x201c, 1},
- Range{0x201f, 0x2039, 26},
- Range{0x2e02, 0x2e04, 2},
- Range{0x2e09, 0x2e0c, 3},
- Range{0x2e1c, 0x2e20, 4},
+ {0x00ab, 0x2018, 8045},
+ {0x201b, 0x201c, 1},
+ {0x201f, 0x2039, 26},
+ {0x2e02, 0x2e04, 2},
+ {0x2e09, 0x2e0c, 3},
+ {0x2e1c, 0x2e20, 4},
}
var _Pf = []Range{
- Range{0x00bb, 0x2019, 8030},
- Range{0x201d, 0x203a, 29},
- Range{0x2e03, 0x2e05, 2},
- Range{0x2e0a, 0x2e0d, 3},
- Range{0x2e1d, 0x2e21, 4},
+ {0x00bb, 0x2019, 8030},
+ {0x201d, 0x203a, 29},
+ {0x2e03, 0x2e05, 2},
+ {0x2e0a, 0x2e0d, 3},
+ {0x2e1d, 0x2e21, 4},
}
var _Pe = []Range{
- Range{0x0029, 0x005d, 52},
- Range{0x007d, 0x0f3b, 3774},
- Range{0x0f3d, 0x169c, 1887},
- Range{0x2046, 0x207e, 56},
- Range{0x208e, 0x232a, 668},
- Range{0x2769, 0x2775, 2},
- Range{0x27c6, 0x27e7, 33},
- Range{0x27e9, 0x27ef, 2},
- Range{0x2984, 0x2998, 2},
- Range{0x29d9, 0x29db, 2},
- Range{0x29fd, 0x2e23, 1062},
- Range{0x2e25, 0x2e29, 2},
- Range{0x3009, 0x3011, 2},
- Range{0x3015, 0x301b, 2},
- Range{0x301e, 0x301f, 1},
- Range{0xfd3f, 0xfe18, 217},
- Range{0xfe36, 0xfe44, 2},
- Range{0xfe48, 0xfe5a, 18},
- Range{0xfe5c, 0xfe5e, 2},
- Range{0xff09, 0xff3d, 52},
- Range{0xff5d, 0xff63, 3},
+ {0x0029, 0x005d, 52},
+ {0x007d, 0x0f3b, 3774},
+ {0x0f3d, 0x169c, 1887},
+ {0x2046, 0x207e, 56},
+ {0x208e, 0x232a, 668},
+ {0x2769, 0x2775, 2},
+ {0x27c6, 0x27e7, 33},
+ {0x27e9, 0x27ef, 2},
+ {0x2984, 0x2998, 2},
+ {0x29d9, 0x29db, 2},
+ {0x29fd, 0x2e23, 1062},
+ {0x2e25, 0x2e29, 2},
+ {0x3009, 0x3011, 2},
+ {0x3015, 0x301b, 2},
+ {0x301e, 0x301f, 1},
+ {0xfd3f, 0xfe18, 217},
+ {0xfe36, 0xfe44, 2},
+ {0xfe48, 0xfe5a, 18},
+ {0xfe5c, 0xfe5e, 2},
+ {0xff09, 0xff3d, 52},
+ {0xff5d, 0xff63, 3},
}
var _Pd = []Range{
- Range{0x002d, 0x058a, 1373},
- Range{0x05be, 0x1400, 3650},
- Range{0x1806, 0x2010, 2058},
- Range{0x2011, 0x2015, 1},
- Range{0x2e17, 0x2e1a, 3},
- Range{0x301c, 0x3030, 20},
- Range{0x30a0, 0xfe31, 52625},
- Range{0xfe32, 0xfe58, 38},
- Range{0xfe63, 0xff0d, 170},
+ {0x002d, 0x058a, 1373},
+ {0x05be, 0x1400, 3650},
+ {0x1806, 0x2010, 2058},
+ {0x2011, 0x2015, 1},
+ {0x2e17, 0x2e1a, 3},
+ {0x301c, 0x3030, 20},
+ {0x30a0, 0xfe31, 52625},
+ {0xfe32, 0xfe58, 38},
+ {0xfe63, 0xff0d, 170},
}
var _Pc = []Range{
- Range{0x005f, 0x203f, 8160},
- Range{0x2040, 0x2054, 20},
- Range{0xfe33, 0xfe34, 1},
- Range{0xfe4d, 0xfe4f, 1},
- Range{0xff3f, 0xff3f, 1},
+ {0x005f, 0x203f, 8160},
+ {0x2040, 0x2054, 20},
+ {0xfe33, 0xfe34, 1},
+ {0xfe4d, 0xfe4f, 1},
+ {0xff3f, 0xff3f, 1},
}
var _Ps = []Range{
- Range{0x0028, 0x005b, 51},
- Range{0x007b, 0x0f3a, 3775},
- Range{0x0f3c, 0x169b, 1887},
- Range{0x201a, 0x201e, 4},
- Range{0x2045, 0x207d, 56},
- Range{0x208d, 0x2329, 668},
- Range{0x2768, 0x2774, 2},
- Range{0x27c5, 0x27e6, 33},
- Range{0x27e8, 0x27ee, 2},
- Range{0x2983, 0x2997, 2},
- Range{0x29d8, 0x29da, 2},
- Range{0x29fc, 0x2e22, 1062},
- Range{0x2e24, 0x2e28, 2},
- Range{0x3008, 0x3010, 2},
- Range{0x3014, 0x301a, 2},
- Range{0x301d, 0xfd3e, 52513},
- Range{0xfe17, 0xfe35, 30},
- Range{0xfe37, 0xfe43, 2},
- Range{0xfe47, 0xfe59, 18},
- Range{0xfe5b, 0xfe5d, 2},
- Range{0xff08, 0xff3b, 51},
- Range{0xff5b, 0xff5f, 4},
- Range{0xff62, 0xff62, 1},
+ {0x0028, 0x005b, 51},
+ {0x007b, 0x0f3a, 3775},
+ {0x0f3c, 0x169b, 1887},
+ {0x201a, 0x201e, 4},
+ {0x2045, 0x207d, 56},
+ {0x208d, 0x2329, 668},
+ {0x2768, 0x2774, 2},
+ {0x27c5, 0x27e6, 33},
+ {0x27e8, 0x27ee, 2},
+ {0x2983, 0x2997, 2},
+ {0x29d8, 0x29da, 2},
+ {0x29fc, 0x2e22, 1062},
+ {0x2e24, 0x2e28, 2},
+ {0x3008, 0x3010, 2},
+ {0x3014, 0x301a, 2},
+ {0x301d, 0xfd3e, 52513},
+ {0xfe17, 0xfe35, 30},
+ {0xfe37, 0xfe43, 2},
+ {0xfe47, 0xfe59, 18},
+ {0xfe5b, 0xfe5d, 2},
+ {0xff08, 0xff3b, 51},
+ {0xff5b, 0xff5f, 4},
+ {0xff62, 0xff62, 1},
}
var _Nd = []Range{
- Range{0x0030, 0x0039, 1},
- Range{0x0660, 0x0669, 1},
- Range{0x06f0, 0x06f9, 1},
- Range{0x07c0, 0x07c9, 1},
- Range{0x0966, 0x096f, 1},
- Range{0x09e6, 0x09ef, 1},
- Range{0x0a66, 0x0a6f, 1},
- Range{0x0ae6, 0x0aef, 1},
- Range{0x0b66, 0x0b6f, 1},
- Range{0x0be6, 0x0bef, 1},
- Range{0x0c66, 0x0c6f, 1},
- Range{0x0ce6, 0x0cef, 1},
- Range{0x0d66, 0x0d6f, 1},
- Range{0x0e50, 0x0e59, 1},
- Range{0x0ed0, 0x0ed9, 1},
- Range{0x0f20, 0x0f29, 1},
- Range{0x1040, 0x1049, 1},
- Range{0x1090, 0x1099, 1},
- Range{0x17e0, 0x17e9, 1},
- Range{0x1810, 0x1819, 1},
- Range{0x1946, 0x194f, 1},
- Range{0x19d0, 0x19da, 1},
- Range{0x1a80, 0x1a89, 1},
- Range{0x1a90, 0x1a99, 1},
- Range{0x1b50, 0x1b59, 1},
- Range{0x1bb0, 0x1bb9, 1},
- Range{0x1c40, 0x1c49, 1},
- Range{0x1c50, 0x1c59, 1},
- Range{0xa620, 0xa629, 1},
- Range{0xa8d0, 0xa8d9, 1},
- Range{0xa900, 0xa909, 1},
- Range{0xa9d0, 0xa9d9, 1},
- Range{0xaa50, 0xaa59, 1},
- Range{0xabf0, 0xabf9, 1},
- Range{0xff10, 0xff19, 1},
- Range{0x104a0, 0x104a9, 1},
- Range{0x1d7ce, 0x1d7ff, 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, 0x19da, 1},
+ {0x1a80, 0x1a89, 1},
+ {0x1a90, 0x1a99, 1},
+ {0x1b50, 0x1b59, 1},
+ {0x1bb0, 0x1bb9, 1},
+ {0x1c40, 0x1c49, 1},
+ {0x1c50, 0x1c59, 1},
+ {0xa620, 0xa629, 1},
+ {0xa8d0, 0xa8d9, 1},
+ {0xa900, 0xa909, 1},
+ {0xa9d0, 0xa9d9, 1},
+ {0xaa50, 0xaa59, 1},
+ {0xabf0, 0xabf9, 1},
+ {0xff10, 0xff19, 1},
+ {0x104a0, 0x104a9, 1},
+ {0x1d7ce, 0x1d7ff, 1},
}
var _Nl = []Range{
- Range{0x16ee, 0x16f0, 1},
- Range{0x2160, 0x2182, 1},
- Range{0x2185, 0x2188, 1},
- Range{0x3007, 0x3021, 26},
- Range{0x3022, 0x3029, 1},
- Range{0x3038, 0x303a, 1},
- Range{0xa6e6, 0xa6ef, 1},
- Range{0x10140, 0x10174, 1},
- Range{0x10341, 0x1034a, 9},
- Range{0x103d1, 0x103d5, 1},
- Range{0x12400, 0x12462, 1},
+ {0x16ee, 0x16f0, 1},
+ {0x2160, 0x2182, 1},
+ {0x2185, 0x2188, 1},
+ {0x3007, 0x3021, 26},
+ {0x3022, 0x3029, 1},
+ {0x3038, 0x303a, 1},
+ {0xa6e6, 0xa6ef, 1},
+ {0x10140, 0x10174, 1},
+ {0x10341, 0x1034a, 9},
+ {0x103d1, 0x103d5, 1},
+ {0x12400, 0x12462, 1},
}
var _No = []Range{
- Range{0x00b2, 0x00b3, 1},
- Range{0x00b9, 0x00bc, 3},
- Range{0x00bd, 0x00be, 1},
- Range{0x09f4, 0x09f9, 1},
- Range{0x0bf0, 0x0bf2, 1},
- Range{0x0c78, 0x0c7e, 1},
- Range{0x0d70, 0x0d75, 1},
- Range{0x0f2a, 0x0f33, 1},
- Range{0x1369, 0x137c, 1},
- Range{0x17f0, 0x17f9, 1},
- Range{0x2070, 0x2074, 4},
- Range{0x2075, 0x2079, 1},
- Range{0x2080, 0x2089, 1},
- Range{0x2150, 0x215f, 1},
- Range{0x2189, 0x2460, 727},
- Range{0x2461, 0x249b, 1},
- Range{0x24ea, 0x24ff, 1},
- Range{0x2776, 0x2793, 1},
- Range{0x2cfd, 0x3192, 1173},
- Range{0x3193, 0x3195, 1},
- Range{0x3220, 0x3229, 1},
- Range{0x3251, 0x325f, 1},
- Range{0x3280, 0x3289, 1},
- Range{0x32b1, 0x32bf, 1},
- Range{0xa830, 0xa835, 1},
- Range{0x10107, 0x10133, 1},
- Range{0x10175, 0x10178, 1},
- Range{0x1018a, 0x10320, 406},
- Range{0x10321, 0x10323, 1},
- Range{0x10858, 0x1085f, 1},
- Range{0x10916, 0x1091b, 1},
- Range{0x10a40, 0x10a47, 1},
- Range{0x10a7d, 0x10a7e, 1},
- Range{0x10b58, 0x10b5f, 1},
- Range{0x10b78, 0x10b7f, 1},
- Range{0x10e60, 0x10e7e, 1},
- Range{0x1d360, 0x1d371, 1},
- Range{0x1f100, 0x1f10a, 1},
+ {0x00b2, 0x00b3, 1},
+ {0x00b9, 0x00bc, 3},
+ {0x00bd, 0x00be, 1},
+ {0x09f4, 0x09f9, 1},
+ {0x0bf0, 0x0bf2, 1},
+ {0x0c78, 0x0c7e, 1},
+ {0x0d70, 0x0d75, 1},
+ {0x0f2a, 0x0f33, 1},
+ {0x1369, 0x137c, 1},
+ {0x17f0, 0x17f9, 1},
+ {0x2070, 0x2074, 4},
+ {0x2075, 0x2079, 1},
+ {0x2080, 0x2089, 1},
+ {0x2150, 0x215f, 1},
+ {0x2189, 0x2460, 727},
+ {0x2461, 0x249b, 1},
+ {0x24ea, 0x24ff, 1},
+ {0x2776, 0x2793, 1},
+ {0x2cfd, 0x3192, 1173},
+ {0x3193, 0x3195, 1},
+ {0x3220, 0x3229, 1},
+ {0x3251, 0x325f, 1},
+ {0x3280, 0x3289, 1},
+ {0x32b1, 0x32bf, 1},
+ {0xa830, 0xa835, 1},
+ {0x10107, 0x10133, 1},
+ {0x10175, 0x10178, 1},
+ {0x1018a, 0x10320, 406},
+ {0x10321, 0x10323, 1},
+ {0x10858, 0x1085f, 1},
+ {0x10916, 0x1091b, 1},
+ {0x10a40, 0x10a47, 1},
+ {0x10a7d, 0x10a7e, 1},
+ {0x10b58, 0x10b5f, 1},
+ {0x10b78, 0x10b7f, 1},
+ {0x10e60, 0x10e7e, 1},
+ {0x1d360, 0x1d371, 1},
+ {0x1f100, 0x1f10a, 1},
}
var _So = []Range{
- Range{0x00a6, 0x00a7, 1},
- Range{0x00a9, 0x00ae, 5},
- Range{0x00b0, 0x00b6, 6},
- Range{0x0482, 0x060e, 396},
- Range{0x060f, 0x06e9, 218},
- Range{0x06fd, 0x06fe, 1},
- Range{0x07f6, 0x09fa, 516},
- Range{0x0b70, 0x0bf3, 131},
- Range{0x0bf4, 0x0bf8, 1},
- Range{0x0bfa, 0x0c7f, 133},
- Range{0x0cf1, 0x0cf2, 1},
- Range{0x0d79, 0x0f01, 392},
- Range{0x0f02, 0x0f03, 1},
- Range{0x0f13, 0x0f17, 1},
- Range{0x0f1a, 0x0f1f, 1},
- Range{0x0f34, 0x0f38, 2},
- Range{0x0fbe, 0x0fc5, 1},
- Range{0x0fc7, 0x0fcc, 1},
- Range{0x0fce, 0x0fcf, 1},
- Range{0x0fd5, 0x0fd8, 1},
- Range{0x109e, 0x109f, 1},
- Range{0x1360, 0x1390, 48},
- Range{0x1391, 0x1399, 1},
- Range{0x1940, 0x19e0, 160},
- Range{0x19e1, 0x19ff, 1},
- Range{0x1b61, 0x1b6a, 1},
- Range{0x1b74, 0x1b7c, 1},
- Range{0x2100, 0x2101, 1},
- Range{0x2103, 0x2106, 1},
- Range{0x2108, 0x2109, 1},
- Range{0x2114, 0x2116, 2},
- Range{0x2117, 0x2118, 1},
- Range{0x211e, 0x2123, 1},
- Range{0x2125, 0x2129, 2},
- Range{0x212e, 0x213a, 12},
- Range{0x213b, 0x214a, 15},
- Range{0x214c, 0x214d, 1},
- Range{0x214f, 0x2195, 70},
- Range{0x2196, 0x2199, 1},
- Range{0x219c, 0x219f, 1},
- Range{0x21a1, 0x21a2, 1},
- Range{0x21a4, 0x21a5, 1},
- Range{0x21a7, 0x21ad, 1},
- Range{0x21af, 0x21cd, 1},
- Range{0x21d0, 0x21d1, 1},
- Range{0x21d3, 0x21d5, 2},
- Range{0x21d6, 0x21f3, 1},
- Range{0x2300, 0x2307, 1},
- Range{0x230c, 0x231f, 1},
- Range{0x2322, 0x2328, 1},
- Range{0x232b, 0x237b, 1},
- Range{0x237d, 0x239a, 1},
- Range{0x23b4, 0x23db, 1},
- Range{0x23e2, 0x23e8, 1},
- Range{0x2400, 0x2426, 1},
- Range{0x2440, 0x244a, 1},
- Range{0x249c, 0x24e9, 1},
- Range{0x2500, 0x25b6, 1},
- Range{0x25b8, 0x25c0, 1},
- Range{0x25c2, 0x25f7, 1},
- Range{0x2600, 0x266e, 1},
- Range{0x2670, 0x26cd, 1},
- Range{0x26cf, 0x26e1, 1},
- Range{0x26e3, 0x26e8, 5},
- Range{0x26e9, 0x26ff, 1},
- Range{0x2701, 0x2704, 1},
- Range{0x2706, 0x2709, 1},
- Range{0x270c, 0x2727, 1},
- Range{0x2729, 0x274b, 1},
- Range{0x274d, 0x274f, 2},
- Range{0x2750, 0x2752, 1},
- Range{0x2756, 0x275e, 1},
- Range{0x2761, 0x2767, 1},
- Range{0x2794, 0x2798, 4},
- Range{0x2799, 0x27af, 1},
- Range{0x27b1, 0x27be, 1},
- Range{0x2800, 0x28ff, 1},
- Range{0x2b00, 0x2b2f, 1},
- Range{0x2b45, 0x2b46, 1},
- Range{0x2b50, 0x2b59, 1},
- Range{0x2ce5, 0x2cea, 1},
- Range{0x2e80, 0x2e99, 1},
- Range{0x2e9b, 0x2ef3, 1},
- Range{0x2f00, 0x2fd5, 1},
- Range{0x2ff0, 0x2ffb, 1},
- Range{0x3004, 0x3012, 14},
- Range{0x3013, 0x3020, 13},
- Range{0x3036, 0x3037, 1},
- Range{0x303e, 0x303f, 1},
- Range{0x3190, 0x3191, 1},
- Range{0x3196, 0x319f, 1},
- Range{0x31c0, 0x31e3, 1},
- Range{0x3200, 0x321e, 1},
- Range{0x322a, 0x3250, 1},
- Range{0x3260, 0x327f, 1},
- Range{0x328a, 0x32b0, 1},
- Range{0x32c0, 0x32fe, 1},
- Range{0x3300, 0x33ff, 1},
- Range{0x4dc0, 0x4dff, 1},
- Range{0xa490, 0xa4c6, 1},
- Range{0xa828, 0xa82b, 1},
- Range{0xa836, 0xa837, 1},
- Range{0xa839, 0xaa77, 574},
- Range{0xaa78, 0xaa79, 1},
- Range{0xfdfd, 0xffe4, 487},
- Range{0xffe8, 0xffed, 5},
- Range{0xffee, 0xfffc, 14},
- Range{0xfffd, 0x10102, 261},
- Range{0x10137, 0x1013f, 1},
- Range{0x10179, 0x10189, 1},
- Range{0x10190, 0x1019b, 1},
- Range{0x101d0, 0x101fc, 1},
- Range{0x1d000, 0x1d0f5, 1},
- Range{0x1d100, 0x1d126, 1},
- Range{0x1d129, 0x1d164, 1},
- Range{0x1d16a, 0x1d16c, 1},
- Range{0x1d183, 0x1d184, 1},
- Range{0x1d18c, 0x1d1a9, 1},
- Range{0x1d1ae, 0x1d1dd, 1},
- Range{0x1d200, 0x1d241, 1},
- Range{0x1d245, 0x1d300, 187},
- Range{0x1d301, 0x1d356, 1},
- Range{0x1f000, 0x1f02b, 1},
- Range{0x1f030, 0x1f093, 1},
- Range{0x1f110, 0x1f12e, 1},
- Range{0x1f131, 0x1f13d, 12},
- Range{0x1f13f, 0x1f142, 3},
- Range{0x1f146, 0x1f14a, 4},
- Range{0x1f14b, 0x1f14e, 1},
- Range{0x1f157, 0x1f15f, 8},
- Range{0x1f179, 0x1f17b, 2},
- Range{0x1f17c, 0x1f17f, 3},
- Range{0x1f18a, 0x1f18d, 1},
- Range{0x1f190, 0x1f200, 112},
- Range{0x1f210, 0x1f231, 1},
- Range{0x1f240, 0x1f248, 1},
+ {0x00a6, 0x00a7, 1},
+ {0x00a9, 0x00ae, 5},
+ {0x00b0, 0x00b6, 6},
+ {0x0482, 0x060e, 396},
+ {0x060f, 0x06e9, 218},
+ {0x06fd, 0x06fe, 1},
+ {0x07f6, 0x09fa, 516},
+ {0x0b70, 0x0bf3, 131},
+ {0x0bf4, 0x0bf8, 1},
+ {0x0bfa, 0x0c7f, 133},
+ {0x0cf1, 0x0cf2, 1},
+ {0x0d79, 0x0f01, 392},
+ {0x0f02, 0x0f03, 1},
+ {0x0f13, 0x0f17, 1},
+ {0x0f1a, 0x0f1f, 1},
+ {0x0f34, 0x0f38, 2},
+ {0x0fbe, 0x0fc5, 1},
+ {0x0fc7, 0x0fcc, 1},
+ {0x0fce, 0x0fcf, 1},
+ {0x0fd5, 0x0fd8, 1},
+ {0x109e, 0x109f, 1},
+ {0x1360, 0x1390, 48},
+ {0x1391, 0x1399, 1},
+ {0x1940, 0x19e0, 160},
+ {0x19e1, 0x19ff, 1},
+ {0x1b61, 0x1b6a, 1},
+ {0x1b74, 0x1b7c, 1},
+ {0x2100, 0x2101, 1},
+ {0x2103, 0x2106, 1},
+ {0x2108, 0x2109, 1},
+ {0x2114, 0x2116, 2},
+ {0x2117, 0x2118, 1},
+ {0x211e, 0x2123, 1},
+ {0x2125, 0x2129, 2},
+ {0x212e, 0x213a, 12},
+ {0x213b, 0x214a, 15},
+ {0x214c, 0x214d, 1},
+ {0x214f, 0x2195, 70},
+ {0x2196, 0x2199, 1},
+ {0x219c, 0x219f, 1},
+ {0x21a1, 0x21a2, 1},
+ {0x21a4, 0x21a5, 1},
+ {0x21a7, 0x21ad, 1},
+ {0x21af, 0x21cd, 1},
+ {0x21d0, 0x21d1, 1},
+ {0x21d3, 0x21d5, 2},
+ {0x21d6, 0x21f3, 1},
+ {0x2300, 0x2307, 1},
+ {0x230c, 0x231f, 1},
+ {0x2322, 0x2328, 1},
+ {0x232b, 0x237b, 1},
+ {0x237d, 0x239a, 1},
+ {0x23b4, 0x23db, 1},
+ {0x23e2, 0x23e8, 1},
+ {0x2400, 0x2426, 1},
+ {0x2440, 0x244a, 1},
+ {0x249c, 0x24e9, 1},
+ {0x2500, 0x25b6, 1},
+ {0x25b8, 0x25c0, 1},
+ {0x25c2, 0x25f7, 1},
+ {0x2600, 0x266e, 1},
+ {0x2670, 0x26cd, 1},
+ {0x26cf, 0x26e1, 1},
+ {0x26e3, 0x26e8, 5},
+ {0x26e9, 0x26ff, 1},
+ {0x2701, 0x2704, 1},
+ {0x2706, 0x2709, 1},
+ {0x270c, 0x2727, 1},
+ {0x2729, 0x274b, 1},
+ {0x274d, 0x274f, 2},
+ {0x2750, 0x2752, 1},
+ {0x2756, 0x275e, 1},
+ {0x2761, 0x2767, 1},
+ {0x2794, 0x2798, 4},
+ {0x2799, 0x27af, 1},
+ {0x27b1, 0x27be, 1},
+ {0x2800, 0x28ff, 1},
+ {0x2b00, 0x2b2f, 1},
+ {0x2b45, 0x2b46, 1},
+ {0x2b50, 0x2b59, 1},
+ {0x2ce5, 0x2cea, 1},
+ {0x2e80, 0x2e99, 1},
+ {0x2e9b, 0x2ef3, 1},
+ {0x2f00, 0x2fd5, 1},
+ {0x2ff0, 0x2ffb, 1},
+ {0x3004, 0x3012, 14},
+ {0x3013, 0x3020, 13},
+ {0x3036, 0x3037, 1},
+ {0x303e, 0x303f, 1},
+ {0x3190, 0x3191, 1},
+ {0x3196, 0x319f, 1},
+ {0x31c0, 0x31e3, 1},
+ {0x3200, 0x321e, 1},
+ {0x322a, 0x3250, 1},
+ {0x3260, 0x327f, 1},
+ {0x328a, 0x32b0, 1},
+ {0x32c0, 0x32fe, 1},
+ {0x3300, 0x33ff, 1},
+ {0x4dc0, 0x4dff, 1},
+ {0xa490, 0xa4c6, 1},
+ {0xa828, 0xa82b, 1},
+ {0xa836, 0xa837, 1},
+ {0xa839, 0xaa77, 574},
+ {0xaa78, 0xaa79, 1},
+ {0xfdfd, 0xffe4, 487},
+ {0xffe8, 0xffed, 5},
+ {0xffee, 0xfffc, 14},
+ {0xfffd, 0x10102, 261},
+ {0x10137, 0x1013f, 1},
+ {0x10179, 0x10189, 1},
+ {0x10190, 0x1019b, 1},
+ {0x101d0, 0x101fc, 1},
+ {0x1d000, 0x1d0f5, 1},
+ {0x1d100, 0x1d126, 1},
+ {0x1d129, 0x1d164, 1},
+ {0x1d16a, 0x1d16c, 1},
+ {0x1d183, 0x1d184, 1},
+ {0x1d18c, 0x1d1a9, 1},
+ {0x1d1ae, 0x1d1dd, 1},
+ {0x1d200, 0x1d241, 1},
+ {0x1d245, 0x1d300, 187},
+ {0x1d301, 0x1d356, 1},
+ {0x1f000, 0x1f02b, 1},
+ {0x1f030, 0x1f093, 1},
+ {0x1f110, 0x1f12e, 1},
+ {0x1f131, 0x1f13d, 12},
+ {0x1f13f, 0x1f142, 3},
+ {0x1f146, 0x1f14a, 4},
+ {0x1f14b, 0x1f14e, 1},
+ {0x1f157, 0x1f15f, 8},
+ {0x1f179, 0x1f17b, 2},
+ {0x1f17c, 0x1f17f, 3},
+ {0x1f18a, 0x1f18d, 1},
+ {0x1f190, 0x1f200, 112},
+ {0x1f210, 0x1f231, 1},
+ {0x1f240, 0x1f248, 1},
}
var _Sm = []Range{
- Range{0x002b, 0x003c, 17},
- Range{0x003d, 0x003e, 1},
- Range{0x007c, 0x007e, 2},
- Range{0x00ac, 0x00b1, 5},
- Range{0x00d7, 0x00f7, 32},
- Range{0x03f6, 0x0606, 528},
- Range{0x0607, 0x0608, 1},
- Range{0x2044, 0x2052, 14},
- Range{0x207a, 0x207c, 1},
- Range{0x208a, 0x208c, 1},
- Range{0x2140, 0x2144, 1},
- Range{0x214b, 0x2190, 69},
- Range{0x2191, 0x2194, 1},
- Range{0x219a, 0x219b, 1},
- Range{0x21a0, 0x21a6, 3},
- Range{0x21ae, 0x21ce, 32},
- Range{0x21cf, 0x21d2, 3},
- Range{0x21d4, 0x21f4, 32},
- Range{0x21f5, 0x22ff, 1},
- Range{0x2308, 0x230b, 1},
- Range{0x2320, 0x2321, 1},
- Range{0x237c, 0x239b, 31},
- Range{0x239c, 0x23b3, 1},
- Range{0x23dc, 0x23e1, 1},
- Range{0x25b7, 0x25c1, 10},
- Range{0x25f8, 0x25ff, 1},
- Range{0x266f, 0x27c0, 337},
- Range{0x27c1, 0x27c4, 1},
- Range{0x27c7, 0x27ca, 1},
- Range{0x27cc, 0x27d0, 4},
- Range{0x27d1, 0x27e5, 1},
- Range{0x27f0, 0x27ff, 1},
- Range{0x2900, 0x2982, 1},
- Range{0x2999, 0x29d7, 1},
- Range{0x29dc, 0x29fb, 1},
- Range{0x29fe, 0x2aff, 1},
- Range{0x2b30, 0x2b44, 1},
- Range{0x2b47, 0x2b4c, 1},
- Range{0xfb29, 0xfe62, 825},
- Range{0xfe64, 0xfe66, 1},
- Range{0xff0b, 0xff1c, 17},
- Range{0xff1d, 0xff1e, 1},
- Range{0xff5c, 0xff5e, 2},
- Range{0xffe2, 0xffe9, 7},
- Range{0xffea, 0xffec, 1},
- Range{0x1d6c1, 0x1d6db, 26},
- Range{0x1d6fb, 0x1d715, 26},
- Range{0x1d735, 0x1d74f, 26},
- Range{0x1d76f, 0x1d789, 26},
- Range{0x1d7a9, 0x1d7c3, 26},
+ {0x002b, 0x003c, 17},
+ {0x003d, 0x003e, 1},
+ {0x007c, 0x007e, 2},
+ {0x00ac, 0x00b1, 5},
+ {0x00d7, 0x00f7, 32},
+ {0x03f6, 0x0606, 528},
+ {0x0607, 0x0608, 1},
+ {0x2044, 0x2052, 14},
+ {0x207a, 0x207c, 1},
+ {0x208a, 0x208c, 1},
+ {0x2140, 0x2144, 1},
+ {0x214b, 0x2190, 69},
+ {0x2191, 0x2194, 1},
+ {0x219a, 0x219b, 1},
+ {0x21a0, 0x21a6, 3},
+ {0x21ae, 0x21ce, 32},
+ {0x21cf, 0x21d2, 3},
+ {0x21d4, 0x21f4, 32},
+ {0x21f5, 0x22ff, 1},
+ {0x2308, 0x230b, 1},
+ {0x2320, 0x2321, 1},
+ {0x237c, 0x239b, 31},
+ {0x239c, 0x23b3, 1},
+ {0x23dc, 0x23e1, 1},
+ {0x25b7, 0x25c1, 10},
+ {0x25f8, 0x25ff, 1},
+ {0x266f, 0x27c0, 337},
+ {0x27c1, 0x27c4, 1},
+ {0x27c7, 0x27ca, 1},
+ {0x27cc, 0x27d0, 4},
+ {0x27d1, 0x27e5, 1},
+ {0x27f0, 0x27ff, 1},
+ {0x2900, 0x2982, 1},
+ {0x2999, 0x29d7, 1},
+ {0x29dc, 0x29fb, 1},
+ {0x29fe, 0x2aff, 1},
+ {0x2b30, 0x2b44, 1},
+ {0x2b47, 0x2b4c, 1},
+ {0xfb29, 0xfe62, 825},
+ {0xfe64, 0xfe66, 1},
+ {0xff0b, 0xff1c, 17},
+ {0xff1d, 0xff1e, 1},
+ {0xff5c, 0xff5e, 2},
+ {0xffe2, 0xffe9, 7},
+ {0xffea, 0xffec, 1},
+ {0x1d6c1, 0x1d6db, 26},
+ {0x1d6fb, 0x1d715, 26},
+ {0x1d735, 0x1d74f, 26},
+ {0x1d76f, 0x1d789, 26},
+ {0x1d7a9, 0x1d7c3, 26},
}
var _Sk = []Range{
- Range{0x005e, 0x0060, 2},
- Range{0x00a8, 0x00af, 7},
- Range{0x00b4, 0x00b8, 4},
- Range{0x02c2, 0x02c5, 1},
- Range{0x02d2, 0x02df, 1},
- Range{0x02e5, 0x02eb, 1},
- Range{0x02ed, 0x02ef, 2},
- Range{0x02f0, 0x02ff, 1},
- Range{0x0375, 0x0384, 15},
- Range{0x0385, 0x1fbd, 7224},
- Range{0x1fbf, 0x1fc1, 1},
- Range{0x1fcd, 0x1fcf, 1},
- Range{0x1fdd, 0x1fdf, 1},
- Range{0x1fed, 0x1fef, 1},
- Range{0x1ffd, 0x1ffe, 1},
- Range{0x309b, 0x309c, 1},
- Range{0xa700, 0xa716, 1},
- Range{0xa720, 0xa721, 1},
- Range{0xa789, 0xa78a, 1},
- Range{0xff3e, 0xff40, 2},
- Range{0xffe3, 0xffe3, 1},
+ {0x005e, 0x0060, 2},
+ {0x00a8, 0x00af, 7},
+ {0x00b4, 0x00b8, 4},
+ {0x02c2, 0x02c5, 1},
+ {0x02d2, 0x02df, 1},
+ {0x02e5, 0x02eb, 1},
+ {0x02ed, 0x02ef, 2},
+ {0x02f0, 0x02ff, 1},
+ {0x0375, 0x0384, 15},
+ {0x0385, 0x1fbd, 7224},
+ {0x1fbf, 0x1fc1, 1},
+ {0x1fcd, 0x1fcf, 1},
+ {0x1fdd, 0x1fdf, 1},
+ {0x1fed, 0x1fef, 1},
+ {0x1ffd, 0x1ffe, 1},
+ {0x309b, 0x309c, 1},
+ {0xa700, 0xa716, 1},
+ {0xa720, 0xa721, 1},
+ {0xa789, 0xa78a, 1},
+ {0xff3e, 0xff40, 2},
+ {0xffe3, 0xffe3, 1},
}
var _Sc = []Range{
- Range{0x0024, 0x00a2, 126},
- Range{0x00a3, 0x00a5, 1},
- Range{0x060b, 0x09f2, 999},
- Range{0x09f3, 0x09fb, 8},
- Range{0x0af1, 0x0bf9, 264},
- Range{0x0e3f, 0x17db, 2460},
- Range{0x20a0, 0x20b8, 1},
- Range{0xa838, 0xfdfc, 21956},
- Range{0xfe69, 0xff04, 155},
- Range{0xffe0, 0xffe1, 1},
- Range{0xffe5, 0xffe6, 1},
+ {0x0024, 0x00a2, 126},
+ {0x00a3, 0x00a5, 1},
+ {0x060b, 0x09f2, 999},
+ {0x09f3, 0x09fb, 8},
+ {0x0af1, 0x0bf9, 264},
+ {0x0e3f, 0x17db, 2460},
+ {0x20a0, 0x20b8, 1},
+ {0xa838, 0xfdfc, 21956},
+ {0xfe69, 0xff04, 155},
+ {0xffe0, 0xffe1, 1},
+ {0xffe5, 0xffe6, 1},
}
var _Lu = []Range{
- Range{0x0041, 0x005a, 1},
- Range{0x00c0, 0x00d6, 1},
- Range{0x00d8, 0x00de, 1},
- Range{0x0100, 0x0136, 2},
- Range{0x0139, 0x0147, 2},
- Range{0x014a, 0x0178, 2},
- Range{0x0179, 0x017d, 2},
- Range{0x0181, 0x0182, 1},
- Range{0x0184, 0x0186, 2},
- Range{0x0187, 0x0189, 2},
- Range{0x018a, 0x018b, 1},
- Range{0x018e, 0x0191, 1},
- Range{0x0193, 0x0194, 1},
- Range{0x0196, 0x0198, 1},
- Range{0x019c, 0x019d, 1},
- Range{0x019f, 0x01a0, 1},
- Range{0x01a2, 0x01a6, 2},
- Range{0x01a7, 0x01a9, 2},
- Range{0x01ac, 0x01ae, 2},
- Range{0x01af, 0x01b1, 2},
- Range{0x01b2, 0x01b3, 1},
- Range{0x01b5, 0x01b7, 2},
- Range{0x01b8, 0x01bc, 4},
- Range{0x01c4, 0x01cd, 3},
- Range{0x01cf, 0x01db, 2},
- Range{0x01de, 0x01ee, 2},
- Range{0x01f1, 0x01f4, 3},
- Range{0x01f6, 0x01f8, 1},
- Range{0x01fa, 0x0232, 2},
- Range{0x023a, 0x023b, 1},
- Range{0x023d, 0x023e, 1},
- Range{0x0241, 0x0243, 2},
- Range{0x0244, 0x0246, 1},
- Range{0x0248, 0x024e, 2},
- Range{0x0370, 0x0372, 2},
- Range{0x0376, 0x0386, 16},
- Range{0x0388, 0x038a, 1},
- Range{0x038c, 0x038e, 2},
- Range{0x038f, 0x0391, 2},
- Range{0x0392, 0x03a1, 1},
- Range{0x03a3, 0x03ab, 1},
- Range{0x03cf, 0x03d2, 3},
- Range{0x03d3, 0x03d4, 1},
- Range{0x03d8, 0x03ee, 2},
- Range{0x03f4, 0x03f7, 3},
- Range{0x03f9, 0x03fa, 1},
- Range{0x03fd, 0x042f, 1},
- Range{0x0460, 0x0480, 2},
- Range{0x048a, 0x04c0, 2},
- Range{0x04c1, 0x04cd, 2},
- Range{0x04d0, 0x0524, 2},
- Range{0x0531, 0x0556, 1},
- Range{0x10a0, 0x10c5, 1},
- Range{0x1e00, 0x1e94, 2},
- Range{0x1e9e, 0x1efe, 2},
- Range{0x1f08, 0x1f0f, 1},
- Range{0x1f18, 0x1f1d, 1},
- Range{0x1f28, 0x1f2f, 1},
- Range{0x1f38, 0x1f3f, 1},
- Range{0x1f48, 0x1f4d, 1},
- Range{0x1f59, 0x1f5f, 2},
- Range{0x1f68, 0x1f6f, 1},
- Range{0x1fb8, 0x1fbb, 1},
- Range{0x1fc8, 0x1fcb, 1},
- Range{0x1fd8, 0x1fdb, 1},
- Range{0x1fe8, 0x1fec, 1},
- Range{0x1ff8, 0x1ffb, 1},
- Range{0x2102, 0x2107, 5},
- Range{0x210b, 0x210d, 1},
- Range{0x2110, 0x2112, 1},
- Range{0x2115, 0x2119, 4},
- Range{0x211a, 0x211d, 1},
- Range{0x2124, 0x212a, 2},
- Range{0x212b, 0x212d, 1},
- Range{0x2130, 0x2133, 1},
- Range{0x213e, 0x213f, 1},
- Range{0x2145, 0x2183, 62},
- Range{0x2c00, 0x2c2e, 1},
- Range{0x2c60, 0x2c62, 2},
- Range{0x2c63, 0x2c64, 1},
- Range{0x2c67, 0x2c6d, 2},
- Range{0x2c6e, 0x2c70, 1},
- Range{0x2c72, 0x2c75, 3},
- Range{0x2c7e, 0x2c80, 1},
- Range{0x2c82, 0x2ce2, 2},
- Range{0x2ceb, 0x2ced, 2},
- Range{0xa640, 0xa65e, 2},
- Range{0xa662, 0xa66c, 2},
- Range{0xa680, 0xa696, 2},
- Range{0xa722, 0xa72e, 2},
- Range{0xa732, 0xa76e, 2},
- Range{0xa779, 0xa77d, 2},
- Range{0xa77e, 0xa786, 2},
- Range{0xa78b, 0xff21, 22422},
- Range{0xff22, 0xff3a, 1},
- Range{0x10400, 0x10427, 1},
- Range{0x1d400, 0x1d419, 1},
- Range{0x1d434, 0x1d44d, 1},
- Range{0x1d468, 0x1d481, 1},
- Range{0x1d49c, 0x1d49e, 2},
- Range{0x1d49f, 0x1d4a5, 3},
- Range{0x1d4a6, 0x1d4a9, 3},
- Range{0x1d4aa, 0x1d4ac, 1},
- Range{0x1d4ae, 0x1d4b5, 1},
- Range{0x1d4d0, 0x1d4e9, 1},
- Range{0x1d504, 0x1d505, 1},
- Range{0x1d507, 0x1d50a, 1},
- Range{0x1d50d, 0x1d514, 1},
- Range{0x1d516, 0x1d51c, 1},
- Range{0x1d538, 0x1d539, 1},
- Range{0x1d53b, 0x1d53e, 1},
- Range{0x1d540, 0x1d544, 1},
- Range{0x1d546, 0x1d54a, 4},
- Range{0x1d54b, 0x1d550, 1},
- Range{0x1d56c, 0x1d585, 1},
- Range{0x1d5a0, 0x1d5b9, 1},
- Range{0x1d5d4, 0x1d5ed, 1},
- Range{0x1d608, 0x1d621, 1},
- Range{0x1d63c, 0x1d655, 1},
- Range{0x1d670, 0x1d689, 1},
- Range{0x1d6a8, 0x1d6c0, 1},
- Range{0x1d6e2, 0x1d6fa, 1},
- Range{0x1d71c, 0x1d734, 1},
- Range{0x1d756, 0x1d76e, 1},
- Range{0x1d790, 0x1d7a8, 1},
- Range{0x1d7ca, 0x1d7ca, 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, 0x0524, 2},
+ {0x0531, 0x0556, 1},
+ {0x10a0, 0x10c5, 1},
+ {0x1e00, 0x1e94, 2},
+ {0x1e9e, 0x1efe, 2},
+ {0x1f08, 0x1f0f, 1},
+ {0x1f18, 0x1f1d, 1},
+ {0x1f28, 0x1f2f, 1},
+ {0x1f38, 0x1f3f, 1},
+ {0x1f48, 0x1f4d, 1},
+ {0x1f59, 0x1f5f, 2},
+ {0x1f68, 0x1f6f, 1},
+ {0x1fb8, 0x1fbb, 1},
+ {0x1fc8, 0x1fcb, 1},
+ {0x1fd8, 0x1fdb, 1},
+ {0x1fe8, 0x1fec, 1},
+ {0x1ff8, 0x1ffb, 1},
+ {0x2102, 0x2107, 5},
+ {0x210b, 0x210d, 1},
+ {0x2110, 0x2112, 1},
+ {0x2115, 0x2119, 4},
+ {0x211a, 0x211d, 1},
+ {0x2124, 0x212a, 2},
+ {0x212b, 0x212d, 1},
+ {0x2130, 0x2133, 1},
+ {0x213e, 0x213f, 1},
+ {0x2145, 0x2183, 62},
+ {0x2c00, 0x2c2e, 1},
+ {0x2c60, 0x2c62, 2},
+ {0x2c63, 0x2c64, 1},
+ {0x2c67, 0x2c6d, 2},
+ {0x2c6e, 0x2c70, 1},
+ {0x2c72, 0x2c75, 3},
+ {0x2c7e, 0x2c80, 1},
+ {0x2c82, 0x2ce2, 2},
+ {0x2ceb, 0x2ced, 2},
+ {0xa640, 0xa65e, 2},
+ {0xa662, 0xa66c, 2},
+ {0xa680, 0xa696, 2},
+ {0xa722, 0xa72e, 2},
+ {0xa732, 0xa76e, 2},
+ {0xa779, 0xa77d, 2},
+ {0xa77e, 0xa786, 2},
+ {0xa78b, 0xff21, 22422},
+ {0xff22, 0xff3a, 1},
+ {0x10400, 0x10427, 1},
+ {0x1d400, 0x1d419, 1},
+ {0x1d434, 0x1d44d, 1},
+ {0x1d468, 0x1d481, 1},
+ {0x1d49c, 0x1d49e, 2},
+ {0x1d49f, 0x1d4a5, 3},
+ {0x1d4a6, 0x1d4a9, 3},
+ {0x1d4aa, 0x1d4ac, 1},
+ {0x1d4ae, 0x1d4b5, 1},
+ {0x1d4d0, 0x1d4e9, 1},
+ {0x1d504, 0x1d505, 1},
+ {0x1d507, 0x1d50a, 1},
+ {0x1d50d, 0x1d514, 1},
+ {0x1d516, 0x1d51c, 1},
+ {0x1d538, 0x1d539, 1},
+ {0x1d53b, 0x1d53e, 1},
+ {0x1d540, 0x1d544, 1},
+ {0x1d546, 0x1d54a, 4},
+ {0x1d54b, 0x1d550, 1},
+ {0x1d56c, 0x1d585, 1},
+ {0x1d5a0, 0x1d5b9, 1},
+ {0x1d5d4, 0x1d5ed, 1},
+ {0x1d608, 0x1d621, 1},
+ {0x1d63c, 0x1d655, 1},
+ {0x1d670, 0x1d689, 1},
+ {0x1d6a8, 0x1d6c0, 1},
+ {0x1d6e2, 0x1d6fa, 1},
+ {0x1d71c, 0x1d734, 1},
+ {0x1d756, 0x1d76e, 1},
+ {0x1d790, 0x1d7a8, 1},
+ {0x1d7ca, 0x1d7ca, 1},
}
var _Lt = []Range{
- Range{0x01c5, 0x01cb, 3},
- Range{0x01f2, 0x1f88, 7574},
- Range{0x1f89, 0x1f8f, 1},
- Range{0x1f98, 0x1f9f, 1},
- Range{0x1fa8, 0x1faf, 1},
- Range{0x1fbc, 0x1fcc, 16},
- Range{0x1ffc, 0x1ffc, 1},
+ {0x01c5, 0x01cb, 3},
+ {0x01f2, 0x1f88, 7574},
+ {0x1f89, 0x1f8f, 1},
+ {0x1f98, 0x1f9f, 1},
+ {0x1fa8, 0x1faf, 1},
+ {0x1fbc, 0x1fcc, 16},
+ {0x1ffc, 0x1ffc, 1},
}
var _Lo = []Range{
- Range{0x01bb, 0x01c0, 5},
- Range{0x01c1, 0x01c3, 1},
- Range{0x0294, 0x05d0, 828},
- Range{0x05d1, 0x05ea, 1},
- Range{0x05f0, 0x05f2, 1},
- Range{0x0621, 0x063f, 1},
- Range{0x0641, 0x064a, 1},
- Range{0x066e, 0x066f, 1},
- Range{0x0671, 0x06d3, 1},
- Range{0x06d5, 0x06ee, 25},
- Range{0x06ef, 0x06fa, 11},
- Range{0x06fb, 0x06fc, 1},
- Range{0x06ff, 0x0710, 17},
- Range{0x0712, 0x072f, 1},
- Range{0x074d, 0x07a5, 1},
- Range{0x07b1, 0x07ca, 25},
- Range{0x07cb, 0x07ea, 1},
- Range{0x0800, 0x0815, 1},
- Range{0x0904, 0x0939, 1},
- Range{0x093d, 0x0950, 19},
- Range{0x0958, 0x0961, 1},
- Range{0x0972, 0x0979, 7},
- Range{0x097a, 0x097f, 1},
- Range{0x0985, 0x098c, 1},
- Range{0x098f, 0x0990, 1},
- Range{0x0993, 0x09a8, 1},
- Range{0x09aa, 0x09b0, 1},
- Range{0x09b2, 0x09b6, 4},
- Range{0x09b7, 0x09b9, 1},
- Range{0x09bd, 0x09ce, 17},
- Range{0x09dc, 0x09dd, 1},
- Range{0x09df, 0x09e1, 1},
- Range{0x09f0, 0x09f1, 1},
- Range{0x0a05, 0x0a0a, 1},
- Range{0x0a0f, 0x0a10, 1},
- Range{0x0a13, 0x0a28, 1},
- Range{0x0a2a, 0x0a30, 1},
- Range{0x0a32, 0x0a33, 1},
- Range{0x0a35, 0x0a36, 1},
- Range{0x0a38, 0x0a39, 1},
- Range{0x0a59, 0x0a5c, 1},
- Range{0x0a5e, 0x0a72, 20},
- Range{0x0a73, 0x0a74, 1},
- Range{0x0a85, 0x0a8d, 1},
- Range{0x0a8f, 0x0a91, 1},
- Range{0x0a93, 0x0aa8, 1},
- Range{0x0aaa, 0x0ab0, 1},
- Range{0x0ab2, 0x0ab3, 1},
- Range{0x0ab5, 0x0ab9, 1},
- Range{0x0abd, 0x0ad0, 19},
- Range{0x0ae0, 0x0ae1, 1},
- Range{0x0b05, 0x0b0c, 1},
- Range{0x0b0f, 0x0b10, 1},
- Range{0x0b13, 0x0b28, 1},
- Range{0x0b2a, 0x0b30, 1},
- Range{0x0b32, 0x0b33, 1},
- Range{0x0b35, 0x0b39, 1},
- Range{0x0b3d, 0x0b5c, 31},
- Range{0x0b5d, 0x0b5f, 2},
- Range{0x0b60, 0x0b61, 1},
- Range{0x0b71, 0x0b83, 18},
- Range{0x0b85, 0x0b8a, 1},
- Range{0x0b8e, 0x0b90, 1},
- Range{0x0b92, 0x0b95, 1},
- Range{0x0b99, 0x0b9a, 1},
- Range{0x0b9c, 0x0b9e, 2},
- Range{0x0b9f, 0x0ba3, 4},
- Range{0x0ba4, 0x0ba8, 4},
- Range{0x0ba9, 0x0baa, 1},
- Range{0x0bae, 0x0bb9, 1},
- Range{0x0bd0, 0x0c05, 53},
- Range{0x0c06, 0x0c0c, 1},
- Range{0x0c0e, 0x0c10, 1},
- Range{0x0c12, 0x0c28, 1},
- Range{0x0c2a, 0x0c33, 1},
- Range{0x0c35, 0x0c39, 1},
- Range{0x0c3d, 0x0c58, 27},
- Range{0x0c59, 0x0c60, 7},
- Range{0x0c61, 0x0c85, 36},
- Range{0x0c86, 0x0c8c, 1},
- Range{0x0c8e, 0x0c90, 1},
- Range{0x0c92, 0x0ca8, 1},
- Range{0x0caa, 0x0cb3, 1},
- Range{0x0cb5, 0x0cb9, 1},
- Range{0x0cbd, 0x0cde, 33},
- Range{0x0ce0, 0x0ce1, 1},
- Range{0x0d05, 0x0d0c, 1},
- Range{0x0d0e, 0x0d10, 1},
- Range{0x0d12, 0x0d28, 1},
- Range{0x0d2a, 0x0d39, 1},
- Range{0x0d3d, 0x0d60, 35},
- Range{0x0d61, 0x0d7a, 25},
- Range{0x0d7b, 0x0d7f, 1},
- Range{0x0d85, 0x0d96, 1},
- Range{0x0d9a, 0x0db1, 1},
- Range{0x0db3, 0x0dbb, 1},
- Range{0x0dbd, 0x0dc0, 3},
- Range{0x0dc1, 0x0dc6, 1},
- Range{0x0e01, 0x0e30, 1},
- Range{0x0e32, 0x0e33, 1},
- Range{0x0e40, 0x0e45, 1},
- Range{0x0e81, 0x0e82, 1},
- Range{0x0e84, 0x0e87, 3},
- Range{0x0e88, 0x0e8a, 2},
- Range{0x0e8d, 0x0e94, 7},
- Range{0x0e95, 0x0e97, 1},
- Range{0x0e99, 0x0e9f, 1},
- Range{0x0ea1, 0x0ea3, 1},
- Range{0x0ea5, 0x0ea7, 2},
- Range{0x0eaa, 0x0eab, 1},
- Range{0x0ead, 0x0eb0, 1},
- Range{0x0eb2, 0x0eb3, 1},
- Range{0x0ebd, 0x0ec0, 3},
- Range{0x0ec1, 0x0ec4, 1},
- Range{0x0edc, 0x0edd, 1},
- Range{0x0f00, 0x0f40, 64},
- Range{0x0f41, 0x0f47, 1},
- Range{0x0f49, 0x0f6c, 1},
- Range{0x0f88, 0x0f8b, 1},
- Range{0x1000, 0x102a, 1},
- Range{0x103f, 0x1050, 17},
- Range{0x1051, 0x1055, 1},
- Range{0x105a, 0x105d, 1},
- Range{0x1061, 0x1065, 4},
- Range{0x1066, 0x106e, 8},
- Range{0x106f, 0x1070, 1},
- Range{0x1075, 0x1081, 1},
- Range{0x108e, 0x10d0, 66},
- Range{0x10d1, 0x10fa, 1},
- Range{0x1100, 0x1248, 1},
- Range{0x124a, 0x124d, 1},
- Range{0x1250, 0x1256, 1},
- Range{0x1258, 0x125a, 2},
- Range{0x125b, 0x125d, 1},
- Range{0x1260, 0x1288, 1},
- Range{0x128a, 0x128d, 1},
- Range{0x1290, 0x12b0, 1},
- Range{0x12b2, 0x12b5, 1},
- Range{0x12b8, 0x12be, 1},
- Range{0x12c0, 0x12c2, 2},
- Range{0x12c3, 0x12c5, 1},
- Range{0x12c8, 0x12d6, 1},
- Range{0x12d8, 0x1310, 1},
- Range{0x1312, 0x1315, 1},
- Range{0x1318, 0x135a, 1},
- Range{0x1380, 0x138f, 1},
- Range{0x13a0, 0x13f4, 1},
- Range{0x1401, 0x166c, 1},
- Range{0x166f, 0x167f, 1},
- Range{0x1681, 0x169a, 1},
- Range{0x16a0, 0x16ea, 1},
- Range{0x1700, 0x170c, 1},
- Range{0x170e, 0x1711, 1},
- Range{0x1720, 0x1731, 1},
- Range{0x1740, 0x1751, 1},
- Range{0x1760, 0x176c, 1},
- Range{0x176e, 0x1770, 1},
- Range{0x1780, 0x17b3, 1},
- Range{0x17dc, 0x1820, 68},
- Range{0x1821, 0x1842, 1},
- Range{0x1844, 0x1877, 1},
- Range{0x1880, 0x18a8, 1},
- Range{0x18aa, 0x18b0, 6},
- Range{0x18b1, 0x18f5, 1},
- Range{0x1900, 0x191c, 1},
- Range{0x1950, 0x196d, 1},
- Range{0x1970, 0x1974, 1},
- Range{0x1980, 0x19ab, 1},
- Range{0x19c1, 0x19c7, 1},
- Range{0x1a00, 0x1a16, 1},
- Range{0x1a20, 0x1a54, 1},
- Range{0x1b05, 0x1b33, 1},
- Range{0x1b45, 0x1b4b, 1},
- Range{0x1b83, 0x1ba0, 1},
- Range{0x1bae, 0x1baf, 1},
- Range{0x1c00, 0x1c23, 1},
- Range{0x1c4d, 0x1c4f, 1},
- Range{0x1c5a, 0x1c77, 1},
- Range{0x1ce9, 0x1cec, 1},
- Range{0x1cee, 0x1cf1, 1},
- Range{0x2135, 0x2138, 1},
- Range{0x2d30, 0x2d65, 1},
- Range{0x2d80, 0x2d96, 1},
- Range{0x2da0, 0x2da6, 1},
- Range{0x2da8, 0x2dae, 1},
- Range{0x2db0, 0x2db6, 1},
- Range{0x2db8, 0x2dbe, 1},
- Range{0x2dc0, 0x2dc6, 1},
- Range{0x2dc8, 0x2dce, 1},
- Range{0x2dd0, 0x2dd6, 1},
- Range{0x2dd8, 0x2dde, 1},
- Range{0x3006, 0x303c, 54},
- Range{0x3041, 0x3096, 1},
- Range{0x309f, 0x30a1, 2},
- Range{0x30a2, 0x30fa, 1},
- Range{0x30ff, 0x3105, 6},
- Range{0x3106, 0x312d, 1},
- Range{0x3131, 0x318e, 1},
- Range{0x31a0, 0x31b7, 1},
- Range{0x31f0, 0x31ff, 1},
- Range{0x3400, 0x4db5, 1},
- Range{0x4e00, 0x9fcb, 1},
- Range{0xa000, 0xa014, 1},
- Range{0xa016, 0xa48c, 1},
- Range{0xa4d0, 0xa4f7, 1},
- Range{0xa500, 0xa60b, 1},
- Range{0xa610, 0xa61f, 1},
- Range{0xa62a, 0xa62b, 1},
- Range{0xa66e, 0xa6a0, 50},
- Range{0xa6a1, 0xa6e5, 1},
- Range{0xa7fb, 0xa801, 1},
- Range{0xa803, 0xa805, 1},
- Range{0xa807, 0xa80a, 1},
- Range{0xa80c, 0xa822, 1},
- Range{0xa840, 0xa873, 1},
- Range{0xa882, 0xa8b3, 1},
- Range{0xa8f2, 0xa8f7, 1},
- Range{0xa8fb, 0xa90a, 15},
- Range{0xa90b, 0xa925, 1},
- Range{0xa930, 0xa946, 1},
- Range{0xa960, 0xa97c, 1},
- Range{0xa984, 0xa9b2, 1},
- Range{0xaa00, 0xaa28, 1},
- Range{0xaa40, 0xaa42, 1},
- Range{0xaa44, 0xaa4b, 1},
- Range{0xaa60, 0xaa6f, 1},
- Range{0xaa71, 0xaa76, 1},
- Range{0xaa7a, 0xaa80, 6},
- Range{0xaa81, 0xaaaf, 1},
- Range{0xaab1, 0xaab5, 4},
- Range{0xaab6, 0xaab9, 3},
- Range{0xaaba, 0xaabd, 1},
- Range{0xaac0, 0xaac2, 2},
- Range{0xaadb, 0xaadc, 1},
- Range{0xabc0, 0xabe2, 1},
- Range{0xac00, 0xd7a3, 1},
- Range{0xd7b0, 0xd7c6, 1},
- Range{0xd7cb, 0xd7fb, 1},
- Range{0xf900, 0xfa2d, 1},
- Range{0xfa30, 0xfa6d, 1},
- Range{0xfa70, 0xfad9, 1},
- Range{0xfb1d, 0xfb1f, 2},
- Range{0xfb20, 0xfb28, 1},
- Range{0xfb2a, 0xfb36, 1},
- Range{0xfb38, 0xfb3c, 1},
- Range{0xfb3e, 0xfb40, 2},
- Range{0xfb41, 0xfb43, 2},
- Range{0xfb44, 0xfb46, 2},
- Range{0xfb47, 0xfbb1, 1},
- Range{0xfbd3, 0xfd3d, 1},
- Range{0xfd50, 0xfd8f, 1},
- Range{0xfd92, 0xfdc7, 1},
- Range{0xfdf0, 0xfdfb, 1},
- Range{0xfe70, 0xfe74, 1},
- Range{0xfe76, 0xfefc, 1},
- Range{0xff66, 0xff6f, 1},
- Range{0xff71, 0xff9d, 1},
- Range{0xffa0, 0xffbe, 1},
- Range{0xffc2, 0xffc7, 1},
- Range{0xffca, 0xffcf, 1},
- Range{0xffd2, 0xffd7, 1},
- Range{0xffda, 0xffdc, 1},
- Range{0x10000, 0x1000b, 1},
- Range{0x1000d, 0x10026, 1},
- Range{0x10028, 0x1003a, 1},
- Range{0x1003c, 0x1003d, 1},
- Range{0x1003f, 0x1004d, 1},
- Range{0x10050, 0x1005d, 1},
- Range{0x10080, 0x100fa, 1},
- Range{0x10280, 0x1029c, 1},
- Range{0x102a0, 0x102d0, 1},
- Range{0x10300, 0x1031e, 1},
- Range{0x10330, 0x10340, 1},
- Range{0x10342, 0x10349, 1},
- Range{0x10380, 0x1039d, 1},
- Range{0x103a0, 0x103c3, 1},
- Range{0x103c8, 0x103cf, 1},
- Range{0x10450, 0x1049d, 1},
- Range{0x10800, 0x10805, 1},
- Range{0x10808, 0x1080a, 2},
- Range{0x1080b, 0x10835, 1},
- Range{0x10837, 0x10838, 1},
- Range{0x1083c, 0x1083f, 3},
- Range{0x10840, 0x10855, 1},
- Range{0x10900, 0x10915, 1},
- Range{0x10920, 0x10939, 1},
- Range{0x10a00, 0x10a10, 16},
- Range{0x10a11, 0x10a13, 1},
- Range{0x10a15, 0x10a17, 1},
- Range{0x10a19, 0x10a33, 1},
- Range{0x10a60, 0x10a7c, 1},
- Range{0x10b00, 0x10b35, 1},
- Range{0x10b40, 0x10b55, 1},
- Range{0x10b60, 0x10b72, 1},
- Range{0x10c00, 0x10c48, 1},
- Range{0x11083, 0x110af, 1},
- Range{0x12000, 0x1236e, 1},
- Range{0x13000, 0x1342e, 1},
- Range{0x20000, 0x2a6d6, 1},
- Range{0x2a700, 0x2b734, 1},
- Range{0x2f800, 0x2fa1d, 1},
+ {0x01bb, 0x01c0, 5},
+ {0x01c1, 0x01c3, 1},
+ {0x0294, 0x05d0, 828},
+ {0x05d1, 0x05ea, 1},
+ {0x05f0, 0x05f2, 1},
+ {0x0621, 0x063f, 1},
+ {0x0641, 0x064a, 1},
+ {0x066e, 0x066f, 1},
+ {0x0671, 0x06d3, 1},
+ {0x06d5, 0x06ee, 25},
+ {0x06ef, 0x06fa, 11},
+ {0x06fb, 0x06fc, 1},
+ {0x06ff, 0x0710, 17},
+ {0x0712, 0x072f, 1},
+ {0x074d, 0x07a5, 1},
+ {0x07b1, 0x07ca, 25},
+ {0x07cb, 0x07ea, 1},
+ {0x0800, 0x0815, 1},
+ {0x0904, 0x0939, 1},
+ {0x093d, 0x0950, 19},
+ {0x0958, 0x0961, 1},
+ {0x0972, 0x0979, 7},
+ {0x097a, 0x097f, 1},
+ {0x0985, 0x098c, 1},
+ {0x098f, 0x0990, 1},
+ {0x0993, 0x09a8, 1},
+ {0x09aa, 0x09b0, 1},
+ {0x09b2, 0x09b6, 4},
+ {0x09b7, 0x09b9, 1},
+ {0x09bd, 0x09ce, 17},
+ {0x09dc, 0x09dd, 1},
+ {0x09df, 0x09e1, 1},
+ {0x09f0, 0x09f1, 1},
+ {0x0a05, 0x0a0a, 1},
+ {0x0a0f, 0x0a10, 1},
+ {0x0a13, 0x0a28, 1},
+ {0x0a2a, 0x0a30, 1},
+ {0x0a32, 0x0a33, 1},
+ {0x0a35, 0x0a36, 1},
+ {0x0a38, 0x0a39, 1},
+ {0x0a59, 0x0a5c, 1},
+ {0x0a5e, 0x0a72, 20},
+ {0x0a73, 0x0a74, 1},
+ {0x0a85, 0x0a8d, 1},
+ {0x0a8f, 0x0a91, 1},
+ {0x0a93, 0x0aa8, 1},
+ {0x0aaa, 0x0ab0, 1},
+ {0x0ab2, 0x0ab3, 1},
+ {0x0ab5, 0x0ab9, 1},
+ {0x0abd, 0x0ad0, 19},
+ {0x0ae0, 0x0ae1, 1},
+ {0x0b05, 0x0b0c, 1},
+ {0x0b0f, 0x0b10, 1},
+ {0x0b13, 0x0b28, 1},
+ {0x0b2a, 0x0b30, 1},
+ {0x0b32, 0x0b33, 1},
+ {0x0b35, 0x0b39, 1},
+ {0x0b3d, 0x0b5c, 31},
+ {0x0b5d, 0x0b5f, 2},
+ {0x0b60, 0x0b61, 1},
+ {0x0b71, 0x0b83, 18},
+ {0x0b85, 0x0b8a, 1},
+ {0x0b8e, 0x0b90, 1},
+ {0x0b92, 0x0b95, 1},
+ {0x0b99, 0x0b9a, 1},
+ {0x0b9c, 0x0b9e, 2},
+ {0x0b9f, 0x0ba3, 4},
+ {0x0ba4, 0x0ba8, 4},
+ {0x0ba9, 0x0baa, 1},
+ {0x0bae, 0x0bb9, 1},
+ {0x0bd0, 0x0c05, 53},
+ {0x0c06, 0x0c0c, 1},
+ {0x0c0e, 0x0c10, 1},
+ {0x0c12, 0x0c28, 1},
+ {0x0c2a, 0x0c33, 1},
+ {0x0c35, 0x0c39, 1},
+ {0x0c3d, 0x0c58, 27},
+ {0x0c59, 0x0c60, 7},
+ {0x0c61, 0x0c85, 36},
+ {0x0c86, 0x0c8c, 1},
+ {0x0c8e, 0x0c90, 1},
+ {0x0c92, 0x0ca8, 1},
+ {0x0caa, 0x0cb3, 1},
+ {0x0cb5, 0x0cb9, 1},
+ {0x0cbd, 0x0cde, 33},
+ {0x0ce0, 0x0ce1, 1},
+ {0x0d05, 0x0d0c, 1},
+ {0x0d0e, 0x0d10, 1},
+ {0x0d12, 0x0d28, 1},
+ {0x0d2a, 0x0d39, 1},
+ {0x0d3d, 0x0d60, 35},
+ {0x0d61, 0x0d7a, 25},
+ {0x0d7b, 0x0d7f, 1},
+ {0x0d85, 0x0d96, 1},
+ {0x0d9a, 0x0db1, 1},
+ {0x0db3, 0x0dbb, 1},
+ {0x0dbd, 0x0dc0, 3},
+ {0x0dc1, 0x0dc6, 1},
+ {0x0e01, 0x0e30, 1},
+ {0x0e32, 0x0e33, 1},
+ {0x0e40, 0x0e45, 1},
+ {0x0e81, 0x0e82, 1},
+ {0x0e84, 0x0e87, 3},
+ {0x0e88, 0x0e8a, 2},
+ {0x0e8d, 0x0e94, 7},
+ {0x0e95, 0x0e97, 1},
+ {0x0e99, 0x0e9f, 1},
+ {0x0ea1, 0x0ea3, 1},
+ {0x0ea5, 0x0ea7, 2},
+ {0x0eaa, 0x0eab, 1},
+ {0x0ead, 0x0eb0, 1},
+ {0x0eb2, 0x0eb3, 1},
+ {0x0ebd, 0x0ec0, 3},
+ {0x0ec1, 0x0ec4, 1},
+ {0x0edc, 0x0edd, 1},
+ {0x0f00, 0x0f40, 64},
+ {0x0f41, 0x0f47, 1},
+ {0x0f49, 0x0f6c, 1},
+ {0x0f88, 0x0f8b, 1},
+ {0x1000, 0x102a, 1},
+ {0x103f, 0x1050, 17},
+ {0x1051, 0x1055, 1},
+ {0x105a, 0x105d, 1},
+ {0x1061, 0x1065, 4},
+ {0x1066, 0x106e, 8},
+ {0x106f, 0x1070, 1},
+ {0x1075, 0x1081, 1},
+ {0x108e, 0x10d0, 66},
+ {0x10d1, 0x10fa, 1},
+ {0x1100, 0x1248, 1},
+ {0x124a, 0x124d, 1},
+ {0x1250, 0x1256, 1},
+ {0x1258, 0x125a, 2},
+ {0x125b, 0x125d, 1},
+ {0x1260, 0x1288, 1},
+ {0x128a, 0x128d, 1},
+ {0x1290, 0x12b0, 1},
+ {0x12b2, 0x12b5, 1},
+ {0x12b8, 0x12be, 1},
+ {0x12c0, 0x12c2, 2},
+ {0x12c3, 0x12c5, 1},
+ {0x12c8, 0x12d6, 1},
+ {0x12d8, 0x1310, 1},
+ {0x1312, 0x1315, 1},
+ {0x1318, 0x135a, 1},
+ {0x1380, 0x138f, 1},
+ {0x13a0, 0x13f4, 1},
+ {0x1401, 0x166c, 1},
+ {0x166f, 0x167f, 1},
+ {0x1681, 0x169a, 1},
+ {0x16a0, 0x16ea, 1},
+ {0x1700, 0x170c, 1},
+ {0x170e, 0x1711, 1},
+ {0x1720, 0x1731, 1},
+ {0x1740, 0x1751, 1},
+ {0x1760, 0x176c, 1},
+ {0x176e, 0x1770, 1},
+ {0x1780, 0x17b3, 1},
+ {0x17dc, 0x1820, 68},
+ {0x1821, 0x1842, 1},
+ {0x1844, 0x1877, 1},
+ {0x1880, 0x18a8, 1},
+ {0x18aa, 0x18b0, 6},
+ {0x18b1, 0x18f5, 1},
+ {0x1900, 0x191c, 1},
+ {0x1950, 0x196d, 1},
+ {0x1970, 0x1974, 1},
+ {0x1980, 0x19ab, 1},
+ {0x19c1, 0x19c7, 1},
+ {0x1a00, 0x1a16, 1},
+ {0x1a20, 0x1a54, 1},
+ {0x1b05, 0x1b33, 1},
+ {0x1b45, 0x1b4b, 1},
+ {0x1b83, 0x1ba0, 1},
+ {0x1bae, 0x1baf, 1},
+ {0x1c00, 0x1c23, 1},
+ {0x1c4d, 0x1c4f, 1},
+ {0x1c5a, 0x1c77, 1},
+ {0x1ce9, 0x1cec, 1},
+ {0x1cee, 0x1cf1, 1},
+ {0x2135, 0x2138, 1},
+ {0x2d30, 0x2d65, 1},
+ {0x2d80, 0x2d96, 1},
+ {0x2da0, 0x2da6, 1},
+ {0x2da8, 0x2dae, 1},
+ {0x2db0, 0x2db6, 1},
+ {0x2db8, 0x2dbe, 1},
+ {0x2dc0, 0x2dc6, 1},
+ {0x2dc8, 0x2dce, 1},
+ {0x2dd0, 0x2dd6, 1},
+ {0x2dd8, 0x2dde, 1},
+ {0x3006, 0x303c, 54},
+ {0x3041, 0x3096, 1},
+ {0x309f, 0x30a1, 2},
+ {0x30a2, 0x30fa, 1},
+ {0x30ff, 0x3105, 6},
+ {0x3106, 0x312d, 1},
+ {0x3131, 0x318e, 1},
+ {0x31a0, 0x31b7, 1},
+ {0x31f0, 0x31ff, 1},
+ {0x3400, 0x4db5, 1},
+ {0x4e00, 0x9fcb, 1},
+ {0xa000, 0xa014, 1},
+ {0xa016, 0xa48c, 1},
+ {0xa4d0, 0xa4f7, 1},
+ {0xa500, 0xa60b, 1},
+ {0xa610, 0xa61f, 1},
+ {0xa62a, 0xa62b, 1},
+ {0xa66e, 0xa6a0, 50},
+ {0xa6a1, 0xa6e5, 1},
+ {0xa7fb, 0xa801, 1},
+ {0xa803, 0xa805, 1},
+ {0xa807, 0xa80a, 1},
+ {0xa80c, 0xa822, 1},
+ {0xa840, 0xa873, 1},
+ {0xa882, 0xa8b3, 1},
+ {0xa8f2, 0xa8f7, 1},
+ {0xa8fb, 0xa90a, 15},
+ {0xa90b, 0xa925, 1},
+ {0xa930, 0xa946, 1},
+ {0xa960, 0xa97c, 1},
+ {0xa984, 0xa9b2, 1},
+ {0xaa00, 0xaa28, 1},
+ {0xaa40, 0xaa42, 1},
+ {0xaa44, 0xaa4b, 1},
+ {0xaa60, 0xaa6f, 1},
+ {0xaa71, 0xaa76, 1},
+ {0xaa7a, 0xaa80, 6},
+ {0xaa81, 0xaaaf, 1},
+ {0xaab1, 0xaab5, 4},
+ {0xaab6, 0xaab9, 3},
+ {0xaaba, 0xaabd, 1},
+ {0xaac0, 0xaac2, 2},
+ {0xaadb, 0xaadc, 1},
+ {0xabc0, 0xabe2, 1},
+ {0xac00, 0xd7a3, 1},
+ {0xd7b0, 0xd7c6, 1},
+ {0xd7cb, 0xd7fb, 1},
+ {0xf900, 0xfa2d, 1},
+ {0xfa30, 0xfa6d, 1},
+ {0xfa70, 0xfad9, 1},
+ {0xfb1d, 0xfb1f, 2},
+ {0xfb20, 0xfb28, 1},
+ {0xfb2a, 0xfb36, 1},
+ {0xfb38, 0xfb3c, 1},
+ {0xfb3e, 0xfb40, 2},
+ {0xfb41, 0xfb43, 2},
+ {0xfb44, 0xfb46, 2},
+ {0xfb47, 0xfbb1, 1},
+ {0xfbd3, 0xfd3d, 1},
+ {0xfd50, 0xfd8f, 1},
+ {0xfd92, 0xfdc7, 1},
+ {0xfdf0, 0xfdfb, 1},
+ {0xfe70, 0xfe74, 1},
+ {0xfe76, 0xfefc, 1},
+ {0xff66, 0xff6f, 1},
+ {0xff71, 0xff9d, 1},
+ {0xffa0, 0xffbe, 1},
+ {0xffc2, 0xffc7, 1},
+ {0xffca, 0xffcf, 1},
+ {0xffd2, 0xffd7, 1},
+ {0xffda, 0xffdc, 1},
+ {0x10000, 0x1000b, 1},
+ {0x1000d, 0x10026, 1},
+ {0x10028, 0x1003a, 1},
+ {0x1003c, 0x1003d, 1},
+ {0x1003f, 0x1004d, 1},
+ {0x10050, 0x1005d, 1},
+ {0x10080, 0x100fa, 1},
+ {0x10280, 0x1029c, 1},
+ {0x102a0, 0x102d0, 1},
+ {0x10300, 0x1031e, 1},
+ {0x10330, 0x10340, 1},
+ {0x10342, 0x10349, 1},
+ {0x10380, 0x1039d, 1},
+ {0x103a0, 0x103c3, 1},
+ {0x103c8, 0x103cf, 1},
+ {0x10450, 0x1049d, 1},
+ {0x10800, 0x10805, 1},
+ {0x10808, 0x1080a, 2},
+ {0x1080b, 0x10835, 1},
+ {0x10837, 0x10838, 1},
+ {0x1083c, 0x1083f, 3},
+ {0x10840, 0x10855, 1},
+ {0x10900, 0x10915, 1},
+ {0x10920, 0x10939, 1},
+ {0x10a00, 0x10a10, 16},
+ {0x10a11, 0x10a13, 1},
+ {0x10a15, 0x10a17, 1},
+ {0x10a19, 0x10a33, 1},
+ {0x10a60, 0x10a7c, 1},
+ {0x10b00, 0x10b35, 1},
+ {0x10b40, 0x10b55, 1},
+ {0x10b60, 0x10b72, 1},
+ {0x10c00, 0x10c48, 1},
+ {0x11083, 0x110af, 1},
+ {0x12000, 0x1236e, 1},
+ {0x13000, 0x1342e, 1},
+ {0x20000, 0x2a6d6, 1},
+ {0x2a700, 0x2b734, 1},
+ {0x2f800, 0x2fa1d, 1},
}
var (
@@ -2058,935 +2058,935 @@ var Scripts = map[string][]Range{
}
var _Katakana = []Range{
- Range{0x30a1, 0x30fa, 1},
- Range{0x30fd, 0x30ff, 1},
- Range{0x31f0, 0x31ff, 1},
- Range{0x32d0, 0x32fe, 1},
- Range{0x3300, 0x3357, 1},
- Range{0xff66, 0xff6f, 1},
- Range{0xff71, 0xff9d, 1},
+ {0x30a1, 0x30fa, 1},
+ {0x30fd, 0x30ff, 1},
+ {0x31f0, 0x31ff, 1},
+ {0x32d0, 0x32fe, 1},
+ {0x3300, 0x3357, 1},
+ {0xff66, 0xff6f, 1},
+ {0xff71, 0xff9d, 1},
}
var _Malayalam = []Range{
- Range{0x0d02, 0x0d03, 1},
- Range{0x0d05, 0x0d0c, 1},
- Range{0x0d0e, 0x0d10, 1},
- Range{0x0d12, 0x0d28, 1},
- Range{0x0d2a, 0x0d39, 1},
- Range{0x0d3d, 0x0d44, 1},
- Range{0x0d46, 0x0d48, 1},
- Range{0x0d4a, 0x0d4d, 1},
- Range{0x0d57, 0x0d57, 1},
- Range{0x0d60, 0x0d63, 1},
- Range{0x0d66, 0x0d75, 1},
- Range{0x0d79, 0x0d7f, 1},
+ {0x0d02, 0x0d03, 1},
+ {0x0d05, 0x0d0c, 1},
+ {0x0d0e, 0x0d10, 1},
+ {0x0d12, 0x0d28, 1},
+ {0x0d2a, 0x0d39, 1},
+ {0x0d3d, 0x0d44, 1},
+ {0x0d46, 0x0d48, 1},
+ {0x0d4a, 0x0d4d, 1},
+ {0x0d57, 0x0d57, 1},
+ {0x0d60, 0x0d63, 1},
+ {0x0d66, 0x0d75, 1},
+ {0x0d79, 0x0d7f, 1},
}
var _Phags_Pa = []Range{
- Range{0xa840, 0xa877, 1},
+ {0xa840, 0xa877, 1},
}
var _Inscriptional_Parthian = []Range{
- Range{0x10b40, 0x10b55, 1},
- Range{0x10b58, 0x10b5f, 1},
+ {0x10b40, 0x10b55, 1},
+ {0x10b58, 0x10b5f, 1},
}
var _Latin = []Range{
- Range{0x0041, 0x005a, 1},
- Range{0x0061, 0x007a, 1},
- Range{0x00aa, 0x00aa, 1},
- Range{0x00ba, 0x00ba, 1},
- Range{0x00c0, 0x00d6, 1},
- Range{0x00d8, 0x00f6, 1},
- Range{0x00f8, 0x02b8, 1},
- Range{0x02e0, 0x02e4, 1},
- Range{0x1d00, 0x1d25, 1},
- Range{0x1d2c, 0x1d5c, 1},
- Range{0x1d62, 0x1d65, 1},
- Range{0x1d6b, 0x1d77, 1},
- Range{0x1d79, 0x1dbe, 1},
- Range{0x1e00, 0x1eff, 1},
- Range{0x2071, 0x2071, 1},
- Range{0x207f, 0x207f, 1},
- Range{0x2090, 0x2094, 1},
- Range{0x212a, 0x212b, 1},
- Range{0x2132, 0x2132, 1},
- Range{0x214e, 0x214e, 1},
- Range{0x2160, 0x2188, 1},
- Range{0x2c60, 0x2c7f, 1},
- Range{0xa722, 0xa787, 1},
- Range{0xa78b, 0xa78c, 1},
- Range{0xa7fb, 0xa7ff, 1},
- Range{0xfb00, 0xfb06, 1},
- Range{0xff21, 0xff3a, 1},
- Range{0xff41, 0xff5a, 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, 0x2094, 1},
+ {0x212a, 0x212b, 1},
+ {0x2132, 0x2132, 1},
+ {0x214e, 0x214e, 1},
+ {0x2160, 0x2188, 1},
+ {0x2c60, 0x2c7f, 1},
+ {0xa722, 0xa787, 1},
+ {0xa78b, 0xa78c, 1},
+ {0xa7fb, 0xa7ff, 1},
+ {0xfb00, 0xfb06, 1},
+ {0xff21, 0xff3a, 1},
+ {0xff41, 0xff5a, 1},
}
var _Inscriptional_Pahlavi = []Range{
- Range{0x10b60, 0x10b72, 1},
- Range{0x10b78, 0x10b7f, 1},
+ {0x10b60, 0x10b72, 1},
+ {0x10b78, 0x10b7f, 1},
}
var _Osmanya = []Range{
- Range{0x10480, 0x1049d, 1},
- Range{0x104a0, 0x104a9, 1},
+ {0x10480, 0x1049d, 1},
+ {0x104a0, 0x104a9, 1},
}
var _Khmer = []Range{
- Range{0x1780, 0x17dd, 1},
- Range{0x17e0, 0x17e9, 1},
- Range{0x17f0, 0x17f9, 1},
- Range{0x19e0, 0x19ff, 1},
+ {0x1780, 0x17dd, 1},
+ {0x17e0, 0x17e9, 1},
+ {0x17f0, 0x17f9, 1},
+ {0x19e0, 0x19ff, 1},
}
var _Inherited = []Range{
- Range{0x0300, 0x036f, 1},
- Range{0x0485, 0x0486, 1},
- Range{0x064b, 0x0655, 1},
- Range{0x0670, 0x0670, 1},
- Range{0x0951, 0x0952, 1},
- Range{0x1cd0, 0x1cd2, 1},
- Range{0x1cd4, 0x1ce0, 1},
- Range{0x1ce2, 0x1ce8, 1},
- Range{0x1ced, 0x1ced, 1},
- Range{0x1dc0, 0x1de6, 1},
- Range{0x1dfd, 0x1dff, 1},
- Range{0x200c, 0x200d, 1},
- Range{0x20d0, 0x20f0, 1},
- Range{0x302a, 0x302f, 1},
- Range{0x3099, 0x309a, 1},
- Range{0xfe00, 0xfe0f, 1},
- Range{0xfe20, 0xfe26, 1},
- Range{0x101fd, 0x101fd, 1},
- Range{0x1d167, 0x1d169, 1},
- Range{0x1d17b, 0x1d182, 1},
- Range{0x1d185, 0x1d18b, 1},
- Range{0x1d1aa, 0x1d1ad, 1},
- Range{0xe0100, 0xe01ef, 1},
+ {0x0300, 0x036f, 1},
+ {0x0485, 0x0486, 1},
+ {0x064b, 0x0655, 1},
+ {0x0670, 0x0670, 1},
+ {0x0951, 0x0952, 1},
+ {0x1cd0, 0x1cd2, 1},
+ {0x1cd4, 0x1ce0, 1},
+ {0x1ce2, 0x1ce8, 1},
+ {0x1ced, 0x1ced, 1},
+ {0x1dc0, 0x1de6, 1},
+ {0x1dfd, 0x1dff, 1},
+ {0x200c, 0x200d, 1},
+ {0x20d0, 0x20f0, 1},
+ {0x302a, 0x302f, 1},
+ {0x3099, 0x309a, 1},
+ {0xfe00, 0xfe0f, 1},
+ {0xfe20, 0xfe26, 1},
+ {0x101fd, 0x101fd, 1},
+ {0x1d167, 0x1d169, 1},
+ {0x1d17b, 0x1d182, 1},
+ {0x1d185, 0x1d18b, 1},
+ {0x1d1aa, 0x1d1ad, 1},
+ {0xe0100, 0xe01ef, 1},
}
var _Telugu = []Range{
- Range{0x0c01, 0x0c03, 1},
- Range{0x0c05, 0x0c0c, 1},
- Range{0x0c0e, 0x0c10, 1},
- Range{0x0c12, 0x0c28, 1},
- Range{0x0c2a, 0x0c33, 1},
- Range{0x0c35, 0x0c39, 1},
- Range{0x0c3d, 0x0c44, 1},
- Range{0x0c46, 0x0c48, 1},
- Range{0x0c4a, 0x0c4d, 1},
- Range{0x0c55, 0x0c56, 1},
- Range{0x0c58, 0x0c59, 1},
- Range{0x0c60, 0x0c63, 1},
- Range{0x0c66, 0x0c6f, 1},
- Range{0x0c78, 0x0c7f, 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 _Samaritan = []Range{
- Range{0x0800, 0x082d, 1},
- Range{0x0830, 0x083e, 1},
+ {0x0800, 0x082d, 1},
+ {0x0830, 0x083e, 1},
}
var _Bopomofo = []Range{
- Range{0x3105, 0x312d, 1},
- Range{0x31a0, 0x31b7, 1},
+ {0x3105, 0x312d, 1},
+ {0x31a0, 0x31b7, 1},
}
var _Imperial_Aramaic = []Range{
- Range{0x10840, 0x10855, 1},
- Range{0x10857, 0x1085f, 1},
+ {0x10840, 0x10855, 1},
+ {0x10857, 0x1085f, 1},
}
var _Kaithi = []Range{
- Range{0x11080, 0x110c1, 1},
+ {0x11080, 0x110c1, 1},
}
var _Old_South_Arabian = []Range{
- Range{0x10a60, 0x10a7f, 1},
+ {0x10a60, 0x10a7f, 1},
}
var _Kayah_Li = []Range{
- Range{0xa900, 0xa92f, 1},
+ {0xa900, 0xa92f, 1},
}
var _New_Tai_Lue = []Range{
- Range{0x1980, 0x19ab, 1},
- Range{0x19b0, 0x19c9, 1},
- Range{0x19d0, 0x19da, 1},
- Range{0x19de, 0x19df, 1},
+ {0x1980, 0x19ab, 1},
+ {0x19b0, 0x19c9, 1},
+ {0x19d0, 0x19da, 1},
+ {0x19de, 0x19df, 1},
}
var _Tai_Le = []Range{
- Range{0x1950, 0x196d, 1},
- Range{0x1970, 0x1974, 1},
+ {0x1950, 0x196d, 1},
+ {0x1970, 0x1974, 1},
}
var _Kharoshthi = []Range{
- Range{0x10a00, 0x10a03, 1},
- Range{0x10a05, 0x10a06, 1},
- Range{0x10a0c, 0x10a13, 1},
- Range{0x10a15, 0x10a17, 1},
- Range{0x10a19, 0x10a33, 1},
- Range{0x10a38, 0x10a3a, 1},
- Range{0x10a3f, 0x10a47, 1},
- Range{0x10a50, 0x10a58, 1},
+ {0x10a00, 0x10a03, 1},
+ {0x10a05, 0x10a06, 1},
+ {0x10a0c, 0x10a13, 1},
+ {0x10a15, 0x10a17, 1},
+ {0x10a19, 0x10a33, 1},
+ {0x10a38, 0x10a3a, 1},
+ {0x10a3f, 0x10a47, 1},
+ {0x10a50, 0x10a58, 1},
}
var _Common = []Range{
- Range{0x0000, 0x0040, 1},
- Range{0x005b, 0x0060, 1},
- Range{0x007b, 0x00a9, 1},
- Range{0x00ab, 0x00b9, 1},
- Range{0x00bb, 0x00bf, 1},
- Range{0x00d7, 0x00d7, 1},
- Range{0x00f7, 0x00f7, 1},
- Range{0x02b9, 0x02df, 1},
- Range{0x02e5, 0x02ff, 1},
- Range{0x0374, 0x0374, 1},
- Range{0x037e, 0x037e, 1},
- Range{0x0385, 0x0385, 1},
- Range{0x0387, 0x0387, 1},
- Range{0x0589, 0x0589, 1},
- Range{0x0600, 0x0603, 1},
- Range{0x060c, 0x060c, 1},
- Range{0x061b, 0x061b, 1},
- Range{0x061f, 0x061f, 1},
- Range{0x0640, 0x0640, 1},
- Range{0x0660, 0x0669, 1},
- Range{0x06dd, 0x06dd, 1},
- Range{0x0964, 0x0965, 1},
- Range{0x0970, 0x0970, 1},
- Range{0x0cf1, 0x0cf2, 1},
- Range{0x0e3f, 0x0e3f, 1},
- Range{0x0fd5, 0x0fd8, 1},
- Range{0x10fb, 0x10fb, 1},
- Range{0x16eb, 0x16ed, 1},
- Range{0x1735, 0x1736, 1},
- Range{0x1802, 0x1803, 1},
- Range{0x1805, 0x1805, 1},
- Range{0x1cd3, 0x1cd3, 1},
- Range{0x1ce1, 0x1ce1, 1},
- Range{0x1ce9, 0x1cec, 1},
- Range{0x1cee, 0x1cf2, 1},
- Range{0x2000, 0x200b, 1},
- Range{0x200e, 0x2064, 1},
- Range{0x206a, 0x2070, 1},
- Range{0x2074, 0x207e, 1},
- Range{0x2080, 0x208e, 1},
- Range{0x20a0, 0x20b8, 1},
- Range{0x2100, 0x2125, 1},
- Range{0x2127, 0x2129, 1},
- Range{0x212c, 0x2131, 1},
- Range{0x2133, 0x214d, 1},
- Range{0x214f, 0x215f, 1},
- Range{0x2189, 0x2189, 1},
- Range{0x2190, 0x23e8, 1},
- Range{0x2400, 0x2426, 1},
- Range{0x2440, 0x244a, 1},
- Range{0x2460, 0x26cd, 1},
- Range{0x26cf, 0x26e1, 1},
- Range{0x26e3, 0x26e3, 1},
- Range{0x26e8, 0x26ff, 1},
- Range{0x2701, 0x2704, 1},
- Range{0x2706, 0x2709, 1},
- Range{0x270c, 0x2727, 1},
- Range{0x2729, 0x274b, 1},
- Range{0x274d, 0x274d, 1},
- Range{0x274f, 0x2752, 1},
- Range{0x2756, 0x275e, 1},
- Range{0x2761, 0x2794, 1},
- Range{0x2798, 0x27af, 1},
- Range{0x27b1, 0x27be, 1},
- Range{0x27c0, 0x27ca, 1},
- Range{0x27cc, 0x27cc, 1},
- Range{0x27d0, 0x27ff, 1},
- Range{0x2900, 0x2b4c, 1},
- Range{0x2b50, 0x2b59, 1},
- Range{0x2e00, 0x2e31, 1},
- Range{0x2ff0, 0x2ffb, 1},
- Range{0x3000, 0x3004, 1},
- Range{0x3006, 0x3006, 1},
- Range{0x3008, 0x3020, 1},
- Range{0x3030, 0x3037, 1},
- Range{0x303c, 0x303f, 1},
- Range{0x309b, 0x309c, 1},
- Range{0x30a0, 0x30a0, 1},
- Range{0x30fb, 0x30fc, 1},
- Range{0x3190, 0x319f, 1},
- Range{0x31c0, 0x31e3, 1},
- Range{0x3220, 0x325f, 1},
- Range{0x327f, 0x32cf, 1},
- Range{0x3358, 0x33ff, 1},
- Range{0x4dc0, 0x4dff, 1},
- Range{0xa700, 0xa721, 1},
- Range{0xa788, 0xa78a, 1},
- Range{0xa830, 0xa839, 1},
- Range{0xfd3e, 0xfd3f, 1},
- Range{0xfdfd, 0xfdfd, 1},
- Range{0xfe10, 0xfe19, 1},
- Range{0xfe30, 0xfe52, 1},
- Range{0xfe54, 0xfe66, 1},
- Range{0xfe68, 0xfe6b, 1},
- Range{0xfeff, 0xfeff, 1},
- Range{0xff01, 0xff20, 1},
- Range{0xff3b, 0xff40, 1},
- Range{0xff5b, 0xff65, 1},
- Range{0xff70, 0xff70, 1},
- Range{0xff9e, 0xff9f, 1},
- Range{0xffe0, 0xffe6, 1},
- Range{0xffe8, 0xffee, 1},
- Range{0xfff9, 0xfffd, 1},
- Range{0x10100, 0x10102, 1},
- Range{0x10107, 0x10133, 1},
- Range{0x10137, 0x1013f, 1},
- Range{0x10190, 0x1019b, 1},
- Range{0x101d0, 0x101fc, 1},
- Range{0x1d000, 0x1d0f5, 1},
- Range{0x1d100, 0x1d126, 1},
- Range{0x1d129, 0x1d166, 1},
- Range{0x1d16a, 0x1d17a, 1},
- Range{0x1d183, 0x1d184, 1},
- Range{0x1d18c, 0x1d1a9, 1},
- Range{0x1d1ae, 0x1d1dd, 1},
- Range{0x1d300, 0x1d356, 1},
- Range{0x1d360, 0x1d371, 1},
- Range{0x1d400, 0x1d454, 1},
- Range{0x1d456, 0x1d49c, 1},
- Range{0x1d49e, 0x1d49f, 1},
- Range{0x1d4a2, 0x1d4a2, 1},
- Range{0x1d4a5, 0x1d4a6, 1},
- Range{0x1d4a9, 0x1d4ac, 1},
- Range{0x1d4ae, 0x1d4b9, 1},
- Range{0x1d4bb, 0x1d4bb, 1},
- Range{0x1d4bd, 0x1d4c3, 1},
- Range{0x1d4c5, 0x1d505, 1},
- Range{0x1d507, 0x1d50a, 1},
- Range{0x1d50d, 0x1d514, 1},
- Range{0x1d516, 0x1d51c, 1},
- Range{0x1d51e, 0x1d539, 1},
- Range{0x1d53b, 0x1d53e, 1},
- Range{0x1d540, 0x1d544, 1},
- Range{0x1d546, 0x1d546, 1},
- Range{0x1d54a, 0x1d550, 1},
- Range{0x1d552, 0x1d6a5, 1},
- Range{0x1d6a8, 0x1d7cb, 1},
- Range{0x1d7ce, 0x1d7ff, 1},
- Range{0x1f000, 0x1f02b, 1},
- Range{0x1f030, 0x1f093, 1},
- Range{0x1f100, 0x1f10a, 1},
- Range{0x1f110, 0x1f12e, 1},
- Range{0x1f131, 0x1f131, 1},
- Range{0x1f13d, 0x1f13d, 1},
- Range{0x1f13f, 0x1f13f, 1},
- Range{0x1f142, 0x1f142, 1},
- Range{0x1f146, 0x1f146, 1},
- Range{0x1f14a, 0x1f14e, 1},
- Range{0x1f157, 0x1f157, 1},
- Range{0x1f15f, 0x1f15f, 1},
- Range{0x1f179, 0x1f179, 1},
- Range{0x1f17b, 0x1f17c, 1},
- Range{0x1f17f, 0x1f17f, 1},
- Range{0x1f18a, 0x1f18d, 1},
- Range{0x1f190, 0x1f190, 1},
- Range{0x1f210, 0x1f231, 1},
- Range{0x1f240, 0x1f248, 1},
- Range{0xe0001, 0xe0001, 1},
- Range{0xe0020, 0xe007f, 1},
+ {0x0000, 0x0040, 1},
+ {0x005b, 0x0060, 1},
+ {0x007b, 0x00a9, 1},
+ {0x00ab, 0x00b9, 1},
+ {0x00bb, 0x00bf, 1},
+ {0x00d7, 0x00d7, 1},
+ {0x00f7, 0x00f7, 1},
+ {0x02b9, 0x02df, 1},
+ {0x02e5, 0x02ff, 1},
+ {0x0374, 0x0374, 1},
+ {0x037e, 0x037e, 1},
+ {0x0385, 0x0385, 1},
+ {0x0387, 0x0387, 1},
+ {0x0589, 0x0589, 1},
+ {0x0600, 0x0603, 1},
+ {0x060c, 0x060c, 1},
+ {0x061b, 0x061b, 1},
+ {0x061f, 0x061f, 1},
+ {0x0640, 0x0640, 1},
+ {0x0660, 0x0669, 1},
+ {0x06dd, 0x06dd, 1},
+ {0x0964, 0x0965, 1},
+ {0x0970, 0x0970, 1},
+ {0x0cf1, 0x0cf2, 1},
+ {0x0e3f, 0x0e3f, 1},
+ {0x0fd5, 0x0fd8, 1},
+ {0x10fb, 0x10fb, 1},
+ {0x16eb, 0x16ed, 1},
+ {0x1735, 0x1736, 1},
+ {0x1802, 0x1803, 1},
+ {0x1805, 0x1805, 1},
+ {0x1cd3, 0x1cd3, 1},
+ {0x1ce1, 0x1ce1, 1},
+ {0x1ce9, 0x1cec, 1},
+ {0x1cee, 0x1cf2, 1},
+ {0x2000, 0x200b, 1},
+ {0x200e, 0x2064, 1},
+ {0x206a, 0x2070, 1},
+ {0x2074, 0x207e, 1},
+ {0x2080, 0x208e, 1},
+ {0x20a0, 0x20b8, 1},
+ {0x2100, 0x2125, 1},
+ {0x2127, 0x2129, 1},
+ {0x212c, 0x2131, 1},
+ {0x2133, 0x214d, 1},
+ {0x214f, 0x215f, 1},
+ {0x2189, 0x2189, 1},
+ {0x2190, 0x23e8, 1},
+ {0x2400, 0x2426, 1},
+ {0x2440, 0x244a, 1},
+ {0x2460, 0x26cd, 1},
+ {0x26cf, 0x26e1, 1},
+ {0x26e3, 0x26e3, 1},
+ {0x26e8, 0x26ff, 1},
+ {0x2701, 0x2704, 1},
+ {0x2706, 0x2709, 1},
+ {0x270c, 0x2727, 1},
+ {0x2729, 0x274b, 1},
+ {0x274d, 0x274d, 1},
+ {0x274f, 0x2752, 1},
+ {0x2756, 0x275e, 1},
+ {0x2761, 0x2794, 1},
+ {0x2798, 0x27af, 1},
+ {0x27b1, 0x27be, 1},
+ {0x27c0, 0x27ca, 1},
+ {0x27cc, 0x27cc, 1},
+ {0x27d0, 0x27ff, 1},
+ {0x2900, 0x2b4c, 1},
+ {0x2b50, 0x2b59, 1},
+ {0x2e00, 0x2e31, 1},
+ {0x2ff0, 0x2ffb, 1},
+ {0x3000, 0x3004, 1},
+ {0x3006, 0x3006, 1},
+ {0x3008, 0x3020, 1},
+ {0x3030, 0x3037, 1},
+ {0x303c, 0x303f, 1},
+ {0x309b, 0x309c, 1},
+ {0x30a0, 0x30a0, 1},
+ {0x30fb, 0x30fc, 1},
+ {0x3190, 0x319f, 1},
+ {0x31c0, 0x31e3, 1},
+ {0x3220, 0x325f, 1},
+ {0x327f, 0x32cf, 1},
+ {0x3358, 0x33ff, 1},
+ {0x4dc0, 0x4dff, 1},
+ {0xa700, 0xa721, 1},
+ {0xa788, 0xa78a, 1},
+ {0xa830, 0xa839, 1},
+ {0xfd3e, 0xfd3f, 1},
+ {0xfdfd, 0xfdfd, 1},
+ {0xfe10, 0xfe19, 1},
+ {0xfe30, 0xfe52, 1},
+ {0xfe54, 0xfe66, 1},
+ {0xfe68, 0xfe6b, 1},
+ {0xfeff, 0xfeff, 1},
+ {0xff01, 0xff20, 1},
+ {0xff3b, 0xff40, 1},
+ {0xff5b, 0xff65, 1},
+ {0xff70, 0xff70, 1},
+ {0xff9e, 0xff9f, 1},
+ {0xffe0, 0xffe6, 1},
+ {0xffe8, 0xffee, 1},
+ {0xfff9, 0xfffd, 1},
+ {0x10100, 0x10102, 1},
+ {0x10107, 0x10133, 1},
+ {0x10137, 0x1013f, 1},
+ {0x10190, 0x1019b, 1},
+ {0x101d0, 0x101fc, 1},
+ {0x1d000, 0x1d0f5, 1},
+ {0x1d100, 0x1d126, 1},
+ {0x1d129, 0x1d166, 1},
+ {0x1d16a, 0x1d17a, 1},
+ {0x1d183, 0x1d184, 1},
+ {0x1d18c, 0x1d1a9, 1},
+ {0x1d1ae, 0x1d1dd, 1},
+ {0x1d300, 0x1d356, 1},
+ {0x1d360, 0x1d371, 1},
+ {0x1d400, 0x1d454, 1},
+ {0x1d456, 0x1d49c, 1},
+ {0x1d49e, 0x1d49f, 1},
+ {0x1d4a2, 0x1d4a2, 1},
+ {0x1d4a5, 0x1d4a6, 1},
+ {0x1d4a9, 0x1d4ac, 1},
+ {0x1d4ae, 0x1d4b9, 1},
+ {0x1d4bb, 0x1d4bb, 1},
+ {0x1d4bd, 0x1d4c3, 1},
+ {0x1d4c5, 0x1d505, 1},
+ {0x1d507, 0x1d50a, 1},
+ {0x1d50d, 0x1d514, 1},
+ {0x1d516, 0x1d51c, 1},
+ {0x1d51e, 0x1d539, 1},
+ {0x1d53b, 0x1d53e, 1},
+ {0x1d540, 0x1d544, 1},
+ {0x1d546, 0x1d546, 1},
+ {0x1d54a, 0x1d550, 1},
+ {0x1d552, 0x1d6a5, 1},
+ {0x1d6a8, 0x1d7cb, 1},
+ {0x1d7ce, 0x1d7ff, 1},
+ {0x1f000, 0x1f02b, 1},
+ {0x1f030, 0x1f093, 1},
+ {0x1f100, 0x1f10a, 1},
+ {0x1f110, 0x1f12e, 1},
+ {0x1f131, 0x1f131, 1},
+ {0x1f13d, 0x1f13d, 1},
+ {0x1f13f, 0x1f13f, 1},
+ {0x1f142, 0x1f142, 1},
+ {0x1f146, 0x1f146, 1},
+ {0x1f14a, 0x1f14e, 1},
+ {0x1f157, 0x1f157, 1},
+ {0x1f15f, 0x1f15f, 1},
+ {0x1f179, 0x1f179, 1},
+ {0x1f17b, 0x1f17c, 1},
+ {0x1f17f, 0x1f17f, 1},
+ {0x1f18a, 0x1f18d, 1},
+ {0x1f190, 0x1f190, 1},
+ {0x1f210, 0x1f231, 1},
+ {0x1f240, 0x1f248, 1},
+ {0xe0001, 0xe0001, 1},
+ {0xe0020, 0xe007f, 1},
}
var _Kannada = []Range{
- Range{0x0c82, 0x0c83, 1},
- Range{0x0c85, 0x0c8c, 1},
- Range{0x0c8e, 0x0c90, 1},
- Range{0x0c92, 0x0ca8, 1},
- Range{0x0caa, 0x0cb3, 1},
- Range{0x0cb5, 0x0cb9, 1},
- Range{0x0cbc, 0x0cc4, 1},
- Range{0x0cc6, 0x0cc8, 1},
- Range{0x0cca, 0x0ccd, 1},
- Range{0x0cd5, 0x0cd6, 1},
- Range{0x0cde, 0x0cde, 1},
- Range{0x0ce0, 0x0ce3, 1},
- Range{0x0ce6, 0x0cef, 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},
}
var _Old_Turkic = []Range{
- Range{0x10c00, 0x10c48, 1},
+ {0x10c00, 0x10c48, 1},
}
var _Tamil = []Range{
- Range{0x0b82, 0x0b83, 1},
- Range{0x0b85, 0x0b8a, 1},
- Range{0x0b8e, 0x0b90, 1},
- Range{0x0b92, 0x0b95, 1},
- Range{0x0b99, 0x0b9a, 1},
- Range{0x0b9c, 0x0b9c, 1},
- Range{0x0b9e, 0x0b9f, 1},
- Range{0x0ba3, 0x0ba4, 1},
- Range{0x0ba8, 0x0baa, 1},
- Range{0x0bae, 0x0bb9, 1},
- Range{0x0bbe, 0x0bc2, 1},
- Range{0x0bc6, 0x0bc8, 1},
- Range{0x0bca, 0x0bcd, 1},
- Range{0x0bd0, 0x0bd0, 1},
- Range{0x0bd7, 0x0bd7, 1},
- Range{0x0be6, 0x0bfa, 1},
+ {0x0b82, 0x0b83, 1},
+ {0x0b85, 0x0b8a, 1},
+ {0x0b8e, 0x0b90, 1},
+ {0x0b92, 0x0b95, 1},
+ {0x0b99, 0x0b9a, 1},
+ {0x0b9c, 0x0b9c, 1},
+ {0x0b9e, 0x0b9f, 1},
+ {0x0ba3, 0x0ba4, 1},
+ {0x0ba8, 0x0baa, 1},
+ {0x0bae, 0x0bb9, 1},
+ {0x0bbe, 0x0bc2, 1},
+ {0x0bc6, 0x0bc8, 1},
+ {0x0bca, 0x0bcd, 1},
+ {0x0bd0, 0x0bd0, 1},
+ {0x0bd7, 0x0bd7, 1},
+ {0x0be6, 0x0bfa, 1},
}
var _Tagalog = []Range{
- Range{0x1700, 0x170c, 1},
- Range{0x170e, 0x1714, 1},
+ {0x1700, 0x170c, 1},
+ {0x170e, 0x1714, 1},
}
var _Arabic = []Range{
- Range{0x0606, 0x060b, 1},
- Range{0x060d, 0x061a, 1},
- Range{0x061e, 0x061e, 1},
- Range{0x0621, 0x063f, 1},
- Range{0x0641, 0x064a, 1},
- Range{0x0656, 0x065e, 1},
- Range{0x066a, 0x066f, 1},
- Range{0x0671, 0x06dc, 1},
- Range{0x06de, 0x06ff, 1},
- Range{0x0750, 0x077f, 1},
- Range{0xfb50, 0xfbb1, 1},
- Range{0xfbd3, 0xfd3d, 1},
- Range{0xfd50, 0xfd8f, 1},
- Range{0xfd92, 0xfdc7, 1},
- Range{0xfdf0, 0xfdfc, 1},
- Range{0xfe70, 0xfe74, 1},
- Range{0xfe76, 0xfefc, 1},
- Range{0x10e60, 0x10e7e, 1},
+ {0x0606, 0x060b, 1},
+ {0x060d, 0x061a, 1},
+ {0x061e, 0x061e, 1},
+ {0x0621, 0x063f, 1},
+ {0x0641, 0x064a, 1},
+ {0x0656, 0x065e, 1},
+ {0x066a, 0x066f, 1},
+ {0x0671, 0x06dc, 1},
+ {0x06de, 0x06ff, 1},
+ {0x0750, 0x077f, 1},
+ {0xfb50, 0xfbb1, 1},
+ {0xfbd3, 0xfd3d, 1},
+ {0xfd50, 0xfd8f, 1},
+ {0xfd92, 0xfdc7, 1},
+ {0xfdf0, 0xfdfc, 1},
+ {0xfe70, 0xfe74, 1},
+ {0xfe76, 0xfefc, 1},
+ {0x10e60, 0x10e7e, 1},
}
var _Tagbanwa = []Range{
- Range{0x1760, 0x176c, 1},
- Range{0x176e, 0x1770, 1},
- Range{0x1772, 0x1773, 1},
+ {0x1760, 0x176c, 1},
+ {0x176e, 0x1770, 1},
+ {0x1772, 0x1773, 1},
}
var _Canadian_Aboriginal = []Range{
- Range{0x1400, 0x167f, 1},
- Range{0x18b0, 0x18f5, 1},
+ {0x1400, 0x167f, 1},
+ {0x18b0, 0x18f5, 1},
}
var _Tibetan = []Range{
- Range{0x0f00, 0x0f47, 1},
- Range{0x0f49, 0x0f6c, 1},
- Range{0x0f71, 0x0f8b, 1},
- Range{0x0f90, 0x0f97, 1},
- Range{0x0f99, 0x0fbc, 1},
- Range{0x0fbe, 0x0fcc, 1},
- Range{0x0fce, 0x0fd4, 1},
+ {0x0f00, 0x0f47, 1},
+ {0x0f49, 0x0f6c, 1},
+ {0x0f71, 0x0f8b, 1},
+ {0x0f90, 0x0f97, 1},
+ {0x0f99, 0x0fbc, 1},
+ {0x0fbe, 0x0fcc, 1},
+ {0x0fce, 0x0fd4, 1},
}
var _Coptic = []Range{
- Range{0x03e2, 0x03ef, 1},
- Range{0x2c80, 0x2cf1, 1},
- Range{0x2cf9, 0x2cff, 1},
+ {0x03e2, 0x03ef, 1},
+ {0x2c80, 0x2cf1, 1},
+ {0x2cf9, 0x2cff, 1},
}
var _Hiragana = []Range{
- Range{0x3041, 0x3096, 1},
- Range{0x309d, 0x309f, 1},
- Range{0x1f200, 0x1f200, 1},
+ {0x3041, 0x3096, 1},
+ {0x309d, 0x309f, 1},
+ {0x1f200, 0x1f200, 1},
}
var _Limbu = []Range{
- Range{0x1900, 0x191c, 1},
- Range{0x1920, 0x192b, 1},
- Range{0x1930, 0x193b, 1},
- Range{0x1940, 0x1940, 1},
- Range{0x1944, 0x194f, 1},
+ {0x1900, 0x191c, 1},
+ {0x1920, 0x192b, 1},
+ {0x1930, 0x193b, 1},
+ {0x1940, 0x1940, 1},
+ {0x1944, 0x194f, 1},
}
var _Egyptian_Hieroglyphs = []Range{
- Range{0x13000, 0x1342e, 1},
+ {0x13000, 0x1342e, 1},
}
var _Avestan = []Range{
- Range{0x10b00, 0x10b35, 1},
- Range{0x10b39, 0x10b3f, 1},
+ {0x10b00, 0x10b35, 1},
+ {0x10b39, 0x10b3f, 1},
}
var _Myanmar = []Range{
- Range{0x1000, 0x109f, 1},
- Range{0xaa60, 0xaa7b, 1},
+ {0x1000, 0x109f, 1},
+ {0xaa60, 0xaa7b, 1},
}
var _Armenian = []Range{
- Range{0x0531, 0x0556, 1},
- Range{0x0559, 0x055f, 1},
- Range{0x0561, 0x0587, 1},
- Range{0x058a, 0x058a, 1},
- Range{0xfb13, 0xfb17, 1},
+ {0x0531, 0x0556, 1},
+ {0x0559, 0x055f, 1},
+ {0x0561, 0x0587, 1},
+ {0x058a, 0x058a, 1},
+ {0xfb13, 0xfb17, 1},
}
var _Sinhala = []Range{
- Range{0x0d82, 0x0d83, 1},
- Range{0x0d85, 0x0d96, 1},
- Range{0x0d9a, 0x0db1, 1},
- Range{0x0db3, 0x0dbb, 1},
- Range{0x0dbd, 0x0dbd, 1},
- Range{0x0dc0, 0x0dc6, 1},
- Range{0x0dca, 0x0dca, 1},
- Range{0x0dcf, 0x0dd4, 1},
- Range{0x0dd6, 0x0dd6, 1},
- Range{0x0dd8, 0x0ddf, 1},
- Range{0x0df2, 0x0df4, 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 _Bengali = []Range{
- Range{0x0981, 0x0983, 1},
- Range{0x0985, 0x098c, 1},
- Range{0x098f, 0x0990, 1},
- Range{0x0993, 0x09a8, 1},
- Range{0x09aa, 0x09b0, 1},
- Range{0x09b2, 0x09b2, 1},
- Range{0x09b6, 0x09b9, 1},
- Range{0x09bc, 0x09c4, 1},
- Range{0x09c7, 0x09c8, 1},
- Range{0x09cb, 0x09ce, 1},
- Range{0x09d7, 0x09d7, 1},
- Range{0x09dc, 0x09dd, 1},
- Range{0x09df, 0x09e3, 1},
- Range{0x09e6, 0x09fb, 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},
}
var _Greek = []Range{
- Range{0x0370, 0x0373, 1},
- Range{0x0375, 0x0377, 1},
- Range{0x037a, 0x037d, 1},
- Range{0x0384, 0x0384, 1},
- Range{0x0386, 0x0386, 1},
- Range{0x0388, 0x038a, 1},
- Range{0x038c, 0x038c, 1},
- Range{0x038e, 0x03a1, 1},
- Range{0x03a3, 0x03e1, 1},
- Range{0x03f0, 0x03ff, 1},
- Range{0x1d26, 0x1d2a, 1},
- Range{0x1d5d, 0x1d61, 1},
- Range{0x1d66, 0x1d6a, 1},
- Range{0x1dbf, 0x1dbf, 1},
- Range{0x1f00, 0x1f15, 1},
- Range{0x1f18, 0x1f1d, 1},
- Range{0x1f20, 0x1f45, 1},
- Range{0x1f48, 0x1f4d, 1},
- Range{0x1f50, 0x1f57, 1},
- Range{0x1f59, 0x1f59, 1},
- Range{0x1f5b, 0x1f5b, 1},
- Range{0x1f5d, 0x1f5d, 1},
- Range{0x1f5f, 0x1f7d, 1},
- Range{0x1f80, 0x1fb4, 1},
- Range{0x1fb6, 0x1fc4, 1},
- Range{0x1fc6, 0x1fd3, 1},
- Range{0x1fd6, 0x1fdb, 1},
- Range{0x1fdd, 0x1fef, 1},
- Range{0x1ff2, 0x1ff4, 1},
- Range{0x1ff6, 0x1ffe, 1},
- Range{0x2126, 0x2126, 1},
- Range{0x10140, 0x1018a, 1},
- Range{0x1d200, 0x1d245, 1},
+ {0x0370, 0x0373, 1},
+ {0x0375, 0x0377, 1},
+ {0x037a, 0x037d, 1},
+ {0x0384, 0x0384, 1},
+ {0x0386, 0x0386, 1},
+ {0x0388, 0x038a, 1},
+ {0x038c, 0x038c, 1},
+ {0x038e, 0x03a1, 1},
+ {0x03a3, 0x03e1, 1},
+ {0x03f0, 0x03ff, 1},
+ {0x1d26, 0x1d2a, 1},
+ {0x1d5d, 0x1d61, 1},
+ {0x1d66, 0x1d6a, 1},
+ {0x1dbf, 0x1dbf, 1},
+ {0x1f00, 0x1f15, 1},
+ {0x1f18, 0x1f1d, 1},
+ {0x1f20, 0x1f45, 1},
+ {0x1f48, 0x1f4d, 1},
+ {0x1f50, 0x1f57, 1},
+ {0x1f59, 0x1f59, 1},
+ {0x1f5b, 0x1f5b, 1},
+ {0x1f5d, 0x1f5d, 1},
+ {0x1f5f, 0x1f7d, 1},
+ {0x1f80, 0x1fb4, 1},
+ {0x1fb6, 0x1fc4, 1},
+ {0x1fc6, 0x1fd3, 1},
+ {0x1fd6, 0x1fdb, 1},
+ {0x1fdd, 0x1fef, 1},
+ {0x1ff2, 0x1ff4, 1},
+ {0x1ff6, 0x1ffe, 1},
+ {0x2126, 0x2126, 1},
+ {0x10140, 0x1018a, 1},
+ {0x1d200, 0x1d245, 1},
}
var _Cham = []Range{
- Range{0xaa00, 0xaa36, 1},
- Range{0xaa40, 0xaa4d, 1},
- Range{0xaa50, 0xaa59, 1},
- Range{0xaa5c, 0xaa5f, 1},
+ {0xaa00, 0xaa36, 1},
+ {0xaa40, 0xaa4d, 1},
+ {0xaa50, 0xaa59, 1},
+ {0xaa5c, 0xaa5f, 1},
}
var _Hebrew = []Range{
- Range{0x0591, 0x05c7, 1},
- Range{0x05d0, 0x05ea, 1},
- Range{0x05f0, 0x05f4, 1},
- Range{0xfb1d, 0xfb36, 1},
- Range{0xfb38, 0xfb3c, 1},
- Range{0xfb3e, 0xfb3e, 1},
- Range{0xfb40, 0xfb41, 1},
- Range{0xfb43, 0xfb44, 1},
- Range{0xfb46, 0xfb4f, 1},
+ {0x0591, 0x05c7, 1},
+ {0x05d0, 0x05ea, 1},
+ {0x05f0, 0x05f4, 1},
+ {0xfb1d, 0xfb36, 1},
+ {0xfb38, 0xfb3c, 1},
+ {0xfb3e, 0xfb3e, 1},
+ {0xfb40, 0xfb41, 1},
+ {0xfb43, 0xfb44, 1},
+ {0xfb46, 0xfb4f, 1},
}
var _Meetei_Mayek = []Range{
- Range{0xabc0, 0xabed, 1},
- Range{0xabf0, 0xabf9, 1},
+ {0xabc0, 0xabed, 1},
+ {0xabf0, 0xabf9, 1},
}
var _Saurashtra = []Range{
- Range{0xa880, 0xa8c4, 1},
- Range{0xa8ce, 0xa8d9, 1},
+ {0xa880, 0xa8c4, 1},
+ {0xa8ce, 0xa8d9, 1},
}
var _Hangul = []Range{
- Range{0x1100, 0x11ff, 1},
- Range{0x3131, 0x318e, 1},
- Range{0x3200, 0x321e, 1},
- Range{0x3260, 0x327e, 1},
- Range{0xa960, 0xa97c, 1},
- Range{0xac00, 0xd7a3, 1},
- Range{0xd7b0, 0xd7c6, 1},
- Range{0xd7cb, 0xd7fb, 1},
- Range{0xffa0, 0xffbe, 1},
- Range{0xffc2, 0xffc7, 1},
- Range{0xffca, 0xffcf, 1},
- Range{0xffd2, 0xffd7, 1},
- Range{0xffda, 0xffdc, 1},
+ {0x1100, 0x11ff, 1},
+ {0x3131, 0x318e, 1},
+ {0x3200, 0x321e, 1},
+ {0x3260, 0x327e, 1},
+ {0xa960, 0xa97c, 1},
+ {0xac00, 0xd7a3, 1},
+ {0xd7b0, 0xd7c6, 1},
+ {0xd7cb, 0xd7fb, 1},
+ {0xffa0, 0xffbe, 1},
+ {0xffc2, 0xffc7, 1},
+ {0xffca, 0xffcf, 1},
+ {0xffd2, 0xffd7, 1},
+ {0xffda, 0xffdc, 1},
}
var _Runic = []Range{
- Range{0x16a0, 0x16ea, 1},
- Range{0x16ee, 0x16f0, 1},
+ {0x16a0, 0x16ea, 1},
+ {0x16ee, 0x16f0, 1},
}
var _Deseret = []Range{
- Range{0x10400, 0x1044f, 1},
+ {0x10400, 0x1044f, 1},
}
var _Lisu = []Range{
- Range{0xa4d0, 0xa4ff, 1},
+ {0xa4d0, 0xa4ff, 1},
}
var _Sundanese = []Range{
- Range{0x1b80, 0x1baa, 1},
- Range{0x1bae, 0x1bb9, 1},
+ {0x1b80, 0x1baa, 1},
+ {0x1bae, 0x1bb9, 1},
}
var _Glagolitic = []Range{
- Range{0x2c00, 0x2c2e, 1},
- Range{0x2c30, 0x2c5e, 1},
+ {0x2c00, 0x2c2e, 1},
+ {0x2c30, 0x2c5e, 1},
}
var _Oriya = []Range{
- Range{0x0b01, 0x0b03, 1},
- Range{0x0b05, 0x0b0c, 1},
- Range{0x0b0f, 0x0b10, 1},
- Range{0x0b13, 0x0b28, 1},
- Range{0x0b2a, 0x0b30, 1},
- Range{0x0b32, 0x0b33, 1},
- Range{0x0b35, 0x0b39, 1},
- Range{0x0b3c, 0x0b44, 1},
- Range{0x0b47, 0x0b48, 1},
- Range{0x0b4b, 0x0b4d, 1},
- Range{0x0b56, 0x0b57, 1},
- Range{0x0b5c, 0x0b5d, 1},
- Range{0x0b5f, 0x0b63, 1},
- Range{0x0b66, 0x0b71, 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, 0x0b71, 1},
}
var _Buhid = []Range{
- Range{0x1740, 0x1753, 1},
+ {0x1740, 0x1753, 1},
}
var _Ethiopic = []Range{
- Range{0x1200, 0x1248, 1},
- Range{0x124a, 0x124d, 1},
- Range{0x1250, 0x1256, 1},
- Range{0x1258, 0x1258, 1},
- Range{0x125a, 0x125d, 1},
- Range{0x1260, 0x1288, 1},
- Range{0x128a, 0x128d, 1},
- Range{0x1290, 0x12b0, 1},
- Range{0x12b2, 0x12b5, 1},
- Range{0x12b8, 0x12be, 1},
- Range{0x12c0, 0x12c0, 1},
- Range{0x12c2, 0x12c5, 1},
- Range{0x12c8, 0x12d6, 1},
- Range{0x12d8, 0x1310, 1},
- Range{0x1312, 0x1315, 1},
- Range{0x1318, 0x135a, 1},
- Range{0x135f, 0x137c, 1},
- Range{0x1380, 0x1399, 1},
- Range{0x2d80, 0x2d96, 1},
- Range{0x2da0, 0x2da6, 1},
- Range{0x2da8, 0x2dae, 1},
- Range{0x2db0, 0x2db6, 1},
- Range{0x2db8, 0x2dbe, 1},
- Range{0x2dc0, 0x2dc6, 1},
- Range{0x2dc8, 0x2dce, 1},
- Range{0x2dd0, 0x2dd6, 1},
- Range{0x2dd8, 0x2dde, 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},
+ {0x135f, 0x137c, 1},
+ {0x1380, 0x1399, 1},
+ {0x2d80, 0x2d96, 1},
+ {0x2da0, 0x2da6, 1},
+ {0x2da8, 0x2dae, 1},
+ {0x2db0, 0x2db6, 1},
+ {0x2db8, 0x2dbe, 1},
+ {0x2dc0, 0x2dc6, 1},
+ {0x2dc8, 0x2dce, 1},
+ {0x2dd0, 0x2dd6, 1},
+ {0x2dd8, 0x2dde, 1},
}
var _Javanese = []Range{
- Range{0xa980, 0xa9cd, 1},
- Range{0xa9cf, 0xa9d9, 1},
- Range{0xa9de, 0xa9df, 1},
+ {0xa980, 0xa9cd, 1},
+ {0xa9cf, 0xa9d9, 1},
+ {0xa9de, 0xa9df, 1},
}
var _Syloti_Nagri = []Range{
- Range{0xa800, 0xa82b, 1},
+ {0xa800, 0xa82b, 1},
}
var _Vai = []Range{
- Range{0xa500, 0xa62b, 1},
+ {0xa500, 0xa62b, 1},
}
var _Cherokee = []Range{
- Range{0x13a0, 0x13f4, 1},
+ {0x13a0, 0x13f4, 1},
}
var _Ogham = []Range{
- Range{0x1680, 0x169c, 1},
+ {0x1680, 0x169c, 1},
}
var _Syriac = []Range{
- Range{0x0700, 0x070d, 1},
- Range{0x070f, 0x074a, 1},
- Range{0x074d, 0x074f, 1},
+ {0x0700, 0x070d, 1},
+ {0x070f, 0x074a, 1},
+ {0x074d, 0x074f, 1},
}
var _Gurmukhi = []Range{
- Range{0x0a01, 0x0a03, 1},
- Range{0x0a05, 0x0a0a, 1},
- Range{0x0a0f, 0x0a10, 1},
- Range{0x0a13, 0x0a28, 1},
- Range{0x0a2a, 0x0a30, 1},
- Range{0x0a32, 0x0a33, 1},
- Range{0x0a35, 0x0a36, 1},
- Range{0x0a38, 0x0a39, 1},
- Range{0x0a3c, 0x0a3c, 1},
- Range{0x0a3e, 0x0a42, 1},
- Range{0x0a47, 0x0a48, 1},
- Range{0x0a4b, 0x0a4d, 1},
- Range{0x0a51, 0x0a51, 1},
- Range{0x0a59, 0x0a5c, 1},
- Range{0x0a5e, 0x0a5e, 1},
- Range{0x0a66, 0x0a75, 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 _Tai_Tham = []Range{
- Range{0x1a20, 0x1a5e, 1},
- Range{0x1a60, 0x1a7c, 1},
- Range{0x1a7f, 0x1a89, 1},
- Range{0x1a90, 0x1a99, 1},
- Range{0x1aa0, 0x1aad, 1},
+ {0x1a20, 0x1a5e, 1},
+ {0x1a60, 0x1a7c, 1},
+ {0x1a7f, 0x1a89, 1},
+ {0x1a90, 0x1a99, 1},
+ {0x1aa0, 0x1aad, 1},
}
var _Ol_Chiki = []Range{
- Range{0x1c50, 0x1c7f, 1},
+ {0x1c50, 0x1c7f, 1},
}
var _Mongolian = []Range{
- Range{0x1800, 0x1801, 1},
- Range{0x1804, 0x1804, 1},
- Range{0x1806, 0x180e, 1},
- Range{0x1810, 0x1819, 1},
- Range{0x1820, 0x1877, 1},
- Range{0x1880, 0x18aa, 1},
+ {0x1800, 0x1801, 1},
+ {0x1804, 0x1804, 1},
+ {0x1806, 0x180e, 1},
+ {0x1810, 0x1819, 1},
+ {0x1820, 0x1877, 1},
+ {0x1880, 0x18aa, 1},
}
var _Hanunoo = []Range{
- Range{0x1720, 0x1734, 1},
+ {0x1720, 0x1734, 1},
}
var _Cypriot = []Range{
- Range{0x10800, 0x10805, 1},
- Range{0x10808, 0x10808, 1},
- Range{0x1080a, 0x10835, 1},
- Range{0x10837, 0x10838, 1},
- Range{0x1083c, 0x1083c, 1},
- Range{0x1083f, 0x1083f, 1},
+ {0x10800, 0x10805, 1},
+ {0x10808, 0x10808, 1},
+ {0x1080a, 0x10835, 1},
+ {0x10837, 0x10838, 1},
+ {0x1083c, 0x1083c, 1},
+ {0x1083f, 0x1083f, 1},
}
var _Buginese = []Range{
- Range{0x1a00, 0x1a1b, 1},
- Range{0x1a1e, 0x1a1f, 1},
+ {0x1a00, 0x1a1b, 1},
+ {0x1a1e, 0x1a1f, 1},
}
var _Bamum = []Range{
- Range{0xa6a0, 0xa6f7, 1},
+ {0xa6a0, 0xa6f7, 1},
}
var _Lepcha = []Range{
- Range{0x1c00, 0x1c37, 1},
- Range{0x1c3b, 0x1c49, 1},
- Range{0x1c4d, 0x1c4f, 1},
+ {0x1c00, 0x1c37, 1},
+ {0x1c3b, 0x1c49, 1},
+ {0x1c4d, 0x1c4f, 1},
}
var _Thaana = []Range{
- Range{0x0780, 0x07b1, 1},
+ {0x0780, 0x07b1, 1},
}
var _Old_Persian = []Range{
- Range{0x103a0, 0x103c3, 1},
- Range{0x103c8, 0x103d5, 1},
+ {0x103a0, 0x103c3, 1},
+ {0x103c8, 0x103d5, 1},
}
var _Cuneiform = []Range{
- Range{0x12000, 0x1236e, 1},
- Range{0x12400, 0x12462, 1},
- Range{0x12470, 0x12473, 1},
+ {0x12000, 0x1236e, 1},
+ {0x12400, 0x12462, 1},
+ {0x12470, 0x12473, 1},
}
var _Rejang = []Range{
- Range{0xa930, 0xa953, 1},
- Range{0xa95f, 0xa95f, 1},
+ {0xa930, 0xa953, 1},
+ {0xa95f, 0xa95f, 1},
}
var _Georgian = []Range{
- Range{0x10a0, 0x10c5, 1},
- Range{0x10d0, 0x10fa, 1},
- Range{0x10fc, 0x10fc, 1},
- Range{0x2d00, 0x2d25, 1},
+ {0x10a0, 0x10c5, 1},
+ {0x10d0, 0x10fa, 1},
+ {0x10fc, 0x10fc, 1},
+ {0x2d00, 0x2d25, 1},
}
var _Shavian = []Range{
- Range{0x10450, 0x1047f, 1},
+ {0x10450, 0x1047f, 1},
}
var _Lycian = []Range{
- Range{0x10280, 0x1029c, 1},
+ {0x10280, 0x1029c, 1},
}
var _Nko = []Range{
- Range{0x07c0, 0x07fa, 1},
+ {0x07c0, 0x07fa, 1},
}
var _Yi = []Range{
- Range{0xa000, 0xa48c, 1},
- Range{0xa490, 0xa4c6, 1},
+ {0xa000, 0xa48c, 1},
+ {0xa490, 0xa4c6, 1},
}
var _Lao = []Range{
- Range{0x0e81, 0x0e82, 1},
- Range{0x0e84, 0x0e84, 1},
- Range{0x0e87, 0x0e88, 1},
- Range{0x0e8a, 0x0e8a, 1},
- Range{0x0e8d, 0x0e8d, 1},
- Range{0x0e94, 0x0e97, 1},
- Range{0x0e99, 0x0e9f, 1},
- Range{0x0ea1, 0x0ea3, 1},
- Range{0x0ea5, 0x0ea5, 1},
- Range{0x0ea7, 0x0ea7, 1},
- Range{0x0eaa, 0x0eab, 1},
- Range{0x0ead, 0x0eb9, 1},
- Range{0x0ebb, 0x0ebd, 1},
- Range{0x0ec0, 0x0ec4, 1},
- Range{0x0ec6, 0x0ec6, 1},
- Range{0x0ec8, 0x0ecd, 1},
- Range{0x0ed0, 0x0ed9, 1},
- Range{0x0edc, 0x0edd, 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 _Linear_B = []Range{
- Range{0x10000, 0x1000b, 1},
- Range{0x1000d, 0x10026, 1},
- Range{0x10028, 0x1003a, 1},
- Range{0x1003c, 0x1003d, 1},
- Range{0x1003f, 0x1004d, 1},
- Range{0x10050, 0x1005d, 1},
- Range{0x10080, 0x100fa, 1},
+ {0x10000, 0x1000b, 1},
+ {0x1000d, 0x10026, 1},
+ {0x10028, 0x1003a, 1},
+ {0x1003c, 0x1003d, 1},
+ {0x1003f, 0x1004d, 1},
+ {0x10050, 0x1005d, 1},
+ {0x10080, 0x100fa, 1},
}
var _Old_Italic = []Range{
- Range{0x10300, 0x1031e, 1},
- Range{0x10320, 0x10323, 1},
+ {0x10300, 0x1031e, 1},
+ {0x10320, 0x10323, 1},
}
var _Tai_Viet = []Range{
- Range{0xaa80, 0xaac2, 1},
- Range{0xaadb, 0xaadf, 1},
+ {0xaa80, 0xaac2, 1},
+ {0xaadb, 0xaadf, 1},
}
var _Devanagari = []Range{
- Range{0x0900, 0x0939, 1},
- Range{0x093c, 0x094e, 1},
- Range{0x0950, 0x0950, 1},
- Range{0x0953, 0x0955, 1},
- Range{0x0958, 0x0963, 1},
- Range{0x0966, 0x096f, 1},
- Range{0x0971, 0x0972, 1},
- Range{0x0979, 0x097f, 1},
- Range{0xa8e0, 0xa8fb, 1},
+ {0x0900, 0x0939, 1},
+ {0x093c, 0x094e, 1},
+ {0x0950, 0x0950, 1},
+ {0x0953, 0x0955, 1},
+ {0x0958, 0x0963, 1},
+ {0x0966, 0x096f, 1},
+ {0x0971, 0x0972, 1},
+ {0x0979, 0x097f, 1},
+ {0xa8e0, 0xa8fb, 1},
}
var _Lydian = []Range{
- Range{0x10920, 0x10939, 1},
- Range{0x1093f, 0x1093f, 1},
+ {0x10920, 0x10939, 1},
+ {0x1093f, 0x1093f, 1},
}
var _Tifinagh = []Range{
- Range{0x2d30, 0x2d65, 1},
- Range{0x2d6f, 0x2d6f, 1},
+ {0x2d30, 0x2d65, 1},
+ {0x2d6f, 0x2d6f, 1},
}
var _Ugaritic = []Range{
- Range{0x10380, 0x1039d, 1},
- Range{0x1039f, 0x1039f, 1},
+ {0x10380, 0x1039d, 1},
+ {0x1039f, 0x1039f, 1},
}
var _Thai = []Range{
- Range{0x0e01, 0x0e3a, 1},
- Range{0x0e40, 0x0e5b, 1},
+ {0x0e01, 0x0e3a, 1},
+ {0x0e40, 0x0e5b, 1},
}
var _Cyrillic = []Range{
- Range{0x0400, 0x0484, 1},
- Range{0x0487, 0x0525, 1},
- Range{0x1d2b, 0x1d2b, 1},
- Range{0x1d78, 0x1d78, 1},
- Range{0x2de0, 0x2dff, 1},
- Range{0xa640, 0xa65f, 1},
- Range{0xa662, 0xa673, 1},
- Range{0xa67c, 0xa697, 1},
+ {0x0400, 0x0484, 1},
+ {0x0487, 0x0525, 1},
+ {0x1d2b, 0x1d2b, 1},
+ {0x1d78, 0x1d78, 1},
+ {0x2de0, 0x2dff, 1},
+ {0xa640, 0xa65f, 1},
+ {0xa662, 0xa673, 1},
+ {0xa67c, 0xa697, 1},
}
var _Gujarati = []Range{
- Range{0x0a81, 0x0a83, 1},
- Range{0x0a85, 0x0a8d, 1},
- Range{0x0a8f, 0x0a91, 1},
- Range{0x0a93, 0x0aa8, 1},
- Range{0x0aaa, 0x0ab0, 1},
- Range{0x0ab2, 0x0ab3, 1},
- Range{0x0ab5, 0x0ab9, 1},
- Range{0x0abc, 0x0ac5, 1},
- Range{0x0ac7, 0x0ac9, 1},
- Range{0x0acb, 0x0acd, 1},
- Range{0x0ad0, 0x0ad0, 1},
- Range{0x0ae0, 0x0ae3, 1},
- Range{0x0ae6, 0x0aef, 1},
- Range{0x0af1, 0x0af1, 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 _Carian = []Range{
- Range{0x102a0, 0x102d0, 1},
+ {0x102a0, 0x102d0, 1},
}
var _Phoenician = []Range{
- Range{0x10900, 0x1091b, 1},
- Range{0x1091f, 0x1091f, 1},
+ {0x10900, 0x1091b, 1},
+ {0x1091f, 0x1091f, 1},
}
var _Balinese = []Range{
- Range{0x1b00, 0x1b4b, 1},
- Range{0x1b50, 0x1b7c, 1},
+ {0x1b00, 0x1b4b, 1},
+ {0x1b50, 0x1b7c, 1},
}
var _Braille = []Range{
- Range{0x2800, 0x28ff, 1},
+ {0x2800, 0x28ff, 1},
}
var _Han = []Range{
- Range{0x2e80, 0x2e99, 1},
- Range{0x2e9b, 0x2ef3, 1},
- Range{0x2f00, 0x2fd5, 1},
- Range{0x3005, 0x3005, 1},
- Range{0x3007, 0x3007, 1},
- Range{0x3021, 0x3029, 1},
- Range{0x3038, 0x303b, 1},
- Range{0x3400, 0x4db5, 1},
- Range{0x4e00, 0x9fcb, 1},
- Range{0xf900, 0xfa2d, 1},
- Range{0xfa30, 0xfa6d, 1},
- Range{0xfa70, 0xfad9, 1},
- Range{0x20000, 0x2a6d6, 1},
- Range{0x2a700, 0x2b734, 1},
- Range{0x2f800, 0x2fa1d, 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},
+ {0x20000, 0x2a6d6, 1},
+ {0x2a700, 0x2b734, 1},
+ {0x2f800, 0x2fa1d, 1},
}
var _Gothic = []Range{
- Range{0x10330, 0x1034a, 1},
+ {0x10330, 0x1034a, 1},
}
var (
@@ -3125,821 +3125,821 @@ var Properties = map[string][]Range{
}
var _Pattern_Syntax = []Range{
- Range{0x0021, 0x002f, 1},
- Range{0x003a, 0x0040, 1},
- Range{0x005b, 0x005e, 1},
- Range{0x0060, 0x0060, 1},
- Range{0x007b, 0x007e, 1},
- Range{0x00a1, 0x00a7, 1},
- Range{0x00a9, 0x00a9, 1},
- Range{0x00ab, 0x00ac, 1},
- Range{0x00ae, 0x00ae, 1},
- Range{0x00b0, 0x00b1, 1},
- Range{0x00b6, 0x00b6, 1},
- Range{0x00bb, 0x00bb, 1},
- Range{0x00bf, 0x00bf, 1},
- Range{0x00d7, 0x00d7, 1},
- Range{0x00f7, 0x00f7, 1},
- Range{0x2010, 0x2027, 1},
- Range{0x2030, 0x203e, 1},
- Range{0x2041, 0x2053, 1},
- Range{0x2055, 0x205e, 1},
- Range{0x2190, 0x245f, 1},
- Range{0x2500, 0x2775, 1},
- Range{0x2794, 0x2bff, 1},
- Range{0x2e00, 0x2e7f, 1},
- Range{0x3001, 0x3003, 1},
- Range{0x3008, 0x3020, 1},
- Range{0x3030, 0x3030, 1},
- Range{0xfd3e, 0xfd3f, 1},
- Range{0xfe45, 0xfe46, 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 _Other_ID_Start = []Range{
- Range{0x2118, 0x2118, 1},
- Range{0x212e, 0x212e, 1},
- Range{0x309b, 0x309c, 1},
+ {0x2118, 0x2118, 1},
+ {0x212e, 0x212e, 1},
+ {0x309b, 0x309c, 1},
}
var _Pattern_White_Space = []Range{
- Range{0x0009, 0x000d, 1},
- Range{0x0020, 0x0020, 1},
- Range{0x0085, 0x0085, 1},
- Range{0x200e, 0x200f, 1},
- Range{0x2028, 0x2029, 1},
+ {0x0009, 0x000d, 1},
+ {0x0020, 0x0020, 1},
+ {0x0085, 0x0085, 1},
+ {0x200e, 0x200f, 1},
+ {0x2028, 0x2029, 1},
}
var _Other_Lowercase = []Range{
- Range{0x02b0, 0x02b8, 1},
- Range{0x02c0, 0x02c1, 1},
- Range{0x02e0, 0x02e4, 1},
- Range{0x0345, 0x0345, 1},
- Range{0x037a, 0x037a, 1},
- Range{0x1d2c, 0x1d61, 1},
- Range{0x1d78, 0x1d78, 1},
- Range{0x1d9b, 0x1dbf, 1},
- Range{0x2090, 0x2094, 1},
- Range{0x2170, 0x217f, 1},
- Range{0x24d0, 0x24e9, 1},
- Range{0x2c7d, 0x2c7d, 1},
- Range{0xa770, 0xa770, 1},
+ {0x02b0, 0x02b8, 1},
+ {0x02c0, 0x02c1, 1},
+ {0x02e0, 0x02e4, 1},
+ {0x0345, 0x0345, 1},
+ {0x037a, 0x037a, 1},
+ {0x1d2c, 0x1d61, 1},
+ {0x1d78, 0x1d78, 1},
+ {0x1d9b, 0x1dbf, 1},
+ {0x2090, 0x2094, 1},
+ {0x2170, 0x217f, 1},
+ {0x24d0, 0x24e9, 1},
+ {0x2c7d, 0x2c7d, 1},
+ {0xa770, 0xa770, 1},
}
var _Soft_Dotted = []Range{
- Range{0x0069, 0x006a, 1},
- Range{0x012f, 0x012f, 1},
- Range{0x0249, 0x0249, 1},
- Range{0x0268, 0x0268, 1},
- Range{0x029d, 0x029d, 1},
- Range{0x02b2, 0x02b2, 1},
- Range{0x03f3, 0x03f3, 1},
- Range{0x0456, 0x0456, 1},
- Range{0x0458, 0x0458, 1},
- Range{0x1d62, 0x1d62, 1},
- Range{0x1d96, 0x1d96, 1},
- Range{0x1da4, 0x1da4, 1},
- Range{0x1da8, 0x1da8, 1},
- Range{0x1e2d, 0x1e2d, 1},
- Range{0x1ecb, 0x1ecb, 1},
- Range{0x2071, 0x2071, 1},
- Range{0x2148, 0x2149, 1},
- Range{0x2c7c, 0x2c7c, 1},
- Range{0x1d422, 0x1d423, 1},
- Range{0x1d456, 0x1d457, 1},
- Range{0x1d48a, 0x1d48b, 1},
- Range{0x1d4be, 0x1d4bf, 1},
- Range{0x1d4f2, 0x1d4f3, 1},
- Range{0x1d526, 0x1d527, 1},
- Range{0x1d55a, 0x1d55b, 1},
- Range{0x1d58e, 0x1d58f, 1},
- Range{0x1d5c2, 0x1d5c3, 1},
- Range{0x1d5f6, 0x1d5f7, 1},
- Range{0x1d62a, 0x1d62b, 1},
- Range{0x1d65e, 0x1d65f, 1},
- Range{0x1d692, 0x1d693, 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},
+ {0x1d422, 0x1d423, 1},
+ {0x1d456, 0x1d457, 1},
+ {0x1d48a, 0x1d48b, 1},
+ {0x1d4be, 0x1d4bf, 1},
+ {0x1d4f2, 0x1d4f3, 1},
+ {0x1d526, 0x1d527, 1},
+ {0x1d55a, 0x1d55b, 1},
+ {0x1d58e, 0x1d58f, 1},
+ {0x1d5c2, 0x1d5c3, 1},
+ {0x1d5f6, 0x1d5f7, 1},
+ {0x1d62a, 0x1d62b, 1},
+ {0x1d65e, 0x1d65f, 1},
+ {0x1d692, 0x1d693, 1},
}
var _Hex_Digit = []Range{
- Range{0x0030, 0x0039, 1},
- Range{0x0041, 0x0046, 1},
- Range{0x0061, 0x0066, 1},
- Range{0xff10, 0xff19, 1},
- Range{0xff21, 0xff26, 1},
- Range{0xff41, 0xff46, 1},
+ {0x0030, 0x0039, 1},
+ {0x0041, 0x0046, 1},
+ {0x0061, 0x0066, 1},
+ {0xff10, 0xff19, 1},
+ {0xff21, 0xff26, 1},
+ {0xff41, 0xff46, 1},
}
var _ASCII_Hex_Digit = []Range{
- Range{0x0030, 0x0039, 1},
- Range{0x0041, 0x0046, 1},
- Range{0x0061, 0x0066, 1},
+ {0x0030, 0x0039, 1},
+ {0x0041, 0x0046, 1},
+ {0x0061, 0x0066, 1},
}
var _Deprecated = []Range{
- Range{0x0149, 0x0149, 1},
- Range{0x0f77, 0x0f77, 1},
- Range{0x0f79, 0x0f79, 1},
- Range{0x17a3, 0x17a4, 1},
- Range{0x206a, 0x206f, 1},
- Range{0x2329, 0x232a, 1},
- Range{0xe0001, 0xe0001, 1},
- Range{0xe0020, 0xe007f, 1},
+ {0x0149, 0x0149, 1},
+ {0x0f77, 0x0f77, 1},
+ {0x0f79, 0x0f79, 1},
+ {0x17a3, 0x17a4, 1},
+ {0x206a, 0x206f, 1},
+ {0x2329, 0x232a, 1},
+ {0xe0001, 0xe0001, 1},
+ {0xe0020, 0xe007f, 1},
}
var _Terminal_Punctuation = []Range{
- Range{0x0021, 0x0021, 1},
- Range{0x002c, 0x002c, 1},
- Range{0x002e, 0x002e, 1},
- Range{0x003a, 0x003b, 1},
- Range{0x003f, 0x003f, 1},
- Range{0x037e, 0x037e, 1},
- Range{0x0387, 0x0387, 1},
- Range{0x0589, 0x0589, 1},
- Range{0x05c3, 0x05c3, 1},
- Range{0x060c, 0x060c, 1},
- Range{0x061b, 0x061b, 1},
- Range{0x061f, 0x061f, 1},
- Range{0x06d4, 0x06d4, 1},
- Range{0x0700, 0x070a, 1},
- Range{0x070c, 0x070c, 1},
- Range{0x07f8, 0x07f9, 1},
- Range{0x0830, 0x083e, 1},
- Range{0x0964, 0x0965, 1},
- Range{0x0e5a, 0x0e5b, 1},
- Range{0x0f08, 0x0f08, 1},
- Range{0x0f0d, 0x0f12, 1},
- Range{0x104a, 0x104b, 1},
- Range{0x1361, 0x1368, 1},
- Range{0x166d, 0x166e, 1},
- Range{0x16eb, 0x16ed, 1},
- Range{0x17d4, 0x17d6, 1},
- Range{0x17da, 0x17da, 1},
- Range{0x1802, 0x1805, 1},
- Range{0x1808, 0x1809, 1},
- Range{0x1944, 0x1945, 1},
- Range{0x1aa8, 0x1aab, 1},
- Range{0x1b5a, 0x1b5b, 1},
- Range{0x1b5d, 0x1b5f, 1},
- Range{0x1c3b, 0x1c3f, 1},
- Range{0x1c7e, 0x1c7f, 1},
- Range{0x203c, 0x203d, 1},
- Range{0x2047, 0x2049, 1},
- Range{0x2e2e, 0x2e2e, 1},
- Range{0x3001, 0x3002, 1},
- Range{0xa4fe, 0xa4ff, 1},
- Range{0xa60d, 0xa60f, 1},
- Range{0xa6f3, 0xa6f7, 1},
- Range{0xa876, 0xa877, 1},
- Range{0xa8ce, 0xa8cf, 1},
- Range{0xa92f, 0xa92f, 1},
- Range{0xa9c7, 0xa9c9, 1},
- Range{0xaa5d, 0xaa5f, 1},
- Range{0xaadf, 0xaadf, 1},
- Range{0xabeb, 0xabeb, 1},
- Range{0xfe50, 0xfe52, 1},
- Range{0xfe54, 0xfe57, 1},
- Range{0xff01, 0xff01, 1},
- Range{0xff0c, 0xff0c, 1},
- Range{0xff0e, 0xff0e, 1},
- Range{0xff1a, 0xff1b, 1},
- Range{0xff1f, 0xff1f, 1},
- Range{0xff61, 0xff61, 1},
- Range{0xff64, 0xff64, 1},
- Range{0x1039f, 0x1039f, 1},
- Range{0x103d0, 0x103d0, 1},
- Range{0x10857, 0x10857, 1},
- Range{0x1091f, 0x1091f, 1},
- Range{0x10b3a, 0x10b3f, 1},
- Range{0x110be, 0x110c1, 1},
- Range{0x12470, 0x12473, 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},
+ {0x0964, 0x0965, 1},
+ {0x0e5a, 0x0e5b, 1},
+ {0x0f08, 0x0f08, 1},
+ {0x0f0d, 0x0f12, 1},
+ {0x104a, 0x104b, 1},
+ {0x1361, 0x1368, 1},
+ {0x166d, 0x166e, 1},
+ {0x16eb, 0x16ed, 1},
+ {0x17d4, 0x17d6, 1},
+ {0x17da, 0x17da, 1},
+ {0x1802, 0x1805, 1},
+ {0x1808, 0x1809, 1},
+ {0x1944, 0x1945, 1},
+ {0x1aa8, 0x1aab, 1},
+ {0x1b5a, 0x1b5b, 1},
+ {0x1b5d, 0x1b5f, 1},
+ {0x1c3b, 0x1c3f, 1},
+ {0x1c7e, 0x1c7f, 1},
+ {0x203c, 0x203d, 1},
+ {0x2047, 0x2049, 1},
+ {0x2e2e, 0x2e2e, 1},
+ {0x3001, 0x3002, 1},
+ {0xa4fe, 0xa4ff, 1},
+ {0xa60d, 0xa60f, 1},
+ {0xa6f3, 0xa6f7, 1},
+ {0xa876, 0xa877, 1},
+ {0xa8ce, 0xa8cf, 1},
+ {0xa92f, 0xa92f, 1},
+ {0xa9c7, 0xa9c9, 1},
+ {0xaa5d, 0xaa5f, 1},
+ {0xaadf, 0xaadf, 1},
+ {0xabeb, 0xabeb, 1},
+ {0xfe50, 0xfe52, 1},
+ {0xfe54, 0xfe57, 1},
+ {0xff01, 0xff01, 1},
+ {0xff0c, 0xff0c, 1},
+ {0xff0e, 0xff0e, 1},
+ {0xff1a, 0xff1b, 1},
+ {0xff1f, 0xff1f, 1},
+ {0xff61, 0xff61, 1},
+ {0xff64, 0xff64, 1},
+ {0x1039f, 0x1039f, 1},
+ {0x103d0, 0x103d0, 1},
+ {0x10857, 0x10857, 1},
+ {0x1091f, 0x1091f, 1},
+ {0x10b3a, 0x10b3f, 1},
+ {0x110be, 0x110c1, 1},
+ {0x12470, 0x12473, 1},
}
var _Quotation_Mark = []Range{
- Range{0x0022, 0x0022, 1},
- Range{0x0027, 0x0027, 1},
- Range{0x00ab, 0x00ab, 1},
- Range{0x00bb, 0x00bb, 1},
- Range{0x2018, 0x201f, 1},
- Range{0x2039, 0x203a, 1},
- Range{0x300c, 0x300f, 1},
- Range{0x301d, 0x301f, 1},
- Range{0xfe41, 0xfe44, 1},
- Range{0xff02, 0xff02, 1},
- Range{0xff07, 0xff07, 1},
- Range{0xff62, 0xff63, 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},
}
var _Other_ID_Continue = []Range{
- Range{0x00b7, 0x00b7, 1},
- Range{0x0387, 0x0387, 1},
- Range{0x1369, 0x1371, 1},
+ {0x00b7, 0x00b7, 1},
+ {0x0387, 0x0387, 1},
+ {0x1369, 0x1371, 1},
}
var _Bidi_Control = []Range{
- Range{0x200e, 0x200f, 1},
- Range{0x202a, 0x202e, 1},
+ {0x200e, 0x200f, 1},
+ {0x202a, 0x202e, 1},
}
var _Variation_Selector = []Range{
- Range{0x180b, 0x180d, 1},
- Range{0xfe00, 0xfe0f, 1},
- Range{0xe0100, 0xe01ef, 1},
+ {0x180b, 0x180d, 1},
+ {0xfe00, 0xfe0f, 1},
+ {0xe0100, 0xe01ef, 1},
}
var _Noncharacter_Code_Point = []Range{
- Range{0xfdd0, 0xfdef, 1},
- Range{0xfffe, 0xffff, 1},
- Range{0x1fffe, 0x1ffff, 1},
- Range{0x2fffe, 0x2ffff, 1},
- Range{0x3fffe, 0x3ffff, 1},
- Range{0x4fffe, 0x4ffff, 1},
- Range{0x5fffe, 0x5ffff, 1},
- Range{0x6fffe, 0x6ffff, 1},
- Range{0x7fffe, 0x7ffff, 1},
- Range{0x8fffe, 0x8ffff, 1},
- Range{0x9fffe, 0x9ffff, 1},
- Range{0xafffe, 0xaffff, 1},
- Range{0xbfffe, 0xbffff, 1},
- Range{0xcfffe, 0xcffff, 1},
- Range{0xdfffe, 0xdffff, 1},
- Range{0xefffe, 0xeffff, 1},
- Range{0xffffe, 0xfffff, 1},
- Range{0x10fffe, 0x10ffff, 1},
+ {0xfdd0, 0xfdef, 1},
+ {0xfffe, 0xffff, 1},
+ {0x1fffe, 0x1ffff, 1},
+ {0x2fffe, 0x2ffff, 1},
+ {0x3fffe, 0x3ffff, 1},
+ {0x4fffe, 0x4ffff, 1},
+ {0x5fffe, 0x5ffff, 1},
+ {0x6fffe, 0x6ffff, 1},
+ {0x7fffe, 0x7ffff, 1},
+ {0x8fffe, 0x8ffff, 1},
+ {0x9fffe, 0x9ffff, 1},
+ {0xafffe, 0xaffff, 1},
+ {0xbfffe, 0xbffff, 1},
+ {0xcfffe, 0xcffff, 1},
+ {0xdfffe, 0xdffff, 1},
+ {0xefffe, 0xeffff, 1},
+ {0xffffe, 0xfffff, 1},
+ {0x10fffe, 0x10ffff, 1},
}
var _Other_Math = []Range{
- Range{0x005e, 0x005e, 1},
- Range{0x03d0, 0x03d2, 1},
- Range{0x03d5, 0x03d5, 1},
- Range{0x03f0, 0x03f1, 1},
- Range{0x03f4, 0x03f5, 1},
- Range{0x2016, 0x2016, 1},
- Range{0x2032, 0x2034, 1},
- Range{0x2040, 0x2040, 1},
- Range{0x2061, 0x2064, 1},
- Range{0x207d, 0x207e, 1},
- Range{0x208d, 0x208e, 1},
- Range{0x20d0, 0x20dc, 1},
- Range{0x20e1, 0x20e1, 1},
- Range{0x20e5, 0x20e6, 1},
- Range{0x20eb, 0x20ef, 1},
- Range{0x2102, 0x2102, 1},
- Range{0x210a, 0x2113, 1},
- Range{0x2115, 0x2115, 1},
- Range{0x2119, 0x211d, 1},
- Range{0x2124, 0x2124, 1},
- Range{0x2128, 0x2129, 1},
- Range{0x212c, 0x212d, 1},
- Range{0x212f, 0x2131, 1},
- Range{0x2133, 0x2138, 1},
- Range{0x213c, 0x213f, 1},
- Range{0x2145, 0x2149, 1},
- Range{0x2195, 0x2199, 1},
- Range{0x219c, 0x219f, 1},
- Range{0x21a1, 0x21a2, 1},
- Range{0x21a4, 0x21a5, 1},
- Range{0x21a7, 0x21a7, 1},
- Range{0x21a9, 0x21ad, 1},
- Range{0x21b0, 0x21b1, 1},
- Range{0x21b6, 0x21b7, 1},
- Range{0x21bc, 0x21cd, 1},
- Range{0x21d0, 0x21d1, 1},
- Range{0x21d3, 0x21d3, 1},
- Range{0x21d5, 0x21db, 1},
- Range{0x21dd, 0x21dd, 1},
- Range{0x21e4, 0x21e5, 1},
- Range{0x23b4, 0x23b5, 1},
- Range{0x23b7, 0x23b7, 1},
- Range{0x23d0, 0x23d0, 1},
- Range{0x23e2, 0x23e2, 1},
- Range{0x25a0, 0x25a1, 1},
- Range{0x25ae, 0x25b6, 1},
- Range{0x25bc, 0x25c0, 1},
- Range{0x25c6, 0x25c7, 1},
- Range{0x25ca, 0x25cb, 1},
- Range{0x25cf, 0x25d3, 1},
- Range{0x25e2, 0x25e2, 1},
- Range{0x25e4, 0x25e4, 1},
- Range{0x25e7, 0x25ec, 1},
- Range{0x2605, 0x2606, 1},
- Range{0x2640, 0x2640, 1},
- Range{0x2642, 0x2642, 1},
- Range{0x2660, 0x2663, 1},
- Range{0x266d, 0x266e, 1},
- Range{0x27c5, 0x27c6, 1},
- Range{0x27e6, 0x27ef, 1},
- Range{0x2983, 0x2998, 1},
- Range{0x29d8, 0x29db, 1},
- Range{0x29fc, 0x29fd, 1},
- Range{0xfe61, 0xfe61, 1},
- Range{0xfe63, 0xfe63, 1},
- Range{0xfe68, 0xfe68, 1},
- Range{0xff3c, 0xff3c, 1},
- Range{0xff3e, 0xff3e, 1},
- Range{0x1d400, 0x1d454, 1},
- Range{0x1d456, 0x1d49c, 1},
- Range{0x1d49e, 0x1d49f, 1},
- Range{0x1d4a2, 0x1d4a2, 1},
- Range{0x1d4a5, 0x1d4a6, 1},
- Range{0x1d4a9, 0x1d4ac, 1},
- Range{0x1d4ae, 0x1d4b9, 1},
- Range{0x1d4bb, 0x1d4bb, 1},
- Range{0x1d4bd, 0x1d4c3, 1},
- Range{0x1d4c5, 0x1d505, 1},
- Range{0x1d507, 0x1d50a, 1},
- Range{0x1d50d, 0x1d514, 1},
- Range{0x1d516, 0x1d51c, 1},
- Range{0x1d51e, 0x1d539, 1},
- Range{0x1d53b, 0x1d53e, 1},
- Range{0x1d540, 0x1d544, 1},
- Range{0x1d546, 0x1d546, 1},
- Range{0x1d54a, 0x1d550, 1},
- Range{0x1d552, 0x1d6a5, 1},
- Range{0x1d6a8, 0x1d6c0, 1},
- Range{0x1d6c2, 0x1d6da, 1},
- Range{0x1d6dc, 0x1d6fa, 1},
- Range{0x1d6fc, 0x1d714, 1},
- Range{0x1d716, 0x1d734, 1},
- Range{0x1d736, 0x1d74e, 1},
- Range{0x1d750, 0x1d76e, 1},
- Range{0x1d770, 0x1d788, 1},
- Range{0x1d78a, 0x1d7a8, 1},
- Range{0x1d7aa, 0x1d7c2, 1},
- Range{0x1d7c4, 0x1d7cb, 1},
- Range{0x1d7ce, 0x1d7ff, 1},
+ {0x005e, 0x005e, 1},
+ {0x03d0, 0x03d2, 1},
+ {0x03d5, 0x03d5, 1},
+ {0x03f0, 0x03f1, 1},
+ {0x03f4, 0x03f5, 1},
+ {0x2016, 0x2016, 1},
+ {0x2032, 0x2034, 1},
+ {0x2040, 0x2040, 1},
+ {0x2061, 0x2064, 1},
+ {0x207d, 0x207e, 1},
+ {0x208d, 0x208e, 1},
+ {0x20d0, 0x20dc, 1},
+ {0x20e1, 0x20e1, 1},
+ {0x20e5, 0x20e6, 1},
+ {0x20eb, 0x20ef, 1},
+ {0x2102, 0x2102, 1},
+ {0x210a, 0x2113, 1},
+ {0x2115, 0x2115, 1},
+ {0x2119, 0x211d, 1},
+ {0x2124, 0x2124, 1},
+ {0x2128, 0x2129, 1},
+ {0x212c, 0x212d, 1},
+ {0x212f, 0x2131, 1},
+ {0x2133, 0x2138, 1},
+ {0x213c, 0x213f, 1},
+ {0x2145, 0x2149, 1},
+ {0x2195, 0x2199, 1},
+ {0x219c, 0x219f, 1},
+ {0x21a1, 0x21a2, 1},
+ {0x21a4, 0x21a5, 1},
+ {0x21a7, 0x21a7, 1},
+ {0x21a9, 0x21ad, 1},
+ {0x21b0, 0x21b1, 1},
+ {0x21b6, 0x21b7, 1},
+ {0x21bc, 0x21cd, 1},
+ {0x21d0, 0x21d1, 1},
+ {0x21d3, 0x21d3, 1},
+ {0x21d5, 0x21db, 1},
+ {0x21dd, 0x21dd, 1},
+ {0x21e4, 0x21e5, 1},
+ {0x23b4, 0x23b5, 1},
+ {0x23b7, 0x23b7, 1},
+ {0x23d0, 0x23d0, 1},
+ {0x23e2, 0x23e2, 1},
+ {0x25a0, 0x25a1, 1},
+ {0x25ae, 0x25b6, 1},
+ {0x25bc, 0x25c0, 1},
+ {0x25c6, 0x25c7, 1},
+ {0x25ca, 0x25cb, 1},
+ {0x25cf, 0x25d3, 1},
+ {0x25e2, 0x25e2, 1},
+ {0x25e4, 0x25e4, 1},
+ {0x25e7, 0x25ec, 1},
+ {0x2605, 0x2606, 1},
+ {0x2640, 0x2640, 1},
+ {0x2642, 0x2642, 1},
+ {0x2660, 0x2663, 1},
+ {0x266d, 0x266e, 1},
+ {0x27c5, 0x27c6, 1},
+ {0x27e6, 0x27ef, 1},
+ {0x2983, 0x2998, 1},
+ {0x29d8, 0x29db, 1},
+ {0x29fc, 0x29fd, 1},
+ {0xfe61, 0xfe61, 1},
+ {0xfe63, 0xfe63, 1},
+ {0xfe68, 0xfe68, 1},
+ {0xff3c, 0xff3c, 1},
+ {0xff3e, 0xff3e, 1},
+ {0x1d400, 0x1d454, 1},
+ {0x1d456, 0x1d49c, 1},
+ {0x1d49e, 0x1d49f, 1},
+ {0x1d4a2, 0x1d4a2, 1},
+ {0x1d4a5, 0x1d4a6, 1},
+ {0x1d4a9, 0x1d4ac, 1},
+ {0x1d4ae, 0x1d4b9, 1},
+ {0x1d4bb, 0x1d4bb, 1},
+ {0x1d4bd, 0x1d4c3, 1},
+ {0x1d4c5, 0x1d505, 1},
+ {0x1d507, 0x1d50a, 1},
+ {0x1d50d, 0x1d514, 1},
+ {0x1d516, 0x1d51c, 1},
+ {0x1d51e, 0x1d539, 1},
+ {0x1d53b, 0x1d53e, 1},
+ {0x1d540, 0x1d544, 1},
+ {0x1d546, 0x1d546, 1},
+ {0x1d54a, 0x1d550, 1},
+ {0x1d552, 0x1d6a5, 1},
+ {0x1d6a8, 0x1d6c0, 1},
+ {0x1d6c2, 0x1d6da, 1},
+ {0x1d6dc, 0x1d6fa, 1},
+ {0x1d6fc, 0x1d714, 1},
+ {0x1d716, 0x1d734, 1},
+ {0x1d736, 0x1d74e, 1},
+ {0x1d750, 0x1d76e, 1},
+ {0x1d770, 0x1d788, 1},
+ {0x1d78a, 0x1d7a8, 1},
+ {0x1d7aa, 0x1d7c2, 1},
+ {0x1d7c4, 0x1d7cb, 1},
+ {0x1d7ce, 0x1d7ff, 1},
}
var _Unified_Ideograph = []Range{
- Range{0x3400, 0x4db5, 1},
- Range{0x4e00, 0x9fcb, 1},
- Range{0xfa0e, 0xfa0f, 1},
- Range{0xfa11, 0xfa11, 1},
- Range{0xfa13, 0xfa14, 1},
- Range{0xfa1f, 0xfa1f, 1},
- Range{0xfa21, 0xfa21, 1},
- Range{0xfa23, 0xfa24, 1},
- Range{0xfa27, 0xfa29, 1},
- Range{0x20000, 0x2a6d6, 1},
- Range{0x2a700, 0x2b734, 1},
+ {0x3400, 0x4db5, 1},
+ {0x4e00, 0x9fcb, 1},
+ {0xfa0e, 0xfa0f, 1},
+ {0xfa11, 0xfa11, 1},
+ {0xfa13, 0xfa14, 1},
+ {0xfa1f, 0xfa1f, 1},
+ {0xfa21, 0xfa21, 1},
+ {0xfa23, 0xfa24, 1},
+ {0xfa27, 0xfa29, 1},
+ {0x20000, 0x2a6d6, 1},
+ {0x2a700, 0x2b734, 1},
}
var _Hyphen = []Range{
- Range{0x002d, 0x002d, 1},
- Range{0x00ad, 0x00ad, 1},
- Range{0x058a, 0x058a, 1},
- Range{0x1806, 0x1806, 1},
- Range{0x2010, 0x2011, 1},
- Range{0x2e17, 0x2e17, 1},
- Range{0x30fb, 0x30fb, 1},
- Range{0xfe63, 0xfe63, 1},
- Range{0xff0d, 0xff0d, 1},
- Range{0xff65, 0xff65, 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 _IDS_Binary_Operator = []Range{
- Range{0x2ff0, 0x2ff1, 1},
- Range{0x2ff4, 0x2ffb, 1},
+ {0x2ff0, 0x2ff1, 1},
+ {0x2ff4, 0x2ffb, 1},
}
var _Logical_Order_Exception = []Range{
- Range{0x0e40, 0x0e44, 1},
- Range{0x0ec0, 0x0ec4, 1},
- Range{0xaab5, 0xaab6, 1},
- Range{0xaab9, 0xaab9, 1},
- Range{0xaabb, 0xaabc, 1},
+ {0x0e40, 0x0e44, 1},
+ {0x0ec0, 0x0ec4, 1},
+ {0xaab5, 0xaab6, 1},
+ {0xaab9, 0xaab9, 1},
+ {0xaabb, 0xaabc, 1},
}
var _Radical = []Range{
- Range{0x2e80, 0x2e99, 1},
- Range{0x2e9b, 0x2ef3, 1},
- Range{0x2f00, 0x2fd5, 1},
+ {0x2e80, 0x2e99, 1},
+ {0x2e9b, 0x2ef3, 1},
+ {0x2f00, 0x2fd5, 1},
}
var _Other_Uppercase = []Range{
- Range{0x2160, 0x216f, 1},
- Range{0x24b6, 0x24cf, 1},
+ {0x2160, 0x216f, 1},
+ {0x24b6, 0x24cf, 1},
}
var _STerm = []Range{
- Range{0x0021, 0x0021, 1},
- Range{0x002e, 0x002e, 1},
- Range{0x003f, 0x003f, 1},
- Range{0x055c, 0x055c, 1},
- Range{0x055e, 0x055e, 1},
- Range{0x0589, 0x0589, 1},
- Range{0x061f, 0x061f, 1},
- Range{0x06d4, 0x06d4, 1},
- Range{0x0700, 0x0702, 1},
- Range{0x07f9, 0x07f9, 1},
- Range{0x0964, 0x0965, 1},
- Range{0x104a, 0x104b, 1},
- Range{0x1362, 0x1362, 1},
- Range{0x1367, 0x1368, 1},
- Range{0x166e, 0x166e, 1},
- Range{0x1803, 0x1803, 1},
- Range{0x1809, 0x1809, 1},
- Range{0x1944, 0x1945, 1},
- Range{0x1b5a, 0x1b5b, 1},
- Range{0x1b5e, 0x1b5f, 1},
- Range{0x1c3b, 0x1c3c, 1},
- Range{0x1c7e, 0x1c7f, 1},
- Range{0x203c, 0x203d, 1},
- Range{0x2047, 0x2049, 1},
- Range{0x2e2e, 0x2e2e, 1},
- Range{0x3002, 0x3002, 1},
- Range{0xa4ff, 0xa4ff, 1},
- Range{0xa60e, 0xa60f, 1},
- Range{0xa6f3, 0xa6f3, 1},
- Range{0xa6f7, 0xa6f7, 1},
- Range{0xa876, 0xa877, 1},
- Range{0xa8ce, 0xa8cf, 1},
- Range{0xa92f, 0xa92f, 1},
- Range{0xa9c8, 0xa9c9, 1},
- Range{0xaa5d, 0xaa5f, 1},
- Range{0xabeb, 0xabeb, 1},
- Range{0xfe52, 0xfe52, 1},
- Range{0xfe56, 0xfe57, 1},
- Range{0xff01, 0xff01, 1},
- Range{0xff0e, 0xff0e, 1},
- Range{0xff1f, 0xff1f, 1},
- Range{0xff61, 0xff61, 1},
- Range{0x110be, 0x110c1, 1},
+ {0x0021, 0x0021, 1},
+ {0x002e, 0x002e, 1},
+ {0x003f, 0x003f, 1},
+ {0x055c, 0x055c, 1},
+ {0x055e, 0x055e, 1},
+ {0x0589, 0x0589, 1},
+ {0x061f, 0x061f, 1},
+ {0x06d4, 0x06d4, 1},
+ {0x0700, 0x0702, 1},
+ {0x07f9, 0x07f9, 1},
+ {0x0964, 0x0965, 1},
+ {0x104a, 0x104b, 1},
+ {0x1362, 0x1362, 1},
+ {0x1367, 0x1368, 1},
+ {0x166e, 0x166e, 1},
+ {0x1803, 0x1803, 1},
+ {0x1809, 0x1809, 1},
+ {0x1944, 0x1945, 1},
+ {0x1b5a, 0x1b5b, 1},
+ {0x1b5e, 0x1b5f, 1},
+ {0x1c3b, 0x1c3c, 1},
+ {0x1c7e, 0x1c7f, 1},
+ {0x203c, 0x203d, 1},
+ {0x2047, 0x2049, 1},
+ {0x2e2e, 0x2e2e, 1},
+ {0x3002, 0x3002, 1},
+ {0xa4ff, 0xa4ff, 1},
+ {0xa60e, 0xa60f, 1},
+ {0xa6f3, 0xa6f3, 1},
+ {0xa6f7, 0xa6f7, 1},
+ {0xa876, 0xa877, 1},
+ {0xa8ce, 0xa8cf, 1},
+ {0xa92f, 0xa92f, 1},
+ {0xa9c8, 0xa9c9, 1},
+ {0xaa5d, 0xaa5f, 1},
+ {0xabeb, 0xabeb, 1},
+ {0xfe52, 0xfe52, 1},
+ {0xfe56, 0xfe57, 1},
+ {0xff01, 0xff01, 1},
+ {0xff0e, 0xff0e, 1},
+ {0xff1f, 0xff1f, 1},
+ {0xff61, 0xff61, 1},
+ {0x110be, 0x110c1, 1},
}
var _Other_Alphabetic = []Range{
- Range{0x0345, 0x0345, 1},
- Range{0x05b0, 0x05bd, 1},
- Range{0x05bf, 0x05bf, 1},
- Range{0x05c1, 0x05c2, 1},
- Range{0x05c4, 0x05c5, 1},
- Range{0x05c7, 0x05c7, 1},
- Range{0x0610, 0x061a, 1},
- Range{0x064b, 0x0657, 1},
- Range{0x0659, 0x065e, 1},
- Range{0x0670, 0x0670, 1},
- Range{0x06d6, 0x06dc, 1},
- Range{0x06e1, 0x06e4, 1},
- Range{0x06e7, 0x06e8, 1},
- Range{0x06ed, 0x06ed, 1},
- Range{0x0711, 0x0711, 1},
- Range{0x0730, 0x073f, 1},
- Range{0x07a6, 0x07b0, 1},
- Range{0x0816, 0x0817, 1},
- Range{0x081b, 0x0823, 1},
- Range{0x0825, 0x0827, 1},
- Range{0x0829, 0x082c, 1},
- Range{0x0900, 0x0903, 1},
- Range{0x093e, 0x094c, 1},
- Range{0x094e, 0x094e, 1},
- Range{0x0955, 0x0955, 1},
- Range{0x0962, 0x0963, 1},
- Range{0x0981, 0x0983, 1},
- Range{0x09be, 0x09c4, 1},
- Range{0x09c7, 0x09c8, 1},
- Range{0x09cb, 0x09cc, 1},
- Range{0x09d7, 0x09d7, 1},
- Range{0x09e2, 0x09e3, 1},
- Range{0x0a01, 0x0a03, 1},
- Range{0x0a3e, 0x0a42, 1},
- Range{0x0a47, 0x0a48, 1},
- Range{0x0a4b, 0x0a4c, 1},
- Range{0x0a51, 0x0a51, 1},
- Range{0x0a70, 0x0a71, 1},
- Range{0x0a75, 0x0a75, 1},
- Range{0x0a81, 0x0a83, 1},
- Range{0x0abe, 0x0ac5, 1},
- Range{0x0ac7, 0x0ac9, 1},
- Range{0x0acb, 0x0acc, 1},
- Range{0x0ae2, 0x0ae3, 1},
- Range{0x0b01, 0x0b03, 1},
- Range{0x0b3e, 0x0b44, 1},
- Range{0x0b47, 0x0b48, 1},
- Range{0x0b4b, 0x0b4c, 1},
- Range{0x0b56, 0x0b57, 1},
- Range{0x0b62, 0x0b63, 1},
- Range{0x0b82, 0x0b82, 1},
- Range{0x0bbe, 0x0bc2, 1},
- Range{0x0bc6, 0x0bc8, 1},
- Range{0x0bca, 0x0bcc, 1},
- Range{0x0bd7, 0x0bd7, 1},
- Range{0x0c01, 0x0c03, 1},
- Range{0x0c3e, 0x0c44, 1},
- Range{0x0c46, 0x0c48, 1},
- Range{0x0c4a, 0x0c4c, 1},
- Range{0x0c55, 0x0c56, 1},
- Range{0x0c62, 0x0c63, 1},
- Range{0x0c82, 0x0c83, 1},
- Range{0x0cbe, 0x0cc4, 1},
- Range{0x0cc6, 0x0cc8, 1},
- Range{0x0cca, 0x0ccc, 1},
- Range{0x0cd5, 0x0cd6, 1},
- Range{0x0ce2, 0x0ce3, 1},
- Range{0x0d02, 0x0d03, 1},
- Range{0x0d3e, 0x0d44, 1},
- Range{0x0d46, 0x0d48, 1},
- Range{0x0d4a, 0x0d4c, 1},
- Range{0x0d57, 0x0d57, 1},
- Range{0x0d62, 0x0d63, 1},
- Range{0x0d82, 0x0d83, 1},
- Range{0x0dcf, 0x0dd4, 1},
- Range{0x0dd6, 0x0dd6, 1},
- Range{0x0dd8, 0x0ddf, 1},
- Range{0x0df2, 0x0df3, 1},
- Range{0x0e31, 0x0e31, 1},
- Range{0x0e34, 0x0e3a, 1},
- Range{0x0e4d, 0x0e4d, 1},
- Range{0x0eb1, 0x0eb1, 1},
- Range{0x0eb4, 0x0eb9, 1},
- Range{0x0ebb, 0x0ebc, 1},
- Range{0x0ecd, 0x0ecd, 1},
- Range{0x0f71, 0x0f81, 1},
- Range{0x0f90, 0x0f97, 1},
- Range{0x0f99, 0x0fbc, 1},
- Range{0x102b, 0x1036, 1},
- Range{0x1038, 0x1038, 1},
- Range{0x103b, 0x103e, 1},
- Range{0x1056, 0x1059, 1},
- Range{0x105e, 0x1060, 1},
- Range{0x1062, 0x1062, 1},
- Range{0x1067, 0x1068, 1},
- Range{0x1071, 0x1074, 1},
- Range{0x1082, 0x1086, 1},
- Range{0x109c, 0x109d, 1},
- Range{0x135f, 0x135f, 1},
- Range{0x1712, 0x1713, 1},
- Range{0x1732, 0x1733, 1},
- Range{0x1752, 0x1753, 1},
- Range{0x1772, 0x1773, 1},
- Range{0x17b6, 0x17c8, 1},
- Range{0x18a9, 0x18a9, 1},
- Range{0x1920, 0x192b, 1},
- Range{0x1930, 0x1938, 1},
- Range{0x19b0, 0x19c0, 1},
- Range{0x19c8, 0x19c9, 1},
- Range{0x1a17, 0x1a1b, 1},
- Range{0x1a55, 0x1a5e, 1},
- Range{0x1a61, 0x1a74, 1},
- Range{0x1b00, 0x1b04, 1},
- Range{0x1b35, 0x1b43, 1},
- Range{0x1b80, 0x1b82, 1},
- Range{0x1ba1, 0x1ba9, 1},
- Range{0x1c24, 0x1c35, 1},
- Range{0x1cf2, 0x1cf2, 1},
- Range{0x24b6, 0x24e9, 1},
- Range{0x2de0, 0x2dff, 1},
- Range{0xa823, 0xa827, 1},
- Range{0xa880, 0xa881, 1},
- Range{0xa8b4, 0xa8c3, 1},
- Range{0xa926, 0xa92a, 1},
- Range{0xa947, 0xa952, 1},
- Range{0xa980, 0xa983, 1},
- Range{0xa9b3, 0xa9bf, 1},
- Range{0xaa29, 0xaa36, 1},
- Range{0xaa43, 0xaa43, 1},
- Range{0xaa4c, 0xaa4d, 1},
- Range{0xaab0, 0xaab0, 1},
- Range{0xaab2, 0xaab4, 1},
- Range{0xaab7, 0xaab8, 1},
- Range{0xaabe, 0xaabe, 1},
- Range{0xabe3, 0xabea, 1},
- Range{0xfb1e, 0xfb1e, 1},
- Range{0x10a01, 0x10a03, 1},
- Range{0x10a05, 0x10a06, 1},
- Range{0x10a0c, 0x10a0f, 1},
- Range{0x11082, 0x11082, 1},
- Range{0x110b0, 0x110b8, 1},
+ {0x0345, 0x0345, 1},
+ {0x05b0, 0x05bd, 1},
+ {0x05bf, 0x05bf, 1},
+ {0x05c1, 0x05c2, 1},
+ {0x05c4, 0x05c5, 1},
+ {0x05c7, 0x05c7, 1},
+ {0x0610, 0x061a, 1},
+ {0x064b, 0x0657, 1},
+ {0x0659, 0x065e, 1},
+ {0x0670, 0x0670, 1},
+ {0x06d6, 0x06dc, 1},
+ {0x06e1, 0x06e4, 1},
+ {0x06e7, 0x06e8, 1},
+ {0x06ed, 0x06ed, 1},
+ {0x0711, 0x0711, 1},
+ {0x0730, 0x073f, 1},
+ {0x07a6, 0x07b0, 1},
+ {0x0816, 0x0817, 1},
+ {0x081b, 0x0823, 1},
+ {0x0825, 0x0827, 1},
+ {0x0829, 0x082c, 1},
+ {0x0900, 0x0903, 1},
+ {0x093e, 0x094c, 1},
+ {0x094e, 0x094e, 1},
+ {0x0955, 0x0955, 1},
+ {0x0962, 0x0963, 1},
+ {0x0981, 0x0983, 1},
+ {0x09be, 0x09c4, 1},
+ {0x09c7, 0x09c8, 1},
+ {0x09cb, 0x09cc, 1},
+ {0x09d7, 0x09d7, 1},
+ {0x09e2, 0x09e3, 1},
+ {0x0a01, 0x0a03, 1},
+ {0x0a3e, 0x0a42, 1},
+ {0x0a47, 0x0a48, 1},
+ {0x0a4b, 0x0a4c, 1},
+ {0x0a51, 0x0a51, 1},
+ {0x0a70, 0x0a71, 1},
+ {0x0a75, 0x0a75, 1},
+ {0x0a81, 0x0a83, 1},
+ {0x0abe, 0x0ac5, 1},
+ {0x0ac7, 0x0ac9, 1},
+ {0x0acb, 0x0acc, 1},
+ {0x0ae2, 0x0ae3, 1},
+ {0x0b01, 0x0b03, 1},
+ {0x0b3e, 0x0b44, 1},
+ {0x0b47, 0x0b48, 1},
+ {0x0b4b, 0x0b4c, 1},
+ {0x0b56, 0x0b57, 1},
+ {0x0b62, 0x0b63, 1},
+ {0x0b82, 0x0b82, 1},
+ {0x0bbe, 0x0bc2, 1},
+ {0x0bc6, 0x0bc8, 1},
+ {0x0bca, 0x0bcc, 1},
+ {0x0bd7, 0x0bd7, 1},
+ {0x0c01, 0x0c03, 1},
+ {0x0c3e, 0x0c44, 1},
+ {0x0c46, 0x0c48, 1},
+ {0x0c4a, 0x0c4c, 1},
+ {0x0c55, 0x0c56, 1},
+ {0x0c62, 0x0c63, 1},
+ {0x0c82, 0x0c83, 1},
+ {0x0cbe, 0x0cc4, 1},
+ {0x0cc6, 0x0cc8, 1},
+ {0x0cca, 0x0ccc, 1},
+ {0x0cd5, 0x0cd6, 1},
+ {0x0ce2, 0x0ce3, 1},
+ {0x0d02, 0x0d03, 1},
+ {0x0d3e, 0x0d44, 1},
+ {0x0d46, 0x0d48, 1},
+ {0x0d4a, 0x0d4c, 1},
+ {0x0d57, 0x0d57, 1},
+ {0x0d62, 0x0d63, 1},
+ {0x0d82, 0x0d83, 1},
+ {0x0dcf, 0x0dd4, 1},
+ {0x0dd6, 0x0dd6, 1},
+ {0x0dd8, 0x0ddf, 1},
+ {0x0df2, 0x0df3, 1},
+ {0x0e31, 0x0e31, 1},
+ {0x0e34, 0x0e3a, 1},
+ {0x0e4d, 0x0e4d, 1},
+ {0x0eb1, 0x0eb1, 1},
+ {0x0eb4, 0x0eb9, 1},
+ {0x0ebb, 0x0ebc, 1},
+ {0x0ecd, 0x0ecd, 1},
+ {0x0f71, 0x0f81, 1},
+ {0x0f90, 0x0f97, 1},
+ {0x0f99, 0x0fbc, 1},
+ {0x102b, 0x1036, 1},
+ {0x1038, 0x1038, 1},
+ {0x103b, 0x103e, 1},
+ {0x1056, 0x1059, 1},
+ {0x105e, 0x1060, 1},
+ {0x1062, 0x1062, 1},
+ {0x1067, 0x1068, 1},
+ {0x1071, 0x1074, 1},
+ {0x1082, 0x1086, 1},
+ {0x109c, 0x109d, 1},
+ {0x135f, 0x135f, 1},
+ {0x1712, 0x1713, 1},
+ {0x1732, 0x1733, 1},
+ {0x1752, 0x1753, 1},
+ {0x1772, 0x1773, 1},
+ {0x17b6, 0x17c8, 1},
+ {0x18a9, 0x18a9, 1},
+ {0x1920, 0x192b, 1},
+ {0x1930, 0x1938, 1},
+ {0x19b0, 0x19c0, 1},
+ {0x19c8, 0x19c9, 1},
+ {0x1a17, 0x1a1b, 1},
+ {0x1a55, 0x1a5e, 1},
+ {0x1a61, 0x1a74, 1},
+ {0x1b00, 0x1b04, 1},
+ {0x1b35, 0x1b43, 1},
+ {0x1b80, 0x1b82, 1},
+ {0x1ba1, 0x1ba9, 1},
+ {0x1c24, 0x1c35, 1},
+ {0x1cf2, 0x1cf2, 1},
+ {0x24b6, 0x24e9, 1},
+ {0x2de0, 0x2dff, 1},
+ {0xa823, 0xa827, 1},
+ {0xa880, 0xa881, 1},
+ {0xa8b4, 0xa8c3, 1},
+ {0xa926, 0xa92a, 1},
+ {0xa947, 0xa952, 1},
+ {0xa980, 0xa983, 1},
+ {0xa9b3, 0xa9bf, 1},
+ {0xaa29, 0xaa36, 1},
+ {0xaa43, 0xaa43, 1},
+ {0xaa4c, 0xaa4d, 1},
+ {0xaab0, 0xaab0, 1},
+ {0xaab2, 0xaab4, 1},
+ {0xaab7, 0xaab8, 1},
+ {0xaabe, 0xaabe, 1},
+ {0xabe3, 0xabea, 1},
+ {0xfb1e, 0xfb1e, 1},
+ {0x10a01, 0x10a03, 1},
+ {0x10a05, 0x10a06, 1},
+ {0x10a0c, 0x10a0f, 1},
+ {0x11082, 0x11082, 1},
+ {0x110b0, 0x110b8, 1},
}
var _Diacritic = []Range{
- Range{0x005e, 0x005e, 1},
- Range{0x0060, 0x0060, 1},
- Range{0x00a8, 0x00a8, 1},
- Range{0x00af, 0x00af, 1},
- Range{0x00b4, 0x00b4, 1},
- Range{0x00b7, 0x00b8, 1},
- Range{0x02b0, 0x034e, 1},
- Range{0x0350, 0x0357, 1},
- Range{0x035d, 0x0362, 1},
- Range{0x0374, 0x0375, 1},
- Range{0x037a, 0x037a, 1},
- Range{0x0384, 0x0385, 1},
- Range{0x0483, 0x0487, 1},
- Range{0x0559, 0x0559, 1},
- Range{0x0591, 0x05a1, 1},
- Range{0x05a3, 0x05bd, 1},
- Range{0x05bf, 0x05bf, 1},
- Range{0x05c1, 0x05c2, 1},
- Range{0x05c4, 0x05c4, 1},
- Range{0x064b, 0x0652, 1},
- Range{0x0657, 0x0658, 1},
- Range{0x06df, 0x06e0, 1},
- Range{0x06e5, 0x06e6, 1},
- Range{0x06ea, 0x06ec, 1},
- Range{0x0730, 0x074a, 1},
- Range{0x07a6, 0x07b0, 1},
- Range{0x07eb, 0x07f5, 1},
- Range{0x0818, 0x0819, 1},
- Range{0x093c, 0x093c, 1},
- Range{0x094d, 0x094d, 1},
- Range{0x0951, 0x0954, 1},
- Range{0x0971, 0x0971, 1},
- Range{0x09bc, 0x09bc, 1},
- Range{0x09cd, 0x09cd, 1},
- Range{0x0a3c, 0x0a3c, 1},
- Range{0x0a4d, 0x0a4d, 1},
- Range{0x0abc, 0x0abc, 1},
- Range{0x0acd, 0x0acd, 1},
- Range{0x0b3c, 0x0b3c, 1},
- Range{0x0b4d, 0x0b4d, 1},
- Range{0x0bcd, 0x0bcd, 1},
- Range{0x0c4d, 0x0c4d, 1},
- Range{0x0cbc, 0x0cbc, 1},
- Range{0x0ccd, 0x0ccd, 1},
- Range{0x0d4d, 0x0d4d, 1},
- Range{0x0dca, 0x0dca, 1},
- Range{0x0e47, 0x0e4c, 1},
- Range{0x0e4e, 0x0e4e, 1},
- Range{0x0ec8, 0x0ecc, 1},
- Range{0x0f18, 0x0f19, 1},
- Range{0x0f35, 0x0f35, 1},
- Range{0x0f37, 0x0f37, 1},
- Range{0x0f39, 0x0f39, 1},
- Range{0x0f3e, 0x0f3f, 1},
- Range{0x0f82, 0x0f84, 1},
- Range{0x0f86, 0x0f87, 1},
- Range{0x0fc6, 0x0fc6, 1},
- Range{0x1037, 0x1037, 1},
- Range{0x1039, 0x103a, 1},
- Range{0x1087, 0x108d, 1},
- Range{0x108f, 0x108f, 1},
- Range{0x109a, 0x109b, 1},
- Range{0x17c9, 0x17d3, 1},
- Range{0x17dd, 0x17dd, 1},
- Range{0x1939, 0x193b, 1},
- Range{0x1a75, 0x1a7c, 1},
- Range{0x1a7f, 0x1a7f, 1},
- Range{0x1b34, 0x1b34, 1},
- Range{0x1b44, 0x1b44, 1},
- Range{0x1b6b, 0x1b73, 1},
- Range{0x1baa, 0x1baa, 1},
- Range{0x1c36, 0x1c37, 1},
- Range{0x1c78, 0x1c7d, 1},
- Range{0x1cd0, 0x1ce8, 1},
- Range{0x1ced, 0x1ced, 1},
- Range{0x1d2c, 0x1d6a, 1},
- Range{0x1dc4, 0x1dcf, 1},
- Range{0x1dfd, 0x1dff, 1},
- Range{0x1fbd, 0x1fbd, 1},
- Range{0x1fbf, 0x1fc1, 1},
- Range{0x1fcd, 0x1fcf, 1},
- Range{0x1fdd, 0x1fdf, 1},
- Range{0x1fed, 0x1fef, 1},
- Range{0x1ffd, 0x1ffe, 1},
- Range{0x2cef, 0x2cf1, 1},
- Range{0x2e2f, 0x2e2f, 1},
- Range{0x302a, 0x302f, 1},
- Range{0x3099, 0x309c, 1},
- Range{0x30fc, 0x30fc, 1},
- Range{0xa66f, 0xa66f, 1},
- Range{0xa67c, 0xa67d, 1},
- Range{0xa67f, 0xa67f, 1},
- Range{0xa6f0, 0xa6f1, 1},
- Range{0xa717, 0xa721, 1},
- Range{0xa788, 0xa788, 1},
- Range{0xa8c4, 0xa8c4, 1},
- Range{0xa8e0, 0xa8f1, 1},
- Range{0xa92b, 0xa92e, 1},
- Range{0xa953, 0xa953, 1},
- Range{0xa9b3, 0xa9b3, 1},
- Range{0xa9c0, 0xa9c0, 1},
- Range{0xaa7b, 0xaa7b, 1},
- Range{0xaabf, 0xaac2, 1},
- Range{0xabec, 0xabed, 1},
- Range{0xfb1e, 0xfb1e, 1},
- Range{0xfe20, 0xfe26, 1},
- Range{0xff3e, 0xff3e, 1},
- Range{0xff40, 0xff40, 1},
- Range{0xff70, 0xff70, 1},
- Range{0xff9e, 0xff9f, 1},
- Range{0xffe3, 0xffe3, 1},
- Range{0x110b9, 0x110ba, 1},
- Range{0x1d167, 0x1d169, 1},
- Range{0x1d16d, 0x1d172, 1},
- Range{0x1d17b, 0x1d182, 1},
- Range{0x1d185, 0x1d18b, 1},
- Range{0x1d1aa, 0x1d1ad, 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},
+ {0x110b9, 0x110ba, 1},
+ {0x1d167, 0x1d169, 1},
+ {0x1d16d, 0x1d172, 1},
+ {0x1d17b, 0x1d182, 1},
+ {0x1d185, 0x1d18b, 1},
+ {0x1d1aa, 0x1d1ad, 1},
}
var _Extender = []Range{
- Range{0x00b7, 0x00b7, 1},
- Range{0x02d0, 0x02d1, 1},
- Range{0x0640, 0x0640, 1},
- Range{0x07fa, 0x07fa, 1},
- Range{0x0e46, 0x0e46, 1},
- Range{0x0ec6, 0x0ec6, 1},
- Range{0x1843, 0x1843, 1},
- Range{0x1aa7, 0x1aa7, 1},
- Range{0x1c36, 0x1c36, 1},
- Range{0x1c7b, 0x1c7b, 1},
- Range{0x3005, 0x3005, 1},
- Range{0x3031, 0x3035, 1},
- Range{0x309d, 0x309e, 1},
- Range{0x30fc, 0x30fe, 1},
- Range{0xa015, 0xa015, 1},
- Range{0xa60c, 0xa60c, 1},
- Range{0xa9cf, 0xa9cf, 1},
- Range{0xaa70, 0xaa70, 1},
- Range{0xaadd, 0xaadd, 1},
- Range{0xff70, 0xff70, 1},
+ {0x00b7, 0x00b7, 1},
+ {0x02d0, 0x02d1, 1},
+ {0x0640, 0x0640, 1},
+ {0x07fa, 0x07fa, 1},
+ {0x0e46, 0x0e46, 1},
+ {0x0ec6, 0x0ec6, 1},
+ {0x1843, 0x1843, 1},
+ {0x1aa7, 0x1aa7, 1},
+ {0x1c36, 0x1c36, 1},
+ {0x1c7b, 0x1c7b, 1},
+ {0x3005, 0x3005, 1},
+ {0x3031, 0x3035, 1},
+ {0x309d, 0x309e, 1},
+ {0x30fc, 0x30fe, 1},
+ {0xa015, 0xa015, 1},
+ {0xa60c, 0xa60c, 1},
+ {0xa9cf, 0xa9cf, 1},
+ {0xaa70, 0xaa70, 1},
+ {0xaadd, 0xaadd, 1},
+ {0xff70, 0xff70, 1},
}
var _Join_Control = []Range{
- Range{0x200c, 0x200d, 1},
+ {0x200c, 0x200d, 1},
}
var _Ideographic = []Range{
- Range{0x3006, 0x3007, 1},
- Range{0x3021, 0x3029, 1},
- Range{0x3038, 0x303a, 1},
- Range{0x3400, 0x4db5, 1},
- Range{0x4e00, 0x9fcb, 1},
- Range{0xf900, 0xfa2d, 1},
- Range{0xfa30, 0xfa6d, 1},
- Range{0xfa70, 0xfad9, 1},
- Range{0x20000, 0x2a6d6, 1},
- Range{0x2a700, 0x2b734, 1},
- Range{0x2f800, 0x2fa1d, 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},
+ {0x20000, 0x2a6d6, 1},
+ {0x2a700, 0x2b734, 1},
+ {0x2f800, 0x2fa1d, 1},
}
var _Dash = []Range{
- Range{0x002d, 0x002d, 1},
- Range{0x058a, 0x058a, 1},
- Range{0x05be, 0x05be, 1},
- Range{0x1400, 0x1400, 1},
- Range{0x1806, 0x1806, 1},
- Range{0x2010, 0x2015, 1},
- Range{0x2053, 0x2053, 1},
- Range{0x207b, 0x207b, 1},
- Range{0x208b, 0x208b, 1},
- Range{0x2212, 0x2212, 1},
- Range{0x2e17, 0x2e17, 1},
- Range{0x2e1a, 0x2e1a, 1},
- Range{0x301c, 0x301c, 1},
- Range{0x3030, 0x3030, 1},
- Range{0x30a0, 0x30a0, 1},
- Range{0xfe31, 0xfe32, 1},
- Range{0xfe58, 0xfe58, 1},
- Range{0xfe63, 0xfe63, 1},
- Range{0xff0d, 0xff0d, 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 _IDS_Trinary_Operator = []Range{
- Range{0x2ff2, 0x2ff3, 1},
+ {0x2ff2, 0x2ff3, 1},
}
var _Other_Grapheme_Extend = []Range{
- Range{0x09be, 0x09be, 1},
- Range{0x09d7, 0x09d7, 1},
- Range{0x0b3e, 0x0b3e, 1},
- Range{0x0b57, 0x0b57, 1},
- Range{0x0bbe, 0x0bbe, 1},
- Range{0x0bd7, 0x0bd7, 1},
- Range{0x0cc2, 0x0cc2, 1},
- Range{0x0cd5, 0x0cd6, 1},
- Range{0x0d3e, 0x0d3e, 1},
- Range{0x0d57, 0x0d57, 1},
- Range{0x0dcf, 0x0dcf, 1},
- Range{0x0ddf, 0x0ddf, 1},
- Range{0x200c, 0x200d, 1},
- Range{0xff9e, 0xff9f, 1},
- Range{0x1d165, 0x1d165, 1},
- Range{0x1d16e, 0x1d172, 1},
+ {0x09be, 0x09be, 1},
+ {0x09d7, 0x09d7, 1},
+ {0x0b3e, 0x0b3e, 1},
+ {0x0b57, 0x0b57, 1},
+ {0x0bbe, 0x0bbe, 1},
+ {0x0bd7, 0x0bd7, 1},
+ {0x0cc2, 0x0cc2, 1},
+ {0x0cd5, 0x0cd6, 1},
+ {0x0d3e, 0x0d3e, 1},
+ {0x0d57, 0x0d57, 1},
+ {0x0dcf, 0x0dcf, 1},
+ {0x0ddf, 0x0ddf, 1},
+ {0x200c, 0x200d, 1},
+ {0xff9e, 0xff9f, 1},
+ {0x1d165, 0x1d165, 1},
+ {0x1d16e, 0x1d172, 1},
}
var _Other_Default_Ignorable_Code_Point = []Range{
- Range{0x034f, 0x034f, 1},
- Range{0x115f, 0x1160, 1},
- Range{0x2065, 0x2069, 1},
- Range{0x3164, 0x3164, 1},
- Range{0xffa0, 0xffa0, 1},
- Range{0xfff0, 0xfff8, 1},
- Range{0xe0000, 0xe0000, 1},
- Range{0xe0002, 0xe001f, 1},
- Range{0xe0080, 0xe00ff, 1},
- Range{0xe01f0, 0xe0fff, 1},
+ {0x034f, 0x034f, 1},
+ {0x115f, 0x1160, 1},
+ {0x2065, 0x2069, 1},
+ {0x3164, 0x3164, 1},
+ {0xffa0, 0xffa0, 1},
+ {0xfff0, 0xfff8, 1},
+ {0xe0000, 0xe0000, 1},
+ {0xe0002, 0xe001f, 1},
+ {0xe0080, 0xe00ff, 1},
+ {0xe01f0, 0xe0fff, 1},
}
var _White_Space = []Range{
- Range{0x0009, 0x000d, 1},
- Range{0x0020, 0x0020, 1},
- Range{0x0085, 0x0085, 1},
- Range{0x00a0, 0x00a0, 1},
- Range{0x1680, 0x1680, 1},
- Range{0x180e, 0x180e, 1},
- Range{0x2000, 0x200a, 1},
- Range{0x2028, 0x2029, 1},
- Range{0x202f, 0x202f, 1},
- Range{0x205f, 0x205f, 1},
- Range{0x3000, 0x3000, 1},
+ {0x0009, 0x000d, 1},
+ {0x0020, 0x0020, 1},
+ {0x0085, 0x0085, 1},
+ {0x00a0, 0x00a0, 1},
+ {0x1680, 0x1680, 1},
+ {0x180e, 0x180e, 1},
+ {0x2000, 0x200a, 1},
+ {0x2028, 0x2029, 1},
+ {0x202f, 0x202f, 1},
+ {0x205f, 0x205f, 1},
+ {0x3000, 0x3000, 1},
}
var (
@@ -3985,254 +3985,254 @@ var (
// non-self mappings.
var CaseRanges = _CaseRanges
var _CaseRanges = []CaseRange{
- CaseRange{0x0041, 0x005A, d{0, 32, 0}},
- CaseRange{0x0061, 0x007A, d{-32, 0, -32}},
- CaseRange{0x00B5, 0x00B5, d{743, 0, 743}},
- CaseRange{0x00C0, 0x00D6, d{0, 32, 0}},
- CaseRange{0x00D8, 0x00DE, d{0, 32, 0}},
- CaseRange{0x00E0, 0x00F6, d{-32, 0, -32}},
- CaseRange{0x00F8, 0x00FE, d{-32, 0, -32}},
- CaseRange{0x00FF, 0x00FF, d{121, 0, 121}},
- CaseRange{0x0100, 0x012F, d{UpperLower, UpperLower, UpperLower}},
- CaseRange{0x0130, 0x0130, d{0, -199, 0}},
- CaseRange{0x0131, 0x0131, d{-232, 0, -232}},
- CaseRange{0x0132, 0x0137, d{UpperLower, UpperLower, UpperLower}},
- CaseRange{0x0139, 0x0148, d{UpperLower, UpperLower, UpperLower}},
- CaseRange{0x014A, 0x0177, d{UpperLower, UpperLower, UpperLower}},
- CaseRange{0x0178, 0x0178, d{0, -121, 0}},
- CaseRange{0x0179, 0x017E, d{UpperLower, UpperLower, UpperLower}},
- CaseRange{0x017F, 0x017F, d{-300, 0, -300}},
- CaseRange{0x0180, 0x0180, d{195, 0, 195}},
- CaseRange{0x0181, 0x0181, d{0, 210, 0}},
- CaseRange{0x0182, 0x0185, d{UpperLower, UpperLower, UpperLower}},
- CaseRange{0x0186, 0x0186, d{0, 206, 0}},
- CaseRange{0x0187, 0x0188, d{UpperLower, UpperLower, UpperLower}},
- CaseRange{0x0189, 0x018A, d{0, 205, 0}},
- CaseRange{0x018B, 0x018C, d{UpperLower, UpperLower, UpperLower}},
- CaseRange{0x018E, 0x018E, d{0, 79, 0}},
- CaseRange{0x018F, 0x018F, d{0, 202, 0}},
- CaseRange{0x0190, 0x0190, d{0, 203, 0}},
- CaseRange{0x0191, 0x0192, d{UpperLower, UpperLower, UpperLower}},
- CaseRange{0x0193, 0x0193, d{0, 205, 0}},
- CaseRange{0x0194, 0x0194, d{0, 207, 0}},
- CaseRange{0x0195, 0x0195, d{97, 0, 97}},
- CaseRange{0x0196, 0x0196, d{0, 211, 0}},
- CaseRange{0x0197, 0x0197, d{0, 209, 0}},
- CaseRange{0x0198, 0x0199, d{UpperLower, UpperLower, UpperLower}},
- CaseRange{0x019A, 0x019A, d{163, 0, 163}},
- CaseRange{0x019C, 0x019C, d{0, 211, 0}},
- CaseRange{0x019D, 0x019D, d{0, 213, 0}},
- CaseRange{0x019E, 0x019E, d{130, 0, 130}},
- CaseRange{0x019F, 0x019F, d{0, 214, 0}},
- CaseRange{0x01A0, 0x01A5, d{UpperLower, UpperLower, UpperLower}},
- CaseRange{0x01A6, 0x01A6, d{0, 218, 0}},
- CaseRange{0x01A7, 0x01A8, d{UpperLower, UpperLower, UpperLower}},
- CaseRange{0x01A9, 0x01A9, d{0, 218, 0}},
- CaseRange{0x01AC, 0x01AD, d{UpperLower, UpperLower, UpperLower}},
- CaseRange{0x01AE, 0x01AE, d{0, 218, 0}},
- CaseRange{0x01AF, 0x01B0, d{UpperLower, UpperLower, UpperLower}},
- CaseRange{0x01B1, 0x01B2, d{0, 217, 0}},
- CaseRange{0x01B3, 0x01B6, d{UpperLower, UpperLower, UpperLower}},
- CaseRange{0x01B7, 0x01B7, d{0, 219, 0}},
- CaseRange{0x01B8, 0x01B9, d{UpperLower, UpperLower, UpperLower}},
- CaseRange{0x01BC, 0x01BD, d{UpperLower, UpperLower, UpperLower}},
- CaseRange{0x01BF, 0x01BF, d{56, 0, 56}},
- CaseRange{0x01C4, 0x01C4, d{0, 2, 1}},
- CaseRange{0x01C5, 0x01C5, d{-1, 1, 0}},
- CaseRange{0x01C6, 0x01C6, d{-2, 0, -1}},
- CaseRange{0x01C7, 0x01C7, d{0, 2, 1}},
- CaseRange{0x01C8, 0x01C8, d{-1, 1, 0}},
- CaseRange{0x01C9, 0x01C9, d{-2, 0, -1}},
- CaseRange{0x01CA, 0x01CA, d{0, 2, 1}},
- CaseRange{0x01CB, 0x01CB, d{-1, 1, 0}},
- CaseRange{0x01CC, 0x01CC, d{-2, 0, -1}},
- CaseRange{0x01CD, 0x01DC, d{UpperLower, UpperLower, UpperLower}},
- CaseRange{0x01DD, 0x01DD, d{-79, 0, -79}},
- CaseRange{0x01DE, 0x01EF, d{UpperLower, UpperLower, UpperLower}},
- CaseRange{0x01F1, 0x01F1, d{0, 2, 1}},
- CaseRange{0x01F2, 0x01F2, d{-1, 1, 0}},
- CaseRange{0x01F3, 0x01F3, d{-2, 0, -1}},
- CaseRange{0x01F4, 0x01F5, d{UpperLower, UpperLower, UpperLower}},
- CaseRange{0x01F6, 0x01F6, d{0, -97, 0}},
- CaseRange{0x01F7, 0x01F7, d{0, -56, 0}},
- CaseRange{0x01F8, 0x021F, d{UpperLower, UpperLower, UpperLower}},
- CaseRange{0x0220, 0x0220, d{0, -130, 0}},
- CaseRange{0x0222, 0x0233, d{UpperLower, UpperLower, UpperLower}},
- CaseRange{0x023A, 0x023A, d{0, 10795, 0}},
- CaseRange{0x023B, 0x023C, d{UpperLower, UpperLower, UpperLower}},
- CaseRange{0x023D, 0x023D, d{0, -163, 0}},
- CaseRange{0x023E, 0x023E, d{0, 10792, 0}},
- CaseRange{0x023F, 0x0240, d{10815, 0, 10815}},
- CaseRange{0x0241, 0x0242, d{UpperLower, UpperLower, UpperLower}},
- CaseRange{0x0243, 0x0243, d{0, -195, 0}},
- CaseRange{0x0244, 0x0244, d{0, 69, 0}},
- CaseRange{0x0245, 0x0245, d{0, 71, 0}},
- CaseRange{0x0246, 0x024F, d{UpperLower, UpperLower, UpperLower}},
- CaseRange{0x0250, 0x0250, d{10783, 0, 10783}},
- CaseRange{0x0251, 0x0251, d{10780, 0, 10780}},
- CaseRange{0x0252, 0x0252, d{10782, 0, 10782}},
- CaseRange{0x0253, 0x0253, d{-210, 0, -210}},
- CaseRange{0x0254, 0x0254, d{-206, 0, -206}},
- CaseRange{0x0256, 0x0257, d{-205, 0, -205}},
- CaseRange{0x0259, 0x0259, d{-202, 0, -202}},
- CaseRange{0x025B, 0x025B, d{-203, 0, -203}},
- CaseRange{0x0260, 0x0260, d{-205, 0, -205}},
- CaseRange{0x0263, 0x0263, d{-207, 0, -207}},
- CaseRange{0x0268, 0x0268, d{-209, 0, -209}},
- CaseRange{0x0269, 0x0269, d{-211, 0, -211}},
- CaseRange{0x026B, 0x026B, d{10743, 0, 10743}},
- CaseRange{0x026F, 0x026F, d{-211, 0, -211}},
- CaseRange{0x0271, 0x0271, d{10749, 0, 10749}},
- CaseRange{0x0272, 0x0272, d{-213, 0, -213}},
- CaseRange{0x0275, 0x0275, d{-214, 0, -214}},
- CaseRange{0x027D, 0x027D, d{10727, 0, 10727}},
- CaseRange{0x0280, 0x0280, d{-218, 0, -218}},
- CaseRange{0x0283, 0x0283, d{-218, 0, -218}},
- CaseRange{0x0288, 0x0288, d{-218, 0, -218}},
- CaseRange{0x0289, 0x0289, d{-69, 0, -69}},
- CaseRange{0x028A, 0x028B, d{-217, 0, -217}},
- CaseRange{0x028C, 0x028C, d{-71, 0, -71}},
- CaseRange{0x0292, 0x0292, d{-219, 0, -219}},
- CaseRange{0x0370, 0x0373, d{UpperLower, UpperLower, UpperLower}},
- CaseRange{0x0376, 0x0377, d{UpperLower, UpperLower, UpperLower}},
- CaseRange{0x037B, 0x037D, d{130, 0, 130}},
- CaseRange{0x0386, 0x0386, d{0, 38, 0}},
- CaseRange{0x0388, 0x038A, d{0, 37, 0}},
- CaseRange{0x038C, 0x038C, d{0, 64, 0}},
- CaseRange{0x038E, 0x038F, d{0, 63, 0}},
- CaseRange{0x0391, 0x03A1, d{0, 32, 0}},
- CaseRange{0x03A3, 0x03AB, d{0, 32, 0}},
- CaseRange{0x03AC, 0x03AC, d{-38, 0, -38}},
- CaseRange{0x03AD, 0x03AF, d{-37, 0, -37}},
- CaseRange{0x03B1, 0x03C1, d{-32, 0, -32}},
- CaseRange{0x03C2, 0x03C2, d{-31, 0, -31}},
- CaseRange{0x03C3, 0x03CB, d{-32, 0, -32}},
- CaseRange{0x03CC, 0x03CC, d{-64, 0, -64}},
- CaseRange{0x03CD, 0x03CE, d{-63, 0, -63}},
- CaseRange{0x03CF, 0x03CF, d{0, 8, 0}},
- CaseRange{0x03D0, 0x03D0, d{-62, 0, -62}},
- CaseRange{0x03D1, 0x03D1, d{-57, 0, -57}},
- CaseRange{0x03D5, 0x03D5, d{-47, 0, -47}},
- CaseRange{0x03D6, 0x03D6, d{-54, 0, -54}},
- CaseRange{0x03D7, 0x03D7, d{-8, 0, -8}},
- CaseRange{0x03D8, 0x03EF, d{UpperLower, UpperLower, UpperLower}},
- CaseRange{0x03F0, 0x03F0, d{-86, 0, -86}},
- CaseRange{0x03F1, 0x03F1, d{-80, 0, -80}},
- CaseRange{0x03F2, 0x03F2, d{7, 0, 7}},
- CaseRange{0x03F4, 0x03F4, d{0, -60, 0}},
- CaseRange{0x03F5, 0x03F5, d{-96, 0, -96}},
- CaseRange{0x03F7, 0x03F8, d{UpperLower, UpperLower, UpperLower}},
- CaseRange{0x03F9, 0x03F9, d{0, -7, 0}},
- CaseRange{0x03FA, 0x03FB, d{UpperLower, UpperLower, UpperLower}},
- CaseRange{0x03FD, 0x03FF, d{0, -130, 0}},
- CaseRange{0x0400, 0x040F, d{0, 80, 0}},
- CaseRange{0x0410, 0x042F, d{0, 32, 0}},
- CaseRange{0x0430, 0x044F, d{-32, 0, -32}},
- CaseRange{0x0450, 0x045F, d{-80, 0, -80}},
- CaseRange{0x0460, 0x0481, d{UpperLower, UpperLower, UpperLower}},
- CaseRange{0x048A, 0x04BF, d{UpperLower, UpperLower, UpperLower}},
- CaseRange{0x04C0, 0x04C0, d{0, 15, 0}},
- CaseRange{0x04C1, 0x04CE, d{UpperLower, UpperLower, UpperLower}},
- CaseRange{0x04CF, 0x04CF, d{-15, 0, -15}},
- CaseRange{0x04D0, 0x0525, d{UpperLower, UpperLower, UpperLower}},
- CaseRange{0x0531, 0x0556, d{0, 48, 0}},
- CaseRange{0x0561, 0x0586, d{-48, 0, -48}},
- CaseRange{0x10A0, 0x10C5, d{0, 7264, 0}},
- CaseRange{0x1D79, 0x1D79, d{35332, 0, 35332}},
- CaseRange{0x1D7D, 0x1D7D, d{3814, 0, 3814}},
- CaseRange{0x1E00, 0x1E95, d{UpperLower, UpperLower, UpperLower}},
- CaseRange{0x1E9B, 0x1E9B, d{-59, 0, -59}},
- CaseRange{0x1E9E, 0x1E9E, d{0, -7615, 0}},
- CaseRange{0x1EA0, 0x1EFF, d{UpperLower, UpperLower, UpperLower}},
- CaseRange{0x1F00, 0x1F07, d{8, 0, 8}},
- CaseRange{0x1F08, 0x1F0F, d{0, -8, 0}},
- CaseRange{0x1F10, 0x1F15, d{8, 0, 8}},
- CaseRange{0x1F18, 0x1F1D, d{0, -8, 0}},
- CaseRange{0x1F20, 0x1F27, d{8, 0, 8}},
- CaseRange{0x1F28, 0x1F2F, d{0, -8, 0}},
- CaseRange{0x1F30, 0x1F37, d{8, 0, 8}},
- CaseRange{0x1F38, 0x1F3F, d{0, -8, 0}},
- CaseRange{0x1F40, 0x1F45, d{8, 0, 8}},
- CaseRange{0x1F48, 0x1F4D, d{0, -8, 0}},
- CaseRange{0x1F51, 0x1F51, d{8, 0, 8}},
- CaseRange{0x1F53, 0x1F53, d{8, 0, 8}},
- CaseRange{0x1F55, 0x1F55, d{8, 0, 8}},
- CaseRange{0x1F57, 0x1F57, d{8, 0, 8}},
- CaseRange{0x1F59, 0x1F59, d{0, -8, 0}},
- CaseRange{0x1F5B, 0x1F5B, d{0, -8, 0}},
- CaseRange{0x1F5D, 0x1F5D, d{0, -8, 0}},
- CaseRange{0x1F5F, 0x1F5F, d{0, -8, 0}},
- CaseRange{0x1F60, 0x1F67, d{8, 0, 8}},
- CaseRange{0x1F68, 0x1F6F, d{0, -8, 0}},
- CaseRange{0x1F70, 0x1F71, d{74, 0, 74}},
- CaseRange{0x1F72, 0x1F75, d{86, 0, 86}},
- CaseRange{0x1F76, 0x1F77, d{100, 0, 100}},
- CaseRange{0x1F78, 0x1F79, d{128, 0, 128}},
- CaseRange{0x1F7A, 0x1F7B, d{112, 0, 112}},
- CaseRange{0x1F7C, 0x1F7D, d{126, 0, 126}},
- CaseRange{0x1F80, 0x1F87, d{8, 0, 8}},
- CaseRange{0x1F88, 0x1F8F, d{0, -8, 0}},
- CaseRange{0x1F90, 0x1F97, d{8, 0, 8}},
- CaseRange{0x1F98, 0x1F9F, d{0, -8, 0}},
- CaseRange{0x1FA0, 0x1FA7, d{8, 0, 8}},
- CaseRange{0x1FA8, 0x1FAF, d{0, -8, 0}},
- CaseRange{0x1FB0, 0x1FB1, d{8, 0, 8}},
- CaseRange{0x1FB3, 0x1FB3, d{9, 0, 9}},
- CaseRange{0x1FB8, 0x1FB9, d{0, -8, 0}},
- CaseRange{0x1FBA, 0x1FBB, d{0, -74, 0}},
- CaseRange{0x1FBC, 0x1FBC, d{0, -9, 0}},
- CaseRange{0x1FBE, 0x1FBE, d{-7205, 0, -7205}},
- CaseRange{0x1FC3, 0x1FC3, d{9, 0, 9}},
- CaseRange{0x1FC8, 0x1FCB, d{0, -86, 0}},
- CaseRange{0x1FCC, 0x1FCC, d{0, -9, 0}},
- CaseRange{0x1FD0, 0x1FD1, d{8, 0, 8}},
- CaseRange{0x1FD8, 0x1FD9, d{0, -8, 0}},
- CaseRange{0x1FDA, 0x1FDB, d{0, -100, 0}},
- CaseRange{0x1FE0, 0x1FE1, d{8, 0, 8}},
- CaseRange{0x1FE5, 0x1FE5, d{7, 0, 7}},
- CaseRange{0x1FE8, 0x1FE9, d{0, -8, 0}},
- CaseRange{0x1FEA, 0x1FEB, d{0, -112, 0}},
- CaseRange{0x1FEC, 0x1FEC, d{0, -7, 0}},
- CaseRange{0x1FF3, 0x1FF3, d{9, 0, 9}},
- CaseRange{0x1FF8, 0x1FF9, d{0, -128, 0}},
- CaseRange{0x1FFA, 0x1FFB, d{0, -126, 0}},
- CaseRange{0x1FFC, 0x1FFC, d{0, -9, 0}},
- CaseRange{0x2126, 0x2126, d{0, -7517, 0}},
- CaseRange{0x212A, 0x212A, d{0, -8383, 0}},
- CaseRange{0x212B, 0x212B, d{0, -8262, 0}},
- CaseRange{0x2132, 0x2132, d{0, 28, 0}},
- CaseRange{0x214E, 0x214E, d{-28, 0, -28}},
- CaseRange{0x2183, 0x2184, d{UpperLower, UpperLower, UpperLower}},
- CaseRange{0x2C00, 0x2C2E, d{0, 48, 0}},
- CaseRange{0x2C30, 0x2C5E, d{-48, 0, -48}},
- CaseRange{0x2C60, 0x2C61, d{UpperLower, UpperLower, UpperLower}},
- CaseRange{0x2C62, 0x2C62, d{0, -10743, 0}},
- CaseRange{0x2C63, 0x2C63, d{0, -3814, 0}},
- CaseRange{0x2C64, 0x2C64, d{0, -10727, 0}},
- CaseRange{0x2C65, 0x2C65, d{-10795, 0, -10795}},
- CaseRange{0x2C66, 0x2C66, d{-10792, 0, -10792}},
- CaseRange{0x2C67, 0x2C6C, d{UpperLower, UpperLower, UpperLower}},
- CaseRange{0x2C6D, 0x2C6D, d{0, -10780, 0}},
- CaseRange{0x2C6E, 0x2C6E, d{0, -10749, 0}},
- CaseRange{0x2C6F, 0x2C6F, d{0, -10783, 0}},
- CaseRange{0x2C70, 0x2C70, d{0, -10782, 0}},
- CaseRange{0x2C72, 0x2C73, d{UpperLower, UpperLower, UpperLower}},
- CaseRange{0x2C75, 0x2C76, d{UpperLower, UpperLower, UpperLower}},
- CaseRange{0x2C7E, 0x2C7F, d{0, -10815, 0}},
- CaseRange{0x2C80, 0x2CE3, d{UpperLower, UpperLower, UpperLower}},
- CaseRange{0x2CEB, 0x2CEE, d{UpperLower, UpperLower, UpperLower}},
- CaseRange{0x2D00, 0x2D25, d{-7264, 0, -7264}},
- CaseRange{0xA640, 0xA65F, d{UpperLower, UpperLower, UpperLower}},
- CaseRange{0xA662, 0xA66D, d{UpperLower, UpperLower, UpperLower}},
- CaseRange{0xA680, 0xA697, d{UpperLower, UpperLower, UpperLower}},
- CaseRange{0xA722, 0xA72F, d{UpperLower, UpperLower, UpperLower}},
- CaseRange{0xA732, 0xA76F, d{UpperLower, UpperLower, UpperLower}},
- CaseRange{0xA779, 0xA77C, d{UpperLower, UpperLower, UpperLower}},
- CaseRange{0xA77D, 0xA77D, d{0, -35332, 0}},
- CaseRange{0xA77E, 0xA787, d{UpperLower, UpperLower, UpperLower}},
- CaseRange{0xA78B, 0xA78C, d{UpperLower, UpperLower, UpperLower}},
- CaseRange{0xFF21, 0xFF3A, d{0, 32, 0}},
- CaseRange{0xFF41, 0xFF5A, d{-32, 0, -32}},
- CaseRange{0x10400, 0x10427, d{0, 40, 0}},
- CaseRange{0x10428, 0x1044F, d{-40, 0, -40}},
+ {0x0041, 0x005A, d{0, 32, 0}},
+ {0x0061, 0x007A, d{-32, 0, -32}},
+ {0x00B5, 0x00B5, d{743, 0, 743}},
+ {0x00C0, 0x00D6, d{0, 32, 0}},
+ {0x00D8, 0x00DE, d{0, 32, 0}},
+ {0x00E0, 0x00F6, d{-32, 0, -32}},
+ {0x00F8, 0x00FE, d{-32, 0, -32}},
+ {0x00FF, 0x00FF, d{121, 0, 121}},
+ {0x0100, 0x012F, d{UpperLower, UpperLower, UpperLower}},
+ {0x0130, 0x0130, d{0, -199, 0}},
+ {0x0131, 0x0131, d{-232, 0, -232}},
+ {0x0132, 0x0137, d{UpperLower, UpperLower, UpperLower}},
+ {0x0139, 0x0148, d{UpperLower, UpperLower, UpperLower}},
+ {0x014A, 0x0177, d{UpperLower, UpperLower, UpperLower}},
+ {0x0178, 0x0178, d{0, -121, 0}},
+ {0x0179, 0x017E, d{UpperLower, UpperLower, UpperLower}},
+ {0x017F, 0x017F, d{-300, 0, -300}},
+ {0x0180, 0x0180, d{195, 0, 195}},
+ {0x0181, 0x0181, d{0, 210, 0}},
+ {0x0182, 0x0185, d{UpperLower, UpperLower, UpperLower}},
+ {0x0186, 0x0186, d{0, 206, 0}},
+ {0x0187, 0x0188, d{UpperLower, UpperLower, UpperLower}},
+ {0x0189, 0x018A, d{0, 205, 0}},
+ {0x018B, 0x018C, d{UpperLower, UpperLower, UpperLower}},
+ {0x018E, 0x018E, d{0, 79, 0}},
+ {0x018F, 0x018F, d{0, 202, 0}},
+ {0x0190, 0x0190, d{0, 203, 0}},
+ {0x0191, 0x0192, d{UpperLower, UpperLower, UpperLower}},
+ {0x0193, 0x0193, d{0, 205, 0}},
+ {0x0194, 0x0194, d{0, 207, 0}},
+ {0x0195, 0x0195, d{97, 0, 97}},
+ {0x0196, 0x0196, d{0, 211, 0}},
+ {0x0197, 0x0197, d{0, 209, 0}},
+ {0x0198, 0x0199, d{UpperLower, UpperLower, UpperLower}},
+ {0x019A, 0x019A, d{163, 0, 163}},
+ {0x019C, 0x019C, d{0, 211, 0}},
+ {0x019D, 0x019D, d{0, 213, 0}},
+ {0x019E, 0x019E, d{130, 0, 130}},
+ {0x019F, 0x019F, d{0, 214, 0}},
+ {0x01A0, 0x01A5, d{UpperLower, UpperLower, UpperLower}},
+ {0x01A6, 0x01A6, d{0, 218, 0}},
+ {0x01A7, 0x01A8, d{UpperLower, UpperLower, UpperLower}},
+ {0x01A9, 0x01A9, d{0, 218, 0}},
+ {0x01AC, 0x01AD, d{UpperLower, UpperLower, UpperLower}},
+ {0x01AE, 0x01AE, d{0, 218, 0}},
+ {0x01AF, 0x01B0, d{UpperLower, UpperLower, UpperLower}},
+ {0x01B1, 0x01B2, d{0, 217, 0}},
+ {0x01B3, 0x01B6, d{UpperLower, UpperLower, UpperLower}},
+ {0x01B7, 0x01B7, d{0, 219, 0}},
+ {0x01B8, 0x01B9, d{UpperLower, UpperLower, UpperLower}},
+ {0x01BC, 0x01BD, d{UpperLower, UpperLower, UpperLower}},
+ {0x01BF, 0x01BF, d{56, 0, 56}},
+ {0x01C4, 0x01C4, d{0, 2, 1}},
+ {0x01C5, 0x01C5, d{-1, 1, 0}},
+ {0x01C6, 0x01C6, d{-2, 0, -1}},
+ {0x01C7, 0x01C7, d{0, 2, 1}},
+ {0x01C8, 0x01C8, d{-1, 1, 0}},
+ {0x01C9, 0x01C9, d{-2, 0, -1}},
+ {0x01CA, 0x01CA, d{0, 2, 1}},
+ {0x01CB, 0x01CB, d{-1, 1, 0}},
+ {0x01CC, 0x01CC, d{-2, 0, -1}},
+ {0x01CD, 0x01DC, d{UpperLower, UpperLower, UpperLower}},
+ {0x01DD, 0x01DD, d{-79, 0, -79}},
+ {0x01DE, 0x01EF, d{UpperLower, UpperLower, UpperLower}},
+ {0x01F1, 0x01F1, d{0, 2, 1}},
+ {0x01F2, 0x01F2, d{-1, 1, 0}},
+ {0x01F3, 0x01F3, d{-2, 0, -1}},
+ {0x01F4, 0x01F5, d{UpperLower, UpperLower, UpperLower}},
+ {0x01F6, 0x01F6, d{0, -97, 0}},
+ {0x01F7, 0x01F7, d{0, -56, 0}},
+ {0x01F8, 0x021F, d{UpperLower, UpperLower, UpperLower}},
+ {0x0220, 0x0220, d{0, -130, 0}},
+ {0x0222, 0x0233, d{UpperLower, UpperLower, UpperLower}},
+ {0x023A, 0x023A, d{0, 10795, 0}},
+ {0x023B, 0x023C, d{UpperLower, UpperLower, UpperLower}},
+ {0x023D, 0x023D, d{0, -163, 0}},
+ {0x023E, 0x023E, d{0, 10792, 0}},
+ {0x023F, 0x0240, d{10815, 0, 10815}},
+ {0x0241, 0x0242, d{UpperLower, UpperLower, UpperLower}},
+ {0x0243, 0x0243, d{0, -195, 0}},
+ {0x0244, 0x0244, d{0, 69, 0}},
+ {0x0245, 0x0245, d{0, 71, 0}},
+ {0x0246, 0x024F, d{UpperLower, UpperLower, UpperLower}},
+ {0x0250, 0x0250, d{10783, 0, 10783}},
+ {0x0251, 0x0251, d{10780, 0, 10780}},
+ {0x0252, 0x0252, d{10782, 0, 10782}},
+ {0x0253, 0x0253, d{-210, 0, -210}},
+ {0x0254, 0x0254, d{-206, 0, -206}},
+ {0x0256, 0x0257, d{-205, 0, -205}},
+ {0x0259, 0x0259, d{-202, 0, -202}},
+ {0x025B, 0x025B, d{-203, 0, -203}},
+ {0x0260, 0x0260, d{-205, 0, -205}},
+ {0x0263, 0x0263, d{-207, 0, -207}},
+ {0x0268, 0x0268, d{-209, 0, -209}},
+ {0x0269, 0x0269, d{-211, 0, -211}},
+ {0x026B, 0x026B, d{10743, 0, 10743}},
+ {0x026F, 0x026F, d{-211, 0, -211}},
+ {0x0271, 0x0271, d{10749, 0, 10749}},
+ {0x0272, 0x0272, d{-213, 0, -213}},
+ {0x0275, 0x0275, d{-214, 0, -214}},
+ {0x027D, 0x027D, d{10727, 0, 10727}},
+ {0x0280, 0x0280, d{-218, 0, -218}},
+ {0x0283, 0x0283, d{-218, 0, -218}},
+ {0x0288, 0x0288, d{-218, 0, -218}},
+ {0x0289, 0x0289, d{-69, 0, -69}},
+ {0x028A, 0x028B, d{-217, 0, -217}},
+ {0x028C, 0x028C, d{-71, 0, -71}},
+ {0x0292, 0x0292, d{-219, 0, -219}},
+ {0x0370, 0x0373, d{UpperLower, UpperLower, UpperLower}},
+ {0x0376, 0x0377, d{UpperLower, UpperLower, UpperLower}},
+ {0x037B, 0x037D, d{130, 0, 130}},
+ {0x0386, 0x0386, d{0, 38, 0}},
+ {0x0388, 0x038A, d{0, 37, 0}},
+ {0x038C, 0x038C, d{0, 64, 0}},
+ {0x038E, 0x038F, d{0, 63, 0}},
+ {0x0391, 0x03A1, d{0, 32, 0}},
+ {0x03A3, 0x03AB, d{0, 32, 0}},
+ {0x03AC, 0x03AC, d{-38, 0, -38}},
+ {0x03AD, 0x03AF, d{-37, 0, -37}},
+ {0x03B1, 0x03C1, d{-32, 0, -32}},
+ {0x03C2, 0x03C2, d{-31, 0, -31}},
+ {0x03C3, 0x03CB, d{-32, 0, -32}},
+ {0x03CC, 0x03CC, d{-64, 0, -64}},
+ {0x03CD, 0x03CE, d{-63, 0, -63}},
+ {0x03CF, 0x03CF, d{0, 8, 0}},
+ {0x03D0, 0x03D0, d{-62, 0, -62}},
+ {0x03D1, 0x03D1, d{-57, 0, -57}},
+ {0x03D5, 0x03D5, d{-47, 0, -47}},
+ {0x03D6, 0x03D6, d{-54, 0, -54}},
+ {0x03D7, 0x03D7, d{-8, 0, -8}},
+ {0x03D8, 0x03EF, d{UpperLower, UpperLower, UpperLower}},
+ {0x03F0, 0x03F0, d{-86, 0, -86}},
+ {0x03F1, 0x03F1, d{-80, 0, -80}},
+ {0x03F2, 0x03F2, d{7, 0, 7}},
+ {0x03F4, 0x03F4, d{0, -60, 0}},
+ {0x03F5, 0x03F5, d{-96, 0, -96}},
+ {0x03F7, 0x03F8, d{UpperLower, UpperLower, UpperLower}},
+ {0x03F9, 0x03F9, d{0, -7, 0}},
+ {0x03FA, 0x03FB, d{UpperLower, UpperLower, UpperLower}},
+ {0x03FD, 0x03FF, d{0, -130, 0}},
+ {0x0400, 0x040F, d{0, 80, 0}},
+ {0x0410, 0x042F, d{0, 32, 0}},
+ {0x0430, 0x044F, d{-32, 0, -32}},
+ {0x0450, 0x045F, d{-80, 0, -80}},
+ {0x0460, 0x0481, d{UpperLower, UpperLower, UpperLower}},
+ {0x048A, 0x04BF, d{UpperLower, UpperLower, UpperLower}},
+ {0x04C0, 0x04C0, d{0, 15, 0}},
+ {0x04C1, 0x04CE, d{UpperLower, UpperLower, UpperLower}},
+ {0x04CF, 0x04CF, d{-15, 0, -15}},
+ {0x04D0, 0x0525, d{UpperLower, UpperLower, UpperLower}},
+ {0x0531, 0x0556, d{0, 48, 0}},
+ {0x0561, 0x0586, d{-48, 0, -48}},
+ {0x10A0, 0x10C5, d{0, 7264, 0}},
+ {0x1D79, 0x1D79, d{35332, 0, 35332}},
+ {0x1D7D, 0x1D7D, d{3814, 0, 3814}},
+ {0x1E00, 0x1E95, d{UpperLower, UpperLower, UpperLower}},
+ {0x1E9B, 0x1E9B, d{-59, 0, -59}},
+ {0x1E9E, 0x1E9E, d{0, -7615, 0}},
+ {0x1EA0, 0x1EFF, d{UpperLower, UpperLower, UpperLower}},
+ {0x1F00, 0x1F07, d{8, 0, 8}},
+ {0x1F08, 0x1F0F, d{0, -8, 0}},
+ {0x1F10, 0x1F15, d{8, 0, 8}},
+ {0x1F18, 0x1F1D, d{0, -8, 0}},
+ {0x1F20, 0x1F27, d{8, 0, 8}},
+ {0x1F28, 0x1F2F, d{0, -8, 0}},
+ {0x1F30, 0x1F37, d{8, 0, 8}},
+ {0x1F38, 0x1F3F, d{0, -8, 0}},
+ {0x1F40, 0x1F45, d{8, 0, 8}},
+ {0x1F48, 0x1F4D, d{0, -8, 0}},
+ {0x1F51, 0x1F51, d{8, 0, 8}},
+ {0x1F53, 0x1F53, d{8, 0, 8}},
+ {0x1F55, 0x1F55, d{8, 0, 8}},
+ {0x1F57, 0x1F57, d{8, 0, 8}},
+ {0x1F59, 0x1F59, d{0, -8, 0}},
+ {0x1F5B, 0x1F5B, d{0, -8, 0}},
+ {0x1F5D, 0x1F5D, d{0, -8, 0}},
+ {0x1F5F, 0x1F5F, d{0, -8, 0}},
+ {0x1F60, 0x1F67, d{8, 0, 8}},
+ {0x1F68, 0x1F6F, d{0, -8, 0}},
+ {0x1F70, 0x1F71, d{74, 0, 74}},
+ {0x1F72, 0x1F75, d{86, 0, 86}},
+ {0x1F76, 0x1F77, d{100, 0, 100}},
+ {0x1F78, 0x1F79, d{128, 0, 128}},
+ {0x1F7A, 0x1F7B, d{112, 0, 112}},
+ {0x1F7C, 0x1F7D, d{126, 0, 126}},
+ {0x1F80, 0x1F87, d{8, 0, 8}},
+ {0x1F88, 0x1F8F, d{0, -8, 0}},
+ {0x1F90, 0x1F97, d{8, 0, 8}},
+ {0x1F98, 0x1F9F, d{0, -8, 0}},
+ {0x1FA0, 0x1FA7, d{8, 0, 8}},
+ {0x1FA8, 0x1FAF, d{0, -8, 0}},
+ {0x1FB0, 0x1FB1, d{8, 0, 8}},
+ {0x1FB3, 0x1FB3, d{9, 0, 9}},
+ {0x1FB8, 0x1FB9, d{0, -8, 0}},
+ {0x1FBA, 0x1FBB, d{0, -74, 0}},
+ {0x1FBC, 0x1FBC, d{0, -9, 0}},
+ {0x1FBE, 0x1FBE, d{-7205, 0, -7205}},
+ {0x1FC3, 0x1FC3, d{9, 0, 9}},
+ {0x1FC8, 0x1FCB, d{0, -86, 0}},
+ {0x1FCC, 0x1FCC, d{0, -9, 0}},
+ {0x1FD0, 0x1FD1, d{8, 0, 8}},
+ {0x1FD8, 0x1FD9, d{0, -8, 0}},
+ {0x1FDA, 0x1FDB, d{0, -100, 0}},
+ {0x1FE0, 0x1FE1, d{8, 0, 8}},
+ {0x1FE5, 0x1FE5, d{7, 0, 7}},
+ {0x1FE8, 0x1FE9, d{0, -8, 0}},
+ {0x1FEA, 0x1FEB, d{0, -112, 0}},
+ {0x1FEC, 0x1FEC, d{0, -7, 0}},
+ {0x1FF3, 0x1FF3, d{9, 0, 9}},
+ {0x1FF8, 0x1FF9, d{0, -128, 0}},
+ {0x1FFA, 0x1FFB, d{0, -126, 0}},
+ {0x1FFC, 0x1FFC, d{0, -9, 0}},
+ {0x2126, 0x2126, d{0, -7517, 0}},
+ {0x212A, 0x212A, d{0, -8383, 0}},
+ {0x212B, 0x212B, d{0, -8262, 0}},
+ {0x2132, 0x2132, d{0, 28, 0}},
+ {0x214E, 0x214E, d{-28, 0, -28}},
+ {0x2183, 0x2184, d{UpperLower, UpperLower, UpperLower}},
+ {0x2C00, 0x2C2E, d{0, 48, 0}},
+ {0x2C30, 0x2C5E, d{-48, 0, -48}},
+ {0x2C60, 0x2C61, d{UpperLower, UpperLower, UpperLower}},
+ {0x2C62, 0x2C62, d{0, -10743, 0}},
+ {0x2C63, 0x2C63, d{0, -3814, 0}},
+ {0x2C64, 0x2C64, d{0, -10727, 0}},
+ {0x2C65, 0x2C65, d{-10795, 0, -10795}},
+ {0x2C66, 0x2C66, d{-10792, 0, -10792}},
+ {0x2C67, 0x2C6C, d{UpperLower, UpperLower, UpperLower}},
+ {0x2C6D, 0x2C6D, d{0, -10780, 0}},
+ {0x2C6E, 0x2C6E, d{0, -10749, 0}},
+ {0x2C6F, 0x2C6F, d{0, -10783, 0}},
+ {0x2C70, 0x2C70, d{0, -10782, 0}},
+ {0x2C72, 0x2C73, d{UpperLower, UpperLower, UpperLower}},
+ {0x2C75, 0x2C76, d{UpperLower, UpperLower, UpperLower}},
+ {0x2C7E, 0x2C7F, d{0, -10815, 0}},
+ {0x2C80, 0x2CE3, d{UpperLower, UpperLower, UpperLower}},
+ {0x2CEB, 0x2CEE, d{UpperLower, UpperLower, UpperLower}},
+ {0x2D00, 0x2D25, d{-7264, 0, -7264}},
+ {0xA640, 0xA65F, d{UpperLower, UpperLower, UpperLower}},
+ {0xA662, 0xA66D, d{UpperLower, UpperLower, UpperLower}},
+ {0xA680, 0xA697, d{UpperLower, UpperLower, UpperLower}},
+ {0xA722, 0xA72F, d{UpperLower, UpperLower, UpperLower}},
+ {0xA732, 0xA76F, d{UpperLower, UpperLower, UpperLower}},
+ {0xA779, 0xA77C, d{UpperLower, UpperLower, UpperLower}},
+ {0xA77D, 0xA77D, d{0, -35332, 0}},
+ {0xA77E, 0xA787, d{UpperLower, UpperLower, UpperLower}},
+ {0xA78B, 0xA78C, d{UpperLower, UpperLower, UpperLower}},
+ {0xFF21, 0xFF3A, d{0, 32, 0}},
+ {0xFF41, 0xFF5A, d{-32, 0, -32}},
+ {0x10400, 0x10427, d{0, 40, 0}},
+ {0x10428, 0x1044F, d{-40, 0, -40}},
}
diff --git a/src/pkg/utf16/Makefile b/src/pkg/utf16/Makefile
index 29e400503..8a564fb0f 100644
--- a/src/pkg/utf16/Makefile
+++ b/src/pkg/utf16/Makefile
@@ -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 ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=utf16
GOFILES=\
diff --git a/src/pkg/utf16/utf16_test.go b/src/pkg/utf16/utf16_test.go
index c0848aa38..2b9fb3d87 100644
--- a/src/pkg/utf16/utf16_test.go
+++ b/src/pkg/utf16/utf16_test.go
@@ -2,13 +2,14 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package utf16
+package utf16_test
import (
"fmt"
"reflect"
"testing"
"unicode"
+ . "utf16"
)
type encodeTest struct {
@@ -17,10 +18,10 @@ type encodeTest struct {
}
var encodeTests = []encodeTest{
- encodeTest{[]int{1, 2, 3, 4}, []uint16{1, 2, 3, 4}},
- encodeTest{[]int{0xffff, 0x10000, 0x10001, 0x12345, 0x10ffff},
+ {[]int{1, 2, 3, 4}, []uint16{1, 2, 3, 4}},
+ {[]int{0xffff, 0x10000, 0x10001, 0x12345, 0x10ffff},
[]uint16{0xffff, 0xd800, 0xdc00, 0xd800, 0xdc01, 0xd808, 0xdf45, 0xdbff, 0xdfff}},
- encodeTest{[]int{'a', 'b', 0xd7ff, 0xd800, 0xdfff, 0xe000, 0x110000, -1},
+ {[]int{'a', 'b', 0xd7ff, 0xd800, 0xdfff, 0xe000, 0x110000, -1},
[]uint16{'a', 'b', 0xd7ff, 0xfffd, 0xfffd, 0xe000, 0xfffd, 0xfffd}},
}
@@ -74,11 +75,11 @@ type decodeTest struct {
}
var decodeTests = []decodeTest{
- decodeTest{[]uint16{1, 2, 3, 4}, []int{1, 2, 3, 4}},
- decodeTest{[]uint16{0xffff, 0xd800, 0xdc00, 0xd800, 0xdc01, 0xd808, 0xdf45, 0xdbff, 0xdfff},
+ {[]uint16{1, 2, 3, 4}, []int{1, 2, 3, 4}},
+ {[]uint16{0xffff, 0xd800, 0xdc00, 0xd800, 0xdc01, 0xd808, 0xdf45, 0xdbff, 0xdfff},
[]int{0xffff, 0x10000, 0x10001, 0x12345, 0x10ffff}},
- decodeTest{[]uint16{0xd800, 'a'}, []int{0xfffd, 'a'}},
- decodeTest{[]uint16{0xdfff}, []int{0xfffd}},
+ {[]uint16{0xd800, 'a'}, []int{0xfffd, 'a'}},
+ {[]uint16{0xdfff}, []int{0xfffd}},
}
func TestDecode(t *testing.T) {
diff --git a/src/pkg/utf8/Makefile b/src/pkg/utf8/Makefile
index a013913c3..b3574ba3b 100644
--- a/src/pkg/utf8/Makefile
+++ b/src/pkg/utf8/Makefile
@@ -2,10 +2,11 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.$(GOARCH)
+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
new file mode 100644
index 000000000..83b56b944
--- /dev/null
+++ b/src/pkg/utf8/string.go
@@ -0,0 +1,211 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package utf8
+
+// String wraps a regular string with a small structure that provides more
+// efficient indexing by code point index, as opposed to byte index.
+// Scanning incrementally forwards or backwards is O(1) per index operation
+// (although not as fast a range clause going forwards). Random access is
+// O(N) in the length of the string, but the overhead is less than always
+// scanning from the beginning.
+// If the string is ASCII, random access is O(1).
+// Unlike the built-in string type, String has internal mutable state and
+// is not thread-safe.
+type String struct {
+ str string
+ numRunes int
+ // If width > 0, the rune at runePos starts at bytePos and has the specified width.
+ width int
+ bytePos int
+ runePos int
+ nonASCII int // byte index of the first non-ASCII rune.
+}
+
+// NewString returns a new UTF-8 string with the provided contents.
+func NewString(contents string) *String {
+ return new(String).Init(contents)
+}
+
+// Init initializes an existing String to hold the provided contents.
+// It returns a pointer to the initialized String.
+func (s *String) Init(contents string) *String {
+ s.str = contents
+ s.bytePos = 0
+ s.runePos = 0
+ for i := 0; i < len(contents); i++ {
+ if contents[i] >= RuneSelf {
+ // Not ASCII.
+ s.numRunes = RuneCountInString(contents)
+ _, s.width = DecodeRuneInString(contents)
+ s.nonASCII = i
+ return s
+ }
+ }
+ // ASCII is simple. Also, the empty string is ASCII.
+ s.numRunes = len(contents)
+ s.width = 0
+ s.nonASCII = len(contents)
+ return s
+}
+
+// String returns the contents of the String. This method also means the
+// String is directly printable by fmt.Print.
+func (s *String) String() string {
+ return s.str
+}
+
+// RuneCount returns the number of runes (Unicode code points) in the String.
+func (s *String) RuneCount() int {
+ return s.numRunes
+}
+
+// IsASCII returns a boolean indicating whether the String contains only ASCII bytes.
+func (s *String) IsASCII() bool {
+ return s.width == 0
+}
+
+// Slice returns the string sliced at rune positions [i:j].
+func (s *String) Slice(i, j int) string {
+ // ASCII is easy. Let the compiler catch the indexing error if there is one.
+ if j < s.nonASCII {
+ return s.str[i:j]
+ }
+ if i < 0 || j > s.numRunes || i > j {
+ panic(sliceOutOfRange)
+ }
+ if i == j {
+ return ""
+ }
+ // For non-ASCII, after At(i), bytePos is always the position of the indexed character.
+ var low, high int
+ switch {
+ case i < s.nonASCII:
+ low = i
+ case i == s.numRunes:
+ low = len(s.str)
+ default:
+ s.At(i)
+ low = s.bytePos
+ }
+ switch {
+ case j == s.numRunes:
+ high = len(s.str)
+ default:
+ s.At(j)
+ high = s.bytePos
+ }
+ return s.str[low:high]
+}
+
+// At returns the rune with index i in the String. The sequence of runes is the same
+// as iterating over the contents with a "for range" clause.
+func (s *String) At(i int) int {
+ // ASCII is easy. Let the compiler catch the indexing error if there is one.
+ if i < s.nonASCII {
+ return int(s.str[i])
+ }
+
+ // Now we do need to know the index is valid.
+ if i < 0 || i >= s.numRunes {
+ panic(outOfRange)
+ }
+
+ var rune int
+
+ // Five easy common cases: within 1 spot of bytePos/runePos, or the beginning, or the end.
+ // With these cases, all scans from beginning or end work in O(1) time per rune.
+ switch {
+
+ case i == s.runePos-1: // backing up one rune
+ rune, s.width = DecodeLastRuneInString(s.str[0:s.bytePos])
+ s.runePos = i
+ s.bytePos -= s.width
+ return rune
+ case i == s.runePos+1: // moving ahead one rune
+ s.runePos = i
+ s.bytePos += s.width
+ fallthrough
+ case i == s.runePos:
+ rune, s.width = DecodeRuneInString(s.str[s.bytePos:])
+ return rune
+ case i == 0: // start of string
+ rune, s.width = DecodeRuneInString(s.str)
+ s.runePos = 0
+ s.bytePos = 0
+ return rune
+
+ case i == s.numRunes-1: // last rune in string
+ rune, s.width = DecodeLastRuneInString(s.str)
+ s.runePos = i
+ s.bytePos = len(s.str) - s.width
+ return rune
+ }
+
+ // We need to do a linear scan. There are three places to start from:
+ // 1) The beginning
+ // 2) bytePos/runePos.
+ // 3) The end
+ // Choose the closest in rune count, scanning backwards if necessary.
+ forward := true
+ if i < s.runePos {
+ // Between beginning and pos. Which is closer?
+ // Since both i and runePos are guaranteed >= nonASCII, that's the
+ // lowest location we need to start from.
+ if i < (s.runePos-s.nonASCII)/2 {
+ // Scan forward from beginning
+ s.bytePos, s.runePos = s.nonASCII, s.nonASCII
+ } else {
+ // Scan backwards from where we are
+ forward = false
+ }
+ } else {
+ // Between pos and end. Which is closer?
+ if i-s.runePos < (s.numRunes-s.runePos)/2 {
+ // Scan forward from pos
+ } else {
+ // Scan backwards from end
+ s.bytePos, s.runePos = len(s.str), s.numRunes
+ forward = false
+ }
+ }
+ if forward {
+ // TODO: Is it much faster to use a range loop for this scan?
+ for {
+ rune, s.width = DecodeRuneInString(s.str[s.bytePos:])
+ if s.runePos == i {
+ break
+ }
+ s.runePos++
+ s.bytePos += s.width
+ }
+ } else {
+ for {
+ rune, s.width = DecodeLastRuneInString(s.str[0:s.bytePos])
+ s.runePos--
+ s.bytePos -= s.width
+ if s.runePos == i {
+ break
+ }
+ }
+ }
+ return rune
+}
+
+// We want the panic in At(i) to satisfy os.Error, because that's what
+// runtime panics satisfy, but we can't import os. This is our solution.
+
+// error is the type of the error returned if a user calls String.At(i) with i out of range.
+// It satisfies os.Error and runtime.Error.
+type error string
+
+func (err error) String() string {
+ return string(err)
+}
+
+func (err error) RunTimeError() {
+}
+
+var outOfRange = error("utf8.String: index out of range")
+var sliceOutOfRange = error("utf8.String: slice index out of range")
diff --git a/src/pkg/utf8/string_test.go b/src/pkg/utf8/string_test.go
new file mode 100644
index 000000000..9dd847247
--- /dev/null
+++ b/src/pkg/utf8/string_test.go
@@ -0,0 +1,109 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package utf8_test
+
+import (
+ "rand"
+ "testing"
+ . "utf8"
+)
+
+func TestScanForwards(t *testing.T) {
+ for _, s := range testStrings {
+ runes := []int(s)
+ str := NewString(s)
+ if str.RuneCount() != len(runes) {
+ t.Errorf("%s: expected %d runes; got %d", s, len(runes), str.RuneCount())
+ break
+ }
+ for i, expect := range runes {
+ got := str.At(i)
+ if got != expect {
+ t.Errorf("%s[%d]: expected %c (%U); got %c (%U)", s, i, expect, expect, got, got)
+ }
+ }
+ }
+}
+
+func TestScanBackwards(t *testing.T) {
+ for _, s := range testStrings {
+ runes := []int(s)
+ str := NewString(s)
+ if str.RuneCount() != len(runes) {
+ t.Errorf("%s: expected %d runes; got %d", s, len(runes), str.RuneCount())
+ break
+ }
+ for i := len(runes) - 1; i >= 0; i-- {
+ expect := runes[i]
+ got := str.At(i)
+ if got != expect {
+ t.Errorf("%s[%d]: expected %c (%U); got %c (%U)", s, i, expect, expect, got, got)
+ }
+ }
+ }
+}
+
+const randCount = 100000
+
+func TestRandomAccess(t *testing.T) {
+ for _, s := range testStrings {
+ if len(s) == 0 {
+ continue
+ }
+ runes := []int(s)
+ str := NewString(s)
+ if str.RuneCount() != len(runes) {
+ t.Errorf("%s: expected %d runes; got %d", s, len(runes), str.RuneCount())
+ break
+ }
+ for j := 0; j < randCount; j++ {
+ i := rand.Intn(len(runes))
+ expect := runes[i]
+ got := str.At(i)
+ if got != expect {
+ t.Errorf("%s[%d]: expected %c (%U); got %c (%U)", s, i, expect, expect, got, got)
+ }
+ }
+ }
+}
+
+func TestRandomSliceAccess(t *testing.T) {
+ for _, s := range testStrings {
+ if len(s) == 0 || s[0] == '\x80' { // the bad-UTF-8 string fools this simple test
+ continue
+ }
+ runes := []int(s)
+ str := NewString(s)
+ if str.RuneCount() != len(runes) {
+ t.Errorf("%s: expected %d runes; got %d", s, len(runes), str.RuneCount())
+ break
+ }
+ for k := 0; k < randCount; k++ {
+ i := rand.Intn(len(runes))
+ j := rand.Intn(len(runes) + 1)
+ if i > j { // include empty strings
+ continue
+ }
+ expect := string(runes[i:j])
+ got := str.Slice(i, j)
+ if got != expect {
+ t.Errorf("%s[%d:%d]: expected %q got %q", s, i, j, expect, got)
+ }
+ }
+ }
+}
+
+func TestLimitSliceAccess(t *testing.T) {
+ for _, s := range testStrings {
+ str := NewString(s)
+ if str.Slice(0, 0) != "" {
+ t.Error("failure with empty slice at beginning")
+ }
+ nr := RuneCountInString(s)
+ if str.Slice(nr, nr) != "" {
+ t.Error("failure with empty slice at end")
+ }
+ }
+}
diff --git a/src/pkg/utf8/utf8.go b/src/pkg/utf8/utf8.go
index 8e373e32d..455499e4d 100644
--- a/src/pkg/utf8/utf8.go
+++ b/src/pkg/utf8/utf8.go
@@ -209,6 +209,73 @@ func DecodeRuneInString(s string) (rune, size int) {
return
}
+// DecodeLastRune unpacks the last UTF-8 encoding in p
+// and returns the rune and its width in bytes.
+func DecodeLastRune(p []byte) (rune, size int) {
+ end := len(p)
+ if end == 0 {
+ return RuneError, 0
+ }
+ start := end - 1
+ rune = int(p[start])
+ if rune < RuneSelf {
+ return rune, 1
+ }
+ // guard against O(n^2) behavior when traversing
+ // backwards through strings with long sequences of
+ // invalid UTF-8.
+ lim := end - UTFMax
+ if lim < 0 {
+ lim = 0
+ }
+ for start--; start >= lim; start-- {
+ if RuneStart(p[start]) {
+ break
+ }
+ }
+ if start < 0 {
+ start = 0
+ }
+ rune, size = DecodeRune(p[start:end])
+ if start+size != end {
+ return RuneError, 1
+ }
+ return rune, size
+}
+
+// DecodeLastRuneInString is like DecodeLastRune but its input is a string.
+func DecodeLastRuneInString(s string) (rune, size int) {
+ end := len(s)
+ if end == 0 {
+ return RuneError, 0
+ }
+ start := end - 1
+ rune = int(s[start])
+ if rune < RuneSelf {
+ return rune, 1
+ }
+ // guard against O(n^2) behavior when traversing
+ // backwards through strings with long sequences of
+ // invalid UTF-8.
+ lim := end - UTFMax
+ if lim < 0 {
+ lim = 0
+ }
+ for start--; start >= lim; start-- {
+ if RuneStart(s[start]) {
+ break
+ }
+ }
+ if start < 0 {
+ start = 0
+ }
+ rune, size = DecodeRuneInString(s[start:end])
+ if start+size != end {
+ return RuneError, 1
+ }
+ return rune, size
+}
+
// RuneLen returns the number of bytes required to encode the rune.
func RuneLen(rune int) int {
switch {
@@ -226,7 +293,7 @@ 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(rune int, p []byte) int {
+func EncodeRune(p []byte, rune int) int {
// Negative values are erroneous. Making it unsigned addresses the problem.
r := uint(rune)
diff --git a/src/pkg/utf8/utf8_test.go b/src/pkg/utf8/utf8_test.go
index 2466cf554..7a1db93e5 100644
--- a/src/pkg/utf8/utf8_test.go
+++ b/src/pkg/utf8/utf8_test.go
@@ -16,51 +16,53 @@ type Utf8Map struct {
}
var utf8map = []Utf8Map{
- Utf8Map{0x0000, "\x00"},
- Utf8Map{0x0001, "\x01"},
- Utf8Map{0x007e, "\x7e"},
- Utf8Map{0x007f, "\x7f"},
- Utf8Map{0x0080, "\xc2\x80"},
- Utf8Map{0x0081, "\xc2\x81"},
- Utf8Map{0x00bf, "\xc2\xbf"},
- Utf8Map{0x00c0, "\xc3\x80"},
- Utf8Map{0x00c1, "\xc3\x81"},
- Utf8Map{0x00c8, "\xc3\x88"},
- Utf8Map{0x00d0, "\xc3\x90"},
- Utf8Map{0x00e0, "\xc3\xa0"},
- Utf8Map{0x00f0, "\xc3\xb0"},
- Utf8Map{0x00f8, "\xc3\xb8"},
- Utf8Map{0x00ff, "\xc3\xbf"},
- Utf8Map{0x0100, "\xc4\x80"},
- Utf8Map{0x07ff, "\xdf\xbf"},
- Utf8Map{0x0800, "\xe0\xa0\x80"},
- Utf8Map{0x0801, "\xe0\xa0\x81"},
- Utf8Map{0xfffe, "\xef\xbf\xbe"},
- Utf8Map{0xffff, "\xef\xbf\xbf"},
- Utf8Map{0x10000, "\xf0\x90\x80\x80"},
- Utf8Map{0x10001, "\xf0\x90\x80\x81"},
- Utf8Map{0x10fffe, "\xf4\x8f\xbf\xbe"},
- Utf8Map{0x10ffff, "\xf4\x8f\xbf\xbf"},
- Utf8Map{0xFFFD, "\xef\xbf\xbd"},
-}
-
-// strings.Bytes with one extra byte at end
-func makeBytes(s string) []byte {
- s += "\x00"
- b := []byte(s)
- return b[0 : len(s)-1]
+ {0x0000, "\x00"},
+ {0x0001, "\x01"},
+ {0x007e, "\x7e"},
+ {0x007f, "\x7f"},
+ {0x0080, "\xc2\x80"},
+ {0x0081, "\xc2\x81"},
+ {0x00bf, "\xc2\xbf"},
+ {0x00c0, "\xc3\x80"},
+ {0x00c1, "\xc3\x81"},
+ {0x00c8, "\xc3\x88"},
+ {0x00d0, "\xc3\x90"},
+ {0x00e0, "\xc3\xa0"},
+ {0x00f0, "\xc3\xb0"},
+ {0x00f8, "\xc3\xb8"},
+ {0x00ff, "\xc3\xbf"},
+ {0x0100, "\xc4\x80"},
+ {0x07ff, "\xdf\xbf"},
+ {0x0800, "\xe0\xa0\x80"},
+ {0x0801, "\xe0\xa0\x81"},
+ {0xfffe, "\xef\xbf\xbe"},
+ {0xffff, "\xef\xbf\xbf"},
+ {0x10000, "\xf0\x90\x80\x80"},
+ {0x10001, "\xf0\x90\x80\x81"},
+ {0x10fffe, "\xf4\x8f\xbf\xbe"},
+ {0x10ffff, "\xf4\x8f\xbf\xbf"},
+ {0xFFFD, "\xef\xbf\xbd"},
+}
+
+var testStrings = []string{
+ "",
+ "abcd",
+ "☺☻☹",
+ "日a本b語ç日ð本Ê語þ日¥本¼語i日©",
+ "日a本b語ç日ð本Ê語þ日¥本¼語i日©日a本b語ç日ð本Ê語þ日¥本¼語i日©日a本b語ç日ð本Ê語þ日¥本¼語i日©",
+ "\x80\x80\x80\x80",
}
func TestFullRune(t *testing.T) {
for i := 0; i < len(utf8map); i++ {
m := utf8map[i]
- b := makeBytes(m.str)
+ b := []byte(m.str)
if !FullRune(b) {
- t.Errorf("FullRune(%q) (rune %04x) = false, want true", b, m.rune)
+ t.Errorf("FullRune(%q) (%U) = false, want true", b, m.rune)
}
s := m.str
if !FullRuneInString(s) {
- t.Errorf("FullRuneInString(%q) (rune %04x) = false, want true", s, m.rune)
+ t.Errorf("FullRuneInString(%q) (%U) = false, want true", s, m.rune)
}
b1 := b[0 : len(b)-1]
if FullRune(b1) {
@@ -76,9 +78,9 @@ func TestFullRune(t *testing.T) {
func TestEncodeRune(t *testing.T) {
for i := 0; i < len(utf8map); i++ {
m := utf8map[i]
- b := makeBytes(m.str)
+ b := []byte(m.str)
var buf [10]byte
- n := EncodeRune(m.rune, buf[0:])
+ n := EncodeRune(buf[0:], m.rune)
b1 := buf[0:n]
if !bytes.Equal(b, b1) {
t.Errorf("EncodeRune(%#04x) = %q want %q", m.rune, b1, b)
@@ -89,7 +91,7 @@ func TestEncodeRune(t *testing.T) {
func TestDecodeRune(t *testing.T) {
for i := 0; i < len(utf8map); i++ {
m := utf8map[i]
- b := makeBytes(m.str)
+ 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))
@@ -141,15 +143,108 @@ func TestDecodeRune(t *testing.T) {
if rune != RuneError || size != 1 {
t.Errorf("DecodeRuneInString(%q) = %#04x, %d want %#04x, %d", s, rune, size, RuneError, 1)
}
+
+ }
+}
+
+// Check that DecodeRune and DecodeLastRune correspond to
+// the equivalent range loop.
+func TestSequencing(t *testing.T) {
+ for _, ts := range testStrings {
+ for _, m := range utf8map {
+ for _, s := range []string{ts + m.str, m.str + ts, ts + m.str + ts} {
+ testSequence(t, s)
+ }
+ }
+ }
+}
+
+// Check that a range loop and a []int conversion visit the same runes.
+// Not really a test of this package, but the assumption is used here and
+// it's good to verify
+func TestIntConversion(t *testing.T) {
+ for _, ts := range testStrings {
+ runes := []int(ts)
+ if RuneCountInString(ts) != len(runes) {
+ t.Errorf("%q: expected %d runes; got %d", ts, len(runes), RuneCountInString(ts))
+ break
+ }
+ i := 0
+ for _, r := range ts {
+ if r != runes[i] {
+ t.Errorf("%q[%d]: expected %c (%U); got %c (%U)", ts, i, runes[i], runes[i], r, r)
+ }
+ i++
+ }
+ }
+}
+
+func testSequence(t *testing.T, s string) {
+ type info struct {
+ index int
+ rune int
+ }
+ index := make([]info, len(s))
+ b := []byte(s)
+ si := 0
+ j := 0
+ for i, r := range s {
+ if si != i {
+ t.Errorf("Sequence(%q) mismatched index %d, want %d", s, si, i)
+ return
+ }
+ index[j] = info{i, r}
+ j++
+ rune1, size1 := DecodeRune(b[i:])
+ if r != rune1 {
+ t.Errorf("DecodeRune(%q) = %#04x, want %#04x", s[i:], rune1, r)
+ return
+ }
+ rune2, size2 := DecodeRuneInString(s[i:])
+ if r != rune2 {
+ t.Errorf("DecodeRuneInString(%q) = %#04x, want %#04x", s[i:], rune2, r)
+ return
+ }
+ if size1 != size2 {
+ t.Errorf("DecodeRune/DecodeRuneInString(%q) size mismatch %d/%d", s[i:], size1, size2)
+ return
+ }
+ si += size1
+ }
+ j--
+ for si = len(s); si > 0; {
+ rune1, size1 := DecodeLastRune(b[0:si])
+ rune2, size2 := DecodeLastRuneInString(s[0:si])
+ if size1 != size2 {
+ t.Errorf("DecodeLastRune/DecodeLastRuneInString(%q, %d) size mismatch %d/%d", s, si, size1, size2)
+ return
+ }
+ if rune1 != index[j].rune {
+ t.Errorf("DecodeLastRune(%q, %d) = %#04x, want %#04x", s, si, rune1, index[j].rune)
+ return
+ }
+ if rune2 != index[j].rune {
+ t.Errorf("DecodeLastRuneInString(%q, %d) = %#04x, want %#04x", s, si, rune2, index[j].rune)
+ return
+ }
+ si -= size1
+ if si != index[j].index {
+ t.Errorf("DecodeLastRune(%q) index mismatch at %d, want %d", s, si, index[j].index)
+ return
+ }
+ j--
+ }
+ if si != 0 {
+ t.Errorf("DecodeLastRune(%q) finished at %d, not 0", s, si)
}
}
// Check that negative runes encode as U+FFFD.
func TestNegativeRune(t *testing.T) {
errorbuf := make([]byte, UTFMax)
- errorbuf = errorbuf[0:EncodeRune(RuneError, errorbuf)]
+ errorbuf = errorbuf[0:EncodeRune(errorbuf, RuneError)]
buf := make([]byte, UTFMax)
- buf = buf[0:EncodeRune(-1, buf)]
+ buf = buf[0:EncodeRune(buf, -1)]
if !bytes.Equal(buf, errorbuf) {
t.Errorf("incorrect encoding [% x] for -1; expected [% x]", buf, errorbuf)
}
@@ -161,10 +256,10 @@ type RuneCountTest struct {
}
var runecounttests = []RuneCountTest{
- RuneCountTest{"abcd", 4},
- RuneCountTest{"☺☻☹", 3},
- RuneCountTest{"1,2,3,4", 7},
- RuneCountTest{"\xe2\x00", 2},
+ {"abcd", 4},
+ {"☺☻☹", 3},
+ {"1,2,3,4", 7},
+ {"\xe2\x00", 2},
}
func TestRuneCount(t *testing.T) {
@@ -173,7 +268,7 @@ func TestRuneCount(t *testing.T) {
if out := RuneCountInString(tt.in); out != tt.out {
t.Errorf("RuneCountInString(%q) = %d, want %d", tt.in, out, tt.out)
}
- if out := RuneCount(makeBytes(tt.in)); out != tt.out {
+ if out := RuneCount([]byte(tt.in)); out != tt.out {
t.Errorf("RuneCount(%q) = %d, want %d", tt.in, out, tt.out)
}
}
@@ -194,14 +289,14 @@ func BenchmarkRuneCountTenJapaneseChars(b *testing.B) {
func BenchmarkEncodeASCIIRune(b *testing.B) {
buf := make([]byte, UTFMax)
for i := 0; i < b.N; i++ {
- EncodeRune('a', buf)
+ EncodeRune(buf, 'a')
}
}
func BenchmarkEncodeJapaneseRune(b *testing.B) {
buf := make([]byte, UTFMax)
for i := 0; i < b.N; i++ {
- EncodeRune('本', buf)
+ EncodeRune(buf, '本')
}
}
diff --git a/src/pkg/websocket/Makefile b/src/pkg/websocket/Makefile
index 145d8f429..6d3c9cbd1 100644
--- a/src/pkg/websocket/Makefile
+++ b/src/pkg/websocket/Makefile
@@ -1,4 +1,4 @@
-include ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=websocket
GOFILES=\
diff --git a/src/pkg/websocket/client.go b/src/pkg/websocket/client.go
index 2966450a6..091345944 100644
--- a/src/pkg/websocket/client.go
+++ b/src/pkg/websocket/client.go
@@ -5,11 +5,10 @@
package websocket
import (
- "encoding/binary"
"bufio"
"bytes"
"container/vector"
- "crypto/md5"
+ "crypto/tls"
"fmt"
"http"
"io"
@@ -24,6 +23,7 @@ type ProtocolError struct {
}
var (
+ ErrBadScheme = os.ErrorString("bad scheme")
ErrBadStatus = &ProtocolError{"bad status"}
ErrBadUpgrade = &ProtocolError{"missing or bad upgrade"}
ErrBadWebSocketOrigin = &ProtocolError{"missing or bad WebSocket-Origin"}
@@ -33,6 +33,17 @@ var (
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++ {
@@ -61,8 +72,9 @@ func newClient(resourceName, host, origin, location, protocol string, rwc io.Rea
}
/*
- Dial opens a new client connection to a Web Socket.
- A trivial example client is:
+Dial opens a new client connection to a Web Socket.
+
+A trivial example client:
package main
@@ -87,21 +99,40 @@ func newClient(resourceName, host, origin, location, protocol string, rwc io.Rea
}
*/
func Dial(url, protocol, origin string) (ws *Conn, err os.Error) {
+ var client net.Conn
+
parsedUrl, err := http.ParseURL(url)
if err != nil {
- return
+ 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
}
- client, err := net.Dial("tcp", "", parsedUrl.Host)
if err != nil {
- return
+ goto Error
}
- return newClient(parsedUrl.RawPath, parsedUrl.Host, origin, url, protocol, client, handshake)
+
+ ws, err = newClient(parsedUrl.RawPath, parsedUrl.Host, origin, url, protocol, client, handshake)
+ if err != nil {
+ goto Error
+ }
+ return
+
+Error:
+ return nil, &DialError{url, protocol, origin, err}
}
/*
- Generates handshake key as described in 4.1 Opening handshake
- step 16 to 22.
- cf. http://www.whatwg.org/specs/web-socket-protocol/
+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.
@@ -123,14 +154,7 @@ func generateKeyNumber() (key string, number uint32) {
// to U+0039 DIGIT NINE (9).
key = fmt.Sprintf("%d", product)
- // 21. Insert /spaces_n/ U+0020 SPACE characters into /key_n/ at random
- // posisions.
- for i := 0; i < spaces; i++ {
- pos := rand.Intn(len(key)-1) + 1
- key = key[0:pos] + " " + key[pos:]
- }
-
- // 22. Insert between one and twelve random characters from the ranges
+ // 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
@@ -139,13 +163,20 @@ func generateKeyNumber() (key string, number uint32) {
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/
+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
@@ -158,35 +189,9 @@ func generateKey3() (key []byte) {
}
/*
- Gets expected from challenge as described in 4.1 Opening handshake
- Step 42 to 43.
- cf. http://www.whatwg.org/specs/web-socket-protocol/
-*/
-func getExpectedForChallenge(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)
- challengeBuf := bytes.NewBuffer(challenge)
- binary.Write(challengeBuf, binary.BigEndian, number1)
- binary.Write(challengeBuf, binary.BigEndian, 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
-}
-
-/*
- Web Socket protocol handshake based on
- http://www.whatwg.org/specs/web-socket-protocol/
- (draft of http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol)
+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.
@@ -258,7 +263,7 @@ func handshake(resourceName, host, origin, location, protocol string, br *bufio.
}
// Step 42-43. get expected data from challange data.
- expected, err := getExpectedForChallenge(number1, number2, key3)
+ expected, err := getChallengeResponse(number1, number2, key3)
if err != nil {
return err
}
@@ -278,8 +283,8 @@ func handshake(resourceName, host, origin, location, protocol string, br *bufio.
}
/*
- Handhake described in (soon obsolete)
- draft-hixie-thewebsocket-protocol-75.
+Handhake described in (soon obsolete)
+draft-hixie-thewebsocket-protocol-75.
*/
func draft75handshake(resourceName, host, origin, location, protocol string, br *bufio.Reader, bw *bufio.Writer) (err os.Error) {
bw.WriteString("GET " + resourceName + " HTTP/1.1\r\n")
diff --git a/src/pkg/websocket/server.go b/src/pkg/websocket/server.go
index 00b537e27..dd797f24e 100644
--- a/src/pkg/websocket/server.go
+++ b/src/pkg/websocket/server.go
@@ -5,17 +5,15 @@
package websocket
import (
- "bytes"
- "crypto/md5"
- "encoding/binary"
"http"
"io"
"strings"
)
/*
- Handler is an interface to a WebSocket.
- A trivial example server is:
+Handler is an interface to a WebSocket.
+
+A trivial example server:
package main
@@ -41,8 +39,8 @@ import (
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.
+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
@@ -59,8 +57,8 @@ func getKeyNumber(s string) (r uint32) {
}
// ServeHTTP implements the http.Handler interface for a Web Socket
-func (f Handler) ServeHTTP(c *http.Conn, req *http.Request) {
- rwc, buf, err := c.Hijack()
+func (f Handler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
+ rwc, buf, err := w.Hijack()
if err != nil {
panic("Hijack failed: " + err.String())
return
@@ -99,7 +97,12 @@ func (f Handler) ServeHTTP(c *http.Conn, req *http.Request) {
return
}
- location := "ws://" + req.Host + req.URL.RawPath
+ var location string
+ if w.UsingTLS() {
+ location = "wss://" + req.Host + req.URL.RawPath
+ } else {
+ location = "ws://" + req.Host + req.URL.RawPath
+ }
// Step 4. get key number in Sec-WebSocket-Key<n> fields.
keyNumber1 := getKeyNumber(key1)
@@ -122,25 +125,11 @@ func (f Handler) ServeHTTP(c *http.Conn, req *http.Request) {
part2 := keyNumber2 / space2
// Step 8. let challenge to be concatination of part1, part2 and key3.
- challenge := make([]byte, 16)
- challengeBuf := bytes.NewBuffer(challenge)
- err = binary.Write(challengeBuf, binary.BigEndian, part1)
- if err != nil {
- return
- }
- err = binary.Write(challengeBuf, binary.BigEndian, part2)
- if err != nil {
- return
- }
- if n := copy(challenge[8:], key3); n != 8 {
- return
- }
// Step 9. get MD5 fingerprint of challenge.
- h := md5.New()
- if _, err = h.Write(challenge); err != nil {
+ response, err := getChallengeResponse(part1, part2, key3)
+ if err != nil {
return
}
- response := h.Sum()
// Step 10. send response status line.
buf.WriteString("HTTP/1.1 101 WebSocket Protocol Handshake\r\n")
@@ -149,7 +138,7 @@ func (f Handler) ServeHTTP(c *http.Conn, req *http.Request) {
buf.WriteString("Connection: Upgrade\r\n")
buf.WriteString("Sec-WebSocket-Location: " + location + "\r\n")
buf.WriteString("Sec-WebSocket-Origin: " + origin + "\r\n")
- protocol, found := req.Header["Sec-WebSocket-Protocol"]
+ protocol, found := req.Header["Sec-Websocket-Protocol"]
if found {
buf.WriteString("Sec-WebSocket-Protocol: " + protocol + "\r\n")
}
@@ -166,42 +155,48 @@ func (f Handler) ServeHTTP(c *http.Conn, req *http.Request) {
/*
- Draft75Handler is an interface to a WebSocket based on
- (soon obsolete) draft-hixie-thewebsocketprotocol-75.
+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(c *http.Conn, req *http.Request) {
+func (f Draft75Handler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
if req.Method != "GET" || req.Proto != "HTTP/1.1" {
- c.WriteHeader(http.StatusBadRequest)
- io.WriteString(c, "Unexpected request")
+ w.WriteHeader(http.StatusBadRequest)
+ io.WriteString(w, "Unexpected request")
return
}
if req.Header["Upgrade"] != "WebSocket" {
- c.WriteHeader(http.StatusBadRequest)
- io.WriteString(c, "missing Upgrade: WebSocket header")
+ w.WriteHeader(http.StatusBadRequest)
+ io.WriteString(w, "missing Upgrade: WebSocket header")
return
}
if req.Header["Connection"] != "Upgrade" {
- c.WriteHeader(http.StatusBadRequest)
- io.WriteString(c, "missing Connection: Upgrade header")
+ w.WriteHeader(http.StatusBadRequest)
+ io.WriteString(w, "missing Connection: Upgrade header")
return
}
origin, found := req.Header["Origin"]
if !found {
- c.WriteHeader(http.StatusBadRequest)
- io.WriteString(c, "missing Origin header")
+ w.WriteHeader(http.StatusBadRequest)
+ io.WriteString(w, "missing Origin header")
return
}
- rwc, buf, err := c.Hijack()
+ rwc, buf, err := w.Hijack()
if err != nil {
panic("Hijack failed: " + err.String())
return
}
defer rwc.Close()
- location := "ws://" + req.Host + req.URL.RawPath
+
+ var location string
+ if w.UsingTLS() {
+ location = "wss://" + req.Host + req.URL.RawPath
+ } else {
+ location = "ws://" + req.Host + req.URL.RawPath
+ }
// TODO(ukai): verify origin,location,protocol.
diff --git a/src/pkg/websocket/websocket.go b/src/pkg/websocket/websocket.go
index bcb42f508..d5996abe1 100644
--- a/src/pkg/websocket/websocket.go
+++ b/src/pkg/websocket/websocket.go
@@ -11,6 +11,8 @@ package websocket
import (
"bufio"
+ "crypto/md5"
+ "encoding/binary"
"io"
"net"
"os"
@@ -25,6 +27,13 @@ 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 {
@@ -37,6 +46,10 @@ type Conn struct {
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.
@@ -46,60 +59,66 @@ func newConn(origin, location, protocol string, buf *bufio.ReadWriter, rwc io.Re
bw := bufio.NewWriter(rwc)
buf = bufio.NewReadWriter(br, bw)
}
- ws := &Conn{origin, location, protocol, buf, rwc}
+ 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) {
- for {
- frameByte, err := ws.buf.ReadByte()
+Frame:
+ for !ws.reading && len(ws.data) == 0 {
+ // Beginning of frame, possibly.
+ b, err := ws.buf.ReadByte()
if err != nil {
- return n, err
+ return 0, err
}
- if (frameByte & 0x80) == 0x80 {
+ if b&0x80 == 0x80 {
+ // Skip length frame.
length := 0
for {
c, err := ws.buf.ReadByte()
if err != nil {
- return n, err
+ return 0, err
}
length = length*128 + int(c&0x7f)
- if (c & 0x80) == 0 {
+ if c&0x80 == 0 {
break
}
}
for length > 0 {
_, err := ws.buf.ReadByte()
if err != nil {
- return n, err
+ return 0, err
}
- length--
}
- } else {
+ continue Frame
+ }
+ // In text mode
+ if b != 0 {
+ // Skip this frame
for {
c, err := ws.buf.ReadByte()
if err != nil {
- return n, err
+ return 0, err
}
if c == '\xff' {
- return n, err
- }
- if frameByte == 0 {
- if n+1 <= cap(msg) {
- msg = msg[0 : n+1]
- }
- msg[n] = c
- n++
- }
- if n >= cap(msg) {
- return n, os.E2BIG
+ break
}
}
+ continue Frame
}
+ ws.reading = true
}
-
- panic("unreachable")
+ 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.
@@ -136,7 +155,7 @@ func (ws *Conn) SetReadTimeout(nsec int64) os.Error {
return os.EINVAL
}
-// SeWritetTimeout sets the connection's network write timeout in nanoseconds.
+// SetWritetTimeout sets the connection's network write timeout in nanoseconds.
func (ws *Conn) SetWriteTimeout(nsec int64) os.Error {
if conn, ok := ws.rwc.(net.Conn); ok {
return conn.SetWriteTimeout(nsec)
@@ -144,4 +163,27 @@ func (ws *Conn) SetWriteTimeout(nsec int64) os.Error {
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
index df7e9f4da..cc4b9dc18 100644
--- a/src/pkg/websocket/websocket_test.go
+++ b/src/pkg/websocket/websocket_test.go
@@ -5,17 +5,19 @@
package websocket
import (
+ "bufio"
"bytes"
"fmt"
"http"
"io"
"log"
"net"
- "once"
+ "sync"
"testing"
)
var serverAddr string
+var once sync.Once
func echoServer(ws *Conn) { io.Copy(ws, ws) }
@@ -25,12 +27,31 @@ func startServer() {
log.Exitf("net.Listen tcp :0 %v", e)
}
serverAddr = l.Addr().String()
- log.Stderr("Test WebSocket server listening on ", serverAddr)
+ log.Print("Test WebSocket server listening on ", serverAddr)
http.Handle("/echo", Handler(echoServer))
http.Handle("/echoDraft75", Draft75Handler(echoServer))
go http.Serve(l, nil)
}
+// Test the getChallengeResponse function with values from section
+// 5.1 of the specification steps 18, 26, and 43 from
+// http://www.whatwg.org/specs/web-socket-protocol/
+func TestChallenge(t *testing.T) {
+ var part1 uint32 = 777007543
+ var part2 uint32 = 114997259
+ key3 := []byte{0x47, 0x30, 0x22, 0x2D, 0x5A, 0x3F, 0x47, 0x58}
+ expected := []byte("0st3Rl&q-2ZU^weu")
+
+ response, err := getChallengeResponse(part1, part2, key3)
+ if err != nil {
+ t.Errorf("getChallengeResponse: returned error %v", err)
+ return
+ }
+ if !bytes.Equal(expected, response) {
+ t.Errorf("getChallengeResponse: expected %q got %q", expected, response)
+ }
+}
+
func TestEcho(t *testing.T) {
once.Do(startServer)
@@ -110,6 +131,23 @@ func TestWithQuery(t *testing.T) {
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)
@@ -117,7 +155,7 @@ func TestHTTP(t *testing.T) {
// specification, the server should abort the WebSocket connection.
_, _, err := http.Get(fmt.Sprintf("http://%s/echo", serverAddr))
if err == nil {
- t.Errorf("Get: unexpected success")
+ t.Error("Get: unexpected success")
return
}
urlerr, ok := err.(*http.URLError)
@@ -143,3 +181,92 @@ func TestHTTPDraft75(t *testing.T) {
t.Errorf("Get: got status %d", r.StatusCode)
}
}
+
+func TestTrailingSpaces(t *testing.T) {
+ // http://code.google.com/p/go/issues/detail?id=955
+ // The last runs of this create keys with trailing spaces that should not be
+ // generated by the client.
+ once.Do(startServer)
+ for i := 0; i < 30; i++ {
+ // body
+ _, err := Dial(fmt.Sprintf("ws://%s/echo", serverAddr), "",
+ "http://localhost/")
+ if err != nil {
+ panic("Dial failed: " + err.String())
+ }
+ }
+}
+
+func TestSmallBuffer(t *testing.T) {
+ // http://code.google.com/p/go/issues/detail?id=1145
+ // Read should be able to handle reading a fragment of a frame.
+ once.Do(startServer)
+
+ // websocket.Dial()
+ client, err := net.Dial("tcp", "", serverAddr)
+ if err != nil {
+ t.Fatal("dialing", err)
+ }
+ ws, err := newClient("/echo", "localhost", "http://localhost",
+ "ws://localhost/echo", "", client, handshake)
+ if err != nil {
+ t.Errorf("WebSocket handshake error: %v", err)
+ return
+ }
+
+ msg := []byte("hello, world\n")
+ if _, err := ws.Write(msg); err != nil {
+ t.Errorf("Write: %v", err)
+ }
+ var small_msg = make([]byte, 8)
+ n, err := ws.Read(small_msg)
+ if err != nil {
+ t.Errorf("Read: %v", err)
+ }
+ if !bytes.Equal(msg[:len(small_msg)], small_msg) {
+ t.Errorf("Echo: expected %q got %q", msg[:len(small_msg)], small_msg)
+ }
+ var second_msg = make([]byte, len(msg))
+ n, err = ws.Read(second_msg)
+ if err != nil {
+ t.Errorf("Read: %v", err)
+ }
+ second_msg = second_msg[0:n]
+ if !bytes.Equal(msg[len(small_msg):], second_msg) {
+ t.Errorf("Echo: expected %q got %q", msg[len(small_msg):], second_msg)
+ }
+ ws.Close()
+
+}
+
+func testSkipLengthFrame(t *testing.T) {
+ b := []byte{'\x80', '\x01', 'x', 0, 'h', 'e', 'l', 'l', 'o', '\xff'}
+ buf := bytes.NewBuffer(b)
+ br := bufio.NewReader(buf)
+ bw := bufio.NewWriter(buf)
+ ws := newConn("http://127.0.0.1/", "ws://127.0.0.1/", "", bufio.NewReadWriter(br, bw), nil)
+ msg := make([]byte, 5)
+ n, err := ws.Read(msg)
+ if err != nil {
+ t.Errorf("Read: %v", err)
+ }
+ if !bytes.Equal(b[4:8], msg[0:n]) {
+ t.Errorf("Read: expected %q got %q", msg[4:8], msg[0:n])
+ }
+}
+
+func testSkipNoUTF8Frame(t *testing.T) {
+ b := []byte{'\x01', 'n', '\xff', 0, 'h', 'e', 'l', 'l', 'o', '\xff'}
+ buf := bytes.NewBuffer(b)
+ br := bufio.NewReader(buf)
+ bw := bufio.NewWriter(buf)
+ ws := newConn("http://127.0.0.1/", "ws://127.0.0.1/", "", bufio.NewReadWriter(br, bw), nil)
+ msg := make([]byte, 5)
+ n, err := ws.Read(msg)
+ if err != nil {
+ t.Errorf("Read: %v", err)
+ }
+ if !bytes.Equal(b[4:8], msg[0:n]) {
+ t.Errorf("Read: expected %q got %q", msg[4:8], msg[0:n])
+ }
+}
diff --git a/src/pkg/xml/Makefile b/src/pkg/xml/Makefile
index 38e32e7a4..b780face6 100644
--- a/src/pkg/xml/Makefile
+++ b/src/pkg/xml/Makefile
@@ -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 ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=xml
diff --git a/src/pkg/xml/read.go b/src/pkg/xml/read.go
index bbceda6b4..9175659b2 100644
--- a/src/pkg/xml/read.go
+++ b/src/pkg/xml/read.go
@@ -233,7 +233,7 @@ func (p *Parser) unmarshal(val reflect.Value, start *StartElement) os.Error {
ncap = 4
}
new := reflect.MakeSlice(typ, n, ncap)
- reflect.ArrayCopy(new, v)
+ reflect.Copy(new, v)
v.Set(new)
}
v.SetLen(n + 1)
@@ -389,12 +389,12 @@ Loop:
case CharData:
if saveData != nil {
- data = bytes.Add(data, t)
+ data = append(data, t...)
}
case Comment:
if saveComment != nil {
- comment = bytes.Add(comment, t)
+ comment = append(comment, t...)
}
}
}
diff --git a/src/pkg/xml/read_test.go b/src/pkg/xml/read_test.go
index a080c016f..9ec1065c2 100644
--- a/src/pkg/xml/read_test.go
+++ b/src/pkg/xml/read_test.go
@@ -119,8 +119,8 @@ var rssFeed = Feed{
XMLName: Name{"http://www.w3.org/2005/Atom", "feed"},
Title: "Code Review - My issues",
Link: []Link{
- Link{Rel: "alternate", Href: "http://codereview.appspot.com/"},
- Link{Rel: "self", Href: "http://codereview.appspot.com/rss/mine/rsc"},
+ {Rel: "alternate", Href: "http://codereview.appspot.com/"},
+ {Rel: "self", Href: "http://codereview.appspot.com/rss/mine/rsc"},
},
Id: "http://codereview.appspot.com/",
Updated: "2009-10-04T01:35:58+00:00",
@@ -129,10 +129,10 @@ var rssFeed = Feed{
InnerXML: "<name>rietveld&lt;&gt;</name>",
},
Entry: []Entry{
- Entry{
+ {
Title: "rietveld: an attempt at pubsubhubbub\n",
Link: []Link{
- Link{Rel: "alternate", Href: "http://codereview.appspot.com/126085"},
+ {Rel: "alternate", Href: "http://codereview.appspot.com/126085"},
},
Updated: "2009-10-04T01:35:58+00:00",
Author: Person{
@@ -176,10 +176,10 @@ the top of feeds.py marked NOTE(rsc).
`,
},
},
- Entry{
+ {
Title: "rietveld: correct tab handling\n",
Link: []Link{
- Link{Rel: "alternate", Href: "http://codereview.appspot.com/124106"},
+ {Rel: "alternate", Href: "http://codereview.appspot.com/124106"},
},
Updated: "2009-10-03T23:02:17+00:00",
Author: Person{
@@ -218,8 +218,8 @@ type FieldNameTest struct {
}
var FieldNameTests = []FieldNameTest{
- FieldNameTest{"Profile-Image", "profileimage"},
- FieldNameTest{"_score", "score"},
+ {"Profile-Image", "profileimage"},
+ {"_score", "score"},
}
func TestFieldName(t *testing.T) {
diff --git a/src/pkg/xml/xml.go b/src/pkg/xml/xml.go
index cd67f6e26..4d9c672d2 100644
--- a/src/pkg/xml/xml.go
+++ b/src/pkg/xml/xml.go
@@ -16,6 +16,7 @@ package xml
import (
"bufio"
"bytes"
+ "fmt"
"io"
"os"
"strconv"
@@ -595,9 +596,7 @@ func (p *Parser) RawToken() (Token, os.Error) {
n := len(attr)
if n >= cap(attr) {
nattr := make([]Attr, n, 2*cap(attr))
- for i, a := range attr {
- nattr[i] = a
- }
+ copy(nattr, attr)
attr = nattr
}
attr = attr[0 : n+1]
@@ -790,7 +789,7 @@ Input:
if quote >= 0 && b == byte(quote) {
break Input
}
- if b == '&' {
+ if b == '&' && !cdata {
// Read escaped character expression up to semicolon.
// XML in all its glory allows a document to define and use
// its own character names with <!ENTITY ...> directives.
@@ -873,6 +872,21 @@ Input:
data := p.buf.Bytes()
data = data[0 : len(data)-trunc]
+ // Inspect each rune for being a disallowed character.
+ buf := data
+ for len(buf) > 0 {
+ r, size := utf8.DecodeRune(buf)
+ if r == utf8.RuneError && size == 1 {
+ p.err = p.syntaxError("invalid UTF-8")
+ return nil
+ }
+ buf = buf[size:]
+ if !isInCharacterRange(r) {
+ p.err = p.syntaxError(fmt.Sprintf("illegal character code %U", r))
+ return nil
+ }
+ }
+
// Must rewrite \r and \r\n into \n.
w := 0
for r := 0; r < len(data); r++ {
@@ -889,6 +903,18 @@ Input:
return data[0:w]
}
+// Decide whether the given rune is in the XML Character Range, per
+// the Char production of http://www.xml.com/axml/testaxml.htm,
+// Section 2.2 Characters.
+func isInCharacterRange(rune int) (inrange bool) {
+ return rune == 0x09 ||
+ rune == 0x0A ||
+ rune == 0x0D ||
+ rune >= 0x20 && rune <= 0xDF77 ||
+ rune >= 0xE000 && rune <= 0xFFFD ||
+ rune >= 0x10000 && rune <= 0x10FFFF
+}
+
// Get name space name: name with a : stuck in the middle.
// The part before the : is the name space identifier.
func (p *Parser) nsname() (name Name, ok bool) {
@@ -957,311 +983,311 @@ func isNameByte(c byte) bool {
// and second corresponds to NameChar.
var first = []unicode.Range{
- unicode.Range{0x003A, 0x003A, 1},
- unicode.Range{0x0041, 0x005A, 1},
- unicode.Range{0x005F, 0x005F, 1},
- unicode.Range{0x0061, 0x007A, 1},
- unicode.Range{0x00C0, 0x00D6, 1},
- unicode.Range{0x00D8, 0x00F6, 1},
- unicode.Range{0x00F8, 0x00FF, 1},
- unicode.Range{0x0100, 0x0131, 1},
- unicode.Range{0x0134, 0x013E, 1},
- unicode.Range{0x0141, 0x0148, 1},
- unicode.Range{0x014A, 0x017E, 1},
- unicode.Range{0x0180, 0x01C3, 1},
- unicode.Range{0x01CD, 0x01F0, 1},
- unicode.Range{0x01F4, 0x01F5, 1},
- unicode.Range{0x01FA, 0x0217, 1},
- unicode.Range{0x0250, 0x02A8, 1},
- unicode.Range{0x02BB, 0x02C1, 1},
- unicode.Range{0x0386, 0x0386, 1},
- unicode.Range{0x0388, 0x038A, 1},
- unicode.Range{0x038C, 0x038C, 1},
- unicode.Range{0x038E, 0x03A1, 1},
- unicode.Range{0x03A3, 0x03CE, 1},
- unicode.Range{0x03D0, 0x03D6, 1},
- unicode.Range{0x03DA, 0x03E0, 2},
- unicode.Range{0x03E2, 0x03F3, 1},
- unicode.Range{0x0401, 0x040C, 1},
- unicode.Range{0x040E, 0x044F, 1},
- unicode.Range{0x0451, 0x045C, 1},
- unicode.Range{0x045E, 0x0481, 1},
- unicode.Range{0x0490, 0x04C4, 1},
- unicode.Range{0x04C7, 0x04C8, 1},
- unicode.Range{0x04CB, 0x04CC, 1},
- unicode.Range{0x04D0, 0x04EB, 1},
- unicode.Range{0x04EE, 0x04F5, 1},
- unicode.Range{0x04F8, 0x04F9, 1},
- unicode.Range{0x0531, 0x0556, 1},
- unicode.Range{0x0559, 0x0559, 1},
- unicode.Range{0x0561, 0x0586, 1},
- unicode.Range{0x05D0, 0x05EA, 1},
- unicode.Range{0x05F0, 0x05F2, 1},
- unicode.Range{0x0621, 0x063A, 1},
- unicode.Range{0x0641, 0x064A, 1},
- unicode.Range{0x0671, 0x06B7, 1},
- unicode.Range{0x06BA, 0x06BE, 1},
- unicode.Range{0x06C0, 0x06CE, 1},
- unicode.Range{0x06D0, 0x06D3, 1},
- unicode.Range{0x06D5, 0x06D5, 1},
- unicode.Range{0x06E5, 0x06E6, 1},
- unicode.Range{0x0905, 0x0939, 1},
- unicode.Range{0x093D, 0x093D, 1},
- unicode.Range{0x0958, 0x0961, 1},
- unicode.Range{0x0985, 0x098C, 1},
- unicode.Range{0x098F, 0x0990, 1},
- unicode.Range{0x0993, 0x09A8, 1},
- unicode.Range{0x09AA, 0x09B0, 1},
- unicode.Range{0x09B2, 0x09B2, 1},
- unicode.Range{0x09B6, 0x09B9, 1},
- unicode.Range{0x09DC, 0x09DD, 1},
- unicode.Range{0x09DF, 0x09E1, 1},
- unicode.Range{0x09F0, 0x09F1, 1},
- unicode.Range{0x0A05, 0x0A0A, 1},
- unicode.Range{0x0A0F, 0x0A10, 1},
- unicode.Range{0x0A13, 0x0A28, 1},
- unicode.Range{0x0A2A, 0x0A30, 1},
- unicode.Range{0x0A32, 0x0A33, 1},
- unicode.Range{0x0A35, 0x0A36, 1},
- unicode.Range{0x0A38, 0x0A39, 1},
- unicode.Range{0x0A59, 0x0A5C, 1},
- unicode.Range{0x0A5E, 0x0A5E, 1},
- unicode.Range{0x0A72, 0x0A74, 1},
- unicode.Range{0x0A85, 0x0A8B, 1},
- unicode.Range{0x0A8D, 0x0A8D, 1},
- unicode.Range{0x0A8F, 0x0A91, 1},
- unicode.Range{0x0A93, 0x0AA8, 1},
- unicode.Range{0x0AAA, 0x0AB0, 1},
- unicode.Range{0x0AB2, 0x0AB3, 1},
- unicode.Range{0x0AB5, 0x0AB9, 1},
- unicode.Range{0x0ABD, 0x0AE0, 0x23},
- unicode.Range{0x0B05, 0x0B0C, 1},
- unicode.Range{0x0B0F, 0x0B10, 1},
- unicode.Range{0x0B13, 0x0B28, 1},
- unicode.Range{0x0B2A, 0x0B30, 1},
- unicode.Range{0x0B32, 0x0B33, 1},
- unicode.Range{0x0B36, 0x0B39, 1},
- unicode.Range{0x0B3D, 0x0B3D, 1},
- unicode.Range{0x0B5C, 0x0B5D, 1},
- unicode.Range{0x0B5F, 0x0B61, 1},
- unicode.Range{0x0B85, 0x0B8A, 1},
- unicode.Range{0x0B8E, 0x0B90, 1},
- unicode.Range{0x0B92, 0x0B95, 1},
- unicode.Range{0x0B99, 0x0B9A, 1},
- unicode.Range{0x0B9C, 0x0B9C, 1},
- unicode.Range{0x0B9E, 0x0B9F, 1},
- unicode.Range{0x0BA3, 0x0BA4, 1},
- unicode.Range{0x0BA8, 0x0BAA, 1},
- unicode.Range{0x0BAE, 0x0BB5, 1},
- unicode.Range{0x0BB7, 0x0BB9, 1},
- unicode.Range{0x0C05, 0x0C0C, 1},
- unicode.Range{0x0C0E, 0x0C10, 1},
- unicode.Range{0x0C12, 0x0C28, 1},
- unicode.Range{0x0C2A, 0x0C33, 1},
- unicode.Range{0x0C35, 0x0C39, 1},
- unicode.Range{0x0C60, 0x0C61, 1},
- unicode.Range{0x0C85, 0x0C8C, 1},
- unicode.Range{0x0C8E, 0x0C90, 1},
- unicode.Range{0x0C92, 0x0CA8, 1},
- unicode.Range{0x0CAA, 0x0CB3, 1},
- unicode.Range{0x0CB5, 0x0CB9, 1},
- unicode.Range{0x0CDE, 0x0CDE, 1},
- unicode.Range{0x0CE0, 0x0CE1, 1},
- unicode.Range{0x0D05, 0x0D0C, 1},
- unicode.Range{0x0D0E, 0x0D10, 1},
- unicode.Range{0x0D12, 0x0D28, 1},
- unicode.Range{0x0D2A, 0x0D39, 1},
- unicode.Range{0x0D60, 0x0D61, 1},
- unicode.Range{0x0E01, 0x0E2E, 1},
- unicode.Range{0x0E30, 0x0E30, 1},
- unicode.Range{0x0E32, 0x0E33, 1},
- unicode.Range{0x0E40, 0x0E45, 1},
- unicode.Range{0x0E81, 0x0E82, 1},
- unicode.Range{0x0E84, 0x0E84, 1},
- unicode.Range{0x0E87, 0x0E88, 1},
- unicode.Range{0x0E8A, 0x0E8D, 3},
- unicode.Range{0x0E94, 0x0E97, 1},
- unicode.Range{0x0E99, 0x0E9F, 1},
- unicode.Range{0x0EA1, 0x0EA3, 1},
- unicode.Range{0x0EA5, 0x0EA7, 2},
- unicode.Range{0x0EAA, 0x0EAB, 1},
- unicode.Range{0x0EAD, 0x0EAE, 1},
- unicode.Range{0x0EB0, 0x0EB0, 1},
- unicode.Range{0x0EB2, 0x0EB3, 1},
- unicode.Range{0x0EBD, 0x0EBD, 1},
- unicode.Range{0x0EC0, 0x0EC4, 1},
- unicode.Range{0x0F40, 0x0F47, 1},
- unicode.Range{0x0F49, 0x0F69, 1},
- unicode.Range{0x10A0, 0x10C5, 1},
- unicode.Range{0x10D0, 0x10F6, 1},
- unicode.Range{0x1100, 0x1100, 1},
- unicode.Range{0x1102, 0x1103, 1},
- unicode.Range{0x1105, 0x1107, 1},
- unicode.Range{0x1109, 0x1109, 1},
- unicode.Range{0x110B, 0x110C, 1},
- unicode.Range{0x110E, 0x1112, 1},
- unicode.Range{0x113C, 0x1140, 2},
- unicode.Range{0x114C, 0x1150, 2},
- unicode.Range{0x1154, 0x1155, 1},
- unicode.Range{0x1159, 0x1159, 1},
- unicode.Range{0x115F, 0x1161, 1},
- unicode.Range{0x1163, 0x1169, 2},
- unicode.Range{0x116D, 0x116E, 1},
- unicode.Range{0x1172, 0x1173, 1},
- unicode.Range{0x1175, 0x119E, 0x119E - 0x1175},
- unicode.Range{0x11A8, 0x11AB, 0x11AB - 0x11A8},
- unicode.Range{0x11AE, 0x11AF, 1},
- unicode.Range{0x11B7, 0x11B8, 1},
- unicode.Range{0x11BA, 0x11BA, 1},
- unicode.Range{0x11BC, 0x11C2, 1},
- unicode.Range{0x11EB, 0x11F0, 0x11F0 - 0x11EB},
- unicode.Range{0x11F9, 0x11F9, 1},
- unicode.Range{0x1E00, 0x1E9B, 1},
- unicode.Range{0x1EA0, 0x1EF9, 1},
- unicode.Range{0x1F00, 0x1F15, 1},
- unicode.Range{0x1F18, 0x1F1D, 1},
- unicode.Range{0x1F20, 0x1F45, 1},
- unicode.Range{0x1F48, 0x1F4D, 1},
- unicode.Range{0x1F50, 0x1F57, 1},
- unicode.Range{0x1F59, 0x1F5B, 0x1F5B - 0x1F59},
- unicode.Range{0x1F5D, 0x1F5D, 1},
- unicode.Range{0x1F5F, 0x1F7D, 1},
- unicode.Range{0x1F80, 0x1FB4, 1},
- unicode.Range{0x1FB6, 0x1FBC, 1},
- unicode.Range{0x1FBE, 0x1FBE, 1},
- unicode.Range{0x1FC2, 0x1FC4, 1},
- unicode.Range{0x1FC6, 0x1FCC, 1},
- unicode.Range{0x1FD0, 0x1FD3, 1},
- unicode.Range{0x1FD6, 0x1FDB, 1},
- unicode.Range{0x1FE0, 0x1FEC, 1},
- unicode.Range{0x1FF2, 0x1FF4, 1},
- unicode.Range{0x1FF6, 0x1FFC, 1},
- unicode.Range{0x2126, 0x2126, 1},
- unicode.Range{0x212A, 0x212B, 1},
- unicode.Range{0x212E, 0x212E, 1},
- unicode.Range{0x2180, 0x2182, 1},
- unicode.Range{0x3007, 0x3007, 1},
- unicode.Range{0x3021, 0x3029, 1},
- unicode.Range{0x3041, 0x3094, 1},
- unicode.Range{0x30A1, 0x30FA, 1},
- unicode.Range{0x3105, 0x312C, 1},
- unicode.Range{0x4E00, 0x9FA5, 1},
- unicode.Range{0xAC00, 0xD7A3, 1},
+ {0x003A, 0x003A, 1},
+ {0x0041, 0x005A, 1},
+ {0x005F, 0x005F, 1},
+ {0x0061, 0x007A, 1},
+ {0x00C0, 0x00D6, 1},
+ {0x00D8, 0x00F6, 1},
+ {0x00F8, 0x00FF, 1},
+ {0x0100, 0x0131, 1},
+ {0x0134, 0x013E, 1},
+ {0x0141, 0x0148, 1},
+ {0x014A, 0x017E, 1},
+ {0x0180, 0x01C3, 1},
+ {0x01CD, 0x01F0, 1},
+ {0x01F4, 0x01F5, 1},
+ {0x01FA, 0x0217, 1},
+ {0x0250, 0x02A8, 1},
+ {0x02BB, 0x02C1, 1},
+ {0x0386, 0x0386, 1},
+ {0x0388, 0x038A, 1},
+ {0x038C, 0x038C, 1},
+ {0x038E, 0x03A1, 1},
+ {0x03A3, 0x03CE, 1},
+ {0x03D0, 0x03D6, 1},
+ {0x03DA, 0x03E0, 2},
+ {0x03E2, 0x03F3, 1},
+ {0x0401, 0x040C, 1},
+ {0x040E, 0x044F, 1},
+ {0x0451, 0x045C, 1},
+ {0x045E, 0x0481, 1},
+ {0x0490, 0x04C4, 1},
+ {0x04C7, 0x04C8, 1},
+ {0x04CB, 0x04CC, 1},
+ {0x04D0, 0x04EB, 1},
+ {0x04EE, 0x04F5, 1},
+ {0x04F8, 0x04F9, 1},
+ {0x0531, 0x0556, 1},
+ {0x0559, 0x0559, 1},
+ {0x0561, 0x0586, 1},
+ {0x05D0, 0x05EA, 1},
+ {0x05F0, 0x05F2, 1},
+ {0x0621, 0x063A, 1},
+ {0x0641, 0x064A, 1},
+ {0x0671, 0x06B7, 1},
+ {0x06BA, 0x06BE, 1},
+ {0x06C0, 0x06CE, 1},
+ {0x06D0, 0x06D3, 1},
+ {0x06D5, 0x06D5, 1},
+ {0x06E5, 0x06E6, 1},
+ {0x0905, 0x0939, 1},
+ {0x093D, 0x093D, 1},
+ {0x0958, 0x0961, 1},
+ {0x0985, 0x098C, 1},
+ {0x098F, 0x0990, 1},
+ {0x0993, 0x09A8, 1},
+ {0x09AA, 0x09B0, 1},
+ {0x09B2, 0x09B2, 1},
+ {0x09B6, 0x09B9, 1},
+ {0x09DC, 0x09DD, 1},
+ {0x09DF, 0x09E1, 1},
+ {0x09F0, 0x09F1, 1},
+ {0x0A05, 0x0A0A, 1},
+ {0x0A0F, 0x0A10, 1},
+ {0x0A13, 0x0A28, 1},
+ {0x0A2A, 0x0A30, 1},
+ {0x0A32, 0x0A33, 1},
+ {0x0A35, 0x0A36, 1},
+ {0x0A38, 0x0A39, 1},
+ {0x0A59, 0x0A5C, 1},
+ {0x0A5E, 0x0A5E, 1},
+ {0x0A72, 0x0A74, 1},
+ {0x0A85, 0x0A8B, 1},
+ {0x0A8D, 0x0A8D, 1},
+ {0x0A8F, 0x0A91, 1},
+ {0x0A93, 0x0AA8, 1},
+ {0x0AAA, 0x0AB0, 1},
+ {0x0AB2, 0x0AB3, 1},
+ {0x0AB5, 0x0AB9, 1},
+ {0x0ABD, 0x0AE0, 0x23},
+ {0x0B05, 0x0B0C, 1},
+ {0x0B0F, 0x0B10, 1},
+ {0x0B13, 0x0B28, 1},
+ {0x0B2A, 0x0B30, 1},
+ {0x0B32, 0x0B33, 1},
+ {0x0B36, 0x0B39, 1},
+ {0x0B3D, 0x0B3D, 1},
+ {0x0B5C, 0x0B5D, 1},
+ {0x0B5F, 0x0B61, 1},
+ {0x0B85, 0x0B8A, 1},
+ {0x0B8E, 0x0B90, 1},
+ {0x0B92, 0x0B95, 1},
+ {0x0B99, 0x0B9A, 1},
+ {0x0B9C, 0x0B9C, 1},
+ {0x0B9E, 0x0B9F, 1},
+ {0x0BA3, 0x0BA4, 1},
+ {0x0BA8, 0x0BAA, 1},
+ {0x0BAE, 0x0BB5, 1},
+ {0x0BB7, 0x0BB9, 1},
+ {0x0C05, 0x0C0C, 1},
+ {0x0C0E, 0x0C10, 1},
+ {0x0C12, 0x0C28, 1},
+ {0x0C2A, 0x0C33, 1},
+ {0x0C35, 0x0C39, 1},
+ {0x0C60, 0x0C61, 1},
+ {0x0C85, 0x0C8C, 1},
+ {0x0C8E, 0x0C90, 1},
+ {0x0C92, 0x0CA8, 1},
+ {0x0CAA, 0x0CB3, 1},
+ {0x0CB5, 0x0CB9, 1},
+ {0x0CDE, 0x0CDE, 1},
+ {0x0CE0, 0x0CE1, 1},
+ {0x0D05, 0x0D0C, 1},
+ {0x0D0E, 0x0D10, 1},
+ {0x0D12, 0x0D28, 1},
+ {0x0D2A, 0x0D39, 1},
+ {0x0D60, 0x0D61, 1},
+ {0x0E01, 0x0E2E, 1},
+ {0x0E30, 0x0E30, 1},
+ {0x0E32, 0x0E33, 1},
+ {0x0E40, 0x0E45, 1},
+ {0x0E81, 0x0E82, 1},
+ {0x0E84, 0x0E84, 1},
+ {0x0E87, 0x0E88, 1},
+ {0x0E8A, 0x0E8D, 3},
+ {0x0E94, 0x0E97, 1},
+ {0x0E99, 0x0E9F, 1},
+ {0x0EA1, 0x0EA3, 1},
+ {0x0EA5, 0x0EA7, 2},
+ {0x0EAA, 0x0EAB, 1},
+ {0x0EAD, 0x0EAE, 1},
+ {0x0EB0, 0x0EB0, 1},
+ {0x0EB2, 0x0EB3, 1},
+ {0x0EBD, 0x0EBD, 1},
+ {0x0EC0, 0x0EC4, 1},
+ {0x0F40, 0x0F47, 1},
+ {0x0F49, 0x0F69, 1},
+ {0x10A0, 0x10C5, 1},
+ {0x10D0, 0x10F6, 1},
+ {0x1100, 0x1100, 1},
+ {0x1102, 0x1103, 1},
+ {0x1105, 0x1107, 1},
+ {0x1109, 0x1109, 1},
+ {0x110B, 0x110C, 1},
+ {0x110E, 0x1112, 1},
+ {0x113C, 0x1140, 2},
+ {0x114C, 0x1150, 2},
+ {0x1154, 0x1155, 1},
+ {0x1159, 0x1159, 1},
+ {0x115F, 0x1161, 1},
+ {0x1163, 0x1169, 2},
+ {0x116D, 0x116E, 1},
+ {0x1172, 0x1173, 1},
+ {0x1175, 0x119E, 0x119E - 0x1175},
+ {0x11A8, 0x11AB, 0x11AB - 0x11A8},
+ {0x11AE, 0x11AF, 1},
+ {0x11B7, 0x11B8, 1},
+ {0x11BA, 0x11BA, 1},
+ {0x11BC, 0x11C2, 1},
+ {0x11EB, 0x11F0, 0x11F0 - 0x11EB},
+ {0x11F9, 0x11F9, 1},
+ {0x1E00, 0x1E9B, 1},
+ {0x1EA0, 0x1EF9, 1},
+ {0x1F00, 0x1F15, 1},
+ {0x1F18, 0x1F1D, 1},
+ {0x1F20, 0x1F45, 1},
+ {0x1F48, 0x1F4D, 1},
+ {0x1F50, 0x1F57, 1},
+ {0x1F59, 0x1F5B, 0x1F5B - 0x1F59},
+ {0x1F5D, 0x1F5D, 1},
+ {0x1F5F, 0x1F7D, 1},
+ {0x1F80, 0x1FB4, 1},
+ {0x1FB6, 0x1FBC, 1},
+ {0x1FBE, 0x1FBE, 1},
+ {0x1FC2, 0x1FC4, 1},
+ {0x1FC6, 0x1FCC, 1},
+ {0x1FD0, 0x1FD3, 1},
+ {0x1FD6, 0x1FDB, 1},
+ {0x1FE0, 0x1FEC, 1},
+ {0x1FF2, 0x1FF4, 1},
+ {0x1FF6, 0x1FFC, 1},
+ {0x2126, 0x2126, 1},
+ {0x212A, 0x212B, 1},
+ {0x212E, 0x212E, 1},
+ {0x2180, 0x2182, 1},
+ {0x3007, 0x3007, 1},
+ {0x3021, 0x3029, 1},
+ {0x3041, 0x3094, 1},
+ {0x30A1, 0x30FA, 1},
+ {0x3105, 0x312C, 1},
+ {0x4E00, 0x9FA5, 1},
+ {0xAC00, 0xD7A3, 1},
}
var second = []unicode.Range{
- unicode.Range{0x002D, 0x002E, 1},
- unicode.Range{0x0030, 0x0039, 1},
- unicode.Range{0x00B7, 0x00B7, 1},
- unicode.Range{0x02D0, 0x02D1, 1},
- unicode.Range{0x0300, 0x0345, 1},
- unicode.Range{0x0360, 0x0361, 1},
- unicode.Range{0x0387, 0x0387, 1},
- unicode.Range{0x0483, 0x0486, 1},
- unicode.Range{0x0591, 0x05A1, 1},
- unicode.Range{0x05A3, 0x05B9, 1},
- unicode.Range{0x05BB, 0x05BD, 1},
- unicode.Range{0x05BF, 0x05BF, 1},
- unicode.Range{0x05C1, 0x05C2, 1},
- unicode.Range{0x05C4, 0x0640, 0x0640 - 0x05C4},
- unicode.Range{0x064B, 0x0652, 1},
- unicode.Range{0x0660, 0x0669, 1},
- unicode.Range{0x0670, 0x0670, 1},
- unicode.Range{0x06D6, 0x06DC, 1},
- unicode.Range{0x06DD, 0x06DF, 1},
- unicode.Range{0x06E0, 0x06E4, 1},
- unicode.Range{0x06E7, 0x06E8, 1},
- unicode.Range{0x06EA, 0x06ED, 1},
- unicode.Range{0x06F0, 0x06F9, 1},
- unicode.Range{0x0901, 0x0903, 1},
- unicode.Range{0x093C, 0x093C, 1},
- unicode.Range{0x093E, 0x094C, 1},
- unicode.Range{0x094D, 0x094D, 1},
- unicode.Range{0x0951, 0x0954, 1},
- unicode.Range{0x0962, 0x0963, 1},
- unicode.Range{0x0966, 0x096F, 1},
- unicode.Range{0x0981, 0x0983, 1},
- unicode.Range{0x09BC, 0x09BC, 1},
- unicode.Range{0x09BE, 0x09BF, 1},
- unicode.Range{0x09C0, 0x09C4, 1},
- unicode.Range{0x09C7, 0x09C8, 1},
- unicode.Range{0x09CB, 0x09CD, 1},
- unicode.Range{0x09D7, 0x09D7, 1},
- unicode.Range{0x09E2, 0x09E3, 1},
- unicode.Range{0x09E6, 0x09EF, 1},
- unicode.Range{0x0A02, 0x0A3C, 0x3A},
- unicode.Range{0x0A3E, 0x0A3F, 1},
- unicode.Range{0x0A40, 0x0A42, 1},
- unicode.Range{0x0A47, 0x0A48, 1},
- unicode.Range{0x0A4B, 0x0A4D, 1},
- unicode.Range{0x0A66, 0x0A6F, 1},
- unicode.Range{0x0A70, 0x0A71, 1},
- unicode.Range{0x0A81, 0x0A83, 1},
- unicode.Range{0x0ABC, 0x0ABC, 1},
- unicode.Range{0x0ABE, 0x0AC5, 1},
- unicode.Range{0x0AC7, 0x0AC9, 1},
- unicode.Range{0x0ACB, 0x0ACD, 1},
- unicode.Range{0x0AE6, 0x0AEF, 1},
- unicode.Range{0x0B01, 0x0B03, 1},
- unicode.Range{0x0B3C, 0x0B3C, 1},
- unicode.Range{0x0B3E, 0x0B43, 1},
- unicode.Range{0x0B47, 0x0B48, 1},
- unicode.Range{0x0B4B, 0x0B4D, 1},
- unicode.Range{0x0B56, 0x0B57, 1},
- unicode.Range{0x0B66, 0x0B6F, 1},
- unicode.Range{0x0B82, 0x0B83, 1},
- unicode.Range{0x0BBE, 0x0BC2, 1},
- unicode.Range{0x0BC6, 0x0BC8, 1},
- unicode.Range{0x0BCA, 0x0BCD, 1},
- unicode.Range{0x0BD7, 0x0BD7, 1},
- unicode.Range{0x0BE7, 0x0BEF, 1},
- unicode.Range{0x0C01, 0x0C03, 1},
- unicode.Range{0x0C3E, 0x0C44, 1},
- unicode.Range{0x0C46, 0x0C48, 1},
- unicode.Range{0x0C4A, 0x0C4D, 1},
- unicode.Range{0x0C55, 0x0C56, 1},
- unicode.Range{0x0C66, 0x0C6F, 1},
- unicode.Range{0x0C82, 0x0C83, 1},
- unicode.Range{0x0CBE, 0x0CC4, 1},
- unicode.Range{0x0CC6, 0x0CC8, 1},
- unicode.Range{0x0CCA, 0x0CCD, 1},
- unicode.Range{0x0CD5, 0x0CD6, 1},
- unicode.Range{0x0CE6, 0x0CEF, 1},
- unicode.Range{0x0D02, 0x0D03, 1},
- unicode.Range{0x0D3E, 0x0D43, 1},
- unicode.Range{0x0D46, 0x0D48, 1},
- unicode.Range{0x0D4A, 0x0D4D, 1},
- unicode.Range{0x0D57, 0x0D57, 1},
- unicode.Range{0x0D66, 0x0D6F, 1},
- unicode.Range{0x0E31, 0x0E31, 1},
- unicode.Range{0x0E34, 0x0E3A, 1},
- unicode.Range{0x0E46, 0x0E46, 1},
- unicode.Range{0x0E47, 0x0E4E, 1},
- unicode.Range{0x0E50, 0x0E59, 1},
- unicode.Range{0x0EB1, 0x0EB1, 1},
- unicode.Range{0x0EB4, 0x0EB9, 1},
- unicode.Range{0x0EBB, 0x0EBC, 1},
- unicode.Range{0x0EC6, 0x0EC6, 1},
- unicode.Range{0x0EC8, 0x0ECD, 1},
- unicode.Range{0x0ED0, 0x0ED9, 1},
- unicode.Range{0x0F18, 0x0F19, 1},
- unicode.Range{0x0F20, 0x0F29, 1},
- unicode.Range{0x0F35, 0x0F39, 2},
- unicode.Range{0x0F3E, 0x0F3F, 1},
- unicode.Range{0x0F71, 0x0F84, 1},
- unicode.Range{0x0F86, 0x0F8B, 1},
- unicode.Range{0x0F90, 0x0F95, 1},
- unicode.Range{0x0F97, 0x0F97, 1},
- unicode.Range{0x0F99, 0x0FAD, 1},
- unicode.Range{0x0FB1, 0x0FB7, 1},
- unicode.Range{0x0FB9, 0x0FB9, 1},
- unicode.Range{0x20D0, 0x20DC, 1},
- unicode.Range{0x20E1, 0x3005, 0x3005 - 0x20E1},
- unicode.Range{0x302A, 0x302F, 1},
- unicode.Range{0x3031, 0x3035, 1},
- unicode.Range{0x3099, 0x309A, 1},
- unicode.Range{0x309D, 0x309E, 1},
- unicode.Range{0x30FC, 0x30FE, 1},
+ {0x002D, 0x002E, 1},
+ {0x0030, 0x0039, 1},
+ {0x00B7, 0x00B7, 1},
+ {0x02D0, 0x02D1, 1},
+ {0x0300, 0x0345, 1},
+ {0x0360, 0x0361, 1},
+ {0x0387, 0x0387, 1},
+ {0x0483, 0x0486, 1},
+ {0x0591, 0x05A1, 1},
+ {0x05A3, 0x05B9, 1},
+ {0x05BB, 0x05BD, 1},
+ {0x05BF, 0x05BF, 1},
+ {0x05C1, 0x05C2, 1},
+ {0x05C4, 0x0640, 0x0640 - 0x05C4},
+ {0x064B, 0x0652, 1},
+ {0x0660, 0x0669, 1},
+ {0x0670, 0x0670, 1},
+ {0x06D6, 0x06DC, 1},
+ {0x06DD, 0x06DF, 1},
+ {0x06E0, 0x06E4, 1},
+ {0x06E7, 0x06E8, 1},
+ {0x06EA, 0x06ED, 1},
+ {0x06F0, 0x06F9, 1},
+ {0x0901, 0x0903, 1},
+ {0x093C, 0x093C, 1},
+ {0x093E, 0x094C, 1},
+ {0x094D, 0x094D, 1},
+ {0x0951, 0x0954, 1},
+ {0x0962, 0x0963, 1},
+ {0x0966, 0x096F, 1},
+ {0x0981, 0x0983, 1},
+ {0x09BC, 0x09BC, 1},
+ {0x09BE, 0x09BF, 1},
+ {0x09C0, 0x09C4, 1},
+ {0x09C7, 0x09C8, 1},
+ {0x09CB, 0x09CD, 1},
+ {0x09D7, 0x09D7, 1},
+ {0x09E2, 0x09E3, 1},
+ {0x09E6, 0x09EF, 1},
+ {0x0A02, 0x0A3C, 0x3A},
+ {0x0A3E, 0x0A3F, 1},
+ {0x0A40, 0x0A42, 1},
+ {0x0A47, 0x0A48, 1},
+ {0x0A4B, 0x0A4D, 1},
+ {0x0A66, 0x0A6F, 1},
+ {0x0A70, 0x0A71, 1},
+ {0x0A81, 0x0A83, 1},
+ {0x0ABC, 0x0ABC, 1},
+ {0x0ABE, 0x0AC5, 1},
+ {0x0AC7, 0x0AC9, 1},
+ {0x0ACB, 0x0ACD, 1},
+ {0x0AE6, 0x0AEF, 1},
+ {0x0B01, 0x0B03, 1},
+ {0x0B3C, 0x0B3C, 1},
+ {0x0B3E, 0x0B43, 1},
+ {0x0B47, 0x0B48, 1},
+ {0x0B4B, 0x0B4D, 1},
+ {0x0B56, 0x0B57, 1},
+ {0x0B66, 0x0B6F, 1},
+ {0x0B82, 0x0B83, 1},
+ {0x0BBE, 0x0BC2, 1},
+ {0x0BC6, 0x0BC8, 1},
+ {0x0BCA, 0x0BCD, 1},
+ {0x0BD7, 0x0BD7, 1},
+ {0x0BE7, 0x0BEF, 1},
+ {0x0C01, 0x0C03, 1},
+ {0x0C3E, 0x0C44, 1},
+ {0x0C46, 0x0C48, 1},
+ {0x0C4A, 0x0C4D, 1},
+ {0x0C55, 0x0C56, 1},
+ {0x0C66, 0x0C6F, 1},
+ {0x0C82, 0x0C83, 1},
+ {0x0CBE, 0x0CC4, 1},
+ {0x0CC6, 0x0CC8, 1},
+ {0x0CCA, 0x0CCD, 1},
+ {0x0CD5, 0x0CD6, 1},
+ {0x0CE6, 0x0CEF, 1},
+ {0x0D02, 0x0D03, 1},
+ {0x0D3E, 0x0D43, 1},
+ {0x0D46, 0x0D48, 1},
+ {0x0D4A, 0x0D4D, 1},
+ {0x0D57, 0x0D57, 1},
+ {0x0D66, 0x0D6F, 1},
+ {0x0E31, 0x0E31, 1},
+ {0x0E34, 0x0E3A, 1},
+ {0x0E46, 0x0E46, 1},
+ {0x0E47, 0x0E4E, 1},
+ {0x0E50, 0x0E59, 1},
+ {0x0EB1, 0x0EB1, 1},
+ {0x0EB4, 0x0EB9, 1},
+ {0x0EBB, 0x0EBC, 1},
+ {0x0EC6, 0x0EC6, 1},
+ {0x0EC8, 0x0ECD, 1},
+ {0x0ED0, 0x0ED9, 1},
+ {0x0F18, 0x0F19, 1},
+ {0x0F20, 0x0F29, 1},
+ {0x0F35, 0x0F39, 2},
+ {0x0F3E, 0x0F3F, 1},
+ {0x0F71, 0x0F84, 1},
+ {0x0F86, 0x0F8B, 1},
+ {0x0F90, 0x0F95, 1},
+ {0x0F97, 0x0F97, 1},
+ {0x0F99, 0x0FAD, 1},
+ {0x0FB1, 0x0FB7, 1},
+ {0x0FB9, 0x0FB9, 1},
+ {0x20D0, 0x20DC, 1},
+ {0x20E1, 0x3005, 0x3005 - 0x20E1},
+ {0x302A, 0x302F, 1},
+ {0x3031, 0x3035, 1},
+ {0x3099, 0x309A, 1},
+ {0x309D, 0x309E, 1},
+ {0x30FC, 0x30FE, 1},
}
// HTMLEntity is an entity map containing translations for the
diff --git a/src/pkg/xml/xml_test.go b/src/pkg/xml/xml_test.go
index 148bd2cd0..9ab199a30 100644
--- a/src/pkg/xml/xml_test.go
+++ b/src/pkg/xml/xml_test.go
@@ -36,16 +36,16 @@ var rawTokens = []Token{
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"`),
),
CharData([]byte("\n")),
- StartElement{Name{"", "body"}, []Attr{Attr{Name{"xmlns", "foo"}, "ns1"}, Attr{Name{"", "xmlns"}, "ns2"}, Attr{Name{"xmlns", "tag"}, "ns3"}}},
+ StartElement{Name{"", "body"}, []Attr{{Name{"xmlns", "foo"}, "ns1"}, {Name{"", "xmlns"}, "ns2"}, {Name{"xmlns", "tag"}, "ns3"}}},
CharData([]byte("\n ")),
- StartElement{Name{"", "hello"}, []Attr{Attr{Name{"", "lang"}, "en"}}},
+ StartElement{Name{"", "hello"}, []Attr{{Name{"", "lang"}, "en"}}},
CharData([]byte("World <>'\" 白鵬翔")),
EndElement{Name{"", "hello"}},
CharData([]byte("\n ")),
StartElement{Name{"", "goodbye"}, nil},
EndElement{Name{"", "goodbye"}},
CharData([]byte("\n ")),
- StartElement{Name{"", "outer"}, []Attr{Attr{Name{"foo", "attr"}, "value"}, Attr{Name{"xmlns", "tag"}, "ns4"}}},
+ StartElement{Name{"", "outer"}, []Attr{{Name{"foo", "attr"}, "value"}, {Name{"xmlns", "tag"}, "ns4"}}},
CharData([]byte("\n ")),
StartElement{Name{"", "inner"}, nil},
EndElement{Name{"", "inner"}},
@@ -70,16 +70,16 @@ var cookedTokens = []Token{
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"`),
),
CharData([]byte("\n")),
- StartElement{Name{"ns2", "body"}, []Attr{Attr{Name{"xmlns", "foo"}, "ns1"}, Attr{Name{"", "xmlns"}, "ns2"}, Attr{Name{"xmlns", "tag"}, "ns3"}}},
+ StartElement{Name{"ns2", "body"}, []Attr{{Name{"xmlns", "foo"}, "ns1"}, {Name{"", "xmlns"}, "ns2"}, {Name{"xmlns", "tag"}, "ns3"}}},
CharData([]byte("\n ")),
- StartElement{Name{"ns2", "hello"}, []Attr{Attr{Name{"", "lang"}, "en"}}},
+ StartElement{Name{"ns2", "hello"}, []Attr{{Name{"", "lang"}, "en"}}},
CharData([]byte("World <>'\" 白鵬翔")),
EndElement{Name{"ns2", "hello"}},
CharData([]byte("\n ")),
StartElement{Name{"ns2", "goodbye"}, nil},
EndElement{Name{"ns2", "goodbye"}},
CharData([]byte("\n ")),
- StartElement{Name{"ns2", "outer"}, []Attr{Attr{Name{"ns1", "attr"}, "value"}, Attr{Name{"xmlns", "tag"}, "ns4"}}},
+ StartElement{Name{"ns2", "outer"}, []Attr{{Name{"ns1", "attr"}, "value"}, {Name{"xmlns", "tag"}, "ns4"}}},
CharData([]byte("\n ")),
StartElement{Name{"ns2", "inner"}, nil},
EndElement{Name{"ns2", "inner"}},
@@ -301,7 +301,7 @@ func TestIssue569(t *testing.T) {
err := Unmarshal(buf, &i)
if err != nil || i.Field_a != "abcd" {
- t.Fatalf("Expecting abcd")
+ t.Fatal("Expecting abcd")
}
}
@@ -339,7 +339,7 @@ func TestCopyTokenCharData(t *testing.T) {
}
func TestCopyTokenStartElement(t *testing.T) {
- elt := StartElement{Name{"", "hello"}, []Attr{Attr{Name{"", "lang"}, "en"}}}
+ elt := StartElement{Name{"", "hello"}, []Attr{{Name{"", "lang"}, "en"}}}
var tok1 Token = elt
tok2 := CopyToken(tok1)
if !reflect.DeepEqual(tok1, tok2) {
@@ -387,3 +387,55 @@ func TestTrailingToken(t *testing.T) {
t.Fatalf("p.Token() = _, %v, want _, os.EOF", err)
}
}
+
+func TestEntityInsideCDATA(t *testing.T) {
+ input := `<test><![CDATA[ &val=foo ]]></test>`
+ p := NewParser(StringReader(input))
+ var err os.Error
+ for _, err = p.Token(); err == nil; _, err = p.Token() {
+ }
+ if err != os.EOF {
+ t.Fatalf("p.Token() = _, %v, want _, os.EOF", err)
+ }
+}
+
+
+// The last three tests (respectively one for characters in attribute
+// names and two for character entities) pass not because of code
+// changed for issue 1259, but instead pass with the given messages
+// from other parts of xml.Parser. I provide these to note the
+// current behavior of situations where one might think that character
+// range checking would detect the error, but it does not in fact.
+
+var characterTests = []struct {
+ in string
+ err string
+}{
+ {"\x12<doc/>", "illegal character code U+0012"},
+ {"<?xml version=\"1.0\"?>\x0b<doc/>", "illegal character code U+000B"},
+ {"\xef\xbf\xbe<doc/>", "illegal character code U+FFFE"},
+ {"<?xml version=\"1.0\"?><doc>\r\n<hiya/>\x07<toots/></doc>", "illegal character code U+0007"},
+ {"<?xml version=\"1.0\"?><doc \x12='value'>what's up</doc>", "expected attribute name in element"},
+ {"<doc>&\x01;</doc>", "invalid character entity &;"},
+ {"<doc>&\xef\xbf\xbe;</doc>", "invalid character entity &;"},
+}
+
+
+func TestDisallowedCharacters(t *testing.T) {
+
+ for i, tt := range characterTests {
+ p := NewParser(StringReader(tt.in))
+ var err os.Error
+
+ for err == nil {
+ _, err = p.Token()
+ }
+ synerr, ok := err.(*SyntaxError)
+ if !ok {
+ t.Fatalf("input %d p.Token() = _, %v, want _, *SyntaxError", i, err)
+ }
+ if synerr.Msg != tt.err {
+ t.Fatalf("input %d synerr.Msg wrong: want '%s', got '%s'", i, tt.err, synerr.Msg)
+ }
+ }
+}
diff --git a/src/quietgcc.bash b/src/quietgcc.bash
index dd3db3642..748fc593e 100755
--- a/src/quietgcc.bash
+++ b/src/quietgcc.bash
@@ -4,7 +4,7 @@
# license that can be found in the LICENSE file.
# The master for this file is $GOROOT/src/quietgcc.bash
-# Changes made to $HOME/bin/quietgcc will be overridden.
+# Changes made to $GOBIN/quietgcc will be overridden.
# Gcc output that we don't care to see.
ignore=': error: .Each undeclared identifier'
@@ -22,14 +22,15 @@ if test "$gcc" = "@C""C@"; then
gcc=gcc
fi
-# If this is a 64-bit machine, compile 64-bit versions of
-# the host tools, to match the native ptrace.
-case "`uname -m -p`" in
+# 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=/tmp/qcc.$$.$USER.out
$gcc -Wall -Wno-sign-compare -Wno-missing-braces \
diff --git a/src/run.bash b/src/run.bash
index 4eb4a476b..0cd129253 100755
--- a/src/run.bash
+++ b/src/run.bash
@@ -4,8 +4,14 @@
# license that can be found in the LICENSE file.
set -e
-. ./env.bash
+if [ "$1" = "--no-env" ]; then
+ # caller has already run env.bash
+ shift
+else
+ . ./env.bash
+fi
+unset MAKEFLAGS # single-threaded make
unset CDPATH # in case user has it set
# no core files, please
@@ -30,11 +36,11 @@ maketest() {
(
xcd $i
if $rebuild; then
- "$GOBIN"/gomake clean
- time "$GOBIN"/gomake
- "$GOBIN"/gomake install
+ gomake clean
+ time gomake
+ gomake install
fi
- "$GOBIN"/gomake test
+ gomake test
) || exit $?
done
}
@@ -47,47 +53,74 @@ maketest \
(xcd pkg/sync;
if $rebuild; then
- "$GOBIN"/gomake clean;
- time "$GOBIN"/gomake
+ gomake clean;
+ time gomake
fi
-GOMAXPROCS=10 "$GOBIN"/gomake test
+GOMAXPROCS=10 gomake test
) || exit $?
+[ "$GOARCH" == arm ] ||
(xcd cmd/gofmt
if $rebuild; then
- "$GOBIN"/gomake clean;
- time "$GOBIN"/gomake
+ gomake clean;
+ time gomake
fi
-time "$GOBIN"/gomake smoketest
+time gomake smoketest
) || exit $?
(xcd cmd/ebnflint
if $rebuild; then
- "$GOBIN"/gomake clean;
- time "$GOBIN"/gomake
+ gomake clean;
+ time gomake
fi
-time "$GOBIN"/gomake test
+time gomake test
) || exit $?
+[ "$GOARCH" == arm ] ||
(xcd ../misc/cgo/stdio
-"$GOBIN"/gomake clean
-./test.bash
+if [[ $(uname | tr A-Z a-z | sed 's/mingw/windows/') != *windows* ]]; then
+ gomake clean
+ ./test.bash
+fi
+) || exit $?
+
+[ "$GOARCH" == arm ] ||
+(xcd ../misc/cgo/life
+if [[ $(uname | tr A-Z a-z | sed 's/mingw/windows/') != *windows* ]]; then
+ gomake clean
+ ./test.bash
+fi
) || exit $?
(xcd pkg/exp/ogle
-"$GOBIN"/gomake clean
-time "$GOBIN"/gomake ogle
+gomake clean
+time gomake ogle
) || exit $?
(xcd ../doc/progs
-time ./run
+if [[ $(uname | tr A-Z a-z | sed 's/mingw/windows/') != *windows* ]]; then
+ time ./run
+fi
) || exit $?
+for i in ../misc/dashboard/builder ../misc/goplay
+do
+ (xcd $i
+ gomake clean
+ gomake
+ ) || exit $?
+done
+
+[ "$GOARCH" == arm ] ||
(xcd ../test/bench
-./timing.sh -test
+if [[ $(uname | tr A-Z a-z | sed 's/mingw/windows/') != *windows* ]]; then
+ ./timing.sh -test
+fi
) || exit $?
(xcd ../test
-./run
+if [[ $(uname | tr A-Z a-z | sed 's/mingw/windows/') != *windows* ]]; then
+ ./run
+fi
) || exit $?
diff --git a/src/sudo.bash b/src/sudo.bash
index d87fb231d..147e58f15 100755
--- a/src/sudo.bash
+++ b/src/sudo.bash
@@ -3,6 +3,9 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
+set -e
+. ./env.bash
+
case "`uname`" in
Darwin)
;;
diff --git a/test/64bit.go b/test/64bit.go
index b014e546c..9e91a97fd 100644
--- a/test/64bit.go
+++ b/test/64bit.go
@@ -15,9 +15,9 @@
package main
import (
- "bufio";
- "fmt";
- "os";
+ "bufio"
+ "fmt"
+ "os"
)
var bout *bufio.Writer
@@ -27,19 +27,19 @@ var bout *bufio.Writer
// if the compiler has buggy or missing 64-bit support.
type Uint64 struct {
- hi uint32;
- lo uint32;
+ hi uint32
+ lo uint32
}
type Int64 struct {
- hi int32;
- lo uint32;
+ hi int32
+ lo uint32
}
func (a Uint64) Int64() (c Int64) {
- c.hi = int32(a.hi);
- c.lo = a.lo;
- return;
+ c.hi = int32(a.hi)
+ c.lo = a.lo
+ return
}
func (a Uint64) Cmp(b Uint64) int {
@@ -53,80 +53,80 @@ func (a Uint64) Cmp(b Uint64) int {
case a.lo > b.lo:
return 1
}
- return 0;
+ return 0
}
func (a Uint64) LeftShift(b uint) (c Uint64) {
switch {
case b >= 64:
- c.hi = 0;
- c.lo = 0;
+ c.hi = 0
+ c.lo = 0
case b >= 32:
- c.hi = a.lo << (b - 32);
- c.lo = 0;
+ c.hi = a.lo << (b - 32)
+ c.lo = 0
default:
- c.hi = a.hi<<b | a.lo>>(32-b);
- c.lo = a.lo << b;
+ c.hi = a.hi<<b | a.lo>>(32-b)
+ c.lo = a.lo << b
}
- return;
+ return
}
func (a Uint64) RightShift(b uint) (c Uint64) {
switch {
case b >= 64:
- c.hi = 0;
- c.lo = a.hi;
+ c.hi = 0
+ c.lo = a.hi
case b >= 32:
- c.hi = 0;
- c.lo = a.hi >> (b - 32);
+ c.hi = 0
+ c.lo = a.hi >> (b - 32)
default:
- c.hi = a.hi >> b;
- c.lo = a.hi<<(32-b) | a.lo>>b;
+ c.hi = a.hi >> b
+ c.lo = a.hi<<(32-b) | a.lo>>b
}
- return;
+ return
}
func (a Uint64) LeftShift64(b Uint64) (c Uint64) {
if b.hi != 0 || b.lo >= 64 {
return
}
- return a.LeftShift(uint(b.lo));
+ return a.LeftShift(uint(b.lo))
}
func (a Uint64) RightShift64(b Uint64) (c Uint64) {
if b.hi != 0 || b.lo >= 64 {
return
}
- return a.RightShift(uint(b.lo));
+ return a.RightShift(uint(b.lo))
}
func (a Uint64) Plus(b Uint64) (c Uint64) {
- var carry uint32;
+ var carry uint32
if c.lo = a.lo + b.lo; c.lo < a.lo {
carry = 1
}
- c.hi = a.hi + b.hi + carry;
- return;
+ c.hi = a.hi + b.hi + carry
+ return
}
func (a Uint64) Minus(b Uint64) (c Uint64) {
- var borrow uint32;
+ var borrow uint32
if c.lo = a.lo - b.lo; c.lo > a.lo {
borrow = 1
}
- c.hi = a.hi - b.hi - borrow;
- return;
+ c.hi = a.hi - b.hi - borrow
+ return
}
func (a Uint64) Neg() (c Uint64) {
- var zero Uint64;
- return zero.Minus(a);
+ var zero Uint64
+ return zero.Minus(a)
}
func (a Uint64) Com() (c Uint64) {
- c.hi = ^a.hi;
- c.lo = ^a.lo;
- return;
+ c.hi = ^a.hi
+ c.lo = ^a.lo
+ return
}
func (a Uint64) Len() int {
@@ -144,7 +144,7 @@ func (a Uint64) Len() int {
}
}
}
- return 0;
+ return 0
}
func (a Uint64) HasBit(b uint) bool {
@@ -154,7 +154,7 @@ func (a Uint64) HasBit(b uint) bool {
case b >= 32:
return a.hi&(1<<(b-32)) != 0
}
- return a.lo&(1<<b) != 0;
+ return a.lo&(1<<b) != 0
}
func (a Uint64) Times(b Uint64) (c Uint64) {
@@ -163,56 +163,56 @@ func (a Uint64) Times(b Uint64) (c Uint64) {
c = c.Plus(a.LeftShift(i))
}
}
- return;
+ return
}
func (a Uint64) DivMod(b Uint64) (quo, rem Uint64) {
- n := a.Len() - b.Len();
+ n := a.Len() - b.Len()
if n >= 0 {
- b = b.LeftShift(uint(n));
+ b = b.LeftShift(uint(n))
for i := 0; i <= n; i++ {
- quo = quo.LeftShift(1);
+ quo = quo.LeftShift(1)
if b.Cmp(a) <= 0 { // b <= a
- quo.lo |= 1;
- a = a.Minus(b);
+ quo.lo |= 1
+ a = a.Minus(b)
}
- b = b.RightShift(1);
+ b = b.RightShift(1)
}
}
- rem = a;
- return;
+ rem = a
+ return
}
func (a Uint64) And(b Uint64) (c Uint64) {
- c.hi = a.hi & b.hi;
- c.lo = a.lo & b.lo;
- return;
+ c.hi = a.hi & b.hi
+ c.lo = a.lo & b.lo
+ return
}
func (a Uint64) AndNot(b Uint64) (c Uint64) {
- c.hi = a.hi &^ b.hi;
- c.lo = a.lo &^ b.lo;
- return;
+ c.hi = a.hi &^ b.hi
+ c.lo = a.lo &^ b.lo
+ return
}
func (a Uint64) Or(b Uint64) (c Uint64) {
- c.hi = a.hi | b.hi;
- c.lo = a.lo | b.lo;
- return;
+ c.hi = a.hi | b.hi
+ c.lo = a.lo | b.lo
+ return
}
func (a Uint64) Xor(b Uint64) (c Uint64) {
- c.hi = a.hi ^ b.hi;
- c.lo = a.lo ^ b.lo;
- return;
+ c.hi = a.hi ^ b.hi
+ c.lo = a.lo ^ b.lo
+ return
}
func (a Uint64) String() string { return fmt.Sprintf("%#x%08x", a.hi, a.lo) }
func (a Int64) Uint64() (c Uint64) {
- c.hi = uint32(a.hi);
- c.lo = a.lo;
- return;
+ c.hi = uint32(a.hi)
+ c.lo = a.lo
+ return
}
func (a Int64) Cmp(b Int64) int {
@@ -229,7 +229,7 @@ func (a Int64) Cmp(b Int64) int {
case a.lo > b.lo:
return 1
}
- return 0;
+ return 0
}
func (a Int64) LeftShift(b uint) (c Int64) { return a.Uint64().LeftShift(b).Int64() }
@@ -237,30 +237,30 @@ func (a Int64) LeftShift(b uint) (c Int64) { return a.Uint64().LeftShift(b).Int6
func (a Int64) RightShift(b uint) (c Int64) {
switch {
case b >= 64:
- c.hi = a.hi >> 31; // sign extend
- c.lo = uint32(c.hi);
+ c.hi = a.hi >> 31 // sign extend
+ c.lo = uint32(c.hi)
case b >= 32:
- c.hi = a.hi >> 31; // sign extend
- c.lo = uint32(a.hi >> (b - 32));
+ c.hi = a.hi >> 31 // sign extend
+ c.lo = uint32(a.hi >> (b - 32))
default:
- c.hi = a.hi >> b;
- c.lo = uint32(a.hi<<(32-b)) | a.lo>>b;
+ c.hi = a.hi >> b
+ c.lo = uint32(a.hi<<(32-b)) | a.lo>>b
}
- return;
+ return
}
func (a Int64) LeftShift64(b Uint64) (c Int64) {
if b.hi != 0 || b.lo >= 64 {
return
}
- return a.LeftShift(uint(b.lo));
+ return a.LeftShift(uint(b.lo))
}
func (a Int64) RightShift64(b Uint64) (c Int64) {
if b.hi != 0 || b.lo >= 64 {
return a.RightShift(64)
}
- return a.RightShift(uint(b.lo));
+ return a.RightShift(uint(b.lo))
}
func (a Int64) Plus(b Int64) (c Int64) { return a.Uint64().Plus(b.Uint64()).Int64() }
@@ -274,23 +274,23 @@ func (a Int64) Com() (c Int64) { return a.Uint64().Com().Int64() }
func (a Int64) Times(b Int64) (c Int64) { return a.Uint64().Times(b.Uint64()).Int64() }
func (a Int64) DivMod(b Int64) (quo Int64, rem Int64) {
- var zero Int64;
+ var zero Int64
- quoSign := +1;
- remSign := +1;
+ quoSign := +1
+ remSign := +1
if a.Cmp(zero) < 0 {
- quoSign = -1;
- remSign = -1;
- a = a.Neg();
+ quoSign = -1
+ remSign = -1
+ a = a.Neg()
}
if b.Cmp(zero) < 0 {
- quoSign = -quoSign;
- b = b.Neg();
+ quoSign = -quoSign
+ b = b.Neg()
}
- q, r := a.Uint64().DivMod(b.Uint64());
- quo = q.Int64();
- rem = r.Int64();
+ q, r := a.Uint64().DivMod(b.Uint64())
+ quo = q.Int64()
+ rem = r.Int64()
if quoSign < 0 {
quo = quo.Neg()
@@ -298,7 +298,7 @@ func (a Int64) DivMod(b Int64) (quo Int64, rem Int64) {
if remSign < 0 {
rem = rem.Neg()
}
- return;
+ return
}
func (a Int64) And(b Int64) (c Int64) { return a.Uint64().And(b.Uint64()).Int64() }
@@ -313,7 +313,7 @@ func (a Int64) String() string {
if a.hi < 0 {
return fmt.Sprintf("-%s", a.Neg().Uint64())
}
- return a.Uint64().String();
+ return a.Uint64().String()
}
var int64Values = []Int64{
@@ -507,56 +507,56 @@ const prolog = "\n" +
"\n"
func varTests() {
- fmt.Fprint(bout, prolog);
+ fmt.Fprint(bout, prolog)
for _, a := range int64Values {
- fmt.Fprintf(bout, "func test%v() {\n", ntest);
- ntest++;
- fmt.Fprintf(bout, "\ttestInt64Unary(%v, %v, %v, %v);\n", a, a, a.Com(), a.Neg());
+ fmt.Fprintf(bout, "func test%v() {\n", ntest)
+ ntest++
+ fmt.Fprintf(bout, "\ttestInt64Unary(%v, %v, %v, %v);\n", a, a, a.Com(), a.Neg())
for _, b := range int64Values {
- var div, mod Int64;
- dodiv := false;
- var zero Int64;
+ var div, mod Int64
+ dodiv := false
+ var zero Int64
if b.Cmp(zero) != 0 { // b != 0
// Can't divide by zero but also can't divide -0x8000...000 by -1.
- var bigneg = Int64{-0x80000000, 0};
- var minus1 = Int64{-1, ^uint32(0)};
+ var bigneg = Int64{-0x80000000, 0}
+ var minus1 = Int64{-1, ^uint32(0)}
if a.Cmp(bigneg) != 0 || b.Cmp(minus1) != 0 { // a != -1<<63 || b != -1
- div, mod = a.DivMod(b);
- dodiv = true;
+ div, mod = a.DivMod(b)
+ dodiv = true
}
}
fmt.Fprintf(bout, "\ttestInt64Binary(%v, %v, %v, %v, %v, %v, %v, %v, %v, %v, %v, %v);\n",
a, b, a.Plus(b), a.Minus(b), a.Times(b), div, mod,
- a.And(b), a.Or(b), a.Xor(b), a.AndNot(b), dodiv);
+ a.And(b), a.Or(b), a.Xor(b), a.AndNot(b), dodiv)
}
for _, b := range shiftValues {
fmt.Fprintf(bout, "\ttestInt64Shift(%v, %v, %v, %v);\n",
a, b, a.LeftShift64(b), a.RightShift64(b))
}
- fmt.Fprintf(bout, "}\n");
+ fmt.Fprintf(bout, "}\n")
}
for _, a := range uint64Values {
- fmt.Fprintf(bout, "func test%v() {\n", ntest);
- ntest++;
- fmt.Fprintf(bout, "\ttestUint64Unary(%v, %v, %v, %v);\n", a, a, a.Com(), a.Neg());
+ fmt.Fprintf(bout, "func test%v() {\n", ntest)
+ ntest++
+ fmt.Fprintf(bout, "\ttestUint64Unary(%v, %v, %v, %v);\n", a, a, a.Com(), a.Neg())
for _, b := range uint64Values {
- var div, mod Uint64;
- dodiv := false;
- var zero Uint64;
+ var div, mod Uint64
+ dodiv := false
+ var zero Uint64
if b.Cmp(zero) != 0 { // b != 0
- div, mod = a.DivMod(b);
- dodiv = true;
+ div, mod = a.DivMod(b)
+ dodiv = true
}
fmt.Fprintf(bout, "\ttestUint64Binary(%v, %v, %v, %v, %v, %v, %v, %v, %v, %v, %v, %v);\n",
a, b, a.Plus(b), a.Minus(b), a.Times(b), div, mod,
- a.And(b), a.Or(b), a.Xor(b), a.AndNot(b), dodiv);
+ a.And(b), a.Or(b), a.Xor(b), a.AndNot(b), dodiv)
}
for _, b := range shiftValues {
fmt.Fprintf(bout, "\ttestUint64Shift(%v, %v, %v, %v);\n",
a, b, a.LeftShift64(b), a.RightShift64(b))
}
- fmt.Fprintf(bout, "}\n");
+ fmt.Fprintf(bout, "}\n")
}
}
@@ -622,88 +622,88 @@ const shiftConstR = "func test%vShiftR%v(a, left, right %v) {\n" +
func constTests() {
for i, a := range int64Values {
- fmt.Fprintf(bout, binaryConstL, "Int64", i, "int64", "int64", a, "int64");
- fmt.Fprintf(bout, binaryConstR, "Int64", i, "int64", "int64", a, "int64");
- fmt.Fprintf(bout, shiftConstL, "Int64", i, "int64", "int64", a, "int64");
+ fmt.Fprintf(bout, binaryConstL, "Int64", i, "int64", "int64", a, "int64")
+ fmt.Fprintf(bout, binaryConstR, "Int64", i, "int64", "int64", a, "int64")
+ fmt.Fprintf(bout, shiftConstL, "Int64", i, "int64", "int64", a, "int64")
}
for i, a := range uint64Values {
- fmt.Fprintf(bout, binaryConstL, "Uint64", i, "uint64", "uint64", a, "uint64");
- fmt.Fprintf(bout, binaryConstR, "Uint64", i, "uint64", "uint64", a, "uint64");
- fmt.Fprintf(bout, shiftConstL, "Uint64", i, "uint64", "uint64", a, "uint64");
+ fmt.Fprintf(bout, binaryConstL, "Uint64", i, "uint64", "uint64", a, "uint64")
+ fmt.Fprintf(bout, binaryConstR, "Uint64", i, "uint64", "uint64", a, "uint64")
+ fmt.Fprintf(bout, shiftConstL, "Uint64", i, "uint64", "uint64", a, "uint64")
}
for i, a := range shiftValues {
- fmt.Fprintf(bout, shiftConstR, "Int64", i, "int64", a, "int64");
- fmt.Fprintf(bout, shiftConstR, "Uint64", i, "uint64", a, "uint64");
+ fmt.Fprintf(bout, shiftConstR, "Int64", i, "int64", a, "int64")
+ fmt.Fprintf(bout, shiftConstR, "Uint64", i, "uint64", a, "uint64")
}
for i, a := range int64Values {
- fmt.Fprintf(bout, "func test%v() {\n", ntest);
- ntest++;
+ fmt.Fprintf(bout, "func test%v() {\n", ntest)
+ ntest++
for j, b := range int64Values {
- var div, mod Int64;
- dodiv := false;
- var zero Int64;
+ var div, mod Int64
+ dodiv := false
+ var zero Int64
if b.Cmp(zero) != 0 { // b != 0
// Can't divide by zero but also can't divide -0x8000...000 by -1.
- var bigneg = Int64{-0x80000000, 0};
- var minus1 = Int64{-1, ^uint32(0)};
+ var bigneg = Int64{-0x80000000, 0}
+ var minus1 = Int64{-1, ^uint32(0)}
if a.Cmp(bigneg) != 0 || b.Cmp(minus1) != 0 { // a != -1<<63 || b != -1
- div, mod = a.DivMod(b);
- dodiv = true;
+ div, mod = a.DivMod(b)
+ dodiv = true
}
}
fmt.Fprintf(bout, "\ttestInt64BinaryL%v(%v, %v, %v, %v, %v, %v, %v, %v, %v, %v, %v);\n",
i, b, a.Plus(b), a.Minus(b), a.Times(b), div, mod,
- a.And(b), a.Or(b), a.Xor(b), a.AndNot(b), dodiv);
+ a.And(b), a.Or(b), a.Xor(b), a.AndNot(b), dodiv)
fmt.Fprintf(bout, "\ttestInt64BinaryR%v(%v, %v, %v, %v, %v, %v, %v, %v, %v, %v, %v);\n",
j, a, a.Plus(b), a.Minus(b), a.Times(b), div, mod,
- a.And(b), a.Or(b), a.Xor(b), a.AndNot(b), dodiv);
+ a.And(b), a.Or(b), a.Xor(b), a.AndNot(b), dodiv)
}
for j, b := range shiftValues {
fmt.Fprintf(bout, "\ttestInt64ShiftL%v(%v, %v, %v);\n",
- i, b, a.LeftShift64(b), a.RightShift64(b));
+ i, b, a.LeftShift64(b), a.RightShift64(b))
fmt.Fprintf(bout, "\ttestInt64ShiftR%v(%v, %v, %v);\n",
- j, a, a.LeftShift64(b), a.RightShift64(b));
+ j, a, a.LeftShift64(b), a.RightShift64(b))
}
- fmt.Fprintf(bout, "}\n");
+ fmt.Fprintf(bout, "}\n")
}
for i, a := range uint64Values {
- fmt.Fprintf(bout, "func test%v() {\n", ntest);
- ntest++;
+ fmt.Fprintf(bout, "func test%v() {\n", ntest)
+ ntest++
for j, b := range uint64Values {
- var div, mod Uint64;
- dodiv := false;
- var zero Uint64;
+ var div, mod Uint64
+ dodiv := false
+ var zero Uint64
if b.Cmp(zero) != 0 { // b != 0
- div, mod = a.DivMod(b);
- dodiv = true;
+ div, mod = a.DivMod(b)
+ dodiv = true
}
fmt.Fprintf(bout, "\ttestUint64BinaryL%v(%v, %v, %v, %v, %v, %v, %v, %v, %v, %v, %v);\n",
i, b, a.Plus(b), a.Minus(b), a.Times(b), div, mod,
- a.And(b), a.Or(b), a.Xor(b), a.AndNot(b), dodiv);
+ a.And(b), a.Or(b), a.Xor(b), a.AndNot(b), dodiv)
fmt.Fprintf(bout, "\ttestUint64BinaryR%v(%v, %v, %v, %v, %v, %v, %v, %v, %v, %v, %v);\n",
j, a, a.Plus(b), a.Minus(b), a.Times(b), div, mod,
- a.And(b), a.Or(b), a.Xor(b), a.AndNot(b), dodiv);
+ a.And(b), a.Or(b), a.Xor(b), a.AndNot(b), dodiv)
}
for j, b := range shiftValues {
fmt.Fprintf(bout, "\ttestUint64ShiftL%v(%v, %v, %v);\n",
- i, b, a.LeftShift64(b), a.RightShift64(b));
+ i, b, a.LeftShift64(b), a.RightShift64(b))
fmt.Fprintf(bout, "\ttestUint64ShiftR%v(%v, %v, %v);\n",
- j, a, a.LeftShift64(b), a.RightShift64(b));
+ j, a, a.LeftShift64(b), a.RightShift64(b))
}
- fmt.Fprintf(bout, "}\n");
+ fmt.Fprintf(bout, "}\n")
}
}
func main() {
- bout = bufio.NewWriter(os.Stdout);
- varTests();
- constTests();
+ bout = bufio.NewWriter(os.Stdout)
+ varTests()
+ constTests()
- fmt.Fprintf(bout, "func main() {\n");
+ fmt.Fprintf(bout, "func main() {\n")
for i := 0; i < ntest; i++ {
fmt.Fprintf(bout, "\ttest%v();\n", i)
}
- fmt.Fprintf(bout, "\tif !ok { os.Exit(1) }\n");
- fmt.Fprintf(bout, "}\n");
- bout.Flush();
+ fmt.Fprintf(bout, "\tif !ok { os.Exit(1) }\n")
+ fmt.Fprintf(bout, "}\n")
+ bout.Flush()
}
diff --git a/test/append.go b/test/append.go
new file mode 100644
index 000000000..17c665227
--- /dev/null
+++ b/test/append.go
@@ -0,0 +1,227 @@
+// $G $F.go && $L $F.$A && ./$A.out
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Semi-exhaustive test for append()
+
+package main
+
+import (
+ "fmt"
+ "reflect"
+)
+
+
+func verify(name string, result, expected interface{}) {
+ if !reflect.DeepEqual(result, expected) {
+ panic(name)
+ }
+}
+
+
+func main() {
+ for _, t := range tests {
+ verify(t.name, t.result, t.expected)
+ }
+ verifyStruct()
+ verifyInterface()
+}
+
+
+var tests = []struct {
+ name string
+ result, expected interface{}
+}{
+ {"bool a", append([]bool{}), []bool{}},
+ {"bool b", append([]bool{}, true), []bool{true}},
+ {"bool c", append([]bool{}, true, false, true, true), []bool{true, false, true, true}},
+
+ {"bool d", append([]bool{true, false, true}), []bool{true, false, true}},
+ {"bool e", append([]bool{true, false, true}, false), []bool{true, false, true, false}},
+ {"bool f", append([]bool{true, false, true}, false, false, false), []bool{true, false, true, false, false, false}},
+
+ {"bool g", append([]bool{}, []bool{true}...), []bool{true}},
+ {"bool h", append([]bool{}, []bool{true, false, true, false}...), []bool{true, false, true, false}},
+
+ {"bool i", append([]bool{true, false, true}, []bool{true}...), []bool{true, false, true, true}},
+ {"bool j", append([]bool{true, false, true}, []bool{true, true, true}...), []bool{true, false, true, true, true, true}},
+
+
+ {"byte a", append([]byte{}), []byte{}},
+ {"byte b", append([]byte{}, 0), []byte{0}},
+ {"byte c", append([]byte{}, 0, 1, 2, 3), []byte{0, 1, 2, 3}},
+
+ {"byte d", append([]byte{0, 1, 2}), []byte{0, 1, 2}},
+ {"byte e", append([]byte{0, 1, 2}, 3), []byte{0, 1, 2, 3}},
+ {"byte f", append([]byte{0, 1, 2}, 3, 4, 5), []byte{0, 1, 2, 3, 4, 5}},
+
+ {"byte g", append([]byte{}, []byte{0}...), []byte{0}},
+ {"byte h", append([]byte{}, []byte{0, 1, 2, 3}...), []byte{0, 1, 2, 3}},
+
+ {"byte i", append([]byte{0, 1, 2}, []byte{3}...), []byte{0, 1, 2, 3}},
+ {"byte j", append([]byte{0, 1, 2}, []byte{3, 4, 5}...), []byte{0, 1, 2, 3, 4, 5}},
+
+
+ {"int16 a", append([]int16{}), []int16{}},
+ {"int16 b", append([]int16{}, 0), []int16{0}},
+ {"int16 c", append([]int16{}, 0, 1, 2, 3), []int16{0, 1, 2, 3}},
+
+ {"int16 d", append([]int16{0, 1, 2}), []int16{0, 1, 2}},
+ {"int16 e", append([]int16{0, 1, 2}, 3), []int16{0, 1, 2, 3}},
+ {"int16 f", append([]int16{0, 1, 2}, 3, 4, 5), []int16{0, 1, 2, 3, 4, 5}},
+
+ {"int16 g", append([]int16{}, []int16{0}...), []int16{0}},
+ {"int16 h", append([]int16{}, []int16{0, 1, 2, 3}...), []int16{0, 1, 2, 3}},
+
+ {"int16 i", append([]int16{0, 1, 2}, []int16{3}...), []int16{0, 1, 2, 3}},
+ {"int16 j", append([]int16{0, 1, 2}, []int16{3, 4, 5}...), []int16{0, 1, 2, 3, 4, 5}},
+
+
+ {"uint32 a", append([]uint32{}), []uint32{}},
+ {"uint32 b", append([]uint32{}, 0), []uint32{0}},
+ {"uint32 c", append([]uint32{}, 0, 1, 2, 3), []uint32{0, 1, 2, 3}},
+
+ {"uint32 d", append([]uint32{0, 1, 2}), []uint32{0, 1, 2}},
+ {"uint32 e", append([]uint32{0, 1, 2}, 3), []uint32{0, 1, 2, 3}},
+ {"uint32 f", append([]uint32{0, 1, 2}, 3, 4, 5), []uint32{0, 1, 2, 3, 4, 5}},
+
+ {"uint32 g", append([]uint32{}, []uint32{0}...), []uint32{0}},
+ {"uint32 h", append([]uint32{}, []uint32{0, 1, 2, 3}...), []uint32{0, 1, 2, 3}},
+
+ {"uint32 i", append([]uint32{0, 1, 2}, []uint32{3}...), []uint32{0, 1, 2, 3}},
+ {"uint32 j", append([]uint32{0, 1, 2}, []uint32{3, 4, 5}...), []uint32{0, 1, 2, 3, 4, 5}},
+
+
+ {"float64 a", append([]float64{}), []float64{}},
+ {"float64 b", append([]float64{}, 0), []float64{0}},
+ {"float64 c", append([]float64{}, 0, 1, 2, 3), []float64{0, 1, 2, 3}},
+
+ {"float64 d", append([]float64{0, 1, 2}), []float64{0, 1, 2}},
+ {"float64 e", append([]float64{0, 1, 2}, 3), []float64{0, 1, 2, 3}},
+ {"float64 f", append([]float64{0, 1, 2}, 3, 4, 5), []float64{0, 1, 2, 3, 4, 5}},
+
+ {"float64 g", append([]float64{}, []float64{0}...), []float64{0}},
+ {"float64 h", append([]float64{}, []float64{0, 1, 2, 3}...), []float64{0, 1, 2, 3}},
+
+ {"float64 i", append([]float64{0, 1, 2}, []float64{3}...), []float64{0, 1, 2, 3}},
+ {"float64 j", append([]float64{0, 1, 2}, []float64{3, 4, 5}...), []float64{0, 1, 2, 3, 4, 5}},
+
+
+ {"complex128 a", append([]complex128{}), []complex128{}},
+ {"complex128 b", append([]complex128{}, 0), []complex128{0}},
+ {"complex128 c", append([]complex128{}, 0, 1, 2, 3), []complex128{0, 1, 2, 3}},
+
+ {"complex128 d", append([]complex128{0, 1, 2}), []complex128{0, 1, 2}},
+ {"complex128 e", append([]complex128{0, 1, 2}, 3), []complex128{0, 1, 2, 3}},
+ {"complex128 f", append([]complex128{0, 1, 2}, 3, 4, 5), []complex128{0, 1, 2, 3, 4, 5}},
+
+ {"complex128 g", append([]complex128{}, []complex128{0}...), []complex128{0}},
+ {"complex128 h", append([]complex128{}, []complex128{0, 1, 2, 3}...), []complex128{0, 1, 2, 3}},
+
+ {"complex128 i", append([]complex128{0, 1, 2}, []complex128{3}...), []complex128{0, 1, 2, 3}},
+ {"complex128 j", append([]complex128{0, 1, 2}, []complex128{3, 4, 5}...), []complex128{0, 1, 2, 3, 4, 5}},
+
+
+ {"string a", append([]string{}), []string{}},
+ {"string b", append([]string{}, "0"), []string{"0"}},
+ {"string c", append([]string{}, "0", "1", "2", "3"), []string{"0", "1", "2", "3"}},
+
+ {"string d", append([]string{"0", "1", "2"}), []string{"0", "1", "2"}},
+ {"string e", append([]string{"0", "1", "2"}, "3"), []string{"0", "1", "2", "3"}},
+ {"string f", append([]string{"0", "1", "2"}, "3", "4", "5"), []string{"0", "1", "2", "3", "4", "5"}},
+
+ {"string g", append([]string{}, []string{"0"}...), []string{"0"}},
+ {"string h", append([]string{}, []string{"0", "1", "2", "3"}...), []string{"0", "1", "2", "3"}},
+
+ {"string i", append([]string{"0", "1", "2"}, []string{"3"}...), []string{"0", "1", "2", "3"}},
+ {"string j", append([]string{"0", "1", "2"}, []string{"3", "4", "5"}...), []string{"0", "1", "2", "3", "4", "5"}},
+}
+
+
+func verifyStruct() {
+ type T struct {
+ a, b, c string
+ }
+ type S []T
+ e := make(S, 100)
+ for i := range e {
+ e[i] = T{"foo", fmt.Sprintf("%d", i), "bar"}
+ }
+
+ verify("struct a", append(S{}), S{})
+ verify("struct b", append(S{}, e[0]), e[0:1])
+ verify("struct c", append(S{}, e[0], e[1], e[2]), e[0:3])
+
+ verify("struct d", append(e[0:1]), e[0:1])
+ verify("struct e", append(e[0:1], e[1]), e[0:2])
+ verify("struct f", append(e[0:1], e[1], e[2], e[3]), e[0:4])
+
+ verify("struct g", append(e[0:3]), e[0:3])
+ verify("struct h", append(e[0:3], e[3]), e[0:4])
+ verify("struct i", append(e[0:3], e[3], e[4], e[5], e[6]), e[0:7])
+
+ for i := range e {
+ verify("struct j", append(S{}, e[0:i]...), e[0:i])
+ input := make(S, i)
+ copy(input, e[0:i])
+ verify("struct k", append(input, e[i:]...), e)
+ verify("struct k - input modified", input, e[0:i])
+ }
+
+ s := make(S, 10, 20)
+ r := make(S, len(s)+len(e))
+ for i, x := range e {
+ r[len(s)+i] = x
+ }
+ verify("struct l", append(s), s)
+ verify("struct m", append(s, e...), r)
+}
+
+
+func verifyInterface() {
+ type T interface{}
+ type S []T
+ e := make(S, 100)
+ for i := range e {
+ switch i % 4 {
+ case 0:
+ e[i] = i
+ case 1:
+ e[i] = "foo"
+ case 2:
+ e[i] = fmt.Sprintf("%d", i)
+ case 3:
+ e[i] = float(i)
+ }
+ }
+
+ verify("interface a", append(S{}), S{})
+ verify("interface b", append(S{}, e[0]), e[0:1])
+ verify("interface c", append(S{}, e[0], e[1], e[2]), e[0:3])
+
+ verify("interface d", append(e[0:1]), e[0:1])
+ verify("interface e", append(e[0:1], e[1]), e[0:2])
+ verify("interface f", append(e[0:1], e[1], e[2], e[3]), e[0:4])
+
+ verify("interface g", append(e[0:3]), e[0:3])
+ verify("interface h", append(e[0:3], e[3]), e[0:4])
+ verify("interface i", append(e[0:3], e[3], e[4], e[5], e[6]), e[0:7])
+
+ for i := range e {
+ verify("interface j", append(S{}, e[0:i]...), e[0:i])
+ input := make(S, i)
+ copy(input, e[0:i])
+ verify("interface k", append(input, e[i:]...), e)
+ verify("interface k - input modified", input, e[0:i])
+ }
+
+ s := make(S, 10, 20)
+ r := make(S, len(s)+len(e))
+ for i, x := range e {
+ r[len(s)+i] = x
+ }
+ verify("interface l", append(s), s)
+ verify("interface m", append(s, e...), r)
+}
diff --git a/test/arm-pass.txt b/test/arm-pass.txt
deleted file mode 100644
index 8878f6dc8..000000000
--- a/test/arm-pass.txt
+++ /dev/null
@@ -1,444 +0,0 @@
-./235.go
-./64bit.go # slow with GOGC=on
-./args.go
-./assign.go
-./bigalg.go
-./blank.go
-./blank1.go
-./chancap.go
-./char_lit.go
-./closedchan.go
-./closure.go
-./cmp1.go
-./cmp2.go
-./cmp3.go
-./cmp4.go
-./cmp5.go
-./complit.go
-./compos.go
-./const.go
-./const1.go
-./const2.go
-./const3.go
-./convert.go
-./convert3.go
-./convlit.go
-./convlit1.go
-# ./copy.go # slow
-./ddd.go
-./ddd1.go
-./ddd2.go
-./ddd3.go
-./decl.go
-./declbad.go
-./defer.go
-# ./deferprint.go # need floating point
-./empty.go
-./env.go
-./escape.go
-# ./float_lit.go # need floating point
-# ./floatcmp.go # need floating point
-./for.go
-# ./func.go
-./func1.go
-./func2.go
-./func3.go
-./func4.go
-./func5.go
-# ./gc.go
-# ./gc1.go
-./hashmap.go
-./hilbert.go
-./helloworld.go
-./if.go
-./if1.go
-./import.go
-./import1.go
-./import2.go
-./import3.go
-./import4.go
-./indirect.go
-./indirect1.go
-./initcomma.go
-# ./initialize.go # need floating point
-./initializerr.go
-./initsyscall.go
-./int_lit.go
-./intcvt.go
-./iota.go
-# ./literal.go # need floating point
-# ./malloc1.go
-# ./mallocfin.go
-# ./mallocrand.go
-# ./mallocrep.go
-# ./mallocrep1.go
-# ./map.go # need floating point
-./method.go
-./method1.go
-./method2.go
-./method3.go
-#./named.go # need floating point
-./named1.go
-./nil.go
-# ./nul1.go # android runner gets confused
-./parentype.go
-# ./peano.go # foo
-./printbig.go
-./range.go
-./recover.go
-./recover1.go
-./recover2.go
-./rename.go
-./rename1.go
-./runtime.go
-./sieve.go
-# ./sigchld.go # fail - does not survive signal
-./simassign.go
-./stack.go
-./string_lit.go
-./stringrange.go
-./switch.go
-./switch1.go
-./test0.go
-./turing.go
-./typeswitch.go
-# ./typeswitch1.go
-./typeswitch2.go
-./utf.go
-./varinit.go
-# ./vectors.go
-ken/array.go
-# ken/chan.go # slow
-# ken/chan1.go # slow
-ken/complit.go
-# ken/cplx0.go # need floating point
-# ken/cplx1.go # need floating point
-# ken/cplx2.go # need floating point
-# ken/cplx3.go # need floating point
-# ken/cplx4.go # need floating point
-# ken/cplx5.go # need floating point
-# ken/divconst.go # slow
-ken/divmod.go
-ken/embed.go
-ken/for.go
-ken/interbasic.go
-ken/interfun.go
-ken/intervar.go
-ken/label.go
-ken/litfun.go
-ken/mfunc.go
-# ken/modconst.go # slow
-ken/ptrfun.go
-ken/ptrvar.go
-ken/range.go
-ken/rob1.go
-ken/rob2.go
-ken/robfor.go
-# ken/robfunc.go # fail
-ken/robif.go
-ken/shift.go
-#ken/simparray.go # need floating point
-ken/simpbool.go
-#ken/simpconv.go # need floating point
-ken/simpfun.go
-ken/simpprint.go
-ken/simpswitch.go
-ken/simpvar.go
-#ken/slicearray.go # need floating point
-#ken/sliceslice.go # need floating point
-ken/string.go
-ken/strvar.go
-# chan/doubleselect.go # slow
-chan/fifo.go
-chan/goroutines.go
-chan/nonblock.go
-chan/perm.go
-chan/powser1.go
-chan/powser2.go
-chan/select.go
-chan/select2.go
-chan/sieve1.go
-chan/sieve2.go
-interface/bigdata.go
-interface/convert.go
-interface/convert1.go
-interface/convert2.go
-interface/embed.go
-interface/embed0.go
-interface/embed1.go
-interface/explicit.go
-# interface/fake.go # fails - panic: assert
-interface/fail.go
-interface/pointer.go
-interface/receiver.go
-interface/receiver1.go
-interface/recursive.go
-interface/returntype.go
-interface/struct.go
-nilptr/arrayindex.go
-nilptr/arrayindex1.go
-nilptr/arraytoslice.go
-nilptr/arraytoslice1.go
-nilptr/arraytoslice2.go
-nilptr/slicearray.go
-nilptr/structfield.go
-nilptr/structfield1.go
-nilptr/structfield2.go
-nilptr/structfieldaddr.go
-syntax/forvar.go
-syntax/import.go
-syntax/interface.go
-syntax/semi1.go
-syntax/semi2.go
-syntax/semi3.go
-syntax/semi4.go
-syntax/semi5.go
-syntax/semi6.go
-syntax/semi7.go
-syntax/slice.go
-syntax/vareq.go
-syntax/vareq1.go
-fixedbugs/bug000.go
-fixedbugs/bug001.go
-fixedbugs/bug002.go
-fixedbugs/bug003.go
-fixedbugs/bug004.go
-fixedbugs/bug005.go
-fixedbugs/bug006.go
-fixedbugs/bug007.go
-fixedbugs/bug008.go
-fixedbugs/bug009.go
-fixedbugs/bug010.go
-#fixedbugs/bug011.go # need floating point
-fixedbugs/bug012.go
-fixedbugs/bug013.go
-fixedbugs/bug014.go
-fixedbugs/bug015.go
-fixedbugs/bug016.go
-fixedbugs/bug017.go
-fixedbugs/bug020.go
-fixedbugs/bug021.go
-fixedbugs/bug022.go
-fixedbugs/bug023.go
-fixedbugs/bug024.go
-fixedbugs/bug026.go
-fixedbugs/bug027.go
-fixedbugs/bug028.go
-fixedbugs/bug030.go
-fixedbugs/bug031.go
-fixedbugs/bug035.go
-fixedbugs/bug036.go
-fixedbugs/bug037.go
-fixedbugs/bug038.go
-fixedbugs/bug039.go
-fixedbugs/bug040.go
-fixedbugs/bug045.go
-fixedbugs/bug046.go
-fixedbugs/bug047.go
-fixedbugs/bug048.go
-fixedbugs/bug049.go
-fixedbugs/bug050.go
-fixedbugs/bug051.go
-fixedbugs/bug052.go
-fixedbugs/bug053.go
-fixedbugs/bug054.go
-fixedbugs/bug055.go
-fixedbugs/bug056.go
-fixedbugs/bug057.go
-fixedbugs/bug058.go
-fixedbugs/bug059.go
-fixedbugs/bug060.go
-fixedbugs/bug061.go
-fixedbugs/bug062.go
-fixedbugs/bug063.go
-fixedbugs/bug064.go
-fixedbugs/bug065.go
-fixedbugs/bug066.go
-fixedbugs/bug067.go
-fixedbugs/bug068.go
-fixedbugs/bug069.go
-fixedbugs/bug070.go
-fixedbugs/bug071.go
-fixedbugs/bug072.go
-fixedbugs/bug073.go
-fixedbugs/bug074.go
-fixedbugs/bug075.go
-fixedbugs/bug076.go
-fixedbugs/bug077.go
-fixedbugs/bug078.go
-fixedbugs/bug080.go
-fixedbugs/bug081.go
-fixedbugs/bug082.go
-fixedbugs/bug083.go
-fixedbugs/bug084.go
-fixedbugs/bug085.go
-fixedbugs/bug086.go
-fixedbugs/bug087.go
-fixedbugs/bug088.go
-fixedbugs/bug089.go
-fixedbugs/bug090.go
-fixedbugs/bug091.go
-fixedbugs/bug092.go
-fixedbugs/bug093.go
-fixedbugs/bug094.go
-fixedbugs/bug096.go
-fixedbugs/bug097.go
-fixedbugs/bug098.go
-fixedbugs/bug099.go
-fixedbugs/bug101.go
-fixedbugs/bug102.go
-fixedbugs/bug103.go
-fixedbugs/bug104.go
-fixedbugs/bug106.go
-fixedbugs/bug107.go
-fixedbugs/bug108.go
-fixedbugs/bug109.go
-fixedbugs/bug110.go
-fixedbugs/bug111.go
-fixedbugs/bug112.go
-fixedbugs/bug113.go
-fixedbugs/bug114.go
-fixedbugs/bug115.go
-fixedbugs/bug116.go
-fixedbugs/bug117.go
-fixedbugs/bug118.go
-fixedbugs/bug119.go
-# fixedbugs/bug120.go # needs floating point
-fixedbugs/bug121.go
-fixedbugs/bug122.go
-fixedbugs/bug123.go
-fixedbugs/bug126.go
-fixedbugs/bug127.go
-fixedbugs/bug128.go
-fixedbugs/bug129.go
-fixedbugs/bug130.go
-fixedbugs/bug131.go
-fixedbugs/bug132.go
-fixedbugs/bug133.go
-fixedbugs/bug135.go
-fixedbugs/bug136.go
-fixedbugs/bug137.go
-fixedbugs/bug139.go
-fixedbugs/bug140.go
-fixedbugs/bug141.go
-fixedbugs/bug142.go
-fixedbugs/bug143.go
-fixedbugs/bug144.go
-fixedbugs/bug145.go
-fixedbugs/bug146.go
-fixedbugs/bug147.go
-fixedbugs/bug148.go
-fixedbugs/bug149.go
-fixedbugs/bug150.go
-fixedbugs/bug151.go
-fixedbugs/bug152.go
-fixedbugs/bug153.go
-# fixedbugs/bug154.go # needs floating point
-fixedbugs/bug155.go
-fixedbugs/bug156.go
-fixedbugs/bug157.go
-fixedbugs/bug158.go
-fixedbugs/bug159.go
-fixedbugs/bug160.go
-fixedbugs/bug161.go
-fixedbugs/bug163.go
-fixedbugs/bug164.go
-fixedbugs/bug165.go
-fixedbugs/bug167.go
-fixedbugs/bug168.go
-fixedbugs/bug169.go
-fixedbugs/bug170.go
-fixedbugs/bug171.go
-fixedbugs/bug172.go
-fixedbugs/bug173.go
-fixedbugs/bug174.go
-fixedbugs/bug175.go
-fixedbugs/bug176.go
-fixedbugs/bug177.go
-fixedbugs/bug178.go
-fixedbugs/bug179.go
-fixedbugs/bug180.go
-fixedbugs/bug181.go
-fixedbugs/bug182.go
-fixedbugs/bug183.go
-fixedbugs/bug184.go
-fixedbugs/bug185.go
-fixedbugs/bug186.go
-fixedbugs/bug187.go
-fixedbugs/bug188.go
-fixedbugs/bug189.go
-fixedbugs/bug190.go
-fixedbugs/bug191.go
-fixedbugs/bug192.go
-fixedbugs/bug193.go
-fixedbugs/bug194.go
-fixedbugs/bug195.go
-fixedbugs/bug196.go
-fixedbugs/bug197.go
-fixedbugs/bug198.go
-fixedbugs/bug199.go
-fixedbugs/bug200.go
-fixedbugs/bug201.go
-fixedbugs/bug202.go
-fixedbugs/bug203.go
-fixedbugs/bug204.go
-fixedbugs/bug205.go
-fixedbugs/bug206.go
-fixedbugs/bug207.go
-fixedbugs/bug208.go
-fixedbugs/bug209.go
-fixedbugs/bug211.go
-fixedbugs/bug212.go
-fixedbugs/bug213.go
-fixedbugs/bug214.go
-fixedbugs/bug215.go
-fixedbugs/bug216.go
-fixedbugs/bug217.go
-fixedbugs/bug218.go
-fixedbugs/bug219.go
-fixedbugs/bug220.go
-# fixedbugs/bug221.go # slow
-fixedbugs/bug222.go
-fixedbugs/bug223.go
-fixedbugs/bug224.go
-fixedbugs/bug225.go
-fixedbugs/bug226.go
-fixedbugs/bug227.go
-fixedbugs/bug228.go
-fixedbugs/bug229.go
-fixedbugs/bug230.go
-fixedbugs/bug231.go
-fixedbugs/bug232.go
-fixedbugs/bug233.go
-fixedbugs/bug234.go
-fixedbugs/bug235.go
-# fixedbugs/bug236.go # slow
-fixedbugs/bug237.go
-fixedbugs/bug238.go
-fixedbugs/bug239.go
-fixedbugs/bug240.go
-fixedbugs/bug241.go
-fixedbugs/bug242.go
-# fixedbugs/bug243.go # fail
-fixedbugs/bug244.go
-fixedbugs/bug245.go
-fixedbugs/bug246.go
-fixedbugs/bug247.go
-fixedbugs/bug248.go
-fixedbugs/bug249.go
-fixedbugs/bug250.go
-fixedbugs/bug251.go
-fixedbugs/bug252.go
-fixedbugs/bug253.go
-fixedbugs/bug254.go
-fixedbugs/bug255.go
-fixedbugs/bug256.go
-# fixedbugs/bug257.go # slow
-# fixedbugs/bug258.go # needs floating point
-fixedbugs/bug259.go
-fixedbugs/bug261.go
-fixedbugs/bug262.go
-fixedbugs/bug263.go
-fixedbugs/bug264.go
-fixedbugs/bug265.go
-bugs/bug260.go
diff --git a/test/assign.go b/test/assign.go
index fea7c2828..59471388c 100644
--- a/test/assign.go
+++ b/test/assign.go
@@ -9,45 +9,45 @@ package main
import "sync"
type T struct {
- int;
- sync.Mutex;
+ int
+ sync.Mutex
}
func main() {
{
- var x, y sync.Mutex;
- x = y; // ERROR "assignment.*Mutex"
- _ = x;
+ var x, y sync.Mutex
+ x = y // ERROR "assignment.*Mutex"
+ _ = x
}
{
- var x, y T;
- x = y; // ERROR "assignment.*Mutex"
- _ = x;
+ var x, y T
+ x = y // ERROR "assignment.*Mutex"
+ _ = x
}
{
- var x, y [2]sync.Mutex;
- x = y; // ERROR "assignment.*Mutex"
- _ = x;
+ var x, y [2]sync.Mutex
+ x = y // ERROR "assignment.*Mutex"
+ _ = x
}
{
- var x, y [2]T;
- x = y; // ERROR "assignment.*Mutex"
- _ = x;
+ var x, y [2]T
+ x = y // ERROR "assignment.*Mutex"
+ _ = x
}
{
- x := sync.Mutex{0, 0}; // ERROR "assignment.*Mutex"
- _ = x;
+ x := sync.Mutex{0, 0} // ERROR "assignment.*Mutex"
+ _ = x
}
{
- x := sync.Mutex{key: 0}; // ERROR "(unknown|assignment).*Mutex"
- _ = x;
+ x := sync.Mutex{key: 0} // ERROR "(unknown|assignment).*Mutex"
+ _ = x
}
{
- x := &sync.Mutex{}; // ok
- var y sync.Mutex; // ok
- y = *x; // ERROR "assignment.*Mutex"
- *x = y; // ERROR "assignment.*Mutex"
- _ = x;
- _ = y;
+ x := &sync.Mutex{} // ok
+ var y sync.Mutex // ok
+ y = *x // ERROR "assignment.*Mutex"
+ *x = y // ERROR "assignment.*Mutex"
+ _ = x
+ _ = y
}
}
diff --git a/test/assign1.go b/test/assign1.go
index 452f90f1c..71e5b4064 100644
--- a/test/assign1.go
+++ b/test/assign1.go
@@ -155,61 +155,61 @@ func main() {
s1 = s0
s1 = s // ERROR "cannot use"
- pa0 = pa // ERROR "cannot use"
- pa0 = pa1 // ERROR "cannot use"
- pa = pa0 // ERROR "cannot use"
- pa = pa1 // ERROR "cannot use"
- pa1 = pa0 // ERROR "cannot use"
- pa1 = pa // ERROR "cannot use"
-
- pb0 = pb // ERROR "cannot use"
- pb0 = pb1 // ERROR "cannot use"
- pb = pb0 // ERROR "cannot use"
- pb = pb1 // ERROR "cannot use"
- pb1 = pb0 // ERROR "cannot use"
- pb1 = pb // ERROR "cannot use"
-
- pc0 = pc // ERROR "cannot use"
- pc0 = pc1 // ERROR "cannot use"
- pc = pc0 // ERROR "cannot use"
- pc = pc1 // ERROR "cannot use"
- pc1 = pc0 // ERROR "cannot use"
- pc1 = pc // ERROR "cannot use"
-
- pf0 = pf // ERROR "cannot use"
- pf0 = pf1 // ERROR "cannot use"
- pf = pf0 // ERROR "cannot use"
- pf = pf1 // ERROR "cannot use"
- pf1 = pf0 // ERROR "cannot use"
- pf1 = pf // ERROR "cannot use"
-
- pi0 = pi // ERROR "cannot use"
- pi0 = pi1 // ERROR "cannot use"
- pi = pi0 // ERROR "cannot use"
- pi = pi1 // ERROR "cannot use"
- pi1 = pi0 // ERROR "cannot use"
- pi1 = pi // ERROR "cannot use"
-
- pm0 = pm // ERROR "cannot use"
- pm0 = pm1 // ERROR "cannot use"
- pm = pm0 // ERROR "cannot use"
- pm = pm1 // ERROR "cannot use"
- pm1 = pm0 // ERROR "cannot use"
- pm1 = pm // ERROR "cannot use"
-
- pp0 = pp // ERROR "cannot use"
- pp0 = pp1 // ERROR "cannot use"
- pp = pp0 // ERROR "cannot use"
- pp = pp1 // ERROR "cannot use"
- pp1 = pp0 // ERROR "cannot use"
- pp1 = pp // ERROR "cannot use"
-
- ps0 = ps // ERROR "cannot use"
- ps0 = ps1 // ERROR "cannot use"
- ps = ps0 // ERROR "cannot use"
- ps = ps1 // ERROR "cannot use"
- ps1 = ps0 // ERROR "cannot use"
- ps1 = ps // ERROR "cannot use"
+ pa0 = pa // ERROR "cannot use|incompatible"
+ pa0 = pa1 // ERROR "cannot use|incompatible"
+ pa = pa0 // ERROR "cannot use|incompatible"
+ pa = pa1 // ERROR "cannot use|incompatible"
+ pa1 = pa0 // ERROR "cannot use|incompatible"
+ pa1 = pa // ERROR "cannot use|incompatible"
+
+ pb0 = pb // ERROR "cannot use|incompatible"
+ pb0 = pb1 // ERROR "cannot use|incompatible"
+ pb = pb0 // ERROR "cannot use|incompatible"
+ pb = pb1 // ERROR "cannot use|incompatible"
+ pb1 = pb0 // ERROR "cannot use|incompatible"
+ pb1 = pb // ERROR "cannot use|incompatible"
+
+ pc0 = pc // ERROR "cannot use|incompatible"
+ pc0 = pc1 // ERROR "cannot use|incompatible"
+ pc = pc0 // ERROR "cannot use|incompatible"
+ pc = pc1 // ERROR "cannot use|incompatible"
+ pc1 = pc0 // ERROR "cannot use|incompatible"
+ pc1 = pc // ERROR "cannot use|incompatible"
+
+ pf0 = pf // ERROR "cannot use|incompatible"
+ pf0 = pf1 // ERROR "cannot use|incompatible"
+ pf = pf0 // ERROR "cannot use|incompatible"
+ pf = pf1 // ERROR "cannot use|incompatible"
+ pf1 = pf0 // ERROR "cannot use|incompatible"
+ pf1 = pf // ERROR "cannot use|incompatible"
+
+ pi0 = pi // ERROR "cannot use|incompatible"
+ pi0 = pi1 // ERROR "cannot use|incompatible"
+ pi = pi0 // ERROR "cannot use|incompatible"
+ pi = pi1 // ERROR "cannot use|incompatible"
+ pi1 = pi0 // ERROR "cannot use|incompatible"
+ pi1 = pi // ERROR "cannot use|incompatible"
+
+ pm0 = pm // ERROR "cannot use|incompatible"
+ pm0 = pm1 // ERROR "cannot use|incompatible"
+ pm = pm0 // ERROR "cannot use|incompatible"
+ pm = pm1 // ERROR "cannot use|incompatible"
+ pm1 = pm0 // ERROR "cannot use|incompatible"
+ pm1 = pm // ERROR "cannot use|incompatible"
+
+ pp0 = pp // ERROR "cannot use|incompatible"
+ pp0 = pp1 // ERROR "cannot use|incompatible"
+ pp = pp0 // ERROR "cannot use|incompatible"
+ pp = pp1 // ERROR "cannot use|incompatible"
+ pp1 = pp0 // ERROR "cannot use|incompatible"
+ pp1 = pp // ERROR "cannot use|incompatible"
+
+ ps0 = ps // ERROR "cannot use|incompatible"
+ ps0 = ps1 // ERROR "cannot use|incompatible"
+ ps = ps0 // ERROR "cannot use|incompatible"
+ ps = ps1 // ERROR "cannot use|incompatible"
+ ps1 = ps0 // ERROR "cannot use|incompatible"
+ ps1 = ps // ERROR "cannot use|incompatible"
a0 = [10]int(a)
diff --git a/test/bench/fannkuch-parallel.go b/test/bench/fannkuch-parallel.go
index 7897eac05..7e9b98d50 100644
--- a/test/bench/fannkuch-parallel.go
+++ b/test/bench/fannkuch-parallel.go
@@ -44,7 +44,7 @@ import (
)
var n = flag.Int("n", 7, "count")
-var nCPU = flag.Int("ncpu", 2, "number of cpus")
+var nCPU = flag.Int("ncpu", 4, "number of cpus")
type Job struct {
start []int
diff --git a/test/bench/fasta.c b/test/bench/fasta.c
index 78a8490d7..64c1c5205 100644
--- a/test/bench/fasta.c
+++ b/test/bench/fasta.c
@@ -41,10 +41,12 @@ POSSIBILITY OF SUCH DAMAGE.
#include <stdlib.h>
#include <string.h>
+#ifndef fwrite_unlocked
// not available on OS X
#define fwrite_unlocked fwrite
#define fputc_unlocked fputc
#define fputs_unlocked fputs
+#endif
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
#define unlikely(x) __builtin_expect((x), 0)
@@ -214,4 +216,4 @@ main(int argc, const char **argv) {
">THREE Homo sapiens frequency\n", n*5, &rand);
return 0;
-} \ No newline at end of file
+}
diff --git a/test/bench/fasta.go b/test/bench/fasta.go
index 470bdb328..d13edd5dc 100644
--- a/test/bench/fasta.go
+++ b/test/bench/fasta.go
@@ -37,7 +37,6 @@ POSSIBILITY OF SUCH DAMAGE.
package main
import (
- "bytes"
"flag"
"os"
)
@@ -49,7 +48,7 @@ var n = flag.Int("n", 1000, "length of result")
const Line = 60
func Repeat(alu []byte, n int) {
- buf := bytes.Add(alu, alu)
+ buf := append(alu, alu...)
off := 0
for n > 0 {
m := n
@@ -138,28 +137,28 @@ func main() {
flag.Parse()
iub := []Acid{
- Acid{prob: 0.27, sym: 'a'},
- Acid{prob: 0.12, sym: 'c'},
- Acid{prob: 0.12, sym: 'g'},
- Acid{prob: 0.27, sym: 't'},
- Acid{prob: 0.02, sym: 'B'},
- Acid{prob: 0.02, sym: 'D'},
- Acid{prob: 0.02, sym: 'H'},
- Acid{prob: 0.02, sym: 'K'},
- Acid{prob: 0.02, sym: 'M'},
- Acid{prob: 0.02, sym: 'N'},
- Acid{prob: 0.02, sym: 'R'},
- Acid{prob: 0.02, sym: 'S'},
- Acid{prob: 0.02, sym: 'V'},
- Acid{prob: 0.02, sym: 'W'},
- Acid{prob: 0.02, sym: 'Y'},
+ {prob: 0.27, sym: 'a'},
+ {prob: 0.12, sym: 'c'},
+ {prob: 0.12, sym: 'g'},
+ {prob: 0.27, sym: 't'},
+ {prob: 0.02, sym: 'B'},
+ {prob: 0.02, sym: 'D'},
+ {prob: 0.02, sym: 'H'},
+ {prob: 0.02, sym: 'K'},
+ {prob: 0.02, sym: 'M'},
+ {prob: 0.02, sym: 'N'},
+ {prob: 0.02, sym: 'R'},
+ {prob: 0.02, sym: 'S'},
+ {prob: 0.02, sym: 'V'},
+ {prob: 0.02, sym: 'W'},
+ {prob: 0.02, sym: 'Y'},
}
homosapiens := []Acid{
- Acid{prob: 0.3029549426680, sym: 'a'},
- Acid{prob: 0.1979883004921, sym: 'c'},
- Acid{prob: 0.1975473066391, sym: 'g'},
- Acid{prob: 0.3015094502008, sym: 't'},
+ {prob: 0.3029549426680, sym: 'a'},
+ {prob: 0.1979883004921, sym: 'c'},
+ {prob: 0.1975473066391, sym: 'g'},
+ {prob: 0.3015094502008, sym: 't'},
}
alu := []byte(
@@ -192,9 +191,7 @@ func (b *buffer) Flush() {
func (b *buffer) WriteString(s string) {
p := b.NextWrite(len(s))
- for i := 0; i < len(s); i++ {
- p[i] = s[i]
- }
+ copy(p, s)
}
func (b *buffer) NextWrite(n int) []byte {
@@ -204,6 +201,6 @@ func (b *buffer) NextWrite(n int) []byte {
p = *b
}
out := p[len(p) : len(p)+n]
- *b = p[0 : len(p)+n]
+ *b = p[:len(p)+n]
return out
}
diff --git a/test/bench/k-nucleotide-parallel.go b/test/bench/k-nucleotide-parallel.go
index 0234f33d1..96c80d8f0 100644
--- a/test/bench/k-nucleotide-parallel.go
+++ b/test/bench/k-nucleotide-parallel.go
@@ -41,6 +41,7 @@ import (
"fmt"
"io/ioutil"
"os"
+ "runtime"
"sort"
)
@@ -97,6 +98,7 @@ func printKnucs(a kNucArray) {
}
func main() {
+ runtime.GOMAXPROCS(4)
in := bufio.NewReader(os.Stdin)
three := []byte(">THREE ")
for {
diff --git a/test/bench/pidigits.go b/test/bench/pidigits.go
index dcfb502ce..e59312177 100644
--- a/test/bench/pidigits.go
+++ b/test/bench/pidigits.go
@@ -49,6 +49,7 @@ var silent = flag.Bool("s", false, "don't print result")
var (
tmp1 = big.NewInt(0)
tmp2 = big.NewInt(0)
+ tmp3 = big.NewInt(0)
y2 = big.NewInt(0)
bigk = big.NewInt(0)
numer = big.NewInt(1)
@@ -80,7 +81,6 @@ func extract_digit() int64 {
}
func next_term(k int64) {
- // TODO(eds) If big.Int ever gets a Scale method, y2 and bigk could be int64
y2.SetInt64(k*2 + 1)
bigk.SetInt64(k)
@@ -92,15 +92,15 @@ func next_term(k int64) {
}
func eliminate_digit(d int64) {
- tmp := big.NewInt(0).Set(denom)
- accum.Sub(accum, tmp.Mul(tmp, big.NewInt(d)))
+ tmp3.SetInt64(d)
+ accum.Sub(accum, tmp3.Mul(denom, tmp3))
accum.Mul(accum, ten)
numer.Mul(numer, ten)
}
func printf(s string, arg ...interface{}) {
if !*silent {
- fmt.Printf(s, arg)
+ fmt.Printf(s, arg...)
}
}
diff --git a/test/bench/regex-dna-parallel.go b/test/bench/regex-dna-parallel.go
index d33f2466e..e8e62b806 100644
--- a/test/bench/regex-dna-parallel.go
+++ b/test/bench/regex-dna-parallel.go
@@ -77,8 +77,8 @@ func countMatches(pat string, bytes []byte) int {
re := regexp.MustCompile(pat)
n := 0
for {
- e := re.Execute(bytes)
- if len(e) == 0 {
+ e := re.FindIndex(bytes)
+ if e == nil {
break
}
n++
diff --git a/test/bench/regex-dna.go b/test/bench/regex-dna.go
index 22de2c6aa..dc31db768 100644
--- a/test/bench/regex-dna.go
+++ b/test/bench/regex-dna.go
@@ -76,7 +76,7 @@ func countMatches(pat string, bytes []byte) int {
re := regexp.MustCompile(pat)
n := 0
for {
- e := re.Execute(bytes)
+ e := re.FindIndex(bytes)
if len(e) == 0 {
break
}
diff --git a/test/bench/timing.log b/test/bench/timing.log
index e7b0b48c1..f2b6a1f40 100644
--- a/test/bench/timing.log
+++ b/test/bench/timing.log
@@ -90,7 +90,7 @@ mandelbrot 5500
gc mandelbrot 74.32u 0.00s 74.35r
gc_B mandelbrot 74.28u 0.01s 74.31r
-meteor 16000
+meteor 2100
# we don't know
gcc -O2 meteor-contest.c 0.10u 0.00s 0.10r
gccgo -O2 meteor-contest.go 0.12u 0.00s 0.14r
@@ -209,7 +209,7 @@ mandelbrot 16000
gc mandelbrot 64.05u 0.02s 64.08r # *** -14%
gc_B mandelbrot 64.10u 0.02s 64.14r # *** -14%
-meteor 16000
+meteor 2100
# we don't know
gcc -O2 meteor-contest.c 0.10u 0.00s 0.10r
gccgo -O2 meteor-contest.go 0.12u 0.00s 0.12r
@@ -307,7 +307,7 @@ mandelbrot 16000
gc mandelbrot 63.31u 0.01s 63.35r # -1%
gc_B mandelbrot 63.29u 0.00s 63.31r # -1%
-meteor 16000
+meteor 2100
# we don't know
gcc -O2 meteor-contest.c 0.10u 0.00s 0.10r
gccgo -O2 meteor-contest.go 0.11u 0.00s 0.12r
@@ -414,7 +414,7 @@ chameneos 6000000
gcc -O2 chameneosredux.c -lpthread 18.00u 303.29s 83.64r
gc chameneosredux 12.10u 0.00s 12.10r # 2.22X faster
-Jan 6, 2009
+Jan 6, 2010
# Long-overdue update. All numbers included in this complete run.
# Some programs (e.g. reverse-complement) rewritten for speed.
@@ -429,7 +429,7 @@ fasta -n 25000000
reverse-complement < output-of-fasta-25000000
gcc -O2 reverse-complement.c 2.00u 0.80s 9.54r
- gccgo -O2 reverse-complement.go 4.57u 0.35s 4.94r # 33% faster
+# gccgo -O2 reverse-complement.go 4.57u 0.35s 4.94r # 33% faster
gc reverse-complement 2.01u 0.38s 2.40r # 3.3X faster
gc_B reverse-complement 1.88u 0.36s 2.24r # 3.2X faster
GOGC=off
@@ -445,7 +445,6 @@ nbody -n 50000000
binary-tree 15 # too slow to use 20
gcc -O2 binary-tree.c -lm 0.86u 0.00s 0.87r
gccgo -O2 binary-tree.go 4.82u 0.41s 5.24r # 2.5X slower
- gccgo -O2 binary-tree-freelist.go 0.00u 0.00s 0.00r
gc binary-tree 7.23u 0.01s 7.25r # # -19%
gc binary-tree-freelist 0.43u 0.00s 0.44r # -9%
@@ -478,7 +477,7 @@ mandelbrot 16000
gc mandelbrot 66.05u 0.00s 66.07r # -3%
gc_B mandelbrot 66.06u 0.00s 66.07r # -3%
-meteor 16000
+meteor 2100
gcc -O2 meteor-contest.c 0.10u 0.00s 0.10r
gccgo -O2 meteor-contest.go 0.12u 0.00s 0.12r
gc meteor-contest 0.17u 0.00s 0.17r
@@ -498,3 +497,98 @@ chameneos 6000000
gcc -O2 chameneosredux.c -lpthread 19.02u 331.08s 90.79r
gc chameneosredux 12.54u 0.00s 12.55r
+Oct 19, 2010
+
+# Another long-overdue update. Some of the code is new; parallel versions
+# of some are added. A few significant improvements.
+
+fasta -n 25000000
+ gcc -O2 fasta.c 4.92u 0.00s 4.93r
+ gccgo -O2 fasta.go 3.31u 0.00s 3.34r # new code
+ gc fasta 3.68u 0.00s 3.69r # 2.5X faster with no code
+ gc_B fasta 3.68u 0.00s 3.69r # 2.3X faster with no code
+
+reverse-complement < output-of-fasta-25000000
+ gcc -O2 reverse-complement.c 1.93u 0.81s 11.24r
+ gccgo -O2 reverse-complement.go 1.58u 0.43s 2.04r # first run with new code?
+ gc reverse-complement 1.84u 0.34s 2.20r # 10% faster
+ gc_B reverse-complement 1.85u 0.32s 2.18r
+
+nbody -n 50000000
+ gcc -O2 nbody.c 21.35u 0.00s 21.36r
+ gccgo -O2 nbody.go 21.62u 0.00s 21.66r # 3.7X faster - why??
+ gc nbody 29.78u 0.00s 29.79r
+ gc_B nbody 29.72u 0.00s 29.72r
+
+binary-tree 15 # too slow to use 20
+ gcc -O2 binary-tree.c -lm 0.86u 0.00s 0.88r
+ gccgo -O2 binary-tree.go 4.05u 0.02s 4.08r # 28% faster
+ gccgo -O2 binary-tree-freelist 0.34u 0.08s 0.34r
+ gc binary-tree 5.94u 0.00s 5.95r # 20% faster
+ gc binary-tree-freelist 0.50u 0.01s 0.54r
+
+fannkuch 12
+ gcc -O2 fannkuch.c 60.45u 0.00s 60.45r
+ gccgo -O2 fannkuch.go 64.64u 0.00s 64.64r
+ gccgo -O2 fannkuch-parallel.go 115.63u 0.00s 31.58r
+ gc fannkuch 126.52u 0.04s 126.68r
+ gc fannkuch-parallel 238.82u 0.10s 65.93r # GOMAXPROCS=4
+ gc_B fannkuch 88.99u 0.00s 89.02r
+
+regex-dna 100000
+ gcc -O2 regex-dna.c -lpcre 0.89u 0.00s 0.89r
+ gc regex-dna 8.99u 0.02s 9.03r
+ gc regex-dna-parallel 8.94u 0.02s 3.68r # GOMAXPROCS=4
+ gc_B regex-dna 9.12u 0.00s 9.14r
+
+spectral-norm 5500
+ gcc -O2 spectral-norm.c -lm 11.55u 0.00s 11.57r
+ gccgo -O2 spectral-norm.go 11.73u 0.00s 11.75r
+ gc spectral-norm 23.74u 0.00s 23.79r
+ gc_B spectral-norm 24.49u 0.02s 24.54r
+
+k-nucleotide 1000000
+ gcc -O2 k-nucleotide.c 11.44u 0.06s 11.50r
+ gccgo -O2 k-nucleotide.go 8.65u 0.04s 8.71r
+ gccgo -O2 k-nucleotide-parallel.go 8.75u 0.03s 2.97r # set GOMAXPROCS=4
+ gc k-nucleotide 14.92u 0.05s 15.01r
+ gc k-nucleotide-parallel 16.96u 0.06s 6.53r # set GOMAXPROCS=4
+ gc_B k-nucleotide 15.97u 0.03s 16.08r
+
+mandelbrot 16000
+ gcc -O2 mandelbrot.c 56.32u 0.00s 56.35r
+ gccgo -O2 mandelbrot.go 55.62u 0.02s 55.77r
+ gc mandelbrot 64.85u 0.01s 64.94r
+ gc_B mandelbrot 65.02u 0.01s 65.14r
+
+meteor 2100
+ gcc -O2 meteor-contest.c 0.10u 0.00s 0.10r
+ gccgo -O2 meteor-contest.go 0.10u 0.00s 0.11r
+ gc meteor-contest 0.17u 0.00s 0.18r
+ gc_B meteor-contest 0.16u 0.00s 0.16r
+
+pidigits 10000
+ gcc -O2 pidigits.c -lgmp 2.58u 0.00s 2.59r
+ gccgo -O2 pidigits.go 14.06u 0.01s 14.09r # first run?
+ gc pidigits 8.47u 0.05s 8.55r # 4.5X faster due to package big
+ gc_B pidigits 8.33u 0.01s 8.36r # 4.5X faster due to package big
+
+threadring 50000000
+ gcc -O2 threadring.c 28.18u 153.19s 186.47r
+ gccgo -O2 threadring.go 110.10u 516.48s 515.25r
+ gc threadring 40.39u 0.00s 40.40r
+
+chameneos 6000000
+ gcc -O2 chameneosredux.c -lpthread 18.20u 301.55s 83.10r
+ gccgo -O2 chameneosredux.go 52.22u 324.54s 201.21r
+ gc chameneosredux 13.52u 0.00s 13.54r
+
+Dec 14, 2010
+
+# Improved regex code (same algorithm) gets ~30%.
+
+regex-dna 100000
+ gcc -O2 regex-dna.c -lpcre 0.77u 0.01s 0.78r
+ gc regex-dna 6.80u 0.00s 6.81r
+ gc regex-dna-parallel 6.82u 0.01s 2.75r
+ gc_B regex-dna 6.69u 0.02s 6.70r
diff --git a/test/bench/timing.sh b/test/bench/timing.sh
index 5cd82dfd9..fec39182c 100755
--- a/test/bench/timing.sh
+++ b/test/bench/timing.sh
@@ -5,11 +5,15 @@
set -e
-GOBIN="${GOBIN:-$HOME/bin}"
-
-. "$GOROOT"/src/Make.$GOARCH
+eval $(gomake --no-print-directory -f ../../src/Make.inc go-env)
PATH=.:$PATH
+havegccgo=false
+if which gccgo >/dev/null 2>&1
+then
+ havegccgo=true
+fi
+
mode=run
case X"$1" in
X-test)
@@ -18,11 +22,11 @@ X-test)
esac
gc() {
- "$GOBIN"/$GC $1.go; "$GOBIN"/$LD $1.$O
+ $GC $1.go; $LD $1.$O
}
gc_B() {
- "$GOBIN"/$GC -B $1.go; "$GOBIN"/$LD $1.$O
+ $GC -B $1.go; $LD $1.$O
}
runonly() {
@@ -32,8 +36,6 @@ runonly() {
fi
}
-
-
run() {
if [ $mode = test ]
then
@@ -59,6 +61,10 @@ run() {
fi
return
fi
+ if ! $havegccgo && echo $1 | grep -q '^gccgo '
+ then
+ return
+ fi
echo -n ' '$1' '
$1
shift
@@ -69,7 +75,7 @@ run() {
fasta() {
runonly echo 'fasta -n 25000000'
run 'gcc -O2 fasta.c' a.out 25000000
- #run 'gccgo -O2 fasta.go' a.out -n 25000000 #commented out until WriteString is in bufio
+ run 'gccgo -O2 fasta.go' a.out -n 25000000 #commented out until WriteString is in bufio
run 'gc fasta' $O.out -n 25000000
run 'gc_B fasta' $O.out -n 25000000
}
@@ -87,7 +93,7 @@ revcomp() {
nbody() {
runonly echo 'nbody -n 50000000'
- run 'gcc -O2 nbody.c' a.out 50000000
+ run 'gcc -O2 -lm nbody.c' a.out 50000000
run 'gccgo -O2 nbody.go' a.out -n 50000000
run 'gc nbody' $O.out -n 50000000
run 'gc_B nbody' $O.out -n 50000000
@@ -117,7 +123,7 @@ regexdna() {
runonly a.out 100000 > x
runonly echo 'regex-dna 100000'
run 'gcc -O2 regex-dna.c -lpcre' a.out <x
-# run 'gccgo -O2 regex-dna.go' a.out <x # pages badly; don't run
+# run 'gccgo -O2 regex-dna.go' a.out <x # restore after regexp.FindIndex is in library
run 'gc regex-dna' $O.out <x
run 'gc regex-dna-parallel' $O.out <x
run 'gc_B regex-dna' $O.out <x
@@ -137,8 +143,8 @@ knucleotide() {
runonly a.out 1000000 > x # should be using 25000000
runonly echo 'k-nucleotide 1000000'
run 'gcc -O2 -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include k-nucleotide.c -lglib-2.0' a.out <x
- run 'gccgo -O2 k-nucleotide.go' a.out <x # warning: pages badly!
- run 'gccgo -O2 k-nucleotide-parallel.go' a.out <x # warning: pages badly!
+ run 'gccgo -O2 k-nucleotide.go' a.out <x
+ run 'gccgo -O2 k-nucleotide-parallel.go' a.out <x
run 'gc k-nucleotide' $O.out <x
run 'gc k-nucleotide-parallel' $O.out <x
run 'gc_B k-nucleotide' $O.out <x
@@ -154,17 +160,17 @@ mandelbrot() {
}
meteor() {
- runonly echo 'meteor 16000'
- run 'gcc -O2 meteor-contest.c' a.out
- run 'gccgo -O2 meteor-contest.go' a.out
- run 'gc meteor-contest' $O.out
- run 'gc_B meteor-contest' $O.out
+ runonly echo 'meteor 2098'
+ run 'gcc -O2 meteor-contest.c' a.out 2098
+ run 'gccgo -O2 meteor-contest.go' a.out -n 2098
+ run 'gc meteor-contest' $O.out -n 2098
+ run 'gc_B meteor-contest' $O.out -n 2098
}
pidigits() {
runonly echo 'pidigits 10000'
run 'gcc -O2 pidigits.c -lgmp' a.out 10000
-# run 'gccgo -O2 pidigits.go' a.out -n 10000 # uncomment when gccgo library updated
+ run 'gccgo -O2 pidigits.go' a.out -n 10000
run 'gc pidigits' $O.out -n 10000
run 'gc_B pidigits' $O.out -n 10000
}
diff --git a/test/bigalg.go b/test/bigalg.go
index 31ce222d6..902ba8410 100644
--- a/test/bigalg.go
+++ b/test/bigalg.go
@@ -7,35 +7,35 @@
package main
type T struct {
- a float64;
- b int64;
- c string;
- d byte;
+ a float64
+ b int64
+ c string
+ d byte
}
var a = []int{ 1, 2, 3 }
-var NIL []int;
+var NIL []int
func arraycmptest() {
if NIL != nil {
- println("fail1:", NIL, "!= nil");
+ println("fail1:", NIL, "!= nil")
}
if nil != NIL {
- println("fail2: nil !=", NIL);
+ println("fail2: nil !=", NIL)
}
if a == nil || nil == a {
- println("fail3:", a, "== nil");
+ println("fail3:", a, "== nil")
}
}
func SameArray(a, b []int) bool {
if len(a) != len(b) || cap(a) != cap(b) {
- return false;
+ return false
}
if len(a) > 0 && &a[0] != &b[0] {
- return false;
+ return false
}
- return true;
+ return true
}
var t = T{1.5, 123, "hello", 255}
@@ -43,16 +43,16 @@ var mt = make(map[int]T)
var ma = make(map[int][]int)
func maptest() {
- mt[0] = t;
- t1 := mt[0];
+ mt[0] = t
+ t1 := mt[0]
if t1.a != t.a || t1.b != t.b || t1.c != t.c || t1.d != t.d {
- println("fail: map val struct", t1.a, t1.b, t1.c, t1.d);
+ println("fail: map val struct", t1.a, t1.b, t1.c, t1.d)
}
- ma[1] = a;
- a1 := ma[1];
+ ma[1] = a
+ a1 := ma[1]
if !SameArray(a, a1) {
- println("fail: map val array", a, a1);
+ println("fail: map val array", a, a1)
}
}
@@ -60,21 +60,21 @@ var ct = make(chan T)
var ca = make(chan []int)
func send() {
- ct <- t;
- ca <- a;
+ ct <- t
+ ca <- a
}
func chantest() {
- go send();
+ go send()
- t1 := <-ct;
+ t1 := <-ct
if t1.a != t.a || t1.b != t.b || t1.c != t.c || t1.d != t.d {
- println("fail: map val struct", t1.a, t1.b, t1.c, t1.d);
+ println("fail: map val struct", t1.a, t1.b, t1.c, t1.d)
}
- a1 := <-ca;
+ a1 := <-ca
if !SameArray(a, a1) {
- println("fail: map val array", a, a1);
+ println("fail: map val array", a, a1)
}
}
@@ -82,36 +82,36 @@ type E struct { }
var e E
func interfacetest() {
- var i interface{};
+ var i interface{}
- i = a;
- a1 := i.([]int);
+ i = a
+ a1 := i.([]int)
if !SameArray(a, a1) {
- println("interface <-> []int", a, a1);
+ println("interface <-> []int", a, a1)
}
- pa := new([]int);
- *pa = a;
- i = pa;
- a1 = *i.(*[]int);
+ pa := new([]int)
+ *pa = a
+ i = pa
+ a1 = *i.(*[]int)
if !SameArray(a, a1) {
- println("interface <-> *[]int", a, a1);
+ println("interface <-> *[]int", a, a1)
}
- i = t;
- t1 := i.(T);
+ i = t
+ t1 := i.(T)
if t1.a != t.a || t1.b != t.b || t1.c != t.c || t1.d != t.d {
- println("interface <-> struct", t1.a, t1.b, t1.c, t1.d);
+ println("interface <-> struct", t1.a, t1.b, t1.c, t1.d)
}
- i = e;
- e1 := i.(E);
+ i = e
+ e1 := i.(E)
// nothing to check; just verify it doesn't crash
- _ = e1;
+ _ = e1
}
func main() {
- arraycmptest();
- maptest();
- chantest();
- interfacetest();
+ arraycmptest()
+ maptest()
+ chantest()
+ interfacetest()
}
diff --git a/test/blank.go b/test/blank.go
index 7175964f7..6e69f8aaa 100644
--- a/test/blank.go
+++ b/test/blank.go
@@ -11,7 +11,7 @@ import _ "fmt"
var call string
type T struct {
- _, _, _ int;
+ _, _, _ int
}
func (T) _() {
@@ -21,11 +21,11 @@ func (T) _() {
}
const (
- c0 = iota;
- _;
- _;
- _;
- c4;
+ c0 = iota
+ _
+ _
+ _
+ c4
)
var ints = []string {
@@ -35,12 +35,12 @@ var ints = []string {
}
func f() (int, int) {
- call += "f";
+ call += "f"
return 1,2
}
func g() (float, float) {
- call += "g";
+ call += "g"
return 3,4
}
@@ -48,54 +48,54 @@ func h(_ int, _ float) {
}
func i() int {
- call += "i";
- return 23;
+ call += "i"
+ return 23
}
-var _ = i();
+var _ = i()
func main() {
if call != "i" {panic("init did not run")}
- call = "";
- _, _ = f();
- a, _ := f();
+ call = ""
+ _, _ = f()
+ a, _ := f()
if a != 1 {panic(a)}
- b, _ := g();
+ b, _ := g()
if b != 3 {panic(b)}
- _, a = f();
+ _, a = f()
if a != 2 {panic(a)}
- _, b = g();
+ _, b = g()
if b != 4 {panic(b)}
- _ = i();
+ _ = i()
if call != "ffgfgi" {panic(call)}
if c4 != 4 {panic(c4)}
- out := "";
+ out := ""
for _, s := range ints {
- out += s;
+ out += s
}
if out != "123" {panic(out)}
- sum := 0;
- for s, _ := range ints {
- sum += s;
+ sum := 0
+ for s := range ints {
+ sum += s
}
if sum != 3 {panic(sum)}
- h(a,b);
+ h(a,b)
}
// useless but legal
-var _ int = 1;
-var _ = 2;
-var _, _ = 3, 4;
-const _ = 3;
-const _, _ = 4, 5;
-type _ int;
+var _ int = 1
+var _ = 2
+var _, _ = 3, 4
+const _ = 3
+const _, _ = 4, 5
+type _ int
func _() {
panic("oops")
}
func ff() {
- var _ int = 1;
+ var _ int = 1
}
diff --git a/test/blank1.go b/test/blank1.go
index 2fa6e9f8f..5bc1efce5 100644
--- a/test/blank1.go
+++ b/test/blank1.go
@@ -7,6 +7,6 @@
package _ // ERROR "invalid package name _"
func main() {
- _(); // ERROR "cannot use _ as value"
- x := _+1; // ERROR "cannot use _ as value"
+ _() // ERROR "cannot use _ as value"
+ x := _+1 // ERROR "cannot use _ as value"
}
diff --git a/test/chan/fifo.go b/test/chan/fifo.go
index 00a297a60..0dddfcaa0 100644
--- a/test/chan/fifo.go
+++ b/test/chan/fifo.go
@@ -13,20 +13,20 @@ import "os"
const N = 10
func AsynchFifo() {
- ch := make(chan int, N);
+ ch := make(chan int, N)
for i := 0; i < N; i++ {
ch <- i
}
for i := 0; i < N; i++ {
if <-ch != i {
- print("bad receive\n");
- os.Exit(1);
+ print("bad receive\n")
+ os.Exit(1)
}
}
}
func Chain(ch <-chan int, val int, in <-chan int, out chan<- int) {
- <-in;
+ <-in
if <-ch != val {
panic(val)
}
@@ -35,15 +35,15 @@ func Chain(ch <-chan int, val int, in <-chan int, out chan<- int) {
// thread together a daisy chain to read the elements in sequence
func SynchFifo() {
- ch := make(chan int);
- in := make(chan int);
- start := in;
+ ch := make(chan int)
+ in := make(chan int)
+ start := in
for i := 0; i < N; i++ {
- out := make(chan int);
- go Chain(ch, i, in, out);
- in = out;
+ out := make(chan int)
+ go Chain(ch, i, in, out)
+ in = out
}
- start <- 0;
+ start <- 0
for i := 0; i < N; i++ {
ch <- i
}
@@ -51,7 +51,7 @@ func SynchFifo() {
}
func main() {
- AsynchFifo();
- SynchFifo();
+ AsynchFifo()
+ SynchFifo()
}
diff --git a/test/chan/goroutines.go b/test/chan/goroutines.go
index cee8a18ac..d8f8803df 100644
--- a/test/chan/goroutines.go
+++ b/test/chan/goroutines.go
@@ -10,32 +10,32 @@
package main
import (
- "os";
- "strconv";
+ "os"
+ "strconv"
)
func f(left, right chan int) {
- left <- <-right;
+ left <- <-right
}
func main() {
- var n = 10000;
+ var n = 10000
if len(os.Args) > 1 {
- var err os.Error;
- n, err = strconv.Atoi(os.Args[1]);
+ var err os.Error
+ n, err = strconv.Atoi(os.Args[1])
if err != nil {
- print("bad arg\n");
- os.Exit(1);
+ print("bad arg\n")
+ os.Exit(1)
}
}
- leftmost := make(chan int);
- right := leftmost;
- left := leftmost;
+ leftmost := make(chan int)
+ right := leftmost
+ left := leftmost
for i := 0; i < n; i++ {
- right = make(chan int);
- go f(left, right);
- left = right;
+ right = make(chan int)
+ go f(left, right)
+ left = right
}
- go func(c chan int) { c <- 1 }(right);
- <-leftmost;
+ go func(c chan int) { c <- 1 }(right)
+ <-leftmost
}
diff --git a/test/chan/nonblock.go b/test/chan/nonblock.go
index 2bc5b6cb2..52f04bfb1 100644
--- a/test/chan/nonblock.go
+++ b/test/chan/nonblock.go
@@ -69,6 +69,8 @@ func sleep() {
runtime.Gosched()
}
+const maxTries = 10000 // Up to 100ms per test.
+
func main() {
var i32 int32
var i64 int64
@@ -105,24 +107,29 @@ func main() {
}
go i32receiver(c32, sync)
- sleep()
- ok = c32 <- 123
- if !ok {
- println("i32receiver buffer=", buffer)
- panic("fail")
+ try := 0
+ for !(c32 <- 123) {
+ try++
+ if try > maxTries {
+ println("i32receiver buffer=", buffer)
+ panic("fail")
+ }
+ sleep()
}
<-sync
go i32sender(c32, sync)
if buffer > 0 {
<-sync
- } else {
- sleep()
}
- i32, ok = <-c32
- if !ok {
- println("i32sender buffer=", buffer)
- panic("fail")
+ try = 0
+ for i32, ok = <-c32; !ok; i32, ok = <-c32 {
+ try++
+ if try > maxTries {
+ println("i32sender buffer=", buffer)
+ panic("fail")
+ }
+ sleep()
}
if i32 != 234 {
panic("i32sender value")
@@ -132,22 +139,27 @@ func main() {
}
go i64receiver(c64, sync)
- sleep()
- ok = c64 <- 123456
- if !ok {
- panic("i64receiver")
+ try = 0
+ for !(c64 <- 123456) {
+ try++
+ if try > maxTries {
+ panic("i64receiver")
+ }
+ sleep()
}
<-sync
go i64sender(c64, sync)
if buffer > 0 {
<-sync
- } else {
- sleep()
}
- i64, ok = <-c64
- if !ok {
- panic("i64sender")
+ try = 0
+ for i64, ok = <-c64; !ok; i64, ok = <-c64 {
+ try++
+ if try > maxTries {
+ panic("i64sender")
+ }
+ sleep()
}
if i64 != 234567 {
panic("i64sender value")
@@ -157,22 +169,27 @@ func main() {
}
go breceiver(cb, sync)
- sleep()
- ok = cb <- true
- if !ok {
- panic("breceiver")
+ try = 0
+ for !(cb <- true) {
+ try++
+ if try > maxTries {
+ panic("breceiver")
+ }
+ sleep()
}
<-sync
go bsender(cb, sync)
if buffer > 0 {
<-sync
- } else {
- sleep()
}
- b, ok = <-cb
- if !ok {
- panic("bsender")
+ try = 0
+ for b, ok = <-cb; !ok; b, ok = <-cb {
+ try++
+ if try > maxTries {
+ panic("bsender")
+ }
+ sleep()
}
if !b {
panic("bsender value")
@@ -182,22 +199,27 @@ func main() {
}
go sreceiver(cs, sync)
- sleep()
- ok = cs <- "hello"
- if !ok {
- panic("sreceiver")
+ try = 0
+ for !(cs <- "hello") {
+ try++
+ if try > maxTries {
+ panic("sreceiver")
+ }
+ sleep()
}
<-sync
go ssender(cs, sync)
if buffer > 0 {
<-sync
- } else {
- sleep()
}
- s, ok = <-cs
- if !ok {
- panic("ssender")
+ try = 0
+ for s, ok = <-cs; !ok; s, ok = <-cs {
+ try++
+ if try > maxTries {
+ panic("ssender")
+ }
+ sleep()
}
if s != "hello again" {
panic("ssender value")
diff --git a/test/chan/perm.go b/test/chan/perm.go
index 502e787a5..d08c03519 100644
--- a/test/chan/perm.go
+++ b/test/chan/perm.go
@@ -7,51 +7,51 @@
package main
var (
- cr <-chan int;
- cs chan<- int;
- c chan int;
+ cr <-chan int
+ cs chan<- int
+ c chan int
)
func main() {
- cr = c; // ok
- cs = c; // ok
- c = cr; // ERROR "illegal types|incompatible|cannot"
- c = cs; // ERROR "illegal types|incompatible|cannot"
- cr = cs; // ERROR "illegal types|incompatible|cannot"
- cs = cr; // ERROR "illegal types|incompatible|cannot"
-
- c <- 0; // ok
- ok := c <- 0; // ok
- _ = ok;
- <-c; // ok
- x, ok := <-c; // ok
- _, _ = x, ok;
-
- cr <- 0; // ERROR "send"
- ok = cr <- 0; // ERROR "send"
- _ = ok;
- <-cr; // ok
- x, ok = <-cr; // ok
- _, _ = x, ok;
-
- cs <- 0; // ok
- ok = cs <- 0; // ok
- _ = ok;
- <-cs; // ERROR "receive"
- x, ok = <-cs; // ERROR "receive"
- _, _ = x, ok;
+ cr = c // ok
+ cs = c // ok
+ c = cr // ERROR "illegal types|incompatible|cannot"
+ c = cs // ERROR "illegal types|incompatible|cannot"
+ cr = cs // ERROR "illegal types|incompatible|cannot"
+ cs = cr // ERROR "illegal types|incompatible|cannot"
+
+ c <- 0 // ok
+ ok := c <- 0 // ok
+ _ = ok
+ <-c // ok
+ x, ok := <-c // ok
+ _, _ = x, ok
+
+ cr <- 0 // ERROR "send"
+ ok = cr <- 0 // ERROR "send"
+ _ = ok
+ <-cr // ok
+ x, ok = <-cr // ok
+ _, _ = x, ok
+
+ cs <- 0 // ok
+ ok = cs <- 0 // ok
+ _ = ok
+ <-cs // ERROR "receive"
+ x, ok = <-cs // ERROR "receive"
+ _, _ = x, ok
select {
case c <- 0: // ok
case x := <-c: // ok
- _ = x;
+ _ = x
case cr <- 0: // ERROR "send"
case x := <-cr: // ok
- _ = x;
+ _ = x
- case cs <- 0: // ok;
+ case cs <- 0: // ok
case x := <-cs: // ERROR "receive"
- _ = x;
+ _ = x
}
}
diff --git a/test/chan/powser1.go b/test/chan/powser1.go
index bb36b1594..dc4ff5325 100644
--- a/test/chan/powser1.go
+++ b/test/chan/powser1.go
@@ -16,7 +16,7 @@ package main
import "os"
type rat struct {
- num, den int64; // numerator, denominator
+ num, den int64 // numerator, denominator
}
func (u rat) pr() {
@@ -33,9 +33,9 @@ func (u rat) eq(c rat) bool {
}
type dch struct {
- req chan int;
- dat chan rat;
- nam int;
+ req chan int
+ dat chan rat
+ nam int
}
type dch2 [2] *dch
@@ -45,20 +45,20 @@ var chnameserial int
var seqno int
func mkdch() *dch {
- c := chnameserial % len(chnames);
- chnameserial++;
- d := new(dch);
- d.req = make(chan int);
- d.dat = make(chan rat);
- d.nam = c;
- return d;
+ c := chnameserial % len(chnames)
+ chnameserial++
+ d := new(dch)
+ d.req = make(chan int)
+ d.dat = make(chan rat)
+ d.nam = c
+ return d
}
func mkdch2() *dch2 {
- d2 := new(dch2);
- d2[0] = mkdch();
- d2[1] = mkdch();
- return d2;
+ d2 := new(dch2)
+ d2[0] = mkdch()
+ d2[1] = mkdch()
+ return d2
}
// split reads a single demand channel and replicates its
@@ -76,98 +76,97 @@ func mkdch2() *dch2 {
// generation to begin servicing out[1].
func dosplit(in *dch, out *dch2, wait chan int ) {
- var t *dch;
- both := false; // do not service both channels
+ both := false // do not service both channels
select {
case <-out[0].req:
- ;
+
case <-wait:
- both = true;
+ both = true
select {
case <-out[0].req:
- ;
+
case <-out[1].req:
- t=out[0]; out[0]=out[1]; out[1]=t;
+ out[0], out[1] = out[1], out[0]
}
}
- seqno++;
- in.req <- seqno;
- release := make(chan int);
- go dosplit(in, out, release);
- dat := <-in.dat;
- out[0].dat <- dat;
+ seqno++
+ in.req <- seqno
+ release := make(chan int)
+ go dosplit(in, out, release)
+ dat := <-in.dat
+ out[0].dat <- dat
if !both {
<-wait
}
- <-out[1].req;
- out[1].dat <- dat;
- release <- 0;
+ <-out[1].req
+ out[1].dat <- dat
+ release <- 0
}
func split(in *dch, out *dch2) {
- release := make(chan int);
- go dosplit(in, out, release);
- release <- 0;
+ release := make(chan int)
+ go dosplit(in, out, release)
+ release <- 0
}
func put(dat rat, out *dch) {
- <-out.req;
- out.dat <- dat;
+ <-out.req
+ out.dat <- dat
}
func get(in *dch) rat {
- seqno++;
- in.req <- seqno;
- return <-in.dat;
+ seqno++
+ in.req <- seqno
+ return <-in.dat
}
// Get one rat from each of n demand channels
func getn(in []*dch) []rat {
- n := len(in);
- if n != 2 { panic("bad n in getn") };
- req := new([2] chan int);
- dat := new([2] chan rat);
- out := make([]rat, 2);
- var i int;
- var it rat;
+ n := len(in)
+ if n != 2 { panic("bad n in getn") }
+ req := new([2] chan int)
+ dat := new([2] chan rat)
+ out := make([]rat, 2)
+ var i int
+ var it rat
for i=0; i<n; i++ {
- req[i] = in[i].req;
- dat[i] = nil;
+ req[i] = in[i].req
+ dat[i] = nil
}
for n=2*n; n>0; n-- {
- seqno++;
+ seqno++
select {
case req[0] <- seqno:
- dat[0] = in[0].dat;
- req[0] = nil;
+ dat[0] = in[0].dat
+ req[0] = nil
case req[1] <- seqno:
- dat[1] = in[1].dat;
- req[1] = nil;
+ dat[1] = in[1].dat
+ req[1] = nil
case it = <-dat[0]:
- out[0] = it;
- dat[0] = nil;
+ out[0] = it
+ dat[0] = nil
case it = <-dat[1]:
- out[1] = it;
- dat[1] = nil;
+ out[1] = it
+ dat[1] = nil
}
}
- return out;
+ return out
}
// Get one rat from each of 2 demand channels
func get2(in0 *dch, in1 *dch) []rat {
- return getn([]*dch{in0, in1});
+ return getn([]*dch{in0, in1})
}
func copy(in *dch, out *dch) {
for {
- <-out.req;
- out.dat <- get(in);
+ <-out.req
+ out.dat <- get(in)
}
}
@@ -177,8 +176,8 @@ func repeat(dat rat, out *dch) {
}
}
-type PS *dch; // power series
-type PS2 *[2] PS; // pair of power series
+type PS *dch // power series
+type PS2 *[2] PS // pair of power series
var Ones PS
var Twos PS
@@ -208,29 +207,29 @@ func gcd (u, v int64) int64 {
// Make a rational from two ints and from one int
func i2tor(u, v int64) rat {
- g := gcd(u,v);
- var r rat;
+ g := gcd(u,v)
+ var r rat
if v > 0 {
- r.num = u/g;
- r.den = v/g;
+ r.num = u/g
+ r.den = v/g
} else {
- r.num = -u/g;
- r.den = -v/g;
+ r.num = -u/g
+ r.den = -v/g
}
- return r;
+ return r
}
func itor(u int64) rat {
- return i2tor(u, 1);
+ return i2tor(u, 1)
}
-var zero rat;
-var one rat;
+var zero rat
+var one rat
// End mark and end test
-var finis rat;
+var finis rat
func end(u rat) int64 {
if u.den==0 { return 1 }
@@ -240,68 +239,68 @@ func end(u rat) int64 {
// Operations on rationals
func add(u, v rat) rat {
- g := gcd(u.den,v.den);
- return i2tor(u.num*(v.den/g)+v.num*(u.den/g),u.den*(v.den/g));
+ g := gcd(u.den,v.den)
+ return i2tor(u.num*(v.den/g)+v.num*(u.den/g),u.den*(v.den/g))
}
func mul(u, v rat) rat {
- g1 := gcd(u.num,v.den);
- g2 := gcd(u.den,v.num);
- var r rat;
- r.num = (u.num/g1)*(v.num/g2);
- r.den = (u.den/g2)*(v.den/g1);
- return r;
+ g1 := gcd(u.num,v.den)
+ g2 := gcd(u.den,v.num)
+ var r rat
+ r.num = (u.num/g1)*(v.num/g2)
+ r.den = (u.den/g2)*(v.den/g1)
+ return r
}
func neg(u rat) rat {
- return i2tor(-u.num, u.den);
+ return i2tor(-u.num, u.den)
}
func sub(u, v rat) rat {
- return add(u, neg(v));
+ return add(u, neg(v))
}
func inv(u rat) rat { // invert a rat
if u.num == 0 { panic("zero divide in inv") }
- return i2tor(u.den, u.num);
+ return i2tor(u.den, u.num)
}
// print eval in floating point of PS at x=c to n terms
func evaln(c rat, U PS, n int) {
- xn := float64(1);
- x := float64(c.num)/float64(c.den);
- val := float64(0);
+ xn := float64(1)
+ x := float64(c.num)/float64(c.den)
+ val := float64(0)
for i:=0; i<n; i++ {
- u := get(U);
+ u := get(U)
if end(u) != 0 {
- break;
+ break
}
- val = val + x * float64(u.num)/float64(u.den);
- xn = xn*x;
+ val = val + x * float64(u.num)/float64(u.den)
+ xn = xn*x
}
- print(val, "\n");
+ print(val, "\n")
}
// Print n terms of a power series
func printn(U PS, n int) {
- done := false;
+ done := false
for ; !done && n>0; n-- {
- u := get(U);
+ u := get(U)
if end(u) != 0 {
done = true
} else {
u.pr()
}
}
- print(("\n"));
+ print(("\n"))
}
// Evaluate n terms of power series U at x=c
func eval(c rat, U PS, n int) rat {
if n==0 { return zero }
- y := get(U);
+ y := get(U)
if end(y) != 0 { return zero }
- return add(y,mul(c,eval(c,U,n-1)));
+ return add(y,mul(c,eval(c,U,n-1)))
}
// Power-series constructors return channels on which power
@@ -311,105 +310,105 @@ func eval(c rat, U PS, n int) rat {
// Make a pair of power series identical to a given power series
func Split(U PS) *dch2 {
- UU := mkdch2();
- go split(U,UU);
- return UU;
+ UU := mkdch2()
+ go split(U,UU)
+ return UU
}
// Add two power series
func Add(U, V PS) PS {
- Z := mkPS();
+ Z := mkPS()
go func() {
- var uv []rat;
+ var uv []rat
for {
- <-Z.req;
- uv = get2(U,V);
+ <-Z.req
+ uv = get2(U,V)
switch end(uv[0])+2*end(uv[1]) {
case 0:
- Z.dat <- add(uv[0], uv[1]);
+ Z.dat <- add(uv[0], uv[1])
case 1:
- Z.dat <- uv[1];
- copy(V,Z);
+ Z.dat <- uv[1]
+ copy(V,Z)
case 2:
- Z.dat <- uv[0];
- copy(U,Z);
+ Z.dat <- uv[0]
+ copy(U,Z)
case 3:
- Z.dat <- finis;
+ Z.dat <- finis
}
}
- }();
- return Z;
+ }()
+ return Z
}
// Multiply a power series by a constant
func Cmul(c rat,U PS) PS {
- Z := mkPS();
+ Z := mkPS()
go func() {
- done := false;
+ done := false
for !done {
- <-Z.req;
- u := get(U);
+ <-Z.req
+ u := get(U)
if end(u) != 0 {
done = true
} else {
Z.dat <- mul(c,u)
}
}
- Z.dat <- finis;
- }();
- return Z;
+ Z.dat <- finis
+ }()
+ return Z
}
// Subtract
func Sub(U, V PS) PS {
- return Add(U, Cmul(neg(one), V));
+ return Add(U, Cmul(neg(one), V))
}
// Multiply a power series by the monomial x^n
func Monmul(U PS, n int) PS {
- Z := mkPS();
+ Z := mkPS()
go func() {
for ; n>0; n-- { put(zero,Z) }
- copy(U,Z);
- }();
- return Z;
+ copy(U,Z)
+ }()
+ return Z
}
// Multiply by x
func Xmul(U PS) PS {
- return Monmul(U,1);
+ return Monmul(U,1)
}
func Rep(c rat) PS {
- Z := mkPS();
- go repeat(c,Z);
- return Z;
+ Z := mkPS()
+ go repeat(c,Z)
+ return Z
}
// Monomial c*x^n
func Mon(c rat, n int) PS {
- Z:=mkPS();
+ Z:=mkPS()
go func() {
if(c.num!=0) {
for ; n>0; n=n-1 { put(zero,Z) }
- put(c,Z);
+ put(c,Z)
}
- put(finis,Z);
- }();
- return Z;
+ put(finis,Z)
+ }()
+ return Z
}
func Shift(c rat, U PS) PS {
- Z := mkPS();
+ Z := mkPS()
go func() {
- put(c,Z);
- copy(U,Z);
- }();
- return Z;
+ put(c,Z)
+ copy(U,Z)
+ }()
+ return Z
}
// simple pole at 1: 1/(1-x) = 1 1 1 1 1 ...
@@ -419,17 +418,17 @@ func Shift(c rat, U PS) PS {
/*
func Poly(a []rat) PS {
- Z:=mkPS();
+ Z:=mkPS()
begin func(a []rat, Z PS) {
- j:=0;
- done:=0;
+ j:=0
+ done:=0
for j=len(a); !done&&j>0; j=j-1)
- if(a[j-1].num!=0) done=1;
- i:=0;
- for(; i<j; i=i+1) put(a[i],Z);
- put(finis,Z);
- }();
- return Z;
+ if(a[j-1].num!=0) done=1
+ i:=0
+ for(; i<j; i=i+1) put(a[i],Z)
+ put(finis,Z)
+ }()
+ return Z
}
*/
@@ -439,82 +438,82 @@ func Poly(a []rat) PS {
// then UV = u*v + x*(u*VV+v*UU) + x*x*UU*VV
func Mul(U, V PS) PS {
- Z:=mkPS();
+ Z:=mkPS()
go func() {
- <-Z.req;
- uv := get2(U,V);
+ <-Z.req
+ uv := get2(U,V)
if end(uv[0])!=0 || end(uv[1]) != 0 {
- Z.dat <- finis;
+ Z.dat <- finis
} else {
- Z.dat <- mul(uv[0],uv[1]);
- UU := Split(U);
- VV := Split(V);
- W := Add(Cmul(uv[0],VV[0]),Cmul(uv[1],UU[0]));
- <-Z.req;
- Z.dat <- get(W);
- copy(Add(W,Mul(UU[1],VV[1])),Z);
+ Z.dat <- mul(uv[0],uv[1])
+ UU := Split(U)
+ VV := Split(V)
+ W := Add(Cmul(uv[0],VV[0]),Cmul(uv[1],UU[0]))
+ <-Z.req
+ Z.dat <- get(W)
+ copy(Add(W,Mul(UU[1],VV[1])),Z)
}
- }();
- return Z;
+ }()
+ return Z
}
// Differentiate
func Diff(U PS) PS {
- Z:=mkPS();
+ Z:=mkPS()
go func() {
- <-Z.req;
- u := get(U);
+ <-Z.req
+ u := get(U)
if end(u) == 0 {
- done:=false;
+ done:=false
for i:=1; !done; i++ {
- u = get(U);
+ u = get(U)
if end(u) != 0 {
done = true
} else {
- Z.dat <- mul(itor(int64(i)),u);
- <-Z.req;
+ Z.dat <- mul(itor(int64(i)),u)
+ <-Z.req
}
}
}
- Z.dat <- finis;
- }();
- return Z;
+ Z.dat <- finis
+ }()
+ return Z
}
// Integrate, with const of integration
func Integ(c rat,U PS) PS {
- Z:=mkPS();
+ Z:=mkPS()
go func() {
- put(c,Z);
- done:=false;
+ put(c,Z)
+ done:=false
for i:=1; !done; i++ {
- <-Z.req;
- u := get(U);
+ <-Z.req
+ u := get(U)
if end(u) != 0 { done= true }
- Z.dat <- mul(i2tor(1,int64(i)),u);
+ Z.dat <- mul(i2tor(1,int64(i)),u)
}
- Z.dat <- finis;
- }();
- return Z;
+ Z.dat <- finis
+ }()
+ return Z
}
// Binomial theorem (1+x)^c
func Binom(c rat) PS {
- Z:=mkPS();
+ Z:=mkPS()
go func() {
- n := 1;
- t := itor(1);
+ n := 1
+ t := itor(1)
for c.num!=0 {
- put(t,Z);
- t = mul(mul(t,c),i2tor(1,int64(n)));
- c = sub(c,one);
- n++;
+ put(t,Z)
+ t = mul(mul(t,c),i2tor(1,int64(n)))
+ c = sub(c,one)
+ n++
}
- put(finis,Z);
- }();
- return Z;
+ put(finis,Z)
+ }()
+ return Z
}
// Reciprocal of a power series
@@ -523,19 +522,19 @@ func Binom(c rat) PS {
// (u+x*UU)*(z+x*ZZ) = 1
// z = 1/u
// u*ZZ + z*UU +x*UU*ZZ = 0
-// ZZ = -UU*(z+x*ZZ)/u;
+// ZZ = -UU*(z+x*ZZ)/u
func Recip(U PS) PS {
- Z:=mkPS();
+ Z:=mkPS()
go func() {
- ZZ:=mkPS2();
- <-Z.req;
- z := inv(get(U));
- Z.dat <- z;
- split(Mul(Cmul(neg(z),U),Shift(z,ZZ[0])),ZZ);
- copy(ZZ[1],Z);
- }();
- return Z;
+ ZZ:=mkPS2()
+ <-Z.req
+ z := inv(get(U))
+ Z.dat <- z
+ split(Mul(Cmul(neg(z),U),Shift(z,ZZ[0])),ZZ)
+ copy(ZZ[1],Z)
+ }()
+ return Z
}
// Exponential of a power series with constant term 0
@@ -546,9 +545,9 @@ func Recip(U PS) PS {
// integrate to get Z
func Exp(U PS) PS {
- ZZ := mkPS2();
- split(Integ(one,Mul(ZZ[0],Diff(U))),ZZ);
- return ZZ[1];
+ ZZ := mkPS2()
+ split(Integ(one,Mul(ZZ[0],Diff(U))),ZZ)
+ return ZZ[1]
}
// Substitute V for x in U, where the leading term of V is zero
@@ -558,69 +557,69 @@ func Exp(U PS) PS {
// bug: a nonzero constant term is ignored
func Subst(U, V PS) PS {
- Z:= mkPS();
+ Z:= mkPS()
go func() {
- VV := Split(V);
- <-Z.req;
- u := get(U);
- Z.dat <- u;
+ VV := Split(V)
+ <-Z.req
+ u := get(U)
+ Z.dat <- u
if end(u) == 0 {
if end(get(VV[0])) != 0 {
- put(finis,Z);
+ put(finis,Z)
} else {
- copy(Mul(VV[0],Subst(U,VV[1])),Z);
+ copy(Mul(VV[0],Subst(U,VV[1])),Z)
}
}
- }();
- return Z;
+ }()
+ return Z
}
// Monomial Substition: U(c x^n)
// Each Ui is multiplied by c^i and followed by n-1 zeros
func MonSubst(U PS, c0 rat, n int) PS {
- Z:= mkPS();
+ Z:= mkPS()
go func() {
- c := one;
+ c := one
for {
- <-Z.req;
- u := get(U);
- Z.dat <- mul(u, c);
- c = mul(c, c0);
+ <-Z.req
+ u := get(U)
+ Z.dat <- mul(u, c)
+ c = mul(c, c0)
if end(u) != 0 {
- Z.dat <- finis;
- break;
+ Z.dat <- finis
+ break
}
for i := 1; i < n; i++ {
- <-Z.req;
- Z.dat <- zero;
+ <-Z.req
+ Z.dat <- zero
}
}
- }();
- return Z;
+ }()
+ return Z
}
func Init() {
- chnameserial = -1;
- seqno = 0;
- chnames = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
- zero = itor(0);
- one = itor(1);
- finis = i2tor(1,0);
- Ones = Rep(one);
- Twos = Rep(itor(2));
+ chnameserial = -1
+ seqno = 0
+ chnames = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
+ zero = itor(0)
+ one = itor(1)
+ finis = i2tor(1,0)
+ Ones = Rep(one)
+ Twos = Rep(itor(2))
}
func check(U PS, c rat, count int, str string) {
for i := 0; i < count; i++ {
- r := get(U);
+ r := get(U)
if !r.eq(c) {
- print("got: ");
- r.pr();
- print("should get ");
- c.pr();
- print("\n");
+ print("got: ")
+ r.pr()
+ print("should get ")
+ c.pr()
+ print("\n")
panic(str)
}
}
@@ -629,82 +628,82 @@ func check(U PS, c rat, count int, str string) {
const N=10
func checka(U PS, a []rat, str string) {
for i := 0; i < N; i++ {
- check(U, a[i], 1, str);
+ check(U, a[i], 1, str)
}
}
func main() {
- Init();
+ Init()
if len(os.Args) > 1 { // print
- print("Ones: "); printn(Ones, 10);
- print("Twos: "); printn(Twos, 10);
- print("Add: "); printn(Add(Ones, Twos), 10);
- print("Diff: "); printn(Diff(Ones), 10);
- print("Integ: "); printn(Integ(zero, Ones), 10);
- print("CMul: "); printn(Cmul(neg(one), Ones), 10);
- print("Sub: "); printn(Sub(Ones, Twos), 10);
- print("Mul: "); printn(Mul(Ones, Ones), 10);
- print("Exp: "); printn(Exp(Ones), 15);
- print("MonSubst: "); printn(MonSubst(Ones, neg(one), 2), 10);
- print("ATan: "); printn(Integ(zero, MonSubst(Ones, neg(one), 2)), 10);
+ print("Ones: "); printn(Ones, 10)
+ print("Twos: "); printn(Twos, 10)
+ print("Add: "); printn(Add(Ones, Twos), 10)
+ print("Diff: "); printn(Diff(Ones), 10)
+ print("Integ: "); printn(Integ(zero, Ones), 10)
+ print("CMul: "); printn(Cmul(neg(one), Ones), 10)
+ print("Sub: "); printn(Sub(Ones, Twos), 10)
+ print("Mul: "); printn(Mul(Ones, Ones), 10)
+ print("Exp: "); printn(Exp(Ones), 15)
+ print("MonSubst: "); printn(MonSubst(Ones, neg(one), 2), 10)
+ print("ATan: "); printn(Integ(zero, MonSubst(Ones, neg(one), 2)), 10)
} else { // test
- check(Ones, one, 5, "Ones");
- check(Add(Ones, Ones), itor(2), 0, "Add Ones Ones"); // 1 1 1 1 1
- check(Add(Ones, Twos), itor(3), 0, "Add Ones Twos"); // 3 3 3 3 3
- a := make([]rat, N);
- d := Diff(Ones);
+ check(Ones, one, 5, "Ones")
+ check(Add(Ones, Ones), itor(2), 0, "Add Ones Ones") // 1 1 1 1 1
+ check(Add(Ones, Twos), itor(3), 0, "Add Ones Twos") // 3 3 3 3 3
+ a := make([]rat, N)
+ d := Diff(Ones)
for i:=0; i < N; i++ {
a[i] = itor(int64(i+1))
}
- checka(d, a, "Diff"); // 1 2 3 4 5
- in := Integ(zero, Ones);
- a[0] = zero; // integration constant
+ checka(d, a, "Diff") // 1 2 3 4 5
+ in := Integ(zero, Ones)
+ a[0] = zero // integration constant
for i:=1; i < N; i++ {
a[i] = i2tor(1, int64(i))
}
- checka(in, a, "Integ"); // 0 1 1/2 1/3 1/4 1/5
- check(Cmul(neg(one), Twos), itor(-2), 10, "CMul"); // -1 -1 -1 -1 -1
- check(Sub(Ones, Twos), itor(-1), 0, "Sub Ones Twos"); // -1 -1 -1 -1 -1
- m := Mul(Ones, Ones);
+ checka(in, a, "Integ") // 0 1 1/2 1/3 1/4 1/5
+ check(Cmul(neg(one), Twos), itor(-2), 10, "CMul") // -1 -1 -1 -1 -1
+ check(Sub(Ones, Twos), itor(-1), 0, "Sub Ones Twos") // -1 -1 -1 -1 -1
+ m := Mul(Ones, Ones)
for i:=0; i < N; i++ {
a[i] = itor(int64(i+1))
}
- checka(m, a, "Mul"); // 1 2 3 4 5
- e := Exp(Ones);
- a[0] = itor(1);
- a[1] = itor(1);
- a[2] = i2tor(3,2);
- a[3] = i2tor(13,6);
- a[4] = i2tor(73,24);
- a[5] = i2tor(167,40);
- a[6] = i2tor(4051,720);
- a[7] = i2tor(37633,5040);
- a[8] = i2tor(43817,4480);
- a[9] = i2tor(4596553,362880);
- checka(e, a, "Exp"); // 1 1 3/2 13/6 73/24
- at := Integ(zero, MonSubst(Ones, neg(one), 2));
+ checka(m, a, "Mul") // 1 2 3 4 5
+ e := Exp(Ones)
+ a[0] = itor(1)
+ a[1] = itor(1)
+ a[2] = i2tor(3,2)
+ a[3] = i2tor(13,6)
+ a[4] = i2tor(73,24)
+ a[5] = i2tor(167,40)
+ a[6] = i2tor(4051,720)
+ a[7] = i2tor(37633,5040)
+ a[8] = i2tor(43817,4480)
+ a[9] = i2tor(4596553,362880)
+ checka(e, a, "Exp") // 1 1 3/2 13/6 73/24
+ at := Integ(zero, MonSubst(Ones, neg(one), 2))
for c, i := 1, 0; i < N; i++ {
if i%2 == 0 {
a[i] = zero
} else {
- a[i] = i2tor(int64(c), int64(i));
+ a[i] = i2tor(int64(c), int64(i))
c *= -1
}
}
- checka(at, a, "ATan"); // 0 -1 0 -1/3 0 -1/5
+ checka(at, a, "ATan") // 0 -1 0 -1/3 0 -1/5
/*
- t := Revert(Integ(zero, MonSubst(Ones, neg(one), 2)));
- a[0] = zero;
- a[1] = itor(1);
- a[2] = zero;
- a[3] = i2tor(1,3);
- a[4] = zero;
- a[5] = i2tor(2,15);
- a[6] = zero;
- a[7] = i2tor(17,315);
- a[8] = zero;
- a[9] = i2tor(62,2835);
- checka(t, a, "Tan"); // 0 1 0 1/3 0 2/15
+ t := Revert(Integ(zero, MonSubst(Ones, neg(one), 2)))
+ a[0] = zero
+ a[1] = itor(1)
+ a[2] = zero
+ a[3] = i2tor(1,3)
+ a[4] = zero
+ a[5] = i2tor(2,15)
+ a[6] = zero
+ a[7] = i2tor(17,315)
+ a[8] = zero
+ a[9] = i2tor(62,2835)
+ checka(t, a, "Tan") // 0 1 0 1/3 0 2/15
*/
}
}
diff --git a/test/chan/powser2.go b/test/chan/powser2.go
index 0c523ac99..bc329270d 100644
--- a/test/chan/powser2.go
+++ b/test/chan/powser2.go
@@ -19,12 +19,12 @@ package main
import "os"
type rat struct {
- num, den int64; // numerator, denominator
+ num, den int64 // numerator, denominator
}
type item interface {
- pr();
- eq(c item) bool;
+ pr()
+ eq(c item) bool
}
func (u *rat) pr(){
@@ -37,14 +37,14 @@ func (u *rat) pr(){
}
func (u *rat) eq(c item) bool {
- c1 := c.(*rat);
+ c1 := c.(*rat)
return u.num == c1.num && u.den == c1.den
}
type dch struct {
- req chan int;
- dat chan item;
- nam int;
+ req chan int
+ dat chan item
+ nam int
}
type dch2 [2] *dch
@@ -54,20 +54,20 @@ var chnameserial int
var seqno int
func mkdch() *dch {
- c := chnameserial % len(chnames);
- chnameserial++;
- d := new(dch);
- d.req = make(chan int);
- d.dat = make(chan item);
- d.nam = c;
- return d;
+ c := chnameserial % len(chnames)
+ chnameserial++
+ d := new(dch)
+ d.req = make(chan int)
+ d.dat = make(chan item)
+ d.nam = c
+ return d
}
func mkdch2() *dch2 {
- d2 := new(dch2);
- d2[0] = mkdch();
- d2[1] = mkdch();
- return d2;
+ d2 := new(dch2)
+ d2[0] = mkdch()
+ d2[1] = mkdch()
+ return d2
}
// split reads a single demand channel and replicates its
@@ -85,98 +85,97 @@ func mkdch2() *dch2 {
// generation to begin servicing out[1].
func dosplit(in *dch, out *dch2, wait chan int ){
- var t *dch;
- both := false; // do not service both channels
+ both := false // do not service both channels
select {
case <-out[0].req:
- ;
+
case <-wait:
- both = true;
+ both = true
select {
case <-out[0].req:
- ;
+
case <-out[1].req:
- t=out[0]; out[0]=out[1]; out[1]=t;
+ out[0],out[1] = out[1], out[0]
}
}
- seqno++;
- in.req <- seqno;
- release := make(chan int);
- go dosplit(in, out, release);
- dat := <-in.dat;
- out[0].dat <- dat;
+ seqno++
+ in.req <- seqno
+ release := make(chan int)
+ go dosplit(in, out, release)
+ dat := <-in.dat
+ out[0].dat <- dat
if !both {
<-wait
}
- <-out[1].req;
- out[1].dat <- dat;
- release <- 0;
+ <-out[1].req
+ out[1].dat <- dat
+ release <- 0
}
func split(in *dch, out *dch2){
- release := make(chan int);
- go dosplit(in, out, release);
- release <- 0;
+ release := make(chan int)
+ go dosplit(in, out, release)
+ release <- 0
}
func put(dat item, out *dch){
- <-out.req;
- out.dat <- dat;
+ <-out.req
+ out.dat <- dat
}
func get(in *dch) *rat {
- seqno++;
- in.req <- seqno;
- return (<-in.dat).(*rat);
+ seqno++
+ in.req <- seqno
+ return (<-in.dat).(*rat)
}
// Get one item from each of n demand channels
func getn(in []*dch) []item {
- n:=len(in);
- if n != 2 { panic("bad n in getn") };
- req := make([] chan int, 2);
- dat := make([] chan item, 2);
- out := make([]item, 2);
- var i int;
- var it item;
+ n:=len(in)
+ if n != 2 { panic("bad n in getn") }
+ req := make([] chan int, 2)
+ dat := make([] chan item, 2)
+ out := make([]item, 2)
+ var i int
+ var it item
for i=0; i<n; i++ {
- req[i] = in[i].req;
- dat[i] = nil;
+ req[i] = in[i].req
+ dat[i] = nil
}
for n=2*n; n>0; n-- {
- seqno++;
+ seqno++
select{
case req[0] <- seqno:
- dat[0] = in[0].dat;
- req[0] = nil;
+ dat[0] = in[0].dat
+ req[0] = nil
case req[1] <- seqno:
- dat[1] = in[1].dat;
- req[1] = nil;
+ dat[1] = in[1].dat
+ req[1] = nil
case it = <-dat[0]:
- out[0] = it;
- dat[0] = nil;
+ out[0] = it
+ dat[0] = nil
case it = <-dat[1]:
- out[1] = it;
- dat[1] = nil;
+ out[1] = it
+ dat[1] = nil
}
}
- return out;
+ return out
}
// Get one item from each of 2 demand channels
func get2(in0 *dch, in1 *dch) []item {
- return getn([]*dch{in0, in1});
+ return getn([]*dch{in0, in1})
}
func copy(in *dch, out *dch){
for {
- <-out.req;
- out.dat <- get(in);
+ <-out.req
+ out.dat <- get(in)
}
}
@@ -186,8 +185,8 @@ func repeat(dat item, out *dch){
}
}
-type PS *dch; // power series
-type PS2 *[2] PS; // pair of power series
+type PS *dch // power series
+type PS2 *[2] PS // pair of power series
var Ones PS
var Twos PS
@@ -217,29 +216,29 @@ func gcd (u, v int64) int64{
// Make a rational from two ints and from one int
func i2tor(u, v int64) *rat{
- g := gcd(u,v);
- r := new(rat);
+ g := gcd(u,v)
+ r := new(rat)
if v > 0 {
- r.num = u/g;
- r.den = v/g;
+ r.num = u/g
+ r.den = v/g
} else {
- r.num = -u/g;
- r.den = -v/g;
+ r.num = -u/g
+ r.den = -v/g
}
- return r;
+ return r
}
func itor(u int64) *rat{
- return i2tor(u, 1);
+ return i2tor(u, 1)
}
-var zero *rat;
-var one *rat;
+var zero *rat
+var one *rat
// End mark and end test
-var finis *rat;
+var finis *rat
func end(u *rat) int64 {
if u.den==0 { return 1 }
@@ -249,72 +248,72 @@ func end(u *rat) int64 {
// Operations on rationals
func add(u, v *rat) *rat {
- g := gcd(u.den,v.den);
- return i2tor(u.num*(v.den/g)+v.num*(u.den/g),u.den*(v.den/g));
+ g := gcd(u.den,v.den)
+ return i2tor(u.num*(v.den/g)+v.num*(u.den/g),u.den*(v.den/g))
}
func mul(u, v *rat) *rat{
- g1 := gcd(u.num,v.den);
- g2 := gcd(u.den,v.num);
- r := new(rat);
- r.num =(u.num/g1)*(v.num/g2);
- r.den = (u.den/g2)*(v.den/g1);
- return r;
+ g1 := gcd(u.num,v.den)
+ g2 := gcd(u.den,v.num)
+ r := new(rat)
+ r.num =(u.num/g1)*(v.num/g2)
+ r.den = (u.den/g2)*(v.den/g1)
+ return r
}
func neg(u *rat) *rat{
- return i2tor(-u.num, u.den);
+ return i2tor(-u.num, u.den)
}
func sub(u, v *rat) *rat{
- return add(u, neg(v));
+ return add(u, neg(v))
}
func inv(u *rat) *rat{ // invert a rat
if u.num == 0 { panic("zero divide in inv") }
- return i2tor(u.den, u.num);
+ return i2tor(u.den, u.num)
}
// print eval in floating point of PS at x=c to n terms
func Evaln(c *rat, U PS, n int) {
- xn := float64(1);
- x := float64(c.num)/float64(c.den);
- val := float64(0);
+ xn := float64(1)
+ x := float64(c.num)/float64(c.den)
+ val := float64(0)
for i:=0; i<n; i++ {
- u := get(U);
+ u := get(U)
if end(u) != 0 {
- break;
+ break
}
- val = val + x * float64(u.num)/float64(u.den);
- xn = xn*x;
+ val = val + x * float64(u.num)/float64(u.den)
+ xn = xn*x
}
- print(val, "\n");
+ print(val, "\n")
}
// Print n terms of a power series
func Printn(U PS, n int){
- done := false;
+ done := false
for ; !done && n>0; n-- {
- u := get(U);
+ u := get(U)
if end(u) != 0 {
done = true
} else {
u.pr()
}
}
- print(("\n"));
+ print(("\n"))
}
func Print(U PS){
- Printn(U,1000000000);
+ Printn(U,1000000000)
}
// Evaluate n terms of power series U at x=c
func eval(c *rat, U PS, n int) *rat{
if n==0 { return zero }
- y := get(U);
+ y := get(U)
if end(y) != 0 { return zero }
- return add(y,mul(c,eval(c,U,n-1)));
+ return add(y,mul(c,eval(c,U,n-1)))
}
// Power-series constructors return channels on which power
@@ -324,105 +323,105 @@ func eval(c *rat, U PS, n int) *rat{
// Make a pair of power series identical to a given power series
func Split(U PS) *dch2{
- UU := mkdch2();
- go split(U,UU);
- return UU;
+ UU := mkdch2()
+ go split(U,UU)
+ return UU
}
// Add two power series
func Add(U, V PS) PS{
- Z := mkPS();
+ Z := mkPS()
go func(U, V, Z PS){
- var uv [] item;
+ var uv [] item
for {
- <-Z.req;
- uv = get2(U,V);
+ <-Z.req
+ uv = get2(U,V)
switch end(uv[0].(*rat))+2*end(uv[1].(*rat)) {
case 0:
- Z.dat <- add(uv[0].(*rat), uv[1].(*rat));
+ Z.dat <- add(uv[0].(*rat), uv[1].(*rat))
case 1:
- Z.dat <- uv[1];
- copy(V,Z);
+ Z.dat <- uv[1]
+ copy(V,Z)
case 2:
- Z.dat <- uv[0];
- copy(U,Z);
+ Z.dat <- uv[0]
+ copy(U,Z)
case 3:
- Z.dat <- finis;
+ Z.dat <- finis
}
}
- }(U, V, Z);
- return Z;
+ }(U, V, Z)
+ return Z
}
// Multiply a power series by a constant
func Cmul(c *rat,U PS) PS{
- Z := mkPS();
+ Z := mkPS()
go func(c *rat, U, Z PS){
- done := false;
+ done := false
for !done {
- <-Z.req;
- u := get(U);
+ <-Z.req
+ u := get(U)
if end(u) != 0 {
done = true
} else {
Z.dat <- mul(c,u)
}
}
- Z.dat <- finis;
- }(c, U, Z);
- return Z;
+ Z.dat <- finis
+ }(c, U, Z)
+ return Z
}
// Subtract
func Sub(U, V PS) PS{
- return Add(U, Cmul(neg(one), V));
+ return Add(U, Cmul(neg(one), V))
}
// Multiply a power series by the monomial x^n
func Monmul(U PS, n int) PS{
- Z := mkPS();
+ Z := mkPS()
go func(n int, U PS, Z PS){
for ; n>0; n-- { put(zero,Z) }
- copy(U,Z);
- }(n, U, Z);
- return Z;
+ copy(U,Z)
+ }(n, U, Z)
+ return Z
}
// Multiply by x
func Xmul(U PS) PS{
- return Monmul(U,1);
+ return Monmul(U,1)
}
func Rep(c *rat) PS{
- Z := mkPS();
- go repeat(c,Z);
- return Z;
+ Z := mkPS()
+ go repeat(c,Z)
+ return Z
}
// Monomial c*x^n
func Mon(c *rat, n int) PS{
- Z:=mkPS();
+ Z:=mkPS()
go func(c *rat, n int, Z PS){
if(c.num!=0) {
for ; n>0; n=n-1 { put(zero,Z) }
- put(c,Z);
+ put(c,Z)
}
- put(finis,Z);
- }(c, n, Z);
- return Z;
+ put(finis,Z)
+ }(c, n, Z)
+ return Z
}
func Shift(c *rat, U PS) PS{
- Z := mkPS();
+ Z := mkPS()
go func(c *rat, U, Z PS){
- put(c,Z);
- copy(U,Z);
- }(c, U, Z);
- return Z;
+ put(c,Z)
+ copy(U,Z)
+ }(c, U, Z)
+ return Z
}
// simple pole at 1: 1/(1-x) = 1 1 1 1 1 ...
@@ -432,17 +431,17 @@ func Shift(c *rat, U PS) PS{
/*
func Poly(a [] *rat) PS{
- Z:=mkPS();
+ Z:=mkPS()
begin func(a [] *rat, Z PS){
- j:=0;
- done:=0;
+ j:=0
+ done:=0
for j=len(a); !done&&j>0; j=j-1)
- if(a[j-1].num!=0) done=1;
- i:=0;
- for(; i<j; i=i+1) put(a[i],Z);
- put(finis,Z);
- }();
- return Z;
+ if(a[j-1].num!=0) done=1
+ i:=0
+ for(; i<j; i=i+1) put(a[i],Z)
+ put(finis,Z)
+ }()
+ return Z
}
*/
@@ -452,82 +451,82 @@ func Poly(a [] *rat) PS{
// then UV = u*v + x*(u*VV+v*UU) + x*x*UU*VV
func Mul(U, V PS) PS{
- Z:=mkPS();
+ Z:=mkPS()
go func(U, V, Z PS){
- <-Z.req;
- uv := get2(U,V);
+ <-Z.req
+ uv := get2(U,V)
if end(uv[0].(*rat))!=0 || end(uv[1].(*rat)) != 0 {
- Z.dat <- finis;
+ Z.dat <- finis
} else {
- Z.dat <- mul(uv[0].(*rat),uv[1].(*rat));
- UU := Split(U);
- VV := Split(V);
- W := Add(Cmul(uv[0].(*rat),VV[0]),Cmul(uv[1].(*rat),UU[0]));
- <-Z.req;
- Z.dat <- get(W);
- copy(Add(W,Mul(UU[1],VV[1])),Z);
+ Z.dat <- mul(uv[0].(*rat),uv[1].(*rat))
+ UU := Split(U)
+ VV := Split(V)
+ W := Add(Cmul(uv[0].(*rat),VV[0]),Cmul(uv[1].(*rat),UU[0]))
+ <-Z.req
+ Z.dat <- get(W)
+ copy(Add(W,Mul(UU[1],VV[1])),Z)
}
- }(U, V, Z);
- return Z;
+ }(U, V, Z)
+ return Z
}
// Differentiate
func Diff(U PS) PS{
- Z:=mkPS();
+ Z:=mkPS()
go func(U, Z PS){
- <-Z.req;
- u := get(U);
+ <-Z.req
+ u := get(U)
if end(u) == 0 {
- done:=false;
+ done:=false
for i:=1; !done; i++ {
- u = get(U);
+ u = get(U)
if end(u) != 0 {
done=true
} else {
- Z.dat <- mul(itor(int64(i)),u);
- <-Z.req;
+ Z.dat <- mul(itor(int64(i)),u)
+ <-Z.req
}
}
}
- Z.dat <- finis;
- }(U, Z);
- return Z;
+ Z.dat <- finis
+ }(U, Z)
+ return Z
}
// Integrate, with const of integration
func Integ(c *rat,U PS) PS{
- Z:=mkPS();
+ Z:=mkPS()
go func(c *rat, U, Z PS){
- put(c,Z);
- done:=false;
+ put(c,Z)
+ done:=false
for i:=1; !done; i++ {
- <-Z.req;
- u := get(U);
+ <-Z.req
+ u := get(U)
if end(u) != 0 { done= true }
- Z.dat <- mul(i2tor(1,int64(i)),u);
+ Z.dat <- mul(i2tor(1,int64(i)),u)
}
- Z.dat <- finis;
- }(c, U, Z);
- return Z;
+ Z.dat <- finis
+ }(c, U, Z)
+ return Z
}
// Binomial theorem (1+x)^c
func Binom(c *rat) PS{
- Z:=mkPS();
+ Z:=mkPS()
go func(c *rat, Z PS){
- n := 1;
- t := itor(1);
+ n := 1
+ t := itor(1)
for c.num!=0 {
- put(t,Z);
- t = mul(mul(t,c),i2tor(1,int64(n)));
- c = sub(c,one);
- n++;
+ put(t,Z)
+ t = mul(mul(t,c),i2tor(1,int64(n)))
+ c = sub(c,one)
+ n++
}
- put(finis,Z);
- }(c, Z);
- return Z;
+ put(finis,Z)
+ }(c, Z)
+ return Z
}
// Reciprocal of a power series
@@ -536,19 +535,19 @@ func Binom(c *rat) PS{
// (u+x*UU)*(z+x*ZZ) = 1
// z = 1/u
// u*ZZ + z*UU +x*UU*ZZ = 0
-// ZZ = -UU*(z+x*ZZ)/u;
+// ZZ = -UU*(z+x*ZZ)/u
func Recip(U PS) PS{
- Z:=mkPS();
+ Z:=mkPS()
go func(U, Z PS){
- ZZ:=mkPS2();
- <-Z.req;
- z := inv(get(U));
- Z.dat <- z;
- split(Mul(Cmul(neg(z),U),Shift(z,ZZ[0])),ZZ);
- copy(ZZ[1],Z);
- }(U, Z);
- return Z;
+ ZZ:=mkPS2()
+ <-Z.req
+ z := inv(get(U))
+ Z.dat <- z
+ split(Mul(Cmul(neg(z),U),Shift(z,ZZ[0])),ZZ)
+ copy(ZZ[1],Z)
+ }(U, Z)
+ return Z
}
// Exponential of a power series with constant term 0
@@ -559,9 +558,9 @@ func Recip(U PS) PS{
// integrate to get Z
func Exp(U PS) PS{
- ZZ := mkPS2();
- split(Integ(one,Mul(ZZ[0],Diff(U))),ZZ);
- return ZZ[1];
+ ZZ := mkPS2()
+ split(Integ(one,Mul(ZZ[0],Diff(U))),ZZ)
+ return ZZ[1]
}
// Substitute V for x in U, where the leading term of V is zero
@@ -571,69 +570,69 @@ func Exp(U PS) PS{
// bug: a nonzero constant term is ignored
func Subst(U, V PS) PS {
- Z:= mkPS();
+ Z:= mkPS()
go func(U, V, Z PS) {
- VV := Split(V);
- <-Z.req;
- u := get(U);
- Z.dat <- u;
+ VV := Split(V)
+ <-Z.req
+ u := get(U)
+ Z.dat <- u
if end(u) == 0 {
if end(get(VV[0])) != 0 {
- put(finis,Z);
+ put(finis,Z)
} else {
- copy(Mul(VV[0],Subst(U,VV[1])),Z);
+ copy(Mul(VV[0],Subst(U,VV[1])),Z)
}
}
- }(U, V, Z);
- return Z;
+ }(U, V, Z)
+ return Z
}
// Monomial Substition: U(c x^n)
// Each Ui is multiplied by c^i and followed by n-1 zeros
func MonSubst(U PS, c0 *rat, n int) PS {
- Z:= mkPS();
+ Z:= mkPS()
go func(U, Z PS, c0 *rat, n int) {
- c := one;
+ c := one
for {
- <-Z.req;
- u := get(U);
- Z.dat <- mul(u, c);
- c = mul(c, c0);
+ <-Z.req
+ u := get(U)
+ Z.dat <- mul(u, c)
+ c = mul(c, c0)
if end(u) != 0 {
- Z.dat <- finis;
- break;
+ Z.dat <- finis
+ break
}
for i := 1; i < n; i++ {
- <-Z.req;
- Z.dat <- zero;
+ <-Z.req
+ Z.dat <- zero
}
}
- }(U, Z, c0, n);
- return Z;
+ }(U, Z, c0, n)
+ return Z
}
func Init() {
- chnameserial = -1;
- seqno = 0;
- chnames = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
- zero = itor(0);
- one = itor(1);
- finis = i2tor(1,0);
- Ones = Rep(one);
- Twos = Rep(itor(2));
+ chnameserial = -1
+ seqno = 0
+ chnames = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
+ zero = itor(0)
+ one = itor(1)
+ finis = i2tor(1,0)
+ Ones = Rep(one)
+ Twos = Rep(itor(2))
}
func check(U PS, c *rat, count int, str string) {
for i := 0; i < count; i++ {
- r := get(U);
+ r := get(U)
if !r.eq(c) {
- print("got: ");
- r.pr();
- print("should get ");
- c.pr();
- print("\n");
+ print("got: ")
+ r.pr()
+ print("should get ")
+ c.pr()
+ print("\n")
panic(str)
}
}
@@ -642,82 +641,82 @@ func check(U PS, c *rat, count int, str string) {
const N=10
func checka(U PS, a []*rat, str string) {
for i := 0; i < N; i++ {
- check(U, a[i], 1, str);
+ check(U, a[i], 1, str)
}
}
func main() {
- Init();
+ Init()
if len(os.Args) > 1 { // print
- print("Ones: "); Printn(Ones, 10);
- print("Twos: "); Printn(Twos, 10);
- print("Add: "); Printn(Add(Ones, Twos), 10);
- print("Diff: "); Printn(Diff(Ones), 10);
- print("Integ: "); Printn(Integ(zero, Ones), 10);
- print("CMul: "); Printn(Cmul(neg(one), Ones), 10);
- print("Sub: "); Printn(Sub(Ones, Twos), 10);
- print("Mul: "); Printn(Mul(Ones, Ones), 10);
- print("Exp: "); Printn(Exp(Ones), 15);
- print("MonSubst: "); Printn(MonSubst(Ones, neg(one), 2), 10);
- print("ATan: "); Printn(Integ(zero, MonSubst(Ones, neg(one), 2)), 10);
+ print("Ones: "); Printn(Ones, 10)
+ print("Twos: "); Printn(Twos, 10)
+ print("Add: "); Printn(Add(Ones, Twos), 10)
+ print("Diff: "); Printn(Diff(Ones), 10)
+ print("Integ: "); Printn(Integ(zero, Ones), 10)
+ print("CMul: "); Printn(Cmul(neg(one), Ones), 10)
+ print("Sub: "); Printn(Sub(Ones, Twos), 10)
+ print("Mul: "); Printn(Mul(Ones, Ones), 10)
+ print("Exp: "); Printn(Exp(Ones), 15)
+ print("MonSubst: "); Printn(MonSubst(Ones, neg(one), 2), 10)
+ print("ATan: "); Printn(Integ(zero, MonSubst(Ones, neg(one), 2)), 10)
} else { // test
- check(Ones, one, 5, "Ones");
- check(Add(Ones, Ones), itor(2), 0, "Add Ones Ones"); // 1 1 1 1 1
- check(Add(Ones, Twos), itor(3), 0, "Add Ones Twos"); // 3 3 3 3 3
- a := make([]*rat, N);
- d := Diff(Ones);
+ check(Ones, one, 5, "Ones")
+ check(Add(Ones, Ones), itor(2), 0, "Add Ones Ones") // 1 1 1 1 1
+ check(Add(Ones, Twos), itor(3), 0, "Add Ones Twos") // 3 3 3 3 3
+ a := make([]*rat, N)
+ d := Diff(Ones)
for i:=0; i < N; i++ {
a[i] = itor(int64(i+1))
}
- checka(d, a, "Diff"); // 1 2 3 4 5
- in := Integ(zero, Ones);
- a[0] = zero; // integration constant
+ checka(d, a, "Diff") // 1 2 3 4 5
+ in := Integ(zero, Ones)
+ a[0] = zero // integration constant
for i:=1; i < N; i++ {
a[i] = i2tor(1, int64(i))
}
- checka(in, a, "Integ"); // 0 1 1/2 1/3 1/4 1/5
- check(Cmul(neg(one), Twos), itor(-2), 10, "CMul"); // -1 -1 -1 -1 -1
- check(Sub(Ones, Twos), itor(-1), 0, "Sub Ones Twos"); // -1 -1 -1 -1 -1
- m := Mul(Ones, Ones);
+ checka(in, a, "Integ") // 0 1 1/2 1/3 1/4 1/5
+ check(Cmul(neg(one), Twos), itor(-2), 10, "CMul") // -1 -1 -1 -1 -1
+ check(Sub(Ones, Twos), itor(-1), 0, "Sub Ones Twos") // -1 -1 -1 -1 -1
+ m := Mul(Ones, Ones)
for i:=0; i < N; i++ {
a[i] = itor(int64(i+1))
}
- checka(m, a, "Mul"); // 1 2 3 4 5
- e := Exp(Ones);
- a[0] = itor(1);
- a[1] = itor(1);
- a[2] = i2tor(3,2);
- a[3] = i2tor(13,6);
- a[4] = i2tor(73,24);
- a[5] = i2tor(167,40);
- a[6] = i2tor(4051,720);
- a[7] = i2tor(37633,5040);
- a[8] = i2tor(43817,4480);
- a[9] = i2tor(4596553,362880);
- checka(e, a, "Exp"); // 1 1 3/2 13/6 73/24
- at := Integ(zero, MonSubst(Ones, neg(one), 2));
+ checka(m, a, "Mul") // 1 2 3 4 5
+ e := Exp(Ones)
+ a[0] = itor(1)
+ a[1] = itor(1)
+ a[2] = i2tor(3,2)
+ a[3] = i2tor(13,6)
+ a[4] = i2tor(73,24)
+ a[5] = i2tor(167,40)
+ a[6] = i2tor(4051,720)
+ a[7] = i2tor(37633,5040)
+ a[8] = i2tor(43817,4480)
+ a[9] = i2tor(4596553,362880)
+ checka(e, a, "Exp") // 1 1 3/2 13/6 73/24
+ at := Integ(zero, MonSubst(Ones, neg(one), 2))
for c, i := 1, 0; i < N; i++ {
if i%2 == 0 {
a[i] = zero
} else {
- a[i] = i2tor(int64(c), int64(i));
+ a[i] = i2tor(int64(c), int64(i))
c *= -1
}
}
checka(at, a, "ATan"); // 0 -1 0 -1/3 0 -1/5
/*
- t := Revert(Integ(zero, MonSubst(Ones, neg(one), 2)));
- a[0] = zero;
- a[1] = itor(1);
- a[2] = zero;
- a[3] = i2tor(1,3);
- a[4] = zero;
- a[5] = i2tor(2,15);
- a[6] = zero;
- a[7] = i2tor(17,315);
- a[8] = zero;
- a[9] = i2tor(62,2835);
- checka(t, a, "Tan"); // 0 1 0 1/3 0 2/15
+ t := Revert(Integ(zero, MonSubst(Ones, neg(one), 2)))
+ a[0] = zero
+ a[1] = itor(1)
+ a[2] = zero
+ a[3] = i2tor(1,3)
+ a[4] = zero
+ a[5] = i2tor(2,15)
+ a[6] = zero
+ a[7] = i2tor(17,315)
+ a[8] = zero
+ a[9] = i2tor(62,2835)
+ checka(t, a, "Tan") // 0 1 0 1/3 0 2/15
*/
}
}
diff --git a/test/chan/select3.go b/test/chan/select3.go
new file mode 100644
index 000000000..a1a2ef50b
--- /dev/null
+++ b/test/chan/select3.go
@@ -0,0 +1,203 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2010 The Go 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 verifying the semantics of the select statement
+// for basic empty/non-empty cases.
+
+package main
+
+import "time"
+
+const always = "function did not"
+const never = "function did"
+
+
+func unreachable() {
+ panic("control flow shouldn't reach here")
+}
+
+
+// Calls f and verifies that f always/never panics depending on signal.
+func testPanic(signal string, f func()) {
+ defer func() {
+ s := never
+ if recover() != nil {
+ s = always // f panicked
+ }
+ if s != signal {
+ panic(signal + " panic")
+ }
+ }()
+ f()
+}
+
+
+// Calls f and empirically verifies that f always/never blocks depending on signal.
+func testBlock(signal string, f func()) {
+ c := make(chan string)
+ go func() {
+ f()
+ c <- never // f didn't block
+ }()
+ go func() {
+ time.Sleep(1e8) // 0.1s seems plenty long
+ c <- always // f blocked always
+ }()
+ if <-c != signal {
+ panic(signal + " block")
+ }
+}
+
+
+func main() {
+ const async = 1 // asynchronous channels
+ var nilch chan int
+ closedch := make(chan int)
+ close(closedch)
+
+ // sending/receiving from a nil channel outside a select panics
+ testPanic(always, func() {
+ nilch <- 7
+ })
+ testPanic(always, func() {
+ <-nilch
+ })
+
+ // sending/receiving from a nil channel inside a select never panics
+ testPanic(never, func() {
+ select {
+ case nilch <- 7:
+ unreachable()
+ default:
+ }
+ })
+ testPanic(never, func() {
+ select {
+ case <-nilch:
+ unreachable()
+ default:
+ }
+ })
+
+ // sending to an async channel with free buffer space never blocks
+ testBlock(never, func() {
+ ch := make(chan int, async)
+ ch <- 7
+ })
+
+ // receiving (a small number of times) from a closed channel never blocks
+ testBlock(never, func() {
+ for i := 0; i < 10; i++ {
+ if <-closedch != 0 {
+ panic("expected zero value when reading from closed channel")
+ }
+ }
+ })
+
+ // sending (a small number of times) to a closed channel is not specified
+ // but the current implementation doesn't block: test that different
+ // implementations behave the same
+ testBlock(never, func() {
+ for i := 0; i < 10; i++ {
+ closedch <- 7
+ }
+ })
+
+ // receiving from a non-ready channel always blocks
+ testBlock(always, func() {
+ ch := make(chan int)
+ <-ch
+ })
+
+ // empty selects always block
+ testBlock(always, func() {
+ select {
+ }
+ })
+
+ // selects with only nil channels always block
+ testBlock(always, func() {
+ select {
+ case <-nilch:
+ unreachable()
+ }
+ })
+ testBlock(always, func() {
+ select {
+ case nilch <- 7:
+ unreachable()
+ }
+ })
+ testBlock(always, func() {
+ select {
+ case <-nilch:
+ unreachable()
+ case nilch <- 7:
+ unreachable()
+ }
+ })
+
+ // selects with non-ready non-nil channels always block
+ testBlock(always, func() {
+ ch := make(chan int)
+ select {
+ case <-ch:
+ unreachable()
+ }
+ })
+
+ // selects with default cases don't block
+ testBlock(never, func() {
+ select {
+ default:
+ }
+ })
+ testBlock(never, func() {
+ select {
+ case <-nilch:
+ unreachable()
+ default:
+ }
+ })
+ testBlock(never, func() {
+ select {
+ case nilch <- 7:
+ unreachable()
+ default:
+ }
+ })
+
+ // selects with ready channels don't block
+ testBlock(never, func() {
+ ch := make(chan int, async)
+ select {
+ case ch <- 7:
+ default:
+ unreachable()
+ }
+ })
+ testBlock(never, func() {
+ ch := make(chan int, async)
+ ch <- 7
+ select {
+ case <-ch:
+ default:
+ unreachable()
+ }
+ })
+
+ // selects with closed channels don't block
+ testBlock(never, func() {
+ select {
+ case <-closedch:
+ }
+ })
+ testBlock(never, func() {
+ select {
+ case closedch <- 7:
+ }
+ })
+}
diff --git a/test/chan/select4.go b/test/chan/select4.go
new file mode 100644
index 000000000..46618ac88
--- /dev/null
+++ b/test/chan/select4.go
@@ -0,0 +1,25 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+package main
+
+func f() *int {
+ println("BUG: called f")
+ return new(int)
+}
+
+func main() {
+ var x struct {
+ a int
+ }
+ c := make(chan int, 1)
+ c1 := make(chan int)
+ c <- 42
+ select {
+ case *f() = <-c1:
+ // nothing
+ case x.a = <-c:
+ if x.a != 42 {
+ println("BUG:", x.a)
+ }
+ }
+}
diff --git a/test/char_lit.go b/test/char_lit.go
index e4f3f8323..99be77a57 100644
--- a/test/char_lit.go
+++ b/test/char_lit.go
@@ -32,13 +32,12 @@ func main() {
'\ubabe' +
'\U0010FFFF' +
'\U000ebabe'
- ;
if '\U000ebabe' != 0x000ebabe {
- print("ebabe wrong\n");
+ print("ebabe wrong\n")
os.Exit(1)
}
if i != 0x20e213 {
- print("number is ", i, " should be ", 0x20e213, "\n");
+ print("number is ", i, " should be ", 0x20e213, "\n")
os.Exit(1)
- }
+ }
}
diff --git a/test/char_lit1.go b/test/char_lit1.go
index ccf1cc9fc..dc5385291 100644
--- a/test/char_lit1.go
+++ b/test/char_lit1.go
@@ -10,16 +10,16 @@ const (
// check that surrogate pair elements are invalid
// (d800-dbff, dc00-dfff).
_ = '\ud7ff' // ok
- _ = '\ud800' // ERROR "Unicode"
- _ = "\U0000D999" // ERROR "Unicode"
- _ = '\udc01' // ERROR "Unicode"
- _ = '\U0000dddd' // ERROR "Unicode"
- _ = '\udfff' // ERROR "Unicode"
+ _ = '\ud800' // ERROR "Unicode|unicode"
+ _ = "\U0000D999" // ERROR "Unicode|unicode"
+ _ = '\udc01' // ERROR "Unicode|unicode"
+ _ = '\U0000dddd' // ERROR "Unicode|unicode"
+ _ = '\udfff' // ERROR "Unicode|unicode"
_ = '\ue000' // ok
_ = '\U0010ffff' // ok
- _ = '\U00110000' // ERROR "Unicode"
+ _ = '\U00110000' // ERROR "Unicode|unicode"
_ = "abc\U0010ffffdef" // ok
- _ = "abc\U00110000def" // ERROR "Unicode"
- _ = '\Uffffffff' // ERROR "Unicode"
+ _ = "abc\U00110000def" // ERROR "Unicode|unicode"
+ _ = '\Uffffffff' // ERROR "Unicode|unicode"
)
diff --git a/test/closedchan.go b/test/closedchan.go
index 4ab12c775..c7c759be3 100644
--- a/test/closedchan.go
+++ b/test/closedchan.go
@@ -12,13 +12,13 @@
package main
type Chan interface {
- Send(int);
- Nbsend(int) bool;
- Recv() int;
- Nbrecv() (int, bool);
- Close();
- Closed() bool;
- Impl() string;
+ Send(int)
+ Nbsend(int) bool
+ Recv() int
+ Nbrecv() (int, bool)
+ Close()
+ Closed() bool
+ Impl() string
}
// direct channel operations
@@ -28,7 +28,7 @@ func (c XChan) Send(x int) {
}
func (c XChan) Nbsend(x int) bool {
- return c <- x;
+ return c <- x
}
func (c XChan) Recv() int {
@@ -36,8 +36,8 @@ func (c XChan) Recv() int {
}
func (c XChan) Nbrecv() (int, bool) {
- x, ok := <-c;
- return x, ok;
+ x, ok := <-c
+ return x, ok
}
func (c XChan) Close() {
@@ -63,29 +63,29 @@ func (c SChan) Send(x int) {
func (c SChan) Nbsend(x int) bool {
select {
case c <- x:
- return true;
+ return true
default:
- return false;
+ return false
}
- panic("nbsend");
+ panic("nbsend")
}
func (c SChan) Recv() int {
select {
case x := <-c:
- return x;
+ return x
}
- panic("recv");
+ panic("recv")
}
func (c SChan) Nbrecv() (int, bool) {
select {
case x := <-c:
- return x, true;
+ return x, true
default:
- return 0, false;
+ return 0, false
}
- panic("nbrecv");
+ panic("nbrecv")
}
func (c SChan) Close() {
@@ -97,101 +97,101 @@ func (c SChan) Closed() bool {
}
func (c SChan) Impl() string {
- return "(select)";
+ return "(select)"
}
func test1(c Chan) {
// not closed until the close signal (a zero value) has been received.
if c.Closed() {
- println("test1: Closed before Recv zero:", c.Impl());
+ println("test1: Closed before Recv zero:", c.Impl())
}
for i := 0; i < 3; i++ {
// recv a close signal (a zero value)
if x := c.Recv(); x != 0 {
- println("test1: recv on closed got non-zero:", x, c.Impl());
+ println("test1: recv on closed got non-zero:", x, c.Impl())
}
// should now be closed.
if !c.Closed() {
- println("test1: not closed after recv zero", c.Impl());
+ println("test1: not closed after recv zero", c.Impl())
}
// should work with ,ok: received a value without blocking, so ok == true.
- x, ok := c.Nbrecv();
+ x, ok := c.Nbrecv()
if !ok {
- println("test1: recv on closed got not ok", c.Impl());
+ println("test1: recv on closed got not ok", c.Impl())
}
if x != 0 {
- println("test1: recv ,ok on closed got non-zero:", x, c.Impl());
+ println("test1: recv ,ok on closed got non-zero:", x, c.Impl())
}
}
// send should work with ,ok too: sent a value without blocking, so ok == true.
- ok := c.Nbsend(1);
+ ok := c.Nbsend(1)
if !ok {
- println("test1: send on closed got not ok", c.Impl());
+ println("test1: send on closed got not ok", c.Impl())
}
// but the value should have been discarded.
if x := c.Recv(); x != 0 {
- println("test1: recv on closed got non-zero after send on closed:", x, c.Impl());
+ println("test1: recv on closed got non-zero after send on closed:", x, c.Impl())
}
// similarly Send.
- c.Send(2);
+ c.Send(2)
if x := c.Recv(); x != 0 {
- println("test1: recv on closed got non-zero after send on closed:", x, c.Impl());
+ println("test1: recv on closed got non-zero after send on closed:", x, c.Impl())
}
}
func testasync1(c Chan) {
// not closed until the close signal (a zero value) has been received.
if c.Closed() {
- println("testasync1: Closed before Recv zero:", c.Impl());
+ println("testasync1: Closed before Recv zero:", c.Impl())
}
// should be able to get the last value via Recv
if x := c.Recv(); x != 1 {
- println("testasync1: Recv did not get 1:", x, c.Impl());
+ println("testasync1: Recv did not get 1:", x, c.Impl())
}
- test1(c);
+ test1(c)
}
func testasync2(c Chan) {
// not closed until the close signal (a zero value) has been received.
if c.Closed() {
- println("testasync2: Closed before Recv zero:", c.Impl());
+ println("testasync2: Closed before Recv zero:", c.Impl())
}
// should be able to get the last value via Nbrecv
if x, ok := c.Nbrecv(); !ok || x != 1 {
- println("testasync2: Nbrecv did not get 1, true:", x, ok, c.Impl());
+ println("testasync2: Nbrecv did not get 1, true:", x, ok, c.Impl())
}
- test1(c);
+ test1(c)
}
func closedsync() chan int {
- c := make(chan int);
- close(c);
- return c;
+ c := make(chan int)
+ close(c)
+ return c
}
func closedasync() chan int {
- c := make(chan int, 2);
- c <- 1;
- close(c);
- return c;
+ c := make(chan int, 2)
+ c <- 1
+ close(c)
+ return c
}
func main() {
- test1(XChan(closedsync()));
- test1(SChan(closedsync()));
+ test1(XChan(closedsync()))
+ test1(SChan(closedsync()))
- testasync1(XChan(closedasync()));
- testasync1(SChan(closedasync()));
- testasync2(XChan(closedasync()));
- testasync2(SChan(closedasync()));
+ testasync1(XChan(closedasync()))
+ testasync1(SChan(closedasync()))
+ testasync2(XChan(closedasync()))
+ testasync2(SChan(closedasync()))
}
diff --git a/test/closure.go b/test/closure.go
index 54e4cf8ea..3033c02ed 100644
--- a/test/closure.go
+++ b/test/closure.go
@@ -98,4 +98,15 @@ func main() {
println("newfunc returned broken funcs")
panic("fail")
}
+
+ ff(1)
+}
+
+func ff(x int) {
+ call(func() {
+ _ = x
+ })
+}
+
+func call(func()) {
}
diff --git a/test/cmp1.go b/test/cmp1.go
index db0a486dd..698544c58 100644
--- a/test/cmp1.go
+++ b/test/cmp1.go
@@ -26,6 +26,8 @@ func istrue(b bool) {
}
}
+type T *int
+
func main() {
var a []int
var b map[string]int
@@ -55,6 +57,24 @@ func main() {
isfalse(ib == id)
istrue(ic == id)
istrue(ie == ie)
+
+ // these are okay because one side of the
+ // comparison need only be assignable to the other.
+ isfalse(a == ib)
+ isfalse(a == ic)
+ isfalse(a == id)
+ isfalse(b == ic)
+ isfalse(b == id)
+ istrue(c == id)
+ istrue(e == ie)
+
+ isfalse(ia == b)
+ isfalse(ia == c)
+ isfalse(ia == d)
+ isfalse(ib == c)
+ isfalse(ib == d)
+ istrue(ic == d)
+ istrue(ie == e)
// 6g used to let this go through as true.
var g uint64 = 123
@@ -73,4 +93,38 @@ func main() {
println("m[ic] = ", m[ic])
panic("bad m[ic]")
}
+
+ // non-interface comparisons
+ {
+ c := make(chan int)
+ c1 := (<-chan int)(c)
+ c2 := (chan<- int)(c)
+ istrue(c == c1)
+ istrue(c == c2)
+ istrue(c1 == c)
+ istrue(c2 == c)
+
+ d := make(chan int)
+ isfalse(c == d)
+ isfalse(d == c)
+ isfalse(d == c1)
+ isfalse(d == c2)
+ isfalse(c1 == d)
+ isfalse(c2 == d)
+ }
+
+ // named types vs not
+ {
+ var x = new(int)
+ var y T
+ var z T = x
+
+ isfalse(x == y)
+ istrue(x == z)
+ isfalse(y == z)
+
+ isfalse(y == x)
+ istrue(z == x)
+ isfalse(z == y)
+ }
}
diff --git a/test/cmp2.go b/test/cmp2.go
index 5442fa17a..f6f124f2e 100644
--- a/test/cmp2.go
+++ b/test/cmp2.go
@@ -9,7 +9,7 @@ package main
func use(bool) { }
func main() {
- var a []int;
- var ia interface{} = a;
- use(ia == ia);
+ var a []int
+ var ia interface{} = a
+ use(ia == ia)
}
diff --git a/test/cmp3.go b/test/cmp3.go
index f34542ade..dd90bfb03 100644
--- a/test/cmp3.go
+++ b/test/cmp3.go
@@ -9,7 +9,7 @@ package main
func use(bool) { }
func main() {
- var b []int;
- var ib interface{} = b;
- use(ib == ib);
+ var b []int
+ var ib interface{} = b
+ use(ib == ib)
}
diff --git a/test/cmp4.go b/test/cmp4.go
index ca1ad2ad3..3f9b2c0b8 100644
--- a/test/cmp4.go
+++ b/test/cmp4.go
@@ -7,8 +7,8 @@
package main
func main() {
- var a []int;
- var ia interface{} = a;
- var m = make(map[interface{}] int);
- m[ia] = 1;
+ var a []int
+ var ia interface{} = a
+ var m = make(map[interface{}] int)
+ m[ia] = 1
}
diff --git a/test/cmp5.go b/test/cmp5.go
index 9c339a43a..3a7d733f0 100644
--- a/test/cmp5.go
+++ b/test/cmp5.go
@@ -7,8 +7,8 @@
package main
func main() {
- var b []int;
- var ib interface{} = b;
- var m = make(map[interface{}] int);
- m[ib] = 1;
+ var b []int
+ var ib interface{} = b
+ var m = make(map[interface{}] int)
+ m[ib] = 1
}
diff --git a/test/cmp6.go b/test/cmp6.go
new file mode 100644
index 000000000..981a85953
--- /dev/null
+++ b/test/cmp6.go
@@ -0,0 +1,42 @@
+// errchk $G -e $D/$F.go
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func use(bool) {}
+
+type T1 *int
+type T2 *int
+
+func main() {
+ // Arguments to comparison must be
+ // assignable one to the other (or vice versa)
+ // so chan int can be compared against
+ // directional channels but channel of different
+ // direction cannot be compared against each other.
+ var c1 chan <-int
+ var c2 <-chan int
+ var c3 chan int
+
+ use(c1 == c2) // ERROR "invalid operation"
+ use(c2 == c1) // ERROR "invalid operation"
+ use(c1 == c3)
+ use(c2 == c2)
+ use(c3 == c1)
+ use(c3 == c2)
+
+ // Same applies to named types.
+ var p1 T1
+ var p2 T2
+ var p3 *int
+
+ use(p1 == p2) // ERROR "invalid operation"
+ use(p2 == p1) // ERROR "invalid operation"
+ use(p1 == p3)
+ use(p2 == p2)
+ use(p3 == p1)
+ use(p3 == p2)
+}
diff --git a/test/cmplx.go b/test/cmplx.go
index 6262c682d..fad96c605 100644
--- a/test/cmplx.go
+++ b/test/cmplx.go
@@ -22,6 +22,7 @@ func main() {
c64 = cmplx(f32, f32)
c128 = cmplx(f64, f64)
+ _ = complex(0) // ok
_ = cmplx(f, f32) // ERROR "cmplx"
_ = cmplx(f, f64) // ERROR "cmplx"
_ = cmplx(f32, f) // ERROR "cmplx"
diff --git a/test/cmplxdivide.go b/test/cmplxdivide.go
index ac4730d64..6a67b175d 100644
--- a/test/cmplxdivide.go
+++ b/test/cmplxdivide.go
@@ -34,9 +34,14 @@ func calike(a, b complex128) bool {
}
func main() {
+ bad := false
for _, t := range tests {
x := t.f/t.g
if !calike(x, t.out) {
+ if !bad {
+ fmt.Printf("BUG\n")
+ bad = true
+ }
fmt.Printf("%v/%v: expected %v error; got %v\n", t.f, t.g, t.out, x)
}
}
diff --git a/test/complit.go b/test/complit.go
index 3d5a68469..f3b7c9abe 100644
--- a/test/complit.go
+++ b/test/complit.go
@@ -11,9 +11,9 @@ type T struct { i int; f float; s string; next *T }
type R struct { num int }
func itor(a int) *R {
- r := new(R);
- r.num = a;
- return r;
+ r := new(R)
+ r.num = a
+ return r
}
func eq(a []*R) {
@@ -22,49 +22,49 @@ func eq(a []*R) {
}
}
-type P struct { a, b int };
+type P struct { a, b int }
func NewP(a, b int) *P {
return &P{a, b}
}
func main() {
- var t T;
- t = T{0, 7.2, "hi", &t};
+ var t T
+ t = T{0, 7.2, "hi", &t}
- var tp *T;
- tp = &T{0, 7.2, "hi", &t};
+ var tp *T
+ tp = &T{0, 7.2, "hi", &t}
- a1 := []int{1,2,3};
+ a1 := []int{1,2,3}
if len(a1) != 3 { panic("a1") }
- a2 := [10]int{1,2,3};
+ a2 := [10]int{1,2,3}
if len(a2) != 10 || cap(a2) != 10 { panic("a2") }
- a3 := [10]int{1,2,3,};
+ a3 := [10]int{1,2,3,}
if len(a3) != 10 || a2[3] != 0 { panic("a3") }
- var oai []int;
- oai = []int{1,2,3};
+ var oai []int
+ oai = []int{1,2,3}
if len(oai) != 3 { panic("oai") }
- at := [...]*T{&t, tp, &t};
+ at := [...]*T{&t, tp, &t}
if len(at) != 3 { panic("at") }
- c := make(chan int);
- ac := []chan int{c, c, c};
+ c := make(chan int)
+ ac := []chan int{c, c, c}
if len(ac) != 3 { panic("ac") }
- aat := [][len(at)]*T{at, at};
+ aat := [][len(at)]*T{at, at}
if len(aat) != 2 || len(aat[1]) != 3 { panic("aat") }
- s := string([]byte{'h', 'e', 'l', 'l', 'o'});
+ s := string([]byte{'h', 'e', 'l', 'l', 'o'})
if s != "hello" { panic("s") }
- m := map[string]float{"one":1.0, "two":2.0, "pi":22./7.};
+ m := map[string]float{"one":1.0, "two":2.0, "pi":22./7.}
if len(m) != 3 { panic("m") }
- eq([]*R{itor(0), itor(1), itor(2), itor(3), itor(4), itor(5)});
+ eq([]*R{itor(0), itor(1), itor(2), itor(3), itor(4), itor(5)})
- p1 := NewP(1, 2);
- p2 := NewP(1, 2);
+ p1 := NewP(1, 2)
+ p2 := NewP(1, 2)
if p1 == p2 { panic("NewP") }
}
diff --git a/test/compos.go b/test/compos.go
index 78a7965ef..70f90f379 100644
--- a/test/compos.go
+++ b/test/compos.go
@@ -7,7 +7,7 @@
package main
type T struct {
- int;
+ int
}
func f() *T {
@@ -15,9 +15,9 @@ func f() *T {
}
func main() {
- x := f();
- y := f();
+ x := f()
+ y := f()
if x == y {
- panic("not allocating & composite literals");
+ panic("not allocating & composite literals")
}
}
diff --git a/test/const.go b/test/const.go
index 8e587cfe5..a55e13a40 100644
--- a/test/const.go
+++ b/test/const.go
@@ -7,26 +7,26 @@
package main
const (
- c0 = 0;
- cm1 = -1;
- chuge = 1 << 100;
- chuge_1 = chuge - 1;
- c1 = chuge >> 100;
- c3div2 = 3/2;
- c1e3 = 1e3;
+ c0 = 0
+ cm1 = -1
+ chuge = 1 << 100
+ chuge_1 = chuge - 1
+ c1 = chuge >> 100
+ c3div2 = 3/2
+ c1e3 = 1e3
- ctrue = true;
- cfalse = !ctrue;
+ ctrue = true
+ cfalse = !ctrue
)
const (
- f0 = 0.0;
- fm1 = -1.;
- fhuge float64 = 1 << 100;
- fhuge_1 float64 = chuge - 1;
- f1 float64 = chuge >> 100;
- f3div2 = 3./2.;
- f1e3 float64 = 1e3;
+ f0 = 0.0
+ fm1 = -1.
+ fhuge float64 = 1 << 100
+ fhuge_1 float64 = chuge - 1
+ f1 float64 = chuge >> 100
+ f3div2 = 3./2.
+ f1e3 float64 = 1e3
)
func assert(t bool, s string) {
@@ -36,85 +36,85 @@ func assert(t bool, s string) {
}
func ints() {
- assert(c0 == 0, "c0");
- assert(c1 == 1, "c1");
- assert(chuge > chuge_1, "chuge");
- assert(chuge_1 + 1 == chuge, "chuge 1");
- assert(chuge + cm1 +1 == chuge, "cm1");
- assert(c3div2 == 1, "3/2");
- assert(c1e3 == 1000, "c1e3 int");
- assert(c1e3 == 1e3, "c1e3 float");
+ assert(c0 == 0, "c0")
+ assert(c1 == 1, "c1")
+ assert(chuge > chuge_1, "chuge")
+ assert(chuge_1 + 1 == chuge, "chuge 1")
+ assert(chuge + cm1 +1 == chuge, "cm1")
+ assert(c3div2 == 1, "3/2")
+ assert(c1e3 == 1000, "c1e3 int")
+ assert(c1e3 == 1e3, "c1e3 float")
// verify that all (in range) are assignable as ints
- var i int;
- i = c0;
- assert(i == c0, "i == c0");
- i = cm1;
- assert(i == cm1, "i == cm1");
- i = c1;
- assert(i == c1, "i == c1");
- i = c3div2;
- assert(i == c3div2, "i == c3div2");
- i = c1e3;
- assert(i == c1e3, "i == c1e3");
+ var i int
+ i = c0
+ assert(i == c0, "i == c0")
+ i = cm1
+ assert(i == cm1, "i == cm1")
+ i = c1
+ assert(i == c1, "i == c1")
+ i = c3div2
+ assert(i == c3div2, "i == c3div2")
+ i = c1e3
+ assert(i == c1e3, "i == c1e3")
// verify that all are assignable as floats
- var f float64;
- f = c0;
- assert(f == c0, "f == c0");
- f = cm1;
- assert(f == cm1, "f == cm1");
- f = chuge;
- assert(f == chuge, "f == chuge");
- f = chuge_1;
- assert(f == chuge_1, "f == chuge_1");
- f = c1;
- assert(f == c1, "f == c1");
- f = c3div2;
- assert(f == c3div2, "f == c3div2");
- f = c1e3;
- assert(f == c1e3, "f == c1e3");
+ var f float64
+ f = c0
+ assert(f == c0, "f == c0")
+ f = cm1
+ assert(f == cm1, "f == cm1")
+ f = chuge
+ assert(f == chuge, "f == chuge")
+ f = chuge_1
+ assert(f == chuge_1, "f == chuge_1")
+ f = c1
+ assert(f == c1, "f == c1")
+ f = c3div2
+ assert(f == c3div2, "f == c3div2")
+ f = c1e3
+ assert(f == c1e3, "f == c1e3")
}
func floats() {
- assert(f0 == c0, "f0");
- assert(f1 == c1, "f1");
- assert(fhuge == fhuge_1, "fhuge"); // float64 can't distinguish fhuge, fhuge_1.
- assert(fhuge_1 + 1 == fhuge, "fhuge 1");
- assert(fhuge + fm1 +1 == fhuge, "fm1");
- assert(f3div2 == 1.5, "3./2.");
- assert(f1e3 == 1000, "f1e3 int");
- assert(f1e3 == 1.e3, "f1e3 float");
+ assert(f0 == c0, "f0")
+ assert(f1 == c1, "f1")
+ assert(fhuge == fhuge_1, "fhuge") // float64 can't distinguish fhuge, fhuge_1.
+ assert(fhuge_1 + 1 == fhuge, "fhuge 1")
+ assert(fhuge + fm1 +1 == fhuge, "fm1")
+ assert(f3div2 == 1.5, "3./2.")
+ assert(f1e3 == 1000, "f1e3 int")
+ assert(f1e3 == 1.e3, "f1e3 float")
// verify that all (in range) are assignable as ints
- var i int;
- i = f0;
- assert(i == f0, "i == f0");
- i = fm1;
- assert(i == fm1, "i == fm1");
+ var i int
+ i = f0
+ assert(i == f0, "i == f0")
+ i = fm1
+ assert(i == fm1, "i == fm1")
// verify that all are assignable as floats
- var f float64;
- f = f0;
- assert(f == f0, "f == f0");
- f = fm1;
- assert(f == fm1, "f == fm1");
- f = fhuge;
- assert(f == fhuge, "f == fhuge");
- f = fhuge_1;
- assert(f == fhuge_1, "f == fhuge_1");
- f = f1;
- assert(f == f1, "f == f1");
- f = f3div2;
- assert(f == f3div2, "f == f3div2");
- f = f1e3;
- assert(f == f1e3, "f == f1e3");
+ var f float64
+ f = f0
+ assert(f == f0, "f == f0")
+ f = fm1
+ assert(f == fm1, "f == fm1")
+ f = fhuge
+ assert(f == fhuge, "f == fhuge")
+ f = fhuge_1
+ assert(f == fhuge_1, "f == fhuge_1")
+ f = f1
+ assert(f == f1, "f == f1")
+ f = f3div2
+ assert(f == f3div2, "f == f3div2")
+ f = f1e3
+ assert(f == f1e3, "f == f1e3")
}
func main() {
- ints();
- floats();
+ ints()
+ floats()
- assert(ctrue == true, "ctrue == true");
- assert(cfalse == false, "cfalse == false");
+ assert(ctrue == true, "ctrue == true")
+ assert(cfalse == false, "cfalse == false")
}
diff --git a/test/const1.go b/test/const1.go
index 78fb1f4e2..cf07055cf 100644
--- a/test/const1.go
+++ b/test/const1.go
@@ -9,71 +9,73 @@ package main
type I interface {}
const (
// assume all types behave similarly to int8/uint8
- Int8 int8 = 101;
- Minus1 int8 = -1;
- Uint8 uint8 = 102;
- Const = 103;
+ Int8 int8 = 101
+ Minus1 int8 = -1
+ Uint8 uint8 = 102
+ Const = 103
- Float32 float32 = 104.5;
- Float float = 105.5;
- ConstFloat = 106.5;
- Big float64 = 1e300;
+ Float32 float32 = 104.5
+ Float float = 105.5
+ ConstFloat = 106.5
+ Big float64 = 1e300
- String = "abc";
- Bool = true;
+ String = "abc"
+ Bool = true
)
var (
- a1 = Int8 * 100; // ERROR "overflow"
- a2 = Int8 * -1; // OK
- a3 = Int8 * 1000; // ERROR "overflow"
- a4 = Int8 * int8(1000); // ERROR "overflow"
- a5 = int8(Int8 * 1000); // ERROR "overflow"
- a6 = int8(Int8 * int8(1000)); // ERROR "overflow"
- a7 = Int8 - 2*Int8 - 2*Int8; // ERROR "overflow"
- a8 = Int8 * Const / 100; // ERROR "overflow"
- a9 = Int8 * (Const / 100); // OK
+ a1 = Int8 * 100 // ERROR "overflow"
+ a2 = Int8 * -1 // OK
+ a3 = Int8 * 1000 // ERROR "overflow"
+ a4 = Int8 * int8(1000) // ERROR "overflow"
+ a5 = int8(Int8 * 1000) // ERROR "overflow"
+ a6 = int8(Int8 * int8(1000)) // ERROR "overflow"
+ a7 = Int8 - 2*Int8 - 2*Int8 // ERROR "overflow"
+ a8 = Int8 * Const / 100 // ERROR "overflow"
+ a9 = Int8 * (Const / 100) // OK
- b1 = Uint8 * Uint8; // ERROR "overflow"
- b2 = Uint8 * -1; // ERROR "overflow"
- b3 = Uint8 - Uint8; // OK
- b4 = Uint8 - Uint8 - Uint8; // ERROR "overflow"
- b5 = uint8(^0); // ERROR "overflow"
- b6 = ^uint8(0); // OK
- b7 = uint8(Minus1); // ERROR "overflow"
- b8 = uint8(int8(-1)); // ERROR "overflow"
- b8a = uint8(-1); // ERROR "overflow"
- b9 byte = (1<<10) >> 8; // OK
- b10 byte = (1<<10); // ERROR "overflow"
- b11 byte = (byte(1)<<10) >> 8; // ERROR "overflow"
- b12 byte = 1000; // ERROR "overflow"
- b13 byte = byte(1000); // ERROR "overflow"
- b14 byte = byte(100) * byte(100); // ERROR "overflow"
- b15 byte = byte(100) * 100; // ERROR "overflow"
- b16 byte = byte(0) * 1000; // ERROR "overflow"
- b16a byte = 0 * 1000; // OK
- b17 byte = byte(0) * byte(1000); // ERROR "overflow"
- b18 byte = Uint8/0; // ERROR "division by zero"
+ b1 = Uint8 * Uint8 // ERROR "overflow"
+ b2 = Uint8 * -1 // ERROR "overflow"
+ b3 = Uint8 - Uint8 // OK
+ b4 = Uint8 - Uint8 - Uint8 // ERROR "overflow"
+ b5 = uint8(^0) // ERROR "overflow"
+ b6 = ^uint8(0) // OK
+ b7 = uint8(Minus1) // ERROR "overflow"
+ b8 = uint8(int8(-1)) // ERROR "overflow"
+ b8a = uint8(-1) // ERROR "overflow"
+ b9 byte = (1<<10) >> 8 // OK
+ b10 byte = (1<<10) // ERROR "overflow"
+ b11 byte = (byte(1)<<10) >> 8 // ERROR "overflow"
+ b12 byte = 1000 // ERROR "overflow"
+ b13 byte = byte(1000) // ERROR "overflow"
+ b14 byte = byte(100) * byte(100) // ERROR "overflow"
+ b15 byte = byte(100) * 100 // ERROR "overflow"
+ b16 byte = byte(0) * 1000 // ERROR "overflow"
+ b16a byte = 0 * 1000 // OK
+ b17 byte = byte(0) * byte(1000) // ERROR "overflow"
+ b18 byte = Uint8/0 // ERROR "division by zero"
- c1 float64 = Big;
- c2 float64 = Big*Big; // ERROR "overflow"
- c3 float64 = float64(Big)*Big; // ERROR "overflow"
- c4 = Big*Big; // ERROR "overflow"
- c5 = Big/0; // ERROR "division by zero"
+ c1 float64 = Big
+ c2 float64 = Big*Big // ERROR "overflow"
+ c3 float64 = float64(Big)*Big // ERROR "overflow"
+ c4 = Big*Big // ERROR "overflow"
+ c5 = Big/0 // ERROR "division by zero"
)
-func f(int);
+func f(int)
func main() {
- f(Int8); // ERROR "convert|wrong type|cannot"
- f(Minus1); // ERROR "convert|wrong type|cannot"
- f(Uint8); // ERROR "convert|wrong type|cannot"
- f(Const); // OK
- f(Float32); // ERROR "convert|wrong type|cannot"
- f(Float); // ERROR "convert|wrong type|cannot"
- f(ConstFloat); // ERROR "truncate"
- f(ConstFloat - 0.5); // OK
- f(Big); // ERROR "convert|wrong type|cannot"
- f(String); // ERROR "convert|wrong type|cannot|incompatible"
- f(Bool); // ERROR "convert|wrong type|cannot|incompatible"
+ f(Int8) // ERROR "convert|wrong type|cannot"
+ f(Minus1) // ERROR "convert|wrong type|cannot"
+ f(Uint8) // ERROR "convert|wrong type|cannot"
+ f(Const) // OK
+ f(Float32) // ERROR "convert|wrong type|cannot"
+ f(Float) // ERROR "convert|wrong type|cannot"
+ f(ConstFloat) // ERROR "truncate"
+ f(ConstFloat - 0.5) // OK
+ f(Big) // ERROR "convert|wrong type|cannot"
+ f(String) // ERROR "convert|wrong type|cannot|incompatible"
+ f(Bool) // ERROR "convert|wrong type|cannot|incompatible"
}
+
+const ptr = nil // ERROR "const.*nil"
diff --git a/test/const2.go b/test/const2.go
index 2ff71ee23..bea1b9912 100644
--- a/test/const2.go
+++ b/test/const2.go
@@ -7,6 +7,6 @@
package main
const (
- A int = 1;
+ A int = 1
B byte; // ERROR "type without expr|expected .=."
)
diff --git a/test/const3.go b/test/const3.go
index dd5c88958..9bba6ced0 100644
--- a/test/const3.go
+++ b/test/const3.go
@@ -26,4 +26,10 @@ func main() {
println("type info didn't propagate in const: got", s)
panic("fail")
}
+ x := uint(5)
+ y := float64(uint64(1)<<x) // used to fail to compile
+ if y != 32 {
+ println("wrong y", y)
+ panic("fail")
+ }
}
diff --git a/test/convert3.go b/test/convert3.go
index 5f1f0dd94..be68c95b3 100644
--- a/test/convert3.go
+++ b/test/convert3.go
@@ -13,8 +13,8 @@ var d1 chan<- int = c
var d2 = (chan<- int)(c)
var e *[4]int
-var f1 []int = e
-var f2 = []int(e)
+var f1 []int = e[0:]
+var f2 = []int(e[0:])
var g = []int(nil)
diff --git a/test/convlit.go b/test/convlit.go
index 22415bb32..94889d4a9 100644
--- a/test/convlit.go
+++ b/test/convlit.go
@@ -9,31 +9,31 @@ package main
// explicit conversion of constants is work in progress.
// the ERRORs in this block are debatable, but they're what
// the language spec says for now.
-var x1 = string(1);
-var x2 string = string(1);
-var x3 = int(1.5); // ERROR "convert|truncate"
-var x4 int = int(1.5); // ERROR "convert|truncate"
-var x5 = "a" + string(1);
-var x6 = int(1e100); // ERROR "overflow"
-var x7 = float(1e1000); // ERROR "overflow"
+var x1 = string(1)
+var x2 string = string(1)
+var x3 = int(1.5) // ERROR "convert|truncate"
+var x4 int = int(1.5) // ERROR "convert|truncate"
+var x5 = "a" + string(1)
+var x6 = int(1e100) // ERROR "overflow"
+var x7 = float(1e1000) // ERROR "overflow"
// implicit conversions merit scrutiny
-var s string;
-var bad1 string = 1; // ERROR "conver|incompatible|invalid|cannot"
-var bad2 = s + 1; // ERROR "conver|incompatible|invalid"
-var bad3 = s + 'a'; // ERROR "conver|incompatible|invalid"
-var bad4 = "a" + 1; // ERROR "literals|incompatible|convert|invalid"
-var bad5 = "a" + 'a'; // ERROR "literals|incompatible|convert|invalid"
+var s string
+var bad1 string = 1 // ERROR "conver|incompatible|invalid|cannot"
+var bad2 = s + 1 // ERROR "conver|incompatible|invalid"
+var bad3 = s + 'a' // ERROR "conver|incompatible|invalid"
+var bad4 = "a" + 1 // ERROR "literals|incompatible|convert|invalid"
+var bad5 = "a" + 'a' // ERROR "literals|incompatible|convert|invalid"
-var bad6 int = 1.5; // ERROR "convert|truncate"
-var bad7 int = 1e100; // ERROR "overflow"
-var bad8 float32 = 1e200; // ERROR "overflow"
+var bad6 int = 1.5 // ERROR "convert|truncate"
+var bad7 int = 1e100 // ERROR "overflow"
+var bad8 float32 = 1e200 // ERROR "overflow"
// but these implicit conversions are okay
-var good1 string = "a";
-var good2 int = 1.0;
-var good3 int = 1e9;
-var good4 float = 1e20;
+var good1 string = "a"
+var good2 int = 1.0
+var good3 int = 1e9
+var good4 float = 1e20
// explicit conversion of string is okay
var _ = []int("abc")
diff --git a/test/copy.go b/test/copy.go
index 037d3f41f..0b5bddbed 100644
--- a/test/copy.go
+++ b/test/copy.go
@@ -23,6 +23,15 @@ var input32 = make([]uint32, N)
var output32 = make([]uint32, N)
var input64 = make([]uint64, N)
var output64 = make([]uint64, N)
+var inputS string
+var outputS = make([]uint8, N)
+
+type my8 []uint8
+type my16 []uint16
+type my32 []uint32
+type my32b []uint32
+type my64 []uint64
+type myS string
func u8(i int) uint8 {
i = 'a' + i%26
@@ -64,6 +73,7 @@ func reset() {
for i := range input8 {
input8[i] = u8(in)
output8[i] = u8(out)
+ outputS[i] = u8(out)
input16[i] = u16(in)
output16[i] = u16(out)
input32[i] = u32(in)
@@ -73,6 +83,7 @@ func reset() {
in++
out++
}
+ inputS = string(input8)
}
func clamp(n int) int {
@@ -95,13 +106,15 @@ func ncopied(length, in, out int) int {
func doAllSlices(length, in, out int) {
reset()
- n := copy(output8[out:clamp(out+length)], input8[in:clamp(in+length)])
+ n := copy(my8(output8[out:clamp(out+length)]), input8[in:clamp(in+length)])
verify8(length, in, out, n)
- n = copy(output16[out:clamp(out+length)], input16[in:clamp(in+length)])
+ n = copy(my8(outputS[out:clamp(out+length)]), myS(inputS[in:clamp(in+length)]))
+ verifyS(length, in, out, n)
+ n = copy(my16(output16[out:clamp(out+length)]), input16[in:clamp(in+length)])
verify16(length, in, out, n)
- n = copy(output32[out:clamp(out+length)], input32[in:clamp(in+length)])
+ n = copy(my32(output32[out:clamp(out+length)]), my32b(input32[in:clamp(in+length)]))
verify32(length, in, out, n)
- n = copy(output64[out:clamp(out+length)], input64[in:clamp(in+length)])
+ n = copy(my64(output64[out:clamp(out+length)]), input64[in:clamp(in+length)])
verify64(length, in, out, n)
}
@@ -145,6 +158,46 @@ func verify8(length, in, out, m int) {
}
}
+func badS(state string, i, length, in, out int) {
+ fmt.Printf("%s bad(%d %d %d): %c not %c:\n\t%s\n\t%s\n",
+ state,
+ length, in, out,
+ outputS[i],
+ uint8(i+13),
+ inputS, outputS)
+ os.Exit(1)
+}
+
+func verifyS(length, in, out, m int) {
+ n := ncopied(length, in, out)
+ if m != n {
+ fmt.Printf("count bad(%d %d %d): %d not %d\n", length, in, out, m, n)
+ return
+ }
+ // before
+ var i int
+ for i = 0; i < out; i++ {
+ if outputS[i] != u8(i+13) {
+ badS("beforeS", i, length, in, out)
+ return
+ }
+ }
+ // copied part
+ for ; i < out+n; i++ {
+ if outputS[i] != u8(i+in-out) {
+ badS("copiedS", i, length, in, out)
+ return
+ }
+ }
+ // after
+ for ; i < len(outputS); i++ {
+ if outputS[i] != u8(i+13) {
+ badS("afterS", i, length, in, out)
+ return
+ }
+ }
+}
+
func bad16(state string, i, length, in, out int) {
fmt.Printf("%s bad(%d %d %d): %x not %x:\n\t%v\n\t%v\n",
state,
diff --git a/test/ddd.go b/test/ddd.go
index c9949c36e..b95d6e883 100644
--- a/test/ddd.go
+++ b/test/ddd.go
@@ -14,13 +14,13 @@ func sum(args ...int) int {
return s
}
-func sumC(args ...int) int { return func() int { return sum(args) }() }
+func sumC(args ...int) int { return func() int { return sum(args...) }() }
-var sumD = func(args ...int) int { return sum(args) }
+var sumD = func(args ...int) int { return sum(args...) }
-var sumE = func() func(...int) int { return func(args ...int) int { return sum(args) } }()
+var sumE = func() func(...int) int { return func(args ...int) int { return sum(args...) } }()
-var sumF = func(args ...int) func() int { return func() int { return sum(args) } }
+var sumF = func(args ...int) func() int { return func() int { return sum(args...) } }
func sumA(args []int) int {
s := 0
@@ -30,10 +30,14 @@ func sumA(args []int) int {
return s
}
-func sum2(args ...int) int { return 2 * sum(args) }
+func sumB(args []int) int { return sum(args...) }
+
+func sum2(args ...int) int { return 2 * sum(args...) }
func sum3(args ...int) int { return 3 * sumA(args) }
+func sum4(args ...int) int { return 4 * sumB(args) }
+
func intersum(args ...interface{}) int {
s := 0
for _, v := range args {
@@ -46,9 +50,9 @@ type T []T
func ln(args ...T) int { return len(args) }
-func ln2(args ...T) int { return 2 * ln(args) }
+func ln2(args ...T) int { return 2 * ln(args...) }
-func (*T) Sum(args ...int) int { return sum(args) }
+func (*T) Sum(args ...int) int { return sum(args...) }
type U struct {
*T
@@ -119,6 +123,22 @@ func main() {
println("sum 9", x)
panic("fail")
}
+ if x := sum4(1, 2, 3); x != 4*6 {
+ println("sum 6", x)
+ panic("fail")
+ }
+ if x := sum4(); x != 4*0 {
+ println("sum 0", x)
+ panic("fail")
+ }
+ if x := sum4(10); x != 4*10 {
+ println("sum 10", x)
+ panic("fail")
+ }
+ if x := sum4(1, 8); x != 4*9 {
+ println("sum 9", x)
+ panic("fail")
+ }
if x := intersum(1, 2, 3); x != 6 {
println("intersum 6", x)
panic("fail")
diff --git a/test/ddd1.go b/test/ddd1.go
index 6f714c078..fcd32c282 100644
--- a/test/ddd1.go
+++ b/test/ddd1.go
@@ -6,6 +6,8 @@
package main
+import "unsafe"
+
func sum(args ...int) int { return 0 }
var (
@@ -26,3 +28,20 @@ var (
_ = funny(nil, nil)
_ = funny([]T{}) // ok because []T{} is a T; passes []T{[]T{}}
)
+
+func bad(args ...int) {
+ print(1, 2, args...) // ERROR "[.][.][.]"
+ println(args...) // ERROR "[.][.][.]"
+ ch := make(chan int)
+ close(ch...) // ERROR "[.][.][.]"
+ _ = len(args...) // ERROR "[.][.][.]"
+ _ = closed(ch...) // ERROR "[.][.][.]"
+ _ = new(int...) // ERROR "[.][.][.]"
+ n := 10
+ _ = make([]byte, n...) // ERROR "[.][.][.]"
+ // TODO(rsc): enable after gofmt bug is fixed
+ // _ = make([]byte, 10 ...) // error "[.][.][.]"
+ var x int
+ _ = unsafe.Pointer(&x...) // ERROR "[.][.][.]"
+ _ = unsafe.Sizeof(x...) // ERROR "[.][.][.]"
+}
diff --git a/test/decl.go b/test/decl.go
index 6e8cbab20..c31082bcf 100644
--- a/test/decl.go
+++ b/test/decl.go
@@ -13,28 +13,28 @@ func f2() (float, int) { return 1, 2 }
func f3() (float, int, string) { return 1, 2, "3" }
func x() (s string) {
- a, b, s := f3();
- _, _ = a, b;
+ a, b, s := f3()
+ _, _ = a, b
return // tests that result var is in scope for redeclaration
}
func main() {
- i, f, s := f3();
- j, f := f2(); // redeclare f
- k := f1();
- m, g, s := f3();
- m, h, s := f3();
+ i, f, s := f3()
+ j, f := f2() // redeclare f
+ k := f1()
+ m, g, s := f3()
+ m, h, s := f3()
{
// new block should be ok.
- i, f, s := f3();
- j, f := f2(); // redeclare f
- k := f1();
- m, g, s := f3();
- m, h, s := f3();
- _, _, _, _, _, _, _, _, _ = i, f, s, j, k, m, g, s, h;
+ i, f, s := f3()
+ j, f := f2() // redeclare f
+ k := f1()
+ m, g, s := f3()
+ m, h, s := f3()
+ _, _, _, _, _, _, _, _, _ = i, f, s, j, k, m, g, s, h
}
if x() != "3" {
- println("x() failed");
+ println("x() failed")
}
- _, _, _, _, _, _, _, _, _ = i, f, s, j, k, m, g, s, h;
+ _, _, _, _, _, _, _, _, _ = i, f, s, j, k, m, g, s, h
}
diff --git a/test/declbad.go b/test/declbad.go
index 5fbb04ab5..269ebdefb 100644
--- a/test/declbad.go
+++ b/test/declbad.go
@@ -15,44 +15,44 @@ func f3() (float, int, string) { return 1, 2, "3" }
func main() {
{
// simple redeclaration
- i := f1();
- i := f1(); // ERROR "redeclared|no new"
- _ = i;
+ i := f1()
+ i := f1() // ERROR "redeclared|no new"
+ _ = i
}
{
// change of type for f
- i, f, s := f3();
- f, g, t := f3(); // ERROR "redeclared|cannot assign|incompatible"
- _, _, _, _, _ = i, f, s, g, t;
+ i, f, s := f3()
+ f, g, t := f3() // ERROR "redeclared|cannot assign|incompatible"
+ _, _, _, _, _ = i, f, s, g, t
}
{
// change of type for i
- i, f, s := f3();
- j, i, t := f3(); // ERROR "redeclared|cannot assign|incompatible"
- _, _, _, _, _ = i, f, s, j, t;
+ i, f, s := f3()
+ j, i, t := f3() // ERROR "redeclared|cannot assign|incompatible"
+ _, _, _, _, _ = i, f, s, j, t
}
{
// no new variables
- i, f, s := f3();
- i, f := f2(); // ERROR "redeclared|no new"
- _, _, _ = i, f, s;
+ i, f, s := f3()
+ i, f := f2() // ERROR "redeclared|no new"
+ _, _, _ = i, f, s
}
{
// single redeclaration
- i, f, s := f3();
- i := f1(); // ERROR "redeclared|no new|incompatible"
- _, _, _ = i, f, s;
+ i, f, s := f3()
+ i := f1() // ERROR "redeclared|no new|incompatible"
+ _, _, _ = i, f, s
}
// double redeclaration
{
- i, f, s := f3();
- i, f := f2(); // ERROR "redeclared|no new"
- _, _, _ = i, f, s;
+ i, f, s := f3()
+ i, f := f2() // ERROR "redeclared|no new"
+ _, _, _ = i, f, s
}
{
// triple redeclaration
- i, f, s := f3();
- i, f, s := f3(); // ERROR "redeclared|no new"
- _, _, _ = i, f, s;
+ i, f, s := f3()
+ i, f, s := f3() // ERROR "redeclared|no new"
+ _, _, _ = i, f, s
}
}
diff --git a/test/defer.go b/test/defer.go
index 8b8312235..bef8fbe26 100644
--- a/test/defer.go
+++ b/test/defer.go
@@ -26,7 +26,7 @@ func test1() {
}
}
-func addDotDotDot(v ...interface{}) { result += fmt.Sprint(v) }
+func addDotDotDot(v ...interface{}) { result += fmt.Sprint(v...) }
func test2helper() {
for i := 0; i < 10; i++ {
diff --git a/test/env.go b/test/env.go
index b12a72973..16b207644 100644
--- a/test/env.go
+++ b/test/env.go
@@ -1,4 +1,3 @@
-// [ $GOOS != nacl ] || exit 0 # NaCl runner does not expose environment
// $G $F.go && $L $F.$A && ./$A.out
// Copyright 2009 The Go Authors. All rights reserved.
@@ -10,18 +9,18 @@ package main
import os "os"
func main() {
- ga, e0 := os.Getenverror("GOARCH");
+ ga, e0 := os.Getenverror("GOARCH")
if e0 != nil {
- print("$GOARCH: ", e0.String(), "\n");
- os.Exit(1);
+ print("$GOARCH: ", e0.String(), "\n")
+ os.Exit(1)
}
if ga != "amd64" && ga != "386" && ga != "arm" {
- print("$GOARCH=", ga, "\n");
- os.Exit(1);
+ print("$GOARCH=", ga, "\n")
+ os.Exit(1)
}
- xxx, e1 := os.Getenverror("DOES_NOT_EXIST");
+ xxx, e1 := os.Getenverror("DOES_NOT_EXIST")
if e1 != os.ENOENV {
- print("$DOES_NOT_EXIST=", xxx, "; err = ", e1.String(), "\n");
- os.Exit(1);
+ print("$DOES_NOT_EXIST=", xxx, "; err = ", e1.String(), "\n")
+ os.Exit(1)
}
}
diff --git a/test/eof.go b/test/eof.go
new file mode 100644
index 000000000..81f9fd028
--- /dev/null
+++ b/test/eof.go
@@ -0,0 +1,9 @@
+// $G $D/$F.go
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// No newline at the end of this file.
+
+package main \ No newline at end of file
diff --git a/test/syntax/slice.go b/test/eof1.go
index 7675ca187..c39a3cfdb 100644
--- a/test/syntax/slice.go
+++ b/test/eof1.go
@@ -1,4 +1,4 @@
-// errchk $G -e $D/$F.go
+// $G $D/$F.go
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
@@ -6,4 +6,4 @@
package main
-var x = y[:z] // ERROR "missing lower bound in slice expression|undefined"
+// No newline at the end of this comment. \ No newline at end of file
diff --git a/test/errchk b/test/errchk
index 115aa7be0..b0edd7a6b 100755
--- a/test/errchk
+++ b/test/errchk
@@ -3,30 +3,38 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-# This script checks that the compilers emits the errors which we
-# expect. Usage: errchk COMPILER [OPTS] SOURCEFILE. This will run
-# the command COMPILER [OPTS] SOURCEFILE. The compilation is expected
-# to fail; if it succeeds, this script will report an error. The
-# stderr output of the compiler will be matched against comments in
-# SOURCEFILE. For each line of the source file which should generate
-# an error, there should be a comment of the form // ERROR "regexp".
-# If the compiler generates an error for a line which has no such
-# commnt, this script will report an error. Likewise if the compiler
-# does not generate an error for a line which has a comment, or if the
-# error message does not match the <regexp>. The <regexp> syntax
-# is Perl but its best to stick to egrep.
+# This script checks that the compilers emit the errors which we expect.
+# Usage: errchk COMPILER [OPTS] SOURCEFILES. This will run the command
+# COMPILER [OPTS] SOURCEFILES. The compilation is expected to fail; if
+# it succeeds, this script will report an error. The stderr output of
+# the compiler will be matched against comments in SOURCEFILES. For each
+# line of the source files which should generate an error, there should
+# be a comment of the form // ERROR "regexp". If the compiler generates
+# an error for a line which has no such comment, this script will report
+# an error. Likewise if the compiler does not generate an error for a
+# line which has a comment, or if the error message does not match the
+# <regexp>. The <regexp> syntax is Perl but its best to stick to egrep.
use POSIX;
if(@ARGV < 1) {
- print STDERR "Usage: errchk COMPILER [OPTS] SOURCEFILE\n";
+ print STDERR "Usage: errchk COMPILER [OPTS] SOURCEFILES\n";
exit 1;
}
-$file = $ARGV[@ARGV-1];
-open(SRC, $file) || die "BUG: errchk: open $file: $!";
-@src = <SRC>;
-close(SRC);
+# Grab SOURCEFILES
+foreach(reverse 0 .. @ARGV-1) {
+ unless($ARGV[$_] =~ /\.go$/) {
+ @file = @ARGV[$_+1 .. @ARGV-1];
+ last;
+ }
+}
+
+foreach $file (@file) {
+ open(SRC, $file) || die "BUG: errchk: open $file: $!";
+ $src{$file} = [<SRC>];
+ close(SRC);
+}
# Run command
$cmd = join(' ', @ARGV);
@@ -57,35 +65,45 @@ sub bug() {
}
}
-$line = 0;
-foreach $src (@src) {
- $line++;
- next unless $src =~ m|// ERROR (.*)|;
- $regexp = $1;
- if($regexp !~ /^"([^"]*)"/) {
- print STDERR "$file:$line: malformed regexp\n";
- next;
- }
- $regexp = $1;
-
- @errmsg = grep { /$file:$line:/ } @out;
- @out = grep { !/$file:$line:/ } @out;
- if(@errmsg == 0) {
- bug();
- print STDERR "errchk: $file:$line: missing expected error: '$regexp'\n";
- next;
- }
- @match = grep { /$regexp/ } @errmsg;
- if(@match == 0) {
- bug();
- print STDERR "errchk: $file:$line: error message does not match '$regexp'\n";
- next;
+sub chk {
+ my $file = shift;
+ my $line = 0;
+ my $regexp;
+ my @errmsg;
+ my @match;
+ foreach my $src (@{$src{$file}}) {
+ $line++;
+ next unless $src =~ m|// (GC_)?ERROR (.*)|;
+ $regexp = $2;
+ if($regexp !~ /^"([^"]*)"/) {
+ print STDERR "$file:$line: malformed regexp\n";
+ next;
+ }
+ $regexp = $1;
+
+ @errmsg = grep { /$file:$line[:[]/ } @out;
+ @out = grep { !/$file:$line[:[]/ } @out;
+ if(@errmsg == 0) {
+ bug();
+ print STDERR "errchk: $file:$line: missing expected error: '$regexp'\n";
+ next;
+ }
+ @match = grep { /$regexp/ } @errmsg;
+ if(@match == 0) {
+ bug();
+ print STDERR "errchk: $file:$line: error message does not match '$regexp'\n";
+ next;
+ }
}
}
+foreach $file (@file) {
+ chk($file)
+}
+
if(@out != 0) {
bug();
- print STDERR "errchk: $file: unmatched error messages:\n";
+ print STDERR "errchk: unmatched error messages:\n";
print STDERR "==================================================\n";
print STDERR @out;
print STDERR "==================================================\n";
diff --git a/test/escape.go b/test/escape.go
index 19c08a527..d4d844704 100644
--- a/test/escape.go
+++ b/test/escape.go
@@ -14,142 +14,142 @@ package main
var bad = false
-var allptr = make([]*int, 0, 100);
+var allptr = make([]*int, 0, 100)
func noalias(p, q *int, s string) {
- n := len(allptr);
- *p = -(n+1);
- *q = -(n+2);
- allptr = allptr[0:n+2];
- allptr[n] = p;
- allptr[n+1] = q;
- n += 2;
+ n := len(allptr)
+ *p = -(n+1)
+ *q = -(n+2)
+ allptr = allptr[0:n+2]
+ allptr[n] = p
+ allptr[n+1] = q
+ n += 2
for i := 0; i < n; i++ {
if allptr[i] != nil && *allptr[i] != -(i+1) {
- println("aliased pointers", -(i+1), *allptr[i], "after", s);
- allptr[i] = nil;
- bad = true;
+ println("aliased pointers", -(i+1), *allptr[i], "after", s)
+ allptr[i] = nil
+ bad = true
}
}
}
func val(p, q *int, v int, s string) {
if *p != v {
- println("wrong value want", v, "got", *p, "after", s);
- bad = true;
+ println("wrong value want", v, "got", *p, "after", s)
+ bad = true
}
if *q != v+1 {
- println("wrong value want", v+1, "got", *q, "after", s);
- bad = true;
+ println("wrong value want", v+1, "got", *q, "after", s)
+ bad = true
}
}
func chk(p, q *int, v int, s string) {
- val(p, q, v, s);
- noalias(p, q, s);
+ val(p, q, v, s)
+ noalias(p, q, s)
}
func chkalias(p, q *int, v int, s string) {
if p != q {
- println("want aliased pointers but got different after", s);
+ println("want aliased pointers but got different after", s)
}
if *q != v+1 {
- println("wrong value want", v+1, "got", *q, "after", s);
+ println("wrong value want", v+1, "got", *q, "after", s)
}
}
func i_escapes(x int) *int {
- var i int;
- i = x;
- return &i;
+ var i int
+ i = x
+ return &i
}
func j_escapes(x int) *int {
- var j int = x;
- j = x;
- return &j;
+ var j int = x
+ j = x
+ return &j
}
func k_escapes(x int) *int {
- k := x;
- return &k;
+ k := x
+ return &k
}
func in_escapes(x int) *int {
- return &x;
+ return &x
}
func send(c chan int, x int) {
- c <- x;
+ c <- x
}
func select_escapes(x int) *int {
- c := make(chan int);
- go send(c, x);
+ c := make(chan int)
+ go send(c, x)
select {
case req := <-c:
- return &req;
+ return &req
}
- return nil;
+ return nil
}
func select_escapes1(x int, y int) (*int, *int) {
- c := make(chan int);
- var a [2]int;
- var p [2]*int;
- a[0] = x;
- a[1] = y;
+ c := make(chan int)
+ var a [2]int
+ var p [2]*int
+ a[0] = x
+ a[1] = y
for i := 0; i < 2; i++ {
- go send(c, a[i]);
+ go send(c, a[i])
select {
case req := <-c:
- p[i] = &req;
+ p[i] = &req
}
}
return p[0], p[1]
}
func range_escapes(x int) *int {
- var a [1]int;
- a[0] = x;
+ var a [1]int
+ a[0] = x
for _, v := range a {
- return &v;
+ return &v
}
- return nil;
+ return nil
}
// *is* aliased
func range_escapes2(x, y int) (*int, *int) {
- var a [2]int;
- var p [2]*int;
- a[0] = x;
- a[1] = y;
+ var a [2]int
+ var p [2]*int
+ a[0] = x
+ a[1] = y
for k, v := range a {
- p[k] = &v;
+ p[k] = &v
}
return p[0], p[1]
}
// *is* aliased
func for_escapes2(x int, y int) (*int, *int) {
- var p [2]*int;
- n := 0;
+ var p [2]*int
+ n := 0
for i := x; n < 2; i = y {
- p[n] = &i;
- n++;
+ p[n] = &i
+ n++
}
return p[0], p[1]
}
func out_escapes(i int) (x int, p *int) {
x = i
- p = &x; // ERROR "address of out parameter"
- return;
+ p = &x // ERROR "address of out parameter"
+ return
}
func out_escapes_2(i int) (x int, p *int) {
x = i
- return x, &x; // ERROR "address of out parameter"
+ return x, &x // ERROR "address of out parameter"
}
func defer1(i int) (x int) {
@@ -160,40 +160,40 @@ func defer1(i int) (x int) {
}
func main() {
- p, q := i_escapes(1), i_escapes(2);
- chk(p, q, 1, "i_escapes");
+ p, q := i_escapes(1), i_escapes(2)
+ chk(p, q, 1, "i_escapes")
- p, q = j_escapes(3), j_escapes(4);
- chk(p, q, 3, "j_escapes");
+ p, q = j_escapes(3), j_escapes(4)
+ chk(p, q, 3, "j_escapes")
- p, q = k_escapes(5), k_escapes(6);
- chk(p, q, 5, "k_escapes");
+ p, q = k_escapes(5), k_escapes(6)
+ chk(p, q, 5, "k_escapes")
- p, q = in_escapes(7), in_escapes(8);
- chk(p, q, 7, "in_escapes");
+ p, q = in_escapes(7), in_escapes(8)
+ chk(p, q, 7, "in_escapes")
- p, q = select_escapes(9), select_escapes(10);
- chk(p, q, 9, "select_escapes");
+ p, q = select_escapes(9), select_escapes(10)
+ chk(p, q, 9, "select_escapes")
- p, q = select_escapes1(11, 12);
- chk(p, q, 11, "select_escapes1");
+ p, q = select_escapes1(11, 12)
+ chk(p, q, 11, "select_escapes1")
- p, q = range_escapes(13), range_escapes(14);
- chk(p, q, 13, "range_escapes");
+ p, q = range_escapes(13), range_escapes(14)
+ chk(p, q, 13, "range_escapes")
- p, q = range_escapes2(101, 102);
- chkalias(p, q, 101, "range_escapes2");
+ p, q = range_escapes2(101, 102)
+ chkalias(p, q, 101, "range_escapes2")
- p, q = for_escapes2(103, 104);
- chkalias(p, q, 103, "for_escapes2");
+ p, q = for_escapes2(103, 104)
+ chkalias(p, q, 103, "for_escapes2")
_, p = out_escapes(15)
- _, q = out_escapes(16);
- chk(p, q, 15, "out_escapes");
+ _, q = out_escapes(16)
+ chk(p, q, 15, "out_escapes")
_, p = out_escapes_2(17)
- _, q = out_escapes_2(18);
- chk(p, q, 17, "out_escapes_2");
+ _, q = out_escapes_2(18)
+ chk(p, q, 17, "out_escapes_2")
x := defer1(20)
if x != 20 {
@@ -202,6 +202,6 @@ func main() {
}
if bad {
- panic("BUG: no escape");
+ panic("BUG: no escape")
}
}
diff --git a/test/fixedbugs/bug045.go b/test/fixedbugs/bug045.go
index d8a712c6d..94888c40e 100644
--- a/test/fixedbugs/bug045.go
+++ b/test/fixedbugs/bug045.go
@@ -13,7 +13,7 @@ type T struct {
func main() {
var ta []*T;
- ta = new([1]*T);
+ ta = new([1]*T)[0:];
ta[0] = nil;
}
/*
diff --git a/test/fixedbugs/bug059.go b/test/fixedbugs/bug059.go
index b190d4f26..6a77367d6 100644
--- a/test/fixedbugs/bug059.go
+++ b/test/fixedbugs/bug059.go
@@ -25,7 +25,7 @@ func main() {
as := new([2]string);
as[0] = "0";
as[1] = "1";
- m["0"] = as;
+ m["0"] = as[0:];
a := m["0"];
a[0] = "x";
diff --git a/test/fixedbugs/bug146.go b/test/fixedbugs/bug146.go
index bfb7529d6..16324c741 100644
--- a/test/fixedbugs/bug146.go
+++ b/test/fixedbugs/bug146.go
@@ -9,7 +9,7 @@ package main
func main() {
type Slice []byte;
a := [...]byte{ 0 };
- b := Slice(&a); // This should be OK.
+ b := Slice(a[0:]); // This should be OK.
c := Slice(a); // ERROR "invalid|illegal|cannot"
_, _ = b, c;
}
diff --git a/test/fixedbugs/bug195.go b/test/fixedbugs/bug195.go
index 27bbbd354..65ab02a03 100644
--- a/test/fixedbugs/bug195.go
+++ b/test/fixedbugs/bug195.go
@@ -19,9 +19,9 @@ type I4 interface {
}
type I5 interface {
- I6
+ I6 // GCCGO_ERROR "interface"
}
type I6 interface {
- I5 // ERROR "interface"
+ I5 // GC_ERROR "interface"
}
diff --git a/test/fixedbugs/bug206.go b/test/fixedbugs/bug206.go
index 3879e8cbd..7efc0b14a 100644
--- a/test/fixedbugs/bug206.go
+++ b/test/fixedbugs/bug206.go
@@ -10,14 +10,14 @@ import "go/ast";
func g(list []ast.Expr) {
n := len(list)-1;
- println(list[n].Pos().Line);
+ println(list[n].Pos());
}
// f is the same as g except that the expression assigned to n is inlined.
func f(list []ast.Expr) {
// n := len(list)-1;
- println(list[len(list)-1 /* n */].Pos().Line);
+ println(list[len(list)-1 /* n */].Pos());
}
diff --git a/test/fixedbugs/bug243.go b/test/fixedbugs/bug243.go
index 30dbc4ed4..236c14402 100644
--- a/test/fixedbugs/bug243.go
+++ b/test/fixedbugs/bug243.go
@@ -1,4 +1,3 @@
-// [ $GOOS != nacl ] || exit 0 # no network
// $G $D/$F.go && $L $F.$A && ./$A.out
// Copyright 2010 The Go Authors. All rights reserved.
@@ -8,22 +7,19 @@
package main
import (
- "fmt"
"net"
- "os"
)
func main() {
- os.Stdout.Close()
var listen, _ = net.Listen("tcp", "127.0.0.1:0")
go func() {
for {
var conn, _ = listen.Accept()
- fmt.Println("[SERVER] ", conn)
+ _ = conn
}
}()
var conn, _ = net.Dial("tcp", "", listen.Addr().String())
- fmt.Println("[CLIENT] ", conn)
+ _ = conn
}
diff --git a/test/fixedbugs/bug251.go b/test/fixedbugs/bug251.go
index 37dec9055..c94ad2abe 100644
--- a/test/fixedbugs/bug251.go
+++ b/test/fixedbugs/bug251.go
@@ -8,14 +8,14 @@ package main
type I1 interface {
m() I2
- I2
+ I2 // GCCGO_ERROR "loop|interface"
}
type I2 interface {
- I1 // ERROR "loop|interface"
+ I1 // GC_ERROR "loop|interface"
}
-var i1 I1 = i2 // ERROR "missing m method|need type assertion"
+var i1 I1 = i2 // GC_ERROR "missing m method|need type assertion"
var i2 I2
var i2a I2 = i1
diff --git a/test/fixedbugs/bug252.go b/test/fixedbugs/bug252.go
index bd11b86eb..5615f84fa 100644
--- a/test/fixedbugs/bug252.go
+++ b/test/fixedbugs/bug252.go
@@ -7,9 +7,9 @@
package main
func f(args ...int) {
- g(args) // ERROR "[.][.][.] mismatch"
+ g(args) // ERROR "[.][.][.]"
}
func g(args ...interface{}) {
- f(args) // ERROR "[.][.][.] mismatch"
+ f(args) // ERROR "[.][.][.]"
}
diff --git a/test/fixedbugs/bug255.go b/test/fixedbugs/bug255.go
index 4003a780c..44427cfdb 100644
--- a/test/fixedbugs/bug255.go
+++ b/test/fixedbugs/bug255.go
@@ -9,7 +9,7 @@ package main
var a [10]int // ok
var b [1e1]int // ok
var c [1.5]int // ERROR "truncated"
-var d ["abc"]int // ERROR "invalid array bound"
-var e [nil]int // ERROR "invalid array bound"
-var f [e]int // ERROR "invalid array bound"
+var d ["abc"]int // ERROR "invalid array bound|not numeric"
+var e [nil]int // ERROR "invalid array bound|not numeric"
+var f [e]int // ERROR "invalid array bound|not constant"
var g [1<<65]int // ERROR "overflows"
diff --git a/test/bugs/bug260.go b/test/fixedbugs/bug260.go
index 6a6331e65..34757c70e 100644
--- a/test/bugs/bug260.go
+++ b/test/fixedbugs/bug260.go
@@ -10,9 +10,15 @@ import (
"strconv"
)
-type T1 struct { x uint8 }
-type T2 struct { x uint16 }
-type T4 struct { x uint32 }
+type T1 struct {
+ x uint8
+}
+type T2 struct {
+ x uint16
+}
+type T4 struct {
+ x uint32
+}
func main() {
report := len(os.Args) > 1
@@ -20,7 +26,7 @@ func main() {
var b1 [10]T1
a0, _ := strconv.Btoui64(fmt.Sprintf("%p", &b1[0])[2:], 16)
a1, _ := strconv.Btoui64(fmt.Sprintf("%p", &b1[1])[2:], 16)
- if a1 != a0 + 1 {
+ if a1 != a0+1 {
fmt.Println("FAIL")
if report {
fmt.Println("alignment should be 1, is", a1-a0)
@@ -30,7 +36,7 @@ func main() {
var b2 [10]T2
a0, _ = strconv.Btoui64(fmt.Sprintf("%p", &b2[0])[2:], 16)
a1, _ = strconv.Btoui64(fmt.Sprintf("%p", &b2[1])[2:], 16)
- if a1 != a0 + 2 {
+ if a1 != a0+2 {
if status == 0 {
fmt.Println("FAIL")
status = 1
@@ -42,7 +48,7 @@ func main() {
var b4 [10]T4
a0, _ = strconv.Btoui64(fmt.Sprintf("%p", &b4[0])[2:], 16)
a1, _ = strconv.Btoui64(fmt.Sprintf("%p", &b4[1])[2:], 16)
- if a1 != a0 + 4 {
+ if a1 != a0+4 {
if status == 0 {
fmt.Println("FAIL")
status = 1
diff --git a/test/fixedbugs/bug273.go b/test/fixedbugs/bug273.go
index ff8f1c6af..816f69e8f 100644
--- a/test/fixedbugs/bug273.go
+++ b/test/fixedbugs/bug273.go
@@ -15,6 +15,8 @@ var bug = false
var minus1 = -1
var big int64 = 10 | 1<<32
+var g1 []int
+
func shouldfail(f func(), desc string) {
defer func() { recover() }()
f()
@@ -26,52 +28,56 @@ func shouldfail(f func(), desc string) {
}
func badlen() {
- _ = make([]int, minus1)
+ g1 = make([]int, minus1)
}
func biglen() {
- _ = make([]int, big)
+ g1 = make([]int, big)
}
func badcap() {
- _ = make([]int, 10, minus1)
+ g1 = make([]int, 10, minus1)
}
func badcap1() {
- _ = make([]int, 10, 5)
+ g1 = make([]int, 10, 5)
}
func bigcap() {
- _ = make([]int, 10, big)
+ g1 = make([]int, 10, big)
}
const (
addrBits = 8*uint(unsafe.Sizeof((*byte)(nil)))
sh = addrBits/2 - 2
)
+var g2 [][1<<sh][1<<sh]byte
func overflow() {
- _ = make([][1<<sh][1<<sh]byte, 64)
+ g2 = make([][1<<sh][1<<sh]byte, 64)
}
+var g3 map[int]int
func badmapcap() {
- _ = make(map[int]int, minus1)
+ g3 = make(map[int]int, minus1)
}
func bigmapcap() {
- _ = make(map[int]int, big)
+ g3 = make(map[int]int, big)
}
+var g4 chan int
func badchancap() {
- _ = make(chan int, minus1)
+ g4 = make(chan int, minus1)
}
func bigchancap() {
- _ = make(chan int, big)
+ g4 = make(chan int, big)
}
+var g5 chan [1<<15]byte
func overflowchan() {
if addrBits == 32 {
- _ = make(chan [1<<15]byte, 1<<20)
+ g5 = make(chan [1<<15]byte, 1<<20)
} else {
// cannot overflow on 64-bit, because
// int is 32 bits and max chan value size
diff --git a/test/bugs/bug274.go b/test/fixedbugs/bug274.go
index 621f31eed..621f31eed 100644
--- a/test/bugs/bug274.go
+++ b/test/fixedbugs/bug274.go
diff --git a/test/fixedbugs/bug278.go b/test/fixedbugs/bug278.go
index 8c804cfe4..3699b9a14 100644
--- a/test/fixedbugs/bug278.go
+++ b/test/fixedbugs/bug278.go
@@ -15,9 +15,9 @@ func f() [10]int {
var m map[int][10]int
func main() {
- f()[1] = 2 // ERROR "cannot"
- f()[2:3][0] = 4 // ERROR "cannot"
+ f()[1] = 2 // ERROR "cannot|invalid"
+ f()[2:3][0] = 4 // ERROR "cannot|addressable"
var x = "abc"
- x[2] = 3 // ERROR "cannot"
- m[0][5] = 6 // ERROR "cannot"
+ x[2] = 3 // ERROR "cannot|invalid"
+ m[0][5] = 6 // ERROR "cannot|invalid"
}
diff --git a/test/fixedbugs/bug284.go b/test/fixedbugs/bug284.go
index 9e9949bed..bcf161e3d 100644
--- a/test/fixedbugs/bug284.go
+++ b/test/fixedbugs/bug284.go
@@ -30,12 +30,12 @@ func main() {
var a2 A2
a0 = a0
a0 = a1
- a0 = [3]int(a2) // ERROR "cannot"
+ a0 = [3]int(a2) // ERROR "cannot|invalid"
a1 = a0
a1 = a1
- a1 = A1(a2) // ERROR "cannot"
- a2 = A2(a0) // ERROR "cannot"
- a2 = A2(a1) // ERROR "cannot"
+ a1 = A1(a2) // ERROR "cannot|invalid"
+ a2 = A2(a0) // ERROR "cannot|invalid"
+ a2 = A2(a1) // ERROR "cannot|invalid"
a2 = a2
type S1 struct {
@@ -53,12 +53,12 @@ func main() {
s0 = s1
s0 = struct {
x int
- }(s2) // ERROR "cannot"
+ }(s2) // ERROR "cannot|invalid"
s1 = s0
s1 = s1
- s1 = S1(s2) // ERROR "cannot"
- s2 = S2(s0) // ERROR "cannot"
- s2 = S2(s1) // ERROR "cannot"
+ s1 = S1(s2) // ERROR "cannot|invalid"
+ s2 = S2(s0) // ERROR "cannot|invalid"
+ s2 = S2(s1) // ERROR "cannot|invalid"
s2 = s2
type P1 *int
@@ -68,12 +68,12 @@ func main() {
var p2 P2
p0 = p0
p0 = p1
- p0 = (*int)(p2) // ERROR "cannot"
+ p0 = (*int)(p2) // ERROR "cannot|invalid"
p1 = p0
p1 = p1
- p1 = P1(p2) // ERROR "cannot"
- p2 = P2(p0) // ERROR "cannot"
- p2 = P2(p1) // ERROR "cannot"
+ p1 = P1(p2) // ERROR "cannot|invalid"
+ p2 = P2(p0) // ERROR "cannot|invalid"
+ p2 = P2(p1) // ERROR "cannot|invalid"
p2 = p2
type Q1 *struct {
@@ -93,12 +93,12 @@ func main() {
})(ps1) // legal because of special conversion exception for pointers
q0 = (*struct {
x int
- })(q2) // ERROR "cannot"
+ })(q2) // ERROR "cannot|invalid"
q1 = q0
q1 = q1
- q1 = Q1(q2) // ERROR "cannot"
+ q1 = Q1(q2) // ERROR "cannot|invalid"
q2 = (*S1)(q0) // legal because of special conversion exception for pointers
- q2 = Q2(q1) // ERROR "cannot"
+ q2 = Q2(q1) // ERROR "cannot|invalid"
q2 = q2
type F1 func(x NewInt) int
@@ -108,12 +108,12 @@ func main() {
var f2 F2
f0 = f0
f0 = f1
- f0 = func(x NewInt) int(f2) // ERROR "cannot"
+ f0 = func(x NewInt) int(f2) // ERROR "cannot|invalid"
f1 = f0
f1 = f1
- f1 = F1(f2) // ERROR "cannot"
- f2 = F2(f0) // ERROR "cannot"
- f2 = F2(f1) // ERROR "cannot"
+ f1 = F1(f2) // ERROR "cannot|invalid"
+ f2 = F2(f0) // ERROR "cannot|invalid"
+ f2 = F2(f1) // ERROR "cannot|invalid"
f2 = f2
type X1 interface {
@@ -131,12 +131,12 @@ func main() {
x0 = x1
x0 = interface {
f() int
- }(x2) // ERROR "cannot|need type assertion"
+ }(x2) // ERROR "cannot|need type assertion|incompatible"
x1 = x0
x1 = x1
- x1 = X1(x2) // ERROR "cannot|need type assertion"
- x2 = X2(x0) // ERROR "cannot|need type assertion"
- x2 = X2(x1) // ERROR "cannot|need type assertion"
+ x1 = X1(x2) // ERROR "cannot|need type assertion|incompatible"
+ x2 = X2(x0) // ERROR "cannot|need type assertion|incompatible"
+ x2 = X2(x1) // ERROR "cannot|need type assertion|incompatible"
x2 = x2
type L1 []int
@@ -146,12 +146,12 @@ func main() {
var l2 L2
l0 = l0
l0 = l1
- l0 = []int(l2) // ERROR "cannot"
+ l0 = []int(l2) // ERROR "cannot|invalid"
l1 = l0
l1 = l1
- l1 = L1(l2) // ERROR "cannot"
- l2 = L2(l0) // ERROR "cannot"
- l2 = L2(l1) // ERROR "cannot"
+ l1 = L1(l2) // ERROR "cannot|invalid"
+ l2 = L2(l0) // ERROR "cannot|invalid"
+ l2 = L2(l1) // ERROR "cannot|invalid"
l2 = l2
type M1 map[string]int
@@ -161,12 +161,12 @@ func main() {
var m2 L2
m0 = m0
m0 = m1
- m0 = []int(m2) // ERROR "cannot"
+ m0 = []int(m2) // ERROR "cannot|invalid"
m1 = m0
m1 = m1
- m1 = L1(m2) // ERROR "cannot"
- m2 = L2(m0) // ERROR "cannot"
- m2 = L2(m1) // ERROR "cannot"
+ m1 = L1(m2) // ERROR "cannot|invalid"
+ m2 = L2(m0) // ERROR "cannot|invalid"
+ m2 = L2(m1) // ERROR "cannot|invalid"
m2 = m2
type C1 chan int
@@ -176,12 +176,12 @@ func main() {
var c2 C2
c0 = c0
c0 = c1
- c0 = chan int(c2) // ERROR "cannot"
+ c0 = chan int(c2) // ERROR "cannot|invalid"
c1 = c0
c1 = c1
- c1 = C1(c2) // ERROR "cannot"
- c2 = C2(c0) // ERROR "cannot"
- c2 = C2(c1) // ERROR "cannot"
+ c1 = C1(c2) // ERROR "cannot|invalid"
+ c2 = C2(c0) // ERROR "cannot|invalid"
+ c2 = C2(c1) // ERROR "cannot|invalid"
c2 = c2
// internal compiler error (6g and gccgo)
diff --git a/test/bugs/bug286.go b/test/fixedbugs/bug286.go
index 94423be81..94423be81 100644
--- a/test/bugs/bug286.go
+++ b/test/fixedbugs/bug286.go
diff --git a/test/fixedbugs/bug289.go b/test/fixedbugs/bug289.go
new file mode 100644
index 000000000..f7180ff04
--- /dev/null
+++ b/test/fixedbugs/bug289.go
@@ -0,0 +1,26 @@
+// errchk $G $D/$F.go
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// https://code.google.com/p/gofrontend/issues/detail?id=1
+
+package main
+
+func f1() {
+ a, b := f() // ERROR "mismatch|does not match"
+ _ = a
+ _ = b
+}
+
+func f2() {
+ var a, b int
+ a, b = f() // ERROR "mismatch|does not match"
+ _ = a
+ _ = b
+}
+
+func f() int {
+ return 1;
+}
diff --git a/test/fixedbugs/bug290.go b/test/fixedbugs/bug290.go
new file mode 100644
index 000000000..80437c7f8
--- /dev/null
+++ b/test/fixedbugs/bug290.go
@@ -0,0 +1,15 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// http://code.google.com/p/go/issues/detail?id=920
+
+package main
+
+type X struct { x []X }
+
+func main() {
+ type Y struct { x []Y } // used to get invalid recursive type
+}
diff --git a/test/fixedbugs/bug291.go b/test/fixedbugs/bug291.go
new file mode 100644
index 000000000..09334c921
--- /dev/null
+++ b/test/fixedbugs/bug291.go
@@ -0,0 +1,23 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// http://code.google.com/p/go/issues/detail?id=915
+
+package main
+
+type T struct {
+ x int
+}
+
+var t = &T{42}
+var i interface{} = t
+var tt, ok = i.(*T)
+
+func main() {
+ if tt == nil || tt.x != 42 {
+ println("BUG")
+ }
+}
diff --git a/test/fixedbugs/bug292.go b/test/fixedbugs/bug292.go
new file mode 100644
index 000000000..05852cd46
--- /dev/null
+++ b/test/fixedbugs/bug292.go
@@ -0,0 +1,22 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// http://code.google.com/p/go/issues/detail?id=843
+
+package main
+
+import "unsafe"
+
+type T struct {
+ X, Y uint8
+}
+
+func main() {
+ var t T
+ if unsafe.Offsetof(t.X) != 0 || unsafe.Offsetof(t.Y) != 1 {
+ println("BUG", unsafe.Offsetof(t.X), unsafe.Offsetof(t.Y))
+ }
+}
diff --git a/test/fixedbugs/bug293.go b/test/fixedbugs/bug293.go
new file mode 100644
index 000000000..ca9b71a3a
--- /dev/null
+++ b/test/fixedbugs/bug293.go
@@ -0,0 +1,37 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// http://code.google.com/p/go/issues/detail?id=846
+
+package main
+
+func x() (a int, b bool) {
+ defer func(){
+ a++
+ }()
+ a, b = y()
+ return
+}
+
+func x2() (a int, b bool) {
+ defer func(){
+ a++
+ }()
+ return y()
+}
+
+func y() (int, bool) {
+ return 4, false
+}
+
+func main() {
+ if a, _ := x(); a != 5 {
+ println("BUG", a)
+ }
+ if a, _ := x2(); a != 5 {
+ println("BUG", a)
+ }
+}
diff --git a/test/fixedbugs/bug294.go b/test/fixedbugs/bug294.go
new file mode 100644
index 000000000..18f45931c
--- /dev/null
+++ b/test/fixedbugs/bug294.go
@@ -0,0 +1,79 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// http://code.google.com/p/go/issues/detail?id=800
+
+package main
+
+var log string
+
+type T int
+
+func (t T) a(s string) T {
+ log += "a(" + s + ")"
+ return t
+}
+
+func (T) b(s string) string {
+ log += "b"
+ return s
+}
+
+type F func(s string) F
+
+func a(s string) F {
+ log += "a(" + s + ")"
+ return F(a)
+}
+
+func b(s string) string {
+ log += "b"
+ return s
+}
+
+type I interface {
+ a(s string) I
+ b(s string) string
+}
+
+type T1 int
+
+func (t T1) a(s string) I {
+ log += "a(" + s + ")"
+ return t
+}
+
+func (T1) b(s string) string {
+ log += "b"
+ return s
+}
+
+var ok = true
+
+func bad() {
+ if !ok {
+ println("BUG")
+ ok = false
+ }
+ println(log)
+}
+
+func main() {
+ var t T
+ if t.a("1").a(t.b("2")); log != "a(1)ba(2)" {
+ bad()
+ }
+ log = ""
+ if a("3")(b("4"))(b("5")); log != "a(3)ba(4)ba(5)" {
+ bad()
+ }
+ log = ""
+ var i I = T1(0)
+ if i.a("6").a(i.b("7")).a(i.b("8")).a(i.b("9")); log != "a(6)ba(7)ba(8)ba(9)" {
+ bad()
+ }
+}
+
diff --git a/test/fixedbugs/bug295.go b/test/fixedbugs/bug295.go
new file mode 100644
index 000000000..fec2351f3
--- /dev/null
+++ b/test/fixedbugs/bug295.go
@@ -0,0 +1,17 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2010 The Go Authors. 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" // defines top-level T
+
+type S struct {
+ T int
+}
+
+func main() {
+ _ = &S{T: 1} // should work
+}
diff --git a/test/fixedbugs/bug296.go b/test/fixedbugs/bug296.go
new file mode 100644
index 000000000..46d8dbcfe
--- /dev/null
+++ b/test/fixedbugs/bug296.go
@@ -0,0 +1,88 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2010 The Go Authors. 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
+
+type I interface {
+ m(a, b, c, d, e, f, g, h byte)
+}
+
+type Int8 int8
+
+func (x Int8) m(a, b, c, d, e, f, g, h byte) {
+ check("Int8", int64(x), 0x01, a, b, c, d, e, f, g, h)
+}
+
+type Uint8 uint8
+
+func (x Uint8) m(a, b, c, d, e, f, g, h byte) {
+ check("Uint8", int64(x), 0x01, a, b, c, d, e, f, g, h)
+}
+
+type Int16 int16
+
+func (x Int16) m(a, b, c, d, e, f, g, h byte) {
+ check("Int16", int64(x), 0x0102, a, b, c, d, e, f, g, h)
+}
+
+type Uint16 uint16
+
+func (x Uint16) m(a, b, c, d, e, f, g, h byte) {
+ check("Uint16", int64(x), 0x0102, a, b, c, d, e, f, g, h)
+}
+
+type Int32 int32
+
+func (x Int32) m(a, b, c, d, e, f, g, h byte) {
+ check("Int32", int64(x), 0x01020304, a, b, c, d, e, f, g, h)
+}
+
+type Uint32 uint32
+
+func (x Uint32) m(a, b, c, d, e, f, g, h byte) {
+ check("Uint32", int64(x), 0x01020304, a, b, c, d, e, f, g, h)
+}
+
+type Int64 int64
+
+func (x Int64) m(a, b, c, d, e, f, g, h byte) {
+ check("Int64", int64(x), 0x0102030405060708, a, b, c, d, e, f, g, h)
+}
+
+type Uint64 uint64
+
+func (x Uint64) m(a, b, c, d, e, f, g, h byte) {
+ check("Uint64", int64(x), 0x0102030405060708, a, b, c, d, e, f, g, h)
+}
+
+var test = []I{
+ Int8(0x01),
+ Uint8(0x01),
+ Int16(0x0102),
+ Uint16(0x0102),
+ Int32(0x01020304),
+ Uint32(0x01020304),
+ Int64(0x0102030405060708),
+ Uint64(0x0102030405060708),
+}
+
+func main() {
+ for _, t := range test {
+ t.m(0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17)
+ }
+}
+
+var bug = false
+
+func check(desc string, have, want int64, a, b, c, d, e, f, g, h byte) {
+ if have != want || a != 0x10 || b != 0x11 || c != 0x12 || d != 0x13 || e != 0x14 || f != 0x15 || g != 0x16 || h != 0x17 {
+ if !bug {
+ bug = true
+ println("BUG")
+ }
+ println(desc, "check", have, want, a, b, c, d, e, f, g, h)
+ }
+}
diff --git a/test/fixedbugs/bug297.go b/test/fixedbugs/bug297.go
new file mode 100644
index 000000000..ba029427f
--- /dev/null
+++ b/test/fixedbugs/bug297.go
@@ -0,0 +1,15 @@
+// errchk $G $D/$F.go
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Used to crash; issue 961.
+
+package main
+
+type ByteSize float64
+const (
+ _ = iota; // ignore first value by assigning to blank identifier
+ KB ByteSize = 1<<(10*X) // ERROR "undefined"
+)
diff --git a/test/fixedbugs/bug298.go b/test/fixedbugs/bug298.go
new file mode 100644
index 000000000..fe4a99a78
--- /dev/null
+++ b/test/fixedbugs/bug298.go
@@ -0,0 +1,11 @@
+// errchk $G $D/$F.go
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ddd
+
+func Sum() int
+ for i := range []int{} { return i } // ERROR "return outside function|expected"
+
diff --git a/test/fixedbugs/bug299.go b/test/fixedbugs/bug299.go
new file mode 100644
index 000000000..4d7314432
--- /dev/null
+++ b/test/fixedbugs/bug299.go
@@ -0,0 +1,27 @@
+// errchk $G $D/$F.go
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type T struct {
+ // legal according to spec
+ x int
+ y (int)
+ int
+ *float
+ // not legal according to spec
+ (complex) // ERROR "non-declaration|expected|parenthesize"
+ (*string) // ERROR "non-declaration|expected|parenthesize"
+ *(bool) // ERROR "non-declaration|expected|parenthesize"
+}
+
+// legal according to spec
+func (p T) m() {}
+
+// not legal according to spec
+func (p (T)) f() {} // ERROR "parenthesize|expected"
+func (p *(T)) g() {} // ERROR "parenthesize|expected"
+func (p (*T)) h() {} // ERROR "parenthesize|expected"
diff --git a/test/fixedbugs/bug300.go b/test/fixedbugs/bug300.go
new file mode 100644
index 000000000..09ee3ab69
--- /dev/null
+++ b/test/fixedbugs/bug300.go
@@ -0,0 +1,29 @@
+// errchk $G $D/$F.go
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type T struct {
+ x, y *T
+}
+
+func main() {
+ // legal composite literals
+ _ = struct{}{}
+ _ = [42]int{}
+ _ = [...]int{}
+ _ = []int{}
+ _ = map[int]int{}
+ _ = T{}
+
+ // illegal composite literals: parentheses not allowed around literal type
+ _ = (struct{}){} // ERROR "parenthesize"
+ _ = ([42]int){} // ERROR "parenthesize"
+ _ = ([...]int){} // ERROR "parenthesize"
+ _ = ([]int){} // ERROR "parenthesize"
+ _ = (map[int]int){} // ERROR "parenthesize"
+ _ = (T){} // ERROR "parenthesize"
+}
diff --git a/test/fixedbugs/bug301.go b/test/fixedbugs/bug301.go
new file mode 100644
index 000000000..a58f4e13b
--- /dev/null
+++ b/test/fixedbugs/bug301.go
@@ -0,0 +1,18 @@
+// $G $D/$F.go || echo BUG: bug301.go
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// http://code.google.com/p/go/issues/detail?id=990
+
+package main
+
+func main() {
+ defer func() {
+ if recover() != nil {
+ panic("non-nil recover")
+ }
+ }()
+ panic(nil)
+}
diff --git a/test/fixedbugs/bug302.dir/main.go b/test/fixedbugs/bug302.dir/main.go
new file mode 100644
index 000000000..9f874d08f
--- /dev/null
+++ b/test/fixedbugs/bug302.dir/main.go
@@ -0,0 +1,12 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+// Check that the export information is correct in p.6.
+import _ "./p"
+
+// Check that it's still correct in pp.a (which contains p.6).
+import _ "./pp"
+
diff --git a/test/fixedbugs/bug302.dir/p.go b/test/fixedbugs/bug302.dir/p.go
new file mode 100644
index 000000000..7c54b906c
--- /dev/null
+++ b/test/fixedbugs/bug302.dir/p.go
@@ -0,0 +1,1011 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+type T struct {
+ x1 int
+ x2 int
+ x3 int
+ x4 int
+ x5 int
+ x6 int
+ x7 int
+ x8 int
+ x9 int
+ x10 int
+ x11 int
+ x12 int
+ x13 int
+ x14 int
+ x15 int
+ x16 int
+ x17 int
+ x18 int
+ x19 int
+ x20 int
+ x21 int
+ x22 int
+ x23 int
+ x24 int
+ x25 int
+ x26 int
+ x27 int
+ x28 int
+ x29 int
+ x30 int
+ x31 int
+ x32 int
+ x33 int
+ x34 int
+ x35 int
+ x36 int
+ x37 int
+ x38 int
+ x39 int
+ x40 int
+ x41 int
+ x42 int
+ x43 int
+ x44 int
+ x45 int
+ x46 int
+ x47 int
+ x48 int
+ x49 int
+ x50 int
+ x51 int
+ x52 int
+ x53 int
+ x54 int
+ x55 int
+ x56 int
+ x57 int
+ x58 int
+ x59 int
+ x60 int
+ x61 int
+ x62 int
+ x63 int
+ x64 int
+ x65 int
+ x66 int
+ x67 int
+ x68 int
+ x69 int
+ x70 int
+ x71 int
+ x72 int
+ x73 int
+ x74 int
+ x75 int
+ x76 int
+ x77 int
+ x78 int
+ x79 int
+ x80 int
+ x81 int
+ x82 int
+ x83 int
+ x84 int
+ x85 int
+ x86 int
+ x87 int
+ x88 int
+ x89 int
+ x90 int
+ x91 int
+ x92 int
+ x93 int
+ x94 int
+ x95 int
+ x96 int
+ x97 int
+ x98 int
+ x99 int
+ x100 int
+ x101 int
+ x102 int
+ x103 int
+ x104 int
+ x105 int
+ x106 int
+ x107 int
+ x108 int
+ x109 int
+ x110 int
+ x111 int
+ x112 int
+ x113 int
+ x114 int
+ x115 int
+ x116 int
+ x117 int
+ x118 int
+ x119 int
+ x120 int
+ x121 int
+ x122 int
+ x123 int
+ x124 int
+ x125 int
+ x126 int
+ x127 int
+ x128 int
+ x129 int
+ x130 int
+ x131 int
+ x132 int
+ x133 int
+ x134 int
+ x135 int
+ x136 int
+ x137 int
+ x138 int
+ x139 int
+ x140 int
+ x141 int
+ x142 int
+ x143 int
+ x144 int
+ x145 int
+ x146 int
+ x147 int
+ x148 int
+ x149 int
+ x150 int
+ x151 int
+ x152 int
+ x153 int
+ x154 int
+ x155 int
+ x156 int
+ x157 int
+ x158 int
+ x159 int
+ x160 int
+ x161 int
+ x162 int
+ x163 int
+ x164 int
+ x165 int
+ x166 int
+ x167 int
+ x168 int
+ x169 int
+ x170 int
+ x171 int
+ x172 int
+ x173 int
+ x174 int
+ x175 int
+ x176 int
+ x177 int
+ x178 int
+ x179 int
+ x180 int
+ x181 int
+ x182 int
+ x183 int
+ x184 int
+ x185 int
+ x186 int
+ x187 int
+ x188 int
+ x189 int
+ x190 int
+ x191 int
+ x192 int
+ x193 int
+ x194 int
+ x195 int
+ x196 int
+ x197 int
+ x198 int
+ x199 int
+ x200 int
+ x201 int
+ x202 int
+ x203 int
+ x204 int
+ x205 int
+ x206 int
+ x207 int
+ x208 int
+ x209 int
+ x210 int
+ x211 int
+ x212 int
+ x213 int
+ x214 int
+ x215 int
+ x216 int
+ x217 int
+ x218 int
+ x219 int
+ x220 int
+ x221 int
+ x222 int
+ x223 int
+ x224 int
+ x225 int
+ x226 int
+ x227 int
+ x228 int
+ x229 int
+ x230 int
+ x231 int
+ x232 int
+ x233 int
+ x234 int
+ x235 int
+ x236 int
+ x237 int
+ x238 int
+ x239 int
+ x240 int
+ x241 int
+ x242 int
+ x243 int
+ x244 int
+ x245 int
+ x246 int
+ x247 int
+ x248 int
+ x249 int
+ x250 int
+ x251 int
+ x252 int
+ x253 int
+ x254 int
+ x255 int
+ x256 int
+ x257 int
+ x258 int
+ x259 int
+ x260 int
+ x261 int
+ x262 int
+ x263 int
+ x264 int
+ x265 int
+ x266 int
+ x267 int
+ x268 int
+ x269 int
+ x270 int
+ x271 int
+ x272 int
+ x273 int
+ x274 int
+ x275 int
+ x276 int
+ x277 int
+ x278 int
+ x279 int
+ x280 int
+ x281 int
+ x282 int
+ x283 int
+ x284 int
+ x285 int
+ x286 int
+ x287 int
+ x288 int
+ x289 int
+ x290 int
+ x291 int
+ x292 int
+ x293 int
+ x294 int
+ x295 int
+ x296 int
+ x297 int
+ x298 int
+ x299 int
+ x300 int
+ x301 int
+ x302 int
+ x303 int
+ x304 int
+ x305 int
+ x306 int
+ x307 int
+ x308 int
+ x309 int
+ x310 int
+ x311 int
+ x312 int
+ x313 int
+ x314 int
+ x315 int
+ x316 int
+ x317 int
+ x318 int
+ x319 int
+ x320 int
+ x321 int
+ x322 int
+ x323 int
+ x324 int
+ x325 int
+ x326 int
+ x327 int
+ x328 int
+ x329 int
+ x330 int
+ x331 int
+ x332 int
+ x333 int
+ x334 int
+ x335 int
+ x336 int
+ x337 int
+ x338 int
+ x339 int
+ x340 int
+ x341 int
+ x342 int
+ x343 int
+ x344 int
+ x345 int
+ x346 int
+ x347 int
+ x348 int
+ x349 int
+ x350 int
+ x351 int
+ x352 int
+ x353 int
+ x354 int
+ x355 int
+ x356 int
+ x357 int
+ x358 int
+ x359 int
+ x360 int
+ x361 int
+ x362 int
+ x363 int
+ x364 int
+ x365 int
+ x366 int
+ x367 int
+ x368 int
+ x369 int
+ x370 int
+ x371 int
+ x372 int
+ x373 int
+ x374 int
+ x375 int
+ x376 int
+ x377 int
+ x378 int
+ x379 int
+ x380 int
+ x381 int
+ x382 int
+ x383 int
+ x384 int
+ x385 int
+ x386 int
+ x387 int
+ x388 int
+ x389 int
+ x390 int
+ x391 int
+ x392 int
+ x393 int
+ x394 int
+ x395 int
+ x396 int
+ x397 int
+ x398 int
+ x399 int
+ x400 int
+ x401 int
+ x402 int
+ x403 int
+ x404 int
+ x405 int
+ x406 int
+ x407 int
+ x408 int
+ x409 int
+ x410 int
+ x411 int
+ x412 int
+ x413 int
+ x414 int
+ x415 int
+ x416 int
+ x417 int
+ x418 int
+ x419 int
+ x420 int
+ x421 int
+ x422 int
+ x423 int
+ x424 int
+ x425 int
+ x426 int
+ x427 int
+ x428 int
+ x429 int
+ x430 int
+ x431 int
+ x432 int
+ x433 int
+ x434 int
+ x435 int
+ x436 int
+ x437 int
+ x438 int
+ x439 int
+ x440 int
+ x441 int
+ x442 int
+ x443 int
+ x444 int
+ x445 int
+ x446 int
+ x447 int
+ x448 int
+ x449 int
+ x450 int
+ x451 int
+ x452 int
+ x453 int
+ x454 int
+ x455 int
+ x456 int
+ x457 int
+ x458 int
+ x459 int
+ x460 int
+ x461 int
+ x462 int
+ x463 int
+ x464 int
+ x465 int
+ x466 int
+ x467 int
+ x468 int
+ x469 int
+ x470 int
+ x471 int
+ x472 int
+ x473 int
+ x474 int
+ x475 int
+ x476 int
+ x477 int
+ x478 int
+ x479 int
+ x480 int
+ x481 int
+ x482 int
+ x483 int
+ x484 int
+ x485 int
+ x486 int
+ x487 int
+ x488 int
+ x489 int
+ x490 int
+ x491 int
+ x492 int
+ x493 int
+ x494 int
+ x495 int
+ x496 int
+ x497 int
+ x498 int
+ x499 int
+ x500 int
+ x501 int
+ x502 int
+ x503 int
+ x504 int
+ x505 int
+ x506 int
+ x507 int
+ x508 int
+ x509 int
+ x510 int
+ x511 int
+ x512 int
+ x513 int
+ x514 int
+ x515 int
+ x516 int
+ x517 int
+ x518 int
+ x519 int
+ x520 int
+ x521 int
+ x522 int
+ x523 int
+ x524 int
+ x525 int
+ x526 int
+ x527 int
+ x528 int
+ x529 int
+ x530 int
+ x531 int
+ x532 int
+ x533 int
+ x534 int
+ x535 int
+ x536 int
+ x537 int
+ x538 int
+ x539 int
+ x540 int
+ x541 int
+ x542 int
+ x543 int
+ x544 int
+ x545 int
+ x546 int
+ x547 int
+ x548 int
+ x549 int
+ x550 int
+ x551 int
+ x552 int
+ x553 int
+ x554 int
+ x555 int
+ x556 int
+ x557 int
+ x558 int
+ x559 int
+ x560 int
+ x561 int
+ x562 int
+ x563 int
+ x564 int
+ x565 int
+ x566 int
+ x567 int
+ x568 int
+ x569 int
+ x570 int
+ x571 int
+ x572 int
+ x573 int
+ x574 int
+ x575 int
+ x576 int
+ x577 int
+ x578 int
+ x579 int
+ x580 int
+ x581 int
+ x582 int
+ x583 int
+ x584 int
+ x585 int
+ x586 int
+ x587 int
+ x588 int
+ x589 int
+ x590 int
+ x591 int
+ x592 int
+ x593 int
+ x594 int
+ x595 int
+ x596 int
+ x597 int
+ x598 int
+ x599 int
+ x600 int
+ x601 int
+ x602 int
+ x603 int
+ x604 int
+ x605 int
+ x606 int
+ x607 int
+ x608 int
+ x609 int
+ x610 int
+ x611 int
+ x612 int
+ x613 int
+ x614 int
+ x615 int
+ x616 int
+ x617 int
+ x618 int
+ x619 int
+ x620 int
+ x621 int
+ x622 int
+ x623 int
+ x624 int
+ x625 int
+ x626 int
+ x627 int
+ x628 int
+ x629 int
+ x630 int
+ x631 int
+ x632 int
+ x633 int
+ x634 int
+ x635 int
+ x636 int
+ x637 int
+ x638 int
+ x639 int
+ x640 int
+ x641 int
+ x642 int
+ x643 int
+ x644 int
+ x645 int
+ x646 int
+ x647 int
+ x648 int
+ x649 int
+ x650 int
+ x651 int
+ x652 int
+ x653 int
+ x654 int
+ x655 int
+ x656 int
+ x657 int
+ x658 int
+ x659 int
+ x660 int
+ x661 int
+ x662 int
+ x663 int
+ x664 int
+ x665 int
+ x666 int
+ x667 int
+ x668 int
+ x669 int
+ x670 int
+ x671 int
+ x672 int
+ x673 int
+ x674 int
+ x675 int
+ x676 int
+ x677 int
+ x678 int
+ x679 int
+ x680 int
+ x681 int
+ x682 int
+ x683 int
+ x684 int
+ x685 int
+ x686 int
+ x687 int
+ x688 int
+ x689 int
+ x690 int
+ x691 int
+ x692 int
+ x693 int
+ x694 int
+ x695 int
+ x696 int
+ x697 int
+ x698 int
+ x699 int
+ x700 int
+ x701 int
+ x702 int
+ x703 int
+ x704 int
+ x705 int
+ x706 int
+ x707 int
+ x708 int
+ x709 int
+ x710 int
+ x711 int
+ x712 int
+ x713 int
+ x714 int
+ x715 int
+ x716 int
+ x717 int
+ x718 int
+ x719 int
+ x720 int
+ x721 int
+ x722 int
+ x723 int
+ x724 int
+ x725 int
+ x726 int
+ x727 int
+ x728 int
+ x729 int
+ x730 int
+ x731 int
+ x732 int
+ x733 int
+ x734 int
+ x735 int
+ x736 int
+ x737 int
+ x738 int
+ x739 int
+ x740 int
+ x741 int
+ x742 int
+ x743 int
+ x744 int
+ x745 int
+ x746 int
+ x747 int
+ x748 int
+ x749 int
+ x750 int
+ x751 int
+ x752 int
+ x753 int
+ x754 int
+ x755 int
+ x756 int
+ x757 int
+ x758 int
+ x759 int
+ x760 int
+ x761 int
+ x762 int
+ x763 int
+ x764 int
+ x765 int
+ x766 int
+ x767 int
+ x768 int
+ x769 int
+ x770 int
+ x771 int
+ x772 int
+ x773 int
+ x774 int
+ x775 int
+ x776 int
+ x777 int
+ x778 int
+ x779 int
+ x780 int
+ x781 int
+ x782 int
+ x783 int
+ x784 int
+ x785 int
+ x786 int
+ x787 int
+ x788 int
+ x789 int
+ x790 int
+ x791 int
+ x792 int
+ x793 int
+ x794 int
+ x795 int
+ x796 int
+ x797 int
+ x798 int
+ x799 int
+ x800 int
+ x801 int
+ x802 int
+ x803 int
+ x804 int
+ x805 int
+ x806 int
+ x807 int
+ x808 int
+ x809 int
+ x810 int
+ x811 int
+ x812 int
+ x813 int
+ x814 int
+ x815 int
+ x816 int
+ x817 int
+ x818 int
+ x819 int
+ x820 int
+ x821 int
+ x822 int
+ x823 int
+ x824 int
+ x825 int
+ x826 int
+ x827 int
+ x828 int
+ x829 int
+ x830 int
+ x831 int
+ x832 int
+ x833 int
+ x834 int
+ x835 int
+ x836 int
+ x837 int
+ x838 int
+ x839 int
+ x840 int
+ x841 int
+ x842 int
+ x843 int
+ x844 int
+ x845 int
+ x846 int
+ x847 int
+ x848 int
+ x849 int
+ x850 int
+ x851 int
+ x852 int
+ x853 int
+ x854 int
+ x855 int
+ x856 int
+ x857 int
+ x858 int
+ x859 int
+ x860 int
+ x861 int
+ x862 int
+ x863 int
+ x864 int
+ x865 int
+ x866 int
+ x867 int
+ x868 int
+ x869 int
+ x870 int
+ x871 int
+ x872 int
+ x873 int
+ x874 int
+ x875 int
+ x876 int
+ x877 int
+ x878 int
+ x879 int
+ x880 int
+ x881 int
+ x882 int
+ x883 int
+ x884 int
+ x885 int
+ x886 int
+ x887 int
+ x888 int
+ x889 int
+ x890 int
+ x891 int
+ x892 int
+ x893 int
+ x894 int
+ x895 int
+ x896 int
+ x897 int
+ x898 int
+ x899 int
+ x900 int
+ x901 int
+ x902 int
+ x903 int
+ x904 int
+ x905 int
+ x906 int
+ x907 int
+ x908 int
+ x909 int
+ x910 int
+ x911 int
+ x912 int
+ x913 int
+ x914 int
+ x915 int
+ x916 int
+ x917 int
+ x918 int
+ x919 int
+ x920 int
+ x921 int
+ x922 int
+ x923 int
+ x924 int
+ x925 int
+ x926 int
+ x927 int
+ x928 int
+ x929 int
+ x930 int
+ x931 int
+ x932 int
+ x933 int
+ x934 int
+ x935 int
+ x936 int
+ x937 int
+ x938 int
+ x939 int
+ x940 int
+ x941 int
+ x942 int
+ x943 int
+ x944 int
+ x945 int
+ x946 int
+ x947 int
+ x948 int
+ x949 int
+ x950 int
+ x951 int
+ x952 int
+ x953 int
+ x954 int
+ x955 int
+ x956 int
+ x957 int
+ x958 int
+ x959 int
+ x960 int
+ x961 int
+ x962 int
+ x963 int
+ x964 int
+ x965 int
+ x966 int
+ x967 int
+ x968 int
+ x969 int
+ x970 int
+ x971 int
+ x972 int
+ x973 int
+ x974 int
+ x975 int
+ x976 int
+ x977 int
+ x978 int
+ x979 int
+ x980 int
+ x981 int
+ x982 int
+ x983 int
+ x984 int
+ x985 int
+ x986 int
+ x987 int
+ x988 int
+ x989 int
+ x990 int
+ x991 int
+ x992 int
+ x993 int
+ x994 int
+ x995 int
+ x996 int
+ x997 int
+ x998 int
+ x999 int
+ x1000 int
+}
+
+func (t *T) M() {
+}
diff --git a/test/fixedbugs/bug302.go b/test/fixedbugs/bug302.go
new file mode 100644
index 000000000..e9edb94ac
--- /dev/null
+++ b/test/fixedbugs/bug302.go
@@ -0,0 +1,6 @@
+// $G $D/bug302.dir/p.go && gopack grc pp.a p.$A && $G $D/bug302.dir/main.go
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
diff --git a/test/fixedbugs/bug303.go b/test/fixedbugs/bug303.go
new file mode 100644
index 000000000..3bd790f13
--- /dev/null
+++ b/test/fixedbugs/bug303.go
@@ -0,0 +1,37 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 1011. Removing either #1 or #3 avoided the crash at #2.
+
+package main
+
+import (
+ "io"
+ "strings"
+)
+
+func readU16BE(b []byte) uint16 {
+ b[0] = 0
+ b[1] = 1
+ return uint16(b[0])<<8 + uint16(b[1]) // #1
+ n := uint16(b[0])<<8 + uint16(b[1])
+ return n
+}
+
+func readStr(r io.Reader, b []byte) string {
+ n := readU16BE(b)
+ if int(n) > len(b) {
+ return "err: n>b"
+ }
+ io.ReadFull(r, b[0:n]) // #2
+ return string(b[0:n]) // #3
+ return "ok"
+}
+
+func main() {
+ br := strings.NewReader("abcd")
+ readStr(br, make([]byte, 256))
+}
diff --git a/test/fixedbugs/bug304.go b/test/fixedbugs/bug304.go
new file mode 100644
index 000000000..adcf08a35
--- /dev/null
+++ b/test/fixedbugs/bug304.go
@@ -0,0 +1,18 @@
+// $G $D/$F.go
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Caused a gccgo crash on compilation.
+// bug304.go: In function ‘p.f’:
+// bug304.go:15:2: internal compiler error: in copy_tree_r, at tree-inline.c:4114
+
+package p
+type S struct {
+ v interface{}
+}
+func g(e interface{}) { }
+func f(s S) {
+ g(s.v.(*int))
+}
diff --git a/test/fixedbugs/bug305.go b/test/fixedbugs/bug305.go
new file mode 100644
index 000000000..758fee269
--- /dev/null
+++ b/test/fixedbugs/bug305.go
@@ -0,0 +1,24 @@
+// errchk $G $D/$F.go
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Use //line to set the line number of the next line to 20.
+//line fixedbugs/bug305.go:20
+
+package p
+
+// Introduce an error which should be reported on line 24.
+var a int = "bogus"
+
+// Line 15 of file.
+// 16
+// 17
+// 18
+// 19
+// 20
+// 21
+// 22
+// 23
+// ERROR "cannot|incompatible"
diff --git a/test/fixedbugs/bug306.dir/p1.go b/test/fixedbugs/bug306.dir/p1.go
new file mode 100644
index 000000000..bf87ea149
--- /dev/null
+++ b/test/fixedbugs/bug306.dir/p1.go
@@ -0,0 +1,9 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p1
+
+type T <-chan int
+var x = make(chan T)
+
diff --git a/src/pkg/debug/proc/regs_nacl_386.go b/test/fixedbugs/bug306.dir/p2.go
index 60c9ac719..3f8bd9d49 100644
--- a/src/pkg/debug/proc/regs_nacl_386.go
+++ b/test/fixedbugs/bug306.dir/p2.go
@@ -1,5 +1,8 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package proc
+package p2
+
+import _ "./p1"
+
diff --git a/test/fixedbugs/bug306.go b/test/fixedbugs/bug306.go
new file mode 100644
index 000000000..a0a43507d
--- /dev/null
+++ b/test/fixedbugs/bug306.go
@@ -0,0 +1,7 @@
+// $G $D/$F.dir/p1.go && $G $D/$F.dir/p2.go
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+ignored
diff --git a/test/fixedbugs/bug307.go b/test/fixedbugs/bug307.go
new file mode 100644
index 000000000..a1a30dfb7
--- /dev/null
+++ b/test/fixedbugs/bug307.go
@@ -0,0 +1,15 @@
+// $G $D/$F.go
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Valid program, gccgo reported an error.
+// bug307.go:14:6: error: cmplx arguments must have identical types
+
+package main
+
+func main() {
+ var f float64
+ _ = cmplx(1 / f, 0)
+}
diff --git a/test/fixedbugs/bug308.go b/test/fixedbugs/bug308.go
new file mode 100644
index 000000000..c2845f042
--- /dev/null
+++ b/test/fixedbugs/bug308.go
@@ -0,0 +1,19 @@
+// $G $D/$F.go
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// issue 1136
+
+package main
+
+import "fmt"
+
+func log1(f string, argv ...interface{}) {
+ fmt.Printf("log: %s\n", fmt.Sprintf(f, argv...))
+}
+
+func main() {
+ log1("%d", 42)
+}
diff --git a/test/fixedbugs/bug309.go b/test/fixedbugs/bug309.go
new file mode 100644
index 000000000..07bebae74
--- /dev/null
+++ b/test/fixedbugs/bug309.go
@@ -0,0 +1,19 @@
+// $G $D/$F.go
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// issue 1016
+
+package main
+
+func foo(t interface{}, c chan int) {
+ switch v := t.(type) {
+ case int:
+ select {
+ case <-c:
+ // bug was: internal compiler error: var without type, init: v
+ }
+ }
+}
diff --git a/test/fixedbugs/bug310.go b/test/fixedbugs/bug310.go
new file mode 100644
index 000000000..191f3ed2b
--- /dev/null
+++ b/test/fixedbugs/bug310.go
@@ -0,0 +1,20 @@
+// errchk $G $D/$F.go
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+import (
+ "bytes"
+ "fmt"
+)
+
+type t int
+
+func main() {
+ _ = t.bar // ERROR "no method"
+ var b bytes.Buffer
+ fmt.Print(b) // ERROR "implicit assignment"
+}
diff --git a/test/fixedbugs/bug311.go b/test/fixedbugs/bug311.go
new file mode 100644
index 000000000..ed937a674
--- /dev/null
+++ b/test/fixedbugs/bug311.go
@@ -0,0 +1,20 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2010 The Go Authors. 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 main() {
+ m := make(map[string][1000]byte)
+ m["hi"] = [1000]byte{1}
+
+ v := m["hi"]
+
+ for k, vv := range m {
+ if k != "hi" || string(v[:]) != string(vv[:]) {
+ panic("bad iter")
+ }
+ }
+}
diff --git a/test/fixedbugs/bug312.go b/test/fixedbugs/bug312.go
new file mode 100644
index 000000000..70888dd41
--- /dev/null
+++ b/test/fixedbugs/bug312.go
@@ -0,0 +1,22 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// issue 1172
+
+package main
+
+func main() {
+ var i interface{}
+ c := make(chan int, 1)
+ c <- 1
+ select {
+ case i = <-c: // error on this line
+ }
+ if i != 1 {
+ println("bad i", i)
+ panic("BUG")
+ }
+}
diff --git a/test/fixedbugs/bug313.dir/a.go b/test/fixedbugs/bug313.dir/a.go
new file mode 100644
index 000000000..cb4ca7256
--- /dev/null
+++ b/test/fixedbugs/bug313.dir/a.go
@@ -0,0 +1,11 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "fmt"
+
+func a() {
+ fmt.DoesNotExist() // ERROR "undefined"
+}
diff --git a/test/fixedbugs/bug313.dir/b.go b/test/fixedbugs/bug313.dir/b.go
new file mode 100644
index 000000000..7eda72b4f
--- /dev/null
+++ b/test/fixedbugs/bug313.dir/b.go
@@ -0,0 +1,11 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import . "fmt"
+
+func b() {
+ Println()
+}
diff --git a/test/fixedbugs/bug313.go b/test/fixedbugs/bug313.go
new file mode 100644
index 000000000..eb2a0223b
--- /dev/null
+++ b/test/fixedbugs/bug313.go
@@ -0,0 +1,19 @@
+// errchk $G -e $D/$F.dir/[ab].go
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 1284
+
+package bug313
+
+/*
+6g bug313.dir/[ab].go
+
+Before:
+bug313.dir/b.go:7: internal compiler error: fault
+
+Now:
+bug313.dir/a.go:10: undefined: fmt.DoesNotExist
+*/
diff --git a/test/fixedbugs/bug314.go b/test/fixedbugs/bug314.go
new file mode 100644
index 000000000..95d81d795
--- /dev/null
+++ b/test/fixedbugs/bug314.go
@@ -0,0 +1,31 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: bug314
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Used to call wrong methods; issue 1290.
+
+package main
+
+type S struct {
+}
+func (S) a() int{
+ return 0
+}
+func (S) b() int{
+ return 1
+}
+
+func main() {
+ var i interface {
+ b() int
+ a() int
+ } = S{}
+ if i.a() != 0 {
+ panic("wrong method called")
+ }
+ if i.b() != 1 {
+ panic("wrong method called")
+ }
+}
diff --git a/test/fixedbugs/bug315.go b/test/fixedbugs/bug315.go
new file mode 100644
index 000000000..198bae77a
--- /dev/null
+++ b/test/fixedbugs/bug315.go
@@ -0,0 +1,18 @@
+// $G $D/$F.go || echo BUG: bug315
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 1368.
+
+package main
+
+func main() {
+ a := cmplx(2, 2)
+ a /= 2
+}
+
+/*
+bug315.go:13: internal compiler error: optoas: no entry DIV-complex
+*/
diff --git a/test/fixedbugs/bug316.go b/test/fixedbugs/bug316.go
new file mode 100644
index 000000000..bd4d99eb6
--- /dev/null
+++ b/test/fixedbugs/bug316.go
@@ -0,0 +1,17 @@
+// $G $D/$F.go || echo BUG: bug316
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Issue 1369.
+
+package main
+
+const (
+ c = cmplx(1, 2)
+ r = real(c) // was: const initializer must be constant
+ i = imag(c) // was: const initializer must be constant
+)
+
+func main() {}
diff --git a/test/fixedbugs/bug317.go b/test/fixedbugs/bug317.go
new file mode 100644
index 000000000..0cb26c29b
--- /dev/null
+++ b/test/fixedbugs/bug317.go
@@ -0,0 +1,16 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: bug317
+
+// Copyright 2011 The Go Authors. 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 main() {
+ x := []uint{0}
+ x[0] &^= f()
+}
+
+func f() uint {
+ return 1<<31 // doesn't panic with 1<<31 - 1
+}
diff --git a/test/float_lit.go b/test/float_lit.go
index 58bd4dac0..7b91d88e5 100644
--- a/test/float_lit.go
+++ b/test/float_lit.go
@@ -6,96 +6,192 @@
package main
-func
-pow10(pow int) float64 {
- if pow < 0 { return 1/pow10(-pow); }
- if pow > 0 { return pow10(pow-1)*10; }
- return 1;
+var bad bool
+
+func pow10(pow int) float64 {
+ if pow < 0 {
+ return 1 / pow10(-pow)
+ }
+ if pow > 0 {
+ return pow10(pow-1) * 10
+ }
+ return 1
}
-func
-close(da float64, ia, ib int64, pow int) bool {
- db := float64(ia) / float64(ib);
- db *= pow10(pow);
+func close(da float64, ia, ib int64, pow int) bool {
+ db := float64(ia) / float64(ib)
+ db *= pow10(pow)
if da == 0 || db == 0 {
if da == 0 && db == 0 {
- return true;
+ return true
}
- return false;
+ return false
}
- de := (da-db) /da;
+ de := (da - db) / da
if de < 0 {
- de = -de;
+ de = -de
}
- if de < 1.0e-14 {
- return true;
+ if de < 1e-14 {
+ return true
+ }
+ if !bad {
+ println("BUG")
+ bad = true
}
- return false;
+ return false
}
-func
-main() {
-
- if !close(0., 0, 1, 0) { print("0. is ", 0., "\n"); }
- if !close(+10., 10, 1, 0) { print("+10. is ", +10., "\n"); }
- if !close(-210., -210, 1, 0) { print("-210. is ", -210., "\n"); }
+func main() {
+ if !close(0., 0, 1, 0) {
+ print("0. is ", 0., "\n")
+ }
+ if !close(+10., 10, 1, 0) {
+ print("+10. is ", +10., "\n")
+ }
+ if !close(-210., -210, 1, 0) {
+ print("-210. is ", -210., "\n")
+ }
- if !close(.0, 0, 1, 0) { print(".0 is ", .0, "\n"); }
- if !close(+.01, 1, 100, 0) { print("+.01 is ", +.01, "\n"); }
- if !close(-.012, -12, 1000, 0) { print("-.012 is ", -.012, "\n"); }
+ if !close(.0, 0, 1, 0) {
+ print(".0 is ", .0, "\n")
+ }
+ if !close(+.01, 1, 100, 0) {
+ print("+.01 is ", +.01, "\n")
+ }
+ if !close(-.012, -12, 1000, 0) {
+ print("-.012 is ", -.012, "\n")
+ }
- if !close(0.0, 0, 1, 0) { print("0.0 is ", 0.0, "\n"); }
- if !close(+10.01, 1001, 100, 0) { print("+10.01 is ", +10.01, "\n"); }
- if !close(-210.012, -210012, 1000, 0) { print("-210.012 is ", -210.012, "\n"); }
+ if !close(0.0, 0, 1, 0) {
+ print("0.0 is ", 0.0, "\n")
+ }
+ if !close(+10.01, 1001, 100, 0) {
+ print("+10.01 is ", +10.01, "\n")
+ }
+ if !close(-210.012, -210012, 1000, 0) {
+ print("-210.012 is ", -210.012, "\n")
+ }
- if !close(0E+1, 0, 1, 0) { print("0E+1 is ", 0E+1, "\n"); }
- if !close(+10e2, 10, 1, 2) { print("+10e2 is ", +10e2, "\n"); }
- if !close(-210e3, -210, 1, 3) { print("-210e3 is ", -210e3, "\n"); }
+ if !close(0E+1, 0, 1, 0) {
+ print("0E+1 is ", 0E+1, "\n")
+ }
+ if !close(+10e2, 10, 1, 2) {
+ print("+10e2 is ", +10e2, "\n")
+ }
+ if !close(-210e3, -210, 1, 3) {
+ print("-210e3 is ", -210e3, "\n")
+ }
- if !close(0E-1, 0, 1, 0) { print("0E-1 is ", 0E-1, "\n"); }
- if !close(+0e23, 0, 1, 1) { print("+0e23 is ", +0e23, "\n"); }
- if !close(-0e345, 0, 1, 1) { print("-0e345 is ", -0e345, "\n"); }
+ if !close(0E-1, 0, 1, 0) {
+ print("0E-1 is ", 0E-1, "\n")
+ }
+ if !close(+0e23, 0, 1, 1) {
+ print("+0e23 is ", +0e23, "\n")
+ }
+ if !close(-0e345, 0, 1, 1) {
+ print("-0e345 is ", -0e345, "\n")
+ }
- if !close(0E1, 0, 1, 1) { print("0E1 is ", 0E1, "\n"); }
- if !close(+10e23, 10, 1, 23) { print("+10e23 is ", +10e23, "\n"); }
- if !close(-210e34, -210, 1, 34) { print("-210e34 is ", -210e34, "\n"); }
+ if !close(0E1, 0, 1, 1) {
+ print("0E1 is ", 0E1, "\n")
+ }
+ if !close(+10e23, 10, 1, 23) {
+ print("+10e23 is ", +10e23, "\n")
+ }
+ if !close(-210e34, -210, 1, 34) {
+ print("-210e34 is ", -210e34, "\n")
+ }
- if !close(0.E1, 0, 1, 1) { print("0.E1 is ", 0.E1, "\n"); }
- if !close(+10.e+2, 10, 1, 2) { print("+10.e+2 is ", +10.e+2, "\n"); }
- if !close(-210.e-3, -210, 1, -3) { print("-210.e-3 is ", -210.e-3, "\n"); }
+ if !close(0.E1, 0, 1, 1) {
+ print("0.E1 is ", 0.E1, "\n")
+ }
+ if !close(+10.e+2, 10, 1, 2) {
+ print("+10.e+2 is ", +10.e+2, "\n")
+ }
+ if !close(-210.e-3, -210, 1, -3) {
+ print("-210.e-3 is ", -210.e-3, "\n")
+ }
- if !close(.0E1, 0, 1, 1) { print(".0E1 is ", .0E1, "\n"); }
- if !close(+.01e2, 1, 100, 2) { print("+.01e2 is ", +.01e2, "\n"); }
- if !close(-.012e3, -12, 1000, 3) { print("-.012e3 is ", -.012e3, "\n"); }
+ if !close(.0E1, 0, 1, 1) {
+ print(".0E1 is ", .0E1, "\n")
+ }
+ if !close(+.01e2, 1, 100, 2) {
+ print("+.01e2 is ", +.01e2, "\n")
+ }
+ if !close(-.012e3, -12, 1000, 3) {
+ print("-.012e3 is ", -.012e3, "\n")
+ }
- if !close(0.0E1, 0, 1, 0) { print("0.0E1 is ", 0.0E1, "\n"); }
- if !close(+10.01e2, 1001, 100, 2) { print("+10.01e2 is ", +10.01e2, "\n"); }
- if !close(-210.012e3, -210012, 1000, 3) { print("-210.012e3 is ", -210.012e3, "\n"); }
+ if !close(0.0E1, 0, 1, 0) {
+ print("0.0E1 is ", 0.0E1, "\n")
+ }
+ if !close(+10.01e2, 1001, 100, 2) {
+ print("+10.01e2 is ", +10.01e2, "\n")
+ }
+ if !close(-210.012e3, -210012, 1000, 3) {
+ print("-210.012e3 is ", -210.012e3, "\n")
+ }
- if !close(0.E+12, 0, 1, 0) { print("0.E+12 is ", 0.E+12, "\n"); }
- if !close(+10.e23, 10, 1, 23) { print("+10.e23 is ", +10.e23, "\n"); }
- if !close(-210.e33, -210, 1, 33) { print("-210.e33 is ", -210.e33, "\n"); }
+ if !close(0.E+12, 0, 1, 0) {
+ print("0.E+12 is ", 0.E+12, "\n")
+ }
+ if !close(+10.e23, 10, 1, 23) {
+ print("+10.e23 is ", +10.e23, "\n")
+ }
+ if !close(-210.e33, -210, 1, 33) {
+ print("-210.e33 is ", -210.e33, "\n")
+ }
- if !close(.0E-12, 0, 1, 0) { print(".0E-12 is ", .0E-12, "\n"); }
- if !close(+.01e23, 1, 100, 23) { print("+.01e23 is ", +.01e23, "\n"); }
- if !close(-.012e34, -12, 1000, 34) { print("-.012e34 is ", -.012e34, "\n"); }
+ if !close(.0E-12, 0, 1, 0) {
+ print(".0E-12 is ", .0E-12, "\n")
+ }
+ if !close(+.01e23, 1, 100, 23) {
+ print("+.01e23 is ", +.01e23, "\n")
+ }
+ if !close(-.012e34, -12, 1000, 34) {
+ print("-.012e34 is ", -.012e34, "\n")
+ }
- if !close(0.0E12, 0, 1, 12) { print("0.0E12 is ", 0.0E12, "\n"); }
- if !close(+10.01e23, 1001, 100, 23) { print("+10.01e23 is ", +10.01e23, "\n"); }
- if !close(-210.012e33, -210012, 1000, 33) { print("-210.012e33 is ", -210.012e33, "\n"); }
+ if !close(0.0E12, 0, 1, 12) {
+ print("0.0E12 is ", 0.0E12, "\n")
+ }
+ if !close(+10.01e23, 1001, 100, 23) {
+ print("+10.01e23 is ", +10.01e23, "\n")
+ }
+ if !close(-210.012e33, -210012, 1000, 33) {
+ print("-210.012e33 is ", -210.012e33, "\n")
+ }
- if !close(0.E123, 0, 1, 123) { print("0.E123 is ", 0.E123, "\n"); }
- if !close(+10.e+23, 10, 1, 23) { print("+10.e+234 is ", +10.e+234, "\n"); }
- if !close(-210.e-35, -210, 1, -35) { print("-210.e-35 is ", -210.e-35, "\n"); }
+ if !close(0.E123, 0, 1, 123) {
+ print("0.E123 is ", 0.E123, "\n")
+ }
+ if !close(+10.e+23, 10, 1, 23) {
+ print("+10.e+234 is ", +10.e+234, "\n")
+ }
+ if !close(-210.e-35, -210, 1, -35) {
+ print("-210.e-35 is ", -210.e-35, "\n")
+ }
- if !close(.0E123, 0, 1, 123) { print(".0E123 is ", .0E123, "\n"); }
- if !close(+.01e29, 1, 100, 29) { print("+.01e29 is ", +.01e29, "\n"); }
- if !close(-.012e29, -12, 1000, 29) { print("-.012e29 is ", -.012e29, "\n"); }
+ if !close(.0E123, 0, 1, 123) {
+ print(".0E123 is ", .0E123, "\n")
+ }
+ if !close(+.01e29, 1, 100, 29) {
+ print("+.01e29 is ", +.01e29, "\n")
+ }
+ if !close(-.012e29, -12, 1000, 29) {
+ print("-.012e29 is ", -.012e29, "\n")
+ }
- if !close(0.0E123, 0, 1, 123) { print("0.0E123 is ", 0.0E123, "\n"); }
- if !close(+10.01e31, 1001, 100, 31) { print("+10.01e31 is ", +10.01e31, "\n"); }
- if !close(-210.012e19, -210012, 1000, 19) { print("-210.012e19 is ", -210.012e19, "\n"); }
+ if !close(0.0E123, 0, 1, 123) {
+ print("0.0E123 is ", 0.0E123, "\n")
+ }
+ if !close(+10.01e31, 1001, 100, 31) {
+ print("+10.01e31 is ", +10.01e31, "\n")
+ }
+ if !close(-210.012e19, -210012, 1000, 19) {
+ print("-210.012e19 is ", -210.012e19, "\n")
+ }
}
diff --git a/test/floatcmp.go b/test/floatcmp.go
index 26fc6ad14..f51cbc277 100644
--- a/test/floatcmp.go
+++ b/test/floatcmp.go
@@ -9,13 +9,13 @@ package main
import "math"
type floatTest struct {
- name string;
- expr bool;
- want bool;
+ name string
+ expr bool
+ want bool
}
-var nan float64 = math.NaN();
-var f float64 = 1;
+var nan float64 = math.NaN()
+var f float64 = 1
var tests = []floatTest{
floatTest{"nan == nan", nan == nan, false},
@@ -75,14 +75,14 @@ var tests = []floatTest{
}
func main() {
- bad := false;
+ bad := false
for _, t := range tests {
if t.expr != t.want {
if !bad {
- bad = true;
- println("BUG: floatcmp");
+ bad = true
+ println("BUG: floatcmp")
}
- println(t.name, "=", t.expr, "want", t.want);
+ println(t.name, "=", t.expr, "want", t.want)
}
}
}
diff --git a/test/for.go b/test/for.go
index 05260ff88..36ad15709 100644
--- a/test/for.go
+++ b/test/for.go
@@ -8,49 +8,49 @@ package main
func assertequal(is, shouldbe int, msg string) {
if is != shouldbe {
- print("assertion fail", msg, "\n");
- panic(1);
+ print("assertion fail", msg, "\n")
+ panic(1)
}
}
func main() {
- var i, sum int;
+ var i, sum int
- i = 0;
+ i = 0
for {
- i = i + 1;
+ i = i + 1
if i > 5 {
- break;
+ break
}
}
- assertequal(i, 6, "break");
+ assertequal(i, 6, "break")
- sum = 0;
+ sum = 0
for i := 0; i <= 10; i++ {
- sum = sum + i;
+ sum = sum + i
}
- assertequal(sum, 55, "all three");
+ assertequal(sum, 55, "all three")
- sum = 0;
+ sum = 0
for i := 0; i <= 10; {
- sum = sum + i;
- i++;
+ sum = sum + i
+ i++
}
- assertequal(sum, 55, "only two");
+ assertequal(sum, 55, "only two")
- sum = 0;
+ sum = 0
for sum < 100 {
- sum = sum + 9;
+ sum = sum + 9
}
- assertequal(sum, 99 + 9, "only one");
+ assertequal(sum, 99 + 9, "only one")
- sum = 0;
+ sum = 0
for i := 0; i <= 10; i++ {
if i % 2 == 0 {
- continue;
+ continue
}
- sum = sum + i;
+ sum = sum + i
}
- assertequal(sum, 1+3+5+7+9, "continue");
+ assertequal(sum, 1+3+5+7+9, "continue")
}
diff --git a/test/func.go b/test/func.go
index ee9414ddc..0c1a07979 100644
--- a/test/func.go
+++ b/test/func.go
@@ -9,8 +9,8 @@ package main
func assertequal(is, shouldbe int, msg string) {
if is != shouldbe {
- print("assertion fail", msg, "\n");
- panic(1);
+ print("assertion fail", msg, "\n")
+ panic(1)
}
}
@@ -21,69 +21,69 @@ func f2(a int) {
}
func f3(a, b int) int {
- return a+b;
+ return a+b
}
func f4(a, b int, c float) int {
- return (a+b)/2 + int(c);
+ return (a+b)/2 + int(c)
}
func f5(a int) int {
- return 5;
+ return 5
}
func f6(a int) (r int) {
- return 6;
+ return 6
}
func f7(a int) (x int, y float) {
- return 7, 7.0;
+ return 7, 7.0
}
func f8(a int) (x int, y float) {
- return 8, 8.0;
+ return 8, 8.0
}
type T struct {
- x, y int;
+ x, y int
}
func (t *T) m10(a int, b float) int {
- return (t.x+a) * (t.y+int(b));
+ return (t.x+a) * (t.y+int(b))
}
func f9(a int) (i int, f float) {
- i = 9;
- f = 9.0;
- return;
+ i = 9
+ f = 9.0
+ return
}
func main() {
- f1();
- f2(1);
- r3 := f3(1, 2);
- assertequal(r3, 3, "3");
- r4 := f4(0, 2, 3.0);
- assertequal(r4, 4, "4");
- r5 := f5(1);
- assertequal(r5, 5, "5");
- r6 := f6(1);
- assertequal(r6, 6, "6");
- r7, s7 := f7(1);
- assertequal(r7, 7, "r7");
- assertequal(int(s7), 7, "s7");
- r8, s8 := f8(1);
- assertequal(r8, 8, "r8");
- assertequal(int(s8), 8, "s8");
- r9, s9 := f9(1);
- assertequal(r9, 9, "r9");
- assertequal(int(s9), 9, "s9");
- var t *T = new(T);
- t.x = 1;
- t.y = 2;
- r10 := t.m10(1, 3.0);
- assertequal(r10, 10, "10");
+ f1()
+ f2(1)
+ r3 := f3(1, 2)
+ assertequal(r3, 3, "3")
+ r4 := f4(0, 2, 3.0)
+ assertequal(r4, 4, "4")
+ r5 := f5(1)
+ assertequal(r5, 5, "5")
+ r6 := f6(1)
+ assertequal(r6, 6, "6")
+ r7, s7 := f7(1)
+ assertequal(r7, 7, "r7")
+ assertequal(int(s7), 7, "s7")
+ r8, s8 := f8(1)
+ assertequal(r8, 8, "r8")
+ assertequal(int(s8), 8, "s8")
+ r9, s9 := f9(1)
+ assertequal(r9, 9, "r9")
+ assertequal(int(s9), 9, "s9")
+ var t *T = new(T)
+ t.x = 1
+ t.y = 2
+ r10 := t.m10(1, 3.0)
+ assertequal(r10, 10, "10")
}
diff --git a/test/func1.go b/test/func1.go
index 2c767d21d..56f4dfcba 100644
--- a/test/func1.go
+++ b/test/func1.go
@@ -9,10 +9,10 @@
package main
func f1(a int) (int, float) { // BUG (not caught by compiler): multiple return values must have names
- return 7, 7.0;
+ return 7, 7.0
}
func f2(a int) (a int, b float) { // ERROR "redeclared|definition"
- return 8, 8.0;
+ return 8, 8.0
}
diff --git a/test/func2.go b/test/func2.go
index e8e6842e0..5a6d7d0e1 100644
--- a/test/func2.go
+++ b/test/func2.go
@@ -5,20 +5,20 @@
// license that can be found in the LICENSE file.
package main
-import os "os";
+import os "os"
-type t1 int;
-type t2 int;
-type t3 int;
+type t1 int
+type t2 int
+type t3 int
-func f1(t1, t2, t3);
-func f2(t1, t2, t3 bool);
-func f3(t1, t2, x t3);
-func f4(t1, *t3);
-func (x *t1) f5(y []t2) (t1, *t3);
-func f6() (int, *string);
-func f7(*t2, t3);
-func f8(os int) int;
+func f1(t1, t2, t3)
+func f2(t1, t2, t3 bool)
+func f3(t1, t2, x t3)
+func f4(t1, *t3)
+func (x *t1) f5(y []t2) (t1, *t3)
+func f6() (int, *string)
+func f7(*t2, t3)
+func f8(os int) int
func f9(os int) int {
return os
diff --git a/test/func3.go b/test/func3.go
index 33e80a716..110b0ef1c 100644
--- a/test/func3.go
+++ b/test/func3.go
@@ -6,12 +6,12 @@
package main
-type t1 int;
-type t2 int;
-type t3 int;
+type t1 int
+type t2 int
+type t3 int
-func f1(*t2, x t3); // ERROR "named"
-func f2(t1, *t2, x t3); // ERROR "named"
-func f3() (x int, *string); // ERROR "named"
+func f1(*t2, x t3) // ERROR "named"
+func f2(t1, *t2, x t3) // ERROR "named"
+func f3() (x int, *string) // ERROR "named"
-func f4() (t1 t1); // legal - scope of parameter named t1 starts in body of f4.
+func f4() (t1 t1) // legal - scope of parameter named t1 starts in body of f4.
diff --git a/test/func4.go b/test/func4.go
index bcf5b93fa..69ce56a19 100644
--- a/test/func4.go
+++ b/test/func4.go
@@ -9,6 +9,6 @@ package main
var notmain func()
func main() {
- var x = &main; // ERROR "address of|invalid"
- main = notmain; // ERROR "assign to|invalid"
+ var x = &main // ERROR "address of|invalid"
+ main = notmain // ERROR "assign to|invalid"
}
diff --git a/test/garbage/Makefile b/test/garbage/Makefile
index 1a5062b44..ab29e0956 100644
--- a/test/garbage/Makefile
+++ b/test/garbage/Makefile
@@ -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 ../../src/Make.$(GOARCH)
+include ../../src/Make.inc
ALL=\
parser\
diff --git a/test/garbage/parser.go b/test/garbage/parser.go
index e8e049474..cf68737fb 100644
--- a/test/garbage/parser.go
+++ b/test/garbage/parser.go
@@ -30,11 +30,11 @@ func isPkgFile(dir *os.FileInfo) bool {
}
func pkgName(filename string) string {
- file, err := parser.ParseFile(filename, nil, nil, parser.PackageClauseOnly)
+ file, err := parser.ParseFile(filename, nil, parser.PackageClauseOnly)
if err != nil || file == nil {
return ""
}
- return file.Name.Name()
+ return file.Name.Name
}
func parseDir(dirpath string) map[string]*ast.Package {
@@ -74,7 +74,7 @@ func main() {
flag.Parse()
var t0 int64
- pkgroot := os.Getenv("GOROOT") + "/src/pkg/"
+ pkgroot := runtime.GOROOT() + "/src/pkg/"
for pass := 0; pass < 2; pass++ {
// Once the heap is grown to full size, reset counters.
// This hides the start-up pauses, which are much smaller
@@ -115,7 +115,6 @@ var packages = []string{
"archive/tar",
"asn1",
"big",
- "bignum",
"bufio",
"bytes",
"cmath",
@@ -185,7 +184,6 @@ var packages = []string{
"mime",
"net",
"nntp",
- "once",
"os",
"os/signal",
"patch",
diff --git a/test/gc.go b/test/gc.go
index 864d05c39..3aab8fac9 100644
--- a/test/gc.go
+++ b/test/gc.go
@@ -11,7 +11,7 @@ import "runtime"
func mk2() {
b := new([10000]byte)
_ = b
- // println(b, "stored at", &b);
+ // println(b, "stored at", &b)
}
func mk1() { mk2() }
diff --git a/test/gc1.go b/test/gc1.go
index 055079aab..84034e7ce 100644
--- a/test/gc1.go
+++ b/test/gc1.go
@@ -8,7 +8,7 @@ package main
func main() {
for i := 0; i < 1e5; i++ {
- x := new([100]byte);
- _ = x;
+ x := new([100]byte)
+ _ = x
}
}
diff --git a/test/golden-arm.out b/test/golden-arm.out
deleted file mode 100644
index a51aea8e5..000000000
--- a/test/golden-arm.out
+++ /dev/null
@@ -1,110 +0,0 @@
-
-=========== ./cmp2.go
-panic: runtime error: comparing uncomparable type []int
-
-panic PC=xxx
-
-=========== ./cmp3.go
-panic: runtime error: comparing uncomparable type []int
-
-panic PC=xxx
-
-=========== ./cmp4.go
-panic: runtime error: hash of unhashable type []int
-
-panic PC=xxx
-
-=========== ./cmp5.go
-panic: runtime error: hash of unhashable type []int
-
-panic PC=xxx
-
-=========== ./helloworld.go
-hello, world
-
-=========== ./printbig.go
--9223372036854775808
-9223372036854775807
-
-=========== ./turing.go
-Hello World!
-
-=========== ken/intervar.go
- print 1 bio 2 file 3 -- abc
-
-=========== ken/label.go
-100
-
-=========== ken/rob1.go
-9876543210
-
-=========== ken/rob2.go
-(defn foo (add 12 34))
-
-=========== ken/simpprint.go
-hello world
-
-=========== ken/simpswitch.go
-0out01out12out2aout34out4fiveout56out6aout78out89out9
-
-=========== ken/string.go
-abcxyz-abcxyz-abcxyz-abcxyz-abcxyz-abcxyz-abcxyz
-
-=========== chan/nonblock.go
-PASS
-
-=========== interface/fail.go
-panic: interface conversion: *main.S is not main.I: missing method Foo
-
-panic PC=xxx
-
-=========== interface/returntype.go
-panic: interface conversion: *main.S is not main.I2: missing method Name
-
-panic PC=xxx
-
-=========== fixedbugs/bug016.go
-fixedbugs/bug016.go:11: constant -3 overflows uint
-
-=========== fixedbugs/bug027.go
-hi
-0 44444
-1 3333
-2 222
-3 11
-4 0
-0 44444
-1 3333
-2 222
-3 11
-4 0
-
-=========== fixedbugs/bug067.go
-ok
-
-=========== fixedbugs/bug070.go
-outer loop top k 0
-inner loop top i 0
-do break
-broke
-
-=========== fixedbugs/bug081.go
-fixedbugs/bug081.go:9: typechecking loop
-
-=========== fixedbugs/bug093.go
-M
-
-=========== fixedbugs/bug113.go
-panic: interface conversion: interface is int, not int32
-
-panic PC=xxx
-
-=========== fixedbugs/bug148.go
-2 3
-panic: interface conversion: interface is main.T, not main.T
-
-panic PC=xxx
-
-=========== bugs/bug260.go
-FAIL
-BUG: bug260 failed
diff --git a/test/golden.out b/test/golden.out
index 82e85340a..e587912a4 100644
--- a/test/golden.out
+++ b/test/golden.out
@@ -173,17 +173,3 @@ panic: interface conversion: interface is main.T, not main.T
panic PC=xxx
== bugs/
-
-=========== bugs/bug260.go
-FAIL
-BUG: bug260 failed
-
-=========== bugs/bug274.go
-BUG: errchk: command succeeded unexpectedly
-
-=========== bugs/bug286.go
-test2 called g
-panic: wrong method called
-
-panic PC=xxx
-BUG: bug286 failed
diff --git a/test/hashmap.go b/test/hashmap.go
index 62943a713..0a4d7ab61 100755
--- a/test/hashmap.go
+++ b/test/hashmap.go
@@ -11,7 +11,7 @@ package main
func ASSERT(p bool) {
if !p {
- // panic 0;
+ // panic 0
}
}
@@ -20,8 +20,8 @@ func ASSERT(p bool) {
// Implementation of the HashMap
type KeyType interface {
- Hash() uint32;
- Match(other *KeyType) bool
+ Hash() uint32
+ Match(other KeyType) bool
}
@@ -31,31 +31,30 @@ type ValueType interface {
type Entry struct {
- key *KeyType;
- value *ValueType;
+ key KeyType
+ value ValueType
}
-// Using the Array type below doesn't seem to work
-//type Array array [1024] Entry;
+type Array [1024]Entry
type HashMap struct {
- map_ *[1024] Entry;
- log2_capacity_ uint32;
- occupancy_ uint32;
+ map_ *Array
+ log2_capacity_ uint32
+ occupancy_ uint32
}
func (m *HashMap) capacity() uint32 {
- return 1 << m.log2_capacity_;
+ return 1 << m.log2_capacity_
}
func (m *HashMap) Clear() {
// Mark all entries as empty.
- var i uint32 = m.capacity() - 1;
+ var i uint32 = m.capacity() - 1
for i > 0 {
- m.map_[i].key = nil;
+ m.map_[i].key = nil
i = i - 1
}
m.occupancy_ = 0
@@ -63,72 +62,72 @@ func (m *HashMap) Clear() {
func (m *HashMap) Initialize (initial_log2_capacity uint32) {
- m.log2_capacity_ = initial_log2_capacity;
- m.map_ = new([1024] Entry);
- m.Clear();
+ m.log2_capacity_ = initial_log2_capacity
+ m.map_ = new(Array)
+ m.Clear()
}
-func (m *HashMap) Probe (key *KeyType) *Entry {
- ASSERT(key != nil);
+func (m *HashMap) Probe (key KeyType) *Entry {
+ ASSERT(key != nil)
- var i uint32 = key.Hash() % m.capacity();
- ASSERT(0 <= i && i < m.capacity());
+ var i uint32 = key.Hash() % m.capacity()
+ ASSERT(0 <= i && i < m.capacity())
- ASSERT(m.occupancy_ < m.capacity()); // guarantees loop termination
+ ASSERT(m.occupancy_ < m.capacity()) // guarantees loop termination
for m.map_[i].key != nil && !m.map_[i].key.Match(key) {
- i++;
+ i++
if i >= m.capacity() {
- i = 0;
+ i = 0
}
}
- return &m.map_[i];
+ return &m.map_[i]
}
-func (m *HashMap) Lookup (key *KeyType, insert bool) *Entry {
+func (m *HashMap) Lookup (key KeyType, insert bool) *Entry {
// Find a matching entry.
- var p *Entry = m.Probe(key);
+ var p *Entry = m.Probe(key)
if p.key != nil {
- return p;
+ return p
}
// No entry found; insert one if necessary.
if insert {
- p.key = key;
- p.value = nil;
- m.occupancy_++;
+ p.key = key
+ p.value = nil
+ m.occupancy_++
// Grow the map if we reached >= 80% occupancy.
if m.occupancy_ + m.occupancy_/4 >= m.capacity() {
- m.Resize();
- p = m.Probe(key);
+ m.Resize()
+ p = m.Probe(key)
}
- return p;
+ return p
}
// No entry found and none inserted.
- return nil;
+ return nil
}
func (m *HashMap) Resize() {
- var hmap *[1024] Entry = m.map_;
- var n uint32 = m.occupancy_;
+ var hmap *Array = m.map_
+ var n uint32 = m.occupancy_
// Allocate a new map of twice the current size.
- m.Initialize(m.log2_capacity_ << 1);
+ m.Initialize(m.log2_capacity_ << 1)
// Rehash all current entries.
- var i uint32 = 0;
+ var i uint32 = 0
for n > 0 {
if hmap[i].key != nil {
- m.Lookup(hmap[i].key, true).value = hmap[i].value;
- n = n - 1;
+ m.Lookup(hmap[i].key, true).value = hmap[i].value
+ n = n - 1
}
- i++;
+ i++
}
}
@@ -137,46 +136,46 @@ func (m *HashMap) Resize() {
// Test code
type Number struct {
- x uint32;
+ x uint32
}
func (n *Number) Hash() uint32 {
- return n.x * 23;
+ return n.x * 23
}
-func (n *Number) Match(other *KeyType) bool {
- // var y *Number = other;
- // return n.x == y.x;
- return false;
+func (n *Number) Match(other KeyType) bool {
+ // var y *Number = other
+ // return n.x == y.x
+ return false
}
func MakeNumber (x uint32) *Number {
- var n *Number = new(Number);
- n.x = x;
- return n;
+ var n *Number = new(Number)
+ n.x = x
+ return n
}
func main() {
- //f unc (n int) int { return n + 1; }(1);
+ // func (n int) int { return n + 1; }(1)
- //print "HashMap - gri 2/8/2008\n";
+ //print "HashMap - gri 2/8/2008\n"
- var hmap *HashMap = new(HashMap);
- hmap.Initialize(0);
+ var hmap *HashMap = new(HashMap)
+ hmap.Initialize(0)
- var x1 *Number = MakeNumber(1001);
- var x2 *Number = MakeNumber(2002);
- var x3 *Number = MakeNumber(3003);
- _, _, _ = x1, x2, x3;
+ var x1 *Number = MakeNumber(1001)
+ var x2 *Number = MakeNumber(2002)
+ var x3 *Number = MakeNumber(3003)
+ _, _, _ = x1, x2, x3
// this doesn't work I think...
- //hmap.Lookup(x1, true);
- //hmap.Lookup(x2, true);
- //hmap.Lookup(x3, true);
+ //hmap.Lookup(x1, true)
+ //hmap.Lookup(x2, true)
+ //hmap.Lookup(x3, true)
- //print "done\n";
+ //print "done\n"
}
diff --git a/test/helloworld.go b/test/helloworld.go
index 7234be35c..e55a74bbd 100644
--- a/test/helloworld.go
+++ b/test/helloworld.go
@@ -7,5 +7,5 @@
package main
func main() {
- print("hello, world\n");
+ print("hello, world\n")
}
diff --git a/test/if.go b/test/if.go
index c7f14c42a..db1fe8b79 100644
--- a/test/if.go
+++ b/test/if.go
@@ -8,92 +8,92 @@ package main
func assertequal(is, shouldbe int, msg string) {
if is != shouldbe {
- print("assertion fail", msg, "\n");
- panic(1);
+ print("assertion fail", msg, "\n")
+ panic(1)
}
}
func main() {
- i5 := 5;
- i7 := 7;
+ i5 := 5
+ i7 := 7
- var count int;
+ var count int
- count = 0;
+ count = 0
if true {
- count = count + 1;
+ count = count + 1
}
- assertequal(count, 1, "if true");
+ assertequal(count, 1, "if true")
- count = 0;
+ count = 0
if false {
- count = count + 1;
+ count = count + 1
}
- assertequal(count, 0, "if false");
+ assertequal(count, 0, "if false")
- count = 0;
+ count = 0
if one := 1; true {
- count = count + one;
+ count = count + one
}
- assertequal(count, 1, "if true one");
+ assertequal(count, 1, "if true one")
- count = 0;
+ count = 0
if one := 1; false {
- count = count + 1;
- _ = one;
+ count = count + 1
+ _ = one
}
- assertequal(count, 0, "if false one");
+ assertequal(count, 0, "if false one")
- count = 0;
+ count = 0
if {
- count = count + 1;
+ count = count + 1
}
- assertequal(count, 1, "if empty");
+ assertequal(count, 1, "if empty")
- count = 0;
+ count = 0
if one := 1; true {
- count = count + one;
+ count = count + one
}
- assertequal(count, 1, "if empty one");
+ assertequal(count, 1, "if empty one")
- count = 0;
+ count = 0
if i5 < i7 {
- count = count + 1;
+ count = count + 1
}
- assertequal(count, 1, "if cond");
+ assertequal(count, 1, "if cond")
- count = 0;
+ count = 0
if true {
- count = count + 1;
+ count = count + 1
} else
- count = count - 1;
- assertequal(count, 1, "if else true");
+ count = count - 1
+ assertequal(count, 1, "if else true")
- count = 0;
+ count = 0
if false {
- count = count + 1;
+ count = count + 1
} else
- count = count - 1;
- assertequal(count, -1, "if else false");
+ count = count - 1
+ assertequal(count, -1, "if else false")
- count = 0;
+ count = 0
if t:=1; false {
- count = count + 1;
- _ = t;
- t := 7;
- _ = t;
+ count = count + 1
+ _ = t
+ t := 7
+ _ = t
} else
- count = count - t;
- assertequal(count, -1, "if else false var");
+ count = count - t
+ assertequal(count, -1, "if else false var")
- count = 0;
- t := 1;
+ count = 0
+ t := 1
if false {
- count = count + 1;
- t := 7;
- _ = t;
+ count = count + 1
+ t := 7
+ _ = t
} else
- count = count - t;
- _ = t;
- assertequal(count, -1, "if else false var outside");
+ count = count - t
+ _ = t
+ assertequal(count, -1, "if else false var outside")
}
diff --git a/test/if1.go b/test/if1.go
index 3f3ef1597..061c36411 100644
--- a/test/if1.go
+++ b/test/if1.go
@@ -9,12 +9,12 @@ package main
import "os"
func main() {
- count := 7;
+ count := 7
if one := 1; {
count = count + one
}
if count != 8 {
- print(count, " should be 8\n");
+ print(count, " should be 8\n")
os.Exit(1)
}
}
diff --git a/test/import.go b/test/import.go
index 9bed8213c..96330340d 100644
--- a/test/import.go
+++ b/test/import.go
@@ -16,10 +16,10 @@ import . "os"
func f(e os.Error)
func main() {
- var _e_ _os_.Error;
- var dot Error;
+ var _e_ _os_.Error
+ var dot Error
- f(_e_);
- f(dot);
+ f(_e_)
+ f(dot)
}
diff --git a/test/import1.go b/test/import1.go
index 351462a26..8bb2a94a2 100644
--- a/test/import1.go
+++ b/test/import1.go
@@ -12,6 +12,6 @@ import "bufio" // GCCGO_ERROR "previous|not used"
import bufio "os" // ERROR "redeclared|redefinition|incompatible"
import (
- "fmt"; // GCCGO_ERROR "previous|not used"
- fmt "math"; // ERROR "redeclared|redefinition|incompatible"
+ "fmt" // GCCGO_ERROR "previous|not used"
+ fmt "math" // ERROR "redeclared|redefinition|incompatible"
)
diff --git a/test/index.go b/test/index.go
new file mode 100644
index 000000000..38aa33dd3
--- /dev/null
+++ b/test/index.go
@@ -0,0 +1,224 @@
+// $G $D/$F.go && $L $F.$A &&
+// ./$A.out -pass 0 >tmp.go && $G tmp.go && $L -o $A.out1 tmp.$A && ./$A.out1 &&
+// ./$A.out -pass 1 >tmp.go && errchk $G -e tmp.go &&
+// ./$A.out -pass 2 >tmp.go && errchk $G -e tmp.go
+// rm -f tmp.go $A.out1
+
+// Copyright 2010 The Go 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 of index and slice bounds checks.
+
+package main
+
+import (
+ "bufio"
+ "flag"
+ "fmt"
+ "os"
+)
+
+const prolog = `
+
+package main
+
+import (
+ "runtime"
+)
+
+type quad struct { x, y, z, w int }
+
+const (
+ cj = 11
+ ci int = 12
+ ci32 int32 = 13
+ ci64 int64 = 14
+ ci64big int64 = 1<<31
+ ci64bigger int64 = 1<<32
+ chuge = 1<<100
+
+ cnj = -2
+ cni int = -3
+ cni32 int32 = -4
+ cni64 int64 = -5
+ cni64big int64 = -1<<31
+ cni64bigger int64 = -1<<32
+ cnhuge = -1<<100
+)
+
+var j int = 20
+var i int = 21
+var i32 int32 = 22
+var i64 int64 = 23
+var i64big int64 = 1<<31
+var i64bigger int64 = 1<<32
+var huge uint64 = 1<<64 - 1
+
+var nj int = -10
+var ni int = -11
+var ni32 int32 = -12
+var ni64 int64 = -13
+var ni64big int64 = -1<<31
+var ni64bigger int64 = -1<<32
+var nhuge int64 = -1<<63
+
+var si []int = make([]int, 10)
+var ai [10]int
+var pai *[10]int = &ai
+
+var sq []quad = make([]quad, 10)
+var aq [10]quad
+var paq *[10]quad = &aq
+
+type T struct {
+ si []int
+ ai [10]int
+ pai *[10]int
+ sq []quad
+ aq [10]quad
+ paq *[10]quad
+}
+
+var t = T{si, ai, pai, sq, aq, paq}
+
+var pt = &T{si, ai, pai, sq, aq, paq}
+
+// test that f panics
+func test(f func(), s string) {
+ defer func() {
+ if err := recover(); err == nil {
+ _, file, line, _ := runtime.Caller(2)
+ bug()
+ print(file, ":", line, ": ", s, " did not panic\n")
+ }
+ }()
+ f()
+}
+
+var X interface{}
+func use(y interface{}) {
+ X = y
+}
+
+var didBug = false
+
+func bug() {
+ if !didBug {
+ didBug = true
+ println("BUG")
+ }
+}
+
+func main() {
+`
+
+// Passes:
+// 0 - dynamic checks
+// 1 - static checks of invalid constants (cannot assign to types)
+// 2 - static checks of array bounds
+var pass = flag.Int("pass", 0, "which test (0,1,2)")
+
+func testExpr(b *bufio.Writer, expr string) {
+ if *pass == 0 {
+ fmt.Fprintf(b, "\ttest(func(){use(%s)}, %q)\n", expr, expr)
+ } else {
+ fmt.Fprintf(b, "\tuse(%s) // ERROR \"index|overflow\"\n", expr)
+ }
+}
+
+func main() {
+ b := bufio.NewWriter(os.Stdout)
+
+ flag.Parse()
+
+ if *pass == 0 {
+ fmt.Fprint(b, "// $G $D/$F.go && $L $F.$A && ./$A.out\n\n")
+ } else {
+ fmt.Fprint(b, "// errchk $G -e $D/$F.go\n\n")
+ }
+ fmt.Fprint(b, prolog)
+
+ var choices = [][]string{
+ // Direct value, fetch from struct, fetch from struct pointer.
+ // The last two cases get us to oindex_const_sudo in gsubr.c.
+ []string{"", "t.", "pt."},
+
+ // Array, pointer to array, slice.
+ []string{"a", "pa", "s"},
+
+ // Element is int, element is quad (struct).
+ // This controls whether we end up in gsubr.c (i) or cgen.c (q).
+ []string{"i", "q"},
+
+ // Variable or constant.
+ []string{"", "c"},
+
+ // Positive or negative.
+ []string{"", "n"},
+
+ // Size of index.
+ []string{"j", "i", "i32", "i64", "i64big", "i64bigger", "huge"},
+ }
+
+ forall(choices, func(x []string) {
+ p, a, e, c, n, i := x[0], x[1], x[2], x[3], x[4], x[5]
+
+ // Pass: dynamic=0, static=1, 2.
+ // Which cases should be caught statically?
+ // Only constants, obviously.
+ // Beyond that, must be one of these:
+ // indexing into array or pointer to array
+ // negative constant
+ // large constant
+ thisPass := 0
+ if c == "c" && (a == "a" || a == "pa" || n == "n" || i == "i64big" || i == "i64bigger" || i == "huge") {
+ if i == "huge" {
+ // Due to a detail of 6g's internals,
+ // the huge constant errors happen in an
+ // earlier pass than the others and inhibits
+ // the next pass from running.
+ // So run it as a separate check.
+ thisPass = 1
+ } else {
+ thisPass = 2
+ }
+ }
+
+ // Only print the test case if it is appropriate for this pass.
+ if thisPass == *pass {
+ pae := p+a+e
+ cni := c+n+i
+
+ // Index operation
+ testExpr(b, pae + "[" + cni + "]")
+
+ // Slice operation.
+ // Low index 0 is a special case in ggen.c
+ // so test both 0 and 1.
+ testExpr(b, pae + "[0:" + cni + "]")
+ testExpr(b, pae + "[1:" + cni + "]")
+ testExpr(b, pae + "[" + cni + ":]")
+ testExpr(b, pae + "[" + cni + ":" + cni + "]")
+ }
+ })
+
+ fmt.Fprintln(b, "}")
+ b.Flush()
+}
+
+func forall(choices [][]string, f func([]string)) {
+ x := make([]string, len(choices))
+
+ var recurse func(d int)
+ recurse = func(d int) {
+ if d >= len(choices) {
+ f(x)
+ return
+ }
+ for _, x[d] = range choices[d] {
+ recurse(d+1)
+ }
+ }
+ recurse(0)
+}
diff --git a/test/indirect1.go b/test/indirect1.go
index 7cd476a01..0fd5c19d4 100644
--- a/test/indirect1.go
+++ b/test/indirect1.go
@@ -64,5 +64,5 @@ func f() {
cap(b1)+ // ERROR "illegal|invalid|must be"
cap(b2)+ // ERROR "illegal|invalid|must be"
cap(b3)+
- cap(b4); // ERROR "illegal|invalid|must be"
+ cap(b4) // ERROR "illegal|invalid|must be"
}
diff --git a/test/initialize.go b/test/initialize.go
index 807bf5bda..6dd7d67dc 100644
--- a/test/initialize.go
+++ b/test/initialize.go
@@ -10,11 +10,11 @@ import "fmt"
import "reflect"
type S struct {
- A, B, C, X, Y, Z int;
+ A, B, C, X, Y, Z int
}
type T struct {
- S;
+ S
}
var a1 = S { 0, 0, 0, 1, 2, 3 }
@@ -49,14 +49,14 @@ var same = []Same {
}
func main() {
- ok := true;
+ ok := true
for _, s := range same {
if !reflect.DeepEqual(s.a, s.b) {
- ok = false;
- fmt.Printf("not same: %v and %v\n", s.a, s.b);
+ ok = false
+ fmt.Printf("not same: %v and %v\n", s.a, s.b)
}
}
if !ok {
- fmt.Println("BUG: test/initialize");
+ fmt.Println("BUG: test/initialize")
}
}
diff --git a/test/initializerr.go b/test/initializerr.go
index b0366ddde..37f8a602d 100644
--- a/test/initializerr.go
+++ b/test/initializerr.go
@@ -7,17 +7,17 @@
package main
type S struct {
- A, B, C, X, Y, Z int;
+ A, B, C, X, Y, Z int
}
type T struct {
- S;
+ S
}
var x = 1
-var a1 = S { 0, X: 1 }; // ERROR "mixture|undefined"
-var a2 = S { Y: 3, Z: 2, Y: 3 }; // ERROR "duplicate"
-var a3 = T { 1, 2, 3, 4, 5, 6 }; // ERROR "convert|too many"
+var a1 = S { 0, X: 1 } // ERROR "mixture|undefined"
+var a2 = S { Y: 3, Z: 2, Y: 3 } // ERROR "duplicate"
+var a3 = T { 1, 2, 3, 4, 5, 6 } // ERROR "convert|too many"
var a4 = [5]byte{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 } // ERROR "index|too many"
var a5 = []byte { x: 2 } // ERROR "index"
diff --git a/test/initsyscall.go b/test/initsyscall.go
index 139bb0acb..b5e5812b6 100644
--- a/test/initsyscall.go
+++ b/test/initsyscall.go
@@ -18,8 +18,8 @@ func f() {
}
func init() {
- go f();
- time.Nanoseconds();
+ go f()
+ time.Nanoseconds()
}
func main() {
diff --git a/test/int_lit.go b/test/int_lit.go
index 1cb42f5d1..2644e17b5 100644
--- a/test/int_lit.go
+++ b/test/int_lit.go
@@ -16,9 +16,9 @@ func main() {
0x0 +
0x123 +
0X0 +
- 0X123;
+ 0X123
if s != 788 {
- print("s is ", s, "; should be 788\n");
- os.Exit(1);
+ print("s is ", s, "; should be 788\n")
+ os.Exit(1)
}
}
diff --git a/test/interface/bigdata.go b/test/interface/bigdata.go
index 674ea1276..44f6ab127 100644
--- a/test/interface/bigdata.go
+++ b/test/interface/bigdata.go
@@ -23,24 +23,24 @@ func (z *IntPtr) M() int64 { return int64(*z) }
var bad bool
func test(name string, i I) {
- m := i.M();
+ m := i.M()
if m != 12345 {
- println(name, m);
- bad = true;
+ println(name, m)
+ bad = true
}
}
func ptrs() {
- var bigptr BigPtr = BigPtr{ 10000, 2000, 300, 45 };
- var smallptr SmallPtr = SmallPtr{ 12345 };
- var intptr IntPtr = 12345;
-
-// test("bigptr", bigptr);
- test("&bigptr", &bigptr);
-// test("smallptr", smallptr);
- test("&smallptr", &smallptr);
-// test("intptr", intptr);
- test("&intptr", &intptr);
+ var bigptr BigPtr = BigPtr{ 10000, 2000, 300, 45 }
+ var smallptr SmallPtr = SmallPtr{ 12345 }
+ var intptr IntPtr = 12345
+
+// test("bigptr", bigptr)
+ test("&bigptr", &bigptr)
+// test("smallptr", smallptr)
+ test("&smallptr", &smallptr)
+// test("intptr", intptr)
+ test("&intptr", &intptr)
}
type Big struct { a, b, c, d int64 }
@@ -53,23 +53,23 @@ type Int int32
func (z Int) M() int64 { return int64(z) }
func nonptrs() {
- var big Big = Big{ 10000, 2000, 300, 45 };
- var small Small = Small{ 12345 };
- var int Int = 12345;
-
- test("big", big);
- test("&big", &big);
- test("small", small);
- test("&small", &small);
- test("int", int);
- test("&int", &int);
+ var big Big = Big{ 10000, 2000, 300, 45 }
+ var small Small = Small{ 12345 }
+ var int Int = 12345
+
+ test("big", big)
+ test("&big", &big)
+ test("small", small)
+ test("&small", &small)
+ test("int", int)
+ test("&int", &int)
}
func main() {
- ptrs();
- nonptrs();
+ ptrs()
+ nonptrs()
if bad {
- println("BUG: interface4");
+ println("BUG: interface4")
}
}
diff --git a/test/interface/convert1.go b/test/interface/convert1.go
index 0eff6a95d..658b1a92f 100644
--- a/test/interface/convert1.go
+++ b/test/interface/convert1.go
@@ -9,17 +9,17 @@
package main
-type R interface { R(); }
-type RW interface { R(); W(); }
+type R interface { R() }
+type RW interface { R(); W() }
var e interface {}
-var r R;
-var rw RW;
+var r R
+var rw RW
func main() {
- r = r;
- r = rw;
- e = r;
- e = rw;
- rw = rw;
+ r = r
+ r = rw
+ e = r
+ e = rw
+ rw = rw
}
diff --git a/test/interface/convert2.go b/test/interface/convert2.go
index 0eff6a95d..658b1a92f 100644
--- a/test/interface/convert2.go
+++ b/test/interface/convert2.go
@@ -9,17 +9,17 @@
package main
-type R interface { R(); }
-type RW interface { R(); W(); }
+type R interface { R() }
+type RW interface { R(); W() }
var e interface {}
-var r R;
-var rw RW;
+var r R
+var rw RW
func main() {
- r = r;
- r = rw;
- e = r;
- e = rw;
- rw = rw;
+ r = r
+ r = rw
+ e = r
+ e = rw
+ rw = rw
}
diff --git a/test/interface/embed.go b/test/interface/embed.go
index 936ea49b7..2fddee190 100644
--- a/test/interface/embed.go
+++ b/test/interface/embed.go
@@ -4,7 +4,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Check methods derived from embedded interface and *interface values.
+// Check methods derived from embedded interface values.
package main
@@ -19,64 +19,43 @@ func (t T) M() int64 { return int64(t) }
var t = T(Value)
var pt = &t
var ti Inter = t
-var pti = &ti
type S struct { Inter }
var s = S{ ti }
var ps = &s
-type SP struct { *Inter }
-var sp = SP{ &ti }
-var psp = &sp
-
var i Inter
-var pi = &i
var ok = true
func check(s string, v int64) {
if v != Value {
- println(s, v);
- ok = false;
+ println(s, v)
+ ok = false
}
}
func main() {
- check("t.M()", t.M());
- check("pt.M()", pt.M());
- check("ti.M()", ti.M());
- check("pti.M()", pti.M());
- check("s.M()", s.M());
- check("ps.M()", ps.M());
- check("sp.M()", sp.M());
- check("psp.M()", psp.M());
-
- i = t;
- check("i = t; i.M()", i.M());
- check("i = t; pi.M()", pi.M());
-
- i = pt;
- check("i = pt; i.M()", i.M());
- check("i = pt; pi.M()", pi.M());
-
- i = s;
- check("i = s; i.M()", i.M());
- check("i = s; pi.M()", pi.M());
-
- i = ps;
- check("i = ps; i.M()", i.M());
- check("i = ps; pi.M()", pi.M());
-
- i = sp;
- check("i = sp; i.M()", i.M());
- check("i = sp; pi.M()", pi.M());
-
- i = psp;
- check("i = psp; i.M()", i.M());
- check("i = psp; pi.M()", pi.M());
+ check("t.M()", t.M())
+ check("pt.M()", pt.M())
+ check("ti.M()", ti.M())
+ check("s.M()", s.M())
+ check("ps.M()", ps.M())
+
+ i = t
+ check("i = t; i.M()", i.M())
+
+ i = pt
+ check("i = pt; i.M()", i.M())
+
+ i = s
+ check("i = s; i.M()", i.M())
+
+ i = ps
+ check("i = ps; i.M()", i.M())
if !ok {
- println("BUG: interface10");
+ println("BUG: interface10")
os.Exit(1)
}
}
diff --git a/test/interface/embed0.go b/test/interface/embed0.go
index fd16e2733..bbd81e760 100644
--- a/test/interface/embed0.go
+++ b/test/interface/embed0.go
@@ -12,18 +12,18 @@ type T int
func (t T) m() {}
type I interface { m() }
-type J interface { I; }
+type J interface { I }
func main() {
- var i I;
- var j J;
- var t T;
- i = t;
- j = t;
- _ = i;
- _ = j;
- i = j;
- _ = i;
- j = i;
- _ = j;
+ var i I
+ var j J
+ var t T
+ i = t
+ j = t
+ _ = i
+ _ = j
+ i = j
+ _ = i
+ j = i
+ _ = j
}
diff --git a/test/interface/embed1.go b/test/interface/embed1.go
index 6e15031ea..24e50471f 100644
--- a/test/interface/embed1.go
+++ b/test/interface/embed1.go
@@ -14,32 +14,32 @@ type T int
func (t T) m() {}
type I interface { m() }
-type J interface { I; }
+type J interface { I }
-type PI interface { p.I; }
-type PJ interface { p.J; }
+type PI interface { p.I }
+type PJ interface { p.J }
func main() {
- var i I;
- var j J;
- var t T;
- i = t;
- j = t;
- _ = i;
- _ = j;
- i = j;
- _ = i;
- j = i;
- _ = j;
- var pi PI;
- var pj PJ;
- var pt p.T;
- pi = pt;
- pj = pt;
- _ = pi;
- _ = pj;
- pi = pj;
- _ = pi;
- pj = pi;
- _ = pj;
+ var i I
+ var j J
+ var t T
+ i = t
+ j = t
+ _ = i
+ _ = j
+ i = j
+ _ = i
+ j = i
+ _ = j
+ var pi PI
+ var pj PJ
+ var pt p.T
+ pi = pt
+ pj = pt
+ _ = pi
+ _ = pj
+ pi = pj
+ _ = pi
+ pj = pi
+ _ = pj
}
diff --git a/test/interface/embed2.go b/test/interface/embed2.go
new file mode 100644
index 000000000..c18a1fece
--- /dev/null
+++ b/test/interface/embed2.go
@@ -0,0 +1,70 @@
+// errchk $G -e $D/$F.go
+
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Check methods derived from embedded interface and *interface values.
+
+package main
+
+import "os"
+
+const Value = 1e12
+
+type Inter interface { M() int64 }
+
+type T int64
+func (t T) M() int64 { return int64(t) }
+var t = T(Value)
+var pt = &t
+var ti Inter = t
+var pti = &ti
+
+type S struct { Inter }
+var s = S{ ti }
+var ps = &s
+
+type SP struct { *Inter } // ERROR "interface"
+
+var i Inter
+var pi = &i
+
+var ok = true
+
+func check(s string, v int64) {
+ if v != Value {
+ println(s, v)
+ ok = false
+ }
+}
+
+func main() {
+ check("t.M()", t.M())
+ check("pt.M()", pt.M())
+ check("ti.M()", ti.M())
+ check("pti.M()", pti.M()) // ERROR "method"
+ check("s.M()", s.M())
+ check("ps.M()", ps.M())
+
+ i = t
+ check("i = t; i.M()", i.M())
+ check("i = t; pi.M()", pi.M()) // ERROR "method"
+
+ i = pt
+ check("i = pt; i.M()", i.M())
+ check("i = pt; pi.M()", pi.M()) // ERROR "method"
+
+ i = s
+ check("i = s; i.M()", i.M())
+ check("i = s; pi.M()", pi.M()) // ERROR "method"
+
+ i = ps
+ check("i = ps; i.M()", i.M())
+ check("i = ps; pi.M()", pi.M()) // ERROR "method"
+
+ if !ok {
+ println("BUG: interface10")
+ os.Exit(1)
+ }
+}
diff --git a/test/interface/explicit.go b/test/interface/explicit.go
index 120135cb6..b952f8fc8 100644
--- a/test/interface/explicit.go
+++ b/test/interface/explicit.go
@@ -42,10 +42,10 @@ func main() {
t = i // ERROR "incompatible|need type assertion"
i = i2 // ok
- i2 = i // ERROR "missing N method"
+ i2 = i // ERROR "incompatible|missing N method"
i = I(i2) // ok
- i2 = I2(i) // ERROR "missing N method"
+ i2 = I2(i) // ERROR "invalid|missing N method"
e = E(t) // ok
t = T(e) // ERROR "need explicit|need type assertion|incompatible"
@@ -64,8 +64,8 @@ var _ = m.(Int) // ERROR "impossible type assertion"
var ii int
var jj Int
-var m1 M = ii // ERROR "missing"
-var m2 M = jj // ERROR "wrong type for M method"
+var m1 M = ii // ERROR "incompatible|missing"
+var m2 M = jj // ERROR "incompatible|wrong type for M method"
-var m3 = M(ii) // ERROR "missing"
-var m4 = M(jj) // ERROR "wrong type for M method"
+var m3 = M(ii) // ERROR "invalid|missing"
+var m4 = M(jj) // ERROR "invalid|wrong type for M method"
diff --git a/test/interface/fail.go b/test/interface/fail.go
index 07bd865c8..3e741d3f9 100644
--- a/test/interface/fail.go
+++ b/test/interface/fail.go
@@ -13,12 +13,12 @@ type I interface {
}
func main() {
- var s *S;
- var i I;
- var e interface {};
- e = s;
- i = e.(I);
- _ = i;
+ var s *S
+ var i I
+ var e interface {}
+ e = s
+ i = e.(I)
+ _ = i
}
// hide S down here to avoid static warning
diff --git a/test/interface/fake.go b/test/interface/fake.go
index 687b3ff0c..5cf3be052 100644
--- a/test/interface/fake.go
+++ b/test/interface/fake.go
@@ -12,69 +12,69 @@ package main
import "reflect"
type T struct {
- f float32;
- g float32;
+ f float32
+ g float32
- s string;
- t string;
+ s string
+ t string
- u uint32;
- v uint32;
+ u uint32
+ v uint32
- w uint32;
- x uint32;
+ w uint32
+ x uint32
- y uint32;
- z uint32;
+ y uint32
+ z uint32
}
func add(s, t string) string {
- return s + t;
+ return s + t
}
func assert(b bool) {
if !b {
- panic("assert");
+ panic("assert")
}
}
func main() {
- var x T;
- x.f = 1.0;
- x.g = x.f;
- x.s = add("abc", "def");
- x.t = add("abc", "def");
- x.u = 1;
- x.v = 2;
- x.w = 1<<28;
- x.x = 2<<28;
- x.y = 0x12345678;
- x.z = x.y;
+ var x T
+ x.f = 1.0
+ x.g = x.f
+ x.s = add("abc", "def")
+ x.t = add("abc", "def")
+ x.u = 1
+ x.v = 2
+ x.w = 1<<28
+ x.x = 2<<28
+ x.y = 0x12345678
+ x.z = x.y
// check mem and string
- v := reflect.NewValue(x);
- i := v.(*reflect.StructValue).Field(0);
- j := v.(*reflect.StructValue).Field(1);
- assert(i.Interface() == j.Interface());
+ v := reflect.NewValue(x)
+ i := v.(*reflect.StructValue).Field(0)
+ j := v.(*reflect.StructValue).Field(1)
+ assert(i.Interface() == j.Interface())
- s := v.(*reflect.StructValue).Field(2);
- t := v.(*reflect.StructValue).Field(3);
- assert(s.Interface() == t.Interface());
+ s := v.(*reflect.StructValue).Field(2)
+ t := v.(*reflect.StructValue).Field(3)
+ assert(s.Interface() == t.Interface())
// make sure different values are different.
// make sure whole word is being compared,
// not just a single byte.
- i = v.(*reflect.StructValue).Field(4);
- j = v.(*reflect.StructValue).Field(5);
- assert(i.Interface() != j.Interface());
+ i = v.(*reflect.StructValue).Field(4)
+ j = v.(*reflect.StructValue).Field(5)
+ assert(i.Interface() != j.Interface())
- i = v.(*reflect.StructValue).Field(6);
- j = v.(*reflect.StructValue).Field(7);
- assert(i.Interface() != j.Interface());
+ i = v.(*reflect.StructValue).Field(6)
+ j = v.(*reflect.StructValue).Field(7)
+ assert(i.Interface() != j.Interface())
- i = v.(*reflect.StructValue).Field(8);
- j = v.(*reflect.StructValue).Field(9);
- assert(i.Interface() == j.Interface());
+ i = v.(*reflect.StructValue).Field(8)
+ j = v.(*reflect.StructValue).Field(9)
+ assert(i.Interface() == j.Interface())
}
/*
diff --git a/test/interface/receiver.go b/test/interface/receiver.go
index f74cecb2c..f53daf8da 100644
--- a/test/interface/receiver.go
+++ b/test/interface/receiver.go
@@ -64,7 +64,7 @@ func main() {
v = &t
v.V()
- // p = t; // ERROR
+ // p = t // ERROR
var i interface{} = t
if _, ok := i.(P); ok {
println("dynamic i.(P) succeeded incorrectly")
@@ -87,7 +87,7 @@ func main() {
v = &s
v.V()
- // p = s; // ERROR
+ // p = s // ERROR
var j interface{} = s
if _, ok := j.(P); ok {
println("dynamic j.(P) succeeded incorrectly")
diff --git a/test/interface/returntype.go b/test/interface/returntype.go
index 93298bce7..c526b3b0e 100644
--- a/test/interface/returntype.go
+++ b/test/interface/returntype.go
@@ -18,8 +18,8 @@ type I1 interface { Name() int8 }
type I2 interface { Name() int64 }
func main() {
- var i1 I1;
- var s *S;
- i1 = s;
+ var i1 I1
+ var s *S
+ i1 = s
print(i1.(I2).Name())
}
diff --git a/test/interface/struct.go b/test/interface/struct.go
index 1c7028e06..40b7f4f91 100644
--- a/test/interface/struct.go
+++ b/test/interface/struct.go
@@ -14,39 +14,39 @@ var fail int
func check(b bool, msg string) {
if (!b) {
- println("failure in", msg);
- fail++;
+ println("failure in", msg)
+ fail++
}
}
-type I1 interface { Get() int; Put(int); }
+type I1 interface { Get() int; Put(int) }
type S1 struct { i int }
func (p S1) Get() int { return p.i }
func (p S1) Put(i int) { p.i = i }
func f1() {
- s := S1{1};
- var i I1 = s;
- i.Put(2);
- check(i.Get() == 1, "f1 i");
- check(s.i == 1, "f1 s");
+ s := S1{1}
+ var i I1 = s
+ i.Put(2)
+ check(i.Get() == 1, "f1 i")
+ check(s.i == 1, "f1 s")
}
func f2() {
- s := S1{1};
- var i I1 = &s;
- i.Put(2);
- check(i.Get() == 1, "f2 i");
- check(s.i == 1, "f2 s");
+ s := S1{1}
+ var i I1 = &s
+ i.Put(2)
+ check(i.Get() == 1, "f2 i")
+ check(s.i == 1, "f2 s")
}
func f3() {
- s := &S1{1};
- var i I1 = s;
- i.Put(2);
- check(i.Get() == 1, "f3 i");
- check(s.i == 1, "f3 s");
+ s := &S1{1}
+ var i I1 = s
+ i.Put(2)
+ check(i.Get() == 1, "f3 i")
+ check(s.i == 1, "f3 s")
}
type S2 struct { i int }
@@ -55,57 +55,57 @@ func (p *S2) Put(i int) { p.i = i }
// Disallowed by restriction of values going to pointer receivers
// func f4() {
-// s := S2{1};
-// var i I1 = s;
-// i.Put(2);
-// check(i.Get() == 2, "f4 i");
-// check(s.i == 1, "f4 s");
+// s := S2{1}
+// var i I1 = s
+// i.Put(2)
+// check(i.Get() == 2, "f4 i")
+// check(s.i == 1, "f4 s")
// }
func f5() {
- s := S2{1};
- var i I1 = &s;
- i.Put(2);
- check(i.Get() == 2, "f5 i");
- check(s.i == 2, "f5 s");
+ s := S2{1}
+ var i I1 = &s
+ i.Put(2)
+ check(i.Get() == 2, "f5 i")
+ check(s.i == 2, "f5 s")
}
func f6() {
- s := &S2{1};
- var i I1 = s;
- i.Put(2);
- check(i.Get() == 2, "f6 i");
- check(s.i == 2, "f6 s");
+ s := &S2{1}
+ var i I1 = s
+ i.Put(2)
+ check(i.Get() == 2, "f6 i")
+ check(s.i == 2, "f6 s")
}
-type I2 interface { Get() int64; Put(int64); }
+type I2 interface { Get() int64; Put(int64) }
type S3 struct { i, j, k, l int64 }
func (p S3) Get() int64 { return p.l }
func (p S3) Put(i int64) { p.l = i }
func f7() {
- s := S3{1, 2, 3, 4};
- var i I2 = s;
- i.Put(5);
- check(i.Get() == 4, "f7 i");
- check(s.l == 4, "f7 s");
+ s := S3{1, 2, 3, 4}
+ var i I2 = s
+ i.Put(5)
+ check(i.Get() == 4, "f7 i")
+ check(s.l == 4, "f7 s")
}
func f8() {
- s := S3{1, 2, 3, 4};
- var i I2 = &s;
- i.Put(5);
- check(i.Get() == 4, "f8 i");
- check(s.l == 4, "f8 s");
+ s := S3{1, 2, 3, 4}
+ var i I2 = &s
+ i.Put(5)
+ check(i.Get() == 4, "f8 i")
+ check(s.l == 4, "f8 s")
}
func f9() {
- s := &S3{1, 2, 3, 4};
- var i I2 = s;
- i.Put(5);
- check(i.Get() == 4, "f9 i");
- check(s.l == 4, "f9 s");
+ s := &S3{1, 2, 3, 4}
+ var i I2 = s
+ i.Put(5)
+ check(i.Get() == 4, "f9 i")
+ check(s.l == 4, "f9 s")
}
type S4 struct { i, j, k, l int64 }
@@ -114,42 +114,42 @@ func (p *S4) Put(i int64) { p.l = i }
// Disallowed by restriction of values going to pointer receivers
// func f10() {
-// s := S4{1, 2, 3, 4};
-// var i I2 = s;
-// i.Put(5);
-// check(i.Get() == 5, "f10 i");
-// check(s.l == 4, "f10 s");
+// s := S4{1, 2, 3, 4}
+// var i I2 = s
+// i.Put(5)
+// check(i.Get() == 5, "f10 i")
+// check(s.l == 4, "f10 s")
// }
func f11() {
- s := S4{1, 2, 3, 4};
- var i I2 = &s;
- i.Put(5);
- check(i.Get() == 5, "f11 i");
- check(s.l == 5, "f11 s");
+ s := S4{1, 2, 3, 4}
+ var i I2 = &s
+ i.Put(5)
+ check(i.Get() == 5, "f11 i")
+ check(s.l == 5, "f11 s")
}
func f12() {
- s := &S4{1, 2, 3, 4};
- var i I2 = s;
- i.Put(5);
- check(i.Get() == 5, "f12 i");
- check(s.l == 5, "f12 s");
+ s := &S4{1, 2, 3, 4}
+ var i I2 = s
+ i.Put(5)
+ check(i.Get() == 5, "f12 i")
+ check(s.l == 5, "f12 s")
}
func main() {
- f1();
- f2();
- f3();
-// f4();
- f5();
- f6();
- f7();
- f8();
- f9();
-// f10();
- f11();
- f12();
+ f1()
+ f2()
+ f3()
+// f4()
+ f5()
+ f6()
+ f7()
+ f8()
+ f9()
+// f10()
+ f11()
+ f12()
if fail > 0 {
os.Exit(1)
}
diff --git a/test/iota.go b/test/iota.go
index 393edac80..20b77c6cc 100644
--- a/test/iota.go
+++ b/test/iota.go
@@ -8,113 +8,113 @@ package main
func assert(cond bool, msg string) {
if !cond {
- print("assertion fail: ", msg, "\n");
- panic(1);
+ print("assertion fail: ", msg, "\n")
+ panic(1)
}
}
const (
- x int = iota;
- y = iota;
- z = 1 << iota;
- f float = 2 * iota;
- g float = 4.5 * float(iota);
+ x int = iota
+ y = iota
+ z = 1 << iota
+ f float = 2 * iota
+ g float = 4.5 * float(iota)
)
const (
- X = 0;
- Y;
- Z;
+ X = 0
+ Y
+ Z
)
const (
- A = 1 << iota;
- B;
- C;
- D;
- E = iota * iota;
- F;
- G;
+ A = 1 << iota
+ B
+ C
+ D
+ E = iota * iota
+ F
+ G
)
const (
- a = 1;
- b = iota << a;
- c = iota << b;
- d;
+ a = 1
+ b = iota << a
+ c = iota << b
+ d
)
const (
- i = (a << iota) + (b * iota);
- j;
- k;
- l;
+ i = (a << iota) + (b * iota)
+ j
+ k
+ l
)
const (
- m = iota == 0;
- n;
+ m = iota == 0
+ n
)
const (
- p = float(iota);
- q;
- r;
+ p = float(iota)
+ q
+ r
)
const (
- s = string(iota + 'a');
- t;
+ s = string(iota + 'a')
+ t
)
const (
- abit, amask = 1 << iota, 1 << iota - 1;
- bbit, bmask = 1 << iota, 1 << iota - 1;
- cbit, cmask = 1 << iota, 1 << iota - 1;
+ abit, amask = 1 << iota, 1 << iota - 1
+ bbit, bmask = 1 << iota, 1 << iota - 1
+ cbit, cmask = 1 << iota, 1 << iota - 1
)
func main() {
- assert(x == 0, "x");
- assert(y == 1, "y");
- assert(z == 4, "z");
- assert(f == 6.0, "f");
- assert(g == 18.0, "g");
-
- assert(X == 0, "X");
- assert(Y == 0, "Y");
- assert(Z == 0, "Z");
-
- assert(A == 1, "A");
- assert(B == 2, "B");
- assert(C == 4, "C");
- assert(D == 8, "D");
- assert(E == 16, "E");
- assert(F == 25, "F");
-
- assert(a == 1, "a");
- assert(b == 2, "b");
- assert(c == 8, "c");
- assert(d == 12, "d");
-
- assert(i == 1, "i");
- assert(j == 4, "j");
- assert(k == 8, "k");
- assert(l == 14, "l");
-
- assert(m, "m");
- assert(!n, "n");
-
- assert(p == 0.0, "p");
- assert(q == 1.0, "q");
- assert(r == 2.0, "r");
-
- assert(s == "a", "s");
- assert(t == "b", "t");
-
- assert(abit == 1, "abit");
- assert(amask == 0, "amask");
- assert(bbit == 2, "bbit");
- assert(bmask == 1, "bmask");
- assert(cbit == 4, "cbit");
- assert(cmask == 3, "cmask");
+ assert(x == 0, "x")
+ assert(y == 1, "y")
+ assert(z == 4, "z")
+ assert(f == 6.0, "f")
+ assert(g == 18.0, "g")
+
+ assert(X == 0, "X")
+ assert(Y == 0, "Y")
+ assert(Z == 0, "Z")
+
+ assert(A == 1, "A")
+ assert(B == 2, "B")
+ assert(C == 4, "C")
+ assert(D == 8, "D")
+ assert(E == 16, "E")
+ assert(F == 25, "F")
+
+ assert(a == 1, "a")
+ assert(b == 2, "b")
+ assert(c == 8, "c")
+ assert(d == 12, "d")
+
+ assert(i == 1, "i")
+ assert(j == 4, "j")
+ assert(k == 8, "k")
+ assert(l == 14, "l")
+
+ assert(m, "m")
+ assert(!n, "n")
+
+ assert(p == 0.0, "p")
+ assert(q == 1.0, "q")
+ assert(r == 2.0, "r")
+
+ assert(s == "a", "s")
+ assert(t == "b", "t")
+
+ assert(abit == 1, "abit")
+ assert(amask == 0, "amask")
+ assert(bbit == 2, "bbit")
+ assert(bmask == 1, "bmask")
+ assert(cbit == 4, "cbit")
+ assert(cmask == 3, "cmask")
}
diff --git a/test/ken/array.go b/test/ken/array.go
index 7785cdf8f..40209f5da 100644
--- a/test/ken/array.go
+++ b/test/ken/array.go
@@ -81,8 +81,8 @@ func testpfpf() {
// call ptr dynamic with ptr fixed from new
func testpdpf1() {
a := new([40]int)
- setpd(a)
- res(sumpd(a), 0, 40)
+ setpd(a[0:])
+ res(sumpd(a[0:]), 0, 40)
b := (*a)[5:30]
res(sumpd(b), 5, 30)
@@ -92,8 +92,8 @@ func testpdpf1() {
func testpdpf2() {
var a [80]int
- setpd(&a)
- res(sumpd(&a), 0, 80)
+ setpd(a[0:])
+ res(sumpd(a[0:]), 0, 80)
}
// generate bounds error with ptr dynamic
diff --git a/test/ken/convert.go b/test/ken/convert.go
new file mode 100644
index 000000000..3780ec886
--- /dev/null
+++ b/test/ken/convert.go
@@ -0,0 +1,431 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// near-exhaustive test of converting numbers between types.
+
+package main
+
+var i8 int8;
+var u8 uint8;
+var i16 int16;
+var u16 uint16;
+var i32 int32;
+var u32 uint32;
+var i64 int64;
+var u64 uint64;
+var f32 float32;
+var f64 float64;
+
+type big float64
+
+type t struct {
+ from, to int
+ val big
+}
+
+const (
+ ti8 = iota+1
+ tu8
+ ti16
+ tu16
+ ti32
+ tu32
+ ti64
+ tu64
+ tf32
+ tf64
+)
+
+var x = []t{
+
+ /* value good in all types (10) */
+ { ti8, ti8, 10 }, { ti8, tu8, 10 }, { ti8, ti16, 10 }, { ti8, tu16, 10 },
+ { ti8, ti32, 10 }, { ti8, tu32, 10 }, { ti8, ti64, 10 }, { ti8, tu64, 10 },
+ { ti8, tf32, 10 }, { ti8, tf64, 10 },
+
+ { tu8, ti8, 10 }, { tu8, tu8, 10 }, { tu8, ti16, 10 }, { tu8, tu16, 10 },
+ { tu8, ti32, 10 }, { tu8, tu32, 10 }, { tu8, ti64, 10 }, { tu8, tu64, 10 },
+ { tu8, tf32, 10 }, { tu8, tf64, 10 },
+
+ { ti16, ti8, 10 }, { ti16, tu8, 10 }, { ti16, ti16, 10 }, { ti16, tu16, 10 },
+ { ti16, ti32, 10 }, { ti16, tu32, 10 }, { ti16, ti64, 10 }, { ti16, tu64, 10 },
+ { ti16, tf32, 10 }, { ti16, tf64, 10 },
+
+ { tu16, ti8, 10 }, { tu16, tu8, 10 }, { tu16, ti16, 10 }, { tu16, tu16, 10 },
+ { tu16, ti32, 10 }, { tu16, tu32, 10 }, { tu16, ti64, 10 }, { tu16, tu64, 10 },
+ { tu16, tf32, 10 }, { tu16, tf64, 10 },
+
+ { ti32, ti8, 10 }, { ti32, tu8, 10 }, { ti32, ti16, 10 }, { ti32, tu16, 10 },
+ { ti32, ti32, 10 }, { ti32, tu32, 10 }, { ti32, ti64, 10 }, { ti32, tu64, 10 },
+ { ti32, tf32, 10 }, { ti32, tf64, 10 },
+
+ { tu32, ti8, 10 }, { tu32, tu8, 10 }, { tu32, ti16, 10 }, { tu32, tu16, 10 },
+ { tu32, ti32, 10 }, { tu32, tu32, 10 }, { tu32, ti64, 10 }, { tu32, tu64, 10 },
+ { tu32, tf32, 10 }, { tu32, tf64, 10 },
+
+ { ti64, ti8, 10 }, { ti64, tu8, 10 }, { ti64, ti16, 10 }, { ti64, tu16, 10 },
+ { ti64, ti32, 10 }, { ti64, tu32, 10 }, { ti64, ti64, 10 }, { ti64, tu64, 10 },
+ { ti64, tf32, 10 }, { ti64, tf64, 10 },
+
+ { tu64, ti8, 10 }, { tu64, tu8, 10 }, { tu64, ti16, 10 }, { tu64, tu16, 10 },
+ { tu64, ti32, 10 }, { tu64, tu32, 10 }, { tu64, ti64, 10 }, { tu64, tu64, 10 },
+ { tu64, tf32, 10 }, { tu64, tf64, 10 },
+
+ { tf32, ti8, 10 }, { tf32, tu8, 10 }, { tf32, ti16, 10 }, { tf32, tu16, 10 },
+ { tf32, ti32, 10 }, { tf32, tu32, 10 }, { tf32, ti64, 10 }, { tf32, tu64, 10 },
+ { tf32, tf32, 10 }, { tf32, tf64, 10 },
+
+ { tf64, ti8, 10 }, { tf64, tu8, 10 }, { tf64, ti16, 10 }, { tf64, tu16, 10 },
+ { tf64, ti32, 10 }, { tf64, tu32, 10 }, { tf64, ti64, 10 }, { tf64, tu64, 10 },
+ { tf64, tf32, 10 }, { tf64, tf64, 10 },
+
+ /* value good in all signed types (-4) */
+ { ti8, ti8, -4 }, { ti8, ti16, -4 },
+ { ti8, ti32, -4 }, { ti8, ti64, -4 },
+ { ti8, tf32, -4 }, { ti8, tf64, -4 },
+
+ { ti16, ti8, -4 }, { ti16, ti16, -4 },
+ { ti16, ti32, -4 }, { ti16, ti64, -4 },
+ { ti16, tf32, -4 },
+
+ { ti32, ti8, -4 }, { ti32, ti16, -4 },
+ { ti32, ti32, -4 }, { ti32, ti64, -4 },
+ { ti32, tf32, -4 }, { ti32, tf64, -4 },
+
+ { ti64, ti8, -4 }, { ti64, ti16, -4 },
+ { ti64, ti32, -4 }, { ti64, ti64, -4 },
+ { ti64, tf32, -4 },
+
+ { tf32, ti8, -4 }, { tf32, ti16, -4 },
+ { tf32, ti32, -4 }, { tf32, ti64, -4 },
+ { tf32, tf32, -4 },
+
+ { tf64, ti8, -4 }, { tf64, ti16, -4 },
+ { tf64, ti32, -4 }, { tf64, ti64, -4 },
+ { tf64, tf32, -4 }, { tf64, tf64, -4 },
+
+ /* value good in u8 and up (175) */
+ { tu8, tu8, 175 }, { tu8, ti16, 175 }, { tu8, tu16, 175 },
+ { tu8, ti32, 175 }, { tu8, tu32, 175 }, { tu8, ti64, 175 }, { tu8, tu64, 175 },
+ { tu8, tf32, 175 }, { tu8, tf64, 175 },
+
+ { ti16, tu8, 175 }, { ti16, ti16, 175 }, { ti16, tu16, 175 },
+ { ti16, ti32, 175 }, { ti16, tu32, 175 }, { ti16, ti64, 175 }, { ti16, tu64, 175 },
+ { ti16, tf32, 175 }, { ti16, tf64, 175 },
+
+ { tu16, tu8, 175 }, { tu16, ti16, 175 }, { tu16, tu16, 175 },
+ { tu16, ti32, 175 }, { tu16, tu32, 175 }, { tu16, ti64, 175 }, { tu16, tu64, 175 },
+ { tu16, tf32, 175 }, { tu16, tf64, 175 },
+
+ { ti32, tu8, 175 }, { ti32, ti16, 175 }, { ti32, tu16, 175 },
+ { ti32, ti32, 175 }, { ti32, tu32, 175 }, { ti32, ti64, 175 }, { ti32, tu64, 175 },
+ { ti32, tf32, 175 }, { ti32, tf64, 175 },
+
+ { tu32, tu8, 175 }, { tu32, ti16, 175 }, { tu32, tu16, 175 },
+ { tu32, ti32, 175 }, { tu32, tu32, 175 }, { tu32, ti64, 175 }, { tu32, tu64, 175 },
+ { tu32, tf32, 175 }, { tu32, tf64, 175 },
+
+ { ti64, tu8, 175 }, { ti64, ti16, 175 }, { ti64, tu16, 175 },
+ { ti64, ti32, 175 }, { ti64, tu32, 175 }, { ti64, ti64, 175 }, { ti64, tu64, 175 },
+ { ti64, tf32, 175 }, { ti64, tf64, 175 },
+
+ { tu64, tu8, 175 }, { tu64, ti16, 175 }, { tu64, tu16, 175 },
+ { tu64, ti32, 175 }, { tu64, tu32, 175 }, { tu64, ti64, 175 }, { tu64, tu64, 175 },
+ { tu64, tf32, 175 }, { tu64, tf64, 175 },
+
+ { tf32, tu8, 175 }, { tf32, ti16, 175 }, { tf32, tu16, 175 },
+ { tf32, ti32, 175 }, { tf32, tu32, 175 }, { tf32, ti64, 175 }, { tf32, tu64, 175 },
+ { tf32, tf32, 175 }, { tf32, tf64, 175 },
+
+ { tf64, tu8, 175 }, { tf64, ti16, 175 }, { tf64, tu16, 175 },
+ { tf64, ti32, 175 }, { tf64, tu32, 175 }, { tf64, ti64, 175 }, { tf64, tu64, 175 },
+ { tf64, tf32, 175 }, { tf64, tf64, 175 },
+
+ /* value good in u16 and up (41259) */
+ { tu16, tu16, 41259 },
+ { tu16, ti32, 41259 }, { tu16, ti64, 41259 }, { tu16, tu64, 41259 },
+ { tu16, tf32, 41259 }, { tu16, tf64, 41259 },
+
+ { ti32, tu16, 41259 },
+ { ti32, ti32, 41259 }, { ti32, tu32, 41259 }, { ti32, ti64, 41259 }, { ti32, tu64, 41259 },
+ { ti32, tf32, 41259 }, { ti32, tf64, 41259 },
+
+ { tu32, tu16, 41259 },
+ { tu32, ti32, 41259 }, { tu32, tu32, 41259 }, { tu32, ti64, 41259 }, { tu32, tu64, 41259 },
+ { tu32, tf32, 41259 }, { tu32, tf64, 41259 },
+
+ { ti64, tu16, 41259 },
+ { ti64, ti32, 41259 }, { ti64, tu32, 41259 }, { ti64, ti64, 41259 }, { ti64, tu64, 41259 },
+ { ti64, tf32, 41259 }, { ti64, tf64, 41259 },
+
+ { tu64, tu16, 41259 },
+ { tu64, ti32, 41259 }, { tu64, tu32, 41259 }, { tu64, ti64, 41259 }, { tu64, tu64, 41259 },
+ { tu64, tf32, 41259 }, { tu64, tf64, 41259 },
+
+ { tf32, tu16, 41259 },
+ { tf32, ti32, 41259 }, { tf32, tu32, 41259 }, { tf32, ti64, 41259 }, { tf32, tu64, 41259 },
+ { tf32, tf32, 41259 }, { tf32, tf64, 41259 },
+
+ { tf64, tu16, 41259 },
+ { tf64, ti32, 41259 }, { tf64, tu32, 41259 }, { tf64, ti64, 41259 }, { tf64, tu64, 41259 },
+ { tf64, tf32, 41259 }, { tf64, tf64, 41259 },
+
+ /* value good in u32 and up (3758096384) */
+ { tu32, tu32, 3758096384 }, { tu32, ti64, 3758096384 }, { tu32, tu64, 3758096384 },
+ { tu32, tf32, 3758096384 }, { tu32, tf64, 3758096384 },
+
+ { ti64, tu32, 3758096384 }, { ti64, ti64, 3758096384 }, { ti64, tu64, 3758096384 },
+ { ti64, tf32, 3758096384 }, { ti64, tf64, 3758096384 },
+
+ { tu64, tu32, 3758096384 }, { tu64, ti64, 3758096384 }, { tu64, tu64, 3758096384 },
+ { tu64, tf32, 3758096384 }, { tu64, tf64, 3758096384 },
+
+ { tf32, tu32, 3758096384 }, { tf32, ti64, 3758096384 }, { tf32, tu64, 3758096384 },
+ { tf32, tf32, 3758096384 }, { tf32, tf64, 3758096384 },
+
+ { tf64, tu32, 3758096384 }, { tf64, ti64, 3758096384 }, { tf64, tu64, 3758096384 },
+ { tf64, tf32, 3758096384 }, { tf64, tf64, 3758096384 },
+
+ /* value good in u64 and up (16717361816799281152) */
+ { tu64, tu64, 16717361816799281152 },
+ { tu64, tf32, 16717361816799281152 }, { tu64, tf64, 16717361816799281152 },
+
+ { tf32, tu64, 16717361816799281152 },
+ { tf32, tf32, 16717361816799281152 }, { tf32, tf64, 16717361816799281152 },
+
+ { tf64, tu64, 16717361816799281152 },
+ { tf64, tf32, 16717361816799281152 }, { tf64, tf64, 16717361816799281152 },
+}
+
+func main() {
+ for i:=0; i<len(x); i++ {
+ v := x[i].val // input value
+ w := big(0) // output value
+ f := x[i].from // input type
+ t := x[i].to // output type
+
+ i8 = 0; u8 = 0; i16 = 0; u16 = 0
+ i32 = 0; u32 = 0; i64 = 0; u64 = 0
+ f32 = 0; f64 = 0
+
+ switch f*100 + t {
+ default:
+ println("missing case", i, v, f, t)
+ w = v
+
+ case ti8*100 + ti8:
+ i8 = int8(v); i8 = int8(i8); w = big(i8)
+ case ti8*100 + tu8:
+ i8 = int8(v); u8 = uint8(i8); w = big(u8)
+ case ti8*100 + ti16:
+ i8 = int8(v); i16 = int16(i8); w = big(i16)
+ case ti8*100 + tu16:
+ i8 = int8(v); u16 = uint16(i8); w = big(u16)
+ case ti8*100 + ti32:
+ i8 = int8(v); i32 = int32(i8); w = big(i32)
+ case ti8*100 + tu32:
+ i8 = int8(v); u32 = uint32(i8); w = big(u32)
+ case ti8*100 + ti64:
+ i8 = int8(v); i64 = int64(i8); w = big(i64)
+ case ti8*100 + tu64:
+ i8 = int8(v); u64 = uint64(i8); w = big(u64)
+ case ti8*100 + tf32:
+ i8 = int8(v); f32 = float32(i8); w = big(f32)
+ case ti8*100 + tf64:
+ i8 = int8(v); f64 = float64(i8); w = big(f64)
+
+ case tu8*100 + ti8:
+ u8 = uint8(v); i8 = int8(u8); w = big(i8)
+ case tu8*100 + tu8:
+ u8 = uint8(v); u8 = uint8(u8); w = big(u8)
+ case tu8*100 + ti16:
+ u8 = uint8(v); i16 = int16(u8); w = big(i16)
+ case tu8*100 + tu16:
+ u8 = uint8(v); u16 = uint16(u8); w = big(u16)
+ case tu8*100 + ti32:
+ u8 = uint8(v); i32 = int32(u8); w = big(i32)
+ case tu8*100 + tu32:
+ u8 = uint8(v); u32 = uint32(u8); w = big(u32)
+ case tu8*100 + ti64:
+ u8 = uint8(v); i64 = int64(u8); w = big(i64)
+ case tu8*100 + tu64:
+ u8 = uint8(v); u64 = uint64(u8); w = big(u64)
+ case tu8*100 + tf32:
+ u8 = uint8(v); f32 = float32(u8); w = big(f32)
+ case tu8*100 + tf64:
+ u8 = uint8(v); f64 = float64(u8); w = big(f64)
+
+ case ti16*100 + ti8:
+ i16 = int16(v); i8 = int8(i16); w = big(i8)
+ case ti16*100 + tu8:
+ i16 = int16(v); u8 = uint8(i16); w = big(u8)
+ case ti16*100 + ti16:
+ i16 = int16(v); i16 = int16(i16); w = big(i16)
+ case ti16*100 + tu16:
+ i16 = int16(v); u16 = uint16(i16); w = big(u16)
+ case ti16*100 + ti32:
+ i16 = int16(v); i32 = int32(i16); w = big(i32)
+ case ti16*100 + tu32:
+ i16 = int16(v); u32 = uint32(i16); w = big(u32)
+ case ti16*100 + ti64:
+ i16 = int16(v); i64 = int64(i16); w = big(i64)
+ case ti16*100 + tu64:
+ i16 = int16(v); u64 = uint64(i16); w = big(u64)
+ case ti16*100 + tf32:
+ i16 = int16(v); f32 = float32(i16); w = big(f32)
+ case ti16*100 + tf64:
+ i16 = int16(v); f64 = float64(i16); w = big(f64)
+
+ case tu16*100 + ti8:
+ u16 = uint16(v); i8 = int8(u16); w = big(i8)
+ case tu16*100 + tu8:
+ u16 = uint16(v); u8 = uint8(u16); w = big(u8)
+ case tu16*100 + ti16:
+ u16 = uint16(v); i16 = int16(u16); w = big(i16)
+ case tu16*100 + tu16:
+ u16 = uint16(v); u16 = uint16(u16); w = big(u16)
+ case tu16*100 + ti32:
+ u16 = uint16(v); i32 = int32(u16); w = big(i32)
+ case tu16*100 + tu32:
+ u16 = uint16(v); u32 = uint32(u16); w = big(u32)
+ case tu16*100 + ti64:
+ u16 = uint16(v); i64 = int64(u16); w = big(i64)
+ case tu16*100 + tu64:
+ u16 = uint16(v); u64 = uint64(u16); w = big(u64)
+ case tu16*100 + tf32:
+ u16 = uint16(v); f32 = float32(u16); w = big(f32)
+ case tu16*100 + tf64:
+ u16 = uint16(v); f64 = float64(u16); w = big(f64)
+
+ case ti32*100 + ti8:
+ i32 = int32(v); i8 = int8(i32); w = big(i8)
+ case ti32*100 + tu8:
+ i32 = int32(v); u8 = uint8(i32); w = big(u8)
+ case ti32*100 + ti16:
+ i32 = int32(v); i16 = int16(i32); w = big(i16)
+ case ti32*100 + tu16:
+ i32 = int32(v); u16 = uint16(i32); w = big(u16)
+ case ti32*100 + ti32:
+ i32 = int32(v); i32 = int32(i32); w = big(i32)
+ case ti32*100 + tu32:
+ i32 = int32(v); u32 = uint32(i32); w = big(u32)
+ case ti32*100 + ti64:
+ i32 = int32(v); i64 = int64(i32); w = big(i64)
+ case ti32*100 + tu64:
+ i32 = int32(v); u64 = uint64(i32); w = big(u64)
+ case ti32*100 + tf32:
+ i32 = int32(v); f32 = float32(i32); w = big(f32)
+ case ti32*100 + tf64:
+ i32 = int32(v); f64 = float64(i32); w = big(f64)
+
+ case tu32*100 + ti8:
+ u32 = uint32(v); i8 = int8(u32); w = big(i8)
+ case tu32*100 + tu8:
+ u32 = uint32(v); u8 = uint8(u32); w = big(u8)
+ case tu32*100 + ti16:
+ u32 = uint32(v); i16 = int16(u32); w = big(i16)
+ case tu32*100 + tu16:
+ u32 = uint32(v); u16 = uint16(u32); w = big(u16)
+ case tu32*100 + ti32:
+ u32 = uint32(v); i32 = int32(u32); w = big(i32)
+ case tu32*100 + tu32:
+ u32 = uint32(v); u32 = uint32(u32); w = big(u32)
+ case tu32*100 + ti64:
+ u32 = uint32(v); i64 = int64(u32); w = big(i64)
+ case tu32*100 + tu64:
+ u32 = uint32(v); u64 = uint64(u32); w = big(u64)
+ case tu32*100 + tf32:
+ u32 = uint32(v); f32 = float32(u32); w = big(f32)
+ case tu32*100 + tf64:
+ u32 = uint32(v); f64 = float64(u32); w = big(f64)
+
+ case ti64*100 + ti8:
+ i64 = int64(v); i8 = int8(i64); w = big(i8)
+ case ti64*100 + tu8:
+ i64 = int64(v); u8 = uint8(i64); w = big(u8)
+ case ti64*100 + ti16:
+ i64 = int64(v); i16 = int16(i64); w = big(i16)
+ case ti64*100 + tu16:
+ i64 = int64(v); u16 = uint16(i64); w = big(u16)
+ case ti64*100 + ti32:
+ i64 = int64(v); i32 = int32(i64); w = big(i32)
+ case ti64*100 + tu32:
+ i64 = int64(v); u32 = uint32(i64); w = big(u32)
+ case ti64*100 + ti64:
+ i64 = int64(v); i64 = int64(i64); w = big(i64)
+ case ti64*100 + tu64:
+ i64 = int64(v); u64 = uint64(i64); w = big(u64)
+ case ti64*100 + tf32:
+ i64 = int64(v); f32 = float32(i64); w = big(f32)
+ case ti64*100 + tf64:
+ i64 = int64(v); f64 = float64(i64); w = big(f64)
+
+ case tu64*100 + ti8:
+ u64 = uint64(v); i8 = int8(u64); w = big(i8)
+ case tu64*100 + tu8:
+ u64 = uint64(v); u8 = uint8(u64); w = big(u8)
+ case tu64*100 + ti16:
+ u64 = uint64(v); i16 = int16(u64); w = big(i16)
+ case tu64*100 + tu16:
+ u64 = uint64(v); u16 = uint16(u64); w = big(u16)
+ case tu64*100 + ti32:
+ u64 = uint64(v); i32 = int32(u64); w = big(i32)
+ case tu64*100 + tu32:
+ u64 = uint64(v); u32 = uint32(u64); w = big(u32)
+ case tu64*100 + ti64:
+ u64 = uint64(v); i64 = int64(u64); w = big(i64)
+ case tu64*100 + tu64:
+ u64 = uint64(v); u64 = uint64(u64); w = big(u64)
+ case tu64*100 + tf32:
+ u64 = uint64(v); f32 = float32(u64); w = big(f32)
+ case tu64*100 + tf64:
+ u64 = uint64(v); f64 = float64(u64); w = big(f64)
+
+ case tf32*100 + ti8:
+ f32 = float32(v); i8 = int8(f32); w = big(i8)
+ case tf32*100 + tu8:
+ f32 = float32(v); u8 = uint8(f32); w = big(u8)
+ case tf32*100 + ti16:
+ f32 = float32(v); i16 = int16(f32); w = big(i16)
+ case tf32*100 + tu16:
+ f32 = float32(v); u16 = uint16(f32); w = big(u16)
+ case tf32*100 + ti32:
+ f32 = float32(v); i32 = int32(f32); w = big(i32)
+ case tf32*100 + tu32:
+ f32 = float32(v); u32 = uint32(f32); w = big(u32)
+ case tf32*100 + ti64:
+ f32 = float32(v); i64 = int64(f32); w = big(i64)
+ case tf32*100 + tu64:
+ f32 = float32(v); u64 = uint64(f32); w = big(u64)
+ case tf32*100 + tf32:
+ f32 = float32(v); f32 = float32(f32); w = big(f32)
+ case tf32*100 + tf64:
+ f32 = float32(v); f64 = float64(f32); w = big(f64)
+
+ case tf64*100 + ti8:
+ f64 = float64(v); i8 = int8(f64); w = big(i8)
+ case tf64*100 + tu8:
+ f64 = float64(v); u8 = uint8(f64); w = big(u8)
+ case tf64*100 + ti16:
+ f64 = float64(v); i16 = int16(f64); w = big(i16)
+ case tf64*100 + tu16:
+ f64 = float64(v); u16 = uint16(f64); w = big(u16)
+ case tf64*100 + ti32:
+ f64 = float64(v); i32 = int32(f64); w = big(i32)
+ case tf64*100 + tu32:
+ f64 = float64(v); u32 = uint32(f64); w = big(u32)
+ case tf64*100 + ti64:
+ f64 = float64(v); i64 = int64(f64); w = big(i64)
+ case tf64*100 + tu64:
+ f64 = float64(v); u64 = uint64(f64); w = big(u64)
+ case tf64*100 + tf32:
+ f64 = float64(v); f32 = float32(f64); w = big(f32)
+ case tf64*100 + tf64:
+ f64 = float64(v); f64 = float64(f64); w = big(f64)
+ }
+ if v != w { println(i, v, w, f, t) }
+ }
+}
diff --git a/test/ken/cplx4.go b/test/ken/cplx4.go
index d55d6a6e3..3c6f1f68c 100644
--- a/test/ken/cplx4.go
+++ b/test/ken/cplx4.go
@@ -39,6 +39,6 @@ func main() {
// compiler used to crash on nested divide
c4 := cmplx(real(c3/2), imag(c3/2))
if c4 != c3/2 {
- fmt.Printf("c3 = %G != c4 = %G\n", c3, c4)
+ fmt.Printf("BUG: c3 = %G != c4 = %G\n", c3, c4)
}
}
diff --git a/test/ken/slicearray.go b/test/ken/slicearray.go
index 76ec80931..6e7088e19 100644
--- a/test/ken/slicearray.go
+++ b/test/ken/slicearray.go
@@ -16,12 +16,12 @@ var t int
func main() {
lb = 0
hb = 10
- by = &bx
+ by = bx[0:]
tstb()
lb = 0
hb = 10
- fy = &fx
+ fy = fx[0:]
tstf()
// width 1 (byte)
@@ -33,12 +33,18 @@ func main() {
tstb()
by = bx[lb:]
tstb()
+ by = bx[:hb]
+ tstb()
by = bx[0:hb]
tstb()
by = bx[0:10]
tstb()
by = bx[0:]
tstb()
+ by = bx[:10]
+ tstb()
+ by = bx[:]
+ tstb()
lb = 2
hb = 10
@@ -65,6 +71,10 @@ func main() {
tstb()
by = bx[0:8]
tstb()
+ by = bx[:8]
+ tstb()
+ by = bx[:hb]
+ tstb()
lb = 2
hb = 8
@@ -86,12 +96,18 @@ func main() {
tstf()
fy = fx[lb:]
tstf()
+ fy = fx[:hb]
+ tstf()
fy = fx[0:hb]
tstf()
fy = fx[0:10]
tstf()
fy = fx[0:]
tstf()
+ fy = fx[:10]
+ tstf()
+ fy = fx[:]
+ tstf()
lb = 2
hb = 10
@@ -114,10 +130,14 @@ func main() {
tstf()
fy = fx[lb:8]
tstf()
+ fy = fx[:hb]
+ tstf()
fy = fx[0:hb]
tstf()
fy = fx[0:8]
tstf()
+ fy = fx[:8]
+ tstf()
lb = 2
hb = 8
diff --git a/test/ken/sliceslice.go b/test/ken/sliceslice.go
index 7e7f1b4ac..5a35acaf4 100644
--- a/test/ken/sliceslice.go
+++ b/test/ken/sliceslice.go
@@ -24,12 +24,18 @@ func main() {
tstb()
by = bx[lb:]
tstb()
+ by = bx[:hb]
+ tstb()
by = bx[0:hb]
tstb()
by = bx[0:10]
tstb()
by = bx[0:]
tstb()
+ by = bx[:10]
+ tstb()
+ by = bx[:]
+ tstb()
lb = 2
hb = 10
@@ -56,6 +62,10 @@ func main() {
tstb()
by = bx[0:8]
tstb()
+ by = bx[:8]
+ tstb()
+ by = bx[:hb]
+ tstb()
lb = 2
hb = 8
@@ -77,12 +87,18 @@ func main() {
tstf()
fy = fx[lb:]
tstf()
+ fy = fx[:hb]
+ tstf()
fy = fx[0:hb]
tstf()
fy = fx[0:10]
tstf()
fy = fx[0:]
tstf()
+ fy = fx[:10]
+ tstf()
+ fy = fx[:]
+ tstf()
lb = 2
hb = 10
@@ -105,10 +121,14 @@ func main() {
tstf()
fy = fx[lb:8]
tstf()
+ fy = fx[:hb]
+ tstf()
fy = fx[0:hb]
tstf()
fy = fx[0:8]
tstf()
+ fy = fx[:8]
+ tstf()
lb = 2
hb = 8
diff --git a/test/literal.go b/test/literal.go
index bd231eae2..9bdbabca8 100644
--- a/test/literal.go
+++ b/test/literal.go
@@ -11,212 +11,216 @@ var nbad int
func assert(cond bool, msg string) {
if !cond {
if nbad == 0 {
- print("BUG");
+ print("BUG")
}
- nbad++;
- print(" ", msg);
+ nbad++
+ print(" ", msg)
}
}
+func equal(a, b float) bool {
+ return a == b
+}
+
+
func main() {
// bool
- var t bool = true;
- var f bool = false;
- assert(t == !f, "bool");
+ var t bool = true
+ var f bool = false
+ assert(t == !f, "bool")
// int8
- var i00 int8 = 0;
- var i01 int8 = 1;
- var i02 int8 = -1;
- var i03 int8 = 127;
- var i04 int8 = -127;
- var i05 int8 = -128;
- var i06 int8 = +127;
- assert(i01 == i00 + 1, "i01");
- assert(i02 == -i01, "i02");
- assert(i03 == -i04, "i03");
- assert(-(i05+1) == i06, "i05");
+ var i00 int8 = 0
+ var i01 int8 = 1
+ var i02 int8 = -1
+ var i03 int8 = 127
+ var i04 int8 = -127
+ var i05 int8 = -128
+ var i06 int8 = +127
+ assert(i01 == i00+1, "i01")
+ assert(i02 == -i01, "i02")
+ assert(i03 == -i04, "i03")
+ assert(-(i05+1) == i06, "i05")
// int16
- var i10 int16 = 0;
- var i11 int16 = 1;
- var i12 int16 = -1;
- var i13 int16 = 32767;
- var i14 int16 = -32767;
- var i15 int16 = -32768;
- var i16 int16 = +32767;
- assert(i11 == i10 + 1, "i11");
- assert(i12 == -i11, "i12");
- assert(i13 == -i14, "i13");
- assert(-(i15+1) == i16, "i15");
+ var i10 int16 = 0
+ var i11 int16 = 1
+ var i12 int16 = -1
+ var i13 int16 = 32767
+ var i14 int16 = -32767
+ var i15 int16 = -32768
+ var i16 int16 = +32767
+ assert(i11 == i10+1, "i11")
+ assert(i12 == -i11, "i12")
+ assert(i13 == -i14, "i13")
+ assert(-(i15+1) == i16, "i15")
// int32
- var i20 int32 = 0;
- var i21 int32 = 1;
- var i22 int32 = -1;
- var i23 int32 = 2147483647;
- var i24 int32 = -2147483647;
- var i25 int32 = -2147483648;
- var i26 int32 = +2147483647;
- assert(i21 == i20 + 1, "i21");
- assert(i22 == -i21, "i22");
- assert(i23 == -i24, "i23");
- assert(-(i25+1) == i26, "i25");
- assert(i23 == (1 << 31) - 1, "i23 size");
+ var i20 int32 = 0
+ var i21 int32 = 1
+ var i22 int32 = -1
+ var i23 int32 = 2147483647
+ var i24 int32 = -2147483647
+ var i25 int32 = -2147483648
+ var i26 int32 = +2147483647
+ assert(i21 == i20+1, "i21")
+ assert(i22 == -i21, "i22")
+ assert(i23 == -i24, "i23")
+ assert(-(i25+1) == i26, "i25")
+ assert(i23 == (1<<31)-1, "i23 size")
// int64
- var i30 int64 = 0;
- var i31 int64 = 1;
- var i32 int64 = -1;
- var i33 int64 = 9223372036854775807;
- var i34 int64 = -9223372036854775807;
- var i35 int64 = -9223372036854775808;
- var i36 int64 = +9223372036854775807;
- assert(i31 == i30 + 1, "i31");
- assert(i32 == -i31, "i32");
- assert(i33 == -i34, "i33");
- assert(-(i35+1) == i36, "i35");
- assert(i33 == (1<<63) - 1, "i33 size");
+ var i30 int64 = 0
+ var i31 int64 = 1
+ var i32 int64 = -1
+ var i33 int64 = 9223372036854775807
+ var i34 int64 = -9223372036854775807
+ var i35 int64 = -9223372036854775808
+ var i36 int64 = +9223372036854775807
+ assert(i31 == i30+1, "i31")
+ assert(i32 == -i31, "i32")
+ assert(i33 == -i34, "i33")
+ assert(-(i35+1) == i36, "i35")
+ assert(i33 == (1<<63)-1, "i33 size")
// uint8
- var u00 uint8 = 0;
- var u01 uint8 = 1;
- var u02 uint8 = 255;
- var u03 uint8 = +255;
- assert(u01 == u00 + 1, "u01");
- assert(u02 == u03, "u02");
- assert(u03 == (1<<8) - 1, "u03 size");
+ var u00 uint8 = 0
+ var u01 uint8 = 1
+ var u02 uint8 = 255
+ var u03 uint8 = +255
+ assert(u01 == u00+1, "u01")
+ assert(u02 == u03, "u02")
+ assert(u03 == (1<<8)-1, "u03 size")
// uint16
- var u10 uint16 = 0;
- var u11 uint16 = 1;
- var u12 uint16 = 65535;
- var u13 uint16 = +65535;
- assert(u11 == u10 + 1, "u11");
- assert(u12 == u13, "u12");
+ var u10 uint16 = 0
+ var u11 uint16 = 1
+ var u12 uint16 = 65535
+ var u13 uint16 = +65535
+ assert(u11 == u10+1, "u11")
+ assert(u12 == u13, "u12")
// uint32
- var u20 uint32 = 0;
- var u21 uint32 = 1;
- var u22 uint32 = 4294967295;
- var u23 uint32 = +4294967295;
- assert(u21 == u20 + 1, "u21");
- assert(u22 == u23, "u22");
+ var u20 uint32 = 0
+ var u21 uint32 = 1
+ var u22 uint32 = 4294967295
+ var u23 uint32 = +4294967295
+ assert(u21 == u20+1, "u21")
+ assert(u22 == u23, "u22")
// uint64
- var u30 uint64 = 0;
- var u31 uint64 = 1;
- var u32 uint64 = 18446744073709551615;
- var u33 uint64 = +18446744073709551615;
- _, _, _, _ = u30, u31, u32, u33;
+ var u30 uint64 = 0
+ var u31 uint64 = 1
+ var u32 uint64 = 18446744073709551615
+ var u33 uint64 = +18446744073709551615
+ _, _, _, _ = u30, u31, u32, u33
// float
- var f00 float = 3.14159;
- var f01 float = -3.14159;
- var f02 float = +3.14159;
- var f03 float = 0.0;
- var f04 float = .0;
- var f05 float = 0.;
- var f06 float = -0.0;
- var f07 float = 1e10;
- var f08 float = -1e10;
- var f09 float = 1e-10;
- var f10 float = 1e+10;
- var f11 float = 1.e-10;
- var f12 float = 1.e+10;
- var f13 float = .1e-10;
- var f14 float = .1e+10;
- var f15 float = 1.1e-10;
- var f16 float = 1.1e+10;
- assert(f01 == -f00, "f01");
- assert(f02 == -f01, "f02");
- assert(f03 == f04, "f03");
- assert(f04 == f05, "f04");
- assert(f05 == f06, "f05");
- assert(f07 == -f08, "f07");
- assert(f09 == 1/f10, "f09");
- assert(f11 == f09, "f11");
- assert(f12 == f10, "f12");
- assert(f13 == f09/10.0, "f13");
- assert(f14 == f12/10.0, "f14");
- assert(f15 == f16/1e20, "f15");
+ var f00 float = 3.14159
+ var f01 float = -3.14159
+ var f02 float = +3.14159
+ var f03 float = 0.0
+ var f04 float = .0
+ var f05 float = 0.
+ var f06 float = -0.0
+ var f07 float = 1e10
+ var f08 float = -1e10
+ var f09 float = 1e-10
+ var f10 float = 1e+10
+ var f11 float = 1.e-10
+ var f12 float = 1.e+10
+ var f13 float = .1e-10
+ var f14 float = .1e+10
+ var f15 float = 1.1e-10
+ var f16 float = 1.1e+10
+ assert(f01 == -f00, "f01")
+ assert(f02 == -f01, "f02")
+ assert(f03 == f04, "f03")
+ assert(f04 == f05, "f04")
+ assert(f05 == f06, "f05")
+ assert(f07 == -f08, "f07")
+ assert(equal(f09, 1/f10), "f09")
+ assert(f11 == f09, "f11")
+ assert(f12 == f10, "f12")
+ assert(equal(f13, f09/10.0), "f13")
+ assert(equal(f14, f12/10.0), "f14")
+ assert(equal(f15, f16/1e20), "f15")
// character
- var c0 uint8 = 'a';
- var c1 uint8 = 'ä';
- var c2 uint8 = '\a';
- var c3 uint8 = '\b';
- var c4 uint8 = '\f';
- var c5 uint8 = '\n';
- var c6 uint8 = '\r';
- var c7 uint8 = '\t';
- var c8 uint8 = '\v';
- // var c9 uint8 = '本'; // correctly caught as error
- var c9 uint16 = '本';
- assert(c0 == 0x61, "c0");
- assert(c1 == 0xe4, "c1");
- assert(c2 == 0x07, "c2");
- assert(c3 == 0x08, "c3");
- assert(c4 == 0x0c, "c4");
- assert(c5 == 0x0a, "c4");
- assert(c6 == 0x0d, "c6");
- assert(c7 == 0x09, "c7");
- assert(c8 == 0x0b, "c8");
- assert(c9 == 0x672c, "c9");
-
-
- var c00 uint8 = '\000';
- var c01 uint8 = '\007';
- var c02 uint8 = '\177';
- var c03 uint8 = '\377';
- assert(c00 == 0, "c00");
- assert(c01 == 7, "c01");
- assert(c02 == 127, "c02");
- assert(c03 == 255, "c03");
-
- var cx0 uint8 = '\x00';
- var cx1 uint8 = '\x0f';
- var cx2 uint8 = '\xff';
- assert(cx0 == 0, "cx0");
- assert(cx1 == 15, "cx1");
- assert(cx2 == 255, "cx2");
-
- var cu0 uint16 = '\u1234';
- var cu1 uint32 = '\U00101234';
- assert(cu0 == 0x1234, "cu0");
- assert(cu1 == 0x101234, "cu1");
+ var c0 uint8 = 'a'
+ var c1 uint8 = 'ä'
+ var c2 uint8 = '\a'
+ var c3 uint8 = '\b'
+ var c4 uint8 = '\f'
+ var c5 uint8 = '\n'
+ var c6 uint8 = '\r'
+ var c7 uint8 = '\t'
+ var c8 uint8 = '\v'
+ // var c9 uint8 = '本' // correctly caught as error
+ var c9 uint16 = '本'
+ assert(c0 == 0x61, "c0")
+ assert(c1 == 0xe4, "c1")
+ assert(c2 == 0x07, "c2")
+ assert(c3 == 0x08, "c3")
+ assert(c4 == 0x0c, "c4")
+ assert(c5 == 0x0a, "c4")
+ assert(c6 == 0x0d, "c6")
+ assert(c7 == 0x09, "c7")
+ assert(c8 == 0x0b, "c8")
+ assert(c9 == 0x672c, "c9")
+
+ var c00 uint8 = '\000'
+ var c01 uint8 = '\007'
+ var c02 uint8 = '\177'
+ var c03 uint8 = '\377'
+ assert(c00 == 0, "c00")
+ assert(c01 == 7, "c01")
+ assert(c02 == 127, "c02")
+ assert(c03 == 255, "c03")
+
+ var cx0 uint8 = '\x00'
+ var cx1 uint8 = '\x0f'
+ var cx2 uint8 = '\xff'
+ assert(cx0 == 0, "cx0")
+ assert(cx1 == 15, "cx1")
+ assert(cx2 == 255, "cx2")
+
+ var cu0 uint16 = '\u1234'
+ var cu1 uint32 = '\U00101234'
+ assert(cu0 == 0x1234, "cu0")
+ assert(cu1 == 0x101234, "cu1")
// string
- var s0 string = "";
- var s1 string = "hellô";
- assert(s1[0] == 'h', "s1-0");
- assert(s1[4] == 0xc3, "s1-4");
- assert(s1[5] == 0xb4, "s1-5");
- var s2 string = "\a\b\f\n\r\t\v";
- _, _ = s0, s2;
-
- var s00 string = "\000";
- var s01 string = "\007";
- var s02 string = "\377";
- assert(s00[0] == 0, "s00");
- assert(s01[0] == 7, "s01");
- assert(s02[0] == 255, "s02");
-
- var x00 string = "\x00";
- var x01 string = "\x0f";
- var x02 string = "\xff";
- assert(x00[0] == 0, "x00");
- assert(x01[0] == 15, "x01");
- assert(x02[0] == 255, "x02");
+ var s0 string = ""
+ var s1 string = "hellô"
+ assert(s1[0] == 'h', "s1-0")
+ assert(s1[4] == 0xc3, "s1-4")
+ assert(s1[5] == 0xb4, "s1-5")
+ var s2 string = "\a\b\f\n\r\t\v"
+ _, _ = s0, s2
+
+ var s00 string = "\000"
+ var s01 string = "\007"
+ var s02 string = "\377"
+ assert(s00[0] == 0, "s00")
+ assert(s01[0] == 7, "s01")
+ assert(s02[0] == 255, "s02")
+
+ var x00 string = "\x00"
+ var x01 string = "\x0f"
+ var x02 string = "\xff"
+ assert(x00[0] == 0, "x00")
+ assert(x01[0] == 15, "x01")
+ assert(x02[0] == 255, "x02")
// these are all the same string
- var sj0 string = "日本語";
- var sj1 string = "\u65e5\u672c\u8a9e";
- var sj2 string = "\U000065e5\U0000672c\U00008a9e";
- var sj3 string = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e";
- assert(sj0 == sj1, "sj1");
- assert(sj0 == sj2, "sj2");
- assert(sj0 == sj3, "sj3");
+ var sj0 string = "日本語"
+ var sj1 string = "\u65e5\u672c\u8a9e"
+ var sj2 string = "\U000065e5\U0000672c\U00008a9e"
+ var sj3 string = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e"
+ assert(sj0 == sj1, "sj1")
+ assert(sj0 == sj2, "sj2")
+ assert(sj0 == sj3, "sj3")
if nbad > 0 {
println()
diff --git a/test/mallocrand.go b/test/mallocrand.go
index bb43e2d46..e6b422e22 100644
--- a/test/mallocrand.go
+++ b/test/mallocrand.go
@@ -56,7 +56,7 @@ func memset(b *byte, c byte, n uintptr) {
func main() {
flag.Parse()
- // prime();
+ // prime()
var blocks [1]struct {
base *byte
siz uintptr
@@ -67,7 +67,7 @@ func main() {
}
b := rand.Int() % len(blocks)
if blocks[b].base != nil {
- // println("Free", blocks[b].siz, blocks[b].base);
+ // println("Free", blocks[b].siz, blocks[b].base)
runtime.Free(blocks[b].base)
blocks[b].base = nil
allocated -= uint64(blocks[b].siz)
@@ -75,8 +75,8 @@ func main() {
}
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);
+ // 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")
@@ -84,7 +84,7 @@ func main() {
blocks[b].base = base
blocks[b].siz = siz
allocated += uint64(siz)
- // println("Alloc", siz, base);
+ // println("Alloc", siz, base)
memset(base, 0xbb, siz)
bigger()
}
diff --git a/test/mallocrep.go b/test/mallocrep.go
index 2357d8375..762f3754f 100644
--- a/test/mallocrep.go
+++ b/test/mallocrep.go
@@ -31,6 +31,7 @@ func bigger() {
}
func main() {
+ runtime.GC() // clean up garbage from init
runtime.MemProfileRate = 0 // disable profiler
runtime.MemStats.Alloc = 0 // ignore stacks
flag.Parse()
@@ -59,7 +60,7 @@ func main() {
if *chatty {
println("Primed", i)
}
- // runtime.frozen = true;
+ // runtime.frozen = true
}
}
}
diff --git a/test/map.go b/test/map.go
index 4905f6e11..ddff7c7a7 100644
--- a/test/map.go
+++ b/test/map.go
@@ -7,318 +7,318 @@
package main
import (
- "fmt";
- "strconv";
+ "fmt"
+ "strconv"
)
-const count = 100;
+const count = 100
func P(a []string) string {
- s := "{";
+ s := "{"
for i := 0; i < len(a); i++ {
if i > 0 {
s += ","
}
- s += `"` + a[i] + `"`;
+ s += `"` + a[i] + `"`
}
- s +="}";
- return s;
+ s +="}"
+ return s
}
func main() {
// Test a map literal.
- mlit := map[string] int { "0":0, "1":1, "2":2, "3":3, "4":4 };
+ mlit := map[string] int { "0":0, "1":1, "2":2, "3":3, "4":4 }
for i := 0; i < len(mlit); i++ {
- s := string([]byte{byte(i)+'0'});
+ s := string([]byte{byte(i)+'0'})
if mlit[s] != i {
fmt.Printf("mlit[%s] = %d\n", s, mlit[s])
}
}
- mib := make(map[int] bool);
- mii := make(map[int] int);
- mfi := make(map[float] int);
- mif := make(map[int] float);
- msi := make(map[string] int);
- mis := make(map[int] string);
- mss := make(map[string] string);
- mspa := make(map[string] []string);
+ mib := make(map[int] bool)
+ mii := make(map[int] int)
+ mfi := make(map[float] int)
+ mif := make(map[int] float)
+ msi := make(map[string] int)
+ mis := make(map[int] string)
+ mss := make(map[string] string)
+ mspa := make(map[string] []string)
// BUG need an interface map both ways too
type T struct {
- i int64; // can't use string here; struct values are only compared at the top level
- f float;
- };
- mipT := make(map[int] *T);
- mpTi := make(map[*T] int);
- mit := make(map[int] T);
-// mti := make(map[T] int);
+ i int64 // can't use string here; struct values are only compared at the top level
+ f float
+ }
+ mipT := make(map[int] *T)
+ mpTi := make(map[*T] int)
+ mit := make(map[int] T)
+// mti := make(map[T] int)
- type M map[int] int;
- mipM := make(map[int] M);
+ type M map[int] int
+ mipM := make(map[int] M)
- var apT [2*count]*T;
+ var apT [2*count]*T
for i := 0; i < count; i++ {
- s := strconv.Itoa(i);
- s10 := strconv.Itoa(i*10);
- f := float(i);
- t := T{int64(i),f};
- apT[i] = new(T);
- apT[i].i = int64(i);
- apT[i].f = f;
- apT[2*i] = new(T); // need twice as many entries as we use, for the nonexistence check
- apT[2*i].i = int64(i);
- apT[2*i].f = f;
- m := M{i: i+1};
- mib[i] = (i != 0);
- mii[i] = 10*i;
- mfi[float(i)] = 10*i;
- mif[i] = 10.0*f;
- mis[i] = s;
- msi[s] = i;
- mss[s] = s10;
- mss[s] = s10;
- as := make([]string, 2);
- as[0] = s10;
- as[1] = s10;
- mspa[s] = as;
- mipT[i] = apT[i];
- mpTi[apT[i]] = i;
- mipM[i] = m;
- mit[i] = t;
- // mti[t] = i;
+ s := strconv.Itoa(i)
+ s10 := strconv.Itoa(i*10)
+ f := float(i)
+ t := T{int64(i),f}
+ apT[i] = new(T)
+ apT[i].i = int64(i)
+ apT[i].f = f
+ apT[2*i] = new(T) // need twice as many entries as we use, for the nonexistence check
+ apT[2*i].i = int64(i)
+ apT[2*i].f = f
+ m := M{i: i+1}
+ mib[i] = (i != 0)
+ mii[i] = 10*i
+ mfi[float(i)] = 10*i
+ mif[i] = 10.0*f
+ mis[i] = s
+ msi[s] = i
+ mss[s] = s10
+ mss[s] = s10
+ as := make([]string, 2)
+ as[0] = s10
+ as[1] = s10
+ mspa[s] = as
+ mipT[i] = apT[i]
+ mpTi[apT[i]] = i
+ mipM[i] = m
+ mit[i] = t
+ // mti[t] = i
}
// test len
if len(mib) != count {
- fmt.Printf("len(mib) = %d\n", len(mib));
+ fmt.Printf("len(mib) = %d\n", len(mib))
}
if len(mii) != count {
- fmt.Printf("len(mii) = %d\n", len(mii));
+ fmt.Printf("len(mii) = %d\n", len(mii))
}
if len(mfi) != count {
- fmt.Printf("len(mfi) = %d\n", len(mfi));
+ fmt.Printf("len(mfi) = %d\n", len(mfi))
}
if len(mif) != count {
- fmt.Printf("len(mif) = %d\n", len(mif));
+ fmt.Printf("len(mif) = %d\n", len(mif))
}
if len(msi) != count {
- fmt.Printf("len(msi) = %d\n", len(msi));
+ fmt.Printf("len(msi) = %d\n", len(msi))
}
if len(mis) != count {
- fmt.Printf("len(mis) = %d\n", len(mis));
+ fmt.Printf("len(mis) = %d\n", len(mis))
}
if len(mss) != count {
- fmt.Printf("len(mss) = %d\n", len(mss));
+ fmt.Printf("len(mss) = %d\n", len(mss))
}
if len(mspa) != count {
- fmt.Printf("len(mspa) = %d\n", len(mspa));
+ fmt.Printf("len(mspa) = %d\n", len(mspa))
}
if len(mipT) != count {
- fmt.Printf("len(mipT) = %d\n", len(mipT));
+ fmt.Printf("len(mipT) = %d\n", len(mipT))
}
if len(mpTi) != count {
- fmt.Printf("len(mpTi) = %d\n", len(mpTi));
+ fmt.Printf("len(mpTi) = %d\n", len(mpTi))
}
// if len(mti) != count {
-// fmt.Printf("len(mti) = %d\n", len(mti));
+// fmt.Printf("len(mti) = %d\n", len(mti))
// }
if len(mipM) != count {
- fmt.Printf("len(mipM) = %d\n", len(mipM));
+ fmt.Printf("len(mipM) = %d\n", len(mipM))
}
// if len(mti) != count {
-// fmt.Printf("len(mti) = %d\n", len(mti));
+// fmt.Printf("len(mti) = %d\n", len(mti))
// }
if len(mit) != count {
- fmt.Printf("len(mit) = %d\n", len(mit));
+ fmt.Printf("len(mit) = %d\n", len(mit))
}
// test construction directly
for i := 0; i < count; i++ {
- s := strconv.Itoa(i);
- s10 := strconv.Itoa(i*10);
- f := float(i);
- // BUG m := M(i, i+1);
+ s := strconv.Itoa(i)
+ s10 := strconv.Itoa(i*10)
+ f := float(i)
+ // BUG m := M(i, i+1)
if mib[i] != (i != 0) {
- fmt.Printf("mib[%d] = %t\n", i, mib[i]);
+ fmt.Printf("mib[%d] = %t\n", i, mib[i])
}
if(mii[i] != 10*i) {
- fmt.Printf("mii[%d] = %d\n", i, mii[i]);
+ fmt.Printf("mii[%d] = %d\n", i, mii[i])
}
if(mfi[f] != 10*i) {
- fmt.Printf("mfi[%d] = %d\n", i, mfi[f]);
+ fmt.Printf("mfi[%d] = %d\n", i, mfi[f])
}
if(mif[i] != 10.0*f) {
- fmt.Printf("mif[%d] = %g\n", i, mif[i]);
+ fmt.Printf("mif[%d] = %g\n", i, mif[i])
}
if(mis[i] != s) {
- fmt.Printf("mis[%d] = %s\n", i, mis[i]);
+ fmt.Printf("mis[%d] = %s\n", i, mis[i])
}
if(msi[s] != i) {
- fmt.Printf("msi[%s] = %d\n", s, msi[s]);
+ fmt.Printf("msi[%s] = %d\n", s, msi[s])
}
if mss[s] != s10 {
- fmt.Printf("mss[%s] = %g\n", s, mss[s]);
+ fmt.Printf("mss[%s] = %g\n", s, mss[s])
}
for j := 0; j < len(mspa[s]); j++ {
if mspa[s][j] != s10 {
- fmt.Printf("mspa[%s][%d] = %s\n", s, j, mspa[s][j]);
+ fmt.Printf("mspa[%s][%d] = %s\n", s, j, mspa[s][j])
}
}
if(mipT[i].i != int64(i) || mipT[i].f != f) {
- fmt.Printf("mipT[%d] = %v\n", i, mipT[i]);
+ fmt.Printf("mipT[%d] = %v\n", i, mipT[i])
}
if(mpTi[apT[i]] != i) {
- fmt.Printf("mpTi[apT[%d]] = %d\n", i, mpTi[apT[i]]);
+ fmt.Printf("mpTi[apT[%d]] = %d\n", i, mpTi[apT[i]])
}
// if(mti[t] != i) {
- // fmt.Printf("mti[%s] = %s\n", s, mti[t]);
+ // fmt.Printf("mti[%s] = %s\n", s, mti[t])
// }
if (mipM[i][i] != i + 1) {
- fmt.Printf("mipM[%d][%d] = %d\n", i, i, mipM[i][i]);
+ fmt.Printf("mipM[%d][%d] = %d\n", i, i, mipM[i][i])
}
// if(mti[t] != i) {
- // fmt.Printf("mti[%v] = %d\n", t, mti[t]);
+ // fmt.Printf("mti[%v] = %d\n", t, mti[t])
// }
if(mit[i].i != int64(i) || mit[i].f != f) {
- fmt.Printf("mit[%d] = {%d %g}\n", i, mit[i].i, mit[i].f);
+ fmt.Printf("mit[%d] = {%d %g}\n", i, mit[i].i, mit[i].f)
}
}
// test existence with tuple check
// failed lookups yield a false value for the boolean.
for i := 0; i < count; i++ {
- s := strconv.Itoa(i);
- f := float(i);
+ s := strconv.Itoa(i)
+ f := float(i)
{
- _, b := mib[i];
+ _, b := mib[i]
if !b {
- fmt.Printf("tuple existence decl: mib[%d]\n", i);
+ fmt.Printf("tuple existence decl: mib[%d]\n", i)
}
- _, b = mib[i];
+ _, b = mib[i]
if !b {
- fmt.Printf("tuple existence assign: mib[%d]\n", i);
+ fmt.Printf("tuple existence assign: mib[%d]\n", i)
}
}
{
- _, b := mii[i];
+ _, b := mii[i]
if !b {
- fmt.Printf("tuple existence decl: mii[%d]\n", i);
+ fmt.Printf("tuple existence decl: mii[%d]\n", i)
}
- _, b = mii[i];
+ _, b = mii[i]
if !b {
- fmt.Printf("tuple existence assign: mii[%d]\n", i);
+ fmt.Printf("tuple existence assign: mii[%d]\n", i)
}
}
{
- _, b := mfi[f];
+ _, b := mfi[f]
if !b {
- fmt.Printf("tuple existence decl: mfi[%d]\n", i);
+ fmt.Printf("tuple existence decl: mfi[%d]\n", i)
}
- _, b = mfi[f];
+ _, b = mfi[f]
if !b {
- fmt.Printf("tuple existence assign: mfi[%d]\n", i);
+ fmt.Printf("tuple existence assign: mfi[%d]\n", i)
}
}
{
- _, b := mif[i];
+ _, b := mif[i]
if !b {
- fmt.Printf("tuple existence decl: mif[%d]\n", i);
+ fmt.Printf("tuple existence decl: mif[%d]\n", i)
}
- _, b = mif[i];
+ _, b = mif[i]
if !b {
- fmt.Printf("tuple existence assign: mif[%d]\n", i);
+ fmt.Printf("tuple existence assign: mif[%d]\n", i)
}
}
{
- _, b := mis[i];
+ _, b := mis[i]
if !b {
- fmt.Printf("tuple existence decl: mis[%d]\n", i);
+ fmt.Printf("tuple existence decl: mis[%d]\n", i)
}
- _, b = mis[i];
+ _, b = mis[i]
if !b {
- fmt.Printf("tuple existence assign: mis[%d]\n", i);
+ fmt.Printf("tuple existence assign: mis[%d]\n", i)
}
}
{
- _, b := msi[s];
+ _, b := msi[s]
if !b {
- fmt.Printf("tuple existence decl: msi[%d]\n", i);
+ fmt.Printf("tuple existence decl: msi[%d]\n", i)
}
- _, b = msi[s];
+ _, b = msi[s]
if !b {
- fmt.Printf("tuple existence assign: msi[%d]\n", i);
+ fmt.Printf("tuple existence assign: msi[%d]\n", i)
}
}
{
- _, b := mss[s];
+ _, b := mss[s]
if !b {
- fmt.Printf("tuple existence decl: mss[%d]\n", i);
+ fmt.Printf("tuple existence decl: mss[%d]\n", i)
}
- _, b = mss[s];
+ _, b = mss[s]
if !b {
- fmt.Printf("tuple existence assign: mss[%d]\n", i);
+ fmt.Printf("tuple existence assign: mss[%d]\n", i)
}
}
{
- _, b := mspa[s];
+ _, b := mspa[s]
if !b {
- fmt.Printf("tuple existence decl: mspa[%d]\n", i);
+ fmt.Printf("tuple existence decl: mspa[%d]\n", i)
}
- _, b = mspa[s];
+ _, b = mspa[s]
if !b {
- fmt.Printf("tuple existence assign: mspa[%d]\n", i);
+ fmt.Printf("tuple existence assign: mspa[%d]\n", i)
}
}
{
- _, b := mipT[i];
+ _, b := mipT[i]
if !b {
- fmt.Printf("tuple existence decl: mipT[%d]\n", i);
+ fmt.Printf("tuple existence decl: mipT[%d]\n", i)
}
- _, b = mipT[i];
+ _, b = mipT[i]
if !b {
- fmt.Printf("tuple existence assign: mipT[%d]\n", i);
+ fmt.Printf("tuple existence assign: mipT[%d]\n", i)
}
}
{
- _, b := mpTi[apT[i]];
+ _, b := mpTi[apT[i]]
if !b {
- fmt.Printf("tuple existence decl: mpTi[apT[%d]]\n", i);
+ fmt.Printf("tuple existence decl: mpTi[apT[%d]]\n", i)
}
- _, b = mpTi[apT[i]];
+ _, b = mpTi[apT[i]]
if !b {
- fmt.Printf("tuple existence assign: mpTi[apT[%d]]\n", i);
+ fmt.Printf("tuple existence assign: mpTi[apT[%d]]\n", i)
}
}
{
- _, b := mipM[i];
+ _, b := mipM[i]
if !b {
- fmt.Printf("tuple existence decl: mipM[%d]\n", i);
+ fmt.Printf("tuple existence decl: mipM[%d]\n", i)
}
- _, b = mipM[i];
+ _, b = mipM[i]
if !b {
- fmt.Printf("tuple existence assign: mipM[%d]\n", i);
+ fmt.Printf("tuple existence assign: mipM[%d]\n", i)
}
}
{
- _, b := mit[i];
+ _, b := mit[i]
if !b {
- fmt.Printf("tuple existence decl: mit[%d]\n", i);
+ fmt.Printf("tuple existence decl: mit[%d]\n", i)
}
- _, b = mit[i];
+ _, b = mit[i]
if !b {
- fmt.Printf("tuple existence assign: mit[%d]\n", i);
+ fmt.Printf("tuple existence assign: mit[%d]\n", i)
}
}
// {
-// _, b := mti[t];
+// _, b := mti[t]
// if !b {
-// fmt.Printf("tuple existence decl: mti[%d]\n", i);
+// fmt.Printf("tuple existence decl: mti[%d]\n", i)
// }
-// _, b = mti[t];
+// _, b = mti[t]
// if !b {
-// fmt.Printf("tuple existence assign: mti[%d]\n", i);
+// fmt.Printf("tuple existence assign: mti[%d]\n", i)
// }
// }
}
@@ -326,136 +326,136 @@ func main() {
// test nonexistence with tuple check
// failed lookups yield a false value for the boolean.
for i := count; i < 2*count; i++ {
- s := strconv.Itoa(i);
- f := float(i);
+ s := strconv.Itoa(i)
+ f := float(i)
{
- _, b := mib[i];
+ _, b := mib[i]
if b {
- fmt.Printf("tuple nonexistence decl: mib[%d]", i);
+ fmt.Printf("tuple nonexistence decl: mib[%d]", i)
}
- _, b = mib[i];
+ _, b = mib[i]
if b {
- fmt.Printf("tuple nonexistence assign: mib[%d]", i);
+ fmt.Printf("tuple nonexistence assign: mib[%d]", i)
}
}
{
- _, b := mii[i];
+ _, b := mii[i]
if b {
- fmt.Printf("tuple nonexistence decl: mii[%d]", i);
+ fmt.Printf("tuple nonexistence decl: mii[%d]", i)
}
- _, b = mii[i];
+ _, b = mii[i]
if b {
- fmt.Printf("tuple nonexistence assign: mii[%d]", i);
+ fmt.Printf("tuple nonexistence assign: mii[%d]", i)
}
}
{
- _, b := mfi[f];
+ _, b := mfi[f]
if b {
- fmt.Printf("tuple nonexistence decl: mfi[%d]", i);
+ fmt.Printf("tuple nonexistence decl: mfi[%d]", i)
}
- _, b = mfi[f];
+ _, b = mfi[f]
if b {
- fmt.Printf("tuple nonexistence assign: mfi[%d]", i);
+ fmt.Printf("tuple nonexistence assign: mfi[%d]", i)
}
}
{
- _, b := mif[i];
+ _, b := mif[i]
if b {
- fmt.Printf("tuple nonexistence decl: mif[%d]", i);
+ fmt.Printf("tuple nonexistence decl: mif[%d]", i)
}
- _, b = mif[i];
+ _, b = mif[i]
if b {
- fmt.Printf("tuple nonexistence assign: mif[%d]", i);
+ fmt.Printf("tuple nonexistence assign: mif[%d]", i)
}
}
{
- _, b := mis[i];
+ _, b := mis[i]
if b {
- fmt.Printf("tuple nonexistence decl: mis[%d]", i);
+ fmt.Printf("tuple nonexistence decl: mis[%d]", i)
}
- _, b = mis[i];
+ _, b = mis[i]
if b {
- fmt.Printf("tuple nonexistence assign: mis[%d]", i);
+ fmt.Printf("tuple nonexistence assign: mis[%d]", i)
}
}
{
- _, b := msi[s];
+ _, b := msi[s]
if b {
- fmt.Printf("tuple nonexistence decl: msi[%d]", i);
+ fmt.Printf("tuple nonexistence decl: msi[%d]", i)
}
- _, b = msi[s];
+ _, b = msi[s]
if b {
- fmt.Printf("tuple nonexistence assign: msi[%d]", i);
+ fmt.Printf("tuple nonexistence assign: msi[%d]", i)
}
}
{
- _, b := mss[s];
+ _, b := mss[s]
if b {
- fmt.Printf("tuple nonexistence decl: mss[%d]", i);
+ fmt.Printf("tuple nonexistence decl: mss[%d]", i)
}
- _, b = mss[s];
+ _, b = mss[s]
if b {
- fmt.Printf("tuple nonexistence assign: mss[%d]", i);
+ fmt.Printf("tuple nonexistence assign: mss[%d]", i)
}
}
{
- _, b := mspa[s];
+ _, b := mspa[s]
if b {
- fmt.Printf("tuple nonexistence decl: mspa[%d]", i);
+ fmt.Printf("tuple nonexistence decl: mspa[%d]", i)
}
- _, b = mspa[s];
+ _, b = mspa[s]
if b {
- fmt.Printf("tuple nonexistence assign: mspa[%d]", i);
+ fmt.Printf("tuple nonexistence assign: mspa[%d]", i)
}
}
{
- _, b := mipT[i];
+ _, b := mipT[i]
if b {
- fmt.Printf("tuple nonexistence decl: mipT[%d]", i);
+ fmt.Printf("tuple nonexistence decl: mipT[%d]", i)
}
- _, b = mipT[i];
+ _, b = mipT[i]
if b {
- fmt.Printf("tuple nonexistence assign: mipT[%d]", i);
+ fmt.Printf("tuple nonexistence assign: mipT[%d]", i)
}
}
{
- _, b := mpTi[apT[i]];
+ _, b := mpTi[apT[i]]
if b {
- fmt.Printf("tuple nonexistence decl: mpTi[apt[%d]]", i);
+ fmt.Printf("tuple nonexistence decl: mpTi[apt[%d]]", i)
}
- _, b = mpTi[apT[i]];
+ _, b = mpTi[apT[i]]
if b {
- fmt.Printf("tuple nonexistence assign: mpTi[apT[%d]]", i);
+ fmt.Printf("tuple nonexistence assign: mpTi[apT[%d]]", i)
}
}
{
- _, b := mipM[i];
+ _, b := mipM[i]
if b {
- fmt.Printf("tuple nonexistence decl: mipM[%d]", i);
+ fmt.Printf("tuple nonexistence decl: mipM[%d]", i)
}
- _, b = mipM[i];
+ _, b = mipM[i]
if b {
- fmt.Printf("tuple nonexistence assign: mipM[%d]", i);
+ fmt.Printf("tuple nonexistence assign: mipM[%d]", i)
}
}
// {
-// _, b := mti[t];
+// _, b := mti[t]
// if b {
-// fmt.Printf("tuple nonexistence decl: mti[%d]", i);
+// fmt.Printf("tuple nonexistence decl: mti[%d]", i)
// }
-// _, b = mti[t];
+// _, b = mti[t]
// if b {
-// fmt.Printf("tuple nonexistence assign: mti[%d]", i);
+// fmt.Printf("tuple nonexistence assign: mti[%d]", i)
// }
// }
{
- _, b := mit[i];
+ _, b := mit[i]
if b {
- fmt.Printf("tuple nonexistence decl: mit[%d]", i);
+ fmt.Printf("tuple nonexistence decl: mit[%d]", i)
}
- _, b = mit[i];
+ _, b = mit[i]
if b {
- fmt.Printf("tuple nonexistence assign: mit[%d]", i);
+ fmt.Printf("tuple nonexistence assign: mit[%d]", i)
}
}
}
@@ -463,30 +463,30 @@ func main() {
// tests for structured map element updates
for i := 0; i < count; i++ {
- s := strconv.Itoa(i);
- mspa[s][i % 2] = "deleted";
+ s := strconv.Itoa(i)
+ mspa[s][i % 2] = "deleted"
if mspa[s][i % 2] != "deleted" {
- fmt.Printf("update mspa[%s][%d] = %s\n", s, i %2, mspa[s][i % 2]);
+ fmt.Printf("update mspa[%s][%d] = %s\n", s, i %2, mspa[s][i % 2])
}
- mipT[i].i += 1;
+ mipT[i].i += 1
if mipT[i].i != int64(i)+1 {
- fmt.Printf("update mipT[%d].i = %d\n", i, mipT[i].i);
+ fmt.Printf("update mipT[%d].i = %d\n", i, mipT[i].i)
}
- mipT[i].f = float(i + 1);
+ mipT[i].f = float(i + 1)
if (mipT[i].f != float(i + 1)) {
- fmt.Printf("update mipT[%d].f = %g\n", i, mipT[i].f);
+ fmt.Printf("update mipT[%d].f = %g\n", i, mipT[i].f)
}
- mipM[i][i]++;
+ mipM[i][i]++
if mipM[i][i] != (i + 1) + 1 {
- fmt.Printf("update mipM[%d][%d] = %i\n", i, i, mipM[i][i]);
+ fmt.Printf("update mipM[%d][%d] = %i\n", i, i, mipM[i][i])
}
}
// test range on nil map
- var mnil map[string] int;
+ var mnil map[string] int
for _, _ = range mnil {
- panic("range mnil");
+ panic("range mnil")
}
}
diff --git a/test/method.go b/test/method.go
index c751c1f1b..b5a02c687 100644
--- a/test/method.go
+++ b/test/method.go
@@ -19,7 +19,7 @@ func (s S) val() int { return 1 }
func (s *S1) val() int { return 2 }
func (i I) val() int { return 3 }
func (i *I1) val() int { return 4 }
-//func (t T) val() int { return 7 }
+func (t T) val() int { return 7 }
func (t *T1) val() int { return 8 }
type Val interface {
@@ -34,6 +34,8 @@ func main() {
var i I
var pi *I1
var pt *T1
+ var t T
+ var v Val
if s.val() != 1 {
println("s.val:", s.val())
@@ -75,7 +77,10 @@ func main() {
println("(*I1).val(pi):", (*I1).val(pi))
panic("fail")
}
- // if t.val() != 7 { prinln("t.val:", t.val()); panic("fail") }
+ if t.val() != 7 {
+ println("t.val:", t.val())
+ panic("fail")
+ }
if pt.val() != 8 {
println("pt.val:", pt.val())
panic("fail")
@@ -101,11 +106,22 @@ func main() {
println("pi.val:", val(pi))
panic("fail")
}
- // if val(t) != 7 { println("t.val:", val(t)); panic("fail") }
+ if val(t) != 7 {
+ println("t.val:", val(t))
+ panic("fail")
+ }
if val(pt) != 8 {
println("pt.val:", val(pt))
panic("fail")
}
- // if Val.val(i) != 3 { println("Val.val(i):", Val.val(i)); panic("fail") }
+ if Val.val(i) != 3 {
+ println("Val.val(i):", Val.val(i))
+ panic("fail")
+ }
+ v = i
+ if Val.val(v) != 3 {
+ println("Val.val(v):", Val.val(v))
+ panic("fail")
+ }
}
diff --git a/test/method1.go b/test/method1.go
index a562e3663..1a2f8cae5 100644
--- a/test/method1.go
+++ b/test/method1.go
@@ -7,11 +7,11 @@
package main
type T struct { }
-func (t *T) M(int, string); // GCCGO_ERROR "previous"
+func (t *T) M(int, string) // GCCGO_ERROR "previous"
func (t *T) M(int, float) { } // ERROR "redeclared|redefinition"
-func f(int, string); // GCCGO_ERROR "previous"
+func f(int, string) // GCCGO_ERROR "previous"
func f(int, float) { } // ERROR "redeclared|redefinition"
-func g(a int, b string); // GCCGO_ERROR "previous"
-func g(a int, c string); // ERROR "redeclared|redefinition"
+func g(a int, b string) // GCCGO_ERROR "previous"
+func g(a int, c string) // ERROR "redeclared|redefinition"
diff --git a/test/method2.go b/test/method2.go
index 3ee0ae136..a72536e7b 100644
--- a/test/method2.go
+++ b/test/method2.go
@@ -6,9 +6,22 @@
package main
-type T struct {a int}
+type T struct {
+ a int
+}
type P *T
type P1 *T
-func (p P) val() int { return 1 } // ERROR "receiver"
-func (p *P1) val() int { return 1 } // ERROR "receiver"
+func (p P) val() int { return 1 } // ERROR "receiver"
+func (p *P1) val() int { return 1 } // ERROR "receiver"
+
+type Val interface {
+ val() int
+}
+
+var _ = (*Val).val // ERROR "method"
+
+var v Val
+var pv = &v
+
+var _ = pv.val() // ERROR "method"
diff --git a/test/named1.go b/test/named1.go
index 241697d5c..600e502f9 100644
--- a/test/named1.go
+++ b/test/named1.go
@@ -64,5 +64,5 @@ func main() {
b = closed(c) // ERROR "cannot use.*type bool.*type Bool"
_ = b
- asString(String(slice)) // ERROR "cannot convert slice"
+ asString(String(slice)) // ERROR "cannot .*type Slice.*type String"
}
diff --git a/test/nil.go b/test/nil.go
index d35309615..6a72b72eb 100644
--- a/test/nil.go
+++ b/test/nil.go
@@ -14,24 +14,24 @@ type IN interface {
}
func main() {
- var i *int;
- var f *float;
- var s *string;
- var m map[float] *int;
- var c chan int;
- var t *T;
- var in IN;
- var ta []IN;
+ var i *int
+ var f *float
+ var s *string
+ var m map[float] *int
+ var c chan int
+ var t *T
+ var in IN
+ var ta []IN
- i = nil;
- f = nil;
- s = nil;
- m = nil;
- c = nil;
- t = nil;
- i = nil;
- ta = make([]IN, 1);
- ta[0] = nil;
+ i = nil
+ f = nil
+ s = nil
+ m = nil
+ c = nil
+ t = nil
+ i = nil
+ ta = make([]IN, 1)
+ ta[0] = nil
- _, _, _, _, _, _, _, _ = i, f, s, m, c, t, in, ta;
+ _, _, _, _, _, _, _, _ = i, f, s, m, c, t, in, ta
}
diff --git a/test/nilptr/arrayindex.go b/test/nilptr/arrayindex.go
index 1767acc27..fa26532c6 100644
--- a/test/nilptr/arrayindex.go
+++ b/test/nilptr/arrayindex.go
@@ -1,4 +1,3 @@
-// [ $GOOS != nacl ] || exit 0 # do not bother on NaCl
// $G $D/$F.go && $L $F.$A &&
// ((! sh -c ./$A.out) >/dev/null 2>&1 || echo BUG: should fail)
@@ -13,8 +12,8 @@ import "unsafe"
var x byte
func main() {
- var p *[1<<30]byte = nil;
- x = 123;
+ var p *[1<<30]byte = nil
+ x = 123
// The problem here is not the use of unsafe:
// it is that indexing into p[] with a large
@@ -23,5 +22,5 @@ func main() {
// Pointer offsets and array indices, if they are
// very large, need to dereference the base pointer
// to trigger a trap.
- println(p[uintptr(unsafe.Pointer(&x))]); // should crash
+ println(p[uintptr(unsafe.Pointer(&x))]) // should crash
}
diff --git a/test/nilptr/arrayindex1.go b/test/nilptr/arrayindex1.go
index c16cac405..64f46e14d 100644
--- a/test/nilptr/arrayindex1.go
+++ b/test/nilptr/arrayindex1.go
@@ -1,4 +1,3 @@
-// [ $GOOS != nacl ] || exit 0 # do not bother on NaCl
// $G $D/$F.go && $L $F.$A &&
// ((! sh -c ./$A.out) >/dev/null 2>&1 || echo BUG: should fail)
@@ -10,7 +9,7 @@ package main
import "unsafe"
-var dummy [512<<20]byte; // give us a big address space
+var dummy [512<<20]byte // give us a big address space
func main() {
// the test only tests what we intend to test
// if dummy starts in the first 256 MB of memory.
@@ -18,7 +17,7 @@ func main() {
// at the address that might be accidentally
// dereferenced below.
if uintptr(unsafe.Pointer(&dummy)) > 256<<20 {
- panic("dummy too far out");
+ panic("dummy too far out")
}
// The problem here is that indexing into p[] with a large
@@ -27,6 +26,6 @@ func main() {
// Pointer offsets and array indices, if they are
// very large, need to dereference the base pointer
// to trigger a trap.
- var p *[1<<30]byte = nil;
- println(p[256<<20]); // very likely to be inside dummy, but should crash
+ var p *[1<<30]byte = nil
+ println(p[256<<20]) // very likely to be inside dummy, but should crash
}
diff --git a/test/nilptr/arraytoslice.go b/test/nilptr/arraytoslice.go
index 65b2f8a76..03879fb42 100644
--- a/test/nilptr/arraytoslice.go
+++ b/test/nilptr/arraytoslice.go
@@ -1,4 +1,3 @@
-// [ $GOOS != nacl ] || exit 0 # do not bother on NaCl
// $G $D/$F.go && $L $F.$A &&
// ((! sh -c ./$A.out) >/dev/null 2>&1 || echo BUG: should fail)
@@ -11,10 +10,10 @@ package main
import "unsafe"
func f([]byte) {
- panic("unreachable");
+ panic("unreachable")
}
-var dummy [512<<20]byte; // give us a big address space
+var dummy [512<<20]byte // give us a big address space
func main() {
// the test only tests what we intend to test
// if dummy starts in the first 256 MB of memory.
@@ -22,7 +21,7 @@ func main() {
// at the address that might be accidentally
// dereferenced below.
if uintptr(unsafe.Pointer(&dummy)) > 256<<20 {
- panic("dummy too far out");
+ panic("dummy too far out")
}
// The problem here is that indexing into p[] with a large
@@ -32,6 +31,6 @@ func main() {
// To avoid needing a check on every slice beyond the
// usual len and cap, we require the *array -> slice
// conversion to do the check.
- var p *[1<<30]byte = nil;
- f(p); // should crash
+ var p *[1<<30]byte = nil
+ f(p[0:]) // should crash
}
diff --git a/test/nilptr/arraytoslice1.go b/test/nilptr/arraytoslice1.go
index b5240a803..c86070fa4 100644
--- a/test/nilptr/arraytoslice1.go
+++ b/test/nilptr/arraytoslice1.go
@@ -1,4 +1,3 @@
-// [ $GOOS != nacl ] || exit 0 # do not bother on NaCl
// $G $D/$F.go && $L $F.$A &&
// ((! sh -c ./$A.out) >/dev/null 2>&1 || echo BUG: should fail)
@@ -10,7 +9,7 @@ package main
import "unsafe"
-var dummy [512<<20]byte; // give us a big address space
+var dummy [512<<20]byte // give us a big address space
func main() {
// the test only tests what we intend to test
// if dummy starts in the first 256 MB of memory.
@@ -18,7 +17,7 @@ func main() {
// at the address that might be accidentally
// dereferenced below.
if uintptr(unsafe.Pointer(&dummy)) > 256<<20 {
- panic("dummy too far out");
+ panic("dummy too far out")
}
// The problem here is that indexing into p[] with a large
@@ -28,7 +27,7 @@ func main() {
// To avoid needing a check on every slice beyond the
// usual len and cap, we require the *array -> slice
// conversion to do the check.
- var p *[1<<30]byte = nil;
- var x []byte = p; // should crash
- _ = x;
+ var p *[1<<30]byte = nil
+ var x []byte = p[0:] // should crash
+ _ = x
}
diff --git a/test/nilptr/arraytoslice2.go b/test/nilptr/arraytoslice2.go
index 38e1a5cb2..68ea44083 100644
--- a/test/nilptr/arraytoslice2.go
+++ b/test/nilptr/arraytoslice2.go
@@ -1,4 +1,3 @@
-// [ $GOOS != nacl ] || exit 0 # do not bother on NaCl
// $G $D/$F.go && $L $F.$A &&
// ((! sh -c ./$A.out) >/dev/null 2>&1 || echo BUG: should fail)
@@ -10,8 +9,8 @@ package main
import "unsafe"
-var dummy [512<<20]byte; // give us a big address space
-var q *[1<<30]byte;
+var dummy [512<<20]byte // give us a big address space
+var q *[1<<30]byte
func main() {
// the test only tests what we intend to test
// if dummy starts in the first 256 MB of memory.
@@ -19,7 +18,7 @@ func main() {
// at the address that might be accidentally
// dereferenced below.
if uintptr(unsafe.Pointer(&dummy)) > 256<<20 {
- panic("dummy too far out");
+ panic("dummy too far out")
}
// The problem here is that indexing into p[] with a large
@@ -29,7 +28,7 @@ func main() {
// To avoid needing a check on every slice beyond the
// usual len and cap, we require the *array -> slice
// conversion to do the check.
- var x []byte;
- var y = &x;
- *y = q; // should crash (uses arraytoslice runtime routine)
+ var x []byte
+ var y = &x
+ *y = q[0:] // should crash (uses arraytoslice runtime routine)
}
diff --git a/test/nilptr/slicearray.go b/test/nilptr/slicearray.go
index 5f88010df..26ca42773 100644
--- a/test/nilptr/slicearray.go
+++ b/test/nilptr/slicearray.go
@@ -1,4 +1,3 @@
-// [ $GOOS != nacl ] || exit 0 # do not bother on NaCl
// $G $D/$F.go && $L $F.$A &&
// ((! sh -c ./$A.out) >/dev/null 2>&1 || echo BUG: should fail)
@@ -10,7 +9,7 @@ package main
import "unsafe"
-var dummy [512<<20]byte; // give us a big address space
+var dummy [512<<20]byte // give us a big address space
func main() {
// the test only tests what we intend to test
// if dummy starts in the first 256 MB of memory.
@@ -18,7 +17,7 @@ func main() {
// at the address that might be accidentally
// dereferenced below.
if uintptr(unsafe.Pointer(&dummy)) > 256<<20 {
- panic("dummy too far out");
+ panic("dummy too far out")
}
// The problem here is that indexing into p[] with a large
@@ -28,6 +27,6 @@ func main() {
// To avoid needing a check on every slice beyond the
// usual len and cap, we require the slice operation
// to do the check.
- var p *[1<<30]byte = nil;
- var _ []byte = p[10:len(p)-10]; // should crash
+ var p *[1<<30]byte = nil
+ var _ []byte = p[10:len(p)-10] // should crash
}
diff --git a/test/nilptr/structfield.go b/test/nilptr/structfield.go
index 9f70ecc70..35196bb68 100644
--- a/test/nilptr/structfield.go
+++ b/test/nilptr/structfield.go
@@ -1,4 +1,3 @@
-// [ $GOOS != nacl ] || exit 0 # do not bother on NaCl
// $G $D/$F.go && $L $F.$A &&
// ((! sh -c ./$A.out) >/dev/null 2>&1 || echo BUG: should fail)
@@ -10,10 +9,10 @@ package main
import "unsafe"
-var dummy [512<<20]byte; // give us a big address space
+var dummy [512<<20]byte // give us a big address space
type T struct {
- x [256<<20] byte;
- i int;
+ x [256<<20] byte
+ i int
}
func main() {
@@ -23,13 +22,13 @@ func main() {
// at the address that might be accidentally
// dereferenced below.
if uintptr(unsafe.Pointer(&dummy)) > 256<<20 {
- panic("dummy too far out");
+ panic("dummy too far out")
}
// The problem here is that indexing into t with a large
// enough index can jump out of the unmapped section
// at the beginning of memory and into valid memory.
// We require the pointer dereference to check.
- var t *T;
- println(t.i); // should crash
+ var t *T
+ println(t.i) // should crash
}
diff --git a/test/nilptr/structfield1.go b/test/nilptr/structfield1.go
index 1a120890a..7c7abed1a 100644
--- a/test/nilptr/structfield1.go
+++ b/test/nilptr/structfield1.go
@@ -1,4 +1,3 @@
-// [ $GOOS != nacl ] || exit 0 # do not bother on NaCl
// $G $D/$F.go && $L $F.$A &&
// ((! sh -c ./$A.out) >/dev/null 2>&1 || echo BUG: should fail)
@@ -10,14 +9,14 @@ package main
import "unsafe"
-var dummy [512<<20]byte; // give us a big address space
+var dummy [512<<20]byte // give us a big address space
type T struct {
- x [256<<20] byte;
- i int;
+ x [256<<20] byte
+ i int
}
func f() *T {
- return nil;
+ return nil
}
func main() {
@@ -27,12 +26,12 @@ func main() {
// at the address that might be accidentally
// dereferenced below.
if uintptr(unsafe.Pointer(&dummy)) > 256<<20 {
- panic("dummy too far out");
+ panic("dummy too far out")
}
// The problem here is that indexing into t with a large
// enough index can jump out of the unmapped section
// at the beginning of memory and into valid memory.
// We require the pointer dereference to check.
- println(f().i); // should crash
+ println(f().i) // should crash
}
diff --git a/test/nilptr/structfield2.go b/test/nilptr/structfield2.go
index 25ea8f665..02a44f173 100644
--- a/test/nilptr/structfield2.go
+++ b/test/nilptr/structfield2.go
@@ -1,4 +1,3 @@
-// [ $GOOS != nacl ] || exit 0 # do not bother on NaCl
// $G $D/$F.go && $L $F.$A &&
// ((! sh -c ./$A.out) >/dev/null 2>&1 || echo BUG: should fail)
@@ -10,14 +9,14 @@ package main
import "unsafe"
-var dummy [512<<20]byte; // give us a big address space
+var dummy [512<<20]byte // give us a big address space
type T struct {
- x [256<<20] byte;
- i int;
+ x [256<<20] byte
+ i int
}
-var y *T;
-var x = &y;
+var y *T
+var x = &y
func main() {
// the test only tests what we intend to test
@@ -26,12 +25,12 @@ func main() {
// at the address that might be accidentally
// dereferenced below.
if uintptr(unsafe.Pointer(&dummy)) > 256<<20 {
- panic("dummy too far out");
+ panic("dummy too far out")
}
// The problem here is that indexing into t with a large
// enough index can jump out of the unmapped section
// at the beginning of memory and into valid memory.
// We require the pointer dereference to check.
- println((*x).i); // should crash
+ println((*x).i) // should crash
}
diff --git a/test/nilptr/structfieldaddr.go b/test/nilptr/structfieldaddr.go
index b5d370ca8..f3177bafb 100644
--- a/test/nilptr/structfieldaddr.go
+++ b/test/nilptr/structfieldaddr.go
@@ -1,4 +1,3 @@
-// [ $GOOS != nacl ] || exit 0 # do not bother on NaCl
// $G $D/$F.go && $L $F.$A &&
// ((! sh -c ./$A.out) >/dev/null 2>&1 || echo BUG: should fail)
@@ -10,10 +9,10 @@ package main
import "unsafe"
-var dummy [512<<20]byte; // give us a big address space
+var dummy [512<<20]byte // give us a big address space
type T struct {
- x [256<<20] byte;
- i int;
+ x [256<<20] byte
+ i int
}
func main() {
@@ -23,13 +22,13 @@ func main() {
// at the address that might be accidentally
// dereferenced below.
if uintptr(unsafe.Pointer(&dummy)) > 256<<20 {
- panic("dummy too far out");
+ panic("dummy too far out")
}
// The problem here is that indexing into t with a large
// enough index can jump out of the unmapped section
// at the beginning of memory and into valid memory.
// We require the address calculation to check.
- var t *T;
- println(&t.i); // should crash
+ var t *T
+ println(&t.i) // should crash
}
diff --git a/test/nul1.go b/test/nul1.go
index 5e4596331..9cf51125b 100644
--- a/test/nul1.go
+++ b/test/nul1.go
@@ -1,4 +1,4 @@
-// [ $GOOS != nacl ] || exit 0 # NaCl runner elides NUL in output
+// [ "$GORUN" == "" ] || exit 0 # Android runner gets confused by the NUL output
// $G $D/$F.go && $L $F.$A && ./$A.out >tmp.go &&
// errchk $G -e tmp.go
// rm -f tmp.go
@@ -24,7 +24,7 @@ func main() {
if len(s) != 2 || s[0] != 0xc2 || s[1] != 0xff ||
len(t) != 2 || t[0] != 0xd0 || t[1] != 0xfe ||
len(u) != 3 || u[0] != 0xab || u[1] != 0x00 || u[2] != 0xfc {
- println("BUG: non-UTF-8 string mangled");
+ println("BUG: non-UTF-8 string mangled")
os.Exit(2)
}
@@ -47,7 +47,7 @@ var yy = ` + "`in raw string \xff foo`" + ` // ERROR "UTF-8"
// in comment ` + "\xe2\x80\x01" + ` // ERROR "UTF-8"
-/* in other comment ` + "\xe0\x00\x00" + ` */ // ERROR "UTF-8"
+/* in other comment ` + "\xe0\x00\x00" + ` */ // ERROR "UTF-8|NUL"
/* in variable name */
var z` + "\xc1\x81" + ` int // ERROR "UTF-8"
diff --git a/test/parentype.go b/test/parentype.go
index d5729f820..1872cd0eb 100644
--- a/test/parentype.go
+++ b/test/parentype.go
@@ -9,11 +9,9 @@ package main
func f(interface{})
func g() {}
func main() {
- f(map[string]string{"a":"b","c":"d"});
- f([...]int{1,2,3});
- f(([...]int){1,2,3});
- f((map[string]string){"a":"b","c":"d"});
- f((map[string]func()){"a":g,"c":g});
- f(make(chan(<-chan int)));
- f(make(chan<-(chan int)));
+ f(map[string]string{"a":"b","c":"d"})
+ f([...]int{1,2,3})
+ f(map[string]func(){"a":g,"c":g})
+ f(make(chan(<-chan int)))
+ f(make(chan<-(chan int)))
}
diff --git a/test/peano.go b/test/peano.go
index 77a0d1272..f4c59d1e1 100644
--- a/test/peano.go
+++ b/test/peano.go
@@ -6,9 +6,7 @@
package main
-type Number struct {
- next *Number
-}
+type Number *Number
// -------------------------------------
@@ -26,13 +24,13 @@ func is_zero(x *Number) bool {
func add1(x *Number) *Number {
e := new(Number)
- e.next = x
+ *e = x
return e
}
func sub1(x *Number) *Number {
- return x.next
+ return *x
}
@@ -96,7 +94,7 @@ func check(x *Number, expected int) {
// -------------------------------------
// Test basic functionality
-func verify() {
+func init() {
check(zero(), 0)
check(add1(zero()), 1)
check(gen(10), 10)
@@ -121,10 +119,7 @@ func verify() {
// -------------------------------------
// Factorial
-
func main() {
-
- verify()
for i := 0; i <= 9; i++ {
print(i, "! = ", count(fact(gen(i))), "\n")
}
diff --git a/test/printbig.go b/test/printbig.go
index 5ec95b946..bbb707004 100644
--- a/test/printbig.go
+++ b/test/printbig.go
@@ -7,6 +7,6 @@
package main
func main() {
- print(-(1<<63), "\n");
+ print(-(1<<63), "\n")
print((1<<63)-1, "\n")
}
diff --git a/test/range.go b/test/range.go
index 9093d714b..91ccd6307 100644
--- a/test/range.go
+++ b/test/range.go
@@ -32,18 +32,59 @@ func testchan() {
}
}
-// test that range over array only evaluates
+// test that range over slice only evaluates
// the expression after "range" once.
var nmake = 0
-func makearray() []int {
+func makeslice() []int {
nmake++
return []int{1, 2, 3, 4, 5}
}
+func testslice() {
+ s := 0
+ nmake = 0
+ for _, v := range makeslice() {
+ s += v
+ }
+ if nmake != 1 {
+ println("range called makeslice", nmake, "times")
+ panic("fail")
+ }
+ if s != 15 {
+ println("wrong sum ranging over makeslice")
+ panic("fail")
+ }
+}
+
+func testslice1() {
+ s := 0
+ nmake = 0
+ for i := range makeslice() {
+ s += i
+ }
+ if nmake != 1 {
+ println("range called makeslice", nmake, "times")
+ panic("fail")
+ }
+ if s != 10 {
+ println("wrong sum ranging over makeslice")
+ panic("fail")
+ }
+}
+
+// test that range over array only evaluates
+// the expression after "range" once.
+
+func makearray() [5]int {
+ nmake++
+ return [5]int{1, 2, 3, 4, 5}
+}
+
func testarray() {
s := 0
+ nmake = 0
for _, v := range makearray() {
s += v
}
@@ -57,6 +98,151 @@ func testarray() {
}
}
+func testarray1() {
+ s := 0
+ nmake = 0
+ for i := range makearray() {
+ s += i
+ }
+ if nmake != 1 {
+ println("range called makearray", nmake, "times")
+ panic("fail")
+ }
+ if s != 10 {
+ println("wrong sum ranging over makearray")
+ panic("fail")
+ }
+}
+
+func makearrayptr() *[5]int {
+ nmake++
+ return &[5]int{1, 2, 3, 4, 5}
+}
+
+func testarrayptr() {
+ nmake = 0
+ x := len(makearrayptr())
+ if x != 5 || nmake != 1 {
+ println("len called makearrayptr", nmake, "times and got len", x)
+ panic("fail")
+ }
+ nmake = 0
+ x = cap(makearrayptr())
+ if x != 5 || nmake != 1 {
+ println("cap called makearrayptr", nmake, "times and got len", x)
+ panic("fail")
+ }
+ s := 0
+ nmake = 0
+ for _, v := range makearrayptr() {
+ s += v
+ }
+ if nmake != 1 {
+ println("range called makearrayptr", nmake, "times")
+ panic("fail")
+ }
+ if s != 15 {
+ println("wrong sum ranging over makearrayptr")
+ panic("fail")
+ }
+}
+
+func testarrayptr1() {
+ s := 0
+ nmake = 0
+ for i := range makearrayptr() {
+ s += i
+ }
+ if nmake != 1 {
+ println("range called makearrayptr", nmake, "times")
+ panic("fail")
+ }
+ if s != 10 {
+ println("wrong sum ranging over makearrayptr")
+ panic("fail")
+ }
+}
+
+// test that range over string only evaluates
+// the expression after "range" once.
+
+func makestring() string {
+ nmake++
+ return "abcd☺"
+}
+
+func teststring() {
+ s := 0
+ nmake = 0
+ for _, v := range makestring() {
+ s += v
+ }
+ if nmake != 1 {
+ println("range called makestring", nmake, "times")
+ panic("fail")
+ }
+ if s != 'a'+'b'+'c'+'d'+'☺' {
+ println("wrong sum ranging over makestring")
+ panic("fail")
+ }
+}
+
+func teststring1() {
+ s := 0
+ nmake = 0
+ for i := range makestring() {
+ s += i
+ }
+ if nmake != 1 {
+ println("range called makestring", nmake, "times")
+ panic("fail")
+ }
+ if s != 10 {
+ println("wrong sum ranging over makestring")
+ panic("fail")
+ }
+}
+
+// test that range over map only evaluates
+// the expression after "range" once.
+
+func makemap() map[int]int {
+ nmake++
+ return map[int]int{0:'a', 1:'b', 2:'c', 3:'d', 4:'☺'}
+}
+
+func testmap() {
+ s := 0
+ nmake = 0
+ for _, v := range makemap() {
+ s += v
+ }
+ if nmake != 1 {
+ println("range called makemap", nmake, "times")
+ panic("fail")
+ }
+ if s != 'a'+'b'+'c'+'d'+'☺' {
+ println("wrong sum ranging over makemap")
+ panic("fail")
+ }
+}
+
+func testmap1() {
+ s := 0
+ nmake = 0
+ for i := range makemap() {
+ s += i
+ }
+ if nmake != 1 {
+ println("range called makemap", nmake, "times")
+ panic("fail")
+ }
+ if s != 10 {
+ println("wrong sum ranging over makemap")
+ panic("fail")
+ }
+}
+
// test that range evaluates the index and value expressions
// exactly once per iteration.
@@ -98,5 +284,14 @@ func testcalls() {
func main() {
testchan()
testarray()
+ testarray1()
+ testarrayptr()
+ testarrayptr1()
+ testslice()
+ testslice1()
+ teststring()
+ teststring1()
+ testmap()
+ testmap1()
testcalls()
}
diff --git a/test/recover2.go b/test/recover2.go
index 496909f35..f33af4457 100644
--- a/test/recover2.go
+++ b/test/recover2.go
@@ -7,7 +7,6 @@
// Test of recover for run-time errors.
// TODO(rsc):
-// integer divide by zero?
// null pointer accesses
package main
@@ -15,7 +14,6 @@ package main
import (
"os"
"strings"
- "syscall"
)
var x = make([]byte, 10)
@@ -52,7 +50,9 @@ func test2() {
func test3() {
defer mustRecover("slice")
- println(x[11:9])
+ var lo = 11
+ var hi = 9
+ println(x[lo:hi])
}
func test4() {
@@ -81,10 +81,6 @@ func test6() {
}
func test7() {
- if syscall.ARCH == "arm" || syscall.OS == "nacl" {
- // ARM doesn't have integer divide trap yet
- return
- }
defer mustRecover("divide by zero")
var x, y int
println(x / y)
diff --git a/test/recover3.go b/test/recover3.go
index b982ec8fa..2aa1df616 100644
--- a/test/recover3.go
+++ b/test/recover3.go
@@ -1,4 +1,3 @@
-// [ $GOOS != nacl ] || exit 0 # NaCl cannot recover from signals
// $G $D/$F.go && $L $F.$A && ./$A.out
// Copyright 2010 The Go Authors. All rights reserved.
@@ -10,7 +9,6 @@ package main
import (
"runtime"
"strings"
- "syscall"
)
var didbug bool
@@ -44,7 +42,7 @@ func check(name string, f func(), err string) {
return
}
}()
-
+
f()
}
@@ -55,11 +53,8 @@ func main() {
var q *[10000]int
var i int
- // not catching divide by zero on the arm. is that even possible?
- if syscall.ARCH != "arm" {
- check("int-div-zero", func() { println(1/x) }, "integer divide by zero")
- check("int64-div-zero", func() { println(1/x64) }, "integer divide by zero")
- }
+ check("int-div-zero", func() { println(1 / x) }, "integer divide by zero")
+ check("int64-div-zero", func() { println(1 / x64) }, "integer divide by zero")
check("nil-deref", func() { println(p[0]) }, "nil pointer dereference")
check("nil-deref-1", func() { println(p[1]) }, "nil pointer dereference")
@@ -69,11 +64,13 @@ func main() {
var sl []int
check("array-bounds", func() { println(p[i]) }, "index out of range")
check("slice-bounds", func() { println(sl[i]) }, "index out of range")
-
+
var inter interface{}
inter = 1
check("type-concrete", func() { println(inter.(string)) }, "int, not string")
check("type-interface", func() { println(inter.(m)) }, "missing method m")
}
-type m interface{ m() }
+type m interface {
+ m()
+}
diff --git a/test/run b/test/run
index b3f54f12f..28d0caa0f 100755
--- a/test/run
+++ b/test/run
@@ -3,7 +3,8 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-export E=""
+eval $(gomake --no-print-directory -f ../src/Make.inc go-env)
+
case X"$GOARCH" in
Xamd64)
export A=6
@@ -13,7 +14,7 @@ X386)
;;
Xarm)
export A=5
- export E=${GORUN:-qemu-arm -cpu cortex-a8}
+ export E="$GORUN"
;;
*)
echo 1>&2 run: unsupported '$GOARCH'
@@ -33,7 +34,7 @@ unset GREP_OPTIONS # in case user has a non-standard set
failed=0
-PATH=/bin:/usr/bin:/usr/local/bin:${GOBIN:-$HOME/bin}:`pwd`
+PATH=/bin:/usr/bin:/usr/local/bin:${GOBIN:-$GOROOT/bin}:`pwd`
RUNFILE=/tmp/gorun-$$-$USER
TMP1FILE=/tmp/gotest1-$$-$USER
@@ -48,26 +49,47 @@ ulimit -c 0
true >pass.out >times.out
+exclude=false # exclude nothing
+golden=golden.out
+
+filterout() {
+ grep '^'"$2"'$' $1 >/dev/null
+}
+
for dir in . ken chan interface nilptr syntax fixedbugs bugs
do
echo
echo '==' $dir'/'
for i in $(ls $dir/*.go 2>/dev/null)
- do
+ do (
+ if $exclude $i; then
+ exit 0 # continues for loop
+ fi
export F=$(basename $i .go)
export D=$dir
- sed '/^\/\//!q' $i | sed 's@//@@; $d' |sed 's|./\$A.out|$E &|' >$RUNFILE
+ sed '/^\/\//!q' $i | sed 's@//@@; $d' |sed 's|./\$A.out|$E &|g' >$RUNFILE
if ! { time -p bash -c "bash $RUNFILE >$TMP1FILE 2>&1" ; } 2>$TMP2FILE
then
echo
echo "===========" $i
cat $TMP1FILE
echo >&2 fail: $i
+ echo "# $i # fail" >>pass.out
elif test -s $TMP1FILE
then
echo
echo "===========" $i
cat $TMP1FILE
+ if grep -q '^BUG' $TMP1FILE
+ then
+ if [ $dir != bugs ]
+ then
+ echo >&2 bug: $i
+ fi
+ echo "# $i # fail, BUG" >>pass.out
+ else
+ echo $i >>pass.out
+ fi
elif [ $dir = "bugs" ]
then
echo $i succeeded with no output.
@@ -75,7 +97,7 @@ do
echo $i >>pass.out
fi
echo $(awk 'NR==1{print $2}' $TMP2FILE) $D/$F >>times.out
- done
+ ) done
done | # clean up some stack noise
egrep -v '^(r[0-9a-z]+|[cfg]s) +0x' |
sed '/tmp.*Bus error/s/.*Bus/Bus/; /tmp.*Trace.BPT/s/.*Trace/Trace/
@@ -87,12 +109,13 @@ done | # clean up some stack noise
/^Trace\/BPT trap/d
/RUNFILE/ s/line 1: *[0-9]*/line 1: PID/
/^\$RUNFILE: line 1: PID Trace\/breakpoint trap/d
+ /Fault in NaCl untrusted code/d
/Segmentation fault/d
/^qemu: uncaught target signal 11 (Segmentation fault) - exiting/d' > run.out
-rm -f $RUNFILE $TMP1FILE $TMP2FILE *.$A $A.out
+rm -f $RUNFILE $TMP1FILE $TMP2FILE *.$A *.a $A.out
diffmsg=""
-if ! diff run.out golden.out
+if ! diff $golden run.out
then
diffmsg="; test output differs"
failed=1
diff --git a/test/run-arm b/test/run-arm
deleted file mode 100755
index c7545ae0e..000000000
--- a/test/run-arm
+++ /dev/null
@@ -1,102 +0,0 @@
-#!/bin/sh
-# Copyright 2009 The Go Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style
-# license that can be found in the LICENSE file.
-
-export E=""
-case X"$GOARCH" in
-Xamd64)
- export A=6
- ;;
-X386)
- export A=8
- ;;
-Xarm)
- export A=5
- export E="${GORUN:-qemu-arm -cpu cortex-a8}"
- ;;
-*)
- echo 1>&2 run: unsupported '$GOARCH'
- exit 1
-esac
-
-export G=${A}g
-export L=${A}l
-export GOTRACEBACK=0
-
-PATH=/bin:/usr/bin:/usr/local/bin:${GOBIN:-$HOME/bin}:`pwd`
-
-RUNFILE=/tmp/gorun-$$-$USER
-TMP1FILE=/tmp/gotest1-$$-$USER
-TMP2FILE=/tmp/gotest2-$$-$USER
-FAILEDFILE=/tmp/gotest3-$$-$USER
-
-# don't run the machine out of memory: limit individual processes to 4GB.
-# on thresher, 3GB suffices to run the tests; with 2GB, peano fails.
-ulimit -v 4000000
-
-# no core files please
-ulimit -c 0
-
-true >times.out
-
-# TODO(kaib): figure out why the GC makes things so utterly slow.
-export GOGC=off
-export GOTRACEBACK=0
-
-for i in $(cat arm-pass.txt | sed 's/#.*//')
-do
- export F=$(basename $i .go)
- dir=$(dirname $i)
- export D=$dir
- sed '/^\/\//!q' $i | sed 's@//@@; $d' |sed 's|./\$A.out|$E &|' >$RUNFILE
- if ! { time -p bash -c "bash $RUNFILE >$TMP1FILE 2>&1" ; } 2>$TMP2FILE
- then
- echo
- echo "===========" $i
- cat $TMP1FILE
- echo >&2 fail: $i
- touch $FAILEDFILE
- elif test -s $TMP1FILE
- then
- echo
- echo "===========" $i
- cat $TMP1FILE
- elif [ $dir = "bugs" ]
- then
- echo $i succeeded with no output.
- fi
- echo $(awk 'NR==1{print $2}' $TMP2FILE) $D/$F >>times.out
-done | # clean up some stack noise
- egrep -v '^(r[0-9a-z]+|[cfg]s) +0x' |
- sed '/tmp.*Bus error/s/.*Bus/Bus/; /tmp.*Trace.BPT/s/.*Trace/Trace/
- s!'$RUNFILE'!$RUNFILE!g
- s/ PC=0x[0-9a-f]*/ PC=xxx/
- s/^pc: 0x[0-9a-f]*/pc: xxx/
- /^Trace\/breakpoint trap/d
- /^Trace\/BPT trap/d
- s!'$GOROOT'!$GOROOT!g
- /Segmentation fault/d
- /RUNFILE/ s/line 1: *[0-9]*/line 1: PID/
- /^\$RUNFILE: line 1: PID Trace\/breakpoint trap/d
- /^qemu: uncaught target signal 11 (Segmentation fault) - exiting/d' > run.out
-
-failed=0
-rm -f $RUNFILE $TMP1FILE $TMP2FILE *.$A $A.out
-diffmsg=""
-if ! diff -b run.out golden-arm.out
-then
- diffmsg="; test output differs"
- failed=1
-fi
-
-notinbugs=$(sed '/== bugs/q' run.out | grep -c '^BUG')
-inbugs=$(sed '1,/== bugs/d' run.out | grep -c '^BUG')
-
-echo 2>&1 $inbugs known bugs';' $notinbugs unexpected bugs$diffmsg
-
-if [ "$failed" != "0" ]; then
- echo FAILED
-fi
-
-exit $failed
diff --git a/test/runtime.go b/test/runtime.go
index 256873a7a..4be1d055b 100644
--- a/test/runtime.go
+++ b/test/runtime.go
@@ -16,5 +16,5 @@ package main
import "runtime"
func main() {
- runtime.printbool(true); // ERROR "unexported"
+ runtime.printbool(true) // ERROR "unexported"
}
diff --git a/test/sieve.go b/test/sieve.go
index ec2ce446e..4fa111582 100644
--- a/test/sieve.go
+++ b/test/sieve.go
@@ -9,7 +9,7 @@ package main
// Send the sequence 2, 3, 4, ... to channel 'ch'.
func Generate(ch chan<- int) {
for i := 2; ; i++ {
- ch <- i // Send 'i' to channel 'ch'.
+ ch <- i // Send 'i' to channel 'ch'.
}
}
@@ -17,22 +17,22 @@ func Generate(ch chan<- int) {
// removing those divisible by 'prime'.
func Filter(in <-chan int, out chan<- int, prime int) {
for {
- i := <-in; // Receive value of new variable 'i' from 'in'.
- if i % prime != 0 {
- out <- i // Send 'i' to channel 'out'.
+ i := <-in // Receive value of new variable 'i' from 'in'.
+ if i%prime != 0 {
+ out <- i // Send 'i' to channel 'out'.
}
}
}
// The prime sieve: Daisy-chain Filter processes together.
func Sieve() {
- ch := make(chan int); // Create a new channel.
- go Generate(ch); // Start Generate() as a subprocess.
+ ch := make(chan int) // Create a new channel.
+ go Generate(ch) // Start Generate() as a subprocess.
for {
- prime := <-ch;
- print(prime, "\n");
- ch1 := make(chan int);
- go Filter(ch, ch1, prime);
+ prime := <-ch
+ print(prime, "\n")
+ ch1 := make(chan int)
+ go Filter(ch, ch1, prime)
ch = ch1
}
}
diff --git a/test/sigchld.go b/test/sigchld.go
index 3887e2d02..1fb2e21bd 100644
--- a/test/sigchld.go
+++ b/test/sigchld.go
@@ -1,4 +1,3 @@
-// if [ $GOOS == nacl ]; then echo survived SIGCHLD; exit 0; fi # NaCl has no signals.
// $G $D/$F.go && $L $F.$A && ./$A.out
// Copyright 2009 The Go Authors. All rights reserved.
@@ -10,6 +9,6 @@ package main
import "syscall"
func main() {
- syscall.Syscall(syscall.SYS_KILL, uintptr(syscall.Getpid()), syscall.SIGCHLD, 0);
- println("survived SIGCHLD");
+ syscall.Kill(syscall.Getpid(), syscall.SIGCHLD)
+ println("survived SIGCHLD")
}
diff --git a/test/sinit.go b/test/sinit.go
index 730106675..2adb931e1 100644
--- a/test/sinit.go
+++ b/test/sinit.go
@@ -9,10 +9,10 @@ package p
// Should be no init func in the assembly.
// All these initializations should be done at link time.
-type S struct{ a,b,c int };
-type SS struct{ aa,bb,cc S };
-type SA struct{ a,b,c [3]int };
-type SC struct{ a,b,c []int };
+type S struct{ a,b,c int }
+type SS struct{ aa,bb,cc S }
+type SA struct{ a,b,c [3]int }
+type SC struct{ a,b,c []int }
var (
zero = 2
diff --git a/test/solitaire.go b/test/solitaire.go
new file mode 100644
index 000000000..c789bf24a
--- /dev/null
+++ b/test/solitaire.go
@@ -0,0 +1,119 @@
+// $G $F.go && $L $F.$A # don't run it - produces too much output
+
+// Copyright 2010 The Go 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 program solves the (English) peg solitaire board game.
+// See also: http://en.wikipedia.org/wiki/Peg_solitaire
+
+package main
+
+const N = 11 + 1 // length of a board row (+1 for newline)
+
+// The board must be surrounded by 2 illegal fields in each direction
+// so that move() doesn't need to check the board boundaries. Periods
+// represent illegal fields, ● are pegs, and ○ are holes.
+var board = []int(
+ `...........
+...........
+....●●●....
+....●●●....
+..●●●●●●●..
+..●●●○●●●..
+..●●●●●●●..
+....●●●....
+....●●●....
+...........
+...........
+`)
+
+
+// center is the position of the center hole if there is a single one;
+// otherwise it is -1.
+var center int
+
+func init() {
+ n := 0
+ for pos, field := range board {
+ if field == '○' {
+ center = pos
+ n++
+ }
+ }
+ if n != 1 {
+ center = -1 // no single hole
+ }
+}
+
+
+var moves int // number of times move is called
+
+// move tests if there is a peg at position pos that can jump over another peg
+// in direction dir. If the move is valid, it is executed and move returns true.
+// Otherwise, move returns false.
+func move(pos, dir int) bool {
+ moves++
+ if board[pos] == '●' && board[pos+dir] == '●' && board[pos+2*dir] == '○' {
+ board[pos] = '○'
+ board[pos+dir] = '○'
+ board[pos+2*dir] = '●'
+ return true
+ }
+ return false
+}
+
+
+// unmove reverts a previously executed valid move.
+func unmove(pos, dir int) {
+ board[pos] = '●'
+ board[pos+dir] = '●'
+ board[pos+2*dir] = '○'
+}
+
+
+// solve tries to find a sequence of moves such that there is only one peg left
+// at the end; if center is >= 0, that last peg must be in the center position.
+// If a solution is found, solve prints the board after each move in a backward
+// fashion (i.e., the last board position is printed first, all the way back to
+// the starting board position).
+func solve() bool {
+ var last, n int
+ for pos, field := range board {
+ // try each board position
+ if field == '●' {
+ // found a peg
+ for _, dir := range [...]int{-1, -N, +1, +N} {
+ // try each direction
+ if move(pos, dir) {
+ // a valid move was found and executed,
+ // see if this new board has a solution
+ if solve() {
+ unmove(pos, dir)
+ println(string(board))
+ return true
+ }
+ unmove(pos, dir)
+ }
+ }
+ last = pos
+ n++
+ }
+ }
+ // tried each possible move
+ if n == 1 && (center < 0 || last == center) {
+ // there's only one peg left
+ println(string(board))
+ return true
+ }
+ // no solution found for this board
+ return false
+}
+
+
+func main() {
+ if !solve() {
+ println("no solution found")
+ }
+ println(moves, "moves tried")
+}
diff --git a/test/string_lit.go b/test/string_lit.go
index 88b5d251f..4358dd8e8 100644
--- a/test/string_lit.go
+++ b/test/string_lit.go
@@ -12,15 +12,15 @@ var ecode int
func assert(a, b, c string) {
if a != b {
- ecode = 1;
- print("FAIL: ", c, ": ", a, "!=", b, "\n");
- var max int = len(a);
+ ecode = 1
+ print("FAIL: ", c, ": ", a, "!=", b, "\n")
+ var max int = len(a)
if len(b) > max {
max = len(b)
}
for i := 0; i < max; i++ {
- ac := 0;
- bc := 0;
+ ac := 0
+ bc := 0
if i < len(a) {
ac = int(a[i])
}
@@ -48,7 +48,7 @@ var (
)
func main() {
- ecode = 0;
+ ecode = 0
s :=
"" +
" " +
@@ -67,38 +67,38 @@ func main() {
`本` +
`\a\b\f\n\r\t\v\\\'` +
`\000\123\x00\xca\xFE\u0123\ubabe\U0000babe` +
- `\x\u\U\`;
+ `\x\u\U\`
- assert("", ``, "empty");
- assert(" ", " ", "blank");
- assert("\x61", "a", "lowercase a");
- assert("\x61", `a`, "lowercase a (backquote)");
- assert("\u00e4", "ä", "a umlaut");
- assert("\u00e4", `ä`, "a umlaut (backquote)");
- assert("\u672c", "本", "nihon");
- assert("\u672c", `本`, "nihon (backquote)");
+ assert("", ``, "empty")
+ assert(" ", " ", "blank")
+ assert("\x61", "a", "lowercase a")
+ assert("\x61", `a`, "lowercase a (backquote)")
+ assert("\u00e4", "ä", "a umlaut")
+ assert("\u00e4", `ä`, "a umlaut (backquote)")
+ assert("\u672c", "本", "nihon")
+ assert("\u672c", `本`, "nihon (backquote)")
assert("\x07\x08\x0c\x0a\x0d\x09\x0b\x5c\x22",
"\a\b\f\n\r\t\v\\\"",
- "backslashes");
+ "backslashes")
assert("\\a\\b\\f\\n\\r\\t\\v\\\\\\\"",
`\a\b\f\n\r\t\v\\\"`,
- "backslashes (backquote)");
+ "backslashes (backquote)")
assert("\x00\x53\000\xca\376S몾몾",
"\000\123\x00\312\xFE\u0053\ubabe\U0000babe",
- "backslashes 2");
+ "backslashes 2")
assert("\\000\\123\\x00\\312\\xFE\\u0123\\ubabe\\U0000babe",
`\000\123\x00\312\xFE\u0123\ubabe\U0000babe`,
- "backslashes 2 (backquote)");
- assert("\\x\\u\\U\\", `\x\u\U\`, "backslash 3 (backquote)");
+ "backslashes 2 (backquote)")
+ assert("\\x\\u\\U\\", `\x\u\U\`, "backslash 3 (backquote)")
// test large runes. perhaps not the most logical place for this test.
- var r int32;
+ var r int32
r = 0x10ffff; // largest rune value
- s = string(r);
- assert(s, "\xf4\x8f\xbf\xbf", "largest rune");
- r = 0x10ffff + 1;
- s = string(r);
- assert(s, "\xef\xbf\xbd", "too-large rune");
+ s = string(r)
+ assert(s, "\xf4\x8f\xbf\xbf", "largest rune")
+ r = 0x10ffff + 1
+ s = string(r)
+ assert(s, "\xef\xbf\xbd", "too-large rune")
assert(string(gr1), gx1, "global ->[]int")
assert(string(gr2), gx2fix, "global invalid ->[]int")
@@ -116,5 +116,5 @@ func main() {
assert(string(b1), gx1, "->[]byte")
assert(string(b2), gx2, "invalid ->[]byte")
- os.Exit(ecode);
+ os.Exit(ecode)
}
diff --git a/test/stringrange.go b/test/stringrange.go
index 9215b95fa..d5ada2628 100644
--- a/test/stringrange.go
+++ b/test/stringrange.go
@@ -7,55 +7,55 @@
package main
import (
- "fmt";
- "os";
- "utf8";
+ "fmt"
+ "os"
+ "utf8"
)
func main() {
- s := "\000\123\x00\xca\xFE\u0123\ubabe\U0000babe\U0010FFFFx";
- expect := []int{ 0, 0123, 0, 0xFFFD, 0xFFFD, 0x123, 0xbabe, 0xbabe, 0x10FFFF, 'x' };
- offset := 0;
- var i, c int;
- ok := true;
- cnum := 0;
+ s := "\000\123\x00\xca\xFE\u0123\ubabe\U0000babe\U0010FFFFx"
+ expect := []int{ 0, 0123, 0, 0xFFFD, 0xFFFD, 0x123, 0xbabe, 0xbabe, 0x10FFFF, 'x' }
+ offset := 0
+ var i, c int
+ ok := true
+ cnum := 0
for i, c = range s {
- rune, size := utf8.DecodeRuneInString(s[i:len(s)]); // check it another way
+ rune, size := utf8.DecodeRuneInString(s[i:len(s)]) // check it another way
if i != offset {
- fmt.Printf("unexpected offset %d not %d\n", i, offset);
- ok = false;
+ fmt.Printf("unexpected offset %d not %d\n", i, offset)
+ ok = false
}
if rune != expect[cnum] {
- fmt.Printf("unexpected rune %d from DecodeRuneInString: %x not %x\n", i, rune, expect[cnum]);
- ok = false;
+ fmt.Printf("unexpected rune %d from DecodeRuneInString: %x not %x\n", i, rune, expect[cnum])
+ ok = false
}
if c != expect[cnum] {
- fmt.Printf("unexpected rune %d from range: %x not %x\n", i, rune, expect[cnum]);
- ok = false;
+ fmt.Printf("unexpected rune %d from range: %x not %x\n", i, rune, expect[cnum])
+ ok = false
}
- offset += size;
- cnum++;
+ offset += size
+ cnum++
}
if i != len(s)-1 {
- fmt.Println("after loop i is", i, "not", len(s)-1);
- ok = false;
+ fmt.Println("after loop i is", i, "not", len(s)-1)
+ ok = false
}
- i = 12345;
- c = 23456;
+ i = 12345
+ c = 23456
for i, c = range "" {
}
if i != 12345 {
- fmt.Println("range empty string assigned to index:", i);
- ok = false;
+ fmt.Println("range empty string assigned to index:", i)
+ ok = false
}
if c != 23456 {
- fmt.Println("range empty string assigned to value:", c);
- ok = false;
+ fmt.Println("range empty string assigned to value:", c)
+ ok = false
}
if !ok {
- fmt.Println("BUG: stringrange");
+ fmt.Println("BUG: stringrange")
os.Exit(1)
}
}
diff --git a/test/switch.go b/test/switch.go
index 835c90081..0c253d6e2 100644
--- a/test/switch.go
+++ b/test/switch.go
@@ -8,59 +8,59 @@ package main
func assert(cond bool, msg string) {
if !cond {
- print("assertion fail: ", msg, "\n");
- panic(1);
+ print("assertion fail: ", msg, "\n")
+ panic(1)
}
}
func main() {
- i5 := 5;
- i7 := 7;
- hello := "hello";
+ i5 := 5
+ i7 := 7
+ hello := "hello"
switch true {
- case i5 < 5: assert(false, "<");
- case i5 == 5: assert(true, "!");
- case i5 > 5: assert(false, ">");
+ case i5 < 5: assert(false, "<")
+ case i5 == 5: assert(true, "!")
+ case i5 > 5: assert(false, ">")
}
switch {
- case i5 < 5: assert(false, "<");
- case i5 == 5: assert(true, "!");
- case i5 > 5: assert(false, ">");
+ case i5 < 5: assert(false, "<")
+ case i5 == 5: assert(true, "!")
+ case i5 > 5: assert(false, ">")
}
switch x := 5; true {
- case i5 < x: assert(false, "<");
- case i5 == x: assert(true, "!");
- case i5 > x: assert(false, ">");
+ case i5 < x: assert(false, "<")
+ case i5 == x: assert(true, "!")
+ case i5 > x: assert(false, ">")
}
switch x := 5; true {
- case i5 < x: assert(false, "<");
- case i5 == x: assert(true, "!");
- case i5 > x: assert(false, ">");
+ case i5 < x: assert(false, "<")
+ case i5 == x: assert(true, "!")
+ case i5 > x: assert(false, ">")
}
switch i5 {
- case 0: assert(false, "0");
- case 1: assert(false, "1");
- case 2: assert(false, "2");
- case 3: assert(false, "3");
- case 4: assert(false, "4");
- case 5: assert(true, "5");
- case 6: assert(false, "6");
- case 7: assert(false, "7");
- case 8: assert(false, "8");
- case 9: assert(false, "9");
- default: assert(false, "default");
+ case 0: assert(false, "0")
+ case 1: assert(false, "1")
+ case 2: assert(false, "2")
+ case 3: assert(false, "3")
+ case 4: assert(false, "4")
+ case 5: assert(true, "5")
+ case 6: assert(false, "6")
+ case 7: assert(false, "7")
+ case 8: assert(false, "8")
+ case 9: assert(false, "9")
+ default: assert(false, "default")
}
switch i5 {
- case 0,1,2,3,4: assert(false, "4");
- case 5: assert(true, "5");
- case 6,7,8,9: assert(false, "9");
- default: assert(false, "default");
+ case 0,1,2,3,4: assert(false, "4")
+ case 5: assert(true, "5")
+ case 6,7,8,9: assert(false, "9")
+ default: assert(false, "default")
}
switch i5 {
@@ -68,72 +68,72 @@ func main() {
case 1:
case 2:
case 3:
- case 4: assert(false, "4");
- case 5: assert(true, "5");
+ case 4: assert(false, "4")
+ case 5: assert(true, "5")
case 6:
case 7:
case 8:
case 9:
- default: assert(i5 == 5, "good");
+ default: assert(i5 == 5, "good")
}
switch i5 {
- case 0: dummy := 0; _ = dummy; fallthrough;
- case 1: dummy := 0; _ = dummy; fallthrough;
- case 2: dummy := 0; _ = dummy; fallthrough;
- case 3: dummy := 0; _ = dummy; fallthrough;
- case 4: dummy := 0; _ = dummy; assert(false, "4");
- case 5: dummy := 0; _ = dummy; fallthrough;
- case 6: dummy := 0; _ = dummy; fallthrough;
- case 7: dummy := 0; _ = dummy; fallthrough;
- case 8: dummy := 0; _ = dummy; fallthrough;
- case 9: dummy := 0; _ = dummy; fallthrough;
- default: dummy := 0; _ = dummy; assert(i5 == 5, "good");
+ case 0: dummy := 0; _ = dummy; fallthrough
+ case 1: dummy := 0; _ = dummy; fallthrough
+ case 2: dummy := 0; _ = dummy; fallthrough
+ case 3: dummy := 0; _ = dummy; fallthrough
+ case 4: dummy := 0; _ = dummy; assert(false, "4")
+ case 5: dummy := 0; _ = dummy; fallthrough
+ case 6: dummy := 0; _ = dummy; fallthrough
+ case 7: dummy := 0; _ = dummy; fallthrough
+ case 8: dummy := 0; _ = dummy; fallthrough
+ case 9: dummy := 0; _ = dummy; fallthrough
+ default: dummy := 0; _ = dummy; assert(i5 == 5, "good")
}
- fired := false;
+ fired := false
switch i5 {
case 0: dummy := 0; _ = dummy; fallthrough; // tests scoping of cases
- case 1: dummy := 0; _ = dummy; fallthrough;
- case 2: dummy := 0; _ = dummy; fallthrough;
- case 3: dummy := 0; _ = dummy; fallthrough;
- case 4: dummy := 0; _ = dummy; assert(false, "4");
- case 5: dummy := 0; _ = dummy; fallthrough;
- case 6: dummy := 0; _ = dummy; fallthrough;
- case 7: dummy := 0; _ = dummy; fallthrough;
- case 8: dummy := 0; _ = dummy; fallthrough;
- case 9: dummy := 0; _ = dummy; fallthrough;
- default: dummy := 0; _ = dummy; fired = !fired; assert(i5 == 5, "good");
+ case 1: dummy := 0; _ = dummy; fallthrough
+ case 2: dummy := 0; _ = dummy; fallthrough
+ case 3: dummy := 0; _ = dummy; fallthrough
+ case 4: dummy := 0; _ = dummy; assert(false, "4")
+ case 5: dummy := 0; _ = dummy; fallthrough
+ case 6: dummy := 0; _ = dummy; fallthrough
+ case 7: dummy := 0; _ = dummy; fallthrough
+ case 8: dummy := 0; _ = dummy; fallthrough
+ case 9: dummy := 0; _ = dummy; fallthrough
+ default: dummy := 0; _ = dummy; fired = !fired; assert(i5 == 5, "good")
}
- assert(fired, "fired");
+ assert(fired, "fired")
- count := 0;
+ count := 0
switch i5 {
- case 0: count = count + 1; fallthrough;
- case 1: count = count + 1; fallthrough;
- case 2: count = count + 1; fallthrough;
- case 3: count = count + 1; fallthrough;
- case 4: count = count + 1; assert(false, "4");
- case 5: count = count + 1; fallthrough;
- case 6: count = count + 1; fallthrough;
- case 7: count = count + 1; fallthrough;
- case 8: count = count + 1; fallthrough;
- case 9: count = count + 1; fallthrough;
- default: assert(i5 == count, "good");
+ case 0: count = count + 1; fallthrough
+ case 1: count = count + 1; fallthrough
+ case 2: count = count + 1; fallthrough
+ case 3: count = count + 1; fallthrough
+ case 4: count = count + 1; assert(false, "4")
+ case 5: count = count + 1; fallthrough
+ case 6: count = count + 1; fallthrough
+ case 7: count = count + 1; fallthrough
+ case 8: count = count + 1; fallthrough
+ case 9: count = count + 1; fallthrough
+ default: assert(i5 == count, "good")
}
- assert(fired, "fired");
+ assert(fired, "fired")
switch hello {
- case "wowie": assert(false, "wowie");
- case "hello": assert(true, "hello");
- case "jumpn": assert(false, "jumpn");
- default: assert(false, "default");
+ case "wowie": assert(false, "wowie")
+ case "hello": assert(true, "hello")
+ case "jumpn": assert(false, "jumpn")
+ default: assert(false, "default")
}
- fired = false;
+ fired = false
switch i := i5 + 2; i {
- case i7: fired = true;
- default: assert(false, "fail");
+ case i7: fired = true
+ default: assert(false, "fail")
}
- assert(fired, "var");
+ assert(fired, "var")
}
diff --git a/test/switch1.go b/test/switch1.go
index 9e61cc658..5bd9d7c5d 100644
--- a/test/switch1.go
+++ b/test/switch1.go
@@ -9,12 +9,12 @@ package main
import "os"
func main() {
- i := 0;
+ i := 0
switch x := 5; {
case i < x:
- os.Exit(0);
+ os.Exit(0)
case i == x:
case i > x:
- os.Exit(1);
+ os.Exit(1)
}
}
diff --git a/test/syntax/chan.go b/test/syntax/chan.go
new file mode 100644
index 000000000..48beb1e70
--- /dev/null
+++ b/test/syntax/chan.go
@@ -0,0 +1,17 @@
+// errchk $G -e $D/$F.go
+
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type xyz struct {
+ ch chan
+} // ERROR "unexpected } in channel type"
+
+func Foo(y chan) { // ERROR "unexpected \) in channel type"
+}
+
+func Bar(x chan, y int) { // ERROR "unexpected comma in channel type"
+}
diff --git a/test/syntax/topexpr.go b/test/syntax/topexpr.go
index 83de49075..93d86fbe9 100644
--- a/test/syntax/topexpr.go
+++ b/test/syntax/topexpr.go
@@ -6,15 +6,15 @@
package main
-fmt.Printf("hello") // ERROR "non-declaration statement outside function body"
+fmt.Printf("hello") // ERROR "non-declaration statement outside function body|expected declaration"
func main() {
}
-x++ // ERROR "non-declaration statement outside function body"
+x++ // ERROR "non-declaration statement outside function body|expected declaration"
func init() {
}
-x,y := 1, 2 // ERROR "non-declaration statement outside function body"
+x,y := 1, 2 // ERROR "non-declaration statement outside function body|expected declaration"
diff --git a/test/syntax/vareq.go b/test/syntax/vareq.go
index 9be03c1d3..8525be8cf 100644
--- a/test/syntax/vareq.go
+++ b/test/syntax/vareq.go
@@ -7,4 +7,4 @@
package main
func main() {
- var x map[string]string{"a":"b"} // ERROR "unexpected { at end of statement"
+ var x map[string]string{"a":"b"} // ERROR "unexpected { at end of statement|expected ';' or '}' or newline"
diff --git a/test/syntax/vareq1.go b/test/syntax/vareq1.go
index 2d35b3ea0..9d70bea39 100644
--- a/test/syntax/vareq1.go
+++ b/test/syntax/vareq1.go
@@ -6,5 +6,5 @@
package main
-var x map[string]string{"a":"b"} // ERROR "unexpected { at end of statement"
+var x map[string]string{"a":"b"} // ERROR "unexpected { at end of statement|expected ';' or newline after top level declaration"
diff --git a/test/test0.go b/test/test0.go
index f42b12b3c..dd2033a98 100644
--- a/test/test0.go
+++ b/test/test0.go
@@ -10,34 +10,34 @@ const
a_const = 0
const (
- pi = /* the usual */ 3.14159265358979323;
- e = 2.718281828;
- mask1 int = 1 << iota;
- mask2 = 1 << iota;
- mask3 = 1 << iota;
- mask4 = 1 << iota;
+ pi = /* the usual */ 3.14159265358979323
+ e = 2.718281828
+ mask1 int = 1 << iota
+ mask2 = 1 << iota
+ mask3 = 1 << iota
+ mask4 = 1 << iota
)
type (
- Empty interface {};
+ Empty interface {}
Point struct {
- x, y int;
- };
+ x, y int
+ }
Point2 Point
)
func (p *Point) Initialize(x, y int) *Point {
- p.x, p.y = x, y;
- return p;
+ p.x, p.y = x, y
+ return p
}
func (p *Point) Distance() int {
- return p.x * p.x + p.y * p.y;
+ return p.x * p.x + p.y * p.y
}
var (
- x1 int;
- x2 int;
+ x1 int
+ x2 int
u, v, w float
)
@@ -45,40 +45,40 @@ func foo() {}
func min(x, y int) int {
if x < y { return x; }
- return y;
+ return y
}
func swap(x, y int) (u, v int) {
- u = y;
- v = x;
- return;
+ u = y
+ v = x
+ return
}
func control_structs() {
- var p *Point = new(Point).Initialize(2, 3);
- i := p.Distance();
- var f float = 0.3;
- _ = f;
+ var p *Point = new(Point).Initialize(2, 3)
+ i := p.Distance()
+ var f float = 0.3
+ _ = f
+ for {}
for {}
- for {};
for j := 0; j < i; j++ {
if i == 0 {
- } else i = 0;
- var x float;
- _ = x;
+ } else i = 0
+ var x float
+ _ = x
}
foo: // a label
- var j int;
+ var j int
switch y := 0; true {
case i < y:
- fallthrough;
+ fallthrough
case i < j:
case i == 0, i == 1, i == j:
- i++; i++;
- goto foo;
+ i++; i++
+ goto foo
default:
- i = -+-+i;
- break;
+ i = -+-+i
+ break
}
}
diff --git a/test/turing.go b/test/turing.go
index 462bb9168..0af39de8b 100644
--- a/test/turing.go
+++ b/test/turing.go
@@ -8,48 +8,45 @@ package main
// brainfuck
+var p, pc int
+var a [30000]byte
+const prog = "++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.!"
+
+func scan(dir int) {
+ for nest := dir; dir*nest > 0; pc += dir {
+ switch prog[pc+dir] {
+ case ']':
+ nest--
+ case '[':
+ nest++
+ }
+ }
+}
+
func main() {
- var a [30000]byte;
- prog := "++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.!";
- p := 0;
- pc := 0;
for {
switch prog[pc] {
case '>':
- p++;
+ p++
case '<':
- p--;
+ p--
case '+':
- a[p]++;
+ a[p]++
case '-':
- a[p]--;
+ a[p]--
case '.':
- print(string(a[p]));
+ print(string(a[p]))
case '[':
if a[p] == 0 {
- for nest := 1; nest > 0; pc++ {
- switch prog[pc+1] {
- case ']':
- nest--;
- case '[':
- nest++;
- }
- }
+ scan(1)
}
case ']':
if a[p] != 0 {
- for nest := -1; nest < 0; pc-- {
- switch prog[pc-1] {
- case ']':
- nest--;
- case '[':
- nest++;
- }
- }
+ scan(-1)
}
default:
- return;
+ return
}
- pc++;
+ pc++
}
}
diff --git a/test/typeswitch.go b/test/typeswitch.go
index 0a421ae96..9e6d10ea8 100644
--- a/test/typeswitch.go
+++ b/test/typeswitch.go
@@ -9,22 +9,22 @@ package main
import "os"
const (
- Bool = iota;
- Int;
- Float;
- String;
- Struct;
- Chan;
- Array;
- Map;
- Func;
- Last;
+ Bool = iota
+ Int
+ Float
+ String
+ Struct
+ Chan
+ Array
+ Map
+ Func
+ Last
)
type S struct { a int }
var s S = S{1234}
-var c = make(chan int);
+var c = make(chan int)
var a = []int{0,1,2,3}
@@ -32,81 +32,81 @@ var m = make(map[string]int)
func assert(b bool, s string) {
if !b {
- println(s);
- os.Exit(1);
+ println(s)
+ os.Exit(1)
}
}
func f(i int) interface{} {
switch i {
case Bool:
- return true;
+ return true
case Int:
- return 7;
+ return 7
case Float:
- return 7.4;
+ return 7.4
case String:
- return "hello";
+ return "hello"
case Struct:
- return s;
+ return s
case Chan:
- return c;
+ return c
case Array:
- return a;
+ return a
case Map:
- return m;
+ return m
case Func:
- return f;
+ return f
}
- panic("bad type number");
+ panic("bad type number")
}
func main() {
for i := Bool; i < Last; i++ {
switch x := f(i).(type) {
case bool:
- assert(x == true && i == Bool, "bool");
+ assert(x == true && i == Bool, "bool")
case int:
- assert(x == 7 && i == Int, "int");
+ assert(x == 7 && i == Int, "int")
case float:
- assert(x == 7.4 && i == Float, "float");
+ assert(x == 7.4 && i == Float, "float")
case string:
- assert(x == "hello"&& i == String, "string");
+ assert(x == "hello"&& i == String, "string")
case S:
- assert(x.a == 1234 && i == Struct, "struct");
+ assert(x.a == 1234 && i == Struct, "struct")
case chan int:
- assert(x == c && i == Chan, "chan");
+ assert(x == c && i == Chan, "chan")
case []int:
- assert(x[3] == 3 && i == Array, "array");
+ assert(x[3] == 3 && i == Array, "array")
case map[string]int:
- assert(x == m && i == Map, "map");
+ assert(x == m && i == Map, "map")
case func(i int) interface{}:
- assert(x == f && i == Func, "fun");
+ assert(x == f && i == Func, "fun")
default:
- assert(false, "unknown");
+ assert(false, "unknown")
}
}
// boolean switch (has had bugs in past; worth writing down)
switch {
case true:
- assert(true, "switch 2 bool");
+ assert(true, "switch 2 bool")
default:
- assert(false, "switch 2 unknown");
+ assert(false, "switch 2 unknown")
}
switch true {
case true:
- assert(true, "switch 3 bool");
+ assert(true, "switch 3 bool")
default:
- assert(false, "switch 3 unknown");
+ assert(false, "switch 3 unknown")
}
switch false {
case false:
- assert(true, "switch 4 bool");
+ assert(true, "switch 4 bool")
default:
- assert(false, "switch 4 unknown");
+ assert(false, "switch 4 unknown")
}
}
diff --git a/test/undef.go b/test/undef.go
index 70785675a..7ef07882a 100644
--- a/test/undef.go
+++ b/test/undef.go
@@ -9,9 +9,9 @@
package main
var (
- _ = x // ERROR "undefined: x"
- _ = x // ERROR "undefined: x"
- _ = x // ERROR "undefined: x"
+ _ = x // ERROR "undefined.*x"
+ _ = x // ERROR "undefined.*x"
+ _ = x // ERROR "undefined.*x"
)
type T struct {
@@ -19,7 +19,7 @@ type T struct {
}
func foo() *T { return &T{y: 99} }
-func bar() int { return y } // ERROR "undefined: y"
+func bar() int { return y } // ERROR "undefined.*y"
type T1 struct {
y1 int
@@ -39,6 +39,6 @@ func f1(val interface{}) {
func f2(val interface{}) {
switch val.(type) {
default:
- println(v) // ERROR "undefined: v"
+ println(v) // ERROR "undefined.*v"
}
}
diff --git a/test/utf.go b/test/utf.go
index 59b0ffaa9..a93fc2934 100644
--- a/test/utf.go
+++ b/test/utf.go
@@ -9,46 +9,46 @@ package main
import "utf8"
func main() {
- var chars [6] int;
- chars[0] = 'a';
- chars[1] = 'b';
- chars[2] = 'c';
- chars[3] = '\u65e5';
- chars[4] = '\u672c';
- chars[5] = '\u8a9e';
- s := "";
+ var chars [6] int
+ chars[0] = 'a'
+ chars[1] = 'b'
+ chars[2] = 'c'
+ chars[3] = '\u65e5'
+ chars[4] = '\u672c'
+ chars[5] = '\u8a9e'
+ s := ""
for i := 0; i < 6; i++ {
- s += string(chars[i]);
+ s += string(chars[i])
}
- var l = len(s);
+ var l = len(s)
for w, i, j := 0,0,0; i < l; i += w {
- var r int;
- r, w = utf8.DecodeRuneInString(s[i:len(s)]);
+ var r int
+ r, w = utf8.DecodeRuneInString(s[i:len(s)])
if w == 0 { panic("zero width in string") }
if r != chars[j] { panic("wrong value from string") }
- j++;
+ j++
}
// encoded as bytes: 'a' 'b' 'c' e6 97 a5 e6 9c ac e8 aa 9e
- const L = 12;
+ const L = 12
if L != l { panic("wrong length constructing array") }
- a := make([]byte, L);
- a[0] = 'a';
- a[1] = 'b';
- a[2] = 'c';
- a[3] = 0xe6;
- a[4] = 0x97;
- a[5] = 0xa5;
- a[6] = 0xe6;
- a[7] = 0x9c;
- a[8] = 0xac;
- a[9] = 0xe8;
- a[10] = 0xaa;
- a[11] = 0x9e;
+ a := make([]byte, L)
+ a[0] = 'a'
+ a[1] = 'b'
+ a[2] = 'c'
+ a[3] = 0xe6
+ a[4] = 0x97
+ a[5] = 0xa5
+ a[6] = 0xe6
+ a[7] = 0x9c
+ a[8] = 0xac
+ a[9] = 0xe8
+ a[10] = 0xaa
+ a[11] = 0x9e
for w, i, j := 0,0,0; i < L; i += w {
- var r int;
- r, w = utf8.DecodeRune(a[i:L]);
+ var r int
+ r, w = utf8.DecodeRune(a[i:L])
if w == 0 { panic("zero width in bytes") }
if r != chars[j] { panic("wrong value from bytes") }
- j++;
+ j++
}
}
diff --git a/test/varerr.go b/test/varerr.go
index 32f33ecc7..ddd718f5b 100644
--- a/test/varerr.go
+++ b/test/varerr.go
@@ -7,8 +7,8 @@
package main
func main() {
- _ = asdf // ERROR "undefined: asdf"
+ _ = asdf // ERROR "undefined.*asdf"
- new = 1 // ERROR "use of builtin new not in function call"
+ new = 1 // ERROR "use of builtin new not in function call|invalid left hand side"
}
diff --git a/test/zerodivide.go b/test/zerodivide.go
index 9d35b392b..cd4f52215 100644
--- a/test/zerodivide.go
+++ b/test/zerodivide.go
@@ -10,7 +10,6 @@ import (
"fmt"
"math"
"strings"
- "syscall"
)
type Error interface {
@@ -46,6 +45,30 @@ var (
c128, d128, e128 complex128 = 0+0i, 0+0i, 1+1i
)
+// Fool gccgo into thinking that these variables can change.
+func NotCalled() {
+ i++; j++; k++
+ i8++; j8++; k8++
+ i16++; j16++; k16++
+ i32++; j32++; k32++
+ i64++; j64++; k64++
+
+ u++; v++; w++
+ u8++; v8++; w8++
+ u16++; v16++; w16++
+ u32++; v32++; w32++
+ u64++; v64++; w64++
+ up++; vp++; wp++
+
+ f += 1; g += 1; h += 1
+ f32 += 1; g32 += 1; h32 += 1
+ f64 += 1; g64 += 1; h64 += 1
+
+ c += 1+1i; d += 1+1i; e += 1+1i
+ c64 += 1+1i; d64 += 1+1i; e64 += 1+1i
+ c128 += 1+1i; d128 += 1+1i; e128 += 1+1i
+}
+
var tmp interface{}
// We could assign to _ but the compiler optimizes it too easily.
@@ -137,8 +160,9 @@ func alike(a, b float64) bool {
}
func main() {
+ bad := false
for _, t := range errorTests {
- if t.err != "" && syscall.OS == "nacl" {
+ if t.err != "" {
continue
}
err := error(t.fn)
@@ -146,11 +170,23 @@ func main() {
case t.err == "" && err == "":
// fine
case t.err != "" && err == "":
+ if !bad {
+ bad = true
+ fmt.Printf("BUG\n")
+ }
fmt.Printf("%s: expected %q; got no error\n", t.name, t.err)
case t.err == "" && err != "":
+ if !bad {
+ bad = true
+ fmt.Printf("BUG\n")
+ }
fmt.Printf("%s: expected no error; got %q\n", t.name, err)
case t.err != "" && err != "":
if strings.Index(err, t.err) < 0 {
+ if !bad {
+ bad = true
+ fmt.Printf("BUG\n")
+ }
fmt.Printf("%s: expected %q; got %q\n", t.name, t.err, err)
continue
}
@@ -161,6 +197,10 @@ func main() {
for _, t := range floatTests {
x := t.f/t.g
if !alike(x, t.out) {
+ if !bad {
+ bad = true
+ fmt.Printf("BUG\n")
+ }
fmt.Printf("%v/%v: expected %g error; got %g\n", t.f, t.g, t.out, x)
}
}